@aws-blocks/core 0.1.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/LICENSE +174 -0
- package/dist/api.d.ts +147 -0
- package/dist/api.d.ts.map +1 -0
- package/dist/api.js +10 -0
- package/dist/api.test.d.ts +2 -0
- package/dist/api.test.d.ts.map +1 -0
- package/dist/api.test.js +19 -0
- package/dist/bb-utils.d.ts +11 -0
- package/dist/bb-utils.d.ts.map +1 -0
- package/dist/bb-utils.js +12 -0
- package/dist/builtin-routes.d.ts +6 -0
- package/dist/builtin-routes.d.ts.map +1 -0
- package/dist/builtin-routes.js +57 -0
- package/dist/cdk/__fixtures__/factory-backend.d.ts +3 -0
- package/dist/cdk/__fixtures__/factory-backend.d.ts.map +1 -0
- package/dist/cdk/__fixtures__/factory-backend.js +6 -0
- package/dist/cdk/__fixtures__/fullid-construct-backend.d.ts +2 -0
- package/dist/cdk/__fixtures__/fullid-construct-backend.d.ts.map +1 -0
- package/dist/cdk/__fixtures__/fullid-construct-backend.js +37 -0
- package/dist/cdk/__fixtures__/handler.d.ts +5 -0
- package/dist/cdk/__fixtures__/handler.d.ts.map +1 -0
- package/dist/cdk/__fixtures__/handler.js +3 -0
- package/dist/cdk/__fixtures__/side-effect-backend.d.ts +2 -0
- package/dist/cdk/__fixtures__/side-effect-backend.d.ts.map +1 -0
- package/dist/cdk/__fixtures__/side-effect-backend.js +5 -0
- package/dist/cdk/blocks-backend.d.ts +68 -0
- package/dist/cdk/blocks-backend.d.ts.map +1 -0
- package/dist/cdk/blocks-backend.js +214 -0
- package/dist/cdk/blocks-backend.test.d.ts +2 -0
- package/dist/cdk/blocks-backend.test.d.ts.map +1 -0
- package/dist/cdk/blocks-backend.test.js +151 -0
- package/dist/cdk/blocks-stack.test.d.ts +2 -0
- package/dist/cdk/blocks-stack.test.d.ts.map +1 -0
- package/dist/cdk/blocks-stack.test.js +78 -0
- package/dist/cdk/config-registry.d.ts +26 -0
- package/dist/cdk/config-registry.d.ts.map +1 -0
- package/dist/cdk/config-registry.js +80 -0
- package/dist/cdk/index.d.ts +35 -0
- package/dist/cdk/index.d.ts.map +1 -0
- package/dist/cdk/index.js +90 -0
- package/dist/cdk/mixins.d.ts +28 -0
- package/dist/cdk/mixins.d.ts.map +1 -0
- package/dist/cdk/mixins.js +37 -0
- package/dist/cdk/mixins.test.d.ts +2 -0
- package/dist/cdk/mixins.test.d.ts.map +1 -0
- package/dist/cdk/mixins.test.js +108 -0
- package/dist/cdk/node-version.d.ts +14 -0
- package/dist/cdk/node-version.d.ts.map +1 -0
- package/dist/cdk/node-version.js +15 -0
- package/dist/cdk/stack-metadata.d.ts +12 -0
- package/dist/cdk/stack-metadata.d.ts.map +1 -0
- package/dist/cdk/stack-metadata.js +22 -0
- package/dist/cdk/stack-metadata.test.d.ts +2 -0
- package/dist/cdk/stack-metadata.test.d.ts.map +1 -0
- package/dist/cdk/stack-metadata.test.js +56 -0
- package/dist/cdk/synth-guard.d.ts +14 -0
- package/dist/cdk/synth-guard.d.ts.map +1 -0
- package/dist/cdk/synth-guard.js +20 -0
- package/dist/cdk/synth-guard.test.d.ts +2 -0
- package/dist/cdk/synth-guard.test.d.ts.map +1 -0
- package/dist/cdk/synth-guard.test.js +15 -0
- package/dist/client/index.d.ts +97 -0
- package/dist/client/index.d.ts.map +1 -0
- package/dist/client/index.js +238 -0
- package/dist/client/index.test.d.ts +2 -0
- package/dist/client/index.test.d.ts.map +1 -0
- package/dist/client/index.test.js +113 -0
- package/dist/common/config.d.ts +45 -0
- package/dist/common/config.d.ts.map +1 -0
- package/dist/common/config.js +154 -0
- package/dist/common/config.test.d.ts +2 -0
- package/dist/common/config.test.d.ts.map +1 -0
- package/dist/common/config.test.js +173 -0
- package/dist/common/constants.d.ts +11 -0
- package/dist/common/constants.d.ts.map +1 -0
- package/dist/common/constants.js +12 -0
- package/dist/common/crypto.d.ts +6 -0
- package/dist/common/crypto.d.ts.map +1 -0
- package/dist/common/crypto.js +14 -0
- package/dist/common/index.d.ts +220 -0
- package/dist/common/index.d.ts.map +1 -0
- package/dist/common/index.js +180 -0
- package/dist/common/index.test.d.ts +2 -0
- package/dist/common/index.test.d.ts.map +1 -0
- package/dist/common/index.test.js +195 -0
- package/dist/common/mock-data.d.ts +40 -0
- package/dist/common/mock-data.d.ts.map +1 -0
- package/dist/common/mock-data.js +39 -0
- package/dist/common/official-bb-names.generated.d.ts +7 -0
- package/dist/common/official-bb-names.generated.d.ts.map +1 -0
- package/dist/common/official-bb-names.generated.js +28 -0
- package/dist/common/sdk-registry.d.ts +136 -0
- package/dist/common/sdk-registry.d.ts.map +1 -0
- package/dist/common/sdk-registry.js +125 -0
- package/dist/constants.d.ts +27 -0
- package/dist/constants.d.ts.map +1 -0
- package/dist/constants.js +28 -0
- package/dist/cors.d.ts +39 -0
- package/dist/cors.d.ts.map +1 -0
- package/dist/cors.js +85 -0
- package/dist/cors.test.d.ts +2 -0
- package/dist/cors.test.d.ts.map +1 -0
- package/dist/cors.test.js +241 -0
- package/dist/db-naming.d.ts +21 -0
- package/dist/db-naming.d.ts.map +1 -0
- package/dist/db-naming.js +38 -0
- package/dist/db-naming.test.d.ts +2 -0
- package/dist/db-naming.test.d.ts.map +1 -0
- package/dist/db-naming.test.js +29 -0
- package/dist/errors.d.ts +67 -0
- package/dist/errors.d.ts.map +1 -0
- package/dist/errors.js +69 -0
- package/dist/hosting.d.ts +258 -0
- package/dist/hosting.d.ts.map +1 -0
- package/dist/hosting.js +340 -0
- package/dist/hosting.test.d.ts +2 -0
- package/dist/hosting.test.d.ts.map +1 -0
- package/dist/hosting.test.js +1077 -0
- package/dist/index.cdk.d.ts +13 -0
- package/dist/index.cdk.d.ts.map +1 -0
- package/dist/index.cdk.js +13 -0
- package/dist/index.d.ts +9 -0
- package/dist/index.d.ts.map +1 -0
- package/dist/index.js +10 -0
- package/dist/lambda-handler.d.ts +131 -0
- package/dist/lambda-handler.d.ts.map +1 -0
- package/dist/lambda-handler.js +610 -0
- package/dist/lambda-handler.test.d.ts +2 -0
- package/dist/lambda-handler.test.d.ts.map +1 -0
- package/dist/lambda-handler.test.js +835 -0
- package/dist/pipeline/index.d.ts +4 -0
- package/dist/pipeline/index.d.ts.map +1 -0
- package/dist/pipeline/index.js +3 -0
- package/dist/pipeline/pipeline-construct.d.ts +130 -0
- package/dist/pipeline/pipeline-construct.d.ts.map +1 -0
- package/dist/pipeline/pipeline-construct.js +484 -0
- package/dist/pipeline/pipeline.test.d.ts +2 -0
- package/dist/pipeline/pipeline.test.d.ts.map +1 -0
- package/dist/pipeline/pipeline.test.js +1231 -0
- package/dist/pipeline/types.d.ts +351 -0
- package/dist/pipeline/types.d.ts.map +1 -0
- package/dist/pipeline/types.js +3 -0
- package/dist/raw-route.cdk.d.ts +47 -0
- package/dist/raw-route.cdk.d.ts.map +1 -0
- package/dist/raw-route.cdk.js +51 -0
- package/dist/raw-route.d.ts +119 -0
- package/dist/raw-route.d.ts.map +1 -0
- package/dist/raw-route.js +239 -0
- package/dist/raw-route.mock.d.ts +47 -0
- package/dist/raw-route.mock.d.ts.map +1 -0
- package/dist/raw-route.mock.js +51 -0
- package/dist/raw-route.test.d.ts +2 -0
- package/dist/raw-route.test.d.ts.map +1 -0
- package/dist/raw-route.test.js +597 -0
- package/dist/redact.d.ts +51 -0
- package/dist/redact.d.ts.map +1 -0
- package/dist/redact.js +134 -0
- package/dist/redact.test.d.ts +2 -0
- package/dist/redact.test.d.ts.map +1 -0
- package/dist/redact.test.js +199 -0
- package/dist/rpc.d.ts +54 -0
- package/dist/rpc.d.ts.map +1 -0
- package/dist/rpc.js +127 -0
- package/dist/rpc.test.d.ts +2 -0
- package/dist/rpc.test.d.ts.map +1 -0
- package/dist/rpc.test.js +60 -0
- package/dist/scripts/cdk-telemetry-env.d.ts +13 -0
- package/dist/scripts/cdk-telemetry-env.d.ts.map +1 -0
- package/dist/scripts/cdk-telemetry-env.js +21 -0
- package/dist/scripts/cdk-telemetry-env.test.d.ts +2 -0
- package/dist/scripts/cdk-telemetry-env.test.d.ts.map +1 -0
- package/dist/scripts/cdk-telemetry-env.test.js +56 -0
- package/dist/scripts/cleanup.d.ts +3 -0
- package/dist/scripts/cleanup.d.ts.map +1 -0
- package/dist/scripts/cleanup.js +35 -0
- package/dist/scripts/console.d.ts +6 -0
- package/dist/scripts/console.d.ts.map +1 -0
- package/dist/scripts/console.js +25 -0
- package/dist/scripts/deploy.d.ts +6 -0
- package/dist/scripts/deploy.d.ts.map +1 -0
- package/dist/scripts/deploy.js +82 -0
- package/dist/scripts/destroy.d.ts +6 -0
- package/dist/scripts/destroy.d.ts.map +1 -0
- package/dist/scripts/destroy.js +30 -0
- package/dist/scripts/dev-server-cors.test.d.ts +2 -0
- package/dist/scripts/dev-server-cors.test.d.ts.map +1 -0
- package/dist/scripts/dev-server-cors.test.js +23 -0
- package/dist/scripts/dev-server-telemetry.test.d.ts +2 -0
- package/dist/scripts/dev-server-telemetry.test.d.ts.map +1 -0
- package/dist/scripts/dev-server-telemetry.test.js +113 -0
- package/dist/scripts/dev-server.d.ts +21 -0
- package/dist/scripts/dev-server.d.ts.map +1 -0
- package/dist/scripts/dev-server.js +456 -0
- package/dist/scripts/ensure-secrets.d.ts +31 -0
- package/dist/scripts/ensure-secrets.d.ts.map +1 -0
- package/dist/scripts/ensure-secrets.js +100 -0
- package/dist/scripts/ensure-secrets.test.d.ts +2 -0
- package/dist/scripts/ensure-secrets.test.d.ts.map +1 -0
- package/dist/scripts/ensure-secrets.test.js +44 -0
- package/dist/scripts/external-migrations-step.d.ts +62 -0
- package/dist/scripts/external-migrations-step.d.ts.map +1 -0
- package/dist/scripts/external-migrations-step.js +243 -0
- package/dist/scripts/external-migrations-step.test.d.ts +2 -0
- package/dist/scripts/external-migrations-step.test.d.ts.map +1 -0
- package/dist/scripts/external-migrations-step.test.js +47 -0
- package/dist/scripts/extract-ts-types.d.ts +65 -0
- package/dist/scripts/extract-ts-types.d.ts.map +1 -0
- package/dist/scripts/extract-ts-types.js +664 -0
- package/dist/scripts/extract-ts-types.test.d.ts +2 -0
- package/dist/scripts/extract-ts-types.test.d.ts.map +1 -0
- package/dist/scripts/extract-ts-types.test.js +497 -0
- package/dist/scripts/generate-client-worker.d.ts +2 -0
- package/dist/scripts/generate-client-worker.d.ts.map +1 -0
- package/dist/scripts/generate-client-worker.js +13 -0
- package/dist/scripts/generate-client.d.ts +14 -0
- package/dist/scripts/generate-client.d.ts.map +1 -0
- package/dist/scripts/generate-client.js +73 -0
- package/dist/scripts/generate-client.test.d.ts +2 -0
- package/dist/scripts/generate-client.test.d.ts.map +1 -0
- package/dist/scripts/generate-client.test.js +48 -0
- package/dist/scripts/generate-spec-cli.d.ts +3 -0
- package/dist/scripts/generate-spec-cli.d.ts.map +1 -0
- package/dist/scripts/generate-spec-cli.js +77 -0
- package/dist/scripts/generate-spec-cli.test.d.ts +14 -0
- package/dist/scripts/generate-spec-cli.test.d.ts.map +1 -0
- package/dist/scripts/generate-spec-cli.test.js +90 -0
- package/dist/scripts/generate-spec.d.ts +61 -0
- package/dist/scripts/generate-spec.d.ts.map +1 -0
- package/dist/scripts/generate-spec.js +746 -0
- package/dist/scripts/generate-spec.test.d.ts +12 -0
- package/dist/scripts/generate-spec.test.d.ts.map +1 -0
- package/dist/scripts/generate-spec.test.js +88 -0
- package/dist/scripts/index.d.ts +12 -0
- package/dist/scripts/index.d.ts.map +1 -0
- package/dist/scripts/index.js +13 -0
- package/dist/scripts/sandbox.d.ts +11 -0
- package/dist/scripts/sandbox.d.ts.map +1 -0
- package/dist/scripts/sandbox.js +200 -0
- package/dist/scripts/telemetry-cli.d.ts +3 -0
- package/dist/scripts/telemetry-cli.d.ts.map +1 -0
- package/dist/scripts/telemetry-cli.js +8 -0
- package/dist/scripts/telemetry.d.ts +17 -0
- package/dist/scripts/telemetry.d.ts.map +1 -0
- package/dist/scripts/telemetry.js +150 -0
- package/dist/scripts/telemetry.test.d.ts +2 -0
- package/dist/scripts/telemetry.test.d.ts.map +1 -0
- package/dist/scripts/telemetry.test.js +203 -0
- package/dist/scripts/validate-spec.d.ts +22 -0
- package/dist/scripts/validate-spec.d.ts.map +1 -0
- package/dist/scripts/validate-spec.js +159 -0
- package/dist/server/index.d.ts +3 -0
- package/dist/server/index.d.ts.map +1 -0
- package/dist/server/index.js +3 -0
- package/dist/server/withAuth.d.ts +142 -0
- package/dist/server/withAuth.d.ts.map +1 -0
- package/dist/server/withAuth.js +261 -0
- package/dist/server/withAuth.test.d.ts +2 -0
- package/dist/server/withAuth.test.d.ts.map +1 -0
- package/dist/server/withAuth.test.js +278 -0
- package/dist/telemetry/client.d.ts +59 -0
- package/dist/telemetry/client.d.ts.map +1 -0
- package/dist/telemetry/client.js +215 -0
- package/dist/telemetry/config-writer.d.ts +16 -0
- package/dist/telemetry/config-writer.d.ts.map +1 -0
- package/dist/telemetry/config-writer.js +36 -0
- package/dist/telemetry/consent-commands.test.d.ts +2 -0
- package/dist/telemetry/consent-commands.test.d.ts.map +1 -0
- package/dist/telemetry/consent-commands.test.js +161 -0
- package/dist/telemetry/consent.d.ts +60 -0
- package/dist/telemetry/consent.d.ts.map +1 -0
- package/dist/telemetry/consent.js +122 -0
- package/dist/telemetry/environment.d.ts +33 -0
- package/dist/telemetry/environment.d.ts.map +1 -0
- package/dist/telemetry/environment.js +87 -0
- package/dist/telemetry/identifiers.d.ts +20 -0
- package/dist/telemetry/identifiers.d.ts.map +1 -0
- package/dist/telemetry/identifiers.js +86 -0
- package/dist/telemetry/index.d.ts +6 -0
- package/dist/telemetry/index.d.ts.map +1 -0
- package/dist/telemetry/index.js +4 -0
- package/dist/telemetry/telemetry.test.d.ts +2 -0
- package/dist/telemetry/telemetry.test.d.ts.map +1 -0
- package/dist/telemetry/telemetry.test.js +1131 -0
- package/dist/telemetry/trackCommand.d.ts +32 -0
- package/dist/telemetry/trackCommand.d.ts.map +1 -0
- package/dist/telemetry/trackCommand.js +102 -0
- package/dist/telemetry/types.d.ts +92 -0
- package/dist/telemetry/types.d.ts.map +1 -0
- package/dist/telemetry/types.js +1 -0
- package/dist/types.d.ts +24 -0
- package/dist/types.d.ts.map +1 -0
- package/dist/types.js +3 -0
- package/dist/version.d.ts +2 -0
- package/dist/version.d.ts.map +1 -0
- package/dist/version.js +2 -0
- package/package.json +83 -0
- package/src/api.test.ts +25 -0
- package/src/api.ts +163 -0
- package/src/bb-utils.ts +13 -0
- package/src/builtin-routes.ts +62 -0
- package/src/cdk/__fixtures__/factory-backend.ts +8 -0
- package/src/cdk/__fixtures__/fullid-construct-backend.ts +42 -0
- package/src/cdk/__fixtures__/handler.ts +4 -0
- package/src/cdk/__fixtures__/side-effect-backend.ts +7 -0
- package/src/cdk/blocks-backend.test.ts +207 -0
- package/src/cdk/blocks-backend.ts +249 -0
- package/src/cdk/blocks-stack.test.ts +106 -0
- package/src/cdk/config-registry.ts +106 -0
- package/src/cdk/index.ts +115 -0
- package/src/cdk/mixins.test.ts +129 -0
- package/src/cdk/mixins.ts +41 -0
- package/src/cdk/node-version.ts +17 -0
- package/src/cdk/stack-metadata.test.ts +71 -0
- package/src/cdk/stack-metadata.ts +29 -0
- package/src/cdk/synth-guard.test.ts +21 -0
- package/src/cdk/synth-guard.ts +23 -0
- package/src/client/index.test.ts +118 -0
- package/src/client/index.ts +320 -0
- package/src/common/config.test.ts +236 -0
- package/src/common/config.ts +169 -0
- package/src/common/constants.ts +15 -0
- package/src/common/crypto.ts +15 -0
- package/src/common/index.test.ts +242 -0
- package/src/common/index.ts +335 -0
- package/src/common/mock-data.ts +52 -0
- package/src/common/official-bb-names.generated.ts +29 -0
- package/src/common/sdk-registry.ts +150 -0
- package/src/constants.ts +31 -0
- package/src/cors.test.ts +279 -0
- package/src/cors.ts +91 -0
- package/src/db-naming.test.ts +48 -0
- package/src/db-naming.ts +41 -0
- package/src/errors.ts +72 -0
- package/src/hosting.test.ts +1431 -0
- package/src/hosting.ts +626 -0
- package/src/index.cdk.ts +45 -0
- package/src/index.ts +22 -0
- package/src/lambda-handler.test.ts +1005 -0
- package/src/lambda-handler.ts +706 -0
- package/src/pipeline/index.ts +12 -0
- package/src/pipeline/pipeline-construct.ts +662 -0
- package/src/pipeline/pipeline.test.ts +1565 -0
- package/src/pipeline/types.ts +384 -0
- package/src/raw-route.cdk.ts +56 -0
- package/src/raw-route.mock.ts +56 -0
- package/src/raw-route.test.ts +819 -0
- package/src/raw-route.ts +316 -0
- package/src/redact.test.ts +222 -0
- package/src/redact.ts +143 -0
- package/src/rpc.test.ts +73 -0
- package/src/rpc.ts +174 -0
- package/src/scripts/cdk-telemetry-env.test.ts +75 -0
- package/src/scripts/cdk-telemetry-env.ts +23 -0
- package/src/scripts/cleanup.ts +39 -0
- package/src/scripts/console.ts +34 -0
- package/src/scripts/deploy.ts +106 -0
- package/src/scripts/destroy.ts +42 -0
- package/src/scripts/dev-server-cors.test.ts +28 -0
- package/src/scripts/dev-server-telemetry.test.ts +127 -0
- package/src/scripts/dev-server.ts +515 -0
- package/src/scripts/ensure-secrets.test.ts +50 -0
- package/src/scripts/ensure-secrets.ts +113 -0
- package/src/scripts/external-migrations-step.test.ts +64 -0
- package/src/scripts/external-migrations-step.ts +269 -0
- package/src/scripts/extract-ts-types.test.ts +516 -0
- package/src/scripts/extract-ts-types.ts +773 -0
- package/src/scripts/generate-client-worker.ts +15 -0
- package/src/scripts/generate-client.test.ts +69 -0
- package/src/scripts/generate-client.ts +86 -0
- package/src/scripts/generate-spec-cli.test.ts +106 -0
- package/src/scripts/generate-spec-cli.ts +92 -0
- package/src/scripts/generate-spec.test.ts +99 -0
- package/src/scripts/generate-spec.ts +833 -0
- package/src/scripts/index.ts +21 -0
- package/src/scripts/sandbox.ts +230 -0
- package/src/scripts/telemetry-cli.ts +10 -0
- package/src/scripts/telemetry.test.ts +239 -0
- package/src/scripts/telemetry.ts +173 -0
- package/src/scripts/validate-spec.ts +199 -0
- package/src/server/index.ts +5 -0
- package/src/server/withAuth.test.ts +348 -0
- package/src/server/withAuth.ts +323 -0
- package/src/telemetry/client.ts +226 -0
- package/src/telemetry/config-writer.ts +52 -0
- package/src/telemetry/consent-commands.test.ts +196 -0
- package/src/telemetry/consent.ts +154 -0
- package/src/telemetry/environment.ts +100 -0
- package/src/telemetry/identifiers.ts +94 -0
- package/src/telemetry/index.ts +11 -0
- package/src/telemetry/telemetry.test.ts +1343 -0
- package/src/telemetry/trackCommand.ts +110 -0
- package/src/telemetry/types.ts +92 -0
- package/src/types.ts +33 -0
- package/src/version.ts +2 -0
|
@@ -0,0 +1,261 @@
|
|
|
1
|
+
// Copyright Amazon.com, Inc. or its affiliates. All Rights Reserved.
|
|
2
|
+
// SPDX-License-Identifier: Apache-2.0
|
|
3
|
+
import { AsyncLocalStorage } from 'node:async_hooks';
|
|
4
|
+
import { ApiError } from '../errors.js';
|
|
5
|
+
function getSsrCookies() {
|
|
6
|
+
const store = globalThis.__BLOCKS_REQUEST_COOKIES_STORE__;
|
|
7
|
+
if (!store || typeof store.getStore !== 'function')
|
|
8
|
+
return undefined;
|
|
9
|
+
return store.getStore();
|
|
10
|
+
}
|
|
11
|
+
/**
|
|
12
|
+
* Get or lazily create the request cookie AsyncLocalStorage.
|
|
13
|
+
*
|
|
14
|
+
* In the API Lambda, `lambda-handler.ts` creates the store and registers it
|
|
15
|
+
* on `globalThis.__BLOCKS_REQUEST_COOKIES_STORE__`. In the SSR Lambda (a separate
|
|
16
|
+
* process), the store may not exist yet — this function creates it on demand.
|
|
17
|
+
*
|
|
18
|
+
* This module is server-only (never bundled for the browser), so direct
|
|
19
|
+
* `node:async_hooks` import is safe — no `webpackIgnore` needed.
|
|
20
|
+
*/
|
|
21
|
+
function getRequestCookieStore() {
|
|
22
|
+
const existing = globalThis.__BLOCKS_REQUEST_COOKIES_STORE__;
|
|
23
|
+
if (existing)
|
|
24
|
+
return existing;
|
|
25
|
+
const store = new AsyncLocalStorage();
|
|
26
|
+
globalThis.__BLOCKS_REQUEST_COOKIES_STORE__ = store;
|
|
27
|
+
return store;
|
|
28
|
+
}
|
|
29
|
+
const providers = [];
|
|
30
|
+
/**
|
|
31
|
+
* Register a framework-specific cookie provider for `withAuth()`.
|
|
32
|
+
*
|
|
33
|
+
* Providers are tried in registration order when `withAuth()` is called
|
|
34
|
+
* without explicit cookies. The first provider that returns a non-undefined
|
|
35
|
+
* value wins.
|
|
36
|
+
*
|
|
37
|
+
* Two providers are registered by default:
|
|
38
|
+
*
|
|
39
|
+
* - **Next.js** — reads cookies from `next/headers`. Works out of the box.
|
|
40
|
+
* - **Nuxt/Nitro** — reads cookies from the active Nitro request event
|
|
41
|
+
* (via the `unctx` `'nitro-app'` async context). Requires
|
|
42
|
+
* `nitro.experimental.asyncContext: true` in `nuxt.config.ts` so Nitro
|
|
43
|
+
* wraps each request in an `AsyncLocalStorage` context. Without that
|
|
44
|
+
* flag the provider returns `undefined` and a warning is emitted on
|
|
45
|
+
* first miss to point at the missing config (see `withAuth` for the
|
|
46
|
+
* no-cookies error path).
|
|
47
|
+
*
|
|
48
|
+
* Use this to add support for additional frameworks (SvelteKit, Astro, etc.)
|
|
49
|
+
* or custom cookie sources.
|
|
50
|
+
*
|
|
51
|
+
* @param name - Human-readable provider name (for debugging).
|
|
52
|
+
* @param detect - Async function that returns a cookie string or `undefined`.
|
|
53
|
+
*
|
|
54
|
+
* @example
|
|
55
|
+
* ```typescript
|
|
56
|
+
* import { registerCookieProvider } from '@aws-blocks/blocks/server';
|
|
57
|
+
*
|
|
58
|
+
* // SvelteKit provider
|
|
59
|
+
* registerCookieProvider('sveltekit', async () => {
|
|
60
|
+
* try {
|
|
61
|
+
* const { getRequestEvent } = await import('$app/server');
|
|
62
|
+
* const event = getRequestEvent();
|
|
63
|
+
* return event?.request.headers.get('cookie') ?? undefined;
|
|
64
|
+
* } catch {
|
|
65
|
+
* return undefined;
|
|
66
|
+
* }
|
|
67
|
+
* });
|
|
68
|
+
* ```
|
|
69
|
+
*/
|
|
70
|
+
export function registerCookieProvider(name, detect) {
|
|
71
|
+
const existingIdx = providers.findIndex(p => p.name === name);
|
|
72
|
+
if (existingIdx >= 0) {
|
|
73
|
+
providers[existingIdx] = { name, detect };
|
|
74
|
+
}
|
|
75
|
+
else {
|
|
76
|
+
providers.push({ name, detect });
|
|
77
|
+
}
|
|
78
|
+
}
|
|
79
|
+
// Built-in Next.js provider — registered by default
|
|
80
|
+
registerCookieProvider('nextjs', async () => {
|
|
81
|
+
try {
|
|
82
|
+
const mod = await import('next/headers');
|
|
83
|
+
const store = await mod.cookies();
|
|
84
|
+
const all = store.getAll();
|
|
85
|
+
if (all.length === 0)
|
|
86
|
+
return undefined;
|
|
87
|
+
return all.map((c) => `${c.name}=${c.value}`).join('; ');
|
|
88
|
+
}
|
|
89
|
+
catch {
|
|
90
|
+
return undefined;
|
|
91
|
+
}
|
|
92
|
+
});
|
|
93
|
+
let nuxtAsyncContextWarned = false;
|
|
94
|
+
registerCookieProvider('nuxt', async () => {
|
|
95
|
+
let getContext;
|
|
96
|
+
try {
|
|
97
|
+
({ getContext } = await import('unctx'));
|
|
98
|
+
}
|
|
99
|
+
catch {
|
|
100
|
+
return undefined; // unctx not installed → not a Nuxt/Nitro app
|
|
101
|
+
}
|
|
102
|
+
// `getContext('nitro-app')` itself never throws — it lazily creates the
|
|
103
|
+
// context registry. `.use()` is what throws when no instance is bound.
|
|
104
|
+
const nitroAsyncContext = getContext('nitro-app');
|
|
105
|
+
let bound;
|
|
106
|
+
try {
|
|
107
|
+
// `.use()` returns the bound NitroApp or throws.
|
|
108
|
+
//
|
|
109
|
+
// TODO(nitro-v3 / nuxt-5): Nitro v3 swaps h3 for srvx, so the bound
|
|
110
|
+
// context shape changes from `{ event }` (h3 `H3Event`, read below via
|
|
111
|
+
// `event.node.req.headers.cookie`) to `{ request }` (a standard Web
|
|
112
|
+
// `Request`, read via `request.headers.get('cookie')`). We read both
|
|
113
|
+
// shapes below so the provider keeps working across the cutover; revisit
|
|
114
|
+
// and drop the h3 branch once Nuxt 5 / Nitro v3 is the floor.
|
|
115
|
+
bound = nitroAsyncContext.use();
|
|
116
|
+
}
|
|
117
|
+
catch {
|
|
118
|
+
// In a Nitro runtime but no context bound for this call — almost
|
|
119
|
+
// always `experimental.asyncContext: true` missing from the config.
|
|
120
|
+
// Surface a hint exactly once per process so the developer sees the
|
|
121
|
+
// root cause, not a downstream generic "no cookies" 401. Suppressible
|
|
122
|
+
// via env var for tests / intentional setups.
|
|
123
|
+
if (!nuxtAsyncContextWarned &&
|
|
124
|
+
process.env.BLOCKS_SUPPRESS_NUXT_ASYNC_CONTEXT_WARN !== '1') {
|
|
125
|
+
nuxtAsyncContextWarned = true;
|
|
126
|
+
// eslint-disable-next-line no-console
|
|
127
|
+
console.warn('[@aws-blocks/core] withAuth: Nuxt/Nitro detected but the request context is not available. ' +
|
|
128
|
+
"Add `nitro: { experimental: { asyncContext: true } }` to nuxt.config.ts so withAuth() can read cookies from the active request. " +
|
|
129
|
+
'See https://nuxt.com/docs/guide/going-further/experimental-features#asynccontext');
|
|
130
|
+
}
|
|
131
|
+
return undefined;
|
|
132
|
+
}
|
|
133
|
+
// h3 (Nitro v2): cookie lives on the Node request headers.
|
|
134
|
+
// srvx (Nitro v3): cookie lives on the Web `Request` headers. See the
|
|
135
|
+
// TODO above — the `request` branch future-proofs this for Nuxt 5.
|
|
136
|
+
const cookie = bound?.event?.node?.req?.headers?.cookie ??
|
|
137
|
+
bound?.request?.headers?.get('cookie') ??
|
|
138
|
+
undefined;
|
|
139
|
+
return typeof cookie === 'string' && cookie.length > 0 ? cookie : undefined;
|
|
140
|
+
});
|
|
141
|
+
/**
|
|
142
|
+
* Try each registered provider in order; return the first non-undefined result.
|
|
143
|
+
*/
|
|
144
|
+
async function detectFrameworkCookies() {
|
|
145
|
+
for (const provider of providers) {
|
|
146
|
+
const result = await provider.detect();
|
|
147
|
+
if (result)
|
|
148
|
+
return result;
|
|
149
|
+
}
|
|
150
|
+
return undefined;
|
|
151
|
+
}
|
|
152
|
+
/**
|
|
153
|
+
* Clear all registered cookie providers, including the built-in Next.js one.
|
|
154
|
+
*
|
|
155
|
+
* Primarily useful for testing. After calling this, you must re-register any
|
|
156
|
+
* providers you need (including Next.js if desired).
|
|
157
|
+
*
|
|
158
|
+
* @example
|
|
159
|
+
* ```typescript
|
|
160
|
+
* import { clearCookieProviders, registerCookieProvider } from '@aws-blocks/blocks/server';
|
|
161
|
+
*
|
|
162
|
+
* // In test setup
|
|
163
|
+
* clearCookieProviders();
|
|
164
|
+
* registerCookieProvider('test', async () => 'session=test');
|
|
165
|
+
* ```
|
|
166
|
+
*/
|
|
167
|
+
export function clearCookieProviders() {
|
|
168
|
+
providers.length = 0;
|
|
169
|
+
}
|
|
170
|
+
/** @internal Read-only view of registered providers (for testing). */
|
|
171
|
+
export function _getProviders() {
|
|
172
|
+
return providers;
|
|
173
|
+
}
|
|
174
|
+
/**
|
|
175
|
+
* Wraps an async function with authenticated cookie forwarding for SSR.
|
|
176
|
+
*
|
|
177
|
+
* In SSR server components, browser cookies aren't automatically forwarded
|
|
178
|
+
* to API calls. This wrapper reads cookies and makes them available to
|
|
179
|
+
* all Blocks API calls within the callback via `AsyncLocalStorage`.
|
|
180
|
+
*
|
|
181
|
+
* **Resolution order:**
|
|
182
|
+
* 1. Explicit `cookies` parameter (framework-agnostic)
|
|
183
|
+
* 2. Existing request context (Lambda handler already set it up)
|
|
184
|
+
* 3. Registered cookie providers — Next.js and Nuxt are built-in, plus any
|
|
185
|
+
* you've added via `registerCookieProvider`
|
|
186
|
+
* 4. Throws if no cookies found
|
|
187
|
+
*
|
|
188
|
+
* **Built-in providers:**
|
|
189
|
+
*
|
|
190
|
+
* | Framework | Source | Notes |
|
|
191
|
+
* |-----------|--------|-------|
|
|
192
|
+
* | Next.js | `next/headers` | Works out of the box. |
|
|
193
|
+
* | Nuxt/Nitro | Nitro async context (via `unctx`) | Requires `nitro: { experimental: { asyncContext: true } }` in `nuxt.config.ts`. With the flag off the provider returns `undefined` and emits a one-time warning naming the missing config. |
|
|
194
|
+
*
|
|
195
|
+
* @param fn - Async function containing Blocks API calls that need auth.
|
|
196
|
+
* @param cookies - Optional explicit cookie string. If omitted, auto-detects
|
|
197
|
+
* from the request context or registered providers. Pass this for frameworks
|
|
198
|
+
* without a registered provider (or use `registerCookieProvider` to add one).
|
|
199
|
+
* @returns The return value of `fn`.
|
|
200
|
+
*
|
|
201
|
+
* @example
|
|
202
|
+
* ```typescript
|
|
203
|
+
* // Next.js — auto-detects cookies from next/headers (built-in provider)
|
|
204
|
+
* import { withAuth } from '@aws-blocks/blocks/server';
|
|
205
|
+
*
|
|
206
|
+
* const posts = await withAuth(() => api.listMyPosts());
|
|
207
|
+
*
|
|
208
|
+
* // Multiple calls in one scope
|
|
209
|
+
* const data = await withAuth(async () => {
|
|
210
|
+
* const posts = await api.listMyPosts();
|
|
211
|
+
* const profile = await api.getProfile();
|
|
212
|
+
* return { posts, profile };
|
|
213
|
+
* });
|
|
214
|
+
*
|
|
215
|
+
* // Explicit cookies for any framework
|
|
216
|
+
* const posts = await withAuth(
|
|
217
|
+
* () => api.listMyPosts(),
|
|
218
|
+
* request.headers.get('cookie'),
|
|
219
|
+
* );
|
|
220
|
+
* ```
|
|
221
|
+
*
|
|
222
|
+
* @example
|
|
223
|
+
* ```typescript
|
|
224
|
+
* // Nuxt — auto-detects cookies via the active Nitro request event
|
|
225
|
+
* // (built-in provider). Requires the experimental.asyncContext flag.
|
|
226
|
+
* //
|
|
227
|
+
* // nuxt.config.ts
|
|
228
|
+
* // export default defineNuxtConfig({
|
|
229
|
+
* // nitro: { experimental: { asyncContext: true } },
|
|
230
|
+
* // });
|
|
231
|
+
* //
|
|
232
|
+
* // server/api/posts.get.ts
|
|
233
|
+
* import { withAuth } from '@aws-blocks/blocks/server';
|
|
234
|
+
*
|
|
235
|
+
* export default defineEventHandler(async () => {
|
|
236
|
+
* return withAuth(() => api.listMyPosts());
|
|
237
|
+
* });
|
|
238
|
+
* ```
|
|
239
|
+
*
|
|
240
|
+
* @throws {Error} If no cookies are found and no provider detected them.
|
|
241
|
+
*/
|
|
242
|
+
export async function withAuth(fn, cookies) {
|
|
243
|
+
if (cookies != null && cookies.trim()) {
|
|
244
|
+
const store = getRequestCookieStore();
|
|
245
|
+
return store.run(cookies, fn);
|
|
246
|
+
}
|
|
247
|
+
const existing = getSsrCookies();
|
|
248
|
+
if (existing) {
|
|
249
|
+
return fn();
|
|
250
|
+
}
|
|
251
|
+
const detected = await detectFrameworkCookies();
|
|
252
|
+
if (detected) {
|
|
253
|
+
const store = getRequestCookieStore();
|
|
254
|
+
return store.run(detected, fn);
|
|
255
|
+
}
|
|
256
|
+
const providerNames = providers.map(p => p.name).join(', ');
|
|
257
|
+
throw new ApiError(`withAuth: No authentication cookies found. ` +
|
|
258
|
+
`Tried providers: [${providerNames || 'none registered'}]. ` +
|
|
259
|
+
`Ensure the user is logged in and cookies are being forwarded, ` +
|
|
260
|
+
`or pass cookies explicitly as the second argument.`, 401);
|
|
261
|
+
}
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"withAuth.test.d.ts","sourceRoot":"","sources":["../../src/server/withAuth.test.ts"],"names":[],"mappings":""}
|
|
@@ -0,0 +1,278 @@
|
|
|
1
|
+
// Copyright Amazon.com, Inc. or its affiliates. All Rights Reserved.
|
|
2
|
+
// SPDX-License-Identifier: Apache-2.0
|
|
3
|
+
import { test, describe, beforeEach, afterEach } from 'node:test';
|
|
4
|
+
import assert from 'node:assert';
|
|
5
|
+
import { AsyncLocalStorage } from 'node:async_hooks';
|
|
6
|
+
import { getContext } from 'unctx';
|
|
7
|
+
import { withAuth, registerCookieProvider, clearCookieProviders } from './index.js';
|
|
8
|
+
import { _getProviders } from './withAuth.js';
|
|
9
|
+
import { ApiError } from '../errors.js';
|
|
10
|
+
// Seed the `nitro-app` unctx context with `asyncContext: true` at module load,
|
|
11
|
+
// mirroring Nitro's `experimental.asyncContext: true`. unctx caches the context
|
|
12
|
+
// instance on first `getContext()` call (first-write-wins), so this MUST run
|
|
13
|
+
// before any test triggers the provider — otherwise a non-async instance gets
|
|
14
|
+
// cached and `.use()` cannot survive the provider's internal `await import`.
|
|
15
|
+
getContext('nitro-app', { asyncContext: true, AsyncLocalStorage });
|
|
16
|
+
describe('withAuth', () => {
|
|
17
|
+
let originalStore;
|
|
18
|
+
beforeEach(() => {
|
|
19
|
+
originalStore = globalThis.__BLOCKS_REQUEST_COOKIES_STORE__;
|
|
20
|
+
});
|
|
21
|
+
afterEach(() => {
|
|
22
|
+
if (originalStore === undefined) {
|
|
23
|
+
delete globalThis.__BLOCKS_REQUEST_COOKIES_STORE__;
|
|
24
|
+
}
|
|
25
|
+
else {
|
|
26
|
+
globalThis.__BLOCKS_REQUEST_COOKIES_STORE__ = originalStore;
|
|
27
|
+
}
|
|
28
|
+
});
|
|
29
|
+
test('forwards explicit cookies via AsyncLocalStorage', async () => {
|
|
30
|
+
const store = new AsyncLocalStorage();
|
|
31
|
+
globalThis.__BLOCKS_REQUEST_COOKIES_STORE__ = store;
|
|
32
|
+
let captured;
|
|
33
|
+
await withAuth(async () => {
|
|
34
|
+
captured = store.getStore();
|
|
35
|
+
return 'result';
|
|
36
|
+
}, 'session=abc123; token=xyz');
|
|
37
|
+
assert.strictEqual(captured, 'session=abc123; token=xyz');
|
|
38
|
+
});
|
|
39
|
+
test('returns the value from fn when explicit cookies provided', async () => {
|
|
40
|
+
const store = new AsyncLocalStorage();
|
|
41
|
+
globalThis.__BLOCKS_REQUEST_COOKIES_STORE__ = store;
|
|
42
|
+
const result = await withAuth(async () => {
|
|
43
|
+
return { data: 42 };
|
|
44
|
+
}, 'session=abc');
|
|
45
|
+
assert.deepStrictEqual(result, { data: 42 });
|
|
46
|
+
});
|
|
47
|
+
test('uses existing AsyncLocalStorage context when already set', async () => {
|
|
48
|
+
const store = new AsyncLocalStorage();
|
|
49
|
+
globalThis.__BLOCKS_REQUEST_COOKIES_STORE__ = store;
|
|
50
|
+
let innerCookies;
|
|
51
|
+
await store.run('existing-cookies', async () => {
|
|
52
|
+
const result = await withAuth(async () => {
|
|
53
|
+
innerCookies = store.getStore();
|
|
54
|
+
return 'ok';
|
|
55
|
+
});
|
|
56
|
+
assert.strictEqual(result, 'ok');
|
|
57
|
+
});
|
|
58
|
+
assert.strictEqual(innerCookies, 'existing-cookies');
|
|
59
|
+
});
|
|
60
|
+
test('throws when no cookies found and no framework detected', async () => {
|
|
61
|
+
const store = new AsyncLocalStorage();
|
|
62
|
+
globalThis.__BLOCKS_REQUEST_COOKIES_STORE__ = store;
|
|
63
|
+
const saved = _getProviders().slice();
|
|
64
|
+
clearCookieProviders();
|
|
65
|
+
try {
|
|
66
|
+
await assert.rejects(() => withAuth(async () => 'should not reach'), (err) => {
|
|
67
|
+
assert.ok(err instanceof ApiError);
|
|
68
|
+
assert.ok(err.message.includes('withAuth: No authentication cookies found'));
|
|
69
|
+
assert.strictEqual(err.status, 401);
|
|
70
|
+
return true;
|
|
71
|
+
});
|
|
72
|
+
}
|
|
73
|
+
finally {
|
|
74
|
+
for (const p of saved)
|
|
75
|
+
registerCookieProvider(p.name, p.detect);
|
|
76
|
+
}
|
|
77
|
+
});
|
|
78
|
+
test('creates AsyncLocalStorage lazily if globalThis store is missing', async () => {
|
|
79
|
+
delete globalThis.__BLOCKS_REQUEST_COOKIES_STORE__;
|
|
80
|
+
let storeExistedDuringCall = false;
|
|
81
|
+
const result = await withAuth(async () => {
|
|
82
|
+
storeExistedDuringCall = !!globalThis.__BLOCKS_REQUEST_COOKIES_STORE__;
|
|
83
|
+
return 'created';
|
|
84
|
+
}, 'lazy-cookies');
|
|
85
|
+
assert.strictEqual(result, 'created');
|
|
86
|
+
assert.ok(storeExistedDuringCall, 'Store should be created lazily');
|
|
87
|
+
assert.ok(globalThis.__BLOCKS_REQUEST_COOKIES_STORE__, 'Store should persist on globalThis');
|
|
88
|
+
});
|
|
89
|
+
test('propagates errors from fn', async () => {
|
|
90
|
+
const store = new AsyncLocalStorage();
|
|
91
|
+
globalThis.__BLOCKS_REQUEST_COOKIES_STORE__ = store;
|
|
92
|
+
await assert.rejects(() => withAuth(async () => {
|
|
93
|
+
throw new Error('inner error');
|
|
94
|
+
}, 'some-cookies'), { message: 'inner error' });
|
|
95
|
+
});
|
|
96
|
+
test('multiple nested API calls share the same cookie context', async () => {
|
|
97
|
+
const store = new AsyncLocalStorage();
|
|
98
|
+
globalThis.__BLOCKS_REQUEST_COOKIES_STORE__ = store;
|
|
99
|
+
const captured = [];
|
|
100
|
+
await withAuth(async () => {
|
|
101
|
+
captured.push(store.getStore() ?? 'none');
|
|
102
|
+
await Promise.resolve();
|
|
103
|
+
captured.push(store.getStore() ?? 'none');
|
|
104
|
+
return captured;
|
|
105
|
+
}, 'shared-session=1');
|
|
106
|
+
assert.deepStrictEqual(captured, ['shared-session=1', 'shared-session=1']);
|
|
107
|
+
});
|
|
108
|
+
});
|
|
109
|
+
describe('Cookie Provider Registry', () => {
|
|
110
|
+
let originalStore;
|
|
111
|
+
let savedProviders;
|
|
112
|
+
beforeEach(() => {
|
|
113
|
+
originalStore = globalThis.__BLOCKS_REQUEST_COOKIES_STORE__;
|
|
114
|
+
savedProviders = _getProviders().slice();
|
|
115
|
+
clearCookieProviders();
|
|
116
|
+
});
|
|
117
|
+
afterEach(() => {
|
|
118
|
+
clearCookieProviders();
|
|
119
|
+
for (const p of savedProviders)
|
|
120
|
+
registerCookieProvider(p.name, p.detect);
|
|
121
|
+
if (originalStore === undefined) {
|
|
122
|
+
delete globalThis.__BLOCKS_REQUEST_COOKIES_STORE__;
|
|
123
|
+
}
|
|
124
|
+
else {
|
|
125
|
+
globalThis.__BLOCKS_REQUEST_COOKIES_STORE__ = originalStore;
|
|
126
|
+
}
|
|
127
|
+
});
|
|
128
|
+
test('default Next.js provider is registered on module load', () => {
|
|
129
|
+
const providers = savedProviders;
|
|
130
|
+
const nextProvider = providers.find(p => p.name === 'nextjs');
|
|
131
|
+
assert.ok(nextProvider, 'Next.js provider should be registered by default');
|
|
132
|
+
});
|
|
133
|
+
test('Next.js provider returns undefined when next/headers is not available', async () => {
|
|
134
|
+
const nextProvider = savedProviders.find(p => p.name === 'nextjs');
|
|
135
|
+
assert.ok(nextProvider);
|
|
136
|
+
const result = await nextProvider.detect();
|
|
137
|
+
assert.strictEqual(result, undefined);
|
|
138
|
+
});
|
|
139
|
+
test('default Nuxt provider is registered on module load', () => {
|
|
140
|
+
const providers = savedProviders;
|
|
141
|
+
const nuxtProvider = providers.find(p => p.name === 'nuxt');
|
|
142
|
+
assert.ok(nuxtProvider, 'Nuxt provider should be registered by default');
|
|
143
|
+
});
|
|
144
|
+
test('Nuxt provider returns undefined cleanly when no Nitro context is bound', async () => {
|
|
145
|
+
// When the test runs in a plain node env (no Nitro), either `unctx`
|
|
146
|
+
// isn't installed (import fails) or it is, but `getContext('nitro-app').use()`
|
|
147
|
+
// throws because no async context is bound. Both paths must return
|
|
148
|
+
// undefined, and neither should leak the underlying error to the caller.
|
|
149
|
+
const nuxtProvider = savedProviders.find(p => p.name === 'nuxt');
|
|
150
|
+
assert.ok(nuxtProvider);
|
|
151
|
+
// Suppress the one-time console.warn on the asyncContext-disabled path so
|
|
152
|
+
// it doesn't contaminate test output.
|
|
153
|
+
process.env.BLOCKS_SUPPRESS_NUXT_ASYNC_CONTEXT_WARN = '1';
|
|
154
|
+
try {
|
|
155
|
+
const result = await nuxtProvider.detect();
|
|
156
|
+
assert.strictEqual(result, undefined);
|
|
157
|
+
}
|
|
158
|
+
finally {
|
|
159
|
+
delete process.env.BLOCKS_SUPPRESS_NUXT_ASYNC_CONTEXT_WARN;
|
|
160
|
+
}
|
|
161
|
+
});
|
|
162
|
+
test('Nuxt provider reads cookie from the h3 `{ event }` shape (Nitro v2)', async () => {
|
|
163
|
+
const nuxtProvider = savedProviders.find(p => p.name === 'nuxt');
|
|
164
|
+
assert.ok(nuxtProvider);
|
|
165
|
+
// The `nitro-app` context is seeded with asyncContext at module load, so
|
|
166
|
+
// the binding survives the provider's internal `await import('unctx')`.
|
|
167
|
+
// Nitro v2 (h3): `{ event }` carrying the cookie on the Node request headers.
|
|
168
|
+
const bound = { event: { node: { req: { headers: { cookie: 'session=h3' } } } } };
|
|
169
|
+
const result = await getContext('nitro-app').callAsync(bound, () => nuxtProvider.detect());
|
|
170
|
+
assert.strictEqual(result, 'session=h3');
|
|
171
|
+
});
|
|
172
|
+
test('Nuxt provider reads cookie from the srvx `{ request }` shape (Nitro v3 / Nuxt 5)', async () => {
|
|
173
|
+
const nuxtProvider = savedProviders.find(p => p.name === 'nuxt');
|
|
174
|
+
assert.ok(nuxtProvider);
|
|
175
|
+
// Nitro v3 (srvx): `{ request }` carrying the cookie on a standard Web
|
|
176
|
+
// `Request`. This is the forward-compat path guarded by the TODO in
|
|
177
|
+
// withAuth.ts.
|
|
178
|
+
const bound = { request: new Request('https://example.com', { headers: { cookie: 'session=srvx' } }) };
|
|
179
|
+
const result = await getContext('nitro-app').callAsync(bound, () => nuxtProvider.detect());
|
|
180
|
+
assert.strictEqual(result, 'session=srvx');
|
|
181
|
+
});
|
|
182
|
+
test('custom provider registration works', async () => {
|
|
183
|
+
const store = new AsyncLocalStorage();
|
|
184
|
+
globalThis.__BLOCKS_REQUEST_COOKIES_STORE__ = store;
|
|
185
|
+
registerCookieProvider('custom', async () => 'custom-cookie=hello');
|
|
186
|
+
let captured;
|
|
187
|
+
await withAuth(async () => {
|
|
188
|
+
captured = store.getStore();
|
|
189
|
+
return 'ok';
|
|
190
|
+
});
|
|
191
|
+
assert.strictEqual(captured, 'custom-cookie=hello');
|
|
192
|
+
});
|
|
193
|
+
test('multiple providers tried in registration order — first match wins', async () => {
|
|
194
|
+
const store = new AsyncLocalStorage();
|
|
195
|
+
globalThis.__BLOCKS_REQUEST_COOKIES_STORE__ = store;
|
|
196
|
+
const callOrder = [];
|
|
197
|
+
registerCookieProvider('first', async () => {
|
|
198
|
+
callOrder.push('first');
|
|
199
|
+
return undefined;
|
|
200
|
+
});
|
|
201
|
+
registerCookieProvider('second', async () => {
|
|
202
|
+
callOrder.push('second');
|
|
203
|
+
return 'winner=second';
|
|
204
|
+
});
|
|
205
|
+
registerCookieProvider('third', async () => {
|
|
206
|
+
callOrder.push('third');
|
|
207
|
+
return 'should-not-reach=true';
|
|
208
|
+
});
|
|
209
|
+
let captured;
|
|
210
|
+
await withAuth(async () => {
|
|
211
|
+
captured = store.getStore();
|
|
212
|
+
return 'ok';
|
|
213
|
+
});
|
|
214
|
+
assert.strictEqual(captured, 'winner=second');
|
|
215
|
+
assert.deepStrictEqual(callOrder, ['first', 'second']);
|
|
216
|
+
});
|
|
217
|
+
test('explicit cookies take priority over providers', async () => {
|
|
218
|
+
const store = new AsyncLocalStorage();
|
|
219
|
+
globalThis.__BLOCKS_REQUEST_COOKIES_STORE__ = store;
|
|
220
|
+
let providerCalled = false;
|
|
221
|
+
registerCookieProvider('should-not-run', async () => {
|
|
222
|
+
providerCalled = true;
|
|
223
|
+
return 'provider-cookie=value';
|
|
224
|
+
});
|
|
225
|
+
let captured;
|
|
226
|
+
await withAuth(async () => {
|
|
227
|
+
captured = store.getStore();
|
|
228
|
+
return 'ok';
|
|
229
|
+
}, 'explicit-cookie=priority');
|
|
230
|
+
assert.strictEqual(captured, 'explicit-cookie=priority');
|
|
231
|
+
assert.strictEqual(providerCalled, false, 'Provider should not be called when explicit cookies given');
|
|
232
|
+
});
|
|
233
|
+
test('existing ALS context takes priority over providers', async () => {
|
|
234
|
+
const store = new AsyncLocalStorage();
|
|
235
|
+
globalThis.__BLOCKS_REQUEST_COOKIES_STORE__ = store;
|
|
236
|
+
let providerCalled = false;
|
|
237
|
+
registerCookieProvider('should-not-run', async () => {
|
|
238
|
+
providerCalled = true;
|
|
239
|
+
return 'provider-cookie=value';
|
|
240
|
+
});
|
|
241
|
+
let captured;
|
|
242
|
+
await store.run('als-cookies', async () => {
|
|
243
|
+
await withAuth(async () => {
|
|
244
|
+
captured = store.getStore();
|
|
245
|
+
return 'ok';
|
|
246
|
+
});
|
|
247
|
+
});
|
|
248
|
+
assert.strictEqual(captured, 'als-cookies');
|
|
249
|
+
assert.strictEqual(providerCalled, false, 'Provider should not be called when ALS context exists');
|
|
250
|
+
});
|
|
251
|
+
test('throws when all providers return undefined', async () => {
|
|
252
|
+
const store = new AsyncLocalStorage();
|
|
253
|
+
globalThis.__BLOCKS_REQUEST_COOKIES_STORE__ = store;
|
|
254
|
+
registerCookieProvider('nope1', async () => undefined);
|
|
255
|
+
registerCookieProvider('nope2', async () => undefined);
|
|
256
|
+
await assert.rejects(() => withAuth(async () => 'should not reach'), (err) => {
|
|
257
|
+
assert.ok(err instanceof ApiError);
|
|
258
|
+
assert.ok(err.message.includes('withAuth: No authentication cookies found'));
|
|
259
|
+
assert.strictEqual(err.status, 401);
|
|
260
|
+
return true;
|
|
261
|
+
});
|
|
262
|
+
});
|
|
263
|
+
test('registerCookieProvider appends to existing providers', () => {
|
|
264
|
+
registerCookieProvider('a', async () => undefined);
|
|
265
|
+
registerCookieProvider('b', async () => undefined);
|
|
266
|
+
const providers = _getProviders();
|
|
267
|
+
assert.strictEqual(providers.length, 2);
|
|
268
|
+
assert.strictEqual(providers[0].name, 'a');
|
|
269
|
+
assert.strictEqual(providers[1].name, 'b');
|
|
270
|
+
});
|
|
271
|
+
test('clearCookieProviders removes all registered providers', () => {
|
|
272
|
+
registerCookieProvider('a', async () => undefined);
|
|
273
|
+
registerCookieProvider('b', async () => undefined);
|
|
274
|
+
assert.strictEqual(_getProviders().length, 2);
|
|
275
|
+
clearCookieProviders();
|
|
276
|
+
assert.strictEqual(_getProviders().length, 0);
|
|
277
|
+
});
|
|
278
|
+
});
|
|
@@ -0,0 +1,59 @@
|
|
|
1
|
+
import type { BlocksTelemetryEvent, BuildAndSendEventOptions } from './types.js';
|
|
2
|
+
/**
|
|
3
|
+
* Parse `--telemetry-file=/path/to/file.json` from process.argv.
|
|
4
|
+
*
|
|
5
|
+
* Supports both `--telemetry-file=path` and `--telemetry-file path` forms.
|
|
6
|
+
*
|
|
7
|
+
* @returns The file path if the flag is present, undefined otherwise.
|
|
8
|
+
*
|
|
9
|
+
* @example
|
|
10
|
+
* // Capture telemetry to file (also sends HTTP when enabled):
|
|
11
|
+
* // npx tsx aws-blocks/scripts/server.ts --telemetry-file=/tmp/events.json
|
|
12
|
+
*
|
|
13
|
+
* // Capture WITHOUT sending (disable HTTP, file still writes):
|
|
14
|
+
* // AWS_BLOCKS_DISABLE_TELEMETRY=1 npx tsx aws-blocks/scripts/server.ts --telemetry-file=/tmp/events.json
|
|
15
|
+
*/
|
|
16
|
+
export declare function getTelemetryFilePath(): string | undefined;
|
|
17
|
+
/**
|
|
18
|
+
* Constructs a telemetry event without sending it.
|
|
19
|
+
* Useful for testing event structure without I/O side effects.
|
|
20
|
+
* @internal
|
|
21
|
+
*/
|
|
22
|
+
export declare function buildEvent(opts: BuildAndSendEventOptions): BlocksTelemetryEvent;
|
|
23
|
+
/**
|
|
24
|
+
* Build a complete telemetry event and send it to the collection endpoint.
|
|
25
|
+
*
|
|
26
|
+
* This is the single entry point for all telemetry emission. It handles:
|
|
27
|
+
* 1. Early exit — if telemetry is disabled AND no `--telemetry-file` is set,
|
|
28
|
+
* returns immediately with no side effects (no IDs persisted, no notice)
|
|
29
|
+
* 2. Full payload construction (identifiers, environment, product info)
|
|
30
|
+
* 3. File sink — writes to the file specified by `--telemetry-file` (if set),
|
|
31
|
+
* regardless of opt-out status (inspired by CDK CLI's --telemetry-file)
|
|
32
|
+
* 4. Privacy filtering — custom BB names are NEVER sent, only counted
|
|
33
|
+
* 5. HTTP sink — fire-and-forget POST (only when telemetry is enabled)
|
|
34
|
+
*
|
|
35
|
+
* The file sink fires unconditionally when `--telemetry-file` is set.
|
|
36
|
+
* The HTTP sink only fires when telemetry is enabled. Callers never need to
|
|
37
|
+
* import consent, identifier, or environment utilities directly.
|
|
38
|
+
*
|
|
39
|
+
* @param opts - Event metadata (command, state, duration, optional error/product/counters)
|
|
40
|
+
*
|
|
41
|
+
* @example
|
|
42
|
+
* ```ts
|
|
43
|
+
* buildAndSendEvent({
|
|
44
|
+
* command: 'deploy',
|
|
45
|
+
* state: 'SUCCESS',
|
|
46
|
+
* duration: 4500,
|
|
47
|
+
* product: { cdkVersion: '2.150.0' },
|
|
48
|
+
* });
|
|
49
|
+
* ```
|
|
50
|
+
*/
|
|
51
|
+
export declare function buildAndSendEvent(opts: BuildAndSendEventOptions): void;
|
|
52
|
+
/**
|
|
53
|
+
* Send a pre-built telemetry event to the collection endpoint.
|
|
54
|
+
*
|
|
55
|
+
* Fire-and-forget: no retry, 500ms timeout, all errors silently swallowed.
|
|
56
|
+
* Debug output available via `NODE_DEBUG=blocks-telemetry`.
|
|
57
|
+
*/
|
|
58
|
+
export declare function sendEvent(event: BlocksTelemetryEvent): void;
|
|
59
|
+
//# sourceMappingURL=client.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"client.d.ts","sourceRoot":"","sources":["../../src/telemetry/client.ts"],"names":[],"mappings":"AAUA,OAAO,KAAK,EAAE,oBAAoB,EAAE,wBAAwB,EAAE,MAAM,YAAY,CAAC;AAajF;;;;;;;;;;;;;GAaG;AACH,wBAAgB,oBAAoB,IAAI,MAAM,GAAG,SAAS,CAWzD;AAwBD;;;;GAIG;AACH,wBAAgB,UAAU,CAAC,IAAI,EAAE,wBAAwB,GAAG,oBAAoB,CAwD/E;AAED;;;;;;;;;;;;;;;;;;;;;;;;;;;GA2BG;AACH,wBAAgB,iBAAiB,CAAC,IAAI,EAAE,wBAAwB,GAAG,IAAI,CAatE;AAED;;;;;GAKG;AACH,wBAAgB,SAAS,CAAC,KAAK,EAAE,oBAAoB,GAAG,IAAI,CAyC3D"}
|