From d5e4d0850fefab7c50d27b7ccf06a764c39ea4a4 Mon Sep 17 00:00:00 2001 From: Sergei Turukin Date: Tue, 7 Apr 2026 17:53:37 -0700 Subject: [PATCH 01/25] Track private API gateway template Ultraworked with [Sisyphus](https://github.com/code-yeongyu/oh-my-openagent) Co-authored-by: Sisyphus --- crates/embucket-lambda/private-api.cfn.yaml | 152 ++++++++++++++++++++ 1 file changed, 152 insertions(+) create mode 100644 crates/embucket-lambda/private-api.cfn.yaml diff --git a/crates/embucket-lambda/private-api.cfn.yaml b/crates/embucket-lambda/private-api.cfn.yaml new file mode 100644 index 00000000..e1cc51e5 --- /dev/null +++ b/crates/embucket-lambda/private-api.cfn.yaml @@ -0,0 +1,152 @@ +AWSTemplateFormatVersion: '2010-09-09' +Description: Private REST API Gateway for embucket-lambda (VPC-only access) + +Parameters: + LambdaFunctionName: + Type: String + Default: embucket-lambda-sturukin_10g + Description: Name of the existing Lambda function to integrate with + + VpcId: + Type: AWS::EC2::VPC::Id + Default: vpc-0b0902caef1afad23 + Description: VPC where the execute-api endpoint will be created + + SubnetIds: + Type: List + Default: subnet-0de6a3cbce55a0ffe,subnet-0f1e7c04da7fed025,subnet-031ed1d51a578a904 + Description: Subnets for the VPC Endpoint (one per AZ) + + VpcCidr: + Type: String + Default: 172.31.0.0/16 + Description: VPC CIDR block allowed to reach the API via the VPC Endpoint + +Resources: + # Security Group for the VPC Endpoint - allows HTTPS from within the VPC + VpceSecurityGroup: + Type: AWS::EC2::SecurityGroup + Properties: + GroupDescription: Allow HTTPS to execute-api VPC Endpoint + VpcId: !Ref VpcId + SecurityGroupIngress: + - IpProtocol: tcp + FromPort: 443 + ToPort: 443 + CidrIp: !Ref VpcCidr + Tags: + - Key: Name + Value: embucket-private-api-vpce-sg + + # Interface VPC Endpoint for execute-api + ExecuteApiVpcEndpoint: + Type: AWS::EC2::VPCEndpoint + Properties: + VpcId: !Ref VpcId + ServiceName: !Sub com.amazonaws.${AWS::Region}.execute-api + VpcEndpointType: Interface + PrivateDnsEnabled: true + SubnetIds: !Ref SubnetIds + SecurityGroupIds: + - !Ref VpceSecurityGroup + + # Private REST API Gateway + PrivateApi: + Type: AWS::ApiGateway::RestApi + Properties: + Name: embucket-private-api + Description: Private API Gateway for embucket-lambda + BinaryMediaTypes: + - '*/*' + EndpointConfiguration: + Types: + - PRIVATE + VpcEndpointIds: + - !Ref ExecuteApiVpcEndpoint + Policy: + Version: '2012-10-17' + Statement: + - Effect: Allow + Principal: '*' + Action: execute-api:Invoke + Resource: execute-api:/* + Condition: + StringEquals: + aws:sourceVpce: !Ref ExecuteApiVpcEndpoint + + # Catch-all proxy resource: {proxy+} + ProxyResource: + Type: AWS::ApiGateway::Resource + Properties: + RestApiId: !Ref PrivateApi + ParentId: !GetAtt PrivateApi.RootResourceId + PathPart: '{proxy+}' + + # ANY method on {proxy+} -> Lambda proxy integration + ProxyMethod: + Type: AWS::ApiGateway::Method + Properties: + RestApiId: !Ref PrivateApi + ResourceId: !Ref ProxyResource + HttpMethod: ANY + AuthorizationType: NONE + Integration: + Type: AWS_PROXY + IntegrationHttpMethod: POST + Uri: !Sub arn:aws:apigateway:${AWS::Region}:lambda:path/2015-03-31/functions/arn:aws:lambda:${AWS::Region}:${AWS::AccountId}:function:${LambdaFunctionName}/invocations + + # ANY method on root / -> Lambda proxy integration + RootMethod: + Type: AWS::ApiGateway::Method + Properties: + RestApiId: !Ref PrivateApi + ResourceId: !GetAtt PrivateApi.RootResourceId + HttpMethod: ANY + AuthorizationType: NONE + Integration: + Type: AWS_PROXY + IntegrationHttpMethod: POST + Uri: !Sub arn:aws:apigateway:${AWS::Region}:lambda:path/2015-03-31/functions/arn:aws:lambda:${AWS::Region}:${AWS::AccountId}:function:${LambdaFunctionName}/invocations + + # API Deployment + ApiDeployment: + Type: AWS::ApiGateway::Deployment + DependsOn: + - ProxyMethod + - RootMethod + Properties: + RestApiId: !Ref PrivateApi + + # API Stage + ApiStage: + Type: AWS::ApiGateway::Stage + Properties: + RestApiId: !Ref PrivateApi + DeploymentId: !Ref ApiDeployment + StageName: v1 + + # Permission for API Gateway to invoke the Lambda + LambdaInvokePermission: + Type: AWS::Lambda::Permission + Properties: + FunctionName: !Ref LambdaFunctionName + Action: lambda:InvokeFunction + Principal: apigateway.amazonaws.com + SourceArn: !Sub arn:aws:execute-api:${AWS::Region}:${AWS::AccountId}:${PrivateApi}/* + +Outputs: + ApiId: + Description: REST API ID + Value: !Ref PrivateApi + + PrivateApiEndpoint: + Description: Private API endpoint (reachable only from within the VPC) + Value: !Sub https://${PrivateApi}.execute-api.${AWS::Region}.amazonaws.com/v1 + + VpcEndpointId: + Description: VPC Endpoint ID for execute-api + Value: !Ref ExecuteApiVpcEndpoint + + SecurityGroupId: + Description: Security Group controlling access to the VPC Endpoint + Value: !Ref VpceSecurityGroup From 4be22727776592ced6187d11c7e50b5c50431fec Mon Sep 17 00:00:00 2001 From: Sergei Turukin Date: Tue, 7 Apr 2026 17:53:37 -0700 Subject: [PATCH 02/25] Add docs smoke checks Ultraworked with [Sisyphus](https://github.com/code-yeongyu/oh-my-openagent) Co-authored-by: Sisyphus --- .github/workflows/docs-ci.yml | 49 +- docs/package.json | 6 +- docs/pnpm-lock.yaml | 652 +++++++++++++++++- docs/scripts/validate-docs-smoke.mjs | 116 ++++ .../docs/development/docs-maintenance.mdx | 69 ++ 5 files changed, 852 insertions(+), 40 deletions(-) create mode 100644 docs/scripts/validate-docs-smoke.mjs create mode 100644 docs/src/content/docs/development/docs-maintenance.mdx diff --git a/.github/workflows/docs-ci.yml b/.github/workflows/docs-ci.yml index 6e008ce2..36f6a6e0 100644 --- a/.github/workflows/docs-ci.yml +++ b/.github/workflows/docs-ci.yml @@ -5,10 +5,18 @@ on: branches: [main] paths: - "docs/**" + - "README.md" + - ".github/workflows/docs-ci.yml" + - "config/metastore.yaml" + - "crates/embucket-lambda/private-api.cfn.yaml" pull_request: branches: [main] paths: - "docs/**" + - "README.md" + - ".github/workflows/docs-ci.yml" + - "config/metastore.yaml" + - "crates/embucket-lambda/private-api.cfn.yaml" # Cancel in-progress runs for the same branch/PR to save resources concurrency: @@ -49,10 +57,47 @@ jobs: working-directory: ./docs run: pnpm prettier --check . + smoke: + name: Docs Smoke Checks + runs-on: ubuntu-latest + needs: [format] + steps: + - uses: actions/checkout@v6 + - name: Setup Node.js + uses: actions/setup-node@v6 + with: + node-version: "22" + - name: Setup PNPM + uses: pnpm/action-setup@v4 + with: + version: "10.11.0" + run_install: false + - name: Get pnpm store directory + id: pnpm-cache + shell: bash + run: | + echo "STORE_PATH=$(pnpm store path)" >> $GITHUB_OUTPUT + - name: Setup pnpm cache + uses: actions/cache@v4 + with: + path: ${{ steps.pnpm-cache.outputs.STORE_PATH }} + key: ${{ runner.os }}-pnpm-store-${{ hashFiles('**/docs/pnpm-lock.yaml') }} + restore-keys: | + ${{ runner.os }}-pnpm-store- + - name: Install dependencies + working-directory: ./docs + run: pnpm install + - name: Run Astro check + working-directory: ./docs + run: pnpm check + - name: Run docs smoke checks + working-directory: ./docs + run: pnpm smoke + build: name: Validate Build runs-on: ubuntu-latest - needs: [format] + needs: [format, smoke] steps: - uses: actions/checkout@v6 - name: Setup Node.js @@ -81,7 +126,7 @@ jobs: run: pnpm install - name: Validate build working-directory: ./docs - run: pnpm build:dry-run + run: pnpm build vale-lint: name: Vale lint diff --git a/docs/package.json b/docs/package.json index 643deb88..14b71bc0 100644 --- a/docs/package.json +++ b/docs/package.json @@ -6,10 +6,12 @@ "astro": "astro", "build": "astro build", "build:dry-run": "astro build --dry-run", + "check": "astro check", "dev": "astro dev", "format": "prettier --write .", "ncu": "ncu -u", "preview": "astro preview", + "smoke": "node ./scripts/validate-docs-smoke.mjs", "start": "astro dev" }, "dependencies": { @@ -24,11 +26,13 @@ "tailwindcss": "^4.1.17" }, "devDependencies": { + "@astrojs/check": "^0.9.8", "npm-check-updates": "^19.1.2", "prettier": "^3.6.2", "prettier-plugin-astro": "^0.14.1", "prettier-plugin-packagejson": "^2.5.19", "prettier-plugin-tailwindcss": "^0.7.1", - "starlight-links-validator": "^0.19.1" + "starlight-links-validator": "^0.19.1", + "typescript": "^5.9.3" } } diff --git a/docs/pnpm-lock.yaml b/docs/pnpm-lock.yaml index cda427bf..1e132a15 100644 --- a/docs/pnpm-lock.yaml +++ b/docs/pnpm-lock.yaml @@ -10,22 +10,22 @@ importers: dependencies: '@astrojs/starlight': specifier: ^0.36.2 - version: 0.36.2(astro@5.15.4(@types/node@24.0.10)(jiti@2.6.1)(lightningcss@1.30.2)(rollup@4.44.1)(typescript@5.8.3)) + version: 0.36.2(astro@5.15.4(@types/node@24.0.10)(jiti@2.6.1)(lightningcss@1.30.2)(rollup@4.44.1)(typescript@5.9.3)(yaml@2.8.3)) '@astrojs/starlight-tailwind': specifier: ^4.0.2 - version: 4.0.2(@astrojs/starlight@0.36.2(astro@5.15.4(@types/node@24.0.10)(jiti@2.6.1)(lightningcss@1.30.2)(rollup@4.44.1)(typescript@5.8.3)))(tailwindcss@4.1.17) + version: 4.0.2(@astrojs/starlight@0.36.2(astro@5.15.4(@types/node@24.0.10)(jiti@2.6.1)(lightningcss@1.30.2)(rollup@4.44.1)(typescript@5.9.3)(yaml@2.8.3)))(tailwindcss@4.1.17) '@fontsource/inter': specifier: ^5.2.8 version: 5.2.8 '@tailwindcss/vite': specifier: ^4.1.17 - version: 4.1.17(vite@6.4.1(@types/node@24.0.10)(jiti@2.6.1)(lightningcss@1.30.2)) + version: 4.1.17(vite@6.4.1(@types/node@24.0.10)(jiti@2.6.1)(lightningcss@1.30.2)(yaml@2.8.3)) astro: specifier: ^5.15.4 - version: 5.15.4(@types/node@24.0.10)(jiti@2.6.1)(lightningcss@1.30.2)(rollup@4.44.1)(typescript@5.8.3) + version: 5.15.4(@types/node@24.0.10)(jiti@2.6.1)(lightningcss@1.30.2)(rollup@4.44.1)(typescript@5.9.3)(yaml@2.8.3) astro-mermaid: specifier: ^1.1.0 - version: 1.1.0(astro@5.15.4(@types/node@24.0.10)(jiti@2.6.1)(lightningcss@1.30.2)(rollup@4.44.1)(typescript@5.8.3))(mermaid@11.12.1) + version: 1.1.0(astro@5.15.4(@types/node@24.0.10)(jiti@2.6.1)(lightningcss@1.30.2)(rollup@4.44.1)(typescript@5.9.3)(yaml@2.8.3))(mermaid@11.12.1) mermaid: specifier: ^11.12.1 version: 11.12.1 @@ -36,6 +36,9 @@ importers: specifier: ^4.1.17 version: 4.1.17 devDependencies: + '@astrojs/check': + specifier: ^0.9.8 + version: 0.9.8(prettier-plugin-astro@0.14.1)(prettier@3.6.2)(typescript@5.9.3) npm-check-updates: specifier: ^19.1.2 version: 19.1.2 @@ -53,7 +56,10 @@ importers: version: 0.7.1(prettier-plugin-astro@0.14.1)(prettier@3.6.2) starlight-links-validator: specifier: ^0.19.1 - version: 0.19.1(@astrojs/starlight@0.36.2(astro@5.15.4(@types/node@24.0.10)(jiti@2.6.1)(lightningcss@1.30.2)(rollup@4.44.1)(typescript@5.8.3))) + version: 0.19.1(@astrojs/starlight@0.36.2(astro@5.15.4(@types/node@24.0.10)(jiti@2.6.1)(lightningcss@1.30.2)(rollup@4.44.1)(typescript@5.9.3)(yaml@2.8.3))) + typescript: + specifier: ^5.9.3 + version: 5.9.3 packages: @@ -63,9 +69,18 @@ packages: '@antfu/utils@9.3.0': resolution: {integrity: sha512-9hFT4RauhcUzqOE4f1+frMKLZrgNog5b06I7VmZQV1BkvwvqrbC8EBZf3L1eEL2AKb6rNKjER0sEvJiSP1FXEA==} + '@astrojs/check@0.9.8': + resolution: {integrity: sha512-LDng8446QLS5ToKjRHd3bgUdirvemVVExV7nRyJfW2wV36xuv7vDxwy5NWN9zqeSEDgg0Tv84sP+T3yEq+Zlkw==} + hasBin: true + peerDependencies: + typescript: ^5.0.0 + '@astrojs/compiler@2.12.2': resolution: {integrity: sha512-w2zfvhjNCkNMmMMOn5b0J8+OmUaBL1o40ipMvqcG6NRpdC+lKxmTi48DT8Xw0SzJ3AfmeFLB45zXZXtmbsjcgw==} + '@astrojs/compiler@2.13.1': + resolution: {integrity: sha512-f3FN83d2G/v32ipNClRKgYv30onQlMZX1vCeZMjPsMMPl1mDpmbl0+N5BYo4S/ofzqJyS5hvwacEo0CCVDn/Qg==} + '@astrojs/internal-helpers@0.6.1': resolution: {integrity: sha512-l5Pqf6uZu31aG+3Lv8nl/3s4DbUzdlxTWDof4pEpto6GUJNhhCbelVi9dEyurOVyqaelwmS9oSyOWOENSfgo9A==} @@ -75,6 +90,18 @@ packages: '@astrojs/internal-helpers@0.7.4': resolution: {integrity: sha512-lDA9MqE8WGi7T/t2BMi+EAXhs4Vcvr94Gqx3q15cFEz8oFZMO4/SFBqYr/UcmNlvW+35alowkVj+w9VhLvs5Cw==} + '@astrojs/language-server@2.16.6': + resolution: {integrity: sha512-N990lu+HSFiG57owR0XBkr02BYMgiLCshLf+4QG4v6jjSWkBeQGnzqi+E1L08xFPPJ7eEeXnxPXGLaVv5pa4Ug==} + hasBin: true + peerDependencies: + prettier: ^3.0.0 + prettier-plugin-astro: '>=0.11.0' + peerDependenciesMeta: + prettier: + optional: true + prettier-plugin-astro: + optional: true + '@astrojs/markdown-remark@6.3.2': resolution: {integrity: sha512-bO35JbWpVvyKRl7cmSJD822e8YA8ThR/YbUsciWNA7yTcqpIAL2hJDToWP5KcZBWxGT6IOdOkHSXARSNZc4l/Q==} @@ -112,6 +139,9 @@ packages: resolution: {integrity: sha512-UFBgfeldP06qu6khs/yY+q1cDAaArM2/7AEIqQ9Cuvf7B1hNLq0xDrZkct+QoIGyjq56y8IaE2I3CTvG99mlhQ==} engines: {node: 18.20.8 || ^20.3.0 || >=22.0.0} + '@astrojs/yaml2ts@0.2.3': + resolution: {integrity: sha512-PJzRmgQzUxI2uwpdX2lXSHtP4G8ocp24/t+bZyf5Fy0SZLSF9f9KXZoMlFM/XCGue+B0nH/2IZ7FpBYQATBsCg==} + '@babel/helper-string-parser@7.27.1': resolution: {integrity: sha512-qMlSxKbpRlAridDExk92nSobyDdpPijUq2DW6oDnUqd0iOGxmQjyqhMIihI9+zv4LPyZdRje2cavWPbCbWm3eA==} engines: {node: '>=6.9.0'} @@ -159,6 +189,27 @@ packages: resolution: {integrity: sha512-WyOx8cJQ+FQus4Mm4uPIZA64gbk3Wxh0so5Lcii0aJifqwoVOlfFtorjLE0Hen4OYyHZMXDWqMmaQemBhgxFRQ==} engines: {node: '>=14'} + '@emmetio/abbreviation@2.3.3': + resolution: {integrity: sha512-mgv58UrU3rh4YgbE/TzgLQwJ3pFsHHhCLqY20aJq+9comytTXUDNGG/SMtSeMJdkpxgXSXunBGLD8Boka3JyVA==} + + '@emmetio/css-abbreviation@2.1.8': + resolution: {integrity: sha512-s9yjhJ6saOO/uk1V74eifykk2CBYi01STTK3WlXWGOepyKa23ymJ053+DNQjpFcy1ingpaO7AxCcwLvHFY9tuw==} + + '@emmetio/css-parser@0.4.1': + resolution: {integrity: sha512-2bC6m0MV/voF4CTZiAbG5MWKbq5EBmDPKu9Sb7s7nVcEzNQlrZP6mFFFlIaISM8X6514H9shWMme1fCm8cWAfQ==} + + '@emmetio/html-matcher@1.3.0': + resolution: {integrity: sha512-NTbsvppE5eVyBMuyGfVu2CRrLvo7J4YHb6t9sBFLyY03WYhXET37qA4zOYUjBWFCRHO7pS1B9khERtY0f5JXPQ==} + + '@emmetio/scanner@1.0.4': + resolution: {integrity: sha512-IqRuJtQff7YHHBk4G8YZ45uB9BaAGcwQeVzgj/zj8/UdOhtQpEIupUhSk8dys6spFIWVZVeK20CzGEnqR5SbqA==} + + '@emmetio/stream-reader-utils@0.1.0': + resolution: {integrity: sha512-ZsZ2I9Vzso3Ho/pjZFsmmZ++FWeEd/txqybHTm4OgaZzdS8V9V/YYWQwg5TC38Z7uLWUV1vavpLLbjJtKubR1A==} + + '@emmetio/stream-reader@2.2.0': + resolution: {integrity: sha512-fXVXEyFA5Yv3M3n8sUGT7+fvecGrZP4k6FnWWMSZVQf69kAq0LLpaBQLGcPR30m3zMmKYhECP4k/ZkzvhEW5kw==} + '@emnapi/runtime@1.7.0': resolution: {integrity: sha512-oAYoQnCYaQZKVS53Fq23ceWMRxq5EhQsE0x0RdQ55jT7wagMu5k+fS39v1fiSLrtrLQlXwVINenqhLMtTrV/1Q==} @@ -918,6 +969,32 @@ packages: '@ungap/structured-clone@1.3.0': resolution: {integrity: sha512-WmoN8qaIAo7WTYWbAZuG8PYEhn5fkz7dZrqTBZ7dtt//lL2Gwms1IcnQ5yHqjDfX8Ft5j4YzDM23f87zBfDe9g==} + '@volar/kit@2.4.28': + resolution: {integrity: sha512-cKX4vK9dtZvDRaAzeoUdaAJEew6IdxHNCRrdp5Kvcl6zZOqb6jTOfk3kXkIkG3T7oTFXguEMt5+9ptyqYR84Pg==} + peerDependencies: + typescript: '*' + + '@volar/language-core@2.4.28': + resolution: {integrity: sha512-w4qhIJ8ZSitgLAkVay6AbcnC7gP3glYM3fYwKV3srj8m494E3xtrCv6E+bWviiK/8hs6e6t1ij1s2Endql7vzQ==} + + '@volar/language-server@2.4.28': + resolution: {integrity: sha512-NqcLnE5gERKuS4PUFwlhMxf6vqYo7hXtbMFbViXcbVkbZ905AIVWhnSo0ZNBC2V127H1/2zP7RvVOVnyITFfBw==} + + '@volar/language-service@2.4.28': + resolution: {integrity: sha512-Rh/wYCZJrI5vCwMk9xyw/Z+MsWxlJY1rmMZPsxUoJKfzIRjS/NF1NmnuEcrMbEVGja00aVpCsInJfixQTMdvLw==} + + '@volar/source-map@2.4.28': + resolution: {integrity: sha512-yX2BDBqJkRXfKw8my8VarTyjv48QwxdJtvRgUpNE5erCsgEUdI2DsLbpa+rOQVAJYshY99szEcRDmyHbF10ggQ==} + + '@volar/typescript@2.4.28': + resolution: {integrity: sha512-Ja6yvWrbis2QtN4ClAKreeUZPVYMARDYZl9LMEv1iQ1QdepB6wn0jTRxA9MftYmYa4DQ4k/DaSZpFPUfxl8giw==} + + '@vscode/emmet-helper@2.11.0': + resolution: {integrity: sha512-QLxjQR3imPZPQltfbWRnHU6JecWTF1QSWhx3GAKQpslx7y3Dp6sIIXhKjiUJ/BR9FX8PVthjr9PD6pNwOJfAzw==} + + '@vscode/l10n@0.0.18': + resolution: {integrity: sha512-KYSIHVmslkaCDyw013pphY+d7x1qV8IZupYfeIfzNA+nsaWHbn5uPuQRvdRFsa9zFzGeudPuoGoZ1Op4jrJXIQ==} + acorn-jsx@5.3.2: resolution: {integrity: sha512-rq9s+JNhf0IChjtDXxllJ7g41oZk5SlXtp0LHwyA5cejwn7vKmKp4pPri6YEePv2PU65sAsegbXtIinmDFDXgQ==} peerDependencies: @@ -928,6 +1005,17 @@ packages: engines: {node: '>=0.4.0'} hasBin: true + ajv-draft-04@1.0.0: + resolution: {integrity: sha512-mv00Te6nmYbRp5DCwclxtt7yV/joXJPGS7nM+97GdxvuttCOfgI3K4U25zboyeX0O+myI8ERluxQe5wljMmVIw==} + peerDependencies: + ajv: ^8.5.0 + peerDependenciesMeta: + ajv: + optional: true + + ajv@8.18.0: + resolution: {integrity: sha512-PlXPeEWMXMZ7sPYOHqmDyCJzcfNrUr3fGNKtezX14ykXOEIvyK81d+qydx89KY5O71FKMPaQ2vBfBFI5NHR63A==} + ansi-align@3.0.1: resolution: {integrity: sha512-IOfwwBF5iczOjp/WeY4YxyjqAFMQoZufdQWDd19SEExbVLNXqvpzSJ/M7Za4/sCPmQ0+GRquoA7bGcINcxew6w==} @@ -943,6 +1031,10 @@ packages: resolution: {integrity: sha512-7HSX4QQb4CspciLpVFwyRe79O3xsIZDDLER21kERQ71oaPodF8jL725AgJMFAYbooIqolJoRLuM81SpeUkpkvA==} engines: {node: '>=12'} + ansi-styles@4.3.0: + resolution: {integrity: sha512-zbB9rCJAT1rbjiVDb2hqKFHNYLxgtk8NURxZ3IZwD3F6NtxbXZQCnnSi1Lkx+IDohdPlFp222wVALIheZJQSEg==} + engines: {node: '>=8'} + ansi-styles@6.2.1: resolution: {integrity: sha512-bN798gFfQX+viw3R7yrGWRqnrN2oRkEkUjjl4JNn4E8GxxbjtG3FbrEIIY3l8/hrwUwIeCZvi4QuOTP4MErVug==} engines: {node: '>=12'} @@ -1060,6 +1152,10 @@ packages: resolution: {integrity: sha512-/lzGpEWL/8PfI0BmBOPRwp0c/wFNX1RdUML3jK/RcSBA9T8mZDdQpqYBKtCFTOfQbwPqWEOpjqW+Fnayc0969g==} engines: {node: '>=10'} + cliui@8.0.1: + resolution: {integrity: sha512-BSeNnyus75C4//NQ9gQt1/csTXyo/8Sb+afLAkzAptFuMsod9HFokGNudZpi/oQV73hnVK+sR+5PVRMd+Dr7YQ==} + engines: {node: '>=12'} + clone@2.1.2: resolution: {integrity: sha512-3Pe/CF1Nn94hyhIYpjtiLhdCoEoz0DqQ+988E9gmeEdQZlojxnOb74wctFyuwWQHzqyf9X7C7MG8juUpqBJT8w==} engines: {node: '>=0.8'} @@ -1071,6 +1167,13 @@ packages: collapse-white-space@2.1.0: resolution: {integrity: sha512-loKTxY1zCOuG4j9f6EPnuyyYkf58RnhhWTvRoZEokgB+WbdXehfjFviyOVYkqzEWz1Q5kRiZdBYS5SwxbQYwzw==} + color-convert@2.0.1: + resolution: {integrity: sha512-RRECPsj7iu/xb5oKYcsFHSppFNnsj/52OVTRKb4zP5onXwVF3zVmmToNcOfGC+CRDpfK/U584fMg38ZHCaElKQ==} + engines: {node: '>=7.0.0'} + + color-name@1.1.4: + resolution: {integrity: sha512-dOy+3AuW3a2wNbZHIuMZpTcgjGuLU/uBL/ubcZF9OXbDo8ff4O8yVp5Bf0efS8uEoYo5q4Fx7dY9OgQGXgAsQA==} + comma-separated-tokens@2.0.3: resolution: {integrity: sha512-Fu4hJdvzeylCfQPp9SGWidpzrMs7tTrlu6Vb8XGaRGck8QSNZJJp538Wrb60Lax4fPwR64ViY468OIUTbRlGZg==} @@ -1346,6 +1449,9 @@ packages: resolution: {integrity: sha512-2QF/g9/zTaPDc3BjNcVTGoBbXBgYfMTTceLaYcFJ/W9kggFUkhxD/hMEeuLKbugyef9SqAx8cpgwlIP/jinUTA==} engines: {node: '>=4'} + emmet@2.4.11: + resolution: {integrity: sha512-23QPJB3moh/U9sT4rQzGgeyyGIrcM+GH5uVYg2C6wZIxAIJq7Ng3QLT79tl8FUwDXhyq9SusfknOrofAKqvgyQ==} + emoji-regex@10.4.0: resolution: {integrity: sha512-EC+0oUMY1Rqm4O6LLrgjtYDvcVYTy7chDnM4Q7030tP4Kwj3u/pR6gP9ygnp2CJMK5Gq+9Q2oqmrFJAz01DXjw==} @@ -1378,6 +1484,10 @@ packages: engines: {node: '>=18'} hasBin: true + escalade@3.2.0: + resolution: {integrity: sha512-WUj2qlxaQtO4g6Pq5c29GTcWGDyd8itL8zTlipgECz3JesAiiOKotd8JU6otB3PACgG6xkJUyVhboMS+bje/jA==} + engines: {node: '>=6'} + escape-string-regexp@5.0.0: resolution: {integrity: sha512-/veY75JbMK4j1yjvuUxuVsiS/hr/4iHs9FTT6cgTexxdE0Ly/glccBAkloH/DofkjRbZU3bnoj38mOmhkZ0lHw==} engines: {node: '>=12'} @@ -1421,6 +1531,9 @@ packages: fast-deep-equal@3.1.3: resolution: {integrity: sha512-f3qQ9oQy9j2AhBe/H9VC91wLmKBCCU/gDOnKNAYG5hswO7BLKj09Hc5HYNz9cGI++xlpDCIgDaitVs03ATR84Q==} + fast-uri@3.1.0: + resolution: {integrity: sha512-iPeeDKJSWf4IEOasVVrknXpaBV0IApz/gp7S2bb7Z4Lljbl2MGJRqInZiUrQwV16cpzw/D3S5j5Julj/gT52AA==} + fdir@6.4.6: resolution: {integrity: sha512-hiFoqpyZcfNm1yc4u8oWCf9A2c4D3QjCrks3zmoVKVxpQRzmPNar1hUJcBG2RQHvEVGDN+Jm81ZheVLAQMK6+w==} peerDependencies: @@ -1429,6 +1542,15 @@ packages: picomatch: optional: true + fdir@6.5.0: + resolution: {integrity: sha512-tIbYtZbucOs0BRGqPJkshJUYdL+SDH7dVM8gjy+ERp3WAUjLEFJE+02kanyHtwjWOnwrKYBiwAmM0p4kLJAnXg==} + engines: {node: '>=12.0.0'} + peerDependencies: + picomatch: ^3 || ^4 + peerDependenciesMeta: + picomatch: + optional: true + flattie@1.1.1: resolution: {integrity: sha512-9UbaD6XdAL97+k/n+N7JwX46K/M6Zc6KcFYskrYL8wbBV/Uyk0CTAMY0VT+qiK5PM7AIc9aTWYtq65U7T+aCNQ==} engines: {node: '>=8'} @@ -1444,6 +1566,10 @@ packages: engines: {node: ^8.16.0 || ^10.6.0 || >=11.0.0} os: [darwin] + get-caller-file@2.0.5: + resolution: {integrity: sha512-DyFP3BM/3YHTQOCUL/w0OZHR0lpKeGrxotcHWcqNEdnltqFwXVfhEBQ94eIo34AfQpo0rGki4cyIiftY06h2Fg==} + engines: {node: 6.* || 8.* || >= 10.*} + get-east-asian-width@1.3.0: resolution: {integrity: sha512-vpeMIQKxczTD/0s2CdEWHcb0eeJe6TFjxb+J5xgX7hScxqrGuyjmv4c1D4A/gelKfyox0gJJwIHF+fLjeaM8kQ==} engines: {node: '>=18'} @@ -1615,6 +1741,15 @@ packages: resolution: {integrity: sha512-wpxZs9NoxZaJESJGIZTyDEaYpl0FKSA+FB9aJiyemKhMwkxQg63h4T1KJgUGHpTqPDNRcmmYLugrRjJlBtWvRA==} hasBin: true + json-schema-traverse@1.0.0: + resolution: {integrity: sha512-NM8/P9n3XjXhIZn1lLhkFaACTOURQXjWhV4BA/RnOv8xvgqtqpAX9IO4mRQxSx1Rlo4tqzeqb0sOlruaOy3dug==} + + jsonc-parser@2.3.1: + resolution: {integrity: sha512-H8jvkz1O50L3dMZCsLqiuB2tA7muqbSg1AtGEkN0leAqGjsUzDJir3Zwr02BhqdcITPg3ei3mZ+HjMocAknhhg==} + + jsonc-parser@3.3.1: + resolution: {integrity: sha512-HUgH65KyejrUFPvHFPbqOY0rsFip3Bo5wb4ngvdi1EpCYWUQDC5V+Y7mZws+DLkr4M//zQJoanu1SP+87Dv1oQ==} + katex@0.16.22: resolution: {integrity: sha512-XCHRdUw4lf3SKBaJe4EvgqIuWwkPSo9XoeO8GjQW94Bp7TWv9hNhzZjZ+OH9yf1UmLygb7DIT5GSFQiyt16zYg==} hasBin: true @@ -1926,6 +2061,9 @@ packages: ms@2.1.3: resolution: {integrity: sha512-6FlzubTLZG3J2a/NVCAleEhjzq5oxgHyaCU9yYXvcLsvoVaHJq/s5xXI6/XXP6tz7R9xAOtHnSO/tXtF3WRTlA==} + muggle-string@0.4.1: + resolution: {integrity: sha512-VNTrAak/KhO2i8dqqnqnAHOa3cYBwXEZe9h+D5h/1ZqFSTEFHdM65lR7RoIqq3tBBYavsOXV84NoHXZ0AkPyqQ==} + nanoid@3.3.11: resolution: {integrity: sha512-N8SpfPUnUp1bK+PMYW8qSWdl9U+wwNWI4QKxOYDy9JAro3WMX7p2OeVRF9v+347pnakNevPmiHhNmZ2HbFA76w==} engines: {node: ^10 || ^12 || ^13.7 || ^14 || >=15.0.1} @@ -1999,6 +2137,9 @@ packages: parse5@7.3.0: resolution: {integrity: sha512-IInvU7fabl34qmi9gY8XOVxhYyMyuH2xUNpb2q8/Y+7552KlejkRvqvD19nMoUW/uQGGbqNpA6Tufu5FL5BZgw==} + path-browserify@1.0.1: + resolution: {integrity: sha512-b7uo2UCUOYZcnF/3ID0lulOJi/bafxa1xPe7ZPsammBSpjSWQkjNxlt635YGS2MiR9GjvuXCtz2emr3jbsz98g==} + path-data-parser@0.1.0: resolution: {integrity: sha512-NOnmBpt5Y2RWbuv0LMzsayp3lVylAHLPUTut412ZA3l+C4uw4ZVkQbjShYCQ8TCpUMdPapr4YjUqLYD6v68j+w==} @@ -2020,6 +2161,10 @@ packages: resolution: {integrity: sha512-5gTmgEY/sqK6gFXLIsQNH19lWb4ebPDLA4SdLP7dsWkIXHWlG66oPuVvXSGFPppYZz8ZDZq0dYYrbHfBCVUb1Q==} engines: {node: '>=12'} + picomatch@4.0.4: + resolution: {integrity: sha512-QP88BAKvMam/3NxH6vj2o21R6MjxZUAd6nlwAS/pnGvN9IVLocLHxGYIzFhg6fUQ+5th6P4dv4eW9jX3DSIj7A==} + engines: {node: '>=12'} + pkg-types@1.3.1: resolution: {integrity: sha512-/Jm5M4RvtBFVkKWRu2BLUTNP8/M2a+UwuAX+ae4770q1qVGtfjG+WTCupoZixokjmHiry8uI+dlY8KXYV5HVVQ==} @@ -2206,6 +2351,20 @@ packages: remark-stringify@11.0.0: resolution: {integrity: sha512-1OSmLd3awB/t8qdoEOMazZkNsfVTeY4fTsgzcQFdXNq8ToTN4ZGwrMnlda4K6smTFKD+GRV6O48i6Z4iKgPPpw==} + request-light@0.5.8: + resolution: {integrity: sha512-3Zjgh+8b5fhRJBQZoy+zbVKpAQGLyka0MPgW3zruTF4dFFJ8Fqcfu9YsAvi/rvdcaTeWG3MkbZv4WKxAn/84Lg==} + + request-light@0.7.0: + resolution: {integrity: sha512-lMbBMrDoxgsyO+yB3sDcrDuX85yYt7sS8BfQd11jtbW/z5ZWgLZRcEGLsLoYw7I0WSUGQBs8CC8ScIxkTX1+6Q==} + + require-directory@2.1.1: + resolution: {integrity: sha512-fGxEI7+wsG9xrvdjsrlmL22OMTTiHRwAMroiEeMgq8gzoLC/PQr7RsRDSTLUg/bZAZtF+TVIkHc6/4RIKrui+Q==} + engines: {node: '>=0.10.0'} + + require-from-string@2.0.2: + resolution: {integrity: sha512-Xf0nWe6RseziFMu+Ap9biiUbmplq6S9/p+7w7YXP/JBHhrUDDUhwa+vANyubuqfZWTveU//DYVGsDG7RKL/vEw==} + engines: {node: '>=0.10.0'} + restructure@3.0.2: resolution: {integrity: sha512-gSfoiOEA0VPE6Tukkrr7I0RBdE0s7H1eFCDBk05l1KIQT1UIKNc5JZy6jdyW6eYH3aR3g5b3PuL77rq0hvwtAw==} @@ -2376,6 +2535,10 @@ packages: resolution: {integrity: sha512-tX5e7OM1HnYr2+a2C/4V0htOcSQcoSTH9KgJnVvNm5zm/cyEWKJ7j7YutsH9CxMdtOkkLFy2AHrMci9IM8IPZQ==} engines: {node: '>=12.0.0'} + tinyglobby@0.2.16: + resolution: {integrity: sha512-pn99VhoACYR8nFHhxqix+uvsbXineAasWm5ojXoN8xEwK5Kd3/TrhNn1wByuD52UxWRLy8pu+kRMniEi6Eq9Zg==} + engines: {node: '>=12.0.0'} + trim-lines@3.0.1: resolution: {integrity: sha512-kRj8B+YHZCc9kQYdWfJB2/oUl9rA99qbowYYBtr4ui4mZyAQ2JpvVBd/6U2YloATfqBhBTSMhTpgBHtU0Mf3Rg==} @@ -2403,8 +2566,14 @@ packages: resolution: {integrity: sha512-TeTSQ6H5YHvpqVwBRcnLDCBnDOHWYu7IvGbHT6N8AOymcr9PJGjc1GTtiWZTYg0NCgYwvnYWEkVChQAr9bjfwA==} engines: {node: '>=16'} - typescript@5.8.3: - resolution: {integrity: sha512-p1diW6TqL9L07nNxvRMM7hMMw4c5XOo/1ibL4aAIGmSAt9slTE1Xgw5KWuof2uTOvCg9BY7ZRi+GaF+7sfgPeQ==} + typesafe-path@0.2.2: + resolution: {integrity: sha512-OJabfkAg1WLZSqJAJ0Z6Sdt3utnbzr/jh+NAHoyWHJe8CMSy79Gm085094M9nvTPy22KzTVn5Zq5mbapCI/hPA==} + + typescript-auto-import-cache@0.3.6: + resolution: {integrity: sha512-RpuHXrknHdVdK7wv/8ug3Fr0WNsNi5l5aB8MYYuXhq2UH5lnEB1htJ1smhtD5VeCsGr2p8mUDtd83LCQDFVgjQ==} + + typescript@5.9.3: + resolution: {integrity: sha512-jl1vZzPDinLr9eUt3J/t7V6FgNEw9QjvBPdysz9KfQDD41fQrC2Y4vKQdiaUpFT4bXlb1RHhLpp8wtm6M5TgSw==} engines: {node: '>=14.17'} hasBin: true @@ -2588,6 +2757,75 @@ packages: vite: optional: true + volar-service-css@0.0.70: + resolution: {integrity: sha512-K1qyOvBpE3rzdAv3e4/6Rv5yizrYPy5R/ne3IWCAzLBuMO4qBMV3kSqWzj6KUVe6S0AnN6wxF7cRkiaKfYMYJw==} + peerDependencies: + '@volar/language-service': ~2.4.0 + peerDependenciesMeta: + '@volar/language-service': + optional: true + + volar-service-emmet@0.0.70: + resolution: {integrity: sha512-xi5bC4m/VyE3zy/n2CXspKeDZs3qA41tHLTw275/7dNWM/RqE2z3BnDICQybHIVp/6G1iOQj5c1qXMgQC08TNg==} + peerDependencies: + '@volar/language-service': ~2.4.0 + peerDependenciesMeta: + '@volar/language-service': + optional: true + + volar-service-html@0.0.70: + resolution: {integrity: sha512-eR6vCgMdmYAo4n+gcT7DSyBQbwB8S3HZZvSagTf0sxNaD4WppMCFfpqWnkrlGStPKMZvMiejRRVmqsX9dYcTvQ==} + peerDependencies: + '@volar/language-service': ~2.4.0 + peerDependenciesMeta: + '@volar/language-service': + optional: true + + volar-service-prettier@0.0.70: + resolution: {integrity: sha512-Z6BCFSpGVCd8BPAsZ785Kce1BGlWd5ODqmqZGVuB14MJvrR4+CYz6cDy4F+igmE1gMifqfvMhdgT8Aud4M5ngg==} + peerDependencies: + '@volar/language-service': ~2.4.0 + prettier: ^2.2 || ^3.0 + peerDependenciesMeta: + '@volar/language-service': + optional: true + prettier: + optional: true + + volar-service-typescript-twoslash-queries@0.0.70: + resolution: {integrity: sha512-IdD13Z9N2Bu8EM6CM0fDV1E69olEYGHDU25X51YXmq8Y0CmJ2LNj6gOiBJgpS5JGUqFzECVhMNBW7R0sPdRTMQ==} + peerDependencies: + '@volar/language-service': ~2.4.0 + peerDependenciesMeta: + '@volar/language-service': + optional: true + + volar-service-typescript@0.0.70: + resolution: {integrity: sha512-l46Bx4cokkUedTd74ojO5H/zqHZJ8SUuyZ0IB8JN4jfRqUM3bQFBHoOwlZCyZmOeO0A3RQNkMnFclxO4c++gsg==} + peerDependencies: + '@volar/language-service': ~2.4.0 + peerDependenciesMeta: + '@volar/language-service': + optional: true + + volar-service-yaml@0.0.70: + resolution: {integrity: sha512-0c8bXDBeoATF9F6iPIlOuYTuZAC4c+yi0siQo920u7eiBJk8oQmUmg9cDUbR4+Gl++bvGP4plj3fErbJuPqdcQ==} + peerDependencies: + '@volar/language-service': ~2.4.0 + peerDependenciesMeta: + '@volar/language-service': + optional: true + + vscode-css-languageservice@6.3.10: + resolution: {integrity: sha512-eq5N9Er3fC4vA9zd9EFhyBG90wtCCuXgRSpAndaOgXMh1Wgep5lBgRIeDgjZBW9pa+332yC9+49cZMW8jcL3MA==} + + vscode-html-languageservice@5.6.2: + resolution: {integrity: sha512-ulCrSnFnfQ16YzvwnYUgEbUEl/ZG7u2eV27YhvLObSHKkb8fw1Z9cgsnUwjTEeDIdJDoTDTDpxuhQwoenoLNMg==} + + vscode-json-languageservice@4.1.8: + resolution: {integrity: sha512-0vSpg6Xd9hfV+eZAaYN63xVVMOTmJ4GgHxXnkLCh+9RsQBkWKIghzLhW2B9ebfG+LQQg8uLtsQ2aUKjTgE+QOg==} + engines: {npm: '>=7.0.0'} + vscode-jsonrpc@8.2.0: resolution: {integrity: sha512-C+r0eKJUIfiDIfwJhria30+TYWPtuHJXHtI7J0YlOmKAo7ogxP20T0zxB7HZQIFhIyvoBPwWskjxrvAtfjyZfA==} engines: {node: '>=14.0.0'} @@ -2605,9 +2843,15 @@ packages: resolution: {integrity: sha512-woByF3PDpkHFUreUa7Hos7+pUWdeWMXRd26+ZX2A8cFx6v/JPTtd4/uN0/jB6XQHYaOlHbio03NTHCqrgG5n7g==} hasBin: true + vscode-nls@5.2.0: + resolution: {integrity: sha512-RAaHx7B14ZU04EU31pT+rKz2/zSl7xMsfIZuo8pd+KZO6PXtQmpevpq3vxvWNcrGbdmhM/rr5Uw5Mz+NBfhVng==} + vscode-uri@3.0.8: resolution: {integrity: sha512-AyFQ0EVmsOZOlAnxoFOGOq1SQDWAB7C6aqMGS23svWAllfOaxbuFvcT8D1i8z3Gyn8fraVeZNNmN6e9bxxXkKw==} + vscode-uri@3.1.0: + resolution: {integrity: sha512-/BpdSx+yCQGnCvecbyXdxHDkuk55/G3xwnC0GqY4gmQ3j+A+g8kzzgB4Nk/SINjqn6+waqw3EgbVF2QKExkRxQ==} + web-namespaces@2.0.1: resolution: {integrity: sha512-bKr1DkiNa2krS7qxNtdrtHAmzuYGFQLiQ13TsorsdT6ULTkPLKuu5+GsFpDlg6JFjUTwX2DyhMPG2be8uPrqsQ==} @@ -2619,6 +2863,10 @@ packages: resolution: {integrity: sha512-c9bZp7b5YtRj2wOe6dlj32MK+Bx/M/d+9VB2SHM1OtsUHR0aV0tdP6DWh/iMt0kWi1t5g1Iudu6hQRNd1A4PVA==} engines: {node: '>=18'} + wrap-ansi@7.0.0: + resolution: {integrity: sha512-YVGIj2kamLSTxw6NsZjoBxfSwsn0ycdesmc4p+Q21c5zPuZ1pl+NfxVdxPtdHvmNVOQ6XSYG4AUtyt/Fi7D16Q==} + engines: {node: '>=10'} + wrap-ansi@9.0.0: resolution: {integrity: sha512-G8ura3S+3Z2G+mkgNRq8dqaFZAuxfsxpBB8OCTGRTCtp+l/v9nbFNmCUP1BZMts3G1142MsZfn6eeUKrr4PD1Q==} engines: {node: '>=18'} @@ -2626,10 +2874,32 @@ packages: xxhash-wasm@1.1.0: resolution: {integrity: sha512-147y/6YNh+tlp6nd/2pWq38i9h6mz/EuQ6njIrmW8D1BS5nCqs0P6DG+m6zTGnNz5I+uhZ0SHxBs9BsPrwcKDA==} + y18n@5.0.8: + resolution: {integrity: sha512-0pfFzegeDWJHJIAmTLRP2DwHjdF5s7jo9tuztdQxAhINCdvS+3nGINqPd00AphqJR/0LhANUS6/+7SCb98YOfA==} + engines: {node: '>=10'} + + yaml-language-server@1.20.0: + resolution: {integrity: sha512-qhjK/bzSRZ6HtTvgeFvjNPJGWdZ0+x5NREV/9XZWFjIGezew2b4r5JPy66IfOhd5OA7KeFwk1JfmEbnTvev0cA==} + hasBin: true + + yaml@2.7.1: + resolution: {integrity: sha512-10ULxpnOCQXxJvBgxsn9ptjq6uviG/htZKk9veJGhlqn3w/DxQ631zFF+nlQXLwmImeS5amR2dl2U8sg6U9jsQ==} + engines: {node: '>= 14'} + hasBin: true + + yaml@2.8.3: + resolution: {integrity: sha512-AvbaCLOO2Otw/lW5bmh9d/WEdcDFdQp2Z2ZUH3pX9U2ihyUY0nvLv7J6TrWowklRGPYbB/IuIMfYgxaCPg5Bpg==} + engines: {node: '>= 14.6'} + hasBin: true + yargs-parser@21.1.1: resolution: {integrity: sha512-tVpsJW7DdjecAiFpbIB1e3qxIQsE6NoPc5/eTdrbbIC4h0LVsWhnoa3g+m2HclBIujHzsxZ4VJVA+GUuc2/LBw==} engines: {node: '>=12'} + yargs@17.7.2: + resolution: {integrity: sha512-7dSzzRQ++CKnNI/krKnYRV7JKKPUXMEh61soaHKg9mrWEhzFWhFnxPxGl+69cD1Ou63C13NUPCnmIcrvqCuM6w==} + engines: {node: '>=12'} + yocto-queue@1.2.1: resolution: {integrity: sha512-AyeEbWOu/TAXdxlV9wmGcR0+yh2j3vYPGOECcIj2S7MkrLyC7ne+oye2BKTItt0ii2PHk4cDy+95+LshzbXnGg==} engines: {node: '>=12.20'} @@ -2671,14 +2941,53 @@ snapshots: '@antfu/utils@9.3.0': {} + '@astrojs/check@0.9.8(prettier-plugin-astro@0.14.1)(prettier@3.6.2)(typescript@5.9.3)': + dependencies: + '@astrojs/language-server': 2.16.6(prettier-plugin-astro@0.14.1)(prettier@3.6.2)(typescript@5.9.3) + chokidar: 4.0.3 + kleur: 4.1.5 + typescript: 5.9.3 + yargs: 17.7.2 + transitivePeerDependencies: + - prettier + - prettier-plugin-astro + '@astrojs/compiler@2.12.2': {} + '@astrojs/compiler@2.13.1': {} + '@astrojs/internal-helpers@0.6.1': {} '@astrojs/internal-helpers@0.7.1': {} '@astrojs/internal-helpers@0.7.4': {} + '@astrojs/language-server@2.16.6(prettier-plugin-astro@0.14.1)(prettier@3.6.2)(typescript@5.9.3)': + dependencies: + '@astrojs/compiler': 2.13.1 + '@astrojs/yaml2ts': 0.2.3 + '@jridgewell/sourcemap-codec': 1.5.5 + '@volar/kit': 2.4.28(typescript@5.9.3) + '@volar/language-core': 2.4.28 + '@volar/language-server': 2.4.28 + '@volar/language-service': 2.4.28 + muggle-string: 0.4.1 + tinyglobby: 0.2.16 + volar-service-css: 0.0.70(@volar/language-service@2.4.28) + volar-service-emmet: 0.0.70(@volar/language-service@2.4.28) + volar-service-html: 0.0.70(@volar/language-service@2.4.28) + volar-service-prettier: 0.0.70(@volar/language-service@2.4.28)(prettier@3.6.2) + volar-service-typescript: 0.0.70(@volar/language-service@2.4.28) + volar-service-typescript-twoslash-queries: 0.0.70(@volar/language-service@2.4.28) + volar-service-yaml: 0.0.70(@volar/language-service@2.4.28) + vscode-html-languageservice: 5.6.2 + vscode-uri: 3.1.0 + optionalDependencies: + prettier: 3.6.2 + prettier-plugin-astro: 0.14.1 + transitivePeerDependencies: + - typescript + '@astrojs/markdown-remark@6.3.2': dependencies: '@astrojs/internal-helpers': 0.6.1 @@ -2757,12 +3066,12 @@ snapshots: transitivePeerDependencies: - supports-color - '@astrojs/mdx@4.3.0(astro@5.15.4(@types/node@24.0.10)(jiti@2.6.1)(lightningcss@1.30.2)(rollup@4.44.1)(typescript@5.8.3))': + '@astrojs/mdx@4.3.0(astro@5.15.4(@types/node@24.0.10)(jiti@2.6.1)(lightningcss@1.30.2)(rollup@4.44.1)(typescript@5.9.3)(yaml@2.8.3))': dependencies: '@astrojs/markdown-remark': 6.3.2 '@mdx-js/mdx': 3.1.0(acorn@8.15.0) acorn: 8.15.0 - astro: 5.15.4(@types/node@24.0.10)(jiti@2.6.1)(lightningcss@1.30.2)(rollup@4.44.1)(typescript@5.8.3) + astro: 5.15.4(@types/node@24.0.10)(jiti@2.6.1)(lightningcss@1.30.2)(rollup@4.44.1)(typescript@5.9.3)(yaml@2.8.3) es-module-lexer: 1.7.0 estree-util-visit: 2.0.0 hast-util-to-html: 9.0.5 @@ -2786,22 +3095,22 @@ snapshots: stream-replace-string: 2.0.0 zod: 3.25.69 - '@astrojs/starlight-tailwind@4.0.2(@astrojs/starlight@0.36.2(astro@5.15.4(@types/node@24.0.10)(jiti@2.6.1)(lightningcss@1.30.2)(rollup@4.44.1)(typescript@5.8.3)))(tailwindcss@4.1.17)': + '@astrojs/starlight-tailwind@4.0.2(@astrojs/starlight@0.36.2(astro@5.15.4(@types/node@24.0.10)(jiti@2.6.1)(lightningcss@1.30.2)(rollup@4.44.1)(typescript@5.9.3)(yaml@2.8.3)))(tailwindcss@4.1.17)': dependencies: - '@astrojs/starlight': 0.36.2(astro@5.15.4(@types/node@24.0.10)(jiti@2.6.1)(lightningcss@1.30.2)(rollup@4.44.1)(typescript@5.8.3)) + '@astrojs/starlight': 0.36.2(astro@5.15.4(@types/node@24.0.10)(jiti@2.6.1)(lightningcss@1.30.2)(rollup@4.44.1)(typescript@5.9.3)(yaml@2.8.3)) tailwindcss: 4.1.17 - '@astrojs/starlight@0.36.2(astro@5.15.4(@types/node@24.0.10)(jiti@2.6.1)(lightningcss@1.30.2)(rollup@4.44.1)(typescript@5.8.3))': + '@astrojs/starlight@0.36.2(astro@5.15.4(@types/node@24.0.10)(jiti@2.6.1)(lightningcss@1.30.2)(rollup@4.44.1)(typescript@5.9.3)(yaml@2.8.3))': dependencies: '@astrojs/markdown-remark': 6.3.5 - '@astrojs/mdx': 4.3.0(astro@5.15.4(@types/node@24.0.10)(jiti@2.6.1)(lightningcss@1.30.2)(rollup@4.44.1)(typescript@5.8.3)) + '@astrojs/mdx': 4.3.0(astro@5.15.4(@types/node@24.0.10)(jiti@2.6.1)(lightningcss@1.30.2)(rollup@4.44.1)(typescript@5.9.3)(yaml@2.8.3)) '@astrojs/sitemap': 3.4.1 '@pagefind/default-ui': 1.3.0 '@types/hast': 3.0.4 '@types/js-yaml': 4.0.9 '@types/mdast': 4.0.4 - astro: 5.15.4(@types/node@24.0.10)(jiti@2.6.1)(lightningcss@1.30.2)(rollup@4.44.1)(typescript@5.8.3) - astro-expressive-code: 0.41.2(astro@5.15.4(@types/node@24.0.10)(jiti@2.6.1)(lightningcss@1.30.2)(rollup@4.44.1)(typescript@5.8.3)) + astro: 5.15.4(@types/node@24.0.10)(jiti@2.6.1)(lightningcss@1.30.2)(rollup@4.44.1)(typescript@5.9.3)(yaml@2.8.3) + astro-expressive-code: 0.41.2(astro@5.15.4(@types/node@24.0.10)(jiti@2.6.1)(lightningcss@1.30.2)(rollup@4.44.1)(typescript@5.9.3)(yaml@2.8.3)) bcp-47: 2.1.0 hast-util-from-html: 2.0.3 hast-util-select: 6.0.4 @@ -2836,6 +3145,10 @@ snapshots: transitivePeerDependencies: - supports-color + '@astrojs/yaml2ts@0.2.3': + dependencies: + yaml: 2.8.3 + '@babel/helper-string-parser@7.27.1': {} '@babel/helper-validator-identifier@7.27.1': {} @@ -2876,6 +3189,29 @@ snapshots: '@ctrl/tinycolor@4.1.0': {} + '@emmetio/abbreviation@2.3.3': + dependencies: + '@emmetio/scanner': 1.0.4 + + '@emmetio/css-abbreviation@2.1.8': + dependencies: + '@emmetio/scanner': 1.0.4 + + '@emmetio/css-parser@0.4.1': + dependencies: + '@emmetio/stream-reader': 2.2.0 + '@emmetio/stream-reader-utils': 0.1.0 + + '@emmetio/html-matcher@1.3.0': + dependencies: + '@emmetio/scanner': 1.0.4 + + '@emmetio/scanner@1.0.4': {} + + '@emmetio/stream-reader-utils@0.1.0': {} + + '@emmetio/stream-reader@2.2.0': {} + '@emnapi/runtime@1.7.0': dependencies: tslib: 2.8.1 @@ -3365,12 +3701,12 @@ snapshots: '@tailwindcss/oxide-win32-arm64-msvc': 4.1.17 '@tailwindcss/oxide-win32-x64-msvc': 4.1.17 - '@tailwindcss/vite@4.1.17(vite@6.4.1(@types/node@24.0.10)(jiti@2.6.1)(lightningcss@1.30.2))': + '@tailwindcss/vite@4.1.17(vite@6.4.1(@types/node@24.0.10)(jiti@2.6.1)(lightningcss@1.30.2)(yaml@2.8.3))': dependencies: '@tailwindcss/node': 4.1.17 '@tailwindcss/oxide': 4.1.17 tailwindcss: 4.1.17 - vite: 6.4.1(@types/node@24.0.10)(jiti@2.6.1)(lightningcss@1.30.2) + vite: 6.4.1(@types/node@24.0.10)(jiti@2.6.1)(lightningcss@1.30.2)(yaml@2.8.3) '@types/d3-array@3.2.1': {} @@ -3544,12 +3880,73 @@ snapshots: '@ungap/structured-clone@1.3.0': {} + '@volar/kit@2.4.28(typescript@5.9.3)': + dependencies: + '@volar/language-service': 2.4.28 + '@volar/typescript': 2.4.28 + typesafe-path: 0.2.2 + typescript: 5.9.3 + vscode-languageserver-textdocument: 1.0.12 + vscode-uri: 3.1.0 + + '@volar/language-core@2.4.28': + dependencies: + '@volar/source-map': 2.4.28 + + '@volar/language-server@2.4.28': + dependencies: + '@volar/language-core': 2.4.28 + '@volar/language-service': 2.4.28 + '@volar/typescript': 2.4.28 + path-browserify: 1.0.1 + request-light: 0.7.0 + vscode-languageserver: 9.0.1 + vscode-languageserver-protocol: 3.17.5 + vscode-languageserver-textdocument: 1.0.12 + vscode-uri: 3.1.0 + + '@volar/language-service@2.4.28': + dependencies: + '@volar/language-core': 2.4.28 + vscode-languageserver-protocol: 3.17.5 + vscode-languageserver-textdocument: 1.0.12 + vscode-uri: 3.1.0 + + '@volar/source-map@2.4.28': {} + + '@volar/typescript@2.4.28': + dependencies: + '@volar/language-core': 2.4.28 + path-browserify: 1.0.1 + vscode-uri: 3.1.0 + + '@vscode/emmet-helper@2.11.0': + dependencies: + emmet: 2.4.11 + jsonc-parser: 2.3.1 + vscode-languageserver-textdocument: 1.0.12 + vscode-languageserver-types: 3.17.5 + vscode-uri: 3.1.0 + + '@vscode/l10n@0.0.18': {} + acorn-jsx@5.3.2(acorn@8.15.0): dependencies: acorn: 8.15.0 acorn@8.15.0: {} + ajv-draft-04@1.0.0(ajv@8.18.0): + optionalDependencies: + ajv: 8.18.0 + + ajv@8.18.0: + dependencies: + fast-deep-equal: 3.1.3 + fast-uri: 3.1.0 + json-schema-traverse: 1.0.0 + require-from-string: 2.0.2 + ansi-align@3.0.1: dependencies: string-width: 4.2.3 @@ -3562,6 +3959,10 @@ snapshots: ansi-regex@6.1.0: {} + ansi-styles@4.3.0: + dependencies: + color-convert: 2.0.1 + ansi-styles@6.2.1: {} anymatch@3.1.3: @@ -3579,20 +3980,20 @@ snapshots: astring@1.9.0: {} - astro-expressive-code@0.41.2(astro@5.15.4(@types/node@24.0.10)(jiti@2.6.1)(lightningcss@1.30.2)(rollup@4.44.1)(typescript@5.8.3)): + astro-expressive-code@0.41.2(astro@5.15.4(@types/node@24.0.10)(jiti@2.6.1)(lightningcss@1.30.2)(rollup@4.44.1)(typescript@5.9.3)(yaml@2.8.3)): dependencies: - astro: 5.15.4(@types/node@24.0.10)(jiti@2.6.1)(lightningcss@1.30.2)(rollup@4.44.1)(typescript@5.8.3) + astro: 5.15.4(@types/node@24.0.10)(jiti@2.6.1)(lightningcss@1.30.2)(rollup@4.44.1)(typescript@5.9.3)(yaml@2.8.3) rehype-expressive-code: 0.41.2 - astro-mermaid@1.1.0(astro@5.15.4(@types/node@24.0.10)(jiti@2.6.1)(lightningcss@1.30.2)(rollup@4.44.1)(typescript@5.8.3))(mermaid@11.12.1): + astro-mermaid@1.1.0(astro@5.15.4(@types/node@24.0.10)(jiti@2.6.1)(lightningcss@1.30.2)(rollup@4.44.1)(typescript@5.9.3)(yaml@2.8.3))(mermaid@11.12.1): dependencies: - astro: 5.15.4(@types/node@24.0.10)(jiti@2.6.1)(lightningcss@1.30.2)(rollup@4.44.1)(typescript@5.8.3) + astro: 5.15.4(@types/node@24.0.10)(jiti@2.6.1)(lightningcss@1.30.2)(rollup@4.44.1)(typescript@5.9.3)(yaml@2.8.3) import-meta-resolve: 4.2.0 mdast-util-to-string: 4.0.0 mermaid: 11.12.1 unist-util-visit: 5.0.0 - astro@5.15.4(@types/node@24.0.10)(jiti@2.6.1)(lightningcss@1.30.2)(rollup@4.44.1)(typescript@5.8.3): + astro@5.15.4(@types/node@24.0.10)(jiti@2.6.1)(lightningcss@1.30.2)(rollup@4.44.1)(typescript@5.9.3)(yaml@2.8.3): dependencies: '@astrojs/compiler': 2.12.2 '@astrojs/internal-helpers': 0.7.4 @@ -3642,20 +4043,20 @@ snapshots: smol-toml: 1.4.2 tinyexec: 1.0.1 tinyglobby: 0.2.14 - tsconfck: 3.1.6(typescript@5.8.3) + tsconfck: 3.1.6(typescript@5.9.3) ultrahtml: 1.6.0 unifont: 0.6.0 unist-util-visit: 5.0.0 unstorage: 1.17.2 vfile: 6.0.3 - vite: 6.4.1(@types/node@24.0.10)(jiti@2.6.1)(lightningcss@1.30.2) - vitefu: 1.1.1(vite@6.4.1(@types/node@24.0.10)(jiti@2.6.1)(lightningcss@1.30.2)) + vite: 6.4.1(@types/node@24.0.10)(jiti@2.6.1)(lightningcss@1.30.2)(yaml@2.8.3) + vitefu: 1.1.1(vite@6.4.1(@types/node@24.0.10)(jiti@2.6.1)(lightningcss@1.30.2)(yaml@2.8.3)) xxhash-wasm: 1.1.0 yargs-parser: 21.1.1 yocto-spinner: 0.2.3 zod: 3.25.76 zod-to-json-schema: 3.24.6(zod@3.25.76) - zod-to-ts: 1.2.0(typescript@5.8.3)(zod@3.25.76) + zod-to-ts: 1.2.0(typescript@5.9.3)(zod@3.25.76) optionalDependencies: sharp: 0.34.5 transitivePeerDependencies: @@ -3762,12 +4163,24 @@ snapshots: cli-boxes@3.0.0: {} + cliui@8.0.1: + dependencies: + string-width: 4.2.3 + strip-ansi: 6.0.1 + wrap-ansi: 7.0.0 + clone@2.1.2: {} clsx@2.1.1: {} collapse-white-space@2.1.0: {} + color-convert@2.0.1: + dependencies: + color-name: 1.1.4 + + color-name@1.1.4: {} + comma-separated-tokens@2.0.3: {} commander@7.2.0: {} @@ -4039,6 +4452,11 @@ snapshots: dset@3.1.4: {} + emmet@2.4.11: + dependencies: + '@emmetio/abbreviation': 2.3.3 + '@emmetio/css-abbreviation': 2.1.8 + emoji-regex@10.4.0: {} emoji-regex@8.0.0: {} @@ -4096,6 +4514,8 @@ snapshots: '@esbuild/win32-ia32': 0.25.5 '@esbuild/win32-x64': 0.25.5 + escalade@3.2.0: {} + escape-string-regexp@5.0.0: {} estree-util-attach-comments@3.0.0: @@ -4148,6 +4568,8 @@ snapshots: fast-deep-equal@3.1.3: {} + fast-uri@3.1.0: {} + fdir@6.4.6(picomatch@4.0.2): optionalDependencies: picomatch: 4.0.2 @@ -4156,6 +4578,10 @@ snapshots: optionalDependencies: picomatch: 4.0.3 + fdir@6.5.0(picomatch@4.0.4): + optionalDependencies: + picomatch: 4.0.4 + flattie@1.1.1: {} fontace@0.3.0: @@ -4178,6 +4604,8 @@ snapshots: fsevents@2.3.3: optional: true + get-caller-file@2.0.5: {} + get-east-asian-width@1.3.0: {} git-hooks-list@4.1.1: {} @@ -4454,6 +4882,12 @@ snapshots: dependencies: argparse: 2.0.1 + json-schema-traverse@1.0.0: {} + + jsonc-parser@2.3.1: {} + + jsonc-parser@3.3.1: {} + katex@0.16.22: dependencies: commander: 8.3.0 @@ -5052,6 +5486,8 @@ snapshots: ms@2.1.3: {} + muggle-string@0.4.1: {} + nanoid@3.3.11: {} neotraverse@0.6.18: {} @@ -5134,6 +5570,8 @@ snapshots: dependencies: entities: 6.0.1 + path-browserify@1.0.1: {} + path-data-parser@0.1.0: {} pathe@2.0.3: {} @@ -5146,6 +5584,8 @@ snapshots: picomatch@4.0.3: {} + picomatch@4.0.4: {} + pkg-types@1.3.1: dependencies: confbox: 0.1.8 @@ -5358,6 +5798,14 @@ snapshots: mdast-util-to-markdown: 2.1.2 unified: 11.0.5 + request-light@0.5.8: {} + + request-light@0.7.0: {} + + require-directory@2.1.1: {} + + require-from-string@2.0.2: {} + restructure@3.0.2: {} retext-latin@4.0.0: @@ -5520,9 +5968,9 @@ snapshots: space-separated-tokens@2.0.2: {} - starlight-links-validator@0.19.1(@astrojs/starlight@0.36.2(astro@5.15.4(@types/node@24.0.10)(jiti@2.6.1)(lightningcss@1.30.2)(rollup@4.44.1)(typescript@5.8.3))): + starlight-links-validator@0.19.1(@astrojs/starlight@0.36.2(astro@5.15.4(@types/node@24.0.10)(jiti@2.6.1)(lightningcss@1.30.2)(rollup@4.44.1)(typescript@5.9.3)(yaml@2.8.3))): dependencies: - '@astrojs/starlight': 0.36.2(astro@5.15.4(@types/node@24.0.10)(jiti@2.6.1)(lightningcss@1.30.2)(rollup@4.44.1)(typescript@5.8.3)) + '@astrojs/starlight': 0.36.2(astro@5.15.4(@types/node@24.0.10)(jiti@2.6.1)(lightningcss@1.30.2)(rollup@4.44.1)(typescript@5.9.3)(yaml@2.8.3)) '@types/picomatch': 3.0.2 github-slugger: 2.0.0 hast-util-from-html: 2.0.3 @@ -5607,21 +6055,32 @@ snapshots: fdir: 6.4.6(picomatch@4.0.2) picomatch: 4.0.2 + tinyglobby@0.2.16: + dependencies: + fdir: 6.5.0(picomatch@4.0.4) + picomatch: 4.0.4 + trim-lines@3.0.1: {} trough@2.2.0: {} ts-dedent@2.2.0: {} - tsconfck@3.1.6(typescript@5.8.3): + tsconfck@3.1.6(typescript@5.9.3): optionalDependencies: - typescript: 5.8.3 + typescript: 5.9.3 tslib@2.8.1: {} type-fest@4.41.0: {} - typescript@5.8.3: {} + typesafe-path@0.2.2: {} + + typescript-auto-import-cache@0.3.6: + dependencies: + semver: 7.7.3 + + typescript@5.9.3: {} ufo@1.6.1: {} @@ -5733,7 +6192,7 @@ snapshots: '@types/unist': 3.0.3 vfile-message: 4.0.2 - vite@6.4.1(@types/node@24.0.10)(jiti@2.6.1)(lightningcss@1.30.2): + vite@6.4.1(@types/node@24.0.10)(jiti@2.6.1)(lightningcss@1.30.2)(yaml@2.8.3): dependencies: esbuild: 0.25.5 fdir: 6.4.6(picomatch@4.0.3) @@ -5746,10 +6205,89 @@ snapshots: fsevents: 2.3.3 jiti: 2.6.1 lightningcss: 1.30.2 + yaml: 2.8.3 - vitefu@1.1.1(vite@6.4.1(@types/node@24.0.10)(jiti@2.6.1)(lightningcss@1.30.2)): + vitefu@1.1.1(vite@6.4.1(@types/node@24.0.10)(jiti@2.6.1)(lightningcss@1.30.2)(yaml@2.8.3)): optionalDependencies: - vite: 6.4.1(@types/node@24.0.10)(jiti@2.6.1)(lightningcss@1.30.2) + vite: 6.4.1(@types/node@24.0.10)(jiti@2.6.1)(lightningcss@1.30.2)(yaml@2.8.3) + + volar-service-css@0.0.70(@volar/language-service@2.4.28): + dependencies: + vscode-css-languageservice: 6.3.10 + vscode-languageserver-textdocument: 1.0.12 + vscode-uri: 3.1.0 + optionalDependencies: + '@volar/language-service': 2.4.28 + + volar-service-emmet@0.0.70(@volar/language-service@2.4.28): + dependencies: + '@emmetio/css-parser': 0.4.1 + '@emmetio/html-matcher': 1.3.0 + '@vscode/emmet-helper': 2.11.0 + vscode-uri: 3.1.0 + optionalDependencies: + '@volar/language-service': 2.4.28 + + volar-service-html@0.0.70(@volar/language-service@2.4.28): + dependencies: + vscode-html-languageservice: 5.6.2 + vscode-languageserver-textdocument: 1.0.12 + vscode-uri: 3.1.0 + optionalDependencies: + '@volar/language-service': 2.4.28 + + volar-service-prettier@0.0.70(@volar/language-service@2.4.28)(prettier@3.6.2): + dependencies: + vscode-uri: 3.1.0 + optionalDependencies: + '@volar/language-service': 2.4.28 + prettier: 3.6.2 + + volar-service-typescript-twoslash-queries@0.0.70(@volar/language-service@2.4.28): + dependencies: + vscode-uri: 3.1.0 + optionalDependencies: + '@volar/language-service': 2.4.28 + + volar-service-typescript@0.0.70(@volar/language-service@2.4.28): + dependencies: + path-browserify: 1.0.1 + semver: 7.7.3 + typescript-auto-import-cache: 0.3.6 + vscode-languageserver-textdocument: 1.0.12 + vscode-nls: 5.2.0 + vscode-uri: 3.1.0 + optionalDependencies: + '@volar/language-service': 2.4.28 + + volar-service-yaml@0.0.70(@volar/language-service@2.4.28): + dependencies: + vscode-uri: 3.1.0 + yaml-language-server: 1.20.0 + optionalDependencies: + '@volar/language-service': 2.4.28 + + vscode-css-languageservice@6.3.10: + dependencies: + '@vscode/l10n': 0.0.18 + vscode-languageserver-textdocument: 1.0.12 + vscode-languageserver-types: 3.17.5 + vscode-uri: 3.1.0 + + vscode-html-languageservice@5.6.2: + dependencies: + '@vscode/l10n': 0.0.18 + vscode-languageserver-textdocument: 1.0.12 + vscode-languageserver-types: 3.17.5 + vscode-uri: 3.1.0 + + vscode-json-languageservice@4.1.8: + dependencies: + jsonc-parser: 3.3.1 + vscode-languageserver-textdocument: 1.0.12 + vscode-languageserver-types: 3.17.5 + vscode-nls: 5.2.0 + vscode-uri: 3.1.0 vscode-jsonrpc@8.2.0: {} @@ -5766,8 +6304,12 @@ snapshots: dependencies: vscode-languageserver-protocol: 3.17.5 + vscode-nls@5.2.0: {} + vscode-uri@3.0.8: {} + vscode-uri@3.1.0: {} + web-namespaces@2.0.1: {} which-pm-runs@1.1.0: {} @@ -5776,6 +6318,12 @@ snapshots: dependencies: string-width: 7.2.0 + wrap-ansi@7.0.0: + dependencies: + ansi-styles: 4.3.0 + string-width: 4.2.3 + strip-ansi: 6.0.1 + wrap-ansi@9.0.0: dependencies: ansi-styles: 6.2.1 @@ -5784,8 +6332,38 @@ snapshots: xxhash-wasm@1.1.0: {} + y18n@5.0.8: {} + + yaml-language-server@1.20.0: + dependencies: + '@vscode/l10n': 0.0.18 + ajv: 8.18.0 + ajv-draft-04: 1.0.0(ajv@8.18.0) + prettier: 3.6.2 + request-light: 0.5.8 + vscode-json-languageservice: 4.1.8 + vscode-languageserver: 9.0.1 + vscode-languageserver-textdocument: 1.0.12 + vscode-languageserver-types: 3.17.5 + vscode-uri: 3.1.0 + yaml: 2.7.1 + + yaml@2.7.1: {} + + yaml@2.8.3: {} + yargs-parser@21.1.1: {} + yargs@17.7.2: + dependencies: + cliui: 8.0.1 + escalade: 3.2.0 + get-caller-file: 2.0.5 + require-directory: 2.1.1 + string-width: 4.2.3 + y18n: 5.0.8 + yargs-parser: 21.1.1 + yocto-queue@1.2.1: {} yocto-spinner@0.2.3: @@ -5798,9 +6376,9 @@ snapshots: dependencies: zod: 3.25.76 - zod-to-ts@1.2.0(typescript@5.8.3)(zod@3.25.76): + zod-to-ts@1.2.0(typescript@5.9.3)(zod@3.25.76): dependencies: - typescript: 5.8.3 + typescript: 5.9.3 zod: 3.25.76 zod@3.25.69: {} diff --git a/docs/scripts/validate-docs-smoke.mjs b/docs/scripts/validate-docs-smoke.mjs new file mode 100644 index 00000000..483c2e63 --- /dev/null +++ b/docs/scripts/validate-docs-smoke.mjs @@ -0,0 +1,116 @@ +import { readFileSync, existsSync } from 'node:fs'; +import path from 'node:path'; +import { fileURLToPath } from 'node:url'; + +const __dirname = path.dirname(fileURLToPath(import.meta.url)); +const docsRoot = path.resolve(__dirname, '..'); +const repoRoot = path.resolve(docsRoot, '..'); + +function read(relativePath, base = repoRoot) { + return readFileSync(path.join(base, relativePath), 'utf8'); +} + +function assert(condition, message) { + if (!condition) { + throw new Error(message); + } +} + +function assertIncludes(content, expected, label) { + assert(content.includes(expected), `${label} is missing expected text: ${expected}`); +} + +const quickStart = read('docs/src/content/docs/essentials/quick-start.mdx'); +const snowflakeCli = read('docs/src/content/docs/guides/snowflake-cli.mdx'); +const troubleshooting = read('docs/src/content/docs/guides/troubleshooting.mdx'); +const runtimeModes = read('docs/src/content/docs/essentials/runtime-modes.mdx'); +const configuration = read('docs/src/content/docs/essentials/configuration.mdx'); +const supportMatrix = read('docs/src/content/docs/essentials/support-matrix.mdx'); +const dbtGuide = read('docs/src/content/docs/guides/dbt.mdx'); +const endToEndDbt = read('docs/src/content/docs/guides/end-to-end-dbt.mdx'); +const docsMaintenance = read('docs/src/content/docs/development/docs-maintenance.mdx'); +const awsLambda = read('docs/src/content/docs/guides/aws-lambda.mdx'); +const s3Tables = read('docs/src/content/docs/guides/s3-tables.mdx'); +const selfHosted = read('docs/src/content/docs/guides/self-hosted.mdx'); +const snowplow = read('docs/src/content/docs/guides/snowplow.mdx'); +const docsReadme = read('docs/README.md'); +const packageJson = JSON.parse(read('docs/package.json')); + +const highTrafficGuides = [ + 'docs/src/content/docs/essentials/quick-start.mdx', + 'docs/src/content/docs/essentials/runtime-modes.mdx', + 'docs/src/content/docs/guides/aws-lambda.mdx', + 'docs/src/content/docs/guides/dbt.mdx', + 'docs/src/content/docs/guides/end-to-end-dbt.mdx', + 'docs/src/content/docs/guides/self-hosted.mdx', + 'docs/src/content/docs/guides/snowplow.mdx', + 'docs/src/content/docs/guides/troubleshooting.mdx', +]; + +for (const guidePath of highTrafficGuides) { + const content = read(guidePath); + assert(/> Owner:/m.test(content), `${guidePath} must include an Owner block near the top`); + assert( + /> Last reviewed:/m.test(content), + `${guidePath} must include a Last reviewed block near the top`, + ); +} + +for (const filePath of ['config/metastore.yaml', 'crates/embucket-lambda/private-api.cfn.yaml']) { + assert( + existsSync(path.join(repoRoot, filePath)), + `Docs-referenced file does not exist: ${filePath}`, + ); +} + +for (const [content, label] of [ + [quickStart, 'Quick Start'], + [snowflakeCli, 'Snowflake CLI guide'], + [troubleshooting, 'Troubleshooting guide'], +]) { + assertIncludes(content, 'embucket/embucket', label); + assertIncludes(content, '3000', label); + assertIncludes(content, 'embucket', label); +} + +assertIncludes(quickStart, 'http://127.0.0.1:3000/', 'Quick Start'); +assertIncludes(runtimeModes, 'private-api.cfn.yaml', 'Runtime modes'); +assertIncludes(configuration, 'config/metastore.yaml', 'Configuration guide'); +assertIncludes(snowflakeCli, 'protocol = "http"', 'Snowflake CLI guide'); +assertIncludes(troubleshooting, 'protocol = "http"', 'Troubleshooting guide'); +assertIncludes(selfHosted, 'cargo build', 'Self-hosted guide'); +assertIncludes(selfHosted, 'target/debug/embucketd', 'Self-hosted guide'); +assertIncludes(selfHosted, 'snow connection test', 'Self-hosted guide'); +assertIncludes(selfHosted, 'evaluation and testing', 'Self-hosted guide'); +assertIncludes(snowplow, 'embucket-snowplow', 'Snowplow guide'); +assertIncludes(snowplow, 'dbt run', 'Snowplow guide'); +assertIncludes(snowplow, 'dbt show', 'Snowplow guide'); +assertIncludes(snowplow, 'compatibility workaround', 'Snowplow guide'); +assertIncludes(runtimeModes, '/guides/self-hosted/', 'Runtime modes'); +assertIncludes(runtimeModes, '/guides/snowplow/', 'Runtime modes'); +assertIncludes(supportMatrix, '/guides/self-hosted/', 'Support matrix'); +assertIncludes(supportMatrix, '/guides/snowplow/', 'Support matrix'); +assertIncludes(dbtGuide, '/guides/snowplow/', 'dbt guide'); +assertIncludes(endToEndDbt, '/guides/snowplow/', 'End-to-end dbt guide'); +assertIncludes(awsLambda, '/guides/snowplow/', 'AWS Lambda guide'); +assertIncludes(s3Tables, '/guides/snowplow/', 'S3 Tables guide'); +assertIncludes(docsMaintenance, 'Self-hosted local binary', 'Docs maintenance'); +assertIncludes(docsMaintenance, 'Snowplow web analytics', 'Docs maintenance'); + +const requiredCommands = [ + 'pnpm dev', + 'pnpm build', + 'pnpm preview', + 'pnpm astro', + 'pnpm format', + 'pnpm ncu', +]; +for (const command of requiredCommands) { + assertIncludes(docsReadme, command, 'docs/README.md'); +} + +for (const scriptName of ['astro', 'build', 'check', 'format', 'ncu', 'preview', 'smoke']) { + assert(scriptName in packageJson.scripts, `docs/package.json is missing script: ${scriptName}`); +} + +console.log('Docs smoke checks passed.'); diff --git a/docs/src/content/docs/development/docs-maintenance.mdx b/docs/src/content/docs/development/docs-maintenance.mdx new file mode 100644 index 00000000..a9a06375 --- /dev/null +++ b/docs/src/content/docs/development/docs-maintenance.mdx @@ -0,0 +1,69 @@ +--- +title: Docs maintenance +description: How the docs are validated, reviewed, and kept current. +sidebar: + order: 1 +--- + +> Owner: Embucket maintainers +> Last reviewed: 2026-04-07 + +This page documents the current release-gate process for docs changes. + +## What is validated automatically + +The repo already includes a docs CI workflow at `.github/workflows/docs-ci.yml`. + +On docs changes, it currently runs: + +- formatting checks +- `astro check` +- repo-safe docs smoke checks for repeated constants, guide metadata, and referenced local files +- a full docs build +- Vale linting + +The docs site also uses `starlight-links-validator` during the build. + +## What still needs manual smoke testing + +Before release, manually validate the commands in the highest-traffic guides: + +- `Quick Start` +- `Runtime modes` +- `Self-hosted local binary` +- `AWS Lambda` +- `dbt` +- `End-to-end dbt workflow` +- `Snowplow web analytics` +- `Troubleshooting` + +At minimum, confirm: + +- the local quick start still starts `embucket/embucket` +- the self-hosted guide still uses `cargo build` and can start `target/debug/embucketd` +- Snowflake CLI can still run a simple query against the documented path +- the Lambda guide still reflects the current deploy flow +- the dbt guide still matches the current `dbt-embucket` adapter contract +- the Snowplow guide still matches the current `embucket-snowplow` flow and uses `dbt run` plus `dbt show` as the success state + +The automated smoke checks are intentionally static. They do not call AWS, run dbt against a live Lambda, or execute Snowflake CLI against live infrastructure. + +## Owner and freshness convention + +Major guides should include a short block near the top with: + +- owner +- last reviewed date + +This repo now uses that pattern in the highest-traffic guides so readers can see which pages were reviewed recently. + +## Release checklist + +Before a release or launch push, confirm: + +1. current runtime names are consistent +2. quick-start ports and URLs still match the implementation +3. support claims still match verified workflows +4. docs CI is green +5. the top guides have a recent review date +6. self-hosted and Snowplow guides still match the current source repos and local commands From 44a41c9d5d9983a165af7d4ffa4e728ae6f3063b Mon Sep 17 00:00:00 2001 From: Sergei Turukin Date: Tue, 7 Apr 2026 17:53:37 -0700 Subject: [PATCH 03/25] Add self-hosted local binary guide Ultraworked with [Sisyphus](https://github.com/code-yeongyu/oh-my-openagent) Co-authored-by: Sisyphus --- docs/src/content/docs/guides/self-hosted.mdx | 147 +++++++++++++++++++ 1 file changed, 147 insertions(+) create mode 100644 docs/src/content/docs/guides/self-hosted.mdx diff --git a/docs/src/content/docs/guides/self-hosted.mdx b/docs/src/content/docs/guides/self-hosted.mdx new file mode 100644 index 00000000..455806d7 --- /dev/null +++ b/docs/src/content/docs/guides/self-hosted.mdx @@ -0,0 +1,147 @@ +--- +title: Self-hosted local binary +description: Build and run embucketd from source for local evaluation and testing. +sidebar: + order: 2 +--- + +import { Aside } from '@astrojs/starlight/components'; + +> Owner: Embucket maintainers +> Last reviewed: 2026-04-07 + +Use this guide when you want to build `embucketd` from source and run it locally. This path is currently for **evaluation and testing**, not the primary production deployment recommendation. + + + +## What you will do + +- build the workspace from source with `cargo build` +- start `target/debug/embucketd` with local config +- connect Snowflake CLI to the local deployment +- run a query successfully + +## Prerequisites + +- Rust toolchain +- Python 3.8 or newer +- Snowflake CLI +- a clone of `Embucket/embucket` + +## Step 1: Build the repo + +From the repository root: + +```bash +cargo build +``` + +The repo contributing guide uses `cargo build` as the standard source-build path. + +## Step 2: Create a local env file + +Copy the checked-in example env file: + +```bash +cp config/.env.example .env +``` + +That file sets: + +- `METASTORE_CONFIG=config/metastore.yaml` +- `JWT_SECRET=secret` +- `TRACING_LEVEL=debug` +- `RUST_LOG=info` + + + +## Step 3: Start the binary + +Run the local binary from the repo root: + +```bash +target/debug/embucketd +``` + +Expected startup signals: + +- the process stays running +- the service binds to `localhost:3000` +- you can open `http://127.0.0.1:3000/` in your browser + +## Step 4: Configure Snowflake CLI + +Find your Snowflake CLI config file: + +```bash +snow --info +``` + +Add this connection block: + +```toml +[connections.embucket] +host = "localhost" +region = "us-east-2" +port = 3000 +protocol = "http" +database = "embucket" +schema = "public" +warehouse = "em.wh" +account = "acc.local" +user = "embucket" +password = "embucket" +``` + +## Step 5: Verify the local deployment + +Validate the connection: + +```bash +snow connection test -c embucket +``` + +Run a query: + +```bash +snow sql -c embucket -q "SELECT 1 AS ok" +``` + +Expected output: + +```text ++----+ +| ok | +|----| +| 1 | ++----+ +``` + +## Current limits of this path + +- this is the current source-build local workflow for evaluation and testing +- it is not the recommended production deployment path +- the starter metastore config is minimal and does not populate example tables by itself + +If you need an external catalog or richer metadata, continue to [AWS S3 table bucket](/guides/s3-tables/). + +## Troubleshooting + +- **binary not found**: make sure `cargo build` completed successfully and run from the repo root +- **auth issues**: the local defaults are `embucket` / `embucket` unless you changed `AUTH_DEMO_USER` or `AUTH_DEMO_PASSWORD` +- **missing config**: make sure `.env` points at `config/metastore.yaml` +- **Snowflake CLI SSL/protocol errors**: set `protocol = "http"` + +## Related guides + +- [Quick Start](/essentials/quick-start/) +- [Snowflake CLI](/guides/snowflake-cli/) +- [Runtime modes](/essentials/runtime-modes/) +- [Troubleshooting](/guides/troubleshooting/) From a7d343a88ae6f371c0251e8ff3081c0c91a5a7e7 Mon Sep 17 00:00:00 2001 From: Sergei Turukin Date: Tue, 7 Apr 2026 17:53:37 -0700 Subject: [PATCH 04/25] Add Snowplow web analytics guide Ultraworked with [Sisyphus](https://github.com/code-yeongyu/oh-my-openagent) Co-authored-by: Sisyphus --- docs/src/content/docs/guides/snowplow.mdx | 161 ++++++++++++++++++++++ 1 file changed, 161 insertions(+) create mode 100644 docs/src/content/docs/guides/snowplow.mdx diff --git a/docs/src/content/docs/guides/snowplow.mdx b/docs/src/content/docs/guides/snowplow.mdx new file mode 100644 index 00000000..29cad4d4 --- /dev/null +++ b/docs/src/content/docs/guides/snowplow.mdx @@ -0,0 +1,161 @@ +--- +title: Snowplow web analytics +description: Run the embucket-snowplow example on the documented AWS Lambda plus dbt path. +sidebar: + order: 5 +--- + +import { Aside } from '@astrojs/starlight/components'; + +> Owner: Embucket maintainers +> Last reviewed: 2026-04-07 + +Use this guide when you want a fuller analytics example on top of the documented AWS Lambda + `dbt-embucket` workflow. This guide follows the public `Embucket/embucket-snowplow` repository. + + + +## What success looks like + +By the end of this guide, you should be able to: + +- deploy the Snowplow example runtime path on Lambda +- run `dbt run` successfully +- inspect derived results with `dbt show` + +## Prerequisites + +- AWS credentials +- an AWS S3 Table Bucket ARN +- `uv` or a Python environment that can run the example project +- Git + +## Step 1: Clone the example repo + +```bash +git clone https://github.com/Embucket/embucket-snowplow.git +cd embucket-snowplow +``` + +This example is designed to run without a Snowflake account. + +## Step 2: Set deploy-time values + +Set the stack name and S3 Table Bucket ARN: + +```bash +STACK_NAME="embucket-demo-$(whoami)-$(date +%s)" +BUCKET_ARN="arn:aws:s3tables:us-east-2:YOUR_ACCOUNT:bucket/YOUR_BUCKET" +``` + +Use your own deployment values here. Database, schema, credentials, and the Lambda ARN are all deployment-defined in this flow. + +## Step 3: Deploy the Lambda stack + +```bash +aws cloudformation deploy \ + --template-file deploy/embucket-lambda.cfn.yaml \ + --stack-name "$STACK_NAME" \ + --capabilities CAPABILITY_NAMED_IAM \ + --parameter-overrides S3TableBucketArn="$BUCKET_ARN" +``` + +Capture the Lambda ARN after deploy: + +```bash +LAMBDA_ARN=$(aws cloudformation describe-stacks --stack-name "$STACK_NAME" \ + --query 'Stacks[0].Outputs[?OutputKey==`LambdaFunctionArn`].OutputValue' \ + --output text) +echo "$LAMBDA_ARN" +``` + +## Step 4: Install dependencies + +```bash +uv sync +``` + +## Step 5: Configure the dbt profile + +Start from the example profile: + +```bash +cp profiles.yml.example profiles.yml +sed -i '' "s|YOUR_LAMBDA_ARN_HERE|$LAMBDA_ARN|" profiles.yml +``` + +Review the profile values before you run dbt. Credentials, database, and schema should match your deployment choices rather than a hardcoded docs default. + +## Step 6: Install dbt packages + +```bash +uv run dbt deps --profiles-dir . +``` + +## Step 7: Patch only if package checks require it + +Some dbt packages check `target.type == 'snowflake'` and do not recognize `embucket` yet. + +If your package has that kind of target-type check, run the example patch script: + +```bash +./scripts/patch_snowplow.sh +``` + +Treat this as a **compatibility workaround**. If your package already supports `embucket` or does not hardcode `snowflake` checks, prefer the unpatched path. + +## Step 8: Load the example source data + +```bash +uv run python scripts/load_data.py "$LAMBDA_ARN" +``` + +The example loader creates the required schemas and source tables for the Snowplow workflow. + +## Step 9: Run the pipeline + +```bash +uv run dbt seed --profiles-dir . +uv run dbt run --profiles-dir . +``` + +This is the primary success signal for the example workflow. + +## Step 10: Verify the results with `dbt show` + +Run `dbt show` against one of the derived relations produced by your deployment. + +For the official example layout, start with: + +```bash +uv run dbt show --profiles-dir . --inline "SELECT * FROM demo.atomic_derived.snowplow_web_page_views" --limit 10 +``` + +You can repeat that for other derived relations, for example: + +```bash +uv run dbt show --profiles-dir . --inline "SELECT * FROM demo.atomic_derived.snowplow_web_sessions" --limit 10 +uv run dbt show --profiles-dir . --inline "SELECT * FROM demo.atomic_derived.snowplow_web_users" --limit 10 +``` + +If your deployment uses different database or schema names, update the relation names accordingly. + +## Cleanup + +Delete the CloudFormation stack when you are done: + +```bash +aws cloudformation delete-stack --stack-name "$STACK_NAME" +``` + +The example repo notes that this does not remove data from your S3 Table Bucket automatically. + +## Related guides + +- [AWS Lambda](/guides/aws-lambda/) +- [dbt](/guides/dbt/) +- [End-to-end dbt workflow](/guides/end-to-end-dbt/) +- [Troubleshooting](/guides/troubleshooting/) From 41386a29ccf8bc45a423b91e057cf210f7a8bcde Mon Sep 17 00:00:00 2001 From: Sergei Turukin Date: Tue, 7 Apr 2026 17:53:37 -0700 Subject: [PATCH 05/25] Update Lambda and dbt workflow guides Ultraworked with [Sisyphus](https://github.com/code-yeongyu/oh-my-openagent) Co-authored-by: Sisyphus --- docs/src/content/docs/guides/aws-lambda.mdx | 235 ++++++++++++++++++ docs/src/content/docs/guides/dbt.mdx | 190 ++++++++++++++ .../content/docs/guides/end-to-end-dbt.mdx | 170 +++++++++++++ 3 files changed, 595 insertions(+) create mode 100644 docs/src/content/docs/guides/aws-lambda.mdx create mode 100644 docs/src/content/docs/guides/dbt.mdx create mode 100644 docs/src/content/docs/guides/end-to-end-dbt.mdx diff --git a/docs/src/content/docs/guides/aws-lambda.mdx b/docs/src/content/docs/guides/aws-lambda.mdx new file mode 100644 index 00000000..58c12711 --- /dev/null +++ b/docs/src/content/docs/guides/aws-lambda.mdx @@ -0,0 +1,235 @@ +--- +title: AWS Lambda +description: Build, deploy, verify, and operate the current Embucket Lambda runtime. +sidebar: + order: 0 +--- + +import { Aside } from '@astrojs/starlight/components'; + +> Owner: Embucket maintainers +> Last reviewed: 2026-04-07 + +Use this guide when you want the current serverless runtime. The runtime artifact is `embucket-lambda`, and the repo includes both build metadata and deployment helpers for it. + + + +## Prerequisites + +- Rust toolchain +- `cargo-lambda` +- AWS credentials with permission to deploy and invoke Lambda +- a metastore config under `config/` +- optional env file such as `config/.env.lambda` + +## Deployment modes + +The current repo supports two distinct Lambda access patterns: + +- **Function URL + Snowflake CLI** for validation and manual testing +- **direct Lambda invoke via `dbt-embucket`** for the recommended client path + +Treat them differently: + +- Function URL is convenient for quick validation +- direct Lambda invoke avoids exposing a public endpoint +- private API Gateway is the safer production-facing ingress shape + +## Runtime defaults and config surface + +Current deploy metadata in the repo sets: + +| Setting | Current default | +| ------------- | ----------------------- | +| binary name | `bootstrap` | +| memory | `3008` | +| timeout | `30` | +| tracing | `Active` | +| included file | `config/metastore.yaml` | + +Current deploy-time environment defaults in `Cargo.toml` are: + +| Variable | Default | +| ------------------ | ----------------------- | +| `LOG_FORMAT` | `json` | +| `METASTORE_CONFIG` | `config/metastore.yaml` | +| `TRACING_LEVEL` | `debug` | +| `RUST_LOG` | `info` | + +Optional deploy-time inputs exposed by the Makefile include: + +| Variable | Purpose | +| --------------------- | -------------------------------------------------------- | +| `FUNCTION_NAME` | override the Lambda function name | +| `ENV_FILE` | inject env vars from a file such as `config/.env.lambda` | +| `AWS_LAMBDA_ROLE_ARN` | supply an execution role when creating a new function | +| `WITH_OTEL_CONFIG` | include an OpenTelemetry collector config file | +| `FEATURES` | enable optional cargo features such as `streaming` | +| `LAYERS` | attach additional Lambda layers | + +## Step 1: Build and deploy + +From the repository root: + +```bash +make -C crates/embucket-lambda deploy +``` + +This path builds `embucket-lambda`, deploys the `bootstrap` binary, and creates a Function URL for the test path. + +If you want to supply an env file explicitly: + +```bash +ENV_FILE=config/.env.lambda make -C crates/embucket-lambda deploy +``` + +If you need to deploy a new function with an explicit execution role: + +```bash +AWS_LAMBDA_ROLE_ARN=arn:aws:iam::123456789012:role/embucket-lambda-role make -C crates/embucket-lambda deploy +``` + +## IAM and access model + +There are two IAM concerns in the current deployment story: + +1. **deployer permissions** for the human or CI identity running `cargo lambda deploy` +2. **execution role permissions** for the Lambda function itself + +The repo shows this explicitly: + +- the Makefile accepts `AWS_LAMBDA_ROLE_ARN` when creating a new function +- `dbt-embucket` uses AWS credentials to invoke the Lambda directly by ARN +- the private API template creates API Gateway permission to invoke the function + +At minimum, plan for: + +- permission to deploy or update the Lambda +- permission to read logs for verification +- permission for dbt clients to invoke the target function when using the recommended adapter path + +## Step 2: Verify the deployment + +The crate Makefile includes a built-in check: + +```bash +make -C crates/embucket-lambda verify +``` + +That runs: + +```bash +snow sql -c lambda -q "SELECT 1 as test_column" +``` + +You can also tail logs: + +```bash +make -C crates/embucket-lambda logs +``` + +For HTTP-level validation, the crate README also shows a direct login request: + +```bash +curl -X POST https://.lambda-url.us-east-2.on.aws/session/v1/login-request \ + -H "Content-Type: application/json" \ + -d '{"data": {"ACCOUNT_NAME": "account", "LOGIN_NAME": "embucket", "PASSWORD": "embucket", "CLIENT_APP_ID": "test"}}' +``` + +## What to verify before calling the deployment healthy + +- the function deploys successfully +- logs are readable in CloudWatch +- `snow sql -c lambda -q "SELECT 1 as test_column"` succeeds if you are validating the Function URL path +- `dbt debug` succeeds if you are validating the recommended adapter path +- the deployed config points at the intended metastore file + +## Step 3: Validate with Snowflake CLI over Function URL + +The current repo supports this as a test path. + +1. deploy the Lambda +2. capture the Function URL +3. create a `snow` connection that points to that URL +4. run a simple query such as `SELECT 1` + + + +## Step 4: Recommended production-facing ingress + +For production-facing traffic, keep the Lambda private and put an API gateway layer in front of it. + +The repo already includes a private REST API Gateway template at: + +```text +crates/embucket-lambda/private-api.cfn.yaml +``` + +That template provisions: + +- a private API Gateway +- a VPC endpoint for `execute-api` +- a Lambda proxy integration +- a stage named `v1` + +If your platform standard uses a custom domain, place it on top of the gateway layer rather than exposing a raw public Function URL. + +## Check limits and observability before rollout + +Before you treat a Lambda deployment as rollout-ready, check: + +- CloudWatch logs for runtime verification +- optional OpenTelemetry collector configuration via `WITH_OTEL_CONFIG` +- a state-store-backed pattern in production-style demos +- timeout and memory settings that match your expected workload +- whether your chosen ingress path matches your client path + +## Rollback and redeploy guidance + +The repo does not ship a one-command rollback wrapper, so the safest current guidance is operationally simple: + +1. keep the previous env file and metastore config under version control +2. keep the previously known-good deployment inputs +3. redeploy the function with the previous config if a change regresses behavior +4. re-run the same verification command you used before the change + +If you introduce API Gateway or other surrounding infrastructure, roll it back through the same IaC path that created it. + +## Step 5: Recommended client path + +After the Lambda is live, use the [dbt adapter](/guides/dbt/) for the primary documented workflow. + +If you want the shortest full walkthrough, follow [End-to-end dbt workflow](/guides/end-to-end-dbt/). + +If you want a fuller project example on the same runtime path, follow [Snowplow web analytics](/guides/snowplow/). + +## Cleanup + +If you used the Function URL test path and want to remove it: + +```bash +aws lambda delete-function-url-config --function-name embucket-lambda +``` + +Also clean up any surrounding resources you created for the deployment path you chose: + +- Lambda function +- CloudWatch log group +- API Gateway and VPC endpoint if you used the private ingress path +- extra telemetry layers or config files if you attached them + +Remove infrastructure with the same tool that created it so the Lambda, API, and network state do not drift apart. + +## Common failure modes + +- **deploy succeeds but queries fail**: check that `METASTORE_CONFIG` points to a real packaged file +- **dbt cannot connect**: check AWS credentials and `EMBUCKET_FUNCTION_ARN` +- **Snowflake CLI works but should not be public**: move to the private API Gateway path +- **timeouts or truncated responses**: review timeout, memory, and whether you need `streaming` +- **no useful traces**: verify `RUST_LOG`, `TRACING_LEVEL`, and any OTEL config you attached diff --git a/docs/src/content/docs/guides/dbt.mdx b/docs/src/content/docs/guides/dbt.mdx new file mode 100644 index 00000000..a23f2677 --- /dev/null +++ b/docs/src/content/docs/guides/dbt.mdx @@ -0,0 +1,190 @@ +--- +title: dbt +description: Use the official dbt-embucket adapter with the AWS Lambda runtime. +sidebar: + order: 1 +--- + +import { Aside, Steps } from '@astrojs/starlight/components'; + +> Owner: Embucket maintainers +> Last reviewed: 2026-04-07 + +This is the recommended client path in the current docs. + +The official adapter lives in the sibling repository `Embucket/dbt-embucket`. Its current configuration model is Lambda-based: the profile uses `type: embucket` and `function_arn` to reach a deployed Embucket Lambda. + +## What is currently verified + +The official adapter repository includes live integration tests that run `dbt debug` and `dbt run` against a real Embucket Lambda. + +## Prerequisites + +- a deployed Embucket Lambda +- the Lambda function ARN +- AWS credentials that can invoke the function +- Python and dbt installed locally + +## What this guide gives you + +This page is meant to be enough for a first successful setup: + +- install the adapter +- create a minimal project +- configure `profiles.yml` +- run `dbt debug` +- run `dbt run` on one model + +## Step 1: Install the adapter + +```bash +python -m pip install dbt-embucket +``` + +## Step 2: Create a minimal dbt project + +Create a new working directory and project files: + +```bash +mkdir embucket-dbt-demo +cd embucket-dbt-demo +mkdir -p models +``` + +Create `dbt_project.yml`: + +```yaml +name: embucket_demo +version: 1.0.0 +config-version: 2 + +profile: embucket + +model-paths: ['models'] + +models: + embucket_demo: + +materialized: view +``` + +Create `models/hello_embucket.sql`: + +```sql +select 1 as id, 'hello embucket' as message +``` + +## Step 3: Add a profile + +Add a profile like this to `profiles.yml`: + +```yaml +embucket: + target: dev + outputs: + dev: + type: embucket + function_arn: "{{ env_var('EMBUCKET_FUNCTION_ARN') }}" + account: "{{ env_var('EMBUCKET_ACCOUNT', 'embucket') }}" + user: "{{ env_var('EMBUCKET_USER', 'embucket') }}" + password: "{{ env_var('EMBUCKET_PASSWORD', 'embucket') }}" + database: "{{ env_var('EMBUCKET_DATABASE', 'demo') }}" + schema: public + threads: 1 +``` + +Export the Lambda ARN before running dbt: + +```bash +export EMBUCKET_FUNCTION_ARN=arn:aws:lambda:us-east-2:123456789012:function:embucket-lambda +``` + +If you want to keep credentials out of the file, also export these as needed: + +```bash +export EMBUCKET_ACCOUNT=embucket +export EMBUCKET_USER=embucket +export EMBUCKET_PASSWORD=embucket +export EMBUCKET_DATABASE=demo +``` + +### Profile field reference + +| Field | Required | Meaning | +| -------------- | -------- | ------------------------------------------ | +| `type` | yes | must be `embucket` | +| `function_arn` | yes | target Lambda ARN | +| `account` | yes | logical account name sent in login payload | +| `user` | yes | Embucket login name | +| `password` | yes | Embucket login password | +| `database` | yes | default database | +| `schema` | yes | default schema | +| `threads` | yes | dbt concurrency setting | + +## Step 4: Validate the connection + +```bash +dbt debug +``` + +Expected success signal: + +```text +Connection test: [OK connection ok] +All checks passed! +``` + +## Step 5: Run a model + +```bash +dbt run +``` + +Expected result: + +- dbt builds the `hello_embucket` model +- the run finishes successfully +- the object is available in the configured database and schema + +## Step 6: Verify the result from a client + +If you also have Snowflake CLI configured for the same environment, run: + +```bash +snow sql -c lambda -q "select * from demo.public.hello_embucket" +``` + +You should see one row with `id = 1` and `message = 'hello embucket'`. + + + +## Current caveats + +- the official adapter is currently documented as a Lambda transport, not a local-runtime transport +- the adapter explicitly marks Python models as unsupported +- the adapter uses AWS Lambda invoke semantics rather than a long-lived TCP connection +- use the support matrix when you need to distinguish verified paths from documented-only paths + +## Common setup problems + +- **`profiles.yml` not found**: make sure dbt can see your profiles directory +- **`EMBUCKET_FUNCTION_ARN` missing**: export it before `dbt debug` +- **AWS credentials missing**: the adapter needs AWS credentials that can invoke the Lambda +- **auth failures**: check `EMBUCKET_USER` and `EMBUCKET_PASSWORD` +- **runs succeed but expected data is missing**: check database, schema, and metastore configuration on the Lambda side + +## Next step + +If you want the full ordered path from deploy to verification, read [End-to-end dbt workflow](/guides/end-to-end-dbt/). + +If you want a larger analytics example on the same adapter path, read [Snowplow web analytics](/guides/snowplow/). + +## Related guides + +- [AWS Lambda](/guides/aws-lambda/) +- [End-to-end dbt workflow](/guides/end-to-end-dbt/) +- [Snowplow web analytics](/guides/snowplow/) +- [Support matrix](/essentials/support-matrix/) +- [Troubleshooting](/guides/troubleshooting/) diff --git a/docs/src/content/docs/guides/end-to-end-dbt.mdx b/docs/src/content/docs/guides/end-to-end-dbt.mdx new file mode 100644 index 00000000..1cfb9de1 --- /dev/null +++ b/docs/src/content/docs/guides/end-to-end-dbt.mdx @@ -0,0 +1,170 @@ +--- +title: End-to-end dbt workflow +description: Deploy Embucket on AWS Lambda, connect dbt-embucket, run a minimal model, and verify the result end to end. +sidebar: + order: 2 +--- + +import { Aside, Steps } from '@astrojs/starlight/components'; + +> Owner: Embucket maintainers +> Last reviewed: 2026-04-07 + +This guide is the shortest full workflow on the docs site. It takes you from a deployed Embucket Lambda to a successful dbt run and a verified query result. + + + +## What you need + +- AWS credentials +- a deployable Embucket checkout +- `cargo-lambda` +- Python with dbt and `dbt-embucket` +- a metastore config at `config/metastore.yaml` + +## Step 1: Deploy Embucket Lambda + +From the repo root: + +```bash +make -C crates/embucket-lambda deploy-only +``` + +If you want to inject an env file during deploy: + +```bash +ENV_FILE=config/.env.lambda make -C crates/embucket-lambda deploy-only +``` + +Record the function ARN for the next step. + +## Step 2: Install dbt-embucket + +```bash +python -m pip install dbt-embucket +``` + +## Step 3: Create a minimal dbt project + +```bash +mkdir embucket-dbt-demo +cd embucket-dbt-demo +mkdir -p models +``` + +Create `dbt_project.yml`: + +```yaml +name: embucket_demo +version: 1.0.0 +config-version: 2 + +profile: embucket + +model-paths: ['models'] + +models: + embucket_demo: + +materialized: view +``` + +Create `models/hello_embucket.sql`: + +```sql +select 1 as id, 'hello embucket' as message +``` + +## Step 4: Configure dbt + +Export the runtime values: + +```bash +export EMBUCKET_FUNCTION_ARN=arn:aws:lambda:us-east-2:123456789012:function:embucket-lambda +export EMBUCKET_ACCOUNT=embucket +export EMBUCKET_USER=embucket +export EMBUCKET_PASSWORD=embucket +export EMBUCKET_DATABASE=demo +``` + +Create `~/.dbt/profiles.yml`: + +```yaml +embucket: + target: dev + outputs: + dev: + type: embucket + function_arn: "{{ env_var('EMBUCKET_FUNCTION_ARN') }}" + account: "{{ env_var('EMBUCKET_ACCOUNT', 'embucket') }}" + user: "{{ env_var('EMBUCKET_USER', 'embucket') }}" + password: "{{ env_var('EMBUCKET_PASSWORD', 'embucket') }}" + database: "{{ env_var('EMBUCKET_DATABASE', 'demo') }}" + schema: public + threads: 1 +``` + +## Step 5: Validate the connection + +```bash +dbt debug +``` + +Look for: + +```text +Connection test: [OK connection ok] +All checks passed! +``` + +## Step 6: Run the model + +```bash +dbt run +``` + +The run should create a `hello_embucket` object in the configured target schema. + +## Step 7: Verify the result + +If you have a `snow` connection for the same deployed runtime, verify with: + +```bash +snow sql -c lambda -q "select * from demo.public.hello_embucket" +``` + +Expected result shape: + +```text ++----+-----------------+ +| id | message | +|----+-----------------| +| 1 | hello embucket | ++----+-----------------+ +``` + +## Step 8: Clean up + +When you are done, remove: + +- the demo dbt project directory +- any local exported env vars or shell profile changes +- the deployed Lambda if it was only for evaluation + +Use the same deployment path that created the Lambda to tear it down cleanly. + +## Common failure points + +- `dbt debug` fails because `EMBUCKET_FUNCTION_ARN` is missing +- AWS credentials exist locally but do not have permission to invoke the Lambda +- the Lambda points at the wrong metastore config +- the database or schema in the dbt profile does not match the target you expect + +## Where to go next + +- For deeper Lambda operations, read [AWS Lambda](/guides/aws-lambda/) +- For adapter details, read [dbt](/guides/dbt/) +- For a fuller analytics example on the same path, read [Snowplow web analytics](/guides/snowplow/) +- For known failure modes, read [Troubleshooting](/guides/troubleshooting/) From 913f953afe341ab5d31f5de518bf86904ca48fda Mon Sep 17 00:00:00 2001 From: Sergei Turukin Date: Tue, 7 Apr 2026 17:53:38 -0700 Subject: [PATCH 06/25] Update local evaluation guides Ultraworked with [Sisyphus](https://github.com/code-yeongyu/oh-my-openagent) Co-authored-by: Sisyphus --- .../content/docs/essentials/quick-start.mdx | 88 +++++--- .../src/content/docs/guides/snowflake-cli.mdx | 210 ++++++------------ .../content/docs/guides/troubleshooting.mdx | 143 ++++++++++++ 3 files changed, 266 insertions(+), 175 deletions(-) create mode 100644 docs/src/content/docs/guides/troubleshooting.mdx diff --git a/docs/src/content/docs/essentials/quick-start.mdx b/docs/src/content/docs/essentials/quick-start.mdx index b8c4d876..3f86d221 100644 --- a/docs/src/content/docs/essentials/quick-start.mdx +++ b/docs/src/content/docs/essentials/quick-start.mdx @@ -1,54 +1,59 @@ --- title: Quick Start -description: Get up and running with Embucket in under 5 minutes. From download to first query with zero dependencies. +description: Start Embucket locally, connect Snowflake CLI, and run a first query in the current test and evaluation path. sidebar: order: 0 --- import { Aside, Steps } from '@astrojs/starlight/components'; -This guide shows you how to start Embucket and run your first query in under 5 minutes. You use Embucket's single-binary architecture to start running queries. +> Owner: Embucket maintainers +> Last reviewed: 2026-04-07 -Read this guide to: +This quick start is the fastest way to evaluate Embucket locally. It is the current **test and evaluation** path, not the recommended production deployment path. -- Start Embucket with zero external dependencies -- Connect with the Snowflake command-line tool -- Run your first query +By the end of this guide, you will: -This guide doesn't cover production deployment or advanced configuration options. +- start the current `embucket/embucket` container +- connect Snowflake CLI to the local endpoint +- run a query successfully ## Step 1: Start Embucket -Start the Embucket server: +Run the local container: ```bash -docker run --name embucket --rm -p 3000:3000 embucket/embucket ./embucketd +docker run --name embucket --rm -p 3000:3000 embucket/embucket ``` -**Done.** You need no external dependencies, databases, or complex configuration. +Expected startup output includes a line like: -Embucket displays output like: - -``` +```text {"timestamp":"2025-07-01T15:35:05.687807Z","level":"INFO","fields":{"message":"Listening on http://0.0.0.0:3000"},"target":"embucketd"} ``` - +Install Snowflake CLI if you do not have it already: -## Step 2: Configure the Snowflake command-line tool +```bash +python -m pip install snowflake-cli +``` -Install and configure the Snowflake command-line tool against the local endpoint: +Find your Snowflake CLI config file: ```bash -$ pip install snowflake-cli -# Find the Snowflake command-line tool config file path -$ snow --info | grep "config_file_path" -A 1 -CONFIG= -cat <<'EOF' >> $CONFIG +snow --info +``` + +Add this connection block: + +```toml [connections.local] host = "localhost" region = "us-east-2" @@ -57,16 +62,20 @@ protocol = "http" database = "embucket" schema = "public" warehouse = "em.wh" -password = "embucket" account = "acc.local" user = "embucket" -EOF -$ snow connection test -c local +password = "embucket" ``` -Expected output: +Validate the connection: +```bash +snow connection test -c local ``` + +Expected output: + +```text +-----------------------------+ | key | value | |-----------------+-----------| @@ -83,15 +92,13 @@ Expected output: ## Step 3: Run your first query -Use the Snowflake command-line tool to run a query against the local Embucket instance: - ```bash -$ snow sql -c local -q "select dateadd(day, -1, current_timestamp()) as yesterday;" +snow sql -c local -q "select dateadd(day, -1, current_timestamp()) as yesterday;" ``` Expected output: -``` +```text +----------------------------------+ | yesterday | |----------------------------------| @@ -99,6 +106,21 @@ Expected output: +----------------------------------+ ``` -Open the browser to `http://127.0.0.1:8080` to explore Embucket's web interface, query editor, and data catalog. The interface resembles Snowflake's interface. +## Step 4: Inspect the HTTP surface + +Open `http://127.0.0.1:3000/` in your browser to inspect the current Swagger/OpenAPI surface served by `embucketd`. + + + +## Next steps - +- If you want to run the local binary from source instead of Docker, read [Self-hosted local binary](/guides/self-hosted/). +- If you want the current runtime choices, read [Runtime modes](/essentials/runtime-modes/). +- If you want serverless deployment, read [AWS Lambda](/guides/aws-lambda/). +- If you want the recommended client path, read [dbt](/guides/dbt/). +- If you want a fuller analytics example on the recommended path, read [Snowplow web analytics](/guides/snowplow/). +- If you want an external catalog, read [AWS S3 table bucket](/guides/s3-tables/). +- If something fails, read [Troubleshooting](/guides/troubleshooting/). diff --git a/docs/src/content/docs/guides/snowflake-cli.mdx b/docs/src/content/docs/guides/snowflake-cli.mdx index 1dbd474a..f8c44554 100644 --- a/docs/src/content/docs/guides/snowflake-cli.mdx +++ b/docs/src/content/docs/guides/snowflake-cli.mdx @@ -1,176 +1,102 @@ --- -title: Snowflake command-line tool -description: Use Snowflake command-line tool to query Embucket with familiar Snowflake commands and syntax. +title: Snowflake CLI +description: Connect Snowflake CLI to Embucket for the current local test and evaluation workflow. +sidebar: + order: 3 --- -import { Steps, Aside, Tabs, TabItem } from '@astrojs/starlight/components'; +import { Aside, Steps } from '@astrojs/starlight/components'; -Learn how to connect Snowflake command-line tool to Embucket. Run SQL queries with familiar Snowflake commands. Leverage your existing Snowflake workflows while accessing Embucket's data processing capabilities. +> Owner: Embucket maintainers +> Last reviewed: 2026-04-07 -This guide covers `snowflake-cli` configuration to connect to a local Embucket instance and execute SQL queries through the Snowflake-compatible API. This guide covers local development setup only. Production deployments, advanced authentication, and performance optimization remain outside this scope. +Use this guide when you want to run Snowflake CLI against a local Embucket instance. This is the current **local test and evaluation** client flow. -- Set up Snowflake command-line tool for local development -- Configure connection parameters specific to Embucket's API -- Test connectivity with sample data operations - -**Prerequisites:** you need Python 3.8+, Docker, and a running Embucket container. - -