dynamodb-reactive 0.2.3 → 0.3.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/README.md CHANGED
@@ -32,6 +32,7 @@ Every public entry point supplies ESM (`.js` and `.d.ts`) and CommonJS (`.cjs` a
32
32
  | `dynamodb-reactive/client` | React-free client, WebSocket manager, and query-key helpers |
33
33
  | `dynamodb-reactive/react` | Provider and React hooks |
34
34
  | `dynamodb-reactive/infra` | `ReactiveEngine` and its configuration types |
35
+ | `dynamodb-reactive/cluster` | Cluster-worker connection, signed tickets, and wire-protocol types |
35
36
 
36
37
  React code must import the provider and hooks from `dynamodb-reactive/react`. Importing `dynamodb-reactive/client` does not load React.
37
38
 
@@ -225,7 +226,22 @@ The authorizer must return an authorizer context containing the stable principal
225
226
 
226
227
  The application role running `createReactiveHandler` needs the system-table and application-table permissions installed by `engine.grantApplicationAccess(appRole)`. The engine's generated stream Lambda is router-agnostic and receives only the table access it needs.
227
228
 
228
- `dynamodb-reactive/infra` intentionally exposes only `ReactiveEngine`, `ReactiveEngineProps`, and `ReactiveTableBinding`. User tables are supplied through the constructor's `tables` bindings; stream mappings and system tables are managed by the engine rather than separate public helpers.
229
+ `dynamodb-reactive/infra` intentionally exposes only `ReactiveEngine`, its props types, and `ReactiveTableBinding`. User tables are supplied through the constructor's `tables` bindings; stream mappings and system tables are managed by the engine rather than separate public helpers. Workloads with heavier query fan-out can tune the stream processor independently:
230
+
231
+ ```ts
232
+ new ReactiveEngine(this, 'Reactive', {
233
+ resourcePrefix: 'acme-prod',
234
+ tables: [{ definition: TodoTable, table }],
235
+ connectAuthorizer,
236
+ streamHandlerProps: {
237
+ memorySize: 512,
238
+ timeout: cdk.Duration.seconds(120),
239
+ },
240
+ streamBatchSize: 10,
241
+ });
242
+ ```
243
+
244
+ The stream handler coalesces invalidations within each batch, so one subscription is refreshed once even when several records affect it. If that refresh fails, every contributing record is returned in the partial batch response for retry.
229
245
 
230
246
  ### Bind an existing table
231
247
 
@@ -502,6 +518,32 @@ The client uses the runtime's native `WebSocket` by default. Browsers and Node 2
502
518
 
503
519
  Automatic reconnect can continue after an individual `connect()` wait times out. Keep the same client when recovery is desired, as the React provider does. If an imperative owner abandons or replaces a failed client, call `client.disconnect()` before creating its replacement so the old client's timers and sockets cannot accumulate. The React provider disconnects the clients it owns on replacement and unmount; callers own the lifetime of an externally supplied client.
504
520
 
521
+ ## Cluster workers
522
+
523
+ `dynamodb-reactive/cluster` connects workers that have no inbound access (for example a home cluster) to an application that pushes them work. The worker holds a long-lived runner token, exchanges it at `POST /api/cluster/token` for a short-lived ticket `{ token, expiresAt, url }`, and keeps a reactive WebSocket open. It uses only Web standards, so it runs in Node and in Workers runtimes, against this package's AWS engine or any backend that implements the wire protocol.
524
+
525
+ ```ts
526
+ import { connectClusterWorker } from 'dynamodb-reactive/cluster';
527
+
528
+ const client = await connectClusterWorker({
529
+ baseUrl: 'https://app.example.com',
530
+ runnerToken: process.env.CLUSTER_RUNNER_TOKEN!,
531
+ onRetry: (error) => console.warn('cluster connect failed; retrying:', error.message),
532
+ });
533
+
534
+ const work = client.subscribe('cluster.work', {
535
+ onData: (items) => {
536
+ // Claim and run the pushed work.
537
+ },
538
+ });
539
+ ```
540
+
541
+ `connectClusterWorker` retries ticket and connect failures every `retryDelay` (10 seconds by default) until it connects or `signal` aborts, and fetches a fresh ticket for every connection so reconnects never reuse an expired ticket. The ticket endpoint and the reactive HTTP endpoint default to `/api/cluster/token` and `/api/reactive`; override them with `ticketPath` and `httpPath`.
542
+
543
+ Applications can mint stateless tickets with `createSignedClusterTicket({ secret, principal, url })` and check them with `verifySignedClusterTicket(token, secret)`, which returns the principal or `undefined`. Verification is an HMAC check with no storage read, so reconnect storms do not reach the database. Keep the secret server-side.
544
+
545
+ The module also exports the wire-protocol types (`SubscribeRequest`, `SnapshotResponse`, `ResyncEvent`, `WebSocketEvent`, and the rest) for backends that serve the protocol without the AWS engine. A server that only sends `resync` events is correct: the client answers a resync by re-sending `subscribe`, and accepts the new snapshot only when its `version` is higher than the last one.
546
+
505
547
  ## Delivery model
506
548
 
507
549
  1. The client establishes a WebSocket and receives its API Gateway connection ID.