@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,497 @@
|
|
|
1
|
+
// Copyright Amazon.com, Inc. or its affiliates. All Rights Reserved.
|
|
2
|
+
// SPDX-License-Identifier: Apache-2.0
|
|
3
|
+
/**
|
|
4
|
+
* Tests for extract-ts-types.ts — verifies that `new ApiNamespace(...)`
|
|
5
|
+
* calls and indirect calls (e.g., auth.createApi()) produce proper type info.
|
|
6
|
+
*/
|
|
7
|
+
import { describe, it } from 'node:test';
|
|
8
|
+
import assert from 'node:assert';
|
|
9
|
+
import { extractMethodTypes, extractSkipCodegenMethods } from './extract-ts-types.js';
|
|
10
|
+
import { writeFileSync, mkdirSync, rmSync } from 'fs';
|
|
11
|
+
import { join } from 'path';
|
|
12
|
+
import { tmpdir } from 'os';
|
|
13
|
+
function createTempProject(files) {
|
|
14
|
+
const dir = join(tmpdir(), `blocks-ts-test-${Date.now()}`);
|
|
15
|
+
mkdirSync(dir, { recursive: true });
|
|
16
|
+
for (const [name, content] of Object.entries(files)) {
|
|
17
|
+
const filePath = join(dir, name);
|
|
18
|
+
mkdirSync(join(filePath, '..'), { recursive: true });
|
|
19
|
+
writeFileSync(filePath, content);
|
|
20
|
+
}
|
|
21
|
+
return dir;
|
|
22
|
+
}
|
|
23
|
+
/** Minimal mock so `new ApiNamespace(scope, name, handler)` parses as a NewExpression and types correctly. */
|
|
24
|
+
const API_NS_MOCK = `
|
|
25
|
+
interface ApiNamespaceConstructor { new <T>(scope: any, name: string, handler: (ctx: any) => T): T; }
|
|
26
|
+
const ApiNamespace: ApiNamespaceConstructor = class {} as any;
|
|
27
|
+
`;
|
|
28
|
+
describe('extractMethodTypes — direct ApiNamespace calls', () => {
|
|
29
|
+
it('extracts param and return types from inline ApiNamespace', () => {
|
|
30
|
+
const dir = createTempProject({
|
|
31
|
+
'tsconfig.json': JSON.stringify({
|
|
32
|
+
compilerOptions: {
|
|
33
|
+
target: 'ESNext',
|
|
34
|
+
module: 'ESNext',
|
|
35
|
+
moduleResolution: 'bundler',
|
|
36
|
+
strict: true,
|
|
37
|
+
},
|
|
38
|
+
}),
|
|
39
|
+
'index.ts': `
|
|
40
|
+
${API_NS_MOCK}
|
|
41
|
+
|
|
42
|
+
interface User { id: string; name: string; }
|
|
43
|
+
|
|
44
|
+
export const api = new ApiNamespace(null, 'api', (context) => ({
|
|
45
|
+
async getUser(id: string): Promise<User | null> {
|
|
46
|
+
return null;
|
|
47
|
+
},
|
|
48
|
+
async createUser(name: string, age: number) {
|
|
49
|
+
return { success: true };
|
|
50
|
+
},
|
|
51
|
+
}));
|
|
52
|
+
`,
|
|
53
|
+
});
|
|
54
|
+
try {
|
|
55
|
+
const types = extractMethodTypes(join(dir, 'index.ts'));
|
|
56
|
+
assert.ok(types.has('getUser'), 'should find getUser');
|
|
57
|
+
assert.ok(types.has('createUser'), 'should find createUser');
|
|
58
|
+
const getUser = types.get('getUser');
|
|
59
|
+
assert.strictEqual(getUser.params.length, 1);
|
|
60
|
+
assert.strictEqual(getUser.params[0].name, 'id');
|
|
61
|
+
assert.strictEqual(getUser.params[0].schema.type, 'string');
|
|
62
|
+
const createUser = types.get('createUser');
|
|
63
|
+
assert.strictEqual(createUser.params.length, 2);
|
|
64
|
+
assert.strictEqual(createUser.params[0].schema.type, 'string');
|
|
65
|
+
assert.strictEqual(createUser.params[1].schema.type, 'number');
|
|
66
|
+
}
|
|
67
|
+
finally {
|
|
68
|
+
rmSync(dir, { recursive: true, force: true });
|
|
69
|
+
}
|
|
70
|
+
});
|
|
71
|
+
});
|
|
72
|
+
describe('extractSkipCodegenMethods — pure-AST scan', () => {
|
|
73
|
+
it('returns names of methods tagged with @blocksSkipCodegen, ignoring untagged ones', () => {
|
|
74
|
+
const dir = createTempProject({
|
|
75
|
+
// No tsconfig deliberately — this entry must work without one,
|
|
76
|
+
// since `extractMethodTypes` may crash on a half-resolvable
|
|
77
|
+
// program but the JSDoc scan should still succeed.
|
|
78
|
+
'index.ts': `
|
|
79
|
+
class ApiNamespace { constructor(scope: any, name: any, handler: any) {} }
|
|
80
|
+
|
|
81
|
+
export const api = new ApiNamespace(null, 'api', (context) => ({
|
|
82
|
+
async normalMethod() { return { ok: true }; },
|
|
83
|
+
|
|
84
|
+
/**
|
|
85
|
+
* @blocksSkipCodegen
|
|
86
|
+
*/
|
|
87
|
+
async devOnly() { return null; },
|
|
88
|
+
|
|
89
|
+
/** Plain JSDoc, not tagged. */
|
|
90
|
+
async alsoNormal() { return 1; },
|
|
91
|
+
}));
|
|
92
|
+
`,
|
|
93
|
+
});
|
|
94
|
+
try {
|
|
95
|
+
const skips = extractSkipCodegenMethods(join(dir, 'index.ts'));
|
|
96
|
+
assert.strictEqual(skips.size, 1);
|
|
97
|
+
assert.ok(skips.has('devOnly'));
|
|
98
|
+
assert.ok(!skips.has('normalMethod'));
|
|
99
|
+
assert.ok(!skips.has('alsoNormal'));
|
|
100
|
+
}
|
|
101
|
+
finally {
|
|
102
|
+
rmSync(dir, { recursive: true, force: true });
|
|
103
|
+
}
|
|
104
|
+
});
|
|
105
|
+
it('returns an empty set when the file has no ApiNamespace calls', () => {
|
|
106
|
+
const dir = createTempProject({
|
|
107
|
+
'index.ts': `export const x = 1;`,
|
|
108
|
+
});
|
|
109
|
+
try {
|
|
110
|
+
const skips = extractSkipCodegenMethods(join(dir, 'index.ts'));
|
|
111
|
+
assert.strictEqual(skips.size, 0);
|
|
112
|
+
}
|
|
113
|
+
finally {
|
|
114
|
+
rmSync(dir, { recursive: true, force: true });
|
|
115
|
+
}
|
|
116
|
+
});
|
|
117
|
+
});
|
|
118
|
+
describe('extractMethodTypes — @blocksSkipCodegen JSDoc tag', () => {
|
|
119
|
+
it('flags methods with @blocksSkipCodegen so the spec emitter can drop them', () => {
|
|
120
|
+
const dir = createTempProject({
|
|
121
|
+
'tsconfig.json': JSON.stringify({
|
|
122
|
+
compilerOptions: {
|
|
123
|
+
target: 'ESNext',
|
|
124
|
+
module: 'ESNext',
|
|
125
|
+
moduleResolution: 'bundler',
|
|
126
|
+
strict: true,
|
|
127
|
+
},
|
|
128
|
+
}),
|
|
129
|
+
'index.ts': `
|
|
130
|
+
${API_NS_MOCK}
|
|
131
|
+
|
|
132
|
+
export const api = new ApiNamespace(null, 'api', (context) => ({
|
|
133
|
+
async normalMethod() {
|
|
134
|
+
return { ok: true };
|
|
135
|
+
},
|
|
136
|
+
|
|
137
|
+
/**
|
|
138
|
+
* Mock-only helper. Should not show up in native codegen.
|
|
139
|
+
* @blocksSkipCodegen
|
|
140
|
+
*/
|
|
141
|
+
async getLastCode() {
|
|
142
|
+
return null as { code: string } | null;
|
|
143
|
+
},
|
|
144
|
+
}));
|
|
145
|
+
`,
|
|
146
|
+
});
|
|
147
|
+
try {
|
|
148
|
+
const types = extractMethodTypes(join(dir, 'index.ts'));
|
|
149
|
+
assert.strictEqual(types.get('normalMethod')?.skipCodegen, undefined);
|
|
150
|
+
assert.strictEqual(types.get('getLastCode')?.skipCodegen, true);
|
|
151
|
+
}
|
|
152
|
+
finally {
|
|
153
|
+
rmSync(dir, { recursive: true, force: true });
|
|
154
|
+
}
|
|
155
|
+
});
|
|
156
|
+
});
|
|
157
|
+
describe('extractMethodTypes — indirect ApiNamespace calls (e.g., auth.createApi())', () => {
|
|
158
|
+
it('extracts types from methods returned by a helper method', () => {
|
|
159
|
+
const dir = createTempProject({
|
|
160
|
+
'tsconfig.json': JSON.stringify({
|
|
161
|
+
compilerOptions: {
|
|
162
|
+
target: 'ESNext',
|
|
163
|
+
module: 'ESNext',
|
|
164
|
+
moduleResolution: 'bundler',
|
|
165
|
+
strict: true,
|
|
166
|
+
},
|
|
167
|
+
}),
|
|
168
|
+
'auth.ts': `
|
|
169
|
+
${API_NS_MOCK}
|
|
170
|
+
|
|
171
|
+
interface AuthState {
|
|
172
|
+
isSignedIn: boolean;
|
|
173
|
+
username: string | null;
|
|
174
|
+
error?: string;
|
|
175
|
+
}
|
|
176
|
+
|
|
177
|
+
export class AuthBasic {
|
|
178
|
+
createApi() {
|
|
179
|
+
return new ApiNamespace(null, 'auth', (context) => ({
|
|
180
|
+
async getAuthState(): Promise<AuthState> {
|
|
181
|
+
return { isSignedIn: false, username: null };
|
|
182
|
+
},
|
|
183
|
+
async setAuthState(action: string, fields: Record<string, string>): Promise<AuthState> {
|
|
184
|
+
return { isSignedIn: false, username: null };
|
|
185
|
+
},
|
|
186
|
+
}));
|
|
187
|
+
}
|
|
188
|
+
}
|
|
189
|
+
`,
|
|
190
|
+
'index.ts': `
|
|
191
|
+
import { AuthBasic } from './auth.js';
|
|
192
|
+
|
|
193
|
+
${API_NS_MOCK}
|
|
194
|
+
|
|
195
|
+
const auth = new AuthBasic();
|
|
196
|
+
|
|
197
|
+
export const api = new ApiNamespace(null, 'api', (context) => ({
|
|
198
|
+
async greet(name: string) {
|
|
199
|
+
return { message: 'hello ' + name };
|
|
200
|
+
},
|
|
201
|
+
}));
|
|
202
|
+
|
|
203
|
+
export const authApi = auth.createApi();
|
|
204
|
+
`,
|
|
205
|
+
});
|
|
206
|
+
try {
|
|
207
|
+
const types = extractMethodTypes(join(dir, 'index.ts'));
|
|
208
|
+
// Direct ApiNamespace methods should still work
|
|
209
|
+
assert.ok(types.has('greet'), 'should find greet from direct ApiNamespace');
|
|
210
|
+
const greet = types.get('greet');
|
|
211
|
+
assert.strictEqual(greet.params[0].name, 'name');
|
|
212
|
+
assert.strictEqual(greet.params[0].schema.type, 'string');
|
|
213
|
+
// Indirect methods from auth.createApi() should now be resolved
|
|
214
|
+
assert.ok(types.has('getAuthState'), 'should find getAuthState from auth.createApi()');
|
|
215
|
+
assert.ok(types.has('setAuthState'), 'should find setAuthState from auth.createApi()');
|
|
216
|
+
const getAuthState = types.get('getAuthState');
|
|
217
|
+
assert.strictEqual(getAuthState.params.length, 0, 'getAuthState has no params');
|
|
218
|
+
assert.strictEqual(getAuthState.returnType.type, 'object', 'return type should be object');
|
|
219
|
+
assert.ok(getAuthState.returnType.properties, 'return type should have properties');
|
|
220
|
+
assert.ok('isSignedIn' in getAuthState.returnType.properties, 'should have isSignedIn');
|
|
221
|
+
assert.ok('username' in getAuthState.returnType.properties, 'should have username');
|
|
222
|
+
const setAuthState = types.get('setAuthState');
|
|
223
|
+
assert.strictEqual(setAuthState.params.length, 2, 'setAuthState has 2 params');
|
|
224
|
+
assert.strictEqual(setAuthState.params[0].name, 'action');
|
|
225
|
+
assert.strictEqual(setAuthState.params[0].schema.type, 'string');
|
|
226
|
+
assert.strictEqual(setAuthState.params[1].name, 'fields');
|
|
227
|
+
assert.strictEqual(setAuthState.params[1].schema.type, 'object');
|
|
228
|
+
// Record<string, string> should emit additionalProperties: { type: 'string' }
|
|
229
|
+
assert.deepStrictEqual(setAuthState.params[1].schema.additionalProperties, { type: 'string' }, 'Record<string, string> should have additionalProperties: { type: "string" }');
|
|
230
|
+
}
|
|
231
|
+
finally {
|
|
232
|
+
rmSync(dir, { recursive: true, force: true });
|
|
233
|
+
}
|
|
234
|
+
});
|
|
235
|
+
it('does not overwrite methods already found by AST walk', () => {
|
|
236
|
+
const dir = createTempProject({
|
|
237
|
+
'tsconfig.json': JSON.stringify({
|
|
238
|
+
compilerOptions: {
|
|
239
|
+
target: 'ESNext',
|
|
240
|
+
module: 'ESNext',
|
|
241
|
+
moduleResolution: 'bundler',
|
|
242
|
+
strict: true,
|
|
243
|
+
},
|
|
244
|
+
}),
|
|
245
|
+
'index.ts': `
|
|
246
|
+
${API_NS_MOCK}
|
|
247
|
+
|
|
248
|
+
// new ApiNamespace — AST walk finds this
|
|
249
|
+
export const api = new ApiNamespace(null, 'api', (context) => ({
|
|
250
|
+
async greet(name: string) {
|
|
251
|
+
return { message: 'hello ' + name };
|
|
252
|
+
},
|
|
253
|
+
}));
|
|
254
|
+
`,
|
|
255
|
+
});
|
|
256
|
+
try {
|
|
257
|
+
const types = extractMethodTypes(join(dir, 'index.ts'));
|
|
258
|
+
assert.ok(types.has('greet'), 'should find greet');
|
|
259
|
+
// The AST-walk version should be preserved (it has richer info from the declaration)
|
|
260
|
+
assert.strictEqual(types.get('greet').params[0].name, 'name');
|
|
261
|
+
}
|
|
262
|
+
finally {
|
|
263
|
+
rmSync(dir, { recursive: true, force: true });
|
|
264
|
+
}
|
|
265
|
+
});
|
|
266
|
+
});
|
|
267
|
+
// ── Transferable detection ──────────────────────────────────────────────────
|
|
268
|
+
// A "transferable" is a return type carrying a live handle (e.g.
|
|
269
|
+
// `RealtimeChannel`, `FileDownloadHandle`). It implements `toJSON()` returning
|
|
270
|
+
// a descriptor with a `__blocks: '<tag>'` literal. The spec emitter lowers that
|
|
271
|
+
// into `x-blocks-transferable: '<tag>'` so native client codegen can reconstruct
|
|
272
|
+
// a live handle on the receiving side. These tests target detection — the
|
|
273
|
+
// emission step is straight-line glue and is exercised end-to-end every time
|
|
274
|
+
// a customer's BB returns a transferable.
|
|
275
|
+
const TRANSFERABLE_TSCONFIG = JSON.stringify({
|
|
276
|
+
compilerOptions: {
|
|
277
|
+
target: 'ESNext',
|
|
278
|
+
module: 'ESNext',
|
|
279
|
+
moduleResolution: 'bundler',
|
|
280
|
+
strict: true,
|
|
281
|
+
esModuleInterop: true,
|
|
282
|
+
skipLibCheck: true,
|
|
283
|
+
},
|
|
284
|
+
});
|
|
285
|
+
/**
|
|
286
|
+
* Inline definitions of the transferable protocol + a couple of common
|
|
287
|
+
* handles. Reusing one source-of-truth string keeps the per-test fixtures
|
|
288
|
+
* small and focused on the variation under test.
|
|
289
|
+
*/
|
|
290
|
+
const TRANSFERABLE_PRELUDE = `
|
|
291
|
+
${API_NS_MOCK}
|
|
292
|
+
|
|
293
|
+
interface RealtimeChannelDescriptor { __blocks: 'realtime/channel'; channel: string; }
|
|
294
|
+
interface RealtimeChannel<T = unknown> {
|
|
295
|
+
subscribe(handler: (message: T) => void): void;
|
|
296
|
+
toJSON(): RealtimeChannelDescriptor;
|
|
297
|
+
}
|
|
298
|
+
|
|
299
|
+
interface FileDownloadDescriptor { __blocks: 'file-bucket/download'; url: string; }
|
|
300
|
+
interface FileDownloadHandle {
|
|
301
|
+
download(): Promise<Blob>;
|
|
302
|
+
toJSON(): FileDownloadDescriptor;
|
|
303
|
+
}
|
|
304
|
+
`;
|
|
305
|
+
describe('extractMethodTypes — transferable detection', () => {
|
|
306
|
+
it('identifies a generic transferable and resolves its written type arg', () => {
|
|
307
|
+
const dir = createTempProject({
|
|
308
|
+
'tsconfig.json': TRANSFERABLE_TSCONFIG,
|
|
309
|
+
'index.ts': `
|
|
310
|
+
${TRANSFERABLE_PRELUDE}
|
|
311
|
+
interface CursorPosition { userId: string; x: number; y: number; }
|
|
312
|
+
export const api = new ApiNamespace(null, 'api', () => ({
|
|
313
|
+
async getCursorChannel(): Promise<RealtimeChannel<CursorPosition>> { return null as any; },
|
|
314
|
+
}));
|
|
315
|
+
`,
|
|
316
|
+
});
|
|
317
|
+
try {
|
|
318
|
+
const info = extractMethodTypes(join(dir, 'index.ts')).get('getCursorChannel');
|
|
319
|
+
assert.ok(info, 'method should be discovered');
|
|
320
|
+
assert.ok(info.transferable, 'should be detected as transferable');
|
|
321
|
+
assert.strictEqual(info.transferable.blocksTag, 'realtime/channel');
|
|
322
|
+
assert.strictEqual(info.transferable.typeArgs.length, 1);
|
|
323
|
+
const arg = info.transferable.typeArgs[0];
|
|
324
|
+
assert.strictEqual(arg.title, 'CursorPosition');
|
|
325
|
+
assert.strictEqual(arg.properties?.userId?.type, 'string');
|
|
326
|
+
assert.strictEqual(arg.properties?.x?.type, 'number');
|
|
327
|
+
}
|
|
328
|
+
finally {
|
|
329
|
+
rmSync(dir, { recursive: true, force: true });
|
|
330
|
+
}
|
|
331
|
+
});
|
|
332
|
+
it('identifies a non-generic transferable with no type args', () => {
|
|
333
|
+
const dir = createTempProject({
|
|
334
|
+
'tsconfig.json': TRANSFERABLE_TSCONFIG,
|
|
335
|
+
'index.ts': `
|
|
336
|
+
${TRANSFERABLE_PRELUDE}
|
|
337
|
+
export const api = new ApiNamespace(null, 'api', () => ({
|
|
338
|
+
async getDownload(): Promise<FileDownloadHandle> { return null as any; },
|
|
339
|
+
}));
|
|
340
|
+
`,
|
|
341
|
+
});
|
|
342
|
+
try {
|
|
343
|
+
const info = extractMethodTypes(join(dir, 'index.ts')).get('getDownload');
|
|
344
|
+
assert.ok(info?.transferable);
|
|
345
|
+
assert.strictEqual(info.transferable.blocksTag, 'file-bucket/download');
|
|
346
|
+
assert.deepStrictEqual(info.transferable.typeArgs, []);
|
|
347
|
+
}
|
|
348
|
+
finally {
|
|
349
|
+
rmSync(dir, { recursive: true, force: true });
|
|
350
|
+
}
|
|
351
|
+
});
|
|
352
|
+
it('distinguishes default-unknown from explicit-unknown type args', () => {
|
|
353
|
+
const dir = createTempProject({
|
|
354
|
+
'tsconfig.json': TRANSFERABLE_TSCONFIG,
|
|
355
|
+
'index.ts': `
|
|
356
|
+
${TRANSFERABLE_PRELUDE}
|
|
357
|
+
export const api = new ApiNamespace(null, 'api', () => ({
|
|
358
|
+
async defaulted(): Promise<RealtimeChannel> { return null as any; },
|
|
359
|
+
async explicit(): Promise<RealtimeChannel<unknown>> { return null as any; },
|
|
360
|
+
}));
|
|
361
|
+
`,
|
|
362
|
+
});
|
|
363
|
+
try {
|
|
364
|
+
const types = extractMethodTypes(join(dir, 'index.ts'));
|
|
365
|
+
assert.deepStrictEqual(types.get('defaulted')?.transferable?.typeArgs, []);
|
|
366
|
+
assert.deepStrictEqual(types.get('explicit')?.transferable?.typeArgs, [{}]);
|
|
367
|
+
}
|
|
368
|
+
finally {
|
|
369
|
+
rmSync(dir, { recursive: true, force: true });
|
|
370
|
+
}
|
|
371
|
+
});
|
|
372
|
+
it('returns no transferable info when toJSON is missing or __blocks is not a literal', () => {
|
|
373
|
+
const dir = createTempProject({
|
|
374
|
+
'tsconfig.json': TRANSFERABLE_TSCONFIG,
|
|
375
|
+
'index.ts': `
|
|
376
|
+
${API_NS_MOCK}
|
|
377
|
+
interface Plain { value: number; }
|
|
378
|
+
interface NotLiteral { toJSON(): { __blocks: string; channel: string }; }
|
|
379
|
+
export const api = new ApiNamespace(null, 'api', () => ({
|
|
380
|
+
async plain(): Promise<Plain> { return null as any; },
|
|
381
|
+
async loose(): Promise<NotLiteral> { return null as any; },
|
|
382
|
+
}));
|
|
383
|
+
`,
|
|
384
|
+
});
|
|
385
|
+
try {
|
|
386
|
+
const types = extractMethodTypes(join(dir, 'index.ts'));
|
|
387
|
+
assert.strictEqual(types.get('plain')?.transferable, undefined);
|
|
388
|
+
assert.strictEqual(types.get('loose')?.transferable, undefined);
|
|
389
|
+
}
|
|
390
|
+
finally {
|
|
391
|
+
rmSync(dir, { recursive: true, force: true });
|
|
392
|
+
}
|
|
393
|
+
});
|
|
394
|
+
it('detects transferables imported from another module', () => {
|
|
395
|
+
const dir = createTempProject({
|
|
396
|
+
'tsconfig.json': TRANSFERABLE_TSCONFIG,
|
|
397
|
+
'handles.ts': `
|
|
398
|
+
export interface MessageDescriptor { __blocks: 'realtime/channel'; channel: string; }
|
|
399
|
+
export interface MessageChannel<T = unknown> {
|
|
400
|
+
subscribe(h: (m: T) => void): void;
|
|
401
|
+
toJSON(): MessageDescriptor;
|
|
402
|
+
}
|
|
403
|
+
`,
|
|
404
|
+
'index.ts': `
|
|
405
|
+
import type { MessageChannel } from './handles.js';
|
|
406
|
+
${API_NS_MOCK}
|
|
407
|
+
interface Notification { id: string; message: string; }
|
|
408
|
+
export const api = new ApiNamespace(null, 'api', () => ({
|
|
409
|
+
async getNotifications(): Promise<MessageChannel<Notification>> { return null as any; },
|
|
410
|
+
}));
|
|
411
|
+
`,
|
|
412
|
+
});
|
|
413
|
+
try {
|
|
414
|
+
const info = extractMethodTypes(join(dir, 'index.ts')).get('getNotifications');
|
|
415
|
+
assert.ok(info?.transferable);
|
|
416
|
+
assert.strictEqual(info.transferable.blocksTag, 'realtime/channel');
|
|
417
|
+
assert.strictEqual(info.transferable.typeArgs[0]?.title, 'Notification');
|
|
418
|
+
}
|
|
419
|
+
finally {
|
|
420
|
+
rmSync(dir, { recursive: true, force: true });
|
|
421
|
+
}
|
|
422
|
+
});
|
|
423
|
+
});
|
|
424
|
+
describe('extractMethodTypes — open-shape intersections', () => {
|
|
425
|
+
it('preserves additionalProperties from `T & Record<string, V>` intersections', () => {
|
|
426
|
+
const dir = createTempProject({
|
|
427
|
+
'tsconfig.json': JSON.stringify({
|
|
428
|
+
compilerOptions: {
|
|
429
|
+
target: 'ESNext',
|
|
430
|
+
module: 'ESNext',
|
|
431
|
+
moduleResolution: 'bundler',
|
|
432
|
+
strict: true,
|
|
433
|
+
},
|
|
434
|
+
}),
|
|
435
|
+
'index.ts': `
|
|
436
|
+
${API_NS_MOCK}
|
|
437
|
+
|
|
438
|
+
// Mirrors AuthCognito's signUp payload: fixed fields plus an open
|
|
439
|
+
// string-keyed bag for custom attributes.
|
|
440
|
+
type SignUpInput = { username: string; password: string } & Record<string, string>;
|
|
441
|
+
|
|
442
|
+
export const api = new ApiNamespace(null, 'api', () => ({
|
|
443
|
+
async signUp(input: SignUpInput) { return { success: true }; },
|
|
444
|
+
}));
|
|
445
|
+
`,
|
|
446
|
+
});
|
|
447
|
+
try {
|
|
448
|
+
const info = extractMethodTypes(join(dir, 'index.ts')).get('signUp');
|
|
449
|
+
assert.ok(info, 'should find signUp');
|
|
450
|
+
const inputSchema = info.params[0].schema;
|
|
451
|
+
assert.strictEqual(inputSchema.type, 'object');
|
|
452
|
+
assert.ok(inputSchema.properties?.username, 'fixed username property survives');
|
|
453
|
+
assert.ok(inputSchema.properties?.password, 'fixed password property survives');
|
|
454
|
+
assert.ok(inputSchema.additionalProperties, 'open shape preserved as additionalProperties');
|
|
455
|
+
assert.strictEqual(inputSchema.additionalProperties.type, 'string');
|
|
456
|
+
}
|
|
457
|
+
finally {
|
|
458
|
+
rmSync(dir, { recursive: true, force: true });
|
|
459
|
+
}
|
|
460
|
+
});
|
|
461
|
+
it('emits additionalProperties for object types with index signatures alongside fixed properties', () => {
|
|
462
|
+
const dir = createTempProject({
|
|
463
|
+
'tsconfig.json': JSON.stringify({
|
|
464
|
+
compilerOptions: {
|
|
465
|
+
target: 'ESNext',
|
|
466
|
+
module: 'ESNext',
|
|
467
|
+
moduleResolution: 'bundler',
|
|
468
|
+
strict: true,
|
|
469
|
+
},
|
|
470
|
+
}),
|
|
471
|
+
'index.ts': `
|
|
472
|
+
${API_NS_MOCK}
|
|
473
|
+
|
|
474
|
+
interface OpenShape {
|
|
475
|
+
id: string;
|
|
476
|
+
[key: string]: string;
|
|
477
|
+
}
|
|
478
|
+
|
|
479
|
+
export const api = new ApiNamespace(null, 'api', () => ({
|
|
480
|
+
async tag(input: OpenShape) { return { success: true }; },
|
|
481
|
+
}));
|
|
482
|
+
`,
|
|
483
|
+
});
|
|
484
|
+
try {
|
|
485
|
+
const info = extractMethodTypes(join(dir, 'index.ts')).get('tag');
|
|
486
|
+
assert.ok(info, 'should find tag');
|
|
487
|
+
const inputSchema = info.params[0].schema;
|
|
488
|
+
assert.strictEqual(inputSchema.type, 'object');
|
|
489
|
+
assert.ok(inputSchema.properties?.id, 'fixed id property survives');
|
|
490
|
+
assert.ok(inputSchema.additionalProperties, 'index signature surfaces as additionalProperties');
|
|
491
|
+
assert.strictEqual(inputSchema.additionalProperties.type, 'string');
|
|
492
|
+
}
|
|
493
|
+
finally {
|
|
494
|
+
rmSync(dir, { recursive: true, force: true });
|
|
495
|
+
}
|
|
496
|
+
});
|
|
497
|
+
});
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"generate-client-worker.d.ts","sourceRoot":"","sources":["../../src/scripts/generate-client-worker.ts"],"names":[],"mappings":""}
|
|
@@ -0,0 +1,13 @@
|
|
|
1
|
+
// Copyright Amazon.com, Inc. or its affiliates. All Rights Reserved.
|
|
2
|
+
// SPDX-License-Identifier: Apache-2.0
|
|
3
|
+
/**
|
|
4
|
+
* Worker script for generating client code.
|
|
5
|
+
* Usage: node [--conditions=aws-runtime] --import tsx generate-client-worker.js <foundationPath> <outputPath>
|
|
6
|
+
*/
|
|
7
|
+
import { generateClientCode } from './generate-client.js';
|
|
8
|
+
import { writeFileSync, mkdirSync } from 'fs';
|
|
9
|
+
import { dirname } from 'path';
|
|
10
|
+
const [foundationPath, outputPath] = process.argv.slice(2);
|
|
11
|
+
const code = await generateClientCode(foundationPath);
|
|
12
|
+
mkdirSync(dirname(outputPath), { recursive: true });
|
|
13
|
+
writeFileSync(outputPath, code);
|
|
@@ -0,0 +1,14 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Generate browser-safe client code from backend exports.
|
|
3
|
+
*
|
|
4
|
+
* Sets up global collectors (__BLOCKS_CLIENT_MIDDLEWARE__) before importing
|
|
5
|
+
* the backend so that Building Block constructors can register their
|
|
6
|
+
* middleware. After import, reads the collected specifiers and emits
|
|
7
|
+
* import statements + ApiNamespace proxy exports.
|
|
8
|
+
*/
|
|
9
|
+
export declare function generateClientCode(foundationPath: string): Promise<string>;
|
|
10
|
+
/**
|
|
11
|
+
* Generate client code and write it to the aws-blocks subpackage.
|
|
12
|
+
*/
|
|
13
|
+
export declare function writeClientCode(foundationPath: string, outputPath: string): Promise<void>;
|
|
14
|
+
//# sourceMappingURL=generate-client.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"generate-client.d.ts","sourceRoot":"","sources":["../../src/scripts/generate-client.ts"],"names":[],"mappings":"AAQA;;;;;;;GAOG;AACH,wBAAsB,kBAAkB,CAAC,cAAc,EAAE,MAAM,GAAG,OAAO,CAAC,MAAM,CAAC,CA4DhF;AAED;;GAEG;AACH,wBAAsB,eAAe,CAAC,cAAc,EAAE,MAAM,EAAE,UAAU,EAAE,MAAM,GAAG,OAAO,CAAC,IAAI,CAAC,CAI/F"}
|
|
@@ -0,0 +1,73 @@
|
|
|
1
|
+
// Copyright Amazon.com, Inc. or its affiliates. All Rights Reserved.
|
|
2
|
+
// SPDX-License-Identifier: Apache-2.0
|
|
3
|
+
import { writeFileSync, mkdirSync } from 'fs';
|
|
4
|
+
import { dirname } from 'path';
|
|
5
|
+
import { pathToFileURL } from 'url';
|
|
6
|
+
import { API_NAMESPACE_MARKER } from '../api.js';
|
|
7
|
+
/**
|
|
8
|
+
* Generate browser-safe client code from backend exports.
|
|
9
|
+
*
|
|
10
|
+
* Sets up global collectors (__BLOCKS_CLIENT_MIDDLEWARE__) before importing
|
|
11
|
+
* the backend so that Building Block constructors can register their
|
|
12
|
+
* middleware. After import, reads the collected specifiers and emits
|
|
13
|
+
* import statements + ApiNamespace proxy exports.
|
|
14
|
+
*/
|
|
15
|
+
export async function generateClientCode(foundationPath) {
|
|
16
|
+
// Set up global collector if not already present (dev server may have already done this)
|
|
17
|
+
const collectorAlreadyActive = Array.isArray(globalThis.__BLOCKS_CLIENT_MIDDLEWARE__);
|
|
18
|
+
if (!collectorAlreadyActive) {
|
|
19
|
+
globalThis.__BLOCKS_CLIENT_MIDDLEWARE__ = [];
|
|
20
|
+
}
|
|
21
|
+
const backend = await import(pathToFileURL(foundationPath).href);
|
|
22
|
+
// Read collected middleware and clean up
|
|
23
|
+
const middleware = globalThis.__BLOCKS_CLIENT_MIDDLEWARE__;
|
|
24
|
+
delete globalThis.__BLOCKS_CLIENT_MIDDLEWARE__;
|
|
25
|
+
const imports = new Set();
|
|
26
|
+
const lines = [];
|
|
27
|
+
const namespaceNames = [];
|
|
28
|
+
imports.add(`import { ApiNamespaceClient as __BLOCKS_ApiNamespaceClient__ } from '@aws-blocks/blocks/client';`);
|
|
29
|
+
for (const specifier of middleware) {
|
|
30
|
+
imports.add(`import '${specifier}';`);
|
|
31
|
+
}
|
|
32
|
+
// Emit ApiNamespace proxy exports
|
|
33
|
+
for (const [name, value] of Object.entries(backend)) {
|
|
34
|
+
if (name.startsWith('_'))
|
|
35
|
+
continue;
|
|
36
|
+
const isApiNamespace = typeof value?.[API_NAMESPACE_MARKER] === 'string';
|
|
37
|
+
if (isApiNamespace) {
|
|
38
|
+
lines.push(`export const ${name} = __BLOCKS_ApiNamespaceClient__('${name}');`);
|
|
39
|
+
namespaceNames.push(name);
|
|
40
|
+
continue;
|
|
41
|
+
}
|
|
42
|
+
// Fallback: any exported function/object that isn't a Scope gets a proxy.
|
|
43
|
+
const isScope = typeof value?.id === 'string' && typeof value?.fullId === 'string';
|
|
44
|
+
if (isScope)
|
|
45
|
+
continue;
|
|
46
|
+
// Fallback: any exported function/object gets an ApiNamespace proxy.
|
|
47
|
+
if ((typeof value === 'function' || typeof value === 'object') && value !== null) {
|
|
48
|
+
lines.push(`export const ${name} = __BLOCKS_ApiNamespaceClient__('${name}');`);
|
|
49
|
+
namespaceNames.push(name);
|
|
50
|
+
}
|
|
51
|
+
}
|
|
52
|
+
// Emit generateClient — creates new ApiNamespaceClient instances with the given url
|
|
53
|
+
const nsEntries = namespaceNames.map(n => ` ${n}: __BLOCKS_ApiNamespaceClient__('${n}', config),`).join('\n');
|
|
54
|
+
lines.push('');
|
|
55
|
+
lines.push(`export const generateClient = (config) => ({\n${nsEntries}\n});`);
|
|
56
|
+
const header = [
|
|
57
|
+
'// ============================================================',
|
|
58
|
+
'// AUTO-GENERATED FILE — DO NOT EDIT',
|
|
59
|
+
'//',
|
|
60
|
+
'// This file is generated by the Blocks dev server / build process.',
|
|
61
|
+
'// Any manual changes will be overwritten on the next build.',
|
|
62
|
+
'// ============================================================',
|
|
63
|
+
];
|
|
64
|
+
return [...header, '', ...imports, '', ...lines].join('\n');
|
|
65
|
+
}
|
|
66
|
+
/**
|
|
67
|
+
* Generate client code and write it to the aws-blocks subpackage.
|
|
68
|
+
*/
|
|
69
|
+
export async function writeClientCode(foundationPath, outputPath) {
|
|
70
|
+
const code = await generateClientCode(foundationPath);
|
|
71
|
+
mkdirSync(dirname(outputPath), { recursive: true });
|
|
72
|
+
writeFileSync(outputPath, code);
|
|
73
|
+
}
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"generate-client.test.d.ts","sourceRoot":"","sources":["../../src/scripts/generate-client.test.ts"],"names":[],"mappings":""}
|
|
@@ -0,0 +1,48 @@
|
|
|
1
|
+
// Copyright Amazon.com, Inc. or its affiliates. All Rights Reserved.
|
|
2
|
+
// SPDX-License-Identifier: Apache-2.0
|
|
3
|
+
import { describe, it, beforeEach, afterEach } from 'node:test';
|
|
4
|
+
import assert from 'node:assert';
|
|
5
|
+
import { generateClientCode } from './generate-client.js';
|
|
6
|
+
import { writeFileSync, mkdirSync, rmSync } from 'fs';
|
|
7
|
+
import { join } from 'path';
|
|
8
|
+
import { tmpdir } from 'os';
|
|
9
|
+
/**
|
|
10
|
+
* Regression test: generateClientCode collects middleware from whatever
|
|
11
|
+
* the backend registers via registerClientMiddleware(). In sandbox mode,
|
|
12
|
+
* the backend is imported WITHOUT --conditions=aws-runtime, so it registers
|
|
13
|
+
* mock-middleware instead of aws-middleware. The dev server must NOT call
|
|
14
|
+
* generateClientCode in sandbox mode (sandbox.ts already generated the
|
|
15
|
+
* correct client with the aws-runtime condition).
|
|
16
|
+
*
|
|
17
|
+
* This test verifies the mechanism: middleware specifiers registered during
|
|
18
|
+
* backend import appear as imports in the generated client code.
|
|
19
|
+
*/
|
|
20
|
+
describe('generateClientCode — middleware collection', () => {
|
|
21
|
+
let tmpDir;
|
|
22
|
+
beforeEach(() => {
|
|
23
|
+
tmpDir = join(tmpdir(), `blocks-gen-client-test-${Date.now()}`);
|
|
24
|
+
mkdirSync(tmpDir, { recursive: true });
|
|
25
|
+
});
|
|
26
|
+
afterEach(() => {
|
|
27
|
+
rmSync(tmpDir, { recursive: true, force: true });
|
|
28
|
+
});
|
|
29
|
+
it('includes middleware specifiers registered by the backend', async () => {
|
|
30
|
+
// Create a minimal backend that registers a middleware specifier
|
|
31
|
+
const backendPath = join(tmpDir, 'backend.mjs');
|
|
32
|
+
writeFileSync(backendPath, `
|
|
33
|
+
globalThis.__BLOCKS_CLIENT_MIDDLEWARE__?.push('@aws-blocks/bb-realtime/aws-middleware');
|
|
34
|
+
`);
|
|
35
|
+
const code = await generateClientCode(backendPath);
|
|
36
|
+
assert.ok(code.includes("import '@aws-blocks/bb-realtime/aws-middleware'"), 'Generated client must include aws-middleware when backend registers it');
|
|
37
|
+
assert.ok(!code.includes('mock-middleware'), 'Generated client must NOT include mock-middleware when backend registers aws-middleware');
|
|
38
|
+
});
|
|
39
|
+
it('includes mock-middleware when backend registers it (local dev mode)', async () => {
|
|
40
|
+
const backendPath = join(tmpDir, 'backend.mjs');
|
|
41
|
+
writeFileSync(backendPath, `
|
|
42
|
+
globalThis.__BLOCKS_CLIENT_MIDDLEWARE__?.push('@aws-blocks/bb-realtime/mock-middleware');
|
|
43
|
+
`);
|
|
44
|
+
const code = await generateClientCode(backendPath);
|
|
45
|
+
assert.ok(code.includes("import '@aws-blocks/bb-realtime/mock-middleware'"), 'Generated client must include mock-middleware in local dev mode');
|
|
46
|
+
assert.ok(!code.includes('aws-middleware'), 'Generated client must NOT include aws-middleware in local dev mode');
|
|
47
|
+
});
|
|
48
|
+
});
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"generate-spec-cli.d.ts","sourceRoot":"","sources":["../../src/scripts/generate-spec-cli.ts"],"names":[],"mappings":""}
|