dynamodb-reactive 0.1.0 → 0.1.1
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dist/chunk-HZ6JHAJJ.js +131 -0
- package/dist/chunk-HZ6JHAJJ.js.map +1 -0
- package/dist/chunk-KRZQWA2W.js +657 -0
- package/dist/chunk-KRZQWA2W.js.map +1 -0
- package/dist/client.d.ts +55 -2
- package/dist/client.js +2 -17
- package/dist/client.js.map +1 -1
- package/dist/core.d.ts +4 -2
- package/dist/core.js +2 -17
- package/dist/core.js.map +1 -1
- package/dist/index.d.ts +171 -2
- package/dist/index.js +2 -17
- package/dist/index.js.map +1 -1
- package/dist/infra.d.ts +189 -2
- package/dist/infra.js +358 -15
- package/dist/infra.js.map +1 -1
- package/dist/react-BMZQ8Mth.d.ts +371 -0
- package/dist/react.d.ts +3 -2
- package/dist/react.js +2 -17
- package/dist/react.js.map +1 -1
- package/dist/server.d.ts +631 -2
- package/dist/server.js +1687 -16
- package/dist/server.js.map +1 -1
- package/dist/table-CSJysZPQ.d.ts +85 -0
- package/dist/types-Ci7IieDA.d.ts +141 -0
- package/package.json +10 -6
- package/dist/client.d.ts.map +0 -1
- package/dist/core.d.ts.map +0 -1
- package/dist/index.d.ts.map +0 -1
- package/dist/infra.d.ts.map +0 -1
- package/dist/react.d.ts.map +0 -1
- package/dist/server.d.ts.map +0 -1
package/dist/server.d.ts
CHANGED
|
@@ -1,2 +1,631 @@
|
|
|
1
|
-
|
|
2
|
-
|
|
1
|
+
import { z } from 'zod';
|
|
2
|
+
import { D as DynamoTable } from './table-CSJysZPQ.js';
|
|
3
|
+
import { A as AnyDynamoTable, F as FieldRef, a as FilterCondition, Q as QueryMetadata, J as JsonPatch } from './types-Ci7IieDA.js';
|
|
4
|
+
import { DynamoDBClient } from '@aws-sdk/client-dynamodb';
|
|
5
|
+
import { DynamoDBStreamEvent, APIGatewayProxyEvent, APIGatewayProxyResult } from 'aws-lambda';
|
|
6
|
+
|
|
7
|
+
/**
|
|
8
|
+
* Context type for procedures
|
|
9
|
+
*/
|
|
10
|
+
interface ProcedureContext<TContext = unknown> {
|
|
11
|
+
ctx: TContext & {
|
|
12
|
+
db: DatabaseContext;
|
|
13
|
+
};
|
|
14
|
+
input: unknown;
|
|
15
|
+
}
|
|
16
|
+
/**
|
|
17
|
+
* Database context provided to procedures
|
|
18
|
+
*/
|
|
19
|
+
interface DatabaseContext {
|
|
20
|
+
query<TTable extends AnyDynamoTable>(table: TTable): QueryBuilder<TTable>;
|
|
21
|
+
get<TTable extends AnyDynamoTable>(table: TTable, key: TableKeyInput<TTable>): Promise<TableItem<TTable> | null>;
|
|
22
|
+
put<TTable extends AnyDynamoTable>(table: TTable, item: TableItem<TTable>): Promise<void>;
|
|
23
|
+
delete<TTable extends AnyDynamoTable>(table: TTable, key: TableKeyInput<TTable>): Promise<void>;
|
|
24
|
+
update<TTable extends AnyDynamoTable>(table: TTable, key: TableKeyInput<TTable>, updates: Partial<TableItem<TTable>>): Promise<TableItem<TTable>>;
|
|
25
|
+
}
|
|
26
|
+
/**
|
|
27
|
+
* Extract the item type from a DynamoTable
|
|
28
|
+
* Works with both the DynamoTable class and AnyDynamoTable interface
|
|
29
|
+
*/
|
|
30
|
+
type TableItem<T extends AnyDynamoTable> = T extends DynamoTable<infer TSchema, any, any, any> ? z.infer<TSchema> : T extends {
|
|
31
|
+
schema: infer TSchema extends z.ZodTypeAny;
|
|
32
|
+
} ? z.infer<TSchema> : never;
|
|
33
|
+
/**
|
|
34
|
+
* Extract key input type from a DynamoTable
|
|
35
|
+
* Works with both the DynamoTable class and AnyDynamoTable interface
|
|
36
|
+
*/
|
|
37
|
+
type TableKeyInput<T extends AnyDynamoTable> = T extends DynamoTable<infer TSchema, infer TPk, infer TSk, any> ? TSk extends keyof z.infer<TSchema> ? Pick<z.infer<TSchema>, TPk | TSk> : Pick<z.infer<TSchema>, TPk> : T extends {
|
|
38
|
+
schema: infer TSchema extends z.ZodTypeAny;
|
|
39
|
+
pk: infer TPk;
|
|
40
|
+
sk: infer TSk;
|
|
41
|
+
} ? TSk extends keyof z.infer<TSchema> ? Pick<z.infer<TSchema>, (TPk & keyof z.infer<TSchema>) | TSk> : Pick<z.infer<TSchema>, TPk & keyof z.infer<TSchema>> : never;
|
|
42
|
+
/**
|
|
43
|
+
* Query builder for type-safe DynamoDB queries
|
|
44
|
+
*/
|
|
45
|
+
interface QueryBuilder<TTable extends AnyDynamoTable> {
|
|
46
|
+
filter(fn: (q: FilterBuilder<TTable>) => FilterCondition): QueryBuilder<TTable>;
|
|
47
|
+
useIndex(indexName: keyof TableIndexes<TTable>): QueryBuilder<TTable>;
|
|
48
|
+
take(limit: number): QueryBuilder<TTable>;
|
|
49
|
+
startFrom(key: TableKeyInput<TTable>): QueryBuilder<TTable>;
|
|
50
|
+
sortAscending(): QueryBuilder<TTable>;
|
|
51
|
+
sortDescending(): QueryBuilder<TTable>;
|
|
52
|
+
execute(): Promise<TableItem<TTable>[]>;
|
|
53
|
+
}
|
|
54
|
+
/**
|
|
55
|
+
* Filter builder for query conditions
|
|
56
|
+
*/
|
|
57
|
+
interface FilterBuilder<TTable extends AnyDynamoTable> {
|
|
58
|
+
eq<K extends keyof TableItem<TTable>>(field: FieldRef<K & string, TableItem<TTable>[K]>, value: TableItem<TTable>[K]): FilterCondition;
|
|
59
|
+
ne<K extends keyof TableItem<TTable>>(field: FieldRef<K & string, TableItem<TTable>[K]>, value: TableItem<TTable>[K]): FilterCondition;
|
|
60
|
+
gt<K extends keyof TableItem<TTable>>(field: FieldRef<K & string, TableItem<TTable>[K]>, value: TableItem<TTable>[K]): FilterCondition;
|
|
61
|
+
gte<K extends keyof TableItem<TTable>>(field: FieldRef<K & string, TableItem<TTable>[K]>, value: TableItem<TTable>[K]): FilterCondition;
|
|
62
|
+
lt<K extends keyof TableItem<TTable>>(field: FieldRef<K & string, TableItem<TTable>[K]>, value: TableItem<TTable>[K]): FilterCondition;
|
|
63
|
+
lte<K extends keyof TableItem<TTable>>(field: FieldRef<K & string, TableItem<TTable>[K]>, value: TableItem<TTable>[K]): FilterCondition;
|
|
64
|
+
between<K extends keyof TableItem<TTable>>(field: FieldRef<K & string, TableItem<TTable>[K]>, lower: TableItem<TTable>[K], upper: TableItem<TTable>[K]): FilterCondition;
|
|
65
|
+
beginsWith<K extends keyof TableItem<TTable>>(field: FieldRef<K & string, string>, prefix: string): FilterCondition;
|
|
66
|
+
contains<K extends keyof TableItem<TTable>>(field: FieldRef<K & string, string>, substring: string): FilterCondition;
|
|
67
|
+
and(...conditions: FilterCondition[]): FilterCondition;
|
|
68
|
+
or(...conditions: FilterCondition[]): FilterCondition;
|
|
69
|
+
not(condition: FilterCondition): FilterCondition;
|
|
70
|
+
}
|
|
71
|
+
/**
|
|
72
|
+
* Extract indexes from a DynamoTable
|
|
73
|
+
*/
|
|
74
|
+
type TableIndexes<T extends AnyDynamoTable> = T extends DynamoTable<any, any, any, infer TIndexes> ? TIndexes : T extends {
|
|
75
|
+
indexes: infer TIndexes;
|
|
76
|
+
} ? TIndexes : never;
|
|
77
|
+
/**
|
|
78
|
+
* Procedure types
|
|
79
|
+
*/
|
|
80
|
+
type ProcedureType = 'query' | 'mutation';
|
|
81
|
+
/**
|
|
82
|
+
* Procedure definition
|
|
83
|
+
*/
|
|
84
|
+
interface ProcedureDefinition<TContext, TInput extends z.ZodTypeAny = z.ZodUndefined, TOutput = unknown> {
|
|
85
|
+
type: ProcedureType;
|
|
86
|
+
inputSchema?: TInput;
|
|
87
|
+
resolver: (opts: {
|
|
88
|
+
ctx: TContext & {
|
|
89
|
+
db: DatabaseContext;
|
|
90
|
+
};
|
|
91
|
+
input: z.infer<TInput>;
|
|
92
|
+
}) => Promise<TOutput> | TOutput;
|
|
93
|
+
}
|
|
94
|
+
/**
|
|
95
|
+
* Any procedure definition - used for generic constraints
|
|
96
|
+
* Uses 'any' for input/output to allow covariant assignment
|
|
97
|
+
*/
|
|
98
|
+
type AnyProcedureDefinition<TContext> = ProcedureDefinition<TContext, any, any>;
|
|
99
|
+
/**
|
|
100
|
+
* Router definition
|
|
101
|
+
*/
|
|
102
|
+
type RouterDefinition<TContext> = {
|
|
103
|
+
[key: string]: AnyProcedureDefinition<TContext> | RouterDefinition<TContext>;
|
|
104
|
+
};
|
|
105
|
+
/**
|
|
106
|
+
* Dependency information extracted from a query
|
|
107
|
+
*/
|
|
108
|
+
interface QueryDependency {
|
|
109
|
+
tableName: string;
|
|
110
|
+
fieldName: string;
|
|
111
|
+
fieldValue: string;
|
|
112
|
+
indexName?: string;
|
|
113
|
+
}
|
|
114
|
+
/**
|
|
115
|
+
* Tracked query operation (for dependency extraction and stream processing)
|
|
116
|
+
*/
|
|
117
|
+
interface TrackedQueryOperation {
|
|
118
|
+
tableName: string;
|
|
119
|
+
filters: FilterCondition[];
|
|
120
|
+
indexName?: string;
|
|
121
|
+
/** Primary key field name for the table */
|
|
122
|
+
pkField: string;
|
|
123
|
+
/** Sort key field name for the table (if any) */
|
|
124
|
+
skField?: string;
|
|
125
|
+
/** Sort field for ordering results */
|
|
126
|
+
sortField?: string;
|
|
127
|
+
/** Sort direction */
|
|
128
|
+
sortOrder?: 'asc' | 'desc';
|
|
129
|
+
/** Maximum number of results */
|
|
130
|
+
limit?: number;
|
|
131
|
+
}
|
|
132
|
+
|
|
133
|
+
/**
|
|
134
|
+
* Procedure builder for creating type-safe procedures
|
|
135
|
+
*/
|
|
136
|
+
declare class ProcedureBuilder<TContext, TInput extends z.ZodType = z.ZodUndefined> {
|
|
137
|
+
private inputSchema?;
|
|
138
|
+
constructor(inputSchema?: TInput);
|
|
139
|
+
/**
|
|
140
|
+
* Define the input schema for the procedure
|
|
141
|
+
*/
|
|
142
|
+
input<TNewInput extends z.ZodType>(schema: TNewInput): ProcedureBuilder<TContext, TNewInput>;
|
|
143
|
+
/**
|
|
144
|
+
* Define a query procedure (read-only operation)
|
|
145
|
+
*/
|
|
146
|
+
query<TOutput>(resolver: (opts: {
|
|
147
|
+
ctx: TContext & {
|
|
148
|
+
db: DatabaseContext;
|
|
149
|
+
};
|
|
150
|
+
input: z.infer<TInput>;
|
|
151
|
+
}) => Promise<TOutput> | TOutput): ProcedureDefinition<TContext, TInput, TOutput>;
|
|
152
|
+
/**
|
|
153
|
+
* Define a mutation procedure (write operation)
|
|
154
|
+
*/
|
|
155
|
+
mutation<TOutput>(resolver: (opts: {
|
|
156
|
+
ctx: TContext & {
|
|
157
|
+
db: DatabaseContext;
|
|
158
|
+
};
|
|
159
|
+
input: z.infer<TInput>;
|
|
160
|
+
}) => Promise<TOutput> | TOutput): ProcedureDefinition<TContext, TInput, TOutput>;
|
|
161
|
+
}
|
|
162
|
+
/**
|
|
163
|
+
* Check if a value is a procedure definition
|
|
164
|
+
*/
|
|
165
|
+
declare function isProcedure(value: unknown): value is ProcedureDefinition<any, any, any>;
|
|
166
|
+
/**
|
|
167
|
+
* Execute a procedure with the given context and input
|
|
168
|
+
*/
|
|
169
|
+
declare function executeProcedure<TContext, TInput extends z.ZodType, TOutput>(procedure: ProcedureDefinition<TContext, TInput, TOutput>, ctx: TContext & {
|
|
170
|
+
db: DatabaseContext;
|
|
171
|
+
}, rawInput: unknown): Promise<TOutput>;
|
|
172
|
+
|
|
173
|
+
/**
|
|
174
|
+
* Router class for organizing procedures
|
|
175
|
+
*/
|
|
176
|
+
declare class Router<TContext, TRouter extends RouterDefinition<TContext>> {
|
|
177
|
+
readonly definition: TRouter;
|
|
178
|
+
constructor(definition: TRouter);
|
|
179
|
+
/**
|
|
180
|
+
* Get a procedure by its path (e.g., "todos.list")
|
|
181
|
+
*/
|
|
182
|
+
getProcedure(path: string): ProcedureDefinition<TContext, any, any> | null;
|
|
183
|
+
/**
|
|
184
|
+
* Execute a procedure by its path
|
|
185
|
+
*/
|
|
186
|
+
execute(path: string, ctx: TContext & {
|
|
187
|
+
db: DatabaseContext;
|
|
188
|
+
}, input: unknown): Promise<unknown>;
|
|
189
|
+
/**
|
|
190
|
+
* Get all procedure paths in the router
|
|
191
|
+
*/
|
|
192
|
+
getProcedurePaths(): string[];
|
|
193
|
+
/**
|
|
194
|
+
* Check if a path is a query procedure
|
|
195
|
+
*/
|
|
196
|
+
isQuery(path: string): boolean;
|
|
197
|
+
/**
|
|
198
|
+
* Check if a path is a mutation procedure
|
|
199
|
+
*/
|
|
200
|
+
isMutation(path: string): boolean;
|
|
201
|
+
}
|
|
202
|
+
/**
|
|
203
|
+
* Create a router from a definition
|
|
204
|
+
*/
|
|
205
|
+
declare function createRouter<TContext, TRouter extends RouterDefinition<TContext>>(definition: TRouter): Router<TContext, TRouter>;
|
|
206
|
+
/**
|
|
207
|
+
* Merge multiple routers into one
|
|
208
|
+
*/
|
|
209
|
+
declare function mergeRouters<TContext>(...routers: Router<TContext, any>[]): Router<TContext, RouterDefinition<TContext>>;
|
|
210
|
+
|
|
211
|
+
/**
|
|
212
|
+
* ReactiveBuilder - The main builder returned by initReactive
|
|
213
|
+
*/
|
|
214
|
+
interface ReactiveBuilder<TContext> {
|
|
215
|
+
/**
|
|
216
|
+
* Create a new procedure builder
|
|
217
|
+
*/
|
|
218
|
+
procedure: ProcedureBuilder<TContext>;
|
|
219
|
+
/**
|
|
220
|
+
* Create a router from procedure definitions
|
|
221
|
+
*/
|
|
222
|
+
router<TRouter extends RouterDefinition<TContext>>(definition: TRouter): Router<TContext, TRouter>;
|
|
223
|
+
}
|
|
224
|
+
/**
|
|
225
|
+
* Initialize the reactive system with a context type
|
|
226
|
+
*
|
|
227
|
+
* @example
|
|
228
|
+
* ```ts
|
|
229
|
+
* const t = initReactive<{ userId: string }>();
|
|
230
|
+
*
|
|
231
|
+
* export const appRouter = t.router({
|
|
232
|
+
* todos: {
|
|
233
|
+
* list: t.procedure
|
|
234
|
+
* .input(z.object({ taskListId: z.string() }))
|
|
235
|
+
* .query(({ ctx, input }) => {
|
|
236
|
+
* return ctx.db
|
|
237
|
+
* .query(TodoTable)
|
|
238
|
+
* .filter((q) => q.eq(TodoTable.field.taskListId, input.taskListId))
|
|
239
|
+
* .take(50);
|
|
240
|
+
* }),
|
|
241
|
+
* }
|
|
242
|
+
* });
|
|
243
|
+
* ```
|
|
244
|
+
*/
|
|
245
|
+
declare function initReactive<TContext = Record<string, unknown>>(): ReactiveBuilder<TContext>;
|
|
246
|
+
/**
|
|
247
|
+
* Type helper to infer the router type
|
|
248
|
+
*/
|
|
249
|
+
type InferRouterType<T> = T extends Router<infer TContext, infer TRouter> ? {
|
|
250
|
+
context: TContext;
|
|
251
|
+
router: TRouter;
|
|
252
|
+
} : never;
|
|
253
|
+
/**
|
|
254
|
+
* Type helper to get procedure input type
|
|
255
|
+
*/
|
|
256
|
+
type InferProcedureInput<T> = T extends {
|
|
257
|
+
inputSchema: infer TSchema;
|
|
258
|
+
} ? TSchema extends z.ZodType ? z.infer<TSchema> : undefined : undefined;
|
|
259
|
+
/**
|
|
260
|
+
* Type helper to get procedure output type
|
|
261
|
+
*/
|
|
262
|
+
type InferProcedureOutput<T> = T extends {
|
|
263
|
+
resolver: (...args: any) => infer TOutput;
|
|
264
|
+
} ? Awaited<TOutput> : unknown;
|
|
265
|
+
|
|
266
|
+
/**
|
|
267
|
+
* Extract dependencies from a tracked query operation
|
|
268
|
+
*/
|
|
269
|
+
declare function extractDependencies(operation: TrackedQueryOperation): QueryDependency[];
|
|
270
|
+
/**
|
|
271
|
+
* Create a dependency key for the inverted index
|
|
272
|
+
* Format: "TableName#FieldName#FieldValue"
|
|
273
|
+
*/
|
|
274
|
+
declare function createDependencyKey(dependency: QueryDependency): string;
|
|
275
|
+
/**
|
|
276
|
+
* Parse a dependency key back into its components
|
|
277
|
+
*/
|
|
278
|
+
declare function parseDependencyKey(key: string): QueryDependency | null;
|
|
279
|
+
/**
|
|
280
|
+
* Extract affected dependency keys from a DynamoDB stream record
|
|
281
|
+
* This finds all keys that might be affected by a change
|
|
282
|
+
*/
|
|
283
|
+
declare function extractAffectedKeys(tableName: string, item: Record<string, unknown>): string[];
|
|
284
|
+
/**
|
|
285
|
+
* Convert a TrackedQueryOperation to QueryMetadata for storage.
|
|
286
|
+
* Normalizes filter operators for evaluation.
|
|
287
|
+
*/
|
|
288
|
+
declare function operationToQueryMetadata(operation: TrackedQueryOperation): QueryMetadata;
|
|
289
|
+
/**
|
|
290
|
+
* DependencyTracker - Tracks query operations during procedure execution
|
|
291
|
+
*/
|
|
292
|
+
declare class DependencyTracker {
|
|
293
|
+
private operations;
|
|
294
|
+
/**
|
|
295
|
+
* Track a query operation
|
|
296
|
+
*/
|
|
297
|
+
track(operation: TrackedQueryOperation): void;
|
|
298
|
+
/**
|
|
299
|
+
* Get all tracked operations
|
|
300
|
+
*/
|
|
301
|
+
getOperations(): TrackedQueryOperation[];
|
|
302
|
+
/**
|
|
303
|
+
* Extract all dependencies from tracked operations
|
|
304
|
+
*/
|
|
305
|
+
extractAll(): QueryDependency[];
|
|
306
|
+
/**
|
|
307
|
+
* Get all dependency keys for the inverted index
|
|
308
|
+
*/
|
|
309
|
+
getDependencyKeys(): string[];
|
|
310
|
+
/**
|
|
311
|
+
* Get query metadata for the first tracked operation.
|
|
312
|
+
* Used for storing subscription state.
|
|
313
|
+
*/
|
|
314
|
+
getQueryMetadata(): QueryMetadata | null;
|
|
315
|
+
/**
|
|
316
|
+
* Get the primary key field from the first operation
|
|
317
|
+
*/
|
|
318
|
+
getPkField(): string | null;
|
|
319
|
+
/**
|
|
320
|
+
* Get the sort key field from the first operation
|
|
321
|
+
*/
|
|
322
|
+
getSkField(): string | undefined;
|
|
323
|
+
/**
|
|
324
|
+
* Clear tracked operations
|
|
325
|
+
*/
|
|
326
|
+
clear(): void;
|
|
327
|
+
}
|
|
328
|
+
|
|
329
|
+
/**
|
|
330
|
+
* Configuration for creating a database context
|
|
331
|
+
*/
|
|
332
|
+
interface DbContextConfig {
|
|
333
|
+
client?: DynamoDBClient;
|
|
334
|
+
region?: string;
|
|
335
|
+
endpoint?: string;
|
|
336
|
+
}
|
|
337
|
+
/**
|
|
338
|
+
* Creates a database context for procedure execution
|
|
339
|
+
*/
|
|
340
|
+
declare function createDbContext(config: DbContextConfig, dependencyTracker?: DependencyTracker): DatabaseContext;
|
|
341
|
+
|
|
342
|
+
/**
|
|
343
|
+
* Query execution function type
|
|
344
|
+
*/
|
|
345
|
+
type QueryExecutor<TTable extends AnyDynamoTable> = (operation: TrackedQueryOperation, options: QueryOptions) => Promise<TableItem<TTable>[]>;
|
|
346
|
+
/**
|
|
347
|
+
* Query options
|
|
348
|
+
*/
|
|
349
|
+
interface QueryOptions {
|
|
350
|
+
limit?: number;
|
|
351
|
+
startKey?: Record<string, unknown>;
|
|
352
|
+
ascending: boolean;
|
|
353
|
+
}
|
|
354
|
+
/**
|
|
355
|
+
* Implementation of QueryBuilder
|
|
356
|
+
*/
|
|
357
|
+
declare class QueryBuilderImpl<TTable extends AnyDynamoTable> implements QueryBuilder<TTable> {
|
|
358
|
+
private table;
|
|
359
|
+
private filters;
|
|
360
|
+
private indexName?;
|
|
361
|
+
private limit?;
|
|
362
|
+
private startKey?;
|
|
363
|
+
private ascending;
|
|
364
|
+
private executor;
|
|
365
|
+
private operationTracker?;
|
|
366
|
+
constructor(table: TTable, executor: QueryExecutor<TTable>, operationTracker?: (op: TrackedQueryOperation) => void);
|
|
367
|
+
filter(fn: (q: FilterBuilder<TTable>) => FilterCondition): QueryBuilder<TTable>;
|
|
368
|
+
useIndex(indexName: string): QueryBuilder<TTable>;
|
|
369
|
+
take(limit: number): QueryBuilder<TTable>;
|
|
370
|
+
startFrom(key: TableKeyInput<TTable>): QueryBuilder<TTable>;
|
|
371
|
+
sortAscending(): QueryBuilder<TTable>;
|
|
372
|
+
sortDescending(): QueryBuilder<TTable>;
|
|
373
|
+
execute(): Promise<TableItem<TTable>[]>;
|
|
374
|
+
/**
|
|
375
|
+
* Get the current operation without executing
|
|
376
|
+
* Used for dependency extraction
|
|
377
|
+
*/
|
|
378
|
+
getOperation(): TrackedQueryOperation;
|
|
379
|
+
}
|
|
380
|
+
/**
|
|
381
|
+
* Create a filter builder instance
|
|
382
|
+
*/
|
|
383
|
+
declare function createFilterBuilder<TTable extends AnyDynamoTable>(): FilterBuilder<TTable>;
|
|
384
|
+
|
|
385
|
+
/**
|
|
386
|
+
* PartiQL statement with parameters
|
|
387
|
+
*/
|
|
388
|
+
interface PartiQLStatement {
|
|
389
|
+
statement: string;
|
|
390
|
+
parameters: unknown[];
|
|
391
|
+
}
|
|
392
|
+
/**
|
|
393
|
+
* Build a PartiQL SELECT statement from a query operation
|
|
394
|
+
*/
|
|
395
|
+
declare function buildSelectStatement(operation: TrackedQueryOperation): PartiQLStatement;
|
|
396
|
+
/**
|
|
397
|
+
* Build a PartiQL INSERT statement
|
|
398
|
+
*/
|
|
399
|
+
declare function buildInsertStatement(tableName: string, item: Record<string, unknown>): PartiQLStatement;
|
|
400
|
+
/**
|
|
401
|
+
* Build a PartiQL UPDATE statement
|
|
402
|
+
*/
|
|
403
|
+
declare function buildUpdateStatement(tableName: string, key: Record<string, unknown>, updates: Record<string, unknown>): PartiQLStatement;
|
|
404
|
+
/**
|
|
405
|
+
* Build a PartiQL DELETE statement
|
|
406
|
+
*/
|
|
407
|
+
declare function buildDeleteStatement(tableName: string, key: Record<string, unknown>): PartiQLStatement;
|
|
408
|
+
/**
|
|
409
|
+
* Build a PartiQL GET statement (for single item by key)
|
|
410
|
+
*/
|
|
411
|
+
declare function buildGetStatement(tableName: string, key: Record<string, unknown>): PartiQLStatement;
|
|
412
|
+
|
|
413
|
+
/**
|
|
414
|
+
* Generate JSON patches between two objects
|
|
415
|
+
* Uses RFC 6902 JSON Patch format
|
|
416
|
+
*/
|
|
417
|
+
declare function generatePatches(oldValue: unknown, newValue: unknown): JsonPatch[];
|
|
418
|
+
/**
|
|
419
|
+
* Apply JSON patches to an object
|
|
420
|
+
* Returns the patched result
|
|
421
|
+
*/
|
|
422
|
+
declare function applyPatches<T>(document: T, patches: JsonPatch[]): T;
|
|
423
|
+
/**
|
|
424
|
+
* Check if there are any changes between two values
|
|
425
|
+
*/
|
|
426
|
+
declare function hasChanges(oldValue: unknown, newValue: unknown): boolean;
|
|
427
|
+
/**
|
|
428
|
+
* Create a minimal patch that only includes necessary operations
|
|
429
|
+
* Optimizes the patch by removing redundant operations
|
|
430
|
+
*/
|
|
431
|
+
declare function optimizePatches(patches: JsonPatch[]): JsonPatch[];
|
|
432
|
+
/**
|
|
433
|
+
* Batch multiple patch sets into a single set
|
|
434
|
+
*/
|
|
435
|
+
declare function batchPatches(patchSets: JsonPatch[][]): JsonPatch[];
|
|
436
|
+
|
|
437
|
+
/**
|
|
438
|
+
* Request types for the reactive handler
|
|
439
|
+
*/
|
|
440
|
+
interface SubscribeRequest {
|
|
441
|
+
type: 'subscribe';
|
|
442
|
+
subscriptionId: string;
|
|
443
|
+
path: string;
|
|
444
|
+
input: unknown;
|
|
445
|
+
}
|
|
446
|
+
interface UnsubscribeRequest {
|
|
447
|
+
type: 'unsubscribe';
|
|
448
|
+
subscriptionId: string;
|
|
449
|
+
}
|
|
450
|
+
interface CallRequest {
|
|
451
|
+
type: 'call';
|
|
452
|
+
path: string;
|
|
453
|
+
input: unknown;
|
|
454
|
+
}
|
|
455
|
+
type ReactiveRequest = SubscribeRequest | UnsubscribeRequest | CallRequest;
|
|
456
|
+
/**
|
|
457
|
+
* Response types for the reactive handler
|
|
458
|
+
*/
|
|
459
|
+
interface SnapshotResponse {
|
|
460
|
+
type: 'snapshot';
|
|
461
|
+
subscriptionId: string;
|
|
462
|
+
data: unknown;
|
|
463
|
+
}
|
|
464
|
+
interface PatchResponse {
|
|
465
|
+
type: 'patch';
|
|
466
|
+
subscriptionId: string;
|
|
467
|
+
patches: unknown[];
|
|
468
|
+
}
|
|
469
|
+
interface ResultResponse {
|
|
470
|
+
type: 'result';
|
|
471
|
+
data: unknown;
|
|
472
|
+
}
|
|
473
|
+
interface ErrorResponse {
|
|
474
|
+
type: 'error';
|
|
475
|
+
message: string;
|
|
476
|
+
subscriptionId?: string;
|
|
477
|
+
}
|
|
478
|
+
type ReactiveResponse = SnapshotResponse | PatchResponse | ResultResponse | ErrorResponse;
|
|
479
|
+
/**
|
|
480
|
+
* Configuration for the reactive handler
|
|
481
|
+
*/
|
|
482
|
+
interface ReactiveHandlerConfig<TContext> {
|
|
483
|
+
router: Router<TContext, any>;
|
|
484
|
+
dbConfig?: DbContextConfig;
|
|
485
|
+
getContext: (connectionId: string) => Promise<TContext>;
|
|
486
|
+
ttlSeconds?: number;
|
|
487
|
+
/** Table names (uses defaults if not provided) */
|
|
488
|
+
connectionsTableName?: string;
|
|
489
|
+
dependenciesTableName?: string;
|
|
490
|
+
queriesTableName?: string;
|
|
491
|
+
}
|
|
492
|
+
/**
|
|
493
|
+
* Create a reactive handler for Next.js API routes or other HTTP servers.
|
|
494
|
+
* This handler is used for subscribe/call requests and stores queryMetadata
|
|
495
|
+
* for the stream handler to use later.
|
|
496
|
+
*/
|
|
497
|
+
declare function createReactiveHandler<TContext>(config: ReactiveHandlerConfig<TContext>): {
|
|
498
|
+
handleRequest: (connectionId: string, request: ReactiveRequest) => Promise<ReactiveResponse>;
|
|
499
|
+
registerConnection: (connectionId: string, context?: Record<string, unknown>) => Promise<void>;
|
|
500
|
+
unregisterConnection: (connectionId: string) => Promise<void>;
|
|
501
|
+
};
|
|
502
|
+
|
|
503
|
+
/**
|
|
504
|
+
* Configuration for the stream handler.
|
|
505
|
+
* NOTE: Router is no longer required - stream processing uses stored query metadata.
|
|
506
|
+
*/
|
|
507
|
+
interface StreamHandlerConfig {
|
|
508
|
+
dbConfig?: DbContextConfig;
|
|
509
|
+
apiGatewayEndpoint: string;
|
|
510
|
+
connectionsTableName?: string;
|
|
511
|
+
dependenciesTableName?: string;
|
|
512
|
+
queriesTableName?: string;
|
|
513
|
+
}
|
|
514
|
+
/**
|
|
515
|
+
* Create a DynamoDB stream handler for AWS Lambda.
|
|
516
|
+
* Uses stored query metadata to re-execute queries WITHOUT router code.
|
|
517
|
+
*/
|
|
518
|
+
declare function createStreamHandler(config: StreamHandlerConfig): {
|
|
519
|
+
handler: (event: DynamoDBStreamEvent) => Promise<void>;
|
|
520
|
+
};
|
|
521
|
+
/**
|
|
522
|
+
* WebSocket connection handler for $connect
|
|
523
|
+
*/
|
|
524
|
+
declare function createConnectHandler(config: Pick<StreamHandlerConfig, 'dbConfig' | 'connectionsTableName'>): (event: {
|
|
525
|
+
requestContext: {
|
|
526
|
+
connectionId: string;
|
|
527
|
+
authorizer?: Record<string, unknown>;
|
|
528
|
+
};
|
|
529
|
+
}) => Promise<{
|
|
530
|
+
statusCode: number;
|
|
531
|
+
}>;
|
|
532
|
+
/**
|
|
533
|
+
* WebSocket disconnection handler for $disconnect
|
|
534
|
+
*/
|
|
535
|
+
declare function createDisconnectHandler(config: Pick<StreamHandlerConfig, 'dbConfig' | 'connectionsTableName' | 'queriesTableName' | 'dependenciesTableName'>): (event: {
|
|
536
|
+
requestContext: {
|
|
537
|
+
connectionId: string;
|
|
538
|
+
};
|
|
539
|
+
}) => Promise<{
|
|
540
|
+
statusCode: number;
|
|
541
|
+
}>;
|
|
542
|
+
|
|
543
|
+
/**
|
|
544
|
+
* Configuration for creating a reactive harness
|
|
545
|
+
*/
|
|
546
|
+
interface ReactiveHarnessConfig<TContext> {
|
|
547
|
+
/**
|
|
548
|
+
* Function to get the context for a connection
|
|
549
|
+
* This is called on each request to build the procedure context
|
|
550
|
+
*/
|
|
551
|
+
getContext?: (connectionId: string) => Promise<TContext>;
|
|
552
|
+
/**
|
|
553
|
+
* Optional database configuration
|
|
554
|
+
*/
|
|
555
|
+
dbConfig?: DbContextConfig;
|
|
556
|
+
}
|
|
557
|
+
/**
|
|
558
|
+
* The reactive harness object containing all configuration needed for the engine
|
|
559
|
+
*/
|
|
560
|
+
interface ReactiveHarness<TContext> {
|
|
561
|
+
getContext: (connectionId: string) => Promise<TContext>;
|
|
562
|
+
dbConfig?: DbContextConfig;
|
|
563
|
+
}
|
|
564
|
+
/**
|
|
565
|
+
* Create a reactive harness that encapsulates the router and context configuration.
|
|
566
|
+
*
|
|
567
|
+
* This is the only export needed from user code for the ReactiveEngine.
|
|
568
|
+
* The engine will use this harness to automatically create all WebSocket handlers.
|
|
569
|
+
*
|
|
570
|
+
* @example
|
|
571
|
+
* ```typescript
|
|
572
|
+
* // harness.ts - This is all you need in your handlers directory
|
|
573
|
+
* import { createReactiveHarness } from 'dynamodb-reactive/server';
|
|
574
|
+
* import { appRouter } from './router';
|
|
575
|
+
*
|
|
576
|
+
* export default createReactiveHarness({
|
|
577
|
+
* getContext: async (connectionId) => ({
|
|
578
|
+
* connectionId,
|
|
579
|
+
* }),
|
|
580
|
+
* });
|
|
581
|
+
* ```
|
|
582
|
+
*/
|
|
583
|
+
declare function createReactiveHarness<TContext>(config: ReactiveHarnessConfig<TContext>): ReactiveHarness<TContext>;
|
|
584
|
+
|
|
585
|
+
/**
|
|
586
|
+
* Lambda handler implementations for the reactive WebSocket system.
|
|
587
|
+
*
|
|
588
|
+
* These handlers process WebSocket events and DynamoDB stream events
|
|
589
|
+
* WITHOUT requiring user router code at runtime.
|
|
590
|
+
*
|
|
591
|
+
* Stream processing uses stored query metadata to evaluate changes
|
|
592
|
+
* directly, rather than re-executing queries through a router.
|
|
593
|
+
*/
|
|
594
|
+
|
|
595
|
+
/**
|
|
596
|
+
* Create all Lambda handlers.
|
|
597
|
+
* No user code required - all configuration comes from environment variables.
|
|
598
|
+
* The stream handler uses stored query metadata (PartiQL), not router code.
|
|
599
|
+
*/
|
|
600
|
+
declare function createLambdaHandlers(): {
|
|
601
|
+
connectHandler: (event: APIGatewayProxyEvent) => Promise<APIGatewayProxyResult>;
|
|
602
|
+
disconnectHandler: (event: APIGatewayProxyEvent) => Promise<APIGatewayProxyResult>;
|
|
603
|
+
messageHandler: (event: APIGatewayProxyEvent) => Promise<APIGatewayProxyResult>;
|
|
604
|
+
streamHandler: (event: DynamoDBStreamEvent) => Promise<void>;
|
|
605
|
+
};
|
|
606
|
+
|
|
607
|
+
/**
|
|
608
|
+
* Filter evaluator for evaluating FilterCondition against DynamoDB records.
|
|
609
|
+
* Used by the stream handler to determine if a record matches a subscription's query.
|
|
610
|
+
*/
|
|
611
|
+
|
|
612
|
+
/**
|
|
613
|
+
* Evaluate a filter condition against a record.
|
|
614
|
+
* Returns true if the record matches the filter.
|
|
615
|
+
*/
|
|
616
|
+
declare function evaluateFilter(filter: FilterCondition, record: Record<string, unknown>): boolean;
|
|
617
|
+
/**
|
|
618
|
+
* Evaluate multiple filter conditions (all must match - AND logic).
|
|
619
|
+
*/
|
|
620
|
+
declare function evaluateFilters(filters: FilterCondition[], record: Record<string, unknown>): boolean;
|
|
621
|
+
/**
|
|
622
|
+
* Sort records by a field.
|
|
623
|
+
*/
|
|
624
|
+
declare function sortRecords(records: Record<string, unknown>[], sortField?: string, sortOrder?: 'asc' | 'desc'): Record<string, unknown>[];
|
|
625
|
+
/**
|
|
626
|
+
* Find the primary key value(s) from a record.
|
|
627
|
+
* Used to identify records for update/removal.
|
|
628
|
+
*/
|
|
629
|
+
declare function getRecordKey(record: Record<string, unknown>, pkField: string, skField?: string): string;
|
|
630
|
+
|
|
631
|
+
export { AnyDynamoTable, type AnyProcedureDefinition, type CallRequest, type DatabaseContext, type DbContextConfig, DependencyTracker, type ErrorResponse, type FilterBuilder, FilterCondition, type InferProcedureInput, type InferProcedureOutput, type InferRouterType, type PartiQLStatement, type PatchResponse, ProcedureBuilder, type ProcedureContext, type ProcedureDefinition, type ProcedureType, type QueryBuilder, QueryBuilderImpl, type QueryDependency, type ReactiveBuilder, type ReactiveHandlerConfig, type ReactiveHarness, type ReactiveHarnessConfig, type ReactiveRequest, type ReactiveResponse, type ResultResponse, Router, type RouterDefinition, type SnapshotResponse, type StreamHandlerConfig, type SubscribeRequest, type TableItem, type TableKeyInput, type TrackedQueryOperation, type UnsubscribeRequest, applyPatches, batchPatches, buildDeleteStatement, buildGetStatement, buildInsertStatement, buildSelectStatement, buildUpdateStatement, createConnectHandler, createDbContext, createDependencyKey, createDisconnectHandler, createFilterBuilder, createLambdaHandlers, createReactiveHandler, createReactiveHarness, createRouter, createStreamHandler, evaluateFilter, evaluateFilters, executeProcedure, extractAffectedKeys, extractDependencies, generatePatches, getRecordKey, hasChanges, initReactive, isProcedure, mergeRouters, operationToQueryMetadata, optimizePatches, parseDependencyKey, sortRecords };
|