dynamodb-reactive 0.1.5 → 0.1.7

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.
@@ -1,6 +1,23 @@
1
1
  import { z } from 'zod';
2
2
 
3
3
  // ../core/src/table.ts
4
+ function getSchemaFields(schema) {
5
+ const fields = /* @__PURE__ */ new Set();
6
+ if ("options" in schema && Array.isArray(schema.options)) {
7
+ for (const option of schema.options) {
8
+ if ("shape" in option && typeof option.shape === "object") {
9
+ for (const key of Object.keys(option.shape)) {
10
+ fields.add(key);
11
+ }
12
+ }
13
+ }
14
+ } else if ("shape" in schema && typeof schema.shape === "object") {
15
+ for (const key of Object.keys(schema.shape)) {
16
+ fields.add(key);
17
+ }
18
+ }
19
+ return fields;
20
+ }
4
21
  var DynamoTable = class {
5
22
  tableName;
6
23
  schema;
@@ -17,9 +34,9 @@ var DynamoTable = class {
17
34
  this.field = this.createFieldRefs();
18
35
  }
19
36
  createFieldRefs() {
20
- const shape = this.schema.shape;
37
+ const fields = getSchemaFields(this.schema);
21
38
  const refs = {};
22
- for (const key of Object.keys(shape)) {
39
+ for (const key of fields) {
23
40
  refs[key] = {
24
41
  fieldName: key,
25
42
  _type: void 0
@@ -58,13 +75,15 @@ var DynamoTable = class {
58
75
  * Get the list of field names in the schema
59
76
  */
60
77
  getFieldNames() {
61
- return Object.keys(this.schema.shape);
78
+ return Array.from(
79
+ getSchemaFields(this.schema)
80
+ );
62
81
  }
63
82
  /**
64
83
  * Check if a field exists in the schema
65
84
  */
66
85
  hasField(fieldName) {
67
- return fieldName in this.schema.shape;
86
+ return getSchemaFields(this.schema).has(fieldName);
68
87
  }
69
88
  };
70
89
  function defineSchema(config) {
@@ -127,5 +146,5 @@ var SystemTableNames = {
127
146
  };
128
147
 
129
148
  export { DynamoTable, SystemSchemas, SystemTableNames, defineSchema };
130
- //# sourceMappingURL=chunk-HZ6JHAJJ.js.map
131
- //# sourceMappingURL=chunk-HZ6JHAJJ.js.map
149
+ //# sourceMappingURL=chunk-L4NOAOXX.js.map
150
+ //# sourceMappingURL=chunk-L4NOAOXX.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"sources":["../../core/src/table.ts","../../core/src/schema.ts"],"names":[],"mappings":"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","file":"chunk-L4NOAOXX.js","sourcesContent":["import type { z } from 'zod';\n\nimport type {\n DynamoTableConfig,\n FieldRef,\n IndexDefinition,\n SupportedSchema,\n} from './types.js';\n\n/**\n * Extract all field names from a schema (handles both ZodObject and ZodDiscriminatedUnion)\n */\nfunction getSchemaFields(schema: SupportedSchema): Set<string> {\n const fields = new Set<string>();\n\n // Check if it's a discriminated union by looking for 'options' property\n if ('options' in schema && Array.isArray(schema.options)) {\n // It's a discriminated union - collect fields from all options\n for (const option of schema.options) {\n if ('shape' in option && typeof option.shape === 'object') {\n for (const key of Object.keys(option.shape)) {\n fields.add(key);\n }\n }\n }\n } else if ('shape' in schema && typeof schema.shape === 'object') {\n // It's a regular ZodObject\n for (const key of Object.keys(schema.shape)) {\n fields.add(key);\n }\n }\n\n return fields;\n}\n\n/**\n * Creates field references for type-safe query building\n */\ntype FieldRefs<TSchema extends SupportedSchema> = {\n [K in keyof z.infer<TSchema>]: FieldRef<K & string, z.infer<TSchema>[K]>;\n};\n\n/**\n * DynamoTable - Defines a DynamoDB table with type-safe schema\n *\n * Supports both ZodObject and ZodDiscriminatedUnion schemas for single-table design patterns.\n *\n * @example\n * ```ts\n * // Simple schema\n * const TodoTable = new DynamoTable({\n * tableName: 'prod-todo-table',\n * schema: z.object({\n * PK: z.string(),\n * SK: z.string(),\n * text: z.string(),\n * isDone: z.boolean(),\n * }),\n * pk: 'PK',\n * sk: 'SK',\n * });\n *\n * // Discriminated union for single-table design\n * const MultiEntityTable = new DynamoTable({\n * tableName: 'prod-entities',\n * schema: z.discriminatedUnion('entityType', [\n * z.object({ PK: z.string(), SK: z.string(), entityType: z.literal('USER'), name: z.string() }),\n * z.object({ PK: z.string(), SK: z.string(), entityType: z.literal('ITEM'), title: z.string() }),\n * ]),\n * pk: 'PK',\n * sk: 'SK',\n * });\n * ```\n */\nexport class DynamoTable<\n TSchema extends SupportedSchema,\n TPk extends keyof z.infer<TSchema>,\n TSk extends keyof z.infer<TSchema> | undefined = undefined,\n TIndexes extends Record<string, IndexDefinition> = Record<\n string,\n IndexDefinition\n >,\n> {\n public readonly tableName: string;\n public readonly schema: TSchema;\n public readonly pk: TPk;\n public readonly sk: TSk;\n public readonly indexes: TIndexes;\n public readonly field: FieldRefs<TSchema>;\n\n constructor(config: DynamoTableConfig<TSchema, TPk, TSk, TIndexes>) {\n this.tableName = config.tableName;\n this.schema = config.schema;\n this.pk = config.pk;\n this.sk = config.sk as TSk;\n this.indexes = (config.indexes ?? {}) as TIndexes;\n\n // Create field references for query building\n this.field = this.createFieldRefs();\n }\n\n private createFieldRefs(): FieldRefs<TSchema> {\n const fields = getSchemaFields(this.schema);\n const refs: Record<string, FieldRef<string, unknown>> = {};\n\n for (const key of fields) {\n refs[key] = {\n fieldName: key,\n _type: undefined as unknown,\n };\n }\n\n return refs as FieldRefs<TSchema>;\n }\n\n /**\n * Validate an item against the schema\n */\n validate(item: unknown): z.infer<TSchema> {\n return this.schema.parse(item);\n }\n\n /**\n * Safely validate an item, returning a result object\n */\n safeParse(item: unknown): z.SafeParseReturnType<unknown, z.infer<TSchema>> {\n return this.schema.safeParse(item);\n }\n\n /**\n * Get the partition key value from an item\n */\n getPk(item: z.infer<TSchema>): z.infer<TSchema>[TPk] {\n return item[this.pk];\n }\n\n /**\n * Get the sort key value from an item (if defined)\n */\n getSk(\n item: z.infer<TSchema>,\n ): TSk extends keyof z.infer<TSchema> ? z.infer<TSchema>[TSk] : undefined {\n if (this.sk === undefined) {\n return undefined as TSk extends keyof z.infer<TSchema>\n ? z.infer<TSchema>[TSk]\n : undefined;\n }\n return item[\n this.sk as keyof z.infer<TSchema>\n ] as TSk extends keyof z.infer<TSchema> ? z.infer<TSchema>[TSk] : undefined;\n }\n\n /**\n * Get the list of field names in the schema\n */\n getFieldNames(): (keyof z.infer<TSchema>)[] {\n return Array.from(\n getSchemaFields(this.schema),\n ) as (keyof z.infer<TSchema>)[];\n }\n\n /**\n * Check if a field exists in the schema\n */\n hasField(fieldName: string): fieldName is keyof z.infer<TSchema> & string {\n return getSchemaFields(this.schema).has(fieldName);\n }\n}\n\n/**\n * Helper type to extract the shape from a Zod schema\n */\nexport type InferSchema<T> =\n T extends DynamoTable<infer TSchema, any, any, any>\n ? z.infer<TSchema>\n : never;\n\n/**\n * Helper type to extract field names from a table\n */\nexport type TableFields<T> =\n T extends DynamoTable<infer TSchema, any, any, any>\n ? keyof z.infer<TSchema>\n : never;\n\n/**\n * Helper type to get the pk field name\n */\nexport type TablePk<T> =\n T extends DynamoTable<any, infer TPk, any, any> ? TPk : never;\n\n/**\n * Helper type to get the sk field name\n */\nexport type TableSk<T> =\n T extends DynamoTable<any, any, infer TSk, any> ? TSk : never;\n\n/**\n * Helper type to get indexes\n */\nexport type TableIndexes<T> =\n T extends DynamoTable<any, any, any, infer TIndexes> ? TIndexes : never;\n","import { z } from 'zod';\n\nimport { DynamoTable } from './table.js';\nimport type { IndexDefinition, SupportedSchema } from './types.js';\n\n/**\n * Helper function to define a schema with type inference\n * This provides a cleaner API for defining tables\n *\n * Supports both ZodObject and ZodDiscriminatedUnion schemas.\n *\n * @example\n * ```ts\n * // Simple schema\n * const TodoTable = defineSchema({\n * tableName: 'prod-todo-table',\n * schema: z.object({\n * id: z.string(),\n * taskListId: z.string(),\n * text: z.string(),\n * isDone: z.boolean(),\n * }),\n * pk: 'id',\n * indexes: {\n * byTaskId: { name: 'gsi_by_task_id', pk: 'taskListId' }\n * }\n * });\n *\n * // Discriminated union for single-table design\n * const MultiEntityTable = defineSchema({\n * tableName: 'prod-entities',\n * schema: z.discriminatedUnion('entityType', [\n * z.object({ PK: z.string(), SK: z.string(), entityType: z.literal('USER'), name: z.string() }),\n * z.object({ PK: z.string(), SK: z.string(), entityType: z.literal('ITEM'), title: z.string() }),\n * ]),\n * pk: 'PK',\n * sk: 'SK',\n * });\n * ```\n */\nexport function defineSchema<\n TSchema extends SupportedSchema,\n TPk extends keyof z.infer<TSchema> & string,\n TSk extends (keyof z.infer<TSchema> & string) | undefined = undefined,\n TIndexes extends Record<string, IndexDefinition> = Record<\n string,\n IndexDefinition\n >,\n>(config: {\n tableName: string;\n schema: TSchema;\n pk: TPk;\n sk?: TSk;\n indexes?: TIndexes;\n}): DynamoTable<TSchema, TPk, TSk, TIndexes> {\n return new DynamoTable(config);\n}\n\n/**\n * System table schemas for the reactive engine\n */\nexport const SystemSchemas = {\n /**\n * ReactiveConnections - Tracks active WebSocket connections\n */\n connections: z.object({\n connectionId: z.string(),\n context: z.record(z.unknown()).optional(),\n connectedAt: z.number(),\n ttl: z.number(),\n }),\n\n /**\n * ReactiveDependencies - The inverted index for O(1) lookups\n */\n dependencies: z.object({\n pk: z.string(), // Format: \"TableName#FieldName#FieldValue\"\n sk: z.string(), // ConnectionID#SubscriptionID\n connectionId: z.string(),\n subscriptionId: z.string(),\n tableName: z.string(),\n fieldName: z.string(),\n fieldValue: z.string(),\n ttl: z.number(),\n }),\n\n /**\n * ReactiveConnectionQueries - Stores subscription state for diffing\n */\n queries: z.object({\n pk: z.string(), // ConnectionID\n sk: z.string(), // SubscriptionID\n connectionId: z.string(),\n subscriptionId: z.string(),\n queryMetadata: z.object({\n tableName: z.string(),\n indexName: z.string().optional(),\n filterConditions: z.array(z.unknown()),\n sortField: z.string().optional(),\n sortOrder: z.enum(['asc', 'desc']).optional(),\n limit: z.number().optional(),\n }),\n lastResult: z.array(z.unknown()),\n dependencies: z.array(z.string()),\n createdAt: z.number(),\n updatedAt: z.number(),\n ttl: z.number(),\n }),\n};\n\n/**\n * System table names\n */\nexport const SystemTableNames = {\n connections: 'ReactiveConnections',\n dependencies: 'ReactiveDependencies',\n queries: 'ReactiveConnectionQueries',\n} as const;\n"]}
package/dist/core.d.ts CHANGED
@@ -1,4 +1,4 @@
1
1
  export { SystemSchemas, SystemTableNames, defineSchema } from './index.js';
2
- export { D as DynamoTable, I as InferSchema, T as TableFields, a as TableIndexes, b as TablePk, c as TableSk } from './table-CfIWxbuJ.js';
3
- export { A as AnyDynamoTable, C as ConnectionEntry, b as DependencyEntry, D as DynamoTableConfig, F as FieldRef, a as FilterCondition, I as IndexDefinition, J as JsonPatch, c as QueryEntry, Q as QueryMetadata, S as SubscriptionMessage } from './types-DeshTSf5.js';
2
+ export { D as DynamoTable, I as InferSchema, T as TableFields, a as TableIndexes, b as TablePk, c as TableSk } from './table-DjeyVXYp.js';
3
+ export { A as AnyDynamoTable, C as ConnectionEntry, b as DependencyEntry, D as DynamoTableConfig, F as FieldRef, a as FilterCondition, I as IndexDefinition, c as InferSupportedSchema, J as JsonPatch, d as QueryEntry, Q as QueryMetadata, e as SubscriptionMessage, S as SupportedSchema } from './types-2EfCnE0c.js';
4
4
  import 'zod';
package/dist/core.js CHANGED
@@ -1,3 +1,3 @@
1
- export { DynamoTable, SystemSchemas, SystemTableNames, defineSchema } from './chunk-HZ6JHAJJ.js';
1
+ export { DynamoTable, SystemSchemas, SystemTableNames, defineSchema } from './chunk-L4NOAOXX.js';
2
2
  //# sourceMappingURL=core.js.map
3
3
  //# sourceMappingURL=core.js.map
package/dist/index.d.ts CHANGED
@@ -1,15 +1,18 @@
1
- import { D as DynamoTable } from './table-CfIWxbuJ.js';
2
- export { I as InferSchema, T as TableFields, a as TableIndexes, b as TablePk, c as TableSk } from './table-CfIWxbuJ.js';
3
- import { I as IndexDefinition } from './types-DeshTSf5.js';
4
- export { A as AnyDynamoTable, C as ConnectionEntry, b as DependencyEntry, D as DynamoTableConfig, F as FieldRef, a as FilterCondition, J as JsonPatch, c as QueryEntry, Q as QueryMetadata, S as SubscriptionMessage } from './types-DeshTSf5.js';
1
+ import { D as DynamoTable } from './table-DjeyVXYp.js';
2
+ export { I as InferSchema, T as TableFields, a as TableIndexes, b as TablePk, c as TableSk } from './table-DjeyVXYp.js';
3
+ import { S as SupportedSchema, I as IndexDefinition } from './types-2EfCnE0c.js';
4
+ export { A as AnyDynamoTable, C as ConnectionEntry, b as DependencyEntry, D as DynamoTableConfig, F as FieldRef, a as FilterCondition, c as InferSupportedSchema, J as JsonPatch, d as QueryEntry, Q as QueryMetadata, e as SubscriptionMessage } from './types-2EfCnE0c.js';
5
5
  import { z } from 'zod';
6
6
 
7
7
  /**
8
8
  * Helper function to define a schema with type inference
9
9
  * This provides a cleaner API for defining tables
10
10
  *
11
+ * Supports both ZodObject and ZodDiscriminatedUnion schemas.
12
+ *
11
13
  * @example
12
14
  * ```ts
15
+ * // Simple schema
13
16
  * const TodoTable = defineSchema({
14
17
  * tableName: 'prod-todo-table',
15
18
  * schema: z.object({
@@ -23,9 +26,20 @@ import { z } from 'zod';
23
26
  * byTaskId: { name: 'gsi_by_task_id', pk: 'taskListId' }
24
27
  * }
25
28
  * });
29
+ *
30
+ * // Discriminated union for single-table design
31
+ * const MultiEntityTable = defineSchema({
32
+ * tableName: 'prod-entities',
33
+ * schema: z.discriminatedUnion('entityType', [
34
+ * z.object({ PK: z.string(), SK: z.string(), entityType: z.literal('USER'), name: z.string() }),
35
+ * z.object({ PK: z.string(), SK: z.string(), entityType: z.literal('ITEM'), title: z.string() }),
36
+ * ]),
37
+ * pk: 'PK',
38
+ * sk: 'SK',
39
+ * });
26
40
  * ```
27
41
  */
28
- declare function defineSchema<TSchema extends z.ZodObject<z.ZodRawShape>, TPk extends keyof z.infer<TSchema> & string, TSk extends (keyof z.infer<TSchema> & string) | undefined = undefined, TIndexes extends Record<string, IndexDefinition> = Record<string, IndexDefinition>>(config: {
42
+ declare function defineSchema<TSchema extends SupportedSchema, TPk extends keyof z.infer<TSchema> & string, TSk extends (keyof z.infer<TSchema> & string) | undefined = undefined, TIndexes extends Record<string, IndexDefinition> = Record<string, IndexDefinition>>(config: {
29
43
  tableName: string;
30
44
  schema: TSchema;
31
45
  pk: TPk;
@@ -168,4 +182,4 @@ declare const SystemTableNames: {
168
182
  readonly queries: "ReactiveConnectionQueries";
169
183
  };
170
184
 
171
- export { DynamoTable, IndexDefinition, SystemSchemas, SystemTableNames, defineSchema };
185
+ export { DynamoTable, IndexDefinition, SupportedSchema, SystemSchemas, SystemTableNames, defineSchema };
package/dist/index.js CHANGED
@@ -1,3 +1,3 @@
1
- export { DynamoTable, SystemSchemas, SystemTableNames, defineSchema } from './chunk-HZ6JHAJJ.js';
1
+ export { DynamoTable, SystemSchemas, SystemTableNames, defineSchema } from './chunk-L4NOAOXX.js';
2
2
  //# sourceMappingURL=index.js.map
3
3
  //# sourceMappingURL=index.js.map
package/dist/infra.d.ts CHANGED
@@ -1,4 +1,4 @@
1
- import { A as AnyDynamoTable } from './types-DeshTSf5.js';
1
+ import { A as AnyDynamoTable } from './types-2EfCnE0c.js';
2
2
  import * as cdk from 'aws-cdk-lib';
3
3
  import * as apigatewayv2 from 'aws-cdk-lib/aws-apigatewayv2';
4
4
  import * as dynamodb from 'aws-cdk-lib/aws-dynamodb';
@@ -7,6 +7,14 @@ import * as logs from 'aws-cdk-lib/aws-logs';
7
7
  import { Construct } from 'constructs';
8
8
  import 'zod';
9
9
 
10
+ /**
11
+ * Provisioning mode for DynamoDB tables
12
+ * - "ON_DEMAND": Pay-per-request billing (default)
13
+ * - { readWrite: number }: Provisioned capacity with specified RCU/WCU
14
+ */
15
+ type ProvisioningMode = 'ON_DEMAND' | {
16
+ readWrite: number;
17
+ };
10
18
  /**
11
19
  * Props for ReactiveSystemTables
12
20
  */
@@ -26,6 +34,11 @@ interface ReactiveSystemTablesProps {
26
34
  * @default false
27
35
  */
28
36
  pointInTimeRecovery?: boolean;
37
+ /**
38
+ * Provisioning mode for tables
39
+ * @default "ON_DEMAND"
40
+ */
41
+ provisioningMode?: ProvisioningMode;
29
42
  }
30
43
  /**
31
44
  * Creates the three system tables for the reactive engine
@@ -186,4 +199,4 @@ declare function createStreamFilter(options: {
186
199
  */
187
200
  declare function generateEntryPointCode(): string;
188
201
 
189
- export { DynamoDBStreamSource, type DynamoDBStreamSourceProps, ReactiveEngine, type ReactiveEngineProps, ReactiveSystemTables, type ReactiveSystemTablesProps, createStreamFilter, generateEntryPointCode };
202
+ export { DynamoDBStreamSource, type DynamoDBStreamSourceProps, type ProvisioningMode, ReactiveEngine, type ReactiveEngineProps, ReactiveSystemTables, type ReactiveSystemTablesProps, createStreamFilter, generateEntryPointCode };
package/dist/infra.js CHANGED
@@ -1,4 +1,4 @@
1
- import { SystemTableNames } from './chunk-HZ6JHAJJ.js';
1
+ import { SystemTableNames } from './chunk-L4NOAOXX.js';
2
2
  import * as fs from 'fs';
3
3
  import * as path from 'path';
4
4
  import * as cdk2 from 'aws-cdk-lib';
@@ -43,13 +43,20 @@ var ReactiveSystemTables = class extends Construct {
43
43
  const prefix = props.tablePrefix ? `${props.tablePrefix}-` : "";
44
44
  const removalPolicy = props.removalPolicy ?? cdk2.RemovalPolicy.RETAIN;
45
45
  const pointInTimeRecovery = props.pointInTimeRecovery ?? false;
46
+ const provisioningMode = props.provisioningMode ?? "ON_DEMAND";
47
+ const isOnDemand = provisioningMode === "ON_DEMAND";
48
+ const capacityProps = isOnDemand ? { billingMode: dynamodb.BillingMode.PAY_PER_REQUEST } : {
49
+ billingMode: dynamodb.BillingMode.PROVISIONED,
50
+ readCapacity: provisioningMode.readWrite,
51
+ writeCapacity: provisioningMode.readWrite
52
+ };
46
53
  this.connectionsTable = new dynamodb.Table(this, "ConnectionsTable", {
47
54
  tableName: `${prefix}${SystemTableNames.connections}`,
48
55
  partitionKey: {
49
56
  name: "connectionId",
50
57
  type: dynamodb.AttributeType.STRING
51
58
  },
52
- billingMode: dynamodb.BillingMode.PAY_PER_REQUEST,
59
+ ...capacityProps,
53
60
  removalPolicy,
54
61
  pointInTimeRecovery,
55
62
  timeToLiveAttribute: "ttl"
@@ -66,18 +73,23 @@ var ReactiveSystemTables = class extends Construct {
66
73
  // Format: "ConnectionID#SubscriptionID"
67
74
  type: dynamodb.AttributeType.STRING
68
75
  },
69
- billingMode: dynamodb.BillingMode.PAY_PER_REQUEST,
76
+ ...capacityProps,
70
77
  removalPolicy,
71
78
  pointInTimeRecovery,
72
79
  timeToLiveAttribute: "ttl"
73
80
  });
81
+ const gsiProps = isOnDemand ? {} : {
82
+ readCapacity: provisioningMode.readWrite,
83
+ writeCapacity: provisioningMode.readWrite
84
+ };
74
85
  this.dependenciesTable.addGlobalSecondaryIndex({
75
86
  indexName: "byConnectionId",
76
87
  partitionKey: {
77
88
  name: "connectionId",
78
89
  type: dynamodb.AttributeType.STRING
79
90
  },
80
- projectionType: dynamodb.ProjectionType.KEYS_ONLY
91
+ projectionType: dynamodb.ProjectionType.KEYS_ONLY,
92
+ ...gsiProps
81
93
  });
82
94
  this.queriesTable = new dynamodb.Table(this, "QueriesTable", {
83
95
  tableName: `${prefix}${SystemTableNames.queries}`,
@@ -91,7 +103,7 @@ var ReactiveSystemTables = class extends Construct {
91
103
  // SubscriptionID
92
104
  type: dynamodb.AttributeType.STRING
93
105
  },
94
- billingMode: dynamodb.BillingMode.PAY_PER_REQUEST,
106
+ ...capacityProps,
95
107
  removalPolicy,
96
108
  pointInTimeRecovery,
97
109
  timeToLiveAttribute: "ttl"
package/dist/infra.js.map CHANGED
@@ -1 +1 @@
1
- {"version":3,"sources":["../../infra/src/handlers/lambda-handlers.ts","../../infra/src/tables.ts","../../infra/src/engine.ts","../../infra/src/stream-source.ts"],"names":["cdk","Construct","cdk3","lambda2"],"mappings":"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","file":"infra.js","sourcesContent":["/**\n * Entry point code generator for the reactive Lambda handlers.\n *\n * No user code is imported - the handlers use only environment variables\n * and stored query metadata for all operations.\n */\n\n/**\n * Generate the entry point code for Lambda functions.\n * This is called by the CDK construct to create the bundled entry file.\n */\nexport function generateEntryPointCode(): string {\n return `// Auto-generated entry point for reactive Lambda handlers\n// No user code required - all configuration comes from environment variables\nimport { createLambdaHandlers } from 'dynamodb-reactive/server';\n\nconst handlers = createLambdaHandlers();\n\nexport const connectHandler = handlers.connectHandler;\nexport const disconnectHandler = handlers.disconnectHandler;\nexport const messageHandler = handlers.messageHandler;\nexport const streamHandler = handlers.streamHandler;\n`;\n}\n","import { SystemTableNames } from '@dynamodb-reactive/core';\nimport * as cdk from 'aws-cdk-lib';\nimport * as dynamodb from 'aws-cdk-lib/aws-dynamodb';\nimport { Construct } from 'constructs';\n\n/**\n * Props for ReactiveSystemTables\n */\nexport interface ReactiveSystemTablesProps {\n /**\n * Prefix for table names\n * @default - no prefix\n */\n tablePrefix?: string;\n\n /**\n * Removal policy for tables\n * @default - cdk.RemovalPolicy.RETAIN\n */\n removalPolicy?: cdk.RemovalPolicy;\n\n /**\n * Enable point-in-time recovery\n * @default false\n */\n pointInTimeRecovery?: boolean;\n}\n\n/**\n * Creates the three system tables for the reactive engine\n */\nexport class ReactiveSystemTables extends Construct {\n /**\n * ReactiveConnections table - tracks WebSocket connections\n */\n public readonly connectionsTable: dynamodb.Table;\n\n /**\n * ReactiveDependencies table - the inverted index\n */\n public readonly dependenciesTable: dynamodb.Table;\n\n /**\n * ReactiveConnectionQueries table - stores subscription state\n */\n public readonly queriesTable: dynamodb.Table;\n\n constructor(\n scope: Construct,\n id: string,\n props: ReactiveSystemTablesProps = {},\n ) {\n super(scope, id);\n\n const prefix = props.tablePrefix ? `${props.tablePrefix}-` : '';\n const removalPolicy = props.removalPolicy ?? cdk.RemovalPolicy.RETAIN;\n const pointInTimeRecovery = props.pointInTimeRecovery ?? false;\n\n // ReactiveConnections Table\n // Tracks active WebSocket connections and user context\n this.connectionsTable = new dynamodb.Table(this, 'ConnectionsTable', {\n tableName: `${prefix}${SystemTableNames.connections}`,\n partitionKey: {\n name: 'connectionId',\n type: dynamodb.AttributeType.STRING,\n },\n billingMode: dynamodb.BillingMode.PAY_PER_REQUEST,\n removalPolicy,\n pointInTimeRecovery,\n timeToLiveAttribute: 'ttl',\n });\n\n // ReactiveDependencies Table (The Inverted Index)\n // Maps Field#Value -> ConnectionID for O(1) lookups\n this.dependenciesTable = new dynamodb.Table(this, 'DependenciesTable', {\n tableName: `${prefix}${SystemTableNames.dependencies}`,\n partitionKey: {\n name: 'pk', // Format: \"TableName#FieldName#FieldValue\"\n type: dynamodb.AttributeType.STRING,\n },\n sortKey: {\n name: 'sk', // Format: \"ConnectionID#SubscriptionID\"\n type: dynamodb.AttributeType.STRING,\n },\n billingMode: dynamodb.BillingMode.PAY_PER_REQUEST,\n removalPolicy,\n pointInTimeRecovery,\n timeToLiveAttribute: 'ttl',\n });\n\n // Add GSI for querying by connectionId (for cleanup)\n this.dependenciesTable.addGlobalSecondaryIndex({\n indexName: 'byConnectionId',\n partitionKey: {\n name: 'connectionId',\n type: dynamodb.AttributeType.STRING,\n },\n projectionType: dynamodb.ProjectionType.KEYS_ONLY,\n });\n\n // ReactiveConnectionQueries Table\n // Stores subscription state for diffing\n this.queriesTable = new dynamodb.Table(this, 'QueriesTable', {\n tableName: `${prefix}${SystemTableNames.queries}`,\n partitionKey: {\n name: 'pk', // ConnectionID\n type: dynamodb.AttributeType.STRING,\n },\n sortKey: {\n name: 'sk', // SubscriptionID\n type: dynamodb.AttributeType.STRING,\n },\n billingMode: dynamodb.BillingMode.PAY_PER_REQUEST,\n removalPolicy,\n pointInTimeRecovery,\n timeToLiveAttribute: 'ttl',\n });\n }\n}\n","import * as fs from 'node:fs';\nimport * as path from 'node:path';\n\nimport type { AnyDynamoTable } from '@dynamodb-reactive/core';\nimport * as cdk from 'aws-cdk-lib';\nimport * as apigatewayv2 from 'aws-cdk-lib/aws-apigatewayv2';\nimport * as apigatewayv2Integrations from 'aws-cdk-lib/aws-apigatewayv2-integrations';\nimport type * as dynamodb from 'aws-cdk-lib/aws-dynamodb';\nimport * as iam from 'aws-cdk-lib/aws-iam';\nimport * as lambda from 'aws-cdk-lib/aws-lambda';\nimport * as nodejs from 'aws-cdk-lib/aws-lambda-nodejs';\nimport * as logs from 'aws-cdk-lib/aws-logs';\nimport { Construct } from 'constructs';\n\nimport { generateEntryPointCode } from './handlers/lambda-handlers.js';\nimport {\n ReactiveSystemTables,\n type ReactiveSystemTablesProps,\n} from './tables.js';\n\n/**\n * Props for ReactiveEngine construct\n */\nexport interface ReactiveEngineProps {\n /**\n * User-defined DynamoDB tables to enable reactive updates on\n */\n tables: AnyDynamoTable[];\n\n /**\n * Prefix for all resource names\n * @default - no prefix\n */\n resourcePrefix?: string;\n\n /**\n * System tables configuration\n */\n systemTablesProps?: ReactiveSystemTablesProps;\n\n /**\n * Lambda function memory size in MB\n * @default 256\n */\n memorySize?: number;\n\n /**\n * Lambda function timeout\n * @default Duration.seconds(30)\n */\n timeout?: cdk.Duration;\n\n /**\n * Log retention period\n * @default logs.RetentionDays.ONE_WEEK\n */\n logRetention?: logs.RetentionDays;\n\n /**\n * Environment variables for Lambda functions\n */\n environment?: Record<string, string>;\n\n /**\n * Enable tracing with X-Ray\n * @default false\n */\n tracing?: boolean;\n}\n\n/**\n * ReactiveEngine - Main CDK construct for the reactive DynamoDB system\n */\nexport class ReactiveEngine extends Construct {\n public readonly systemTables: ReactiveSystemTables;\n public readonly webSocketApi: apigatewayv2.WebSocketApi;\n public readonly webSocketStage: apigatewayv2.WebSocketStage;\n public readonly connectHandler: lambda.Function;\n public readonly disconnectHandler: lambda.Function;\n public readonly messageHandler: lambda.Function;\n public readonly streamHandler: lambda.Function;\n public readonly webSocketUrl: string;\n public readonly callbackUrl: string;\n\n constructor(scope: Construct, id: string, props: ReactiveEngineProps) {\n super(scope, id);\n\n const prefix = props.resourcePrefix ?? '';\n const memorySize = props.memorySize ?? 256;\n const timeout = props.timeout ?? cdk.Duration.seconds(30);\n const logRetention = props.logRetention ?? logs.RetentionDays.ONE_WEEK;\n\n // Create system tables\n this.systemTables = new ReactiveSystemTables(this, 'SystemTables', {\n tablePrefix: prefix,\n ...props.systemTablesProps,\n });\n\n // Create WebSocket API\n this.webSocketApi = new apigatewayv2.WebSocketApi(this, 'WebSocketApi', {\n apiName: `${prefix}ReactiveWebSocket`,\n });\n\n this.webSocketStage = new apigatewayv2.WebSocketStage(\n this,\n 'WebSocketStage',\n {\n webSocketApi: this.webSocketApi,\n stageName: 'prod',\n autoDeploy: true,\n },\n );\n\n this.webSocketUrl = this.webSocketStage.url;\n this.callbackUrl = this.webSocketStage.callbackUrl;\n\n // Generate the entry point file (no user code required)\n // Write to cdk.out directory to avoid path resolution issues with temp directories\n const entryPointCode = generateEntryPointCode();\n const cdkOutDir = path.join(process.cwd(), 'cdk.out', '.generated');\n fs.mkdirSync(cdkOutDir, { recursive: true });\n const entryPointPath = path.join(\n cdkOutDir,\n `reactive-entry-${id}-${Date.now()}.ts`,\n );\n fs.writeFileSync(entryPointPath, entryPointCode);\n\n // Common environment variables\n const environment: Record<string, string> = {\n CONNECTIONS_TABLE: this.systemTables.connectionsTable.tableName,\n DEPENDENCIES_TABLE: this.systemTables.dependenciesTable.tableName,\n QUERIES_TABLE: this.systemTables.queriesTable.tableName,\n WEBSOCKET_ENDPOINT: this.callbackUrl,\n ...props.environment,\n };\n\n // Create handlers using NodejsFunction with the generated entry point\n this.connectHandler = new nodejs.NodejsFunction(this, 'ConnectHandler', {\n functionName: `${prefix}ReactiveConnect`,\n runtime: lambda.Runtime.NODEJS_LATEST,\n handler: 'connectHandler',\n entry: entryPointPath,\n environment,\n memorySize,\n timeout,\n logRetention,\n tracing: props.tracing ? lambda.Tracing.ACTIVE : lambda.Tracing.DISABLED,\n });\n\n this.disconnectHandler = new nodejs.NodejsFunction(\n this,\n 'DisconnectHandler',\n {\n functionName: `${prefix}ReactiveDisconnect`,\n runtime: lambda.Runtime.NODEJS_LATEST,\n handler: 'disconnectHandler',\n entry: entryPointPath,\n environment,\n memorySize,\n timeout,\n logRetention,\n tracing: props.tracing\n ? lambda.Tracing.ACTIVE\n : lambda.Tracing.DISABLED,\n },\n );\n\n this.messageHandler = new nodejs.NodejsFunction(this, 'MessageHandler', {\n functionName: `${prefix}ReactiveMessage`,\n runtime: lambda.Runtime.NODEJS_LATEST,\n handler: 'messageHandler',\n entry: entryPointPath,\n environment,\n memorySize,\n timeout,\n logRetention,\n tracing: props.tracing ? lambda.Tracing.ACTIVE : lambda.Tracing.DISABLED,\n });\n\n this.streamHandler = new nodejs.NodejsFunction(this, 'StreamHandler', {\n functionName: `${prefix}ReactiveStream`,\n runtime: lambda.Runtime.NODEJS_LATEST,\n handler: 'streamHandler',\n entry: entryPointPath,\n environment: {\n ...environment,\n USER_TABLES: props.tables.map((t) => t.tableName).join(','),\n },\n memorySize,\n timeout,\n logRetention,\n tracing: props.tracing ? lambda.Tracing.ACTIVE : lambda.Tracing.DISABLED,\n });\n\n // Grant permissions for system tables\n this.systemTables.connectionsTable.grantReadWriteData(this.connectHandler);\n this.systemTables.connectionsTable.grantReadWriteData(\n this.disconnectHandler,\n );\n this.systemTables.connectionsTable.grantReadWriteData(this.messageHandler);\n this.systemTables.connectionsTable.grantReadWriteData(this.streamHandler);\n\n this.systemTables.dependenciesTable.grantReadWriteData(this.messageHandler);\n this.systemTables.dependenciesTable.grantReadWriteData(this.streamHandler);\n\n this.systemTables.queriesTable.grantReadWriteData(this.messageHandler);\n this.systemTables.queriesTable.grantReadWriteData(this.streamHandler);\n\n // Grant WebSocket management permissions\n const managementPolicy = new iam.PolicyStatement({\n actions: ['execute-api:ManageConnections'],\n resources: [\n `arn:aws:execute-api:${cdk.Stack.of(this).region}:${cdk.Stack.of(this).account}:${this.webSocketApi.apiId}/${this.webSocketStage.stageName}/POST/@connections/*`,\n ],\n });\n\n this.messageHandler.addToRolePolicy(managementPolicy);\n this.streamHandler.addToRolePolicy(managementPolicy);\n\n // Set up WebSocket routes\n this.webSocketApi.addRoute('$connect', {\n integration: new apigatewayv2Integrations.WebSocketLambdaIntegration(\n 'ConnectIntegration',\n this.connectHandler,\n ),\n });\n\n this.webSocketApi.addRoute('$disconnect', {\n integration: new apigatewayv2Integrations.WebSocketLambdaIntegration(\n 'DisconnectIntegration',\n this.disconnectHandler,\n ),\n });\n\n this.webSocketApi.addRoute('$default', {\n integration: new apigatewayv2Integrations.WebSocketLambdaIntegration(\n 'DefaultIntegration',\n this.messageHandler,\n ),\n });\n\n // Set up DynamoDB stream processing for user tables\n for (const table of props.tables) {\n this.setupStreamProcessing(table);\n }\n\n // Output the WebSocket URL\n new cdk.CfnOutput(this, 'WebSocketUrl', {\n value: this.webSocketUrl,\n description: 'WebSocket URL for reactive connections',\n });\n }\n\n private setupStreamProcessing(table: AnyDynamoTable): void {\n const tableArn = `arn:aws:dynamodb:${cdk.Stack.of(this).region}:${cdk.Stack.of(this).account}:table/${table.tableName}`;\n const streamArn = `${tableArn}/stream/*`;\n\n // Stream handler needs stream access\n this.streamHandler.addToRolePolicy(\n new iam.PolicyStatement({\n actions: [\n 'dynamodb:GetRecords',\n 'dynamodb:GetShardIterator',\n 'dynamodb:DescribeStream',\n 'dynamodb:ListStreams',\n ],\n resources: [streamArn],\n }),\n );\n\n // Both handlers need read access to user tables (including PartiQL for queries)\n const tableReadPolicy = new iam.PolicyStatement({\n actions: [\n 'dynamodb:Query',\n 'dynamodb:Scan',\n 'dynamodb:GetItem',\n 'dynamodb:BatchGetItem',\n 'dynamodb:PartiQLSelect',\n ],\n resources: [tableArn, `${tableArn}/index/*`],\n });\n\n this.streamHandler.addToRolePolicy(tableReadPolicy);\n this.messageHandler.addToRolePolicy(tableReadPolicy);\n\n // Message handler also needs write access for mutations\n this.messageHandler.addToRolePolicy(\n new iam.PolicyStatement({\n actions: [\n 'dynamodb:PutItem',\n 'dynamodb:UpdateItem',\n 'dynamodb:DeleteItem',\n 'dynamodb:BatchWriteItem',\n 'dynamodb:PartiQLInsert',\n 'dynamodb:PartiQLUpdate',\n 'dynamodb:PartiQLDelete',\n ],\n resources: [tableArn, `${tableArn}/index/*`],\n }),\n );\n }\n\n public addTable(table: dynamodb.ITable): void {\n if (!table.tableStreamArn) {\n throw new Error(`Table ${table.tableName} does not have streams enabled`);\n }\n\n table.grantStreamRead(this.streamHandler);\n table.grantReadData(this.streamHandler);\n\n new lambda.EventSourceMapping(this, `Stream-${table.tableName}`, {\n target: this.streamHandler,\n eventSourceArn: table.tableStreamArn,\n startingPosition: lambda.StartingPosition.TRIM_HORIZON,\n batchSize: 100,\n maxBatchingWindow: cdk.Duration.seconds(5),\n });\n }\n}\n","import * as cdk from 'aws-cdk-lib';\nimport type * as dynamodb from 'aws-cdk-lib/aws-dynamodb';\nimport * as lambda from 'aws-cdk-lib/aws-lambda';\nimport { Construct } from 'constructs';\n\n/**\n * Props for DynamoDBStreamSource\n */\nexport interface DynamoDBStreamSourceProps {\n /**\n * The DynamoDB table to create a stream source for\n */\n table: dynamodb.ITable;\n\n /**\n * The Lambda function to receive stream events\n */\n target: lambda.IFunction;\n\n /**\n * Batch size for stream processing\n * @default 100\n */\n batchSize?: number;\n\n /**\n * Maximum batching window\n * @default Duration.seconds(5)\n */\n maxBatchingWindow?: cdk.Duration;\n\n /**\n * Starting position for reading the stream\n * @default TRIM_HORIZON\n */\n startingPosition?: lambda.StartingPosition;\n\n /**\n * Enable parallel processing with multiple batches\n * @default 1\n */\n parallelizationFactor?: number;\n\n /**\n * Maximum record age to process\n * @default Duration.days(1)\n */\n maxRecordAge?: cdk.Duration;\n\n /**\n * Number of retries on failure\n * @default 3\n */\n retryAttempts?: number;\n\n /**\n * Filter patterns for the event source\n */\n filters?: lambda.FilterCriteria[];\n}\n\n/**\n * Helper construct for setting up DynamoDB stream event sources\n */\nexport class DynamoDBStreamSource extends Construct {\n public readonly eventSourceMapping: lambda.EventSourceMapping;\n\n constructor(scope: Construct, id: string, props: DynamoDBStreamSourceProps) {\n super(scope, id);\n\n const {\n table,\n target,\n batchSize = 100,\n maxBatchingWindow = cdk.Duration.seconds(5),\n startingPosition = lambda.StartingPosition.TRIM_HORIZON,\n parallelizationFactor = 1,\n maxRecordAge = cdk.Duration.days(1),\n retryAttempts = 3,\n filters,\n } = props;\n\n if (!table.tableStreamArn) {\n throw new Error(\n `Table ${table.tableName} does not have DynamoDB Streams enabled. ` +\n 'Enable streams with streamSpecification when creating the table.',\n );\n }\n\n // Grant stream read permissions\n table.grantStreamRead(target);\n\n // Create the event source mapping\n this.eventSourceMapping = new lambda.EventSourceMapping(\n this,\n 'EventSource',\n {\n target,\n eventSourceArn: table.tableStreamArn,\n startingPosition,\n batchSize,\n maxBatchingWindow,\n parallelizationFactor,\n maxRecordAge,\n retryAttempts,\n bisectBatchOnError: true,\n reportBatchItemFailures: true,\n filters,\n },\n );\n }\n}\n\n/**\n * Create a filter criteria for DynamoDB streams\n */\nexport function createStreamFilter(options: {\n /**\n * Filter by event name (INSERT, MODIFY, REMOVE)\n */\n eventName?: ('INSERT' | 'MODIFY' | 'REMOVE')[];\n\n /**\n * Custom filter patterns\n */\n patterns?: Record<string, unknown>[];\n}): lambda.FilterCriteria[] {\n const filters: Record<string, unknown>[] = [];\n\n if (options.eventName) {\n filters.push({\n eventName: options.eventName,\n });\n }\n\n if (options.patterns) {\n filters.push(...options.patterns);\n }\n\n if (filters.length === 0) {\n return [];\n }\n\n return [lambda.FilterCriteria.filter({ filters })];\n}\n"]}
1
+ {"version":3,"sources":["../../infra/src/handlers/lambda-handlers.ts","../../infra/src/tables.ts","../../infra/src/engine.ts","../../infra/src/stream-source.ts"],"names":["cdk","Construct","cdk3","lambda2"],"mappings":"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","file":"infra.js","sourcesContent":["/**\n * Entry point code generator for the reactive Lambda handlers.\n *\n * No user code is imported - the handlers use only environment variables\n * and stored query metadata for all operations.\n */\n\n/**\n * Generate the entry point code for Lambda functions.\n * This is called by the CDK construct to create the bundled entry file.\n */\nexport function generateEntryPointCode(): string {\n return `// Auto-generated entry point for reactive Lambda handlers\n// No user code required - all configuration comes from environment variables\nimport { createLambdaHandlers } from 'dynamodb-reactive/server';\n\nconst handlers = createLambdaHandlers();\n\nexport const connectHandler = handlers.connectHandler;\nexport const disconnectHandler = handlers.disconnectHandler;\nexport const messageHandler = handlers.messageHandler;\nexport const streamHandler = handlers.streamHandler;\n`;\n}\n","import { SystemTableNames } from '@dynamodb-reactive/core';\nimport * as cdk from 'aws-cdk-lib';\nimport * as dynamodb from 'aws-cdk-lib/aws-dynamodb';\nimport { Construct } from 'constructs';\n\n/**\n * Provisioning mode for DynamoDB tables\n * - \"ON_DEMAND\": Pay-per-request billing (default)\n * - { readWrite: number }: Provisioned capacity with specified RCU/WCU\n */\nexport type ProvisioningMode = 'ON_DEMAND' | { readWrite: number };\n\n/**\n * Props for ReactiveSystemTables\n */\nexport interface ReactiveSystemTablesProps {\n /**\n * Prefix for table names\n * @default - no prefix\n */\n tablePrefix?: string;\n\n /**\n * Removal policy for tables\n * @default - cdk.RemovalPolicy.RETAIN\n */\n removalPolicy?: cdk.RemovalPolicy;\n\n /**\n * Enable point-in-time recovery\n * @default false\n */\n pointInTimeRecovery?: boolean;\n\n /**\n * Provisioning mode for tables\n * @default \"ON_DEMAND\"\n */\n provisioningMode?: ProvisioningMode;\n}\n\n/**\n * Creates the three system tables for the reactive engine\n */\nexport class ReactiveSystemTables extends Construct {\n /**\n * ReactiveConnections table - tracks WebSocket connections\n */\n public readonly connectionsTable: dynamodb.Table;\n\n /**\n * ReactiveDependencies table - the inverted index\n */\n public readonly dependenciesTable: dynamodb.Table;\n\n /**\n * ReactiveConnectionQueries table - stores subscription state\n */\n public readonly queriesTable: dynamodb.Table;\n\n constructor(\n scope: Construct,\n id: string,\n props: ReactiveSystemTablesProps = {},\n ) {\n super(scope, id);\n\n const prefix = props.tablePrefix ? `${props.tablePrefix}-` : '';\n const removalPolicy = props.removalPolicy ?? cdk.RemovalPolicy.RETAIN;\n const pointInTimeRecovery = props.pointInTimeRecovery ?? false;\n const provisioningMode = props.provisioningMode ?? 'ON_DEMAND';\n\n // Determine billing/capacity settings\n const isOnDemand = provisioningMode === 'ON_DEMAND';\n const capacityProps = isOnDemand\n ? { billingMode: dynamodb.BillingMode.PAY_PER_REQUEST }\n : {\n billingMode: dynamodb.BillingMode.PROVISIONED,\n readCapacity: provisioningMode.readWrite,\n writeCapacity: provisioningMode.readWrite,\n };\n\n // ReactiveConnections Table\n // Tracks active WebSocket connections and user context\n this.connectionsTable = new dynamodb.Table(this, 'ConnectionsTable', {\n tableName: `${prefix}${SystemTableNames.connections}`,\n partitionKey: {\n name: 'connectionId',\n type: dynamodb.AttributeType.STRING,\n },\n ...capacityProps,\n removalPolicy,\n pointInTimeRecovery,\n timeToLiveAttribute: 'ttl',\n });\n\n // ReactiveDependencies Table (The Inverted Index)\n // Maps Field#Value -> ConnectionID for O(1) lookups\n this.dependenciesTable = new dynamodb.Table(this, 'DependenciesTable', {\n tableName: `${prefix}${SystemTableNames.dependencies}`,\n partitionKey: {\n name: 'pk', // Format: \"TableName#FieldName#FieldValue\"\n type: dynamodb.AttributeType.STRING,\n },\n sortKey: {\n name: 'sk', // Format: \"ConnectionID#SubscriptionID\"\n type: dynamodb.AttributeType.STRING,\n },\n ...capacityProps,\n removalPolicy,\n pointInTimeRecovery,\n timeToLiveAttribute: 'ttl',\n });\n\n // Add GSI for querying by connectionId (for cleanup)\n // For provisioned mode, GSI needs its own capacity\n const gsiProps = isOnDemand\n ? {}\n : {\n readCapacity: provisioningMode.readWrite,\n writeCapacity: provisioningMode.readWrite,\n };\n\n this.dependenciesTable.addGlobalSecondaryIndex({\n indexName: 'byConnectionId',\n partitionKey: {\n name: 'connectionId',\n type: dynamodb.AttributeType.STRING,\n },\n projectionType: dynamodb.ProjectionType.KEYS_ONLY,\n ...gsiProps,\n });\n\n // ReactiveConnectionQueries Table\n // Stores subscription state for diffing\n this.queriesTable = new dynamodb.Table(this, 'QueriesTable', {\n tableName: `${prefix}${SystemTableNames.queries}`,\n partitionKey: {\n name: 'pk', // ConnectionID\n type: dynamodb.AttributeType.STRING,\n },\n sortKey: {\n name: 'sk', // SubscriptionID\n type: dynamodb.AttributeType.STRING,\n },\n ...capacityProps,\n removalPolicy,\n pointInTimeRecovery,\n timeToLiveAttribute: 'ttl',\n });\n }\n}\n","import * as fs from 'node:fs';\nimport * as path from 'node:path';\n\nimport type { AnyDynamoTable } from '@dynamodb-reactive/core';\nimport * as cdk from 'aws-cdk-lib';\nimport * as apigatewayv2 from 'aws-cdk-lib/aws-apigatewayv2';\nimport * as apigatewayv2Integrations from 'aws-cdk-lib/aws-apigatewayv2-integrations';\nimport type * as dynamodb from 'aws-cdk-lib/aws-dynamodb';\nimport * as iam from 'aws-cdk-lib/aws-iam';\nimport * as lambda from 'aws-cdk-lib/aws-lambda';\nimport * as nodejs from 'aws-cdk-lib/aws-lambda-nodejs';\nimport * as logs from 'aws-cdk-lib/aws-logs';\nimport { Construct } from 'constructs';\n\nimport { generateEntryPointCode } from './handlers/lambda-handlers.js';\nimport {\n ReactiveSystemTables,\n type ReactiveSystemTablesProps,\n} from './tables.js';\n\n/**\n * Props for ReactiveEngine construct\n */\nexport interface ReactiveEngineProps {\n /**\n * User-defined DynamoDB tables to enable reactive updates on\n */\n tables: AnyDynamoTable[];\n\n /**\n * Prefix for all resource names\n * @default - no prefix\n */\n resourcePrefix?: string;\n\n /**\n * System tables configuration\n */\n systemTablesProps?: ReactiveSystemTablesProps;\n\n /**\n * Lambda function memory size in MB\n * @default 256\n */\n memorySize?: number;\n\n /**\n * Lambda function timeout\n * @default Duration.seconds(30)\n */\n timeout?: cdk.Duration;\n\n /**\n * Log retention period\n * @default logs.RetentionDays.ONE_WEEK\n */\n logRetention?: logs.RetentionDays;\n\n /**\n * Environment variables for Lambda functions\n */\n environment?: Record<string, string>;\n\n /**\n * Enable tracing with X-Ray\n * @default false\n */\n tracing?: boolean;\n}\n\n/**\n * ReactiveEngine - Main CDK construct for the reactive DynamoDB system\n */\nexport class ReactiveEngine extends Construct {\n public readonly systemTables: ReactiveSystemTables;\n public readonly webSocketApi: apigatewayv2.WebSocketApi;\n public readonly webSocketStage: apigatewayv2.WebSocketStage;\n public readonly connectHandler: lambda.Function;\n public readonly disconnectHandler: lambda.Function;\n public readonly messageHandler: lambda.Function;\n public readonly streamHandler: lambda.Function;\n public readonly webSocketUrl: string;\n public readonly callbackUrl: string;\n\n constructor(scope: Construct, id: string, props: ReactiveEngineProps) {\n super(scope, id);\n\n const prefix = props.resourcePrefix ?? '';\n const memorySize = props.memorySize ?? 256;\n const timeout = props.timeout ?? cdk.Duration.seconds(30);\n const logRetention = props.logRetention ?? logs.RetentionDays.ONE_WEEK;\n\n // Create system tables\n this.systemTables = new ReactiveSystemTables(this, 'SystemTables', {\n tablePrefix: prefix,\n ...props.systemTablesProps,\n });\n\n // Create WebSocket API\n this.webSocketApi = new apigatewayv2.WebSocketApi(this, 'WebSocketApi', {\n apiName: `${prefix}ReactiveWebSocket`,\n });\n\n this.webSocketStage = new apigatewayv2.WebSocketStage(\n this,\n 'WebSocketStage',\n {\n webSocketApi: this.webSocketApi,\n stageName: 'prod',\n autoDeploy: true,\n },\n );\n\n this.webSocketUrl = this.webSocketStage.url;\n this.callbackUrl = this.webSocketStage.callbackUrl;\n\n // Generate the entry point file (no user code required)\n // Write to cdk.out directory to avoid path resolution issues with temp directories\n const entryPointCode = generateEntryPointCode();\n const cdkOutDir = path.join(process.cwd(), 'cdk.out', '.generated');\n fs.mkdirSync(cdkOutDir, { recursive: true });\n const entryPointPath = path.join(\n cdkOutDir,\n `reactive-entry-${id}-${Date.now()}.ts`,\n );\n fs.writeFileSync(entryPointPath, entryPointCode);\n\n // Common environment variables\n const environment: Record<string, string> = {\n CONNECTIONS_TABLE: this.systemTables.connectionsTable.tableName,\n DEPENDENCIES_TABLE: this.systemTables.dependenciesTable.tableName,\n QUERIES_TABLE: this.systemTables.queriesTable.tableName,\n WEBSOCKET_ENDPOINT: this.callbackUrl,\n ...props.environment,\n };\n\n // Create handlers using NodejsFunction with the generated entry point\n this.connectHandler = new nodejs.NodejsFunction(this, 'ConnectHandler', {\n functionName: `${prefix}ReactiveConnect`,\n runtime: lambda.Runtime.NODEJS_LATEST,\n handler: 'connectHandler',\n entry: entryPointPath,\n environment,\n memorySize,\n timeout,\n logRetention,\n tracing: props.tracing ? lambda.Tracing.ACTIVE : lambda.Tracing.DISABLED,\n });\n\n this.disconnectHandler = new nodejs.NodejsFunction(\n this,\n 'DisconnectHandler',\n {\n functionName: `${prefix}ReactiveDisconnect`,\n runtime: lambda.Runtime.NODEJS_LATEST,\n handler: 'disconnectHandler',\n entry: entryPointPath,\n environment,\n memorySize,\n timeout,\n logRetention,\n tracing: props.tracing\n ? lambda.Tracing.ACTIVE\n : lambda.Tracing.DISABLED,\n },\n );\n\n this.messageHandler = new nodejs.NodejsFunction(this, 'MessageHandler', {\n functionName: `${prefix}ReactiveMessage`,\n runtime: lambda.Runtime.NODEJS_LATEST,\n handler: 'messageHandler',\n entry: entryPointPath,\n environment,\n memorySize,\n timeout,\n logRetention,\n tracing: props.tracing ? lambda.Tracing.ACTIVE : lambda.Tracing.DISABLED,\n });\n\n this.streamHandler = new nodejs.NodejsFunction(this, 'StreamHandler', {\n functionName: `${prefix}ReactiveStream`,\n runtime: lambda.Runtime.NODEJS_LATEST,\n handler: 'streamHandler',\n entry: entryPointPath,\n environment: {\n ...environment,\n USER_TABLES: props.tables.map((t) => t.tableName).join(','),\n },\n memorySize,\n timeout,\n logRetention,\n tracing: props.tracing ? lambda.Tracing.ACTIVE : lambda.Tracing.DISABLED,\n });\n\n // Grant permissions for system tables\n this.systemTables.connectionsTable.grantReadWriteData(this.connectHandler);\n this.systemTables.connectionsTable.grantReadWriteData(\n this.disconnectHandler,\n );\n this.systemTables.connectionsTable.grantReadWriteData(this.messageHandler);\n this.systemTables.connectionsTable.grantReadWriteData(this.streamHandler);\n\n this.systemTables.dependenciesTable.grantReadWriteData(this.messageHandler);\n this.systemTables.dependenciesTable.grantReadWriteData(this.streamHandler);\n\n this.systemTables.queriesTable.grantReadWriteData(this.messageHandler);\n this.systemTables.queriesTable.grantReadWriteData(this.streamHandler);\n\n // Grant WebSocket management permissions\n const managementPolicy = new iam.PolicyStatement({\n actions: ['execute-api:ManageConnections'],\n resources: [\n `arn:aws:execute-api:${cdk.Stack.of(this).region}:${cdk.Stack.of(this).account}:${this.webSocketApi.apiId}/${this.webSocketStage.stageName}/POST/@connections/*`,\n ],\n });\n\n this.messageHandler.addToRolePolicy(managementPolicy);\n this.streamHandler.addToRolePolicy(managementPolicy);\n\n // Set up WebSocket routes\n this.webSocketApi.addRoute('$connect', {\n integration: new apigatewayv2Integrations.WebSocketLambdaIntegration(\n 'ConnectIntegration',\n this.connectHandler,\n ),\n });\n\n this.webSocketApi.addRoute('$disconnect', {\n integration: new apigatewayv2Integrations.WebSocketLambdaIntegration(\n 'DisconnectIntegration',\n this.disconnectHandler,\n ),\n });\n\n this.webSocketApi.addRoute('$default', {\n integration: new apigatewayv2Integrations.WebSocketLambdaIntegration(\n 'DefaultIntegration',\n this.messageHandler,\n ),\n });\n\n // Set up DynamoDB stream processing for user tables\n for (const table of props.tables) {\n this.setupStreamProcessing(table);\n }\n\n // Output the WebSocket URL\n new cdk.CfnOutput(this, 'WebSocketUrl', {\n value: this.webSocketUrl,\n description: 'WebSocket URL for reactive connections',\n });\n }\n\n private setupStreamProcessing(table: AnyDynamoTable): void {\n const tableArn = `arn:aws:dynamodb:${cdk.Stack.of(this).region}:${cdk.Stack.of(this).account}:table/${table.tableName}`;\n const streamArn = `${tableArn}/stream/*`;\n\n // Stream handler needs stream access\n this.streamHandler.addToRolePolicy(\n new iam.PolicyStatement({\n actions: [\n 'dynamodb:GetRecords',\n 'dynamodb:GetShardIterator',\n 'dynamodb:DescribeStream',\n 'dynamodb:ListStreams',\n ],\n resources: [streamArn],\n }),\n );\n\n // Both handlers need read access to user tables (including PartiQL for queries)\n const tableReadPolicy = new iam.PolicyStatement({\n actions: [\n 'dynamodb:Query',\n 'dynamodb:Scan',\n 'dynamodb:GetItem',\n 'dynamodb:BatchGetItem',\n 'dynamodb:PartiQLSelect',\n ],\n resources: [tableArn, `${tableArn}/index/*`],\n });\n\n this.streamHandler.addToRolePolicy(tableReadPolicy);\n this.messageHandler.addToRolePolicy(tableReadPolicy);\n\n // Message handler also needs write access for mutations\n this.messageHandler.addToRolePolicy(\n new iam.PolicyStatement({\n actions: [\n 'dynamodb:PutItem',\n 'dynamodb:UpdateItem',\n 'dynamodb:DeleteItem',\n 'dynamodb:BatchWriteItem',\n 'dynamodb:PartiQLInsert',\n 'dynamodb:PartiQLUpdate',\n 'dynamodb:PartiQLDelete',\n ],\n resources: [tableArn, `${tableArn}/index/*`],\n }),\n );\n }\n\n public addTable(table: dynamodb.ITable): void {\n if (!table.tableStreamArn) {\n throw new Error(`Table ${table.tableName} does not have streams enabled`);\n }\n\n table.grantStreamRead(this.streamHandler);\n table.grantReadData(this.streamHandler);\n\n new lambda.EventSourceMapping(this, `Stream-${table.tableName}`, {\n target: this.streamHandler,\n eventSourceArn: table.tableStreamArn,\n startingPosition: lambda.StartingPosition.TRIM_HORIZON,\n batchSize: 100,\n maxBatchingWindow: cdk.Duration.seconds(5),\n });\n }\n}\n","import * as cdk from 'aws-cdk-lib';\nimport type * as dynamodb from 'aws-cdk-lib/aws-dynamodb';\nimport * as lambda from 'aws-cdk-lib/aws-lambda';\nimport { Construct } from 'constructs';\n\n/**\n * Props for DynamoDBStreamSource\n */\nexport interface DynamoDBStreamSourceProps {\n /**\n * The DynamoDB table to create a stream source for\n */\n table: dynamodb.ITable;\n\n /**\n * The Lambda function to receive stream events\n */\n target: lambda.IFunction;\n\n /**\n * Batch size for stream processing\n * @default 100\n */\n batchSize?: number;\n\n /**\n * Maximum batching window\n * @default Duration.seconds(5)\n */\n maxBatchingWindow?: cdk.Duration;\n\n /**\n * Starting position for reading the stream\n * @default TRIM_HORIZON\n */\n startingPosition?: lambda.StartingPosition;\n\n /**\n * Enable parallel processing with multiple batches\n * @default 1\n */\n parallelizationFactor?: number;\n\n /**\n * Maximum record age to process\n * @default Duration.days(1)\n */\n maxRecordAge?: cdk.Duration;\n\n /**\n * Number of retries on failure\n * @default 3\n */\n retryAttempts?: number;\n\n /**\n * Filter patterns for the event source\n */\n filters?: lambda.FilterCriteria[];\n}\n\n/**\n * Helper construct for setting up DynamoDB stream event sources\n */\nexport class DynamoDBStreamSource extends Construct {\n public readonly eventSourceMapping: lambda.EventSourceMapping;\n\n constructor(scope: Construct, id: string, props: DynamoDBStreamSourceProps) {\n super(scope, id);\n\n const {\n table,\n target,\n batchSize = 100,\n maxBatchingWindow = cdk.Duration.seconds(5),\n startingPosition = lambda.StartingPosition.TRIM_HORIZON,\n parallelizationFactor = 1,\n maxRecordAge = cdk.Duration.days(1),\n retryAttempts = 3,\n filters,\n } = props;\n\n if (!table.tableStreamArn) {\n throw new Error(\n `Table ${table.tableName} does not have DynamoDB Streams enabled. ` +\n 'Enable streams with streamSpecification when creating the table.',\n );\n }\n\n // Grant stream read permissions\n table.grantStreamRead(target);\n\n // Create the event source mapping\n this.eventSourceMapping = new lambda.EventSourceMapping(\n this,\n 'EventSource',\n {\n target,\n eventSourceArn: table.tableStreamArn,\n startingPosition,\n batchSize,\n maxBatchingWindow,\n parallelizationFactor,\n maxRecordAge,\n retryAttempts,\n bisectBatchOnError: true,\n reportBatchItemFailures: true,\n filters,\n },\n );\n }\n}\n\n/**\n * Create a filter criteria for DynamoDB streams\n */\nexport function createStreamFilter(options: {\n /**\n * Filter by event name (INSERT, MODIFY, REMOVE)\n */\n eventName?: ('INSERT' | 'MODIFY' | 'REMOVE')[];\n\n /**\n * Custom filter patterns\n */\n patterns?: Record<string, unknown>[];\n}): lambda.FilterCriteria[] {\n const filters: Record<string, unknown>[] = [];\n\n if (options.eventName) {\n filters.push({\n eventName: options.eventName,\n });\n }\n\n if (options.patterns) {\n filters.push(...options.patterns);\n }\n\n if (filters.length === 0) {\n return [];\n }\n\n return [lambda.FilterCriteria.filter({ filters })];\n}\n"]}
package/dist/server.d.ts CHANGED
@@ -1,6 +1,6 @@
1
1
  import { z } from 'zod';
2
- import { D as DynamoTable } from './table-CfIWxbuJ.js';
3
- import { A as AnyDynamoTable, F as FieldRef, a as FilterCondition, Q as QueryMetadata, J as JsonPatch } from './types-DeshTSf5.js';
2
+ import { D as DynamoTable } from './table-DjeyVXYp.js';
3
+ import { A as AnyDynamoTable, F as FieldRef, a as FilterCondition, Q as QueryMetadata, J as JsonPatch } from './types-2EfCnE0c.js';
4
4
  import { DynamoDBClient } from '@aws-sdk/client-dynamodb';
5
5
  import { DynamoDBStreamEvent, APIGatewayProxyEvent, APIGatewayProxyResult } from 'aws-lambda';
6
6
 
package/dist/server.js CHANGED
@@ -1,4 +1,4 @@
1
- import { SystemTableNames } from './chunk-HZ6JHAJJ.js';
1
+ import { SystemTableNames } from './chunk-L4NOAOXX.js';
2
2
  import { DynamoDBClient, ExecuteStatementCommand } from '@aws-sdk/client-dynamodb';
3
3
  import { UpdateCommand, DeleteCommand, PutCommand, GetCommand, DynamoDBDocumentClient, QueryCommand } from '@aws-sdk/lib-dynamodb';
4
4
  import { unmarshall } from '@aws-sdk/util-dynamodb';
@@ -1,33 +1,45 @@
1
1
  import { z } from 'zod';
2
- import { I as IndexDefinition, F as FieldRef, D as DynamoTableConfig } from './types-DeshTSf5.js';
2
+ import { S as SupportedSchema, I as IndexDefinition, F as FieldRef, D as DynamoTableConfig } from './types-2EfCnE0c.js';
3
3
 
4
4
  /**
5
5
  * Creates field references for type-safe query building
6
6
  */
7
- type FieldRefs<TSchema extends z.ZodObject<z.ZodRawShape>> = {
7
+ type FieldRefs<TSchema extends SupportedSchema> = {
8
8
  [K in keyof z.infer<TSchema>]: FieldRef<K & string, z.infer<TSchema>[K]>;
9
9
  };
10
10
  /**
11
11
  * DynamoTable - Defines a DynamoDB table with type-safe schema
12
12
  *
13
+ * Supports both ZodObject and ZodDiscriminatedUnion schemas for single-table design patterns.
14
+ *
13
15
  * @example
14
16
  * ```ts
17
+ * // Simple schema
15
18
  * const TodoTable = new DynamoTable({
16
19
  * tableName: 'prod-todo-table',
17
20
  * schema: z.object({
18
- * id: z.string(),
19
- * taskListId: z.string(),
21
+ * PK: z.string(),
22
+ * SK: z.string(),
20
23
  * text: z.string(),
21
24
  * isDone: z.boolean(),
22
25
  * }),
23
- * pk: 'id',
24
- * indexes: {
25
- * byTaskId: { name: 'gsi_by_task_id', pk: 'taskListId' }
26
- * }
26
+ * pk: 'PK',
27
+ * sk: 'SK',
28
+ * });
29
+ *
30
+ * // Discriminated union for single-table design
31
+ * const MultiEntityTable = new DynamoTable({
32
+ * tableName: 'prod-entities',
33
+ * schema: z.discriminatedUnion('entityType', [
34
+ * z.object({ PK: z.string(), SK: z.string(), entityType: z.literal('USER'), name: z.string() }),
35
+ * z.object({ PK: z.string(), SK: z.string(), entityType: z.literal('ITEM'), title: z.string() }),
36
+ * ]),
37
+ * pk: 'PK',
38
+ * sk: 'SK',
27
39
  * });
28
40
  * ```
29
41
  */
30
- declare class DynamoTable<TSchema extends z.ZodObject<z.ZodRawShape>, TPk extends keyof z.infer<TSchema>, TSk extends keyof z.infer<TSchema> | undefined = undefined, TIndexes extends Record<string, IndexDefinition> = Record<string, IndexDefinition>> {
42
+ declare class DynamoTable<TSchema extends SupportedSchema, TPk extends keyof z.infer<TSchema>, TSk extends keyof z.infer<TSchema> | undefined = undefined, TIndexes extends Record<string, IndexDefinition> = Record<string, IndexDefinition>> {
31
43
  readonly tableName: string;
32
44
  readonly schema: TSchema;
33
45
  readonly pk: TPk;
@@ -8,6 +8,15 @@ interface IndexDefinition {
8
8
  pk: string;
9
9
  sk?: string;
10
10
  }
11
+ /**
12
+ * Supported schema types for DynamoTable
13
+ * Accepts both ZodObject and ZodDiscriminatedUnion
14
+ */
15
+ type SupportedSchema = z.ZodObject<z.ZodRawShape> | z.ZodDiscriminatedUnion<string, z.ZodDiscriminatedUnionOption<string>[]>;
16
+ /**
17
+ * Extract the inferred type from a supported schema
18
+ */
19
+ type InferSupportedSchema<T extends SupportedSchema> = z.infer<T>;
11
20
  /**
12
21
  * Base interface for any DynamoTable - used for generic constraints
13
22
  * Defines the minimal shape that all DynamoTable instances satisfy
@@ -31,8 +40,9 @@ interface AnyDynamoTable {
31
40
  }
32
41
  /**
33
42
  * Configuration for DynamoTable
43
+ * Supports both ZodObject and ZodDiscriminatedUnion schemas
34
44
  */
35
- interface DynamoTableConfig<TSchema extends z.ZodObject<z.ZodRawShape>, TPk extends keyof z.infer<TSchema>, TSk extends keyof z.infer<TSchema> | undefined = undefined, TIndexes extends Record<string, IndexDefinition> = Record<string, IndexDefinition>> {
45
+ interface DynamoTableConfig<TSchema extends SupportedSchema, TPk extends keyof z.infer<TSchema>, TSk extends keyof z.infer<TSchema> | undefined = undefined, TIndexes extends Record<string, IndexDefinition> = Record<string, IndexDefinition>> {
36
46
  tableName: string;
37
47
  schema: TSchema;
38
48
  pk: TPk;
@@ -138,4 +148,4 @@ interface QueryEntry {
138
148
  ttl: number;
139
149
  }
140
150
 
141
- export type { AnyDynamoTable as A, ConnectionEntry as C, DynamoTableConfig as D, FieldRef as F, IndexDefinition as I, JsonPatch as J, QueryMetadata as Q, SubscriptionMessage as S, FilterCondition as a, DependencyEntry as b, QueryEntry as c };
151
+ export type { AnyDynamoTable as A, ConnectionEntry as C, DynamoTableConfig as D, FieldRef as F, IndexDefinition as I, JsonPatch as J, QueryMetadata as Q, SupportedSchema as S, FilterCondition as a, DependencyEntry as b, InferSupportedSchema as c, QueryEntry as d, SubscriptionMessage as e };
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "dynamodb-reactive",
3
- "version": "0.1.5",
3
+ "version": "0.1.7",
4
4
  "type": "module",
5
5
  "description": "A Serverless, Reactive tRPC replacement for AWS DynamoDB",
6
6
  "keywords": [
@@ -1 +0,0 @@
1
- {"version":3,"sources":["../../core/src/table.ts","../../core/src/schema.ts"],"names":[],"mappings":"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","file":"chunk-HZ6JHAJJ.js","sourcesContent":["import type { z } from 'zod';\n\nimport type { DynamoTableConfig, FieldRef, IndexDefinition } from './types.js';\n\n/**\n * Creates field references for type-safe query building\n */\ntype FieldRefs<TSchema extends z.ZodObject<z.ZodRawShape>> = {\n [K in keyof z.infer<TSchema>]: FieldRef<K & string, z.infer<TSchema>[K]>;\n};\n\n/**\n * DynamoTable - Defines a DynamoDB table with type-safe schema\n *\n * @example\n * ```ts\n * const TodoTable = new DynamoTable({\n * tableName: 'prod-todo-table',\n * schema: z.object({\n * id: z.string(),\n * taskListId: z.string(),\n * text: z.string(),\n * isDone: z.boolean(),\n * }),\n * pk: 'id',\n * indexes: {\n * byTaskId: { name: 'gsi_by_task_id', pk: 'taskListId' }\n * }\n * });\n * ```\n */\nexport class DynamoTable<\n TSchema extends z.ZodObject<z.ZodRawShape>,\n TPk extends keyof z.infer<TSchema>,\n TSk extends keyof z.infer<TSchema> | undefined = undefined,\n TIndexes extends Record<string, IndexDefinition> = Record<\n string,\n IndexDefinition\n >,\n> {\n public readonly tableName: string;\n public readonly schema: TSchema;\n public readonly pk: TPk;\n public readonly sk: TSk;\n public readonly indexes: TIndexes;\n public readonly field: FieldRefs<TSchema>;\n\n constructor(config: DynamoTableConfig<TSchema, TPk, TSk, TIndexes>) {\n this.tableName = config.tableName;\n this.schema = config.schema;\n this.pk = config.pk;\n this.sk = config.sk as TSk;\n this.indexes = (config.indexes ?? {}) as TIndexes;\n\n // Create field references for query building\n this.field = this.createFieldRefs();\n }\n\n private createFieldRefs(): FieldRefs<TSchema> {\n const shape = this.schema.shape;\n const refs: Record<string, FieldRef<string, unknown>> = {};\n\n for (const key of Object.keys(shape)) {\n refs[key] = {\n fieldName: key,\n _type: undefined as unknown,\n };\n }\n\n return refs as FieldRefs<TSchema>;\n }\n\n /**\n * Validate an item against the schema\n */\n validate(item: unknown): z.infer<TSchema> {\n return this.schema.parse(item);\n }\n\n /**\n * Safely validate an item, returning a result object\n */\n safeParse(item: unknown): z.SafeParseReturnType<unknown, z.infer<TSchema>> {\n return this.schema.safeParse(item);\n }\n\n /**\n * Get the partition key value from an item\n */\n getPk(item: z.infer<TSchema>): z.infer<TSchema>[TPk] {\n return item[this.pk];\n }\n\n /**\n * Get the sort key value from an item (if defined)\n */\n getSk(\n item: z.infer<TSchema>,\n ): TSk extends keyof z.infer<TSchema> ? z.infer<TSchema>[TSk] : undefined {\n if (this.sk === undefined) {\n return undefined as TSk extends keyof z.infer<TSchema>\n ? z.infer<TSchema>[TSk]\n : undefined;\n }\n return item[\n this.sk as keyof z.infer<TSchema>\n ] as TSk extends keyof z.infer<TSchema> ? z.infer<TSchema>[TSk] : undefined;\n }\n\n /**\n * Get the list of field names in the schema\n */\n getFieldNames(): (keyof z.infer<TSchema>)[] {\n return Object.keys(this.schema.shape) as (keyof z.infer<TSchema>)[];\n }\n\n /**\n * Check if a field exists in the schema\n */\n hasField(fieldName: string): fieldName is keyof z.infer<TSchema> & string {\n return fieldName in this.schema.shape;\n }\n}\n\n/**\n * Helper type to extract the shape from a Zod schema\n */\nexport type InferSchema<T> =\n T extends DynamoTable<infer TSchema, any, any, any>\n ? z.infer<TSchema>\n : never;\n\n/**\n * Helper type to extract field names from a table\n */\nexport type TableFields<T> =\n T extends DynamoTable<infer TSchema, any, any, any>\n ? keyof z.infer<TSchema>\n : never;\n\n/**\n * Helper type to get the pk field name\n */\nexport type TablePk<T> =\n T extends DynamoTable<any, infer TPk, any, any> ? TPk : never;\n\n/**\n * Helper type to get the sk field name\n */\nexport type TableSk<T> =\n T extends DynamoTable<any, any, infer TSk, any> ? TSk : never;\n\n/**\n * Helper type to get indexes\n */\nexport type TableIndexes<T> =\n T extends DynamoTable<any, any, any, infer TIndexes> ? TIndexes : never;\n","import { z } from 'zod';\n\nimport { DynamoTable } from './table.js';\nimport type { IndexDefinition } from './types.js';\n\n/**\n * Helper function to define a schema with type inference\n * This provides a cleaner API for defining tables\n *\n * @example\n * ```ts\n * const TodoTable = defineSchema({\n * tableName: 'prod-todo-table',\n * schema: z.object({\n * id: z.string(),\n * taskListId: z.string(),\n * text: z.string(),\n * isDone: z.boolean(),\n * }),\n * pk: 'id',\n * indexes: {\n * byTaskId: { name: 'gsi_by_task_id', pk: 'taskListId' }\n * }\n * });\n * ```\n */\nexport function defineSchema<\n TSchema extends z.ZodObject<z.ZodRawShape>,\n TPk extends keyof z.infer<TSchema> & string,\n TSk extends (keyof z.infer<TSchema> & string) | undefined = undefined,\n TIndexes extends Record<string, IndexDefinition> = Record<\n string,\n IndexDefinition\n >,\n>(config: {\n tableName: string;\n schema: TSchema;\n pk: TPk;\n sk?: TSk;\n indexes?: TIndexes;\n}): DynamoTable<TSchema, TPk, TSk, TIndexes> {\n return new DynamoTable(config);\n}\n\n/**\n * System table schemas for the reactive engine\n */\nexport const SystemSchemas = {\n /**\n * ReactiveConnections - Tracks active WebSocket connections\n */\n connections: z.object({\n connectionId: z.string(),\n context: z.record(z.unknown()).optional(),\n connectedAt: z.number(),\n ttl: z.number(),\n }),\n\n /**\n * ReactiveDependencies - The inverted index for O(1) lookups\n */\n dependencies: z.object({\n pk: z.string(), // Format: \"TableName#FieldName#FieldValue\"\n sk: z.string(), // ConnectionID#SubscriptionID\n connectionId: z.string(),\n subscriptionId: z.string(),\n tableName: z.string(),\n fieldName: z.string(),\n fieldValue: z.string(),\n ttl: z.number(),\n }),\n\n /**\n * ReactiveConnectionQueries - Stores subscription state for diffing\n */\n queries: z.object({\n pk: z.string(), // ConnectionID\n sk: z.string(), // SubscriptionID\n connectionId: z.string(),\n subscriptionId: z.string(),\n queryMetadata: z.object({\n tableName: z.string(),\n indexName: z.string().optional(),\n filterConditions: z.array(z.unknown()),\n sortField: z.string().optional(),\n sortOrder: z.enum(['asc', 'desc']).optional(),\n limit: z.number().optional(),\n }),\n lastResult: z.array(z.unknown()),\n dependencies: z.array(z.string()),\n createdAt: z.number(),\n updatedAt: z.number(),\n ttl: z.number(),\n }),\n};\n\n/**\n * System table names\n */\nexport const SystemTableNames = {\n connections: 'ReactiveConnections',\n dependencies: 'ReactiveDependencies',\n queries: 'ReactiveConnectionQueries',\n} as const;\n"]}