@aws-blocks/bb-distributed-table 0.1.4 → 0.1.6

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.
@@ -12,8 +12,8 @@
12
12
  import { test } from 'node:test';
13
13
  import assert from 'node:assert';
14
14
  import * as cdk from 'aws-cdk-lib';
15
- import { Template } from 'aws-cdk-lib/assertions';
16
- import { Scope, DEFAULT_NODE_RUNTIME } from '@aws-blocks/core/cdk';
15
+ import { Template, Match, Annotations } from 'aws-cdk-lib/assertions';
16
+ import { Scope, DEFAULT_NODE_RUNTIME, BlocksPresets } from '@aws-blocks/core/cdk';
17
17
  import { z } from 'zod';
18
18
  import { DistributedTable } from './index.cdk.js';
19
19
  const userSchema = z.object({
@@ -23,21 +23,28 @@ const userSchema = z.object({
23
23
  });
24
24
  class StubBlocksStack extends cdk.Stack {
25
25
  handler;
26
+ executionRole;
26
27
  id;
28
+ defaults = BlocksPresets.production;
27
29
  constructor(scope, id) {
28
30
  super(scope, id);
29
31
  this.id = id;
30
32
  globalThis.CURRENT_BLOCKS_STACK = this;
33
+ this.executionRole = new cdk.aws_iam.Role(this, 'BlocksRole', {
34
+ assumedBy: new cdk.aws_iam.ServicePrincipal('lambda.amazonaws.com'),
35
+ });
31
36
  this.handler = new cdk.aws_lambda.Function(this, 'StubHandler', {
32
37
  runtime: DEFAULT_NODE_RUNTIME,
33
38
  handler: 'index.handler',
34
39
  code: cdk.aws_lambda.Code.fromInline('exports.handler = async () => {};'),
40
+ role: this.executionRole,
35
41
  });
36
42
  }
37
43
  }
38
- function setup() {
44
+ function setup(defaults = BlocksPresets.production) {
39
45
  const app = new cdk.App();
40
46
  const stack = new StubBlocksStack(app, 'TestStack');
47
+ stack.defaults = defaults;
41
48
  const parent = new Scope('app');
42
49
  return { stack, parent };
43
50
  }
@@ -50,6 +57,281 @@ test('CDK: default DistributedTable provisions a DynamoDB table', () => {
50
57
  const template = Template.fromStack(stack);
51
58
  template.resourceCountIs('AWS::DynamoDB::Table', 1);
52
59
  });
60
+ // ── Secure-by-default durability & encryption (prod) ────────────────────────
61
+ // Regression for the bug bash finding: prod DDB tables shipped with
62
+ // DeletionProtection off, PITR disabled, and SSE (KMS) unset.
63
+ test('CDK: prod DistributedTable enables PITR by default', () => {
64
+ const { stack, parent } = setup();
65
+ new DistributedTable(parent, 'users', {
66
+ schema: userSchema,
67
+ key: { partitionKey: 'userId', sortKey: 'createdAt' },
68
+ });
69
+ const template = Template.fromStack(stack);
70
+ template.hasResourceProperties('AWS::DynamoDB::Table', {
71
+ PointInTimeRecoverySpecification: { PointInTimeRecoveryEnabled: true },
72
+ });
73
+ });
74
+ test('CDK: default PITR does not pin a recovery window (DynamoDB 35-day default)', () => {
75
+ const { stack, parent } = setup();
76
+ new DistributedTable(parent, 'users', {
77
+ schema: userSchema,
78
+ key: { partitionKey: 'userId', sortKey: 'createdAt' },
79
+ });
80
+ const template = Template.fromStack(stack);
81
+ template.hasResourceProperties('AWS::DynamoDB::Table', {
82
+ PointInTimeRecoverySpecification: {
83
+ PointInTimeRecoveryEnabled: true,
84
+ RecoveryPeriodInDays: Match.absent(),
85
+ },
86
+ });
87
+ });
88
+ test('CDK: pointInTimeRecovery { retentionDays } enables PITR and pins the window', () => {
89
+ const { stack, parent } = setup();
90
+ new DistributedTable(parent, 'users', {
91
+ schema: userSchema,
92
+ key: { partitionKey: 'userId', sortKey: 'createdAt' },
93
+ pointInTimeRecovery: { retentionDays: 7 },
94
+ });
95
+ const template = Template.fromStack(stack);
96
+ template.hasResourceProperties('AWS::DynamoDB::Table', {
97
+ PointInTimeRecoverySpecification: {
98
+ PointInTimeRecoveryEnabled: true,
99
+ RecoveryPeriodInDays: 7,
100
+ },
101
+ });
102
+ });
103
+ test('CDK: an out-of-range retentionDays falls back to the default window (still enabled)', () => {
104
+ const { stack, parent } = setup();
105
+ new DistributedTable(parent, 'users', {
106
+ schema: userSchema,
107
+ key: { partitionKey: 'userId', sortKey: 'createdAt' },
108
+ pointInTimeRecovery: { retentionDays: 60 },
109
+ });
110
+ const template = Template.fromStack(stack);
111
+ template.hasResourceProperties('AWS::DynamoDB::Table', {
112
+ PointInTimeRecoverySpecification: {
113
+ PointInTimeRecoveryEnabled: true,
114
+ RecoveryPeriodInDays: Match.absent(),
115
+ },
116
+ });
117
+ });
118
+ test('CDK: pointInTimeRecovery: false disables PITR', () => {
119
+ const { stack, parent } = setup();
120
+ new DistributedTable(parent, 'users', {
121
+ schema: userSchema,
122
+ key: { partitionKey: 'userId', sortKey: 'createdAt' },
123
+ pointInTimeRecovery: false,
124
+ });
125
+ const template = Template.fromStack(stack);
126
+ template.hasResourceProperties('AWS::DynamoDB::Table', {
127
+ PointInTimeRecoverySpecification: Match.absent(),
128
+ });
129
+ });
130
+ test('CDK: prod DistributedTable enables DeletionProtection by default', () => {
131
+ const { stack, parent } = setup();
132
+ new DistributedTable(parent, 'users', {
133
+ schema: userSchema,
134
+ key: { partitionKey: 'userId', sortKey: 'createdAt' },
135
+ });
136
+ const template = Template.fromStack(stack);
137
+ template.hasResourceProperties('AWS::DynamoDB::Table', {
138
+ DeletionProtectionEnabled: true,
139
+ });
140
+ });
141
+ test('CDK: prod DistributedTable enables SSE (KMS-managed) by default', () => {
142
+ const { stack, parent } = setup();
143
+ new DistributedTable(parent, 'users', {
144
+ schema: userSchema,
145
+ key: { partitionKey: 'userId', sortKey: 'createdAt' },
146
+ });
147
+ const template = Template.fromStack(stack);
148
+ // AWS_MANAGED emits SSEEnabled:true with no SSEType (the aws/dynamodb key).
149
+ // Contrast with the AWS-owned default, which emits no SSESpecification at all,
150
+ // and customer-managed, which adds SSEType:'KMS' + a KMSMasterKeyId.
151
+ template.hasResourceProperties('AWS::DynamoDB::Table', {
152
+ SSESpecification: { SSEEnabled: true, SSEType: Match.absent() },
153
+ });
154
+ });
155
+ test('CDK: prod DistributedTable table is RETAINed on stack delete by default', () => {
156
+ const { stack, parent } = setup();
157
+ new DistributedTable(parent, 'users', {
158
+ schema: userSchema,
159
+ key: { partitionKey: 'userId', sortKey: 'createdAt' },
160
+ });
161
+ const template = Template.fromStack(stack);
162
+ template.hasResource('AWS::DynamoDB::Table', {
163
+ DeletionPolicy: 'Retain',
164
+ });
165
+ });
166
+ // (Sandbox-default behavior — DESTROY, deletion protection off, PITR off — is
167
+ // covered by the "adopts sandbox defaults" / "PITR follows the stack defaults"
168
+ // tests above, which drive it through the stack `defaults` rather than the
169
+ // `sandboxMode` context.)
170
+ // ── Customer overrides win over the secure defaults ─────────────────────────
171
+ test('CDK: customer can opt OUT of PITR + protection in prod', () => {
172
+ const { stack, parent } = setup();
173
+ new DistributedTable(parent, 'users', {
174
+ schema: userSchema,
175
+ key: { partitionKey: 'userId', sortKey: 'createdAt' },
176
+ pointInTimeRecovery: false,
177
+ protection: 'disposable',
178
+ });
179
+ const template = Template.fromStack(stack);
180
+ template.hasResourceProperties('AWS::DynamoDB::Table', {
181
+ PointInTimeRecoverySpecification: Match.absent(),
182
+ DeletionProtectionEnabled: false,
183
+ });
184
+ template.hasResource('AWS::DynamoDB::Table', { DeletionPolicy: 'Delete' });
185
+ });
186
+ test('CDK: customer can opt INTO durable/protected tables even under the sandbox preset', () => {
187
+ const { stack, parent } = setup(BlocksPresets.sandbox);
188
+ new DistributedTable(parent, 'users', {
189
+ schema: userSchema,
190
+ key: { partitionKey: 'userId', sortKey: 'createdAt' },
191
+ pointInTimeRecovery: true,
192
+ protection: 'locked',
193
+ });
194
+ const template = Template.fromStack(stack);
195
+ template.hasResourceProperties('AWS::DynamoDB::Table', {
196
+ PointInTimeRecoverySpecification: { PointInTimeRecoveryEnabled: true },
197
+ DeletionProtectionEnabled: true,
198
+ });
199
+ template.hasResource('AWS::DynamoDB::Table', { DeletionPolicy: 'Retain' });
200
+ });
201
+ test("CDK: protection 'retained' orphans the table without locking deletes", () => {
202
+ const { stack, parent } = setup();
203
+ new DistributedTable(parent, 'users', {
204
+ schema: userSchema,
205
+ key: { partitionKey: 'userId', sortKey: 'createdAt' },
206
+ protection: 'retained',
207
+ });
208
+ const template = Template.fromStack(stack);
209
+ // RETAIN on stack delete, but deletion protection OFF (a direct delete works).
210
+ template.hasResource('AWS::DynamoDB::Table', { DeletionPolicy: 'Retain' });
211
+ template.hasResourceProperties('AWS::DynamoDB::Table', {
212
+ DeletionProtectionEnabled: false,
213
+ });
214
+ });
215
+ test('CDK: customer-managed encryption provisions a KMS key', () => {
216
+ const { stack, parent } = setup();
217
+ new DistributedTable(parent, 'users', {
218
+ schema: userSchema,
219
+ key: { partitionKey: 'userId', sortKey: 'createdAt' },
220
+ encryption: 'customer-managed',
221
+ });
222
+ const template = Template.fromStack(stack);
223
+ template.resourceCountIs('AWS::KMS::Key', 1);
224
+ template.hasResourceProperties('AWS::DynamoDB::Table', {
225
+ SSESpecification: { SSEEnabled: true, SSEType: 'KMS' },
226
+ });
227
+ });
228
+ test('CDK: fromKmsKey encrypts with an existing key and provisions no new KMS key', () => {
229
+ const { stack, parent } = setup();
230
+ const keyArn = 'arn:aws:kms:us-east-1:111122223333:key/abcd-1234-ef56';
231
+ new DistributedTable(parent, 'orders', {
232
+ schema: userSchema,
233
+ key: { partitionKey: 'userId', sortKey: 'createdAt' },
234
+ encryption: DistributedTable.fromKmsKey(keyArn),
235
+ });
236
+ const template = Template.fromStack(stack);
237
+ // Bringing an existing key must NOT mint a new one (the whole point — a
238
+ // shared key across tables instead of one dedicated key each).
239
+ template.resourceCountIs('AWS::KMS::Key', 0);
240
+ template.hasResourceProperties('AWS::DynamoDB::Table', {
241
+ SSESpecification: { SSEEnabled: true, SSEType: 'KMS', KMSMasterKeyId: keyArn },
242
+ });
243
+ });
244
+ test('CDK: two tables sharing one fromKmsKey ref provision zero KMS keys', () => {
245
+ const { stack, parent } = setup();
246
+ const sharedKey = DistributedTable.fromKmsKey('arn:aws:kms:us-east-1:111122223333:key/shared-1');
247
+ new DistributedTable(parent, 'orders', {
248
+ schema: userSchema,
249
+ key: { partitionKey: 'userId', sortKey: 'createdAt' },
250
+ encryption: sharedKey,
251
+ });
252
+ new DistributedTable(parent, 'events', {
253
+ schema: userSchema,
254
+ key: { partitionKey: 'userId', sortKey: 'createdAt' },
255
+ encryption: sharedKey,
256
+ });
257
+ const template = Template.fromStack(stack);
258
+ template.resourceCountIs('AWS::KMS::Key', 0);
259
+ template.resourceCountIs('AWS::DynamoDB::Table', 2);
260
+ });
261
+ test('CDK: fromExisting ignores durability props (customer owns the table)', () => {
262
+ const { stack, parent } = setup();
263
+ new DistributedTable(parent, 'users', {
264
+ schema: userSchema,
265
+ key: { partitionKey: 'userId', sortKey: 'createdAt' },
266
+ table: DistributedTable.fromExisting('preexisting-users-table'),
267
+ // These must be inert when wrapping an existing table.
268
+ pointInTimeRecovery: true,
269
+ protection: 'locked',
270
+ encryption: 'customer-managed',
271
+ });
272
+ const template = Template.fromStack(stack);
273
+ // No table is provisioned, and customer-managed encryption does NOT
274
+ // provision a CMK — proving the durability options are ignored.
275
+ template.resourceCountIs('AWS::DynamoDB::Table', 0);
276
+ template.resourceCountIs('AWS::KMS::Key', 0);
277
+ });
278
+ // ── Durability follows the stack `defaults` when no per-block override (#302) ──
279
+ test('CDK: table adopts sandbox defaults (DESTROY, deletion protection off)', () => {
280
+ const { stack, parent } = setup(BlocksPresets.sandbox);
281
+ new DistributedTable(parent, 'users', {
282
+ schema: userSchema,
283
+ key: { partitionKey: 'userId', sortKey: 'createdAt' },
284
+ });
285
+ const template = Template.fromStack(stack);
286
+ template.hasResource('AWS::DynamoDB::Table', { DeletionPolicy: 'Delete' });
287
+ template.hasResourceProperties('AWS::DynamoDB::Table', { DeletionProtectionEnabled: false });
288
+ });
289
+ test('CDK: table adopts production defaults (RETAIN, deletion protection on)', () => {
290
+ const { stack, parent } = setup(BlocksPresets.production);
291
+ new DistributedTable(parent, 'users', {
292
+ schema: userSchema,
293
+ key: { partitionKey: 'userId', sortKey: 'createdAt' },
294
+ });
295
+ const template = Template.fromStack(stack);
296
+ template.hasResource('AWS::DynamoDB::Table', { DeletionPolicy: 'Retain' });
297
+ template.hasResourceProperties('AWS::DynamoDB::Table', { DeletionProtectionEnabled: true });
298
+ });
299
+ test('CDK: PITR follows the stack defaults — off under the sandbox preset', () => {
300
+ const { stack, parent } = setup(BlocksPresets.sandbox);
301
+ new DistributedTable(parent, 'users', {
302
+ schema: userSchema,
303
+ key: { partitionKey: 'userId', sortKey: 'createdAt' },
304
+ });
305
+ const template = Template.fromStack(stack);
306
+ template.hasResourceProperties('AWS::DynamoDB::Table', {
307
+ PointInTimeRecoverySpecification: Match.absent(),
308
+ });
309
+ });
310
+ test('CDK: options.pointInTimeRecovery overrides the stack defaults (on under sandbox)', () => {
311
+ const { stack, parent } = setup(BlocksPresets.sandbox);
312
+ new DistributedTable(parent, 'users', {
313
+ schema: userSchema,
314
+ key: { partitionKey: 'userId', sortKey: 'createdAt' },
315
+ pointInTimeRecovery: true,
316
+ });
317
+ const template = Template.fromStack(stack);
318
+ template.hasResourceProperties('AWS::DynamoDB::Table', {
319
+ PointInTimeRecoverySpecification: { PointInTimeRecoveryEnabled: true },
320
+ });
321
+ });
322
+ test('CDK: a per-block protection option overrides the stack defaults', () => {
323
+ // Sandbox preset would give DESTROY + no protection; `protection: 'locked'`
324
+ // must win, proving the per-block override sits on top of the #302 defaults.
325
+ const { stack, parent } = setup(BlocksPresets.sandbox);
326
+ new DistributedTable(parent, 'users', {
327
+ schema: userSchema,
328
+ key: { partitionKey: 'userId', sortKey: 'createdAt' },
329
+ protection: 'locked',
330
+ });
331
+ const template = Template.fromStack(stack);
332
+ template.hasResource('AWS::DynamoDB::Table', { DeletionPolicy: 'Retain' });
333
+ template.hasResourceProperties('AWS::DynamoDB::Table', { DeletionProtectionEnabled: true });
334
+ });
53
335
  test('CDK: DistributedTable.fromExisting does NOT provision a table (regression)', () => {
54
336
  const { stack, parent } = setup();
55
337
  new DistributedTable(parent, 'users', {
@@ -91,3 +373,42 @@ test('CDK: calling a runtime data method throws an actionable error (not a crypt
91
373
  assert.throws(() => table[method]('k'), /cannot be called during CDK synth/, `${method}() should throw the actionable synth-time error`);
92
374
  }
93
375
  });
376
+ // ── Synth-time warnings actually fire (not just the fallback values) ─────────
377
+ test('CDK: an unrecognized protection value warns at synth', () => {
378
+ const { stack, parent } = setup();
379
+ new DistributedTable(parent, 'users', {
380
+ schema: userSchema,
381
+ key: { partitionKey: 'userId', sortKey: 'createdAt' },
382
+ protection: 'retian', // intentional typo — exercise the synth guard
383
+ });
384
+ Annotations.fromStack(stack).hasWarning('*', Match.stringLikeRegexp('Unrecognized protection'));
385
+ });
386
+ test('CDK: an unrecognized encryption value warns at synth', () => {
387
+ const { stack, parent } = setup();
388
+ new DistributedTable(parent, 'users', {
389
+ schema: userSchema,
390
+ key: { partitionKey: 'userId', sortKey: 'createdAt' },
391
+ encryption: 'kms', // intentional typo — exercise the synth guard
392
+ });
393
+ Annotations.fromStack(stack).hasWarning('*', Match.stringLikeRegexp('Unrecognized encryption'));
394
+ });
395
+ test('CDK: an out-of-range retentionDays warns at synth', () => {
396
+ const { stack, parent } = setup();
397
+ new DistributedTable(parent, 'users', {
398
+ schema: userSchema,
399
+ key: { partitionKey: 'userId', sortKey: 'createdAt' },
400
+ pointInTimeRecovery: { retentionDays: 60 },
401
+ });
402
+ Annotations.fromStack(stack).hasWarning('*', Match.stringLikeRegexp('retentionDays must be an integer'));
403
+ });
404
+ test('CDK: durability options passed alongside fromExisting warn at synth', () => {
405
+ const { stack, parent } = setup();
406
+ new DistributedTable(parent, 'users', {
407
+ schema: userSchema,
408
+ key: { partitionKey: 'userId', sortKey: 'createdAt' },
409
+ table: DistributedTable.fromExisting('preexisting-users-table'),
410
+ protection: 'locked',
411
+ pointInTimeRecovery: { retentionDays: 14 },
412
+ });
413
+ Annotations.fromStack(stack).hasWarning('*', Match.stringLikeRegexp('wrapped via fromExisting'));
414
+ });
@@ -1,8 +1,8 @@
1
1
  import { Scope } from '@aws-blocks/core';
2
2
  import type { ScopeParent } from '@aws-blocks/core';
3
3
  export { DistributedTableErrors } from './errors.js';
4
- export type { TableKeyConfig, DistributedTableOptions, ReadValidationMode, ExternalTableRef, TableKey, PartitionKeyCondition, SortKeyCondition, KeyCondition, QueryOptions, ScanOptions, PutOptions, DeleteOptions, } from './types.js';
5
- import type { TableKeyConfig, DistributedTableOptions, ExternalTableRef, ScanOptions, PutOptions, DeleteOptions, TableKey } from './types.js';
4
+ export type { TableKeyConfig, DistributedTableOptions, ReadValidationMode, ExternalTableRef, ExternalKmsKeyRef, TableKey, PartitionKeyCondition, SortKeyCondition, KeyCondition, QueryOptions, ScanOptions, PutOptions, DeleteOptions, } from './types.js';
5
+ import type { TableKeyConfig, DistributedTableOptions, ExternalTableRef, ExternalKmsKeyRef, ScanOptions, PutOptions, DeleteOptions, TableKey } from './types.js';
6
6
  /**
7
7
  * Structured data storage backed by DynamoDB with secondary indexes and
8
8
  * rich query capabilities.
@@ -99,6 +99,7 @@ export declare class DistributedTable<T, K extends TableKeyConfig<T> = TableKeyC
99
99
  */
100
100
  deleteBatch(keys: TableKey<T, K>[]): Promise<void>;
101
101
  static fromExisting(tableName: string): ExternalTableRef;
102
+ static fromKmsKey(keyArn: string): ExternalKmsKeyRef;
102
103
  private checkFieldEquals;
103
104
  private serializeKey;
104
105
  private loadFromDisk;
@@ -1 +1 @@
1
- {"version":3,"file":"index.mock.d.ts","sourceRoot":"","sources":["../src/index.mock.ts"],"names":[],"mappings":"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"}
1
+ {"version":3,"file":"index.mock.d.ts","sourceRoot":"","sources":["../src/index.mock.ts"],"names":[],"mappings":"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"}
@@ -276,6 +276,9 @@ export class DistributedTable extends Scope {
276
276
  static fromExisting(tableName) {
277
277
  return { __brand: 'ExternalTableRef', tableName };
278
278
  }
279
+ static fromKmsKey(keyArn) {
280
+ return { __brand: 'ExternalKmsKeyRef', keyArn };
281
+ }
279
282
  // ── Internal ────────────────────────────────────────────────────────────
280
283
  checkFieldEquals(keyStr, fields) {
281
284
  const entries = Object.entries(fields).filter(([, v]) => v !== undefined);
package/dist/types.d.ts CHANGED
@@ -43,6 +43,82 @@ export interface DistributedTableOptions<T, K extends TableKeyConfig<T> = TableK
43
43
  * ```
44
44
  */
45
45
  ttl?: keyof T & string;
46
+ /**
47
+ * DynamoDB Point-in-Time Recovery (continuous backups) — restore the table
48
+ * to any second within a retention window, protecting against accidental
49
+ * writes/deletes and logical corruption.
50
+ *
51
+ * A single knob, since the recovery window only means anything when PITR is
52
+ * on:
53
+ * - `true` — enable PITR with the default 35-day window.
54
+ * - `false` — disable PITR.
55
+ * - `{ retentionDays: n }` — enable PITR and keep `n` days of continuous
56
+ * backups (**1–35**). A shorter window reduces backup-storage cost at the
57
+ * expense of how far back you can restore.
58
+ *
59
+ * When omitted, the stack-wide default applies (`defaults.pointInTimeRecovery`
60
+ * from `BlocksPresets` — on under `production`, off under `sandbox`). A
61
+ * per-block value always wins.
62
+ *
63
+ * Note: PITR bills for continuous-backup storage (per GB-month of table
64
+ * size), so it is not free on large tables.
65
+ */
66
+ pointInTimeRecovery?: boolean | {
67
+ retentionDays: number;
68
+ };
69
+ /**
70
+ * How hard the table is to destroy — a single knob spanning DynamoDB
71
+ * deletion protection and the CloudFormation removal policy, which together
72
+ * answer one question: "can this table be destroyed?"
73
+ *
74
+ * - `'disposable'`: `RemovalPolicy.DESTROY`, deletion protection **off**.
75
+ * Deleting the stack deletes the table. The **sandbox default** — keeps
76
+ * `sandbox:destroy` a one-command teardown.
77
+ * - `'retained'`: `RemovalPolicy.RETAIN`, deletion protection **off**.
78
+ * Deleting the stack orphans (keeps) the table, but a direct
79
+ * `DeleteTable`/console delete still works. Use when you want the data to
80
+ * survive stack teardown without blocking intentional deletes.
81
+ * - `'locked'`: `RemovalPolicy.RETAIN` **and** deletion protection **on**.
82
+ * The table survives stack deletion and DynamoDB refuses a direct delete
83
+ * until protection is turned off. The **production default**.
84
+ *
85
+ * When omitted, removal policy and deletion protection follow the stack-wide
86
+ * `defaults` (`BlocksPresets.production` ≈ `'locked'`, `BlocksPresets.sandbox`
87
+ * ≈ `'disposable'`). A per-block value always wins.
88
+ *
89
+ * Replaces the separate `deletionProtection` + `removalPolicy` booleans:
90
+ * those two knobs could encode the contradictory `deletionProtection: true`
91
+ * + `removalPolicy: 'destroy'` state, which wedges stack deletion (CFN
92
+ * issues `DeleteTable`, DynamoDB refuses it, the stack lands in
93
+ * `DELETE_FAILED`). A single enum makes that state unrepresentable.
94
+ */
95
+ protection?: 'disposable' | 'retained' | 'locked';
96
+ /**
97
+ * Server-side encryption at rest.
98
+ *
99
+ * - `'aws-managed'` (default): SSE with the AWS-managed `aws/dynamodb` KMS
100
+ * key. Auditable via CloudTrail with no per-key monthly charge.
101
+ * - `'customer-managed'`: provisions a **dedicated** customer-managed KMS
102
+ * key (CMK) for this table, giving you full control over rotation and key
103
+ * policy. Incurs standard KMS key + request charges — and note this mints
104
+ * a **separate key per table**, so a dozen tables means a dozen keys.
105
+ * - a {@link ExternalKmsKeyRef} from {@link DistributedTable.fromKmsKey}:
106
+ * uses an **existing** CMK you already own, so several tables can share one
107
+ * key (and one monthly charge) instead of each provisioning its own.
108
+ *
109
+ * DynamoDB is always encrypted at rest; this only selects the key.
110
+ *
111
+ * @example
112
+ * ```ts
113
+ * // Share one key across several tables
114
+ * const key = DistributedTable.fromKmsKey(
115
+ * 'arn:aws:kms:us-east-1:111122223333:key/abcd-1234',
116
+ * );
117
+ * new DistributedTable(scope, 'orders', { schema, key: { partitionKey: 'id' }, encryption: key });
118
+ * new DistributedTable(scope, 'events', { schema, key: { partitionKey: 'id' }, encryption: key });
119
+ * ```
120
+ */
121
+ encryption?: 'aws-managed' | 'customer-managed' | ExternalKmsKeyRef;
46
122
  /**
47
123
  * How reads (`get`, `getBatch`, `query`, `scan`) reconcile a stored item with
48
124
  * the configured `schema`. Writes (`put`/`putBatch`) always validate; this
@@ -93,6 +169,16 @@ export interface ExternalTableRef {
93
169
  readonly __brand: 'ExternalTableRef';
94
170
  readonly tableName: string;
95
171
  }
172
+ /**
173
+ * A reference to an existing customer-managed KMS key, produced by
174
+ * {@link DistributedTable.fromKmsKey}. Pass it as the `encryption` option to
175
+ * encrypt the table with a CMK you already own — letting several tables share
176
+ * one key instead of each provisioning its own dedicated key.
177
+ */
178
+ export interface ExternalKmsKeyRef {
179
+ readonly __brand: 'ExternalKmsKeyRef';
180
+ readonly keyArn: string;
181
+ }
96
182
  /**
97
183
  * Picks exactly the key fields from T and makes them required.
98
184
  * Non-key fields are excluded.
@@ -1 +1 @@
1
- {"version":3,"file":"types.d.ts","sourceRoot":"","sources":["../src/types.ts"],"names":[],"mappings":"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"}
1
+ {"version":3,"file":"types.d.ts","sourceRoot":"","sources":["../src/types.ts"],"names":[],"mappings":"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"}
package/dist/version.d.ts CHANGED
@@ -1,3 +1,3 @@
1
1
  export declare const BB_NAME = "DistributedTable";
2
- export declare const BB_VERSION = "0.1.4";
2
+ export declare const BB_VERSION = "0.1.6";
3
3
  //# sourceMappingURL=version.d.ts.map
package/dist/version.js CHANGED
@@ -1,3 +1,3 @@
1
1
  // Auto-generated by scripts/generate-version.mjs — do not edit manually
2
2
  export const BB_NAME = 'DistributedTable';
3
- export const BB_VERSION = '0.1.4';
3
+ export const BB_VERSION = '0.1.6';
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@aws-blocks/bb-distributed-table",
3
- "version": "0.1.4",
3
+ "version": "0.1.6",
4
4
  "repository": {
5
5
  "type": "git",
6
6
  "url": "git+https://github.com/aws-devtools-labs/aws-blocks.git",
@@ -39,8 +39,8 @@
39
39
  "test": "node --test --test-concurrency=1 dist/index.test.js dist/parity.test.js dist/index.cdk.test.js"
40
40
  },
41
41
  "dependencies": {
42
- "@aws-blocks/core": "^0.1.17",
43
- "@aws-blocks/bb-logger": "^0.1.3",
42
+ "@aws-blocks/core": "^0.3.0",
43
+ "@aws-blocks/bb-logger": "^0.1.5",
44
44
  "@aws-sdk/client-dynamodb": "^3.0.0",
45
45
  "@aws-sdk/lib-dynamodb": "^3.0.0",
46
46
  "@standard-schema/spec": "^1.0.0",
package/src/index.aws.ts CHANGED
@@ -23,6 +23,7 @@ export type {
23
23
  DistributedTableOptions,
24
24
  ReadValidationMode,
25
25
  ExternalTableRef,
26
+ ExternalKmsKeyRef,
26
27
  TableKey,
27
28
  PartitionKeyCondition,
28
29
  SortKeyCondition,
@@ -37,6 +38,7 @@ import type {
37
38
  TableKeyConfig,
38
39
  DistributedTableOptions,
39
40
  ExternalTableRef,
41
+ ExternalKmsKeyRef,
40
42
  ScanOptions,
41
43
  PutOptions,
42
44
  DeleteOptions,
@@ -280,6 +282,10 @@ export class DistributedTable<
280
282
  return { __brand: 'ExternalTableRef' as const, tableName };
281
283
  }
282
284
 
285
+ static fromKmsKey(keyArn: string): ExternalKmsKeyRef {
286
+ return { __brand: 'ExternalKmsKeyRef' as const, keyArn };
287
+ }
288
+
283
289
  // ── Internal ────────────────────────────────────────────────────────────
284
290
 
285
291
  private async validateItem(item: T): Promise<void> {