@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
package/src/rpc.test.ts
ADDED
|
@@ -0,0 +1,73 @@
|
|
|
1
|
+
// Copyright Amazon.com, Inc. or its affiliates. All Rights Reserved.
|
|
2
|
+
// SPDX-License-Identifier: Apache-2.0
|
|
3
|
+
|
|
4
|
+
import { describe, it } from 'node:test';
|
|
5
|
+
import assert from 'node:assert';
|
|
6
|
+
import { parseRpcRequest, RpcErrorCode } from './rpc.js';
|
|
7
|
+
|
|
8
|
+
describe('-32600 Invalid Request error shape', () => {
|
|
9
|
+
it('returns proper JSON-RPC 2.0 envelope with error code', () => {
|
|
10
|
+
const result = parseRpcRequest(JSON.stringify({ method: 'ns.method', id: 1 }));
|
|
11
|
+
assert.strictEqual(result.ok, false);
|
|
12
|
+
if (!result.ok) {
|
|
13
|
+
const parsed = JSON.parse(result.response);
|
|
14
|
+
assert.strictEqual(parsed.jsonrpc, '2.0');
|
|
15
|
+
assert.strictEqual(parsed.error.code, RpcErrorCode.InvalidRequest);
|
|
16
|
+
assert.strictEqual(parsed.id, 1);
|
|
17
|
+
}
|
|
18
|
+
});
|
|
19
|
+
|
|
20
|
+
it('includes descriptive message with expected JSON-RPC 2.0 shape', () => {
|
|
21
|
+
const result = parseRpcRequest(JSON.stringify({ method: 'test', id: 1 }));
|
|
22
|
+
assert.strictEqual(result.ok, false);
|
|
23
|
+
if (!result.ok) {
|
|
24
|
+
const parsed = JSON.parse(result.response);
|
|
25
|
+
assert.ok(
|
|
26
|
+
parsed.error.message.includes('expected JSON-RPC 2.0'),
|
|
27
|
+
`message should describe the expected format, got: ${parsed.error.message}`,
|
|
28
|
+
);
|
|
29
|
+
assert.ok(
|
|
30
|
+
parsed.error.message.includes('"jsonrpc":"2.0"'),
|
|
31
|
+
`message should echo the expected envelope shape`,
|
|
32
|
+
);
|
|
33
|
+
}
|
|
34
|
+
});
|
|
35
|
+
|
|
36
|
+
it('includes data.name per D-003 convention', () => {
|
|
37
|
+
const result = parseRpcRequest(JSON.stringify({ method: 'test', id: 1 }));
|
|
38
|
+
assert.strictEqual(result.ok, false);
|
|
39
|
+
if (!result.ok) {
|
|
40
|
+
const parsed = JSON.parse(result.response);
|
|
41
|
+
assert.strictEqual(parsed.error.data.name, 'InvalidRequest');
|
|
42
|
+
}
|
|
43
|
+
});
|
|
44
|
+
|
|
45
|
+
it('preserves the caller id in the error response', () => {
|
|
46
|
+
const result = parseRpcRequest(JSON.stringify({ id: 'abc-123' }));
|
|
47
|
+
assert.strictEqual(result.ok, false);
|
|
48
|
+
if (!result.ok) {
|
|
49
|
+
const parsed = JSON.parse(result.response);
|
|
50
|
+
assert.strictEqual(parsed.id, 'abc-123');
|
|
51
|
+
}
|
|
52
|
+
});
|
|
53
|
+
|
|
54
|
+
it('uses null id when request omits id', () => {
|
|
55
|
+
const result = parseRpcRequest(JSON.stringify({ jsonrpc: '1.0', method: 123 }));
|
|
56
|
+
assert.strictEqual(result.ok, false);
|
|
57
|
+
if (!result.ok) {
|
|
58
|
+
const parsed = JSON.parse(result.response);
|
|
59
|
+
assert.strictEqual(parsed.id, null);
|
|
60
|
+
}
|
|
61
|
+
});
|
|
62
|
+
|
|
63
|
+
it('includes data.name when method lacks namespace dot separator', () => {
|
|
64
|
+
const result = parseRpcRequest(JSON.stringify({ jsonrpc: '2.0', method: 'noNamespace', id: 7 }));
|
|
65
|
+
assert.strictEqual(result.ok, false);
|
|
66
|
+
if (!result.ok) {
|
|
67
|
+
const parsed = JSON.parse(result.response);
|
|
68
|
+
assert.strictEqual(parsed.error.code, RpcErrorCode.InvalidRequest);
|
|
69
|
+
assert.strictEqual(parsed.error.data.name, 'InvalidRequest');
|
|
70
|
+
assert.strictEqual(parsed.id, 7);
|
|
71
|
+
}
|
|
72
|
+
});
|
|
73
|
+
});
|
package/src/rpc.ts
ADDED
|
@@ -0,0 +1,174 @@
|
|
|
1
|
+
// Copyright Amazon.com, Inc. or its affiliates. All Rights Reserved.
|
|
2
|
+
// SPDX-License-Identifier: Apache-2.0
|
|
3
|
+
|
|
4
|
+
/**
|
|
5
|
+
* JSON-RPC 2.0 wire format ā single source of truth.
|
|
6
|
+
*
|
|
7
|
+
* All encoding/decoding of the Blocks RPC protocol lives here so that the
|
|
8
|
+
* client, Lambda handler, and dev server never deal with the spec directly.
|
|
9
|
+
*
|
|
10
|
+
* @see https://www.jsonrpc.org/specification
|
|
11
|
+
*/
|
|
12
|
+
|
|
13
|
+
import { ApiError } from './errors.js';
|
|
14
|
+
|
|
15
|
+
// āā Types āāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāā
|
|
16
|
+
|
|
17
|
+
/** The pieces every server-side handler needs after parsing a request. */
|
|
18
|
+
export interface RpcParsedRequest {
|
|
19
|
+
apiNamespace: string;
|
|
20
|
+
method: string;
|
|
21
|
+
/** Positional args ā from array params directly, or Object.values() of named params. */
|
|
22
|
+
args: unknown[];
|
|
23
|
+
id: string | number | null;
|
|
24
|
+
}
|
|
25
|
+
|
|
26
|
+
/** Discriminated union returned by `parseRpcRequest`. */
|
|
27
|
+
export type RpcParseResult =
|
|
28
|
+
| { ok: true; request: RpcParsedRequest }
|
|
29
|
+
| { ok: false; response: string };
|
|
30
|
+
|
|
31
|
+
// āā Constants āāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāā
|
|
32
|
+
|
|
33
|
+
const VERSION = '2.0' as const;
|
|
34
|
+
|
|
35
|
+
/** Reserved JSON-RPC error codes. */
|
|
36
|
+
export const RpcErrorCode = {
|
|
37
|
+
ParseError: -32700,
|
|
38
|
+
InvalidRequest: -32600,
|
|
39
|
+
MethodNotFound: -32601,
|
|
40
|
+
InvalidParams: -32602,
|
|
41
|
+
InternalError: -32603,
|
|
42
|
+
} as const;
|
|
43
|
+
|
|
44
|
+
// āā Client helpers (encode request, decode response) āāāāāāāāāāāāāāāāāāāāāāāā
|
|
45
|
+
|
|
46
|
+
let _nextId = 1;
|
|
47
|
+
|
|
48
|
+
/** Build a JSON-RPC 2.0 request body string ready to POST. */
|
|
49
|
+
export function encodeRpcRequest(apiNamespace: string, method: string, args: unknown[]): string {
|
|
50
|
+
return JSON.stringify({
|
|
51
|
+
jsonrpc: VERSION,
|
|
52
|
+
method: `${apiNamespace}.${method}`,
|
|
53
|
+
params: args,
|
|
54
|
+
id: _nextId++,
|
|
55
|
+
});
|
|
56
|
+
}
|
|
57
|
+
|
|
58
|
+
/**
|
|
59
|
+
* Decode a JSON-RPC 2.0 response body.
|
|
60
|
+
*
|
|
61
|
+
* Returns the `result` on success, or throws an `ApiError` on error.
|
|
62
|
+
*/
|
|
63
|
+
export function decodeRpcResponse(body: unknown): unknown {
|
|
64
|
+
const rpc = body as any;
|
|
65
|
+
if (rpc.error) {
|
|
66
|
+
const { code, message, data } = rpc.error;
|
|
67
|
+
// Application error codes use the HTTP status directly (e.g. 409).
|
|
68
|
+
// Reserved JSON-RPC codes (-32xxx) map to 500.
|
|
69
|
+
const status = code > 0 ? code : 500;
|
|
70
|
+
throw new ApiError(
|
|
71
|
+
message,
|
|
72
|
+
status,
|
|
73
|
+
{
|
|
74
|
+
...(data?.name ? { name: data.name } : {}),
|
|
75
|
+
...(data?.retriable === true ? { retriable: true } : {}),
|
|
76
|
+
},
|
|
77
|
+
);
|
|
78
|
+
}
|
|
79
|
+
return rpc.result;
|
|
80
|
+
}
|
|
81
|
+
|
|
82
|
+
// āā Server helpers (parse request, encode response) āāāāāāāāāāāāāāāāāāāāāāāāā
|
|
83
|
+
|
|
84
|
+
/**
|
|
85
|
+
* Parse a raw body string into a validated `RpcParsedRequest`.
|
|
86
|
+
*
|
|
87
|
+
* Returns `{ ok: false, response }` with a ready-to-send JSON string when
|
|
88
|
+
* the request is malformed, so callers can short-circuit without knowing
|
|
89
|
+
* anything about the JSON-RPC spec.
|
|
90
|
+
*/
|
|
91
|
+
export function parseRpcRequest(bodyText: string): RpcParseResult {
|
|
92
|
+
let parsed: any;
|
|
93
|
+
try {
|
|
94
|
+
parsed = JSON.parse(bodyText || '{}');
|
|
95
|
+
} catch {
|
|
96
|
+
return { ok: false, response: errorResponse(RpcErrorCode.ParseError, 'Parse error', null) };
|
|
97
|
+
}
|
|
98
|
+
|
|
99
|
+
const id = parsed.id ?? null;
|
|
100
|
+
|
|
101
|
+
if (parsed.jsonrpc !== VERSION || typeof parsed.method !== 'string') {
|
|
102
|
+
return {
|
|
103
|
+
ok: false,
|
|
104
|
+
response: errorResponse(
|
|
105
|
+
RpcErrorCode.InvalidRequest,
|
|
106
|
+
'Invalid Request: expected JSON-RPC 2.0 ā {"jsonrpc":"2.0","method":"namespace.method","params":[...],"id":1}',
|
|
107
|
+
id,
|
|
108
|
+
{ name: 'InvalidRequest' },
|
|
109
|
+
),
|
|
110
|
+
};
|
|
111
|
+
}
|
|
112
|
+
|
|
113
|
+
const dotIndex = parsed.method.indexOf('.');
|
|
114
|
+
if (dotIndex === -1) {
|
|
115
|
+
return {
|
|
116
|
+
ok: false,
|
|
117
|
+
response: errorResponse(RpcErrorCode.InvalidRequest, 'Invalid Request: method must be "namespace.method"', id, { name: 'InvalidRequest' }),
|
|
118
|
+
};
|
|
119
|
+
}
|
|
120
|
+
|
|
121
|
+
return {
|
|
122
|
+
ok: true,
|
|
123
|
+
request: {
|
|
124
|
+
apiNamespace: parsed.method.substring(0, dotIndex),
|
|
125
|
+
method: parsed.method.substring(dotIndex + 1),
|
|
126
|
+
// JSON-RPC 2.0 §4.2: params may be an array (positional) or object (named).
|
|
127
|
+
args: Array.isArray(parsed.params)
|
|
128
|
+
? parsed.params
|
|
129
|
+
: Object.values(parsed.params ?? {}),
|
|
130
|
+
id,
|
|
131
|
+
},
|
|
132
|
+
};
|
|
133
|
+
}
|
|
134
|
+
|
|
135
|
+
/** Encode a successful result as a JSON-RPC 2.0 response string. */
|
|
136
|
+
export function successResponse(result: unknown, id: string | number | null): string {
|
|
137
|
+
return JSON.stringify({ jsonrpc: VERSION, result, id });
|
|
138
|
+
}
|
|
139
|
+
|
|
140
|
+
/**
|
|
141
|
+
* Encode an error as a JSON-RPC 2.0 response string.
|
|
142
|
+
*
|
|
143
|
+
* For `ApiError` instances the HTTP status becomes the error code (positive
|
|
144
|
+
* integers never collide with the reserved -32xxx range). Generic errors
|
|
145
|
+
* use code 500.
|
|
146
|
+
*/
|
|
147
|
+
export function errorResponseFromCatch(error: unknown, id: string | number | null): string {
|
|
148
|
+
const code = error instanceof ApiError ? error.status : 500;
|
|
149
|
+
const message = error instanceof Error ? error.message : String(error);
|
|
150
|
+
const data: Record<string, unknown> = {};
|
|
151
|
+
if (error instanceof Error && error.name && error.name !== 'Error') data.name = error.name;
|
|
152
|
+
if (error instanceof ApiError && error.retriable) data.retriable = true;
|
|
153
|
+
return errorResponse(code, message, id, Object.keys(data).length > 0 ? data : undefined);
|
|
154
|
+
}
|
|
155
|
+
|
|
156
|
+
/** Encode a "method not found" error. */
|
|
157
|
+
export function methodNotFoundResponse(detail: string, id: string | number | null): string {
|
|
158
|
+
return errorResponse(RpcErrorCode.MethodNotFound, `Method not found: ${detail}`, id);
|
|
159
|
+
}
|
|
160
|
+
|
|
161
|
+
// āā Internal āāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāā
|
|
162
|
+
|
|
163
|
+
export function errorResponse(
|
|
164
|
+
code: number,
|
|
165
|
+
message: string,
|
|
166
|
+
id: string | number | null,
|
|
167
|
+
data?: Record<string, unknown>,
|
|
168
|
+
): string {
|
|
169
|
+
return JSON.stringify({
|
|
170
|
+
jsonrpc: VERSION,
|
|
171
|
+
error: { code, message, ...(data ? { data } : {}) },
|
|
172
|
+
id,
|
|
173
|
+
});
|
|
174
|
+
}
|
|
@@ -0,0 +1,75 @@
|
|
|
1
|
+
// Copyright Amazon.com, Inc. or its affiliates. All Rights Reserved.
|
|
2
|
+
// SPDX-License-Identifier: Apache-2.0
|
|
3
|
+
|
|
4
|
+
import { describe, it, afterEach } from 'node:test';
|
|
5
|
+
import assert from 'node:assert';
|
|
6
|
+
import { mkdirSync, writeFileSync, rmSync } from 'node:fs';
|
|
7
|
+
import { join } from 'node:path';
|
|
8
|
+
import { tmpdir } from 'node:os';
|
|
9
|
+
|
|
10
|
+
import { getCdkTelemetryEnv } from './cdk-telemetry-env.js';
|
|
11
|
+
|
|
12
|
+
describe('getCdkTelemetryEnv', () => {
|
|
13
|
+
const originalEnv = { ...process.env };
|
|
14
|
+
const originalCwd = process.cwd();
|
|
15
|
+
|
|
16
|
+
afterEach(() => {
|
|
17
|
+
process.env = { ...originalEnv };
|
|
18
|
+
process.chdir(originalCwd);
|
|
19
|
+
});
|
|
20
|
+
|
|
21
|
+
it('returns CDK_CLI_USERAGENT when telemetry is enabled', () => {
|
|
22
|
+
delete process.env.AWS_BLOCKS_DISABLE_TELEMETRY;
|
|
23
|
+
// chdir to a temp dir with no .blocks/config.json so defaults apply
|
|
24
|
+
const tmp = join(tmpdir(), `cdk-telemetry-test-${Date.now()}`);
|
|
25
|
+
mkdirSync(tmp, { recursive: true });
|
|
26
|
+
process.chdir(tmp);
|
|
27
|
+
|
|
28
|
+
const env = getCdkTelemetryEnv('sandbox');
|
|
29
|
+
|
|
30
|
+
assert.ok('CDK_CLI_USERAGENT' in env, 'should have CDK_CLI_USERAGENT');
|
|
31
|
+
assert.ok(!('CDK_DISABLE_CLI_TELEMETRY' in env), 'should NOT have CDK_DISABLE_CLI_TELEMETRY');
|
|
32
|
+
assert.match(env.CDK_CLI_USERAGENT, /^aws-blocks\/.*\/sandbox$/);
|
|
33
|
+
|
|
34
|
+
rmSync(tmp, { recursive: true, force: true });
|
|
35
|
+
});
|
|
36
|
+
|
|
37
|
+
it('returns CDK_DISABLE_CLI_TELEMETRY when env var disables telemetry', () => {
|
|
38
|
+
process.env.AWS_BLOCKS_DISABLE_TELEMETRY = '1';
|
|
39
|
+
|
|
40
|
+
const env = getCdkTelemetryEnv('production');
|
|
41
|
+
|
|
42
|
+
assert.deepStrictEqual(env, { CDK_DISABLE_CLI_TELEMETRY: '1' });
|
|
43
|
+
assert.ok(!('CDK_CLI_USERAGENT' in env), 'should NOT have CDK_CLI_USERAGENT');
|
|
44
|
+
});
|
|
45
|
+
|
|
46
|
+
it('returns CDK_DISABLE_CLI_TELEMETRY when project config disables telemetry', () => {
|
|
47
|
+
delete process.env.AWS_BLOCKS_DISABLE_TELEMETRY;
|
|
48
|
+
const tmp = join(tmpdir(), `cdk-telemetry-test-${Date.now()}`);
|
|
49
|
+
mkdirSync(join(tmp, '.blocks'), { recursive: true });
|
|
50
|
+
writeFileSync(join(tmp, '.blocks', 'config.json'), JSON.stringify({ telemetry: { enabled: false } }));
|
|
51
|
+
process.chdir(tmp);
|
|
52
|
+
|
|
53
|
+
const env = getCdkTelemetryEnv('sandbox');
|
|
54
|
+
|
|
55
|
+
assert.deepStrictEqual(env, { CDK_DISABLE_CLI_TELEMETRY: '1' });
|
|
56
|
+
assert.ok(!('CDK_CLI_USERAGENT' in env), 'should NOT have CDK_CLI_USERAGENT');
|
|
57
|
+
|
|
58
|
+
rmSync(tmp, { recursive: true, force: true });
|
|
59
|
+
});
|
|
60
|
+
|
|
61
|
+
it('includes the command name in the user-agent string', () => {
|
|
62
|
+
delete process.env.AWS_BLOCKS_DISABLE_TELEMETRY;
|
|
63
|
+
const tmp = join(tmpdir(), `cdk-telemetry-test-${Date.now()}`);
|
|
64
|
+
mkdirSync(tmp, { recursive: true });
|
|
65
|
+
process.chdir(tmp);
|
|
66
|
+
|
|
67
|
+
const sandboxEnv = getCdkTelemetryEnv('sandbox');
|
|
68
|
+
const prodEnv = getCdkTelemetryEnv('production');
|
|
69
|
+
|
|
70
|
+
assert.ok(sandboxEnv.CDK_CLI_USERAGENT.endsWith('/sandbox'));
|
|
71
|
+
assert.ok(prodEnv.CDK_CLI_USERAGENT.endsWith('/production'));
|
|
72
|
+
|
|
73
|
+
rmSync(tmp, { recursive: true, force: true });
|
|
74
|
+
});
|
|
75
|
+
});
|
|
@@ -0,0 +1,23 @@
|
|
|
1
|
+
// Copyright Amazon.com, Inc. or its affiliates. All Rights Reserved.
|
|
2
|
+
// SPDX-License-Identifier: Apache-2.0
|
|
3
|
+
|
|
4
|
+
import { isTelemetryEnabled } from '../telemetry/consent.js';
|
|
5
|
+
import { CORE_VERSION } from '../version.js';
|
|
6
|
+
|
|
7
|
+
/**
|
|
8
|
+
* Build CDK CLI telemetry-related environment variables.
|
|
9
|
+
*
|
|
10
|
+
* When Blocks telemetry is enabled, sets `CDK_CLI_USERAGENT` so the CDK CLI
|
|
11
|
+
* attributes usage back to Blocks. When telemetry is disabled (user opted out),
|
|
12
|
+
* sets `CDK_DISABLE_CLI_TELEMETRY=1` to suppress CDK's own telemetry collection
|
|
13
|
+
* and omits the user-agent string.
|
|
14
|
+
*
|
|
15
|
+
* @param command - The Blocks command context (e.g. "sandbox", "production")
|
|
16
|
+
* @returns An object to spread into the child process `env`
|
|
17
|
+
*/
|
|
18
|
+
export function getCdkTelemetryEnv(command: string): Record<string, string> {
|
|
19
|
+
if (!isTelemetryEnabled()) {
|
|
20
|
+
return { CDK_DISABLE_CLI_TELEMETRY: '1' };
|
|
21
|
+
}
|
|
22
|
+
return { CDK_CLI_USERAGENT: `aws-blocks/${CORE_VERSION}/${command}` };
|
|
23
|
+
}
|
|
@@ -0,0 +1,39 @@
|
|
|
1
|
+
#!/usr/bin/env node
|
|
2
|
+
// Copyright Amazon.com, Inc. or its affiliates. All Rights Reserved.
|
|
3
|
+
// SPDX-License-Identifier: Apache-2.0
|
|
4
|
+
|
|
5
|
+
import { execSync } from 'node:child_process';
|
|
6
|
+
import { trackCommand } from '../telemetry/trackCommand.js';
|
|
7
|
+
|
|
8
|
+
export async function cleanup() {
|
|
9
|
+
return trackCommand('cleanup', async () => {
|
|
10
|
+
console.log('š§¹ Cleaning up Blocks processes...');
|
|
11
|
+
|
|
12
|
+
// Find and kill processes on common Blocks ports
|
|
13
|
+
const ports = [3000, 3001, 3002, 3003];
|
|
14
|
+
|
|
15
|
+
for (const port of ports) {
|
|
16
|
+
try {
|
|
17
|
+
const result = execSync(`lsof -ti:${port}`, { encoding: 'utf-8' }).trim();
|
|
18
|
+
if (result) {
|
|
19
|
+
const pids = result.split('\n');
|
|
20
|
+
for (const pid of pids) {
|
|
21
|
+
try {
|
|
22
|
+
execSync(`kill ${pid}`);
|
|
23
|
+
console.log(`ā Killed process ${pid} on port ${port}`);
|
|
24
|
+
} catch {}
|
|
25
|
+
}
|
|
26
|
+
}
|
|
27
|
+
} catch {
|
|
28
|
+
// No process on this port
|
|
29
|
+
}
|
|
30
|
+
}
|
|
31
|
+
|
|
32
|
+
console.log('ā Cleanup complete');
|
|
33
|
+
});
|
|
34
|
+
}
|
|
35
|
+
|
|
36
|
+
cleanup().catch((error) => {
|
|
37
|
+
console.error('Error during cleanup:', error);
|
|
38
|
+
process.exit(1);
|
|
39
|
+
});
|
|
@@ -0,0 +1,34 @@
|
|
|
1
|
+
// Copyright Amazon.com, Inc. or its affiliates. All Rights Reserved.
|
|
2
|
+
// SPDX-License-Identifier: Apache-2.0
|
|
3
|
+
|
|
4
|
+
import { execFileSync } from 'node:child_process';
|
|
5
|
+
import { readFileSync } from 'node:fs';
|
|
6
|
+
import { trackCommand } from '../telemetry/trackCommand.js';
|
|
7
|
+
|
|
8
|
+
export interface ConsoleOptions {
|
|
9
|
+
stackId?: string;
|
|
10
|
+
outputsFile?: string;
|
|
11
|
+
}
|
|
12
|
+
|
|
13
|
+
export async function openConsole(options: ConsoleOptions) {
|
|
14
|
+
return trackCommand('console', async () => {
|
|
15
|
+
let stackName: string;
|
|
16
|
+
|
|
17
|
+
if (options.stackId) {
|
|
18
|
+
stackName = options.stackId;
|
|
19
|
+
} else if (options.outputsFile) {
|
|
20
|
+
const outputs = JSON.parse(readFileSync(options.outputsFile, 'utf-8'));
|
|
21
|
+
stackName = Object.keys(outputs)[0];
|
|
22
|
+
} else {
|
|
23
|
+
throw new Error('Must provide either stackId or outputsFile');
|
|
24
|
+
}
|
|
25
|
+
|
|
26
|
+
const region = execFileSync('aws', ['configure', 'get', 'region'], { encoding: 'utf-8' }).trim() || 'us-east-1';
|
|
27
|
+
const stackUrl = `https://${region}.console.aws.amazon.com/cloudformation/home?region=${region}#/stacks?filteringText=${encodeURIComponent(stackName)}`;
|
|
28
|
+
|
|
29
|
+
console.log('Opening AWS Console...');
|
|
30
|
+
console.log(stackUrl);
|
|
31
|
+
|
|
32
|
+
execFileSync('open', [stackUrl], { stdio: 'inherit' });
|
|
33
|
+
});
|
|
34
|
+
}
|
|
@@ -0,0 +1,106 @@
|
|
|
1
|
+
// Copyright Amazon.com, Inc. or its affiliates. All Rights Reserved.
|
|
2
|
+
// SPDX-License-Identifier: Apache-2.0
|
|
3
|
+
|
|
4
|
+
import { execFileSync } from 'node:child_process';
|
|
5
|
+
import { readFileSync, writeFileSync, mkdirSync } from 'node:fs';
|
|
6
|
+
import { join, resolve, dirname } from 'node:path';
|
|
7
|
+
import { fileURLToPath, pathToFileURL } from 'node:url';
|
|
8
|
+
import { ensureSecrets, loadProductionEnv } from './ensure-secrets.js';
|
|
9
|
+
import { applyExternalMigrations } from './external-migrations-step.js';
|
|
10
|
+
import { trackCommand } from '../telemetry/trackCommand.js';
|
|
11
|
+
import { getCdkTelemetryEnv } from './cdk-telemetry-env.js';
|
|
12
|
+
|
|
13
|
+
export interface DeployOptions {
|
|
14
|
+
cdkAppPath: string;
|
|
15
|
+
projectRoot: string;
|
|
16
|
+
}
|
|
17
|
+
|
|
18
|
+
export async function deploy(options: DeployOptions) {
|
|
19
|
+
return trackCommand('deploy', async () => {
|
|
20
|
+
console.log('šļø Preparing deployment...');
|
|
21
|
+
|
|
22
|
+
// Load production environment (from .env.production or CI env vars)
|
|
23
|
+
loadProductionEnv();
|
|
24
|
+
|
|
25
|
+
process.env.BLOCKS_STAGE = 'production';
|
|
26
|
+
|
|
27
|
+
// Provision secrets for production
|
|
28
|
+
const secrets = await ensureSecrets('production');
|
|
29
|
+
if (secrets.created.length > 0 || secrets.updated.length > 0) {
|
|
30
|
+
console.log(`š Secrets provisioned: ${[...secrets.created, ...secrets.updated].join(', ')}`);
|
|
31
|
+
}
|
|
32
|
+
|
|
33
|
+
// Apply external-database migrations to the production database before
|
|
34
|
+
// deploying. No-op unless this app uses an external DB and has ./migrations.
|
|
35
|
+
await applyExternalMigrations({ stage: 'production' });
|
|
36
|
+
|
|
37
|
+
// Import backend to populate BB registry for telemetry
|
|
38
|
+
const foundationPath = resolve(options.projectRoot, 'aws-blocks/index.ts');
|
|
39
|
+
try {
|
|
40
|
+
await import(pathToFileURL(foundationPath).href);
|
|
41
|
+
} catch { /* ignore import errors */ }
|
|
42
|
+
|
|
43
|
+
// Generate client code FIRST (before cdk deploy triggers the Vite build)
|
|
44
|
+
const clientPath = join(dirname(foundationPath), 'client.js');
|
|
45
|
+
console.log('š Generating client code...');
|
|
46
|
+
const __dirname = dirname(fileURLToPath(import.meta.url));
|
|
47
|
+
const workerPath = join(__dirname, 'generate-client-worker.js');
|
|
48
|
+
execFileSync('node', ['--conditions=aws-runtime', '--import', 'tsx', workerPath, foundationPath, clientPath], {
|
|
49
|
+
stdio: 'inherit',
|
|
50
|
+
env: { ...process.env, NODE_OPTIONS: '' },
|
|
51
|
+
});
|
|
52
|
+
|
|
53
|
+
console.log('š Deploying to AWS...');
|
|
54
|
+
console.log(' (This may take a few minutes on first deploy)');
|
|
55
|
+
console.log(' - Backend API (Lambda + API Gateway)');
|
|
56
|
+
console.log(' - Frontend hosting (S3 + CloudFront)');
|
|
57
|
+
|
|
58
|
+
try {
|
|
59
|
+
execFileSync(
|
|
60
|
+
"npx",
|
|
61
|
+
[
|
|
62
|
+
"cdk", "deploy",
|
|
63
|
+
"--require-approval", "never",
|
|
64
|
+
"--outputs-file", ".blocks-sandbox/outputs.json",
|
|
65
|
+
"--context", `projectRoot=${options.projectRoot}`,
|
|
66
|
+
],
|
|
67
|
+
{
|
|
68
|
+
stdio: 'inherit',
|
|
69
|
+
cwd: options.projectRoot,
|
|
70
|
+
env: {
|
|
71
|
+
...process.env,
|
|
72
|
+
NODE_OPTIONS: '--conditions=cdk',
|
|
73
|
+
...getCdkTelemetryEnv('production')
|
|
74
|
+
}
|
|
75
|
+
}
|
|
76
|
+
);
|
|
77
|
+
} catch (error) {
|
|
78
|
+
console.error('\nā Deployment failed.');
|
|
79
|
+
throw error;
|
|
80
|
+
}
|
|
81
|
+
|
|
82
|
+
const outputs = JSON.parse(readFileSync(join(options.projectRoot, '.blocks-sandbox', 'outputs.json'), 'utf-8'));
|
|
83
|
+
const stackOutputs = Object.values(outputs)[0] as Record<string, string>;
|
|
84
|
+
const apiUrl = stackOutputs.ApiUrl;
|
|
85
|
+
|
|
86
|
+
const hostingUrl = Object.entries(stackOutputs).find(([key]) =>
|
|
87
|
+
key.includes('Hosting') && key.includes('Url')
|
|
88
|
+
)?.[1];
|
|
89
|
+
|
|
90
|
+
if (!apiUrl) {
|
|
91
|
+
throw new Error('Could not find API URL in CDK outputs');
|
|
92
|
+
}
|
|
93
|
+
|
|
94
|
+
// Write config.json with API endpoint
|
|
95
|
+
const config: Record<string, string> = { apiUrl, environment: 'production' };
|
|
96
|
+
const outDir = join(options.projectRoot, '.blocks-sandbox');
|
|
97
|
+
mkdirSync(outDir, { recursive: true });
|
|
98
|
+
writeFileSync(join(outDir, 'config.json'), JSON.stringify(config, null, 2));
|
|
99
|
+
|
|
100
|
+
console.log('\nā
Deployment complete!');
|
|
101
|
+
console.log(`\nš” API URL: ${apiUrl}`);
|
|
102
|
+
if (hostingUrl) {
|
|
103
|
+
console.log(`š Frontend URL: ${hostingUrl}`);
|
|
104
|
+
}
|
|
105
|
+
});
|
|
106
|
+
}
|
|
@@ -0,0 +1,42 @@
|
|
|
1
|
+
// Copyright Amazon.com, Inc. or its affiliates. All Rights Reserved.
|
|
2
|
+
// SPDX-License-Identifier: Apache-2.0
|
|
3
|
+
|
|
4
|
+
import { execFileSync } from 'node:child_process';
|
|
5
|
+
import { trackCommand } from '../telemetry/trackCommand.js';
|
|
6
|
+
import { getCdkTelemetryEnv } from './cdk-telemetry-env.js';
|
|
7
|
+
|
|
8
|
+
export interface DestroyOptions {
|
|
9
|
+
cdkAppPath: string;
|
|
10
|
+
projectRoot: string;
|
|
11
|
+
}
|
|
12
|
+
|
|
13
|
+
export async function destroy(options: DestroyOptions) {
|
|
14
|
+
return trackCommand('destroy', async () => {
|
|
15
|
+
console.log('šļø Destroying production stack...');
|
|
16
|
+
|
|
17
|
+
try {
|
|
18
|
+
execFileSync(
|
|
19
|
+
"npx",
|
|
20
|
+
[
|
|
21
|
+
"cdk", "destroy",
|
|
22
|
+
"--force",
|
|
23
|
+
"--context", `projectRoot=${options.projectRoot}`,
|
|
24
|
+
],
|
|
25
|
+
{
|
|
26
|
+
stdio: 'inherit',
|
|
27
|
+
cwd: options.projectRoot,
|
|
28
|
+
env: {
|
|
29
|
+
...process.env,
|
|
30
|
+
NODE_OPTIONS: '--conditions=cdk',
|
|
31
|
+
...getCdkTelemetryEnv('production')
|
|
32
|
+
}
|
|
33
|
+
}
|
|
34
|
+
);
|
|
35
|
+
} catch (error) {
|
|
36
|
+
console.error('\nā Destroy failed.');
|
|
37
|
+
throw error;
|
|
38
|
+
}
|
|
39
|
+
|
|
40
|
+
console.log('\nā
Production stack destroyed!');
|
|
41
|
+
});
|
|
42
|
+
}
|
|
@@ -0,0 +1,28 @@
|
|
|
1
|
+
// Copyright Amazon.com, Inc. or its affiliates. All Rights Reserved.
|
|
2
|
+
// SPDX-License-Identifier: Apache-2.0
|
|
3
|
+
import { describe, it } from 'node:test';
|
|
4
|
+
import assert from 'node:assert';
|
|
5
|
+
import { resolveDevCorsOrigin, LOCALHOST_PATTERN } from './dev-server.js';
|
|
6
|
+
|
|
7
|
+
describe('resolveDevCorsOrigin ā dev server CORS', () => {
|
|
8
|
+
it('reflects localhost origin back as-is', () => {
|
|
9
|
+
assert.strictEqual(resolveDevCorsOrigin('http://localhost:3000'), 'http://localhost:3000');
|
|
10
|
+
});
|
|
11
|
+
|
|
12
|
+
it('reflects 127.0.0.1 origin back as-is', () => {
|
|
13
|
+
assert.strictEqual(resolveDevCorsOrigin('http://127.0.0.1:3000'), 'http://127.0.0.1:3000');
|
|
14
|
+
});
|
|
15
|
+
|
|
16
|
+
it('returns fallback http://localhost:3000 for non-localhost origin', () => {
|
|
17
|
+
assert.strictEqual(resolveDevCorsOrigin('https://evil.com'), 'http://localhost:3000');
|
|
18
|
+
});
|
|
19
|
+
|
|
20
|
+
it('returns fallback http://localhost:3000 when origin is empty', () => {
|
|
21
|
+
assert.strictEqual(resolveDevCorsOrigin(''), 'http://localhost:3000');
|
|
22
|
+
});
|
|
23
|
+
|
|
24
|
+
it('rejects subdomain impersonation (evil.localhost)', () => {
|
|
25
|
+
assert.strictEqual(LOCALHOST_PATTERN.test('http://localhost.evil.com'), false);
|
|
26
|
+
assert.strictEqual(resolveDevCorsOrigin('http://localhost.evil.com'), 'http://localhost:3000');
|
|
27
|
+
});
|
|
28
|
+
});
|