@aws-blocks/core 0.1.17 → 0.2.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.
Files changed (70) hide show
  1. package/dist/cdk/__fixtures__/import-meta-handler.d.ts +6 -0
  2. package/dist/cdk/__fixtures__/import-meta-handler.d.ts.map +1 -0
  3. package/dist/cdk/__fixtures__/import-meta-handler.js +13 -0
  4. package/dist/cdk/blocks-backend.d.ts +15 -0
  5. package/dist/cdk/blocks-backend.d.ts.map +1 -1
  6. package/dist/cdk/blocks-backend.js +41 -3
  7. package/dist/cdk/blocks-backend.test.js +137 -1
  8. package/dist/cdk/blocks-defaults.d.ts +44 -0
  9. package/dist/cdk/blocks-defaults.d.ts.map +1 -0
  10. package/dist/cdk/blocks-defaults.js +23 -0
  11. package/dist/cdk/blocks-defaults.test.d.ts +2 -0
  12. package/dist/cdk/blocks-defaults.test.d.ts.map +1 -0
  13. package/dist/cdk/blocks-defaults.test.js +22 -0
  14. package/dist/cdk/blocks-stack.test.js +39 -1
  15. package/dist/cdk/bundling.d.ts +42 -0
  16. package/dist/cdk/bundling.d.ts.map +1 -0
  17. package/dist/cdk/bundling.js +72 -0
  18. package/dist/cdk/bundling.test.d.ts +2 -0
  19. package/dist/cdk/bundling.test.d.ts.map +1 -0
  20. package/dist/cdk/bundling.test.js +80 -0
  21. package/dist/cdk/compute/compute.d.ts +33 -0
  22. package/dist/cdk/compute/compute.d.ts.map +1 -0
  23. package/dist/cdk/compute/compute.js +28 -0
  24. package/dist/cdk/index.d.ts +52 -0
  25. package/dist/cdk/index.d.ts.map +1 -1
  26. package/dist/cdk/index.js +95 -5
  27. package/dist/cdk/internal.d.ts +24 -0
  28. package/dist/cdk/internal.d.ts.map +1 -0
  29. package/dist/cdk/internal.js +27 -0
  30. package/dist/cdk/mixins.d.ts +18 -4
  31. package/dist/cdk/mixins.d.ts.map +1 -1
  32. package/dist/cdk/mixins.js +31 -7
  33. package/dist/cdk/mixins.test.js +45 -0
  34. package/dist/common/index.d.ts +9 -0
  35. package/dist/common/index.d.ts.map +1 -1
  36. package/dist/index.cdk.d.ts +2 -1
  37. package/dist/index.cdk.d.ts.map +1 -1
  38. package/dist/index.cdk.js +2 -1
  39. package/dist/rpc.d.ts.map +1 -1
  40. package/dist/rpc.js +12 -3
  41. package/dist/rpc.test.js +20 -0
  42. package/dist/scripts/telemetry.test.js +2 -0
  43. package/dist/telemetry/environment.d.ts.map +1 -1
  44. package/dist/telemetry/environment.js +3 -1
  45. package/dist/telemetry/telemetry.test.js +10 -0
  46. package/dist/version.d.ts +1 -1
  47. package/dist/version.d.ts.map +1 -1
  48. package/dist/version.js +1 -1
  49. package/package.json +6 -1
  50. package/src/cdk/__fixtures__/import-meta-handler.ts +16 -0
  51. package/src/cdk/blocks-backend.test.ts +166 -1
  52. package/src/cdk/blocks-backend.ts +55 -3
  53. package/src/cdk/blocks-defaults.test.ts +25 -0
  54. package/src/cdk/blocks-defaults.ts +49 -0
  55. package/src/cdk/blocks-stack.test.ts +48 -1
  56. package/src/cdk/bundling.test.ts +90 -0
  57. package/src/cdk/bundling.ts +76 -0
  58. package/src/cdk/compute/compute.ts +37 -0
  59. package/src/cdk/index.ts +105 -5
  60. package/src/cdk/internal.ts +29 -0
  61. package/src/cdk/mixins.test.ts +56 -1
  62. package/src/cdk/mixins.ts +32 -7
  63. package/src/common/index.ts +9 -0
  64. package/src/index.cdk.ts +5 -1
  65. package/src/rpc.test.ts +22 -0
  66. package/src/rpc.ts +19 -3
  67. package/src/scripts/telemetry.test.ts +2 -0
  68. package/src/telemetry/environment.ts +3 -1
  69. package/src/telemetry/telemetry.test.ts +12 -0
  70. package/src/version.ts +1 -1
@@ -0,0 +1,72 @@
1
+ // Copyright Amazon.com, Inc. or its affiliates. All Rights Reserved.
2
+ // SPDX-License-Identifier: Apache-2.0
3
+ import { OutputFormat } from 'aws-cdk-lib/aws-lambda-nodejs';
4
+ /** Banner-defined identifiers the shim substitutes `import.meta.*` with (CJS only). */
5
+ const IMPORT_META_SHIM = {
6
+ url: '__blocksImportMetaUrl',
7
+ dirname: '__blocksImportMetaDirname',
8
+ filename: '__blocksImportMetaFilename',
9
+ };
10
+ /**
11
+ * Wrap a `NodejsFunction` `bundling` config with the framework's hardened esbuild
12
+ * defaults, so every Lambda the framework bundles behaves consistently.
13
+ *
14
+ * **What it fixes.** `NodejsFunction` bundles to **CommonJS**, where `import.meta` is
15
+ * empty. Any bundled code that does `fileURLToPath(import.meta.url)` (a customer
16
+ * handler, a Building Block's `aws-runtime` code, or a dependency) would otherwise
17
+ * become `fileURLToPath(undefined)` and throw at Lambda load — esbuild only *warns*
18
+ * (`empty-import-meta`), so the broken bundle deploys and 502s on first invocation.
19
+ *
20
+ * **How.** For CJS output this shims `import.meta.url` / `import.meta.dirname` /
21
+ * `import.meta.filename` to their CommonJS equivalents (`pathToFileURL(__filename)`,
22
+ * `__dirname`, `__filename`) via an esbuild `--define` + `banner`. This is the same
23
+ * approach esbuild blesses (defining `import.meta` also suppresses the warning) and
24
+ * that Rollup applies by default, so:
25
+ * - a handler that reads `import.meta.url` no longer crashes at load, and
26
+ * - a bundled dependency that merely *contains* `import.meta` (even in dead code) no
27
+ * longer trips a build failure.
28
+ *
29
+ * The value resolves to the **bundled output file** (esbuild flattens the module tree),
30
+ * which is correct for the common cases — a value computed at synth (e.g. a
31
+ * `migrationsPath`) or dead interop fallbacks — but note it does not point at your
32
+ * source layout. Runtime code that must read a file relative to itself should not rely
33
+ * on `import.meta.url` inside a bundle; resolve such paths at synth time or ship the
34
+ * file as an asset. ESM output (`OutputFormat.ESM`) supports `import.meta` natively and
35
+ * is left untouched.
36
+ *
37
+ * All other options (`minify`, `commandHooks`, `externalModules`, other `esbuildArgs`
38
+ * such as `--conditions`, and any caller `banner`) are preserved.
39
+ *
40
+ * @param options - The site-specific `NodejsFunction` bundling options (optional).
41
+ * @returns The same options with the CJS `import.meta` shim merged in.
42
+ *
43
+ * @example
44
+ * new lambda.NodejsFunction(scope, 'Handler', {
45
+ * entry,
46
+ * bundling: blocksNodejsBundling({ minify: true, esbuildArgs: { '--conditions': 'aws-runtime' } }),
47
+ * });
48
+ */
49
+ export function blocksNodejsBundling(options = {}) {
50
+ // ESM output has real `import.meta` — nothing to shim, and `require` in the banner
51
+ // wouldn't resolve. Only the CommonJS bundle needs the shim.
52
+ if (options.format === OutputFormat.ESM)
53
+ return options;
54
+ const shimBanner = [
55
+ `const ${IMPORT_META_SHIM.url}=require('url').pathToFileURL(__filename).href;`,
56
+ `const ${IMPORT_META_SHIM.dirname}=__dirname;`,
57
+ `const ${IMPORT_META_SHIM.filename}=__filename;`,
58
+ ].join('');
59
+ return {
60
+ ...options,
61
+ // Prepend the shim definitions; keep any caller-supplied banner after them.
62
+ banner: options.banner ? `${shimBanner}\n${options.banner}` : shimBanner,
63
+ esbuildArgs: {
64
+ ...options.esbuildArgs,
65
+ // Substitute import.meta.* with the banner identifiers. Also suppresses esbuild's
66
+ // empty-import-meta warning, so import.meta anywhere in the graph is safe.
67
+ '--define:import.meta.url': IMPORT_META_SHIM.url,
68
+ '--define:import.meta.dirname': IMPORT_META_SHIM.dirname,
69
+ '--define:import.meta.filename': IMPORT_META_SHIM.filename,
70
+ },
71
+ };
72
+ }
@@ -0,0 +1,2 @@
1
+ export {};
2
+ //# sourceMappingURL=bundling.test.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"bundling.test.d.ts","sourceRoot":"","sources":["../../src/cdk/bundling.test.ts"],"names":[],"mappings":""}
@@ -0,0 +1,80 @@
1
+ // Copyright Amazon.com, Inc. or its affiliates. All Rights Reserved.
2
+ // SPDX-License-Identifier: Apache-2.0
3
+ import { test, describe } from 'node:test';
4
+ import assert from 'node:assert';
5
+ import { fileURLToPath } from 'node:url';
6
+ import { dirname, join } from 'node:path';
7
+ import { mkdtempSync, rmSync } from 'node:fs';
8
+ import { tmpdir } from 'node:os';
9
+ import { createRequire } from 'node:module';
10
+ import { build } from 'esbuild';
11
+ import { OutputFormat } from 'aws-cdk-lib/aws-lambda-nodejs';
12
+ import { blocksNodejsBundling } from './bundling.js';
13
+ const __dirname = dirname(fileURLToPath(import.meta.url));
14
+ const importMetaFixture = join(__dirname, '__fixtures__', 'import-meta-handler.js');
15
+ const requireCjs = createRequire(import.meta.url);
16
+ describe('blocksNodejsBundling', () => {
17
+ test('injects the import.meta.* CJS shim for the default (CJS) output', () => {
18
+ const out = blocksNodejsBundling({ minify: true, esbuildArgs: { '--conditions': 'aws-runtime' } });
19
+ // Caller options are preserved.
20
+ assert.equal(out.minify, true);
21
+ assert.equal(out.esbuildArgs?.['--conditions'], 'aws-runtime');
22
+ // All three import.meta path properties are substituted.
23
+ assert.ok(out.esbuildArgs?.['--define:import.meta.url']);
24
+ assert.ok(out.esbuildArgs?.['--define:import.meta.dirname']);
25
+ assert.ok(out.esbuildArgs?.['--define:import.meta.filename']);
26
+ // The banner defines the substituted identifiers via CommonJS primitives.
27
+ assert.match(out.banner ?? '', /pathToFileURL\(__filename\)/);
28
+ assert.match(out.banner ?? '', /__dirname/);
29
+ assert.match(out.banner ?? '', /__filename/);
30
+ });
31
+ test('leaves ESM output untouched (import.meta works natively there)', () => {
32
+ const input = { format: OutputFormat.ESM, esbuildArgs: { '--conditions': 'aws-runtime' } };
33
+ const out = blocksNodejsBundling(input);
34
+ assert.deepEqual(out, input);
35
+ assert.equal(out.esbuildArgs?.['--define:import.meta.url'], undefined);
36
+ assert.equal(out.banner, undefined);
37
+ });
38
+ test('prepends the shim while keeping a caller-supplied banner', () => {
39
+ const out = blocksNodejsBundling({ banner: '// caller banner' });
40
+ assert.match(out.banner ?? '', /pathToFileURL\(__filename\)/);
41
+ assert.ok((out.banner ?? '').includes('// caller banner'));
42
+ });
43
+ test('a CJS bundle built with the shim resolves import.meta.url at load (no crash)', async () => {
44
+ // Bundle the fixture exactly as NodejsFunction would: apply the helper's `banner`
45
+ // and its `--define:import.meta.*` esbuildArgs. Without the shim this fixture's
46
+ // top-level `fileURLToPath(import.meta.url)` becomes `fileURLToPath(undefined)`
47
+ // and throws when the module is loaded.
48
+ const opts = blocksNodejsBundling({ minify: true });
49
+ const define = {};
50
+ for (const [key, value] of Object.entries(opts.esbuildArgs ?? {})) {
51
+ const m = key.match(/^--define:(.+)$/);
52
+ if (m)
53
+ define[m[1]] = String(value);
54
+ }
55
+ const tmp = mkdtempSync(join(tmpdir(), 'bb-shim-'));
56
+ const outfile = join(tmp, 'out.cjs');
57
+ try {
58
+ await build({
59
+ entryPoints: [importMetaFixture],
60
+ bundle: true,
61
+ platform: 'node',
62
+ format: 'cjs',
63
+ minify: true,
64
+ banner: { js: opts.banner ?? '' },
65
+ define,
66
+ outfile,
67
+ logLevel: 'silent',
68
+ });
69
+ // Loading the bundle must not throw, and import.meta.url must resolve to a real
70
+ // (file-URL-derived) path rather than being undefined.
71
+ const mod = requireCjs(outfile);
72
+ assert.equal(typeof mod.moduleDir, 'string');
73
+ assert.ok(mod.moduleDir.length > 0, 'moduleDir should resolve to a non-empty path');
74
+ assert.equal(typeof mod.handler, 'function');
75
+ }
76
+ finally {
77
+ rmSync(tmp, { recursive: true, force: true });
78
+ }
79
+ });
80
+ });
@@ -0,0 +1,33 @@
1
+ import { Scope } from '../index.js';
2
+ /**
3
+ * Base class for a Blocks *compute* — a runtime that executes handler code
4
+ * (Lambda today; containers later). A compute owns the physical function/service
5
+ * plus its ingress, and receives config via {@link setEnv}.
6
+ *
7
+ * The backend entry and stack name a compute needs are inherited from
8
+ * {@link Scope} (`backendHandlerPath` / `backendStackName`), which resolve them
9
+ * from the owning BlocksStack/BlocksBackend — never caller-supplied, so every
10
+ * compute in an app runs the same backend and agrees on the resource-name
11
+ * namespace.
12
+ *
13
+ * The abstract base lives in core (a framework primitive); concrete computes
14
+ * live in their own packages (e.g. `LambdaCompute` in `@aws-blocks/bb-lambda-compute`).
15
+ *
16
+ * @internal Not exported from the package's public entry points. Customers
17
+ * cannot instantiate a compute until the customer-facing surface exists.
18
+ */
19
+ export declare abstract class Compute extends Scope {
20
+ /**
21
+ * API namespaces assigned to run on this compute — recorded so request
22
+ * routing can map a namespace to the compute that hosts it. Currently
23
+ * unpopulated (no compute assignment surface yet).
24
+ */
25
+ readonly namespaces: string[];
26
+ /**
27
+ * Inject a runtime configuration value (an environment variable) into this
28
+ * compute. The framework calls this instead of `handler.addEnvironment()`
29
+ * directly so config targets the right compute.
30
+ */
31
+ abstract setEnv(key: string, value: string): void;
32
+ }
33
+ //# sourceMappingURL=compute.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"compute.d.ts","sourceRoot":"","sources":["../../../src/cdk/compute/compute.ts"],"names":[],"mappings":"AAGA,OAAO,EAAE,KAAK,EAAE,MAAM,aAAa,CAAC;AAEpC;;;;;;;;;;;;;;;;GAgBG;AACH,8BAAsB,OAAQ,SAAQ,KAAK;IAC1C;;;;OAIG;IACH,QAAQ,CAAC,UAAU,EAAE,MAAM,EAAE,CAAM;IAEnC;;;;OAIG;IACH,QAAQ,CAAC,MAAM,CAAC,GAAG,EAAE,MAAM,EAAE,KAAK,EAAE,MAAM,GAAG,IAAI;CACjD"}
@@ -0,0 +1,28 @@
1
+ // Copyright Amazon.com, Inc. or its affiliates. All Rights Reserved.
2
+ // SPDX-License-Identifier: Apache-2.0
3
+ import { Scope } from '../index.js';
4
+ /**
5
+ * Base class for a Blocks *compute* — a runtime that executes handler code
6
+ * (Lambda today; containers later). A compute owns the physical function/service
7
+ * plus its ingress, and receives config via {@link setEnv}.
8
+ *
9
+ * The backend entry and stack name a compute needs are inherited from
10
+ * {@link Scope} (`backendHandlerPath` / `backendStackName`), which resolve them
11
+ * from the owning BlocksStack/BlocksBackend — never caller-supplied, so every
12
+ * compute in an app runs the same backend and agrees on the resource-name
13
+ * namespace.
14
+ *
15
+ * The abstract base lives in core (a framework primitive); concrete computes
16
+ * live in their own packages (e.g. `LambdaCompute` in `@aws-blocks/bb-lambda-compute`).
17
+ *
18
+ * @internal Not exported from the package's public entry points. Customers
19
+ * cannot instantiate a compute until the customer-facing surface exists.
20
+ */
21
+ export class Compute extends Scope {
22
+ /**
23
+ * API namespaces assigned to run on this compute — recorded so request
24
+ * routing can map a namespace to the compute that hosts it. Currently
25
+ * unpopulated (no compute assignment surface yet).
26
+ */
27
+ namespaces = [];
28
+ }
@@ -1,10 +1,13 @@
1
1
  import * as cdk from 'aws-cdk-lib';
2
2
  import { Construct } from 'constructs';
3
3
  import { type BlocksStackProps, type BlocksStack as BaseBlocksStack, type ScopeParent, type ScopeOptions } from '../common/index.js';
4
+ import { type BlocksDefaults } from './blocks-defaults.js';
4
5
  export { BlocksBackend, type BlocksBackendProps } from './blocks-backend.js';
5
6
  export { DEFAULT_NODE_RUNTIME } from './node-version.js';
7
+ export { blocksNodejsBundling } from './bundling.js';
6
8
  export { SandboxDisableDeletionProtection } from './mixins.js';
7
9
  export { registerConfig, finalizeConfigRegistry } from './config-registry.js';
10
+ export { type BlocksDefaults, BlocksPresets, } from './blocks-defaults.js';
8
11
  export { synthGuard } from './synth-guard.js';
9
12
  export type { ScopeOptions } from '../index.js';
10
13
  export { ApiError, isBlocksError, hasAuthError, DEFAULT_API_ERROR_NAME } from '../errors.js';
@@ -14,6 +17,10 @@ export declare class BlocksStack extends cdk.Stack implements BaseBlocksStack {
14
17
  readonly gateway: cdk.aws_apigateway.RestApi;
15
18
  readonly handler: cdk.aws_lambda_nodejs.NodejsFunction;
16
19
  readonly backendHandlerPath: string;
20
+ /** Shared IAM role assumed by all Blocks compute. Building Blocks grant to this role. */
21
+ readonly executionRole: cdk.aws_iam.IRole;
22
+ /** Infrastructure defaults for Building Blocks created under this stack. */
23
+ readonly defaults: BlocksDefaults;
17
24
  private constructor();
18
25
  static create(scope: Construct, id: string, props: BlocksStackProps): Promise<BlocksStack>;
19
26
  }
@@ -22,9 +29,54 @@ export declare class Scope extends Construct {
22
29
  readonly parent: ScopeParent;
23
30
  readonly bbName?: string;
24
31
  readonly bbVersion?: string;
32
+ /**
33
+ * The owning stack/backend (the root of the Blocks construct tree), resolved
34
+ * once at construction: the nearest BlocksStack/BlocksBackend up the construct
35
+ * tree, or the ambient `globalThis.CURRENT_BLOCKS_STACK` fallback. All
36
+ * root-derived accessors below read from this instead of each repeating the
37
+ * tree walk.
38
+ */
39
+ private readonly root;
25
40
  constructor(id: string, options?: ScopeOptions);
41
+ /**
42
+ * Walk up the construct tree to the nearest owning BlocksStack/BlocksBackend;
43
+ * fall back to the ambient `globalThis.CURRENT_BLOCKS_STACK`. Called once from
44
+ * the constructor; the result is cached in {@link root}.
45
+ */
46
+ private resolveRoot;
26
47
  get handler(): cdk.aws_lambda_nodejs.NodejsFunction;
48
+ /**
49
+ * The shared IAM role assumed by all Blocks compute. Building Blocks grant
50
+ * their permissions to this role; CDK's `grant*()` / `addToPrincipalPolicy()`
51
+ * route those grants to the role's default (inline) policy.
52
+ */
53
+ get executionRole(): cdk.aws_iam.IRole;
54
+ /**
55
+ * The backend entry file the owning BlocksStack/BlocksBackend runs — the
56
+ * single handler entry shared across the whole app.
57
+ */
58
+ get backendHandlerPath(): string;
59
+ /**
60
+ * The owning stack/backend's token-free root identity. This is the value the
61
+ * runtime receives as `BLOCKS_STACK_NAME` and rebuilds `fullId` from, so
62
+ * physical resource names (DynamoDB tables, env-var keys, IAM ARNs) derived
63
+ * from `fullId` match byte-for-byte between synth and runtime — otherwise the
64
+ * runtime looks up names that were never created. `BlocksBackend` exposes this
65
+ * as `fullId` ({@link BlocksBackend.fullId}); `BlocksStack` as `id`.
66
+ */
67
+ get backendStackName(): string;
27
68
  get fullId(): string;
69
+ /**
70
+ * The stack-wide infrastructure {@link BlocksDefaults} registered by
71
+ * `BlocksStack.create` / `BlocksBackend.create`. Read these in a Building
72
+ * Block's CDK constructor to resolve a durability value, letting a per-block
73
+ * option override:
74
+ *
75
+ * ```ts
76
+ * const removalPolicy = options?.removalPolicy ?? this.defaults.removalPolicy;
77
+ * ```
78
+ */
79
+ get defaults(): BlocksDefaults;
28
80
  protected buildUserAgentChain(): [string, string][];
29
81
  registerClientMiddleware(_packageSpecifier: string): void;
30
82
  registerDevAttachment(_packageSpecifier: string): void;
@@ -1 +1 @@
1
- {"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../src/cdk/index.ts"],"names":[],"mappings":"AAGA,OAAO,KAAK,GAAG,MAAM,aAAa,CAAC;AACnC,OAAO,EAAE,SAAS,EAAE,MAAM,YAAY,CAAC;AAGvC,OAAO,EACL,KAAK,gBAAgB,EACrB,KAAK,WAAW,IAAI,eAAe,EACnC,KAAK,WAAW,EAChB,KAAK,YAAY,EAElB,MAAM,oBAAoB,CAAC;AAK5B,OAAO,EAAE,aAAa,EAAE,KAAK,kBAAkB,EAAE,MAAM,qBAAqB,CAAC;AAC7E,OAAO,EAAE,oBAAoB,EAAE,MAAM,mBAAmB,CAAC;AACzD,OAAO,EAAE,gCAAgC,EAAE,MAAM,aAAa,CAAC;AAC/D,OAAO,EAAE,cAAc,EAAE,sBAAsB,EAAE,MAAM,sBAAsB,CAAC;AAC9E,OAAO,EAAE,UAAU,EAAE,MAAM,kBAAkB,CAAC;AAC9C,YAAY,EAAE,YAAY,EAAE,MAAM,aAAa,CAAC;AAChD,OAAO,EAAE,QAAQ,EAAE,aAAa,EAAE,YAAY,EAAE,sBAAsB,EAAE,MAAM,cAAc,CAAC;AAE7F,qBAAa,WAAY,SAAQ,GAAG,CAAC,KAAM,YAAW,eAAe;IACnE,SAAgB,EAAE,EAAE,MAAM,CAAC;IAC3B,SAAgB,MAAM,EAAE,MAAM,CAAC;IAC/B,SAAgB,OAAO,EAAE,GAAG,CAAC,cAAc,CAAC,OAAO,CAAC;IACpD,SAAgB,OAAO,EAAE,GAAG,CAAC,iBAAiB,CAAC,cAAc,CAAC;IAC9D,SAAgB,kBAAkB,EAAE,MAAM,CAAC;IAE3C,OAAO;WAcM,MAAM,CAAC,KAAK,EAAE,SAAS,EAAE,EAAE,EAAE,MAAM,EAAE,KAAK,EAAE,gBAAgB;CA6B1E;AAED,qBAAa,KAAM,SAAQ,SAAS;IAClC,SAAgB,EAAE,EAAE,MAAM,CAAC;IAC3B,SAAgB,MAAM,EAAE,WAAW,CAAC;IAEpC,QAAQ,CAAC,MAAM,CAAC,EAAE,MAAM,CAAC;IACzB,QAAQ,CAAC,SAAS,CAAC,EAAE,MAAM,CAAC;gBAEhB,EAAE,EAAE,MAAM,EAAE,OAAO,CAAC,EAAE,YAAY;IAO9C,IAAI,OAAO,yCAWV;IAED,IAAI,MAAM,IAAI,MAAM,CAEnB;IAED,SAAS,CAAC,mBAAmB,IAAI,CAAC,MAAM,EAAE,MAAM,CAAC,EAAE;IAKnD,wBAAwB,CAAC,iBAAiB,EAAE,MAAM,GAAG,IAAI;IACzD,qBAAqB,CAAC,iBAAiB,EAAE,MAAM,GAAG,IAAI;IACtD,0BAA0B,CAAC,YAAY,EAAE,MAAM,EAAE,WAAW,EAAE,MAAM,EAAE,QAAQ,EAAE,CAAC,MAAM,EAAE,GAAG,KAAK,OAAO,CAAC,IAAI,CAAC,GAAG,IAAI;IACrH,IAAI,gBAAgB,IAAI,SAAS,MAAM,EAAE,CAAe;IACxD,IAAI,cAAc,IAAI,SAAS,MAAM,EAAE,CAAe;CACvD"}
1
+ {"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../src/cdk/index.ts"],"names":[],"mappings":"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"}
package/dist/cdk/index.js CHANGED
@@ -8,10 +8,13 @@ import { computeScopeFullId, } from '../common/index.js';
8
8
  import { setupBlocksInfra, BlocksBackend, assertCdkConditionActive } from './blocks-backend.js';
9
9
  import { addBlocksStackMetadata } from './stack-metadata.js';
10
10
  import { finalizeConfigRegistry } from './config-registry.js';
11
+ import { BlocksPresets } from './blocks-defaults.js';
11
12
  export { BlocksBackend } from './blocks-backend.js';
12
13
  export { DEFAULT_NODE_RUNTIME } from './node-version.js';
14
+ export { blocksNodejsBundling } from './bundling.js';
13
15
  export { SandboxDisableDeletionProtection } from './mixins.js';
14
16
  export { registerConfig, finalizeConfigRegistry } from './config-registry.js';
17
+ export { BlocksPresets, } from './blocks-defaults.js';
15
18
  export { synthGuard } from './synth-guard.js';
16
19
  export { ApiError, isBlocksError, hasAuthError, DEFAULT_API_ERROR_NAME } from '../errors.js';
17
20
  export class BlocksStack extends cdk.Stack {
@@ -20,16 +23,22 @@ export class BlocksStack extends cdk.Stack {
20
23
  gateway;
21
24
  handler;
22
25
  backendHandlerPath;
26
+ /** Shared IAM role assumed by all Blocks compute. Building Blocks grant to this role. */
27
+ executionRole;
28
+ /** Infrastructure defaults for Building Blocks created under this stack. */
29
+ defaults;
23
30
  constructor(scope, id, props) {
24
31
  super(scope, id, props);
25
32
  this.id = id;
26
33
  this.backendHandlerPath = props.backendHandlerPath;
34
+ this.defaults = props.defaults;
27
35
  // Set globalThis so Building Blocks attach directly to this stack
28
36
  globalThis.CURRENT_BLOCKS_STACK = this;
29
37
  const infra = setupBlocksInfra(this, props, id);
30
38
  this.handler = infra.handler;
31
39
  this.gateway = infra.gateway;
32
40
  this.apiUrl = infra.apiUrl;
41
+ this.executionRole = infra.executionRole;
33
42
  }
34
43
  static async create(scope, id, props) {
35
44
  assertCdkConditionActive();
@@ -62,27 +71,108 @@ export class Scope extends Construct {
62
71
  parent;
63
72
  bbName;
64
73
  bbVersion;
74
+ /**
75
+ * The owning stack/backend (the root of the Blocks construct tree), resolved
76
+ * once at construction: the nearest BlocksStack/BlocksBackend up the construct
77
+ * tree, or the ambient `globalThis.CURRENT_BLOCKS_STACK` fallback. All
78
+ * root-derived accessors below read from this instead of each repeating the
79
+ * tree walk.
80
+ */
81
+ root;
65
82
  constructor(id, options) {
66
83
  const parent = options?.parent || globalThis.CURRENT_BLOCKS_STACK;
67
84
  super(parent, id);
68
85
  this.id = id;
69
86
  this.parent = parent;
87
+ this.root = this.resolveRoot();
70
88
  }
71
- get handler() {
72
- // Walk up the construct tree to find the owning BlocksStack/BlocksBackend
89
+ /**
90
+ * Walk up the construct tree to the nearest owning BlocksStack/BlocksBackend;
91
+ * fall back to the ambient `globalThis.CURRENT_BLOCKS_STACK`. Called once from
92
+ * the constructor; the result is cached in {@link root}.
93
+ */
94
+ resolveRoot() {
73
95
  let current = this;
74
96
  while (current.node.scope) {
75
97
  current = current.node.scope;
76
98
  if (current instanceof BlocksStack || current instanceof BlocksBackend) {
77
- return current.handler;
99
+ return current;
78
100
  }
79
101
  }
80
- // Fallback to globalThis for backward compatibility
81
- return globalThis.CURRENT_BLOCKS_STACK.handler;
102
+ // Fallback to the ambient stack. In production this is always a real
103
+ // BlocksStack/BlocksBackend; the cast also admits the test doubles that set
104
+ // globalThis.CURRENT_BLOCKS_STACK to a stub exposing the same surface.
105
+ return globalThis.CURRENT_BLOCKS_STACK;
106
+ }
107
+ get handler() {
108
+ return this.root.handler;
109
+ }
110
+ /**
111
+ * The shared IAM role assumed by all Blocks compute. Building Blocks grant
112
+ * their permissions to this role; CDK's `grant*()` / `addToPrincipalPolicy()`
113
+ * route those grants to the role's default (inline) policy.
114
+ */
115
+ get executionRole() {
116
+ return this.root.executionRole;
117
+ }
118
+ /**
119
+ * The backend entry file the owning BlocksStack/BlocksBackend runs — the
120
+ * single handler entry shared across the whole app.
121
+ */
122
+ get backendHandlerPath() {
123
+ return this.root.backendHandlerPath;
124
+ }
125
+ /**
126
+ * The owning stack/backend's token-free root identity. This is the value the
127
+ * runtime receives as `BLOCKS_STACK_NAME` and rebuilds `fullId` from, so
128
+ * physical resource names (DynamoDB tables, env-var keys, IAM ARNs) derived
129
+ * from `fullId` match byte-for-byte between synth and runtime — otherwise the
130
+ * runtime looks up names that were never created. `BlocksBackend` exposes this
131
+ * as `fullId` ({@link BlocksBackend.fullId}); `BlocksStack` as `id`.
132
+ */
133
+ get backendStackName() {
134
+ const name = this.root instanceof BlocksBackend ? this.root.fullId : this.root.id;
135
+ if (!name) {
136
+ throw new Error('Owning Blocks stack/backend has no id to derive BLOCKS_STACK_NAME');
137
+ }
138
+ return name;
82
139
  }
83
140
  get fullId() {
84
141
  return computeScopeFullId(this);
85
142
  }
143
+ /**
144
+ * The stack-wide infrastructure {@link BlocksDefaults} registered by
145
+ * `BlocksStack.create` / `BlocksBackend.create`. Read these in a Building
146
+ * Block's CDK constructor to resolve a durability value, letting a per-block
147
+ * option override:
148
+ *
149
+ * ```ts
150
+ * const removalPolicy = options?.removalPolicy ?? this.defaults.removalPolicy;
151
+ * ```
152
+ */
153
+ get defaults() {
154
+ // Resolve the same way as handler/executionRole: walk up to the owning
155
+ // BlocksStack/BlocksBackend and read its defaults, so several backends in
156
+ // one stack each keep their own posture. Falls back to the ambient stack,
157
+ // then to the production preset when none was registered.
158
+ let current = this;
159
+ while (current.node.scope) {
160
+ current = current.node.scope;
161
+ if (current instanceof BlocksStack || current instanceof BlocksBackend) {
162
+ return current.defaults;
163
+ }
164
+ }
165
+ const ambient = globalThis.CURRENT_BLOCKS_STACK?.defaults;
166
+ if (ambient)
167
+ return ambient;
168
+ // No owning BlocksStack/BlocksBackend in the tree and none ambient — this is
169
+ // usually a deliberate test stub, but could be a real misconfiguration (a
170
+ // block built outside any Blocks backend). Fall back to the safe production
171
+ // posture, and log so it's debuggable if it fires unexpectedly.
172
+ console.warn(`[Blocks] Scope "${this.id}" resolved infrastructure defaults with no owning ` +
173
+ 'BlocksStack/BlocksBackend in scope; falling back to BlocksPresets.production.');
174
+ return BlocksPresets.production;
175
+ }
86
176
  buildUserAgentChain() {
87
177
  return [];
88
178
  }
@@ -0,0 +1,24 @@
1
+ /**
2
+ * Internal CDK entry point — framework- and test-only surface that is
3
+ * intentionally NOT part of the public API (`@aws-blocks/core` /
4
+ * `@aws-blocks/core/cdk`).
5
+ *
6
+ * The compute abstraction lives behind this path while it has no public,
7
+ * customer-facing surface. Importing from here is a signal that you are inside
8
+ * the framework or a test, not a customer.
9
+ *
10
+ * Planned removal: once a customer can assign a compute and have it actually
11
+ * take effect — i.e. `this.compute` resolution and request routing to the
12
+ * chosen compute both exist, plus a synth-time guard that rejects an assignment
13
+ * with no route — these exports move to the public CDK entry point
14
+ * (`@aws-blocks/core/cdk`, re-exported from `index.cdk.ts`) and this file is
15
+ * deleted. It must NOT be made public before then: a compute a customer can
16
+ * declare but that is silently ignored is a worse experience than not having
17
+ * the feature. Until that flip, treat everything here as unstable — no
18
+ * backward-compatibility guarantee.
19
+ *
20
+ * @internal
21
+ */
22
+ export { Compute } from './compute/compute.js';
23
+ export { BLOCKS_NAMESPACE } from '../constants.js';
24
+ //# sourceMappingURL=internal.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"internal.d.ts","sourceRoot":"","sources":["../../src/cdk/internal.ts"],"names":[],"mappings":"AAGA;;;;;;;;;;;;;;;;;;;;GAoBG;AAEH,OAAO,EAAE,OAAO,EAAE,MAAM,sBAAsB,CAAC;AAG/C,OAAO,EAAE,gBAAgB,EAAE,MAAM,iBAAiB,CAAC"}
@@ -0,0 +1,27 @@
1
+ // Copyright Amazon.com, Inc. or its affiliates. All Rights Reserved.
2
+ // SPDX-License-Identifier: Apache-2.0
3
+ /**
4
+ * Internal CDK entry point — framework- and test-only surface that is
5
+ * intentionally NOT part of the public API (`@aws-blocks/core` /
6
+ * `@aws-blocks/core/cdk`).
7
+ *
8
+ * The compute abstraction lives behind this path while it has no public,
9
+ * customer-facing surface. Importing from here is a signal that you are inside
10
+ * the framework or a test, not a customer.
11
+ *
12
+ * Planned removal: once a customer can assign a compute and have it actually
13
+ * take effect — i.e. `this.compute` resolution and request routing to the
14
+ * chosen compute both exist, plus a synth-time guard that rejects an assignment
15
+ * with no route — these exports move to the public CDK entry point
16
+ * (`@aws-blocks/core/cdk`, re-exported from `index.cdk.ts`) and this file is
17
+ * deleted. It must NOT be made public before then: a compute a customer can
18
+ * declare but that is silently ignored is a worse experience than not having
19
+ * the feature. Until that flip, treat everything here as unstable — no
20
+ * backward-compatibility guarantee.
21
+ *
22
+ * @internal
23
+ */
24
+ export { Compute } from './compute/compute.js';
25
+ // Reserved `/aws-blocks` path segment, needed by concrete computes (e.g.
26
+ // LambdaCompute in @aws-blocks/bb-lambda-compute) to build their API route tree.
27
+ export { BLOCKS_NAMESPACE } from '../constants.js';
@@ -2,13 +2,27 @@ import { Mixin } from 'aws-cdk-lib';
2
2
  import type { IConstruct } from 'constructs';
3
3
  import type { IMixin } from 'constructs';
4
4
  /**
5
- * Disables deletion protection on any construct that has a `deletionProtection`
6
- * property (e.g. RDS clusters, RDS instances). Uses duck-typing so it
7
- * automatically covers current and future resource types.
5
+ * Disables deletion protection on any construct that exposes a deletion
6
+ * protection property (e.g. RDS clusters, RDS instances, DynamoDB tables).
7
+ * Uses duck-typing so it automatically covers current and future resource
8
+ * types, matching both the `deletionProtection` and
9
+ * `deletionProtectionEnabled` spellings.
10
+ *
11
+ * Note that a DynamoDB L2 `Table` only accepts `deletionProtection` as a prop
12
+ * and does not re-expose it, so tables are matched through their underlying
13
+ * L1 `CfnTable.deletionProtectionEnabled`.
8
14
  *
9
15
  * Intended for sandbox teardown — use in the CDK layer alongside
10
16
  * `RemovalPolicies.of(stack).destroy()` to ensure `sandbox:destroy` can
11
- * delete the entire stack without manual cleanup.
17
+ * delete the entire stack without manual cleanup. DynamoDB refuses
18
+ * `DeleteTable` while deletion protection is enabled, regardless of the
19
+ * CloudFormation `DeletionPolicy`.
20
+ *
21
+ * @deprecated Prefer the stack-wide `defaults` prop on `BlocksStack`/`BlocksBackend`
22
+ * (`defaults: BlocksPresets.sandbox` / `.production`, or `sandboxMode ? … : …`).
23
+ * Amazon-authored Building Blocks now read removal policy + deletion protection
24
+ * from `defaults`, so this mixin is no longer needed; it is retained only for
25
+ * backward compatibility.
12
26
  *
13
27
  * @example
14
28
  * ```ts
@@ -1 +1 @@
1
- {"version":3,"file":"mixins.d.ts","sourceRoot":"","sources":["../../src/cdk/mixins.ts"],"names":[],"mappings":"AAGA,OAAO,EAAE,KAAK,EAAE,MAAM,aAAa,CAAC;AACpC,OAAO,KAAK,EAAE,UAAU,EAAE,MAAM,YAAY,CAAC;AAC7C,OAAO,KAAK,EAAE,MAAM,EAAE,MAAM,YAAY,CAAC;AAEzC;;;;;;;;;;;;;;;;;;;GAmBG;AACH,qBAAa,gCAAiC,SAAQ,KAAM,YAAW,MAAM;IAC3E,QAAQ,CAAC,SAAS,EAAE,GAAG,GAAG,OAAO;IAGjC,OAAO,CAAC,IAAI,EAAE,UAAU,GAAG,IAAI;CAShC"}
1
+ {"version":3,"file":"mixins.d.ts","sourceRoot":"","sources":["../../src/cdk/mixins.ts"],"names":[],"mappings":"AAGA,OAAO,EAAE,KAAK,EAAE,MAAM,aAAa,CAAC;AACpC,OAAO,KAAK,EAAE,UAAU,EAAE,MAAM,YAAY,CAAC;AAC7C,OAAO,KAAK,EAAE,MAAM,EAAE,MAAM,YAAY,CAAC;AAWzC;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;GAiCG;AACH,qBAAa,gCAAiC,SAAQ,KAAM,YAAW,MAAM;IAC3E,QAAQ,CAAC,SAAS,EAAE,GAAG,GAAG,OAAO;IAGjC,OAAO,CAAC,IAAI,EAAE,UAAU,GAAG,IAAI;CAWhC"}
@@ -2,13 +2,35 @@
2
2
  // SPDX-License-Identifier: Apache-2.0
3
3
  import { Mixin } from 'aws-cdk-lib';
4
4
  /**
5
- * Disables deletion protection on any construct that has a `deletionProtection`
6
- * property (e.g. RDS clusters, RDS instances). Uses duck-typing so it
7
- * automatically covers current and future resource types.
5
+ * Property names used across CloudFormation resources to express deletion
6
+ * protection. L2 constructs and most L1s use `deletionProtection` (e.g. RDS
7
+ * clusters and instances, ELBv2 load balancers), while others spell it
8
+ * `deletionProtectionEnabled` (e.g. the DynamoDB `CfnTable` behind an L2
9
+ * `Table`, Aurora DSQL clusters).
10
+ */
11
+ const DELETION_PROTECTION_PROPERTIES = ['deletionProtection', 'deletionProtectionEnabled'];
12
+ /**
13
+ * Disables deletion protection on any construct that exposes a deletion
14
+ * protection property (e.g. RDS clusters, RDS instances, DynamoDB tables).
15
+ * Uses duck-typing so it automatically covers current and future resource
16
+ * types, matching both the `deletionProtection` and
17
+ * `deletionProtectionEnabled` spellings.
18
+ *
19
+ * Note that a DynamoDB L2 `Table` only accepts `deletionProtection` as a prop
20
+ * and does not re-expose it, so tables are matched through their underlying
21
+ * L1 `CfnTable.deletionProtectionEnabled`.
8
22
  *
9
23
  * Intended for sandbox teardown — use in the CDK layer alongside
10
24
  * `RemovalPolicies.of(stack).destroy()` to ensure `sandbox:destroy` can
11
- * delete the entire stack without manual cleanup.
25
+ * delete the entire stack without manual cleanup. DynamoDB refuses
26
+ * `DeleteTable` while deletion protection is enabled, regardless of the
27
+ * CloudFormation `DeletionPolicy`.
28
+ *
29
+ * @deprecated Prefer the stack-wide `defaults` prop on `BlocksStack`/`BlocksBackend`
30
+ * (`defaults: BlocksPresets.sandbox` / `.production`, or `sandboxMode ? … : …`).
31
+ * Amazon-authored Building Blocks now read removal policy + deletion protection
32
+ * from `defaults`, so this mixin is no longer needed; it is retained only for
33
+ * backward compatibility.
12
34
  *
13
35
  * @example
14
36
  * ```ts
@@ -23,15 +45,17 @@ import { Mixin } from 'aws-cdk-lib';
23
45
  */
24
46
  export class SandboxDisableDeletionProtection extends Mixin {
25
47
  supports(construct) {
26
- return 'deletionProtection' in construct;
48
+ return DELETION_PROTECTION_PROPERTIES.some((property) => property in construct);
27
49
  }
28
50
  applyTo(node) {
29
51
  // Only flip explicitly-enabled protection. When undefined (the default),
30
52
  // deletion protection is already off — setting it to false would emit the
31
53
  // property in the CloudFormation template, which breaks Aurora DB instances
32
54
  // (RDS rejects DeletionProtection on cluster members).
33
- if (node.deletionProtection === true) {
34
- node.deletionProtection = false;
55
+ for (const property of DELETION_PROTECTION_PROPERTIES) {
56
+ if (node[property] === true) {
57
+ node[property] = false;
58
+ }
35
59
  }
36
60
  }
37
61
  }