@noy-db/hub 0.1.0-pre.3

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (195) hide show
  1. package/LICENSE +21 -0
  2. package/README.md +197 -0
  3. package/dist/aggregate/index.cjs +476 -0
  4. package/dist/aggregate/index.cjs.map +1 -0
  5. package/dist/aggregate/index.d.cts +38 -0
  6. package/dist/aggregate/index.d.ts +38 -0
  7. package/dist/aggregate/index.js +53 -0
  8. package/dist/aggregate/index.js.map +1 -0
  9. package/dist/blobs/index.cjs +1480 -0
  10. package/dist/blobs/index.cjs.map +1 -0
  11. package/dist/blobs/index.d.cts +45 -0
  12. package/dist/blobs/index.d.ts +45 -0
  13. package/dist/blobs/index.js +48 -0
  14. package/dist/blobs/index.js.map +1 -0
  15. package/dist/bundle/index.cjs +436 -0
  16. package/dist/bundle/index.cjs.map +1 -0
  17. package/dist/bundle/index.d.cts +7 -0
  18. package/dist/bundle/index.d.ts +7 -0
  19. package/dist/bundle/index.js +40 -0
  20. package/dist/bundle/index.js.map +1 -0
  21. package/dist/chunk-2QR2PQTT.js +217 -0
  22. package/dist/chunk-2QR2PQTT.js.map +1 -0
  23. package/dist/chunk-4OWFYIDQ.js +79 -0
  24. package/dist/chunk-4OWFYIDQ.js.map +1 -0
  25. package/dist/chunk-5AATM2M2.js +90 -0
  26. package/dist/chunk-5AATM2M2.js.map +1 -0
  27. package/dist/chunk-ACLDOTNQ.js +543 -0
  28. package/dist/chunk-ACLDOTNQ.js.map +1 -0
  29. package/dist/chunk-BTDCBVJW.js +160 -0
  30. package/dist/chunk-BTDCBVJW.js.map +1 -0
  31. package/dist/chunk-CIMZBAZB.js +72 -0
  32. package/dist/chunk-CIMZBAZB.js.map +1 -0
  33. package/dist/chunk-E445ICYI.js +365 -0
  34. package/dist/chunk-E445ICYI.js.map +1 -0
  35. package/dist/chunk-EXQRC2L4.js +722 -0
  36. package/dist/chunk-EXQRC2L4.js.map +1 -0
  37. package/dist/chunk-FZU343FL.js +32 -0
  38. package/dist/chunk-FZU343FL.js.map +1 -0
  39. package/dist/chunk-GJILMRPO.js +354 -0
  40. package/dist/chunk-GJILMRPO.js.map +1 -0
  41. package/dist/chunk-GOUT6DND.js +1285 -0
  42. package/dist/chunk-GOUT6DND.js.map +1 -0
  43. package/dist/chunk-J66GRPNH.js +111 -0
  44. package/dist/chunk-J66GRPNH.js.map +1 -0
  45. package/dist/chunk-M2F2JAWB.js +464 -0
  46. package/dist/chunk-M2F2JAWB.js.map +1 -0
  47. package/dist/chunk-M5INGEFC.js +84 -0
  48. package/dist/chunk-M5INGEFC.js.map +1 -0
  49. package/dist/chunk-M62XNWRA.js +72 -0
  50. package/dist/chunk-M62XNWRA.js.map +1 -0
  51. package/dist/chunk-MR4424N3.js +275 -0
  52. package/dist/chunk-MR4424N3.js.map +1 -0
  53. package/dist/chunk-NPC4LFV5.js +132 -0
  54. package/dist/chunk-NPC4LFV5.js.map +1 -0
  55. package/dist/chunk-NXFEYLVG.js +311 -0
  56. package/dist/chunk-NXFEYLVG.js.map +1 -0
  57. package/dist/chunk-R36SIKES.js +79 -0
  58. package/dist/chunk-R36SIKES.js.map +1 -0
  59. package/dist/chunk-TDR6T5CJ.js +381 -0
  60. package/dist/chunk-TDR6T5CJ.js.map +1 -0
  61. package/dist/chunk-UF3BUNQZ.js +1 -0
  62. package/dist/chunk-UF3BUNQZ.js.map +1 -0
  63. package/dist/chunk-UQFSPSWG.js +1109 -0
  64. package/dist/chunk-UQFSPSWG.js.map +1 -0
  65. package/dist/chunk-USKYUS74.js +793 -0
  66. package/dist/chunk-USKYUS74.js.map +1 -0
  67. package/dist/chunk-XCL3WP6J.js +121 -0
  68. package/dist/chunk-XCL3WP6J.js.map +1 -0
  69. package/dist/chunk-XHFOENR2.js +680 -0
  70. package/dist/chunk-XHFOENR2.js.map +1 -0
  71. package/dist/chunk-ZFKD4QMV.js +430 -0
  72. package/dist/chunk-ZFKD4QMV.js.map +1 -0
  73. package/dist/chunk-ZLMV3TUA.js +490 -0
  74. package/dist/chunk-ZLMV3TUA.js.map +1 -0
  75. package/dist/chunk-ZRG4V3F5.js +17 -0
  76. package/dist/chunk-ZRG4V3F5.js.map +1 -0
  77. package/dist/consent/index.cjs +204 -0
  78. package/dist/consent/index.cjs.map +1 -0
  79. package/dist/consent/index.d.cts +24 -0
  80. package/dist/consent/index.d.ts +24 -0
  81. package/dist/consent/index.js +23 -0
  82. package/dist/consent/index.js.map +1 -0
  83. package/dist/crdt/index.cjs +152 -0
  84. package/dist/crdt/index.cjs.map +1 -0
  85. package/dist/crdt/index.d.cts +30 -0
  86. package/dist/crdt/index.d.ts +30 -0
  87. package/dist/crdt/index.js +24 -0
  88. package/dist/crdt/index.js.map +1 -0
  89. package/dist/crypto-IVKU7YTT.js +44 -0
  90. package/dist/crypto-IVKU7YTT.js.map +1 -0
  91. package/dist/delegation-XDJCBTI2.js +16 -0
  92. package/dist/delegation-XDJCBTI2.js.map +1 -0
  93. package/dist/dev-unlock-CeXic1xC.d.cts +263 -0
  94. package/dist/dev-unlock-KrKkcqD3.d.ts +263 -0
  95. package/dist/hash-9KO1BGxh.d.cts +63 -0
  96. package/dist/hash-ChfJjRjQ.d.ts +63 -0
  97. package/dist/history/index.cjs +1215 -0
  98. package/dist/history/index.cjs.map +1 -0
  99. package/dist/history/index.d.cts +62 -0
  100. package/dist/history/index.d.ts +62 -0
  101. package/dist/history/index.js +79 -0
  102. package/dist/history/index.js.map +1 -0
  103. package/dist/i18n/index.cjs +746 -0
  104. package/dist/i18n/index.cjs.map +1 -0
  105. package/dist/i18n/index.d.cts +38 -0
  106. package/dist/i18n/index.d.ts +38 -0
  107. package/dist/i18n/index.js +55 -0
  108. package/dist/i18n/index.js.map +1 -0
  109. package/dist/index-BRHBCmLt.d.ts +1940 -0
  110. package/dist/index-C8kQtmOk.d.ts +380 -0
  111. package/dist/index-DN-J-5wT.d.cts +1940 -0
  112. package/dist/index-DhjMjz7L.d.cts +380 -0
  113. package/dist/index.cjs +14756 -0
  114. package/dist/index.cjs.map +1 -0
  115. package/dist/index.d.cts +269 -0
  116. package/dist/index.d.ts +269 -0
  117. package/dist/index.js +6085 -0
  118. package/dist/index.js.map +1 -0
  119. package/dist/indexing/index.cjs +736 -0
  120. package/dist/indexing/index.cjs.map +1 -0
  121. package/dist/indexing/index.d.cts +36 -0
  122. package/dist/indexing/index.d.ts +36 -0
  123. package/dist/indexing/index.js +77 -0
  124. package/dist/indexing/index.js.map +1 -0
  125. package/dist/lazy-builder-BwEoBQZ9.d.ts +304 -0
  126. package/dist/lazy-builder-CZVLKh0Z.d.cts +304 -0
  127. package/dist/ledger-2NX4L7PN.js +33 -0
  128. package/dist/ledger-2NX4L7PN.js.map +1 -0
  129. package/dist/mime-magic-CBBSOkjm.d.cts +50 -0
  130. package/dist/mime-magic-CBBSOkjm.d.ts +50 -0
  131. package/dist/periods/index.cjs +1035 -0
  132. package/dist/periods/index.cjs.map +1 -0
  133. package/dist/periods/index.d.cts +21 -0
  134. package/dist/periods/index.d.ts +21 -0
  135. package/dist/periods/index.js +25 -0
  136. package/dist/periods/index.js.map +1 -0
  137. package/dist/predicate-SBHmi6D0.d.cts +161 -0
  138. package/dist/predicate-SBHmi6D0.d.ts +161 -0
  139. package/dist/query/index.cjs +1957 -0
  140. package/dist/query/index.cjs.map +1 -0
  141. package/dist/query/index.d.cts +3 -0
  142. package/dist/query/index.d.ts +3 -0
  143. package/dist/query/index.js +62 -0
  144. package/dist/query/index.js.map +1 -0
  145. package/dist/session/index.cjs +487 -0
  146. package/dist/session/index.cjs.map +1 -0
  147. package/dist/session/index.d.cts +45 -0
  148. package/dist/session/index.d.ts +45 -0
  149. package/dist/session/index.js +44 -0
  150. package/dist/session/index.js.map +1 -0
  151. package/dist/shadow/index.cjs +133 -0
  152. package/dist/shadow/index.cjs.map +1 -0
  153. package/dist/shadow/index.d.cts +16 -0
  154. package/dist/shadow/index.d.ts +16 -0
  155. package/dist/shadow/index.js +20 -0
  156. package/dist/shadow/index.js.map +1 -0
  157. package/dist/store/index.cjs +1069 -0
  158. package/dist/store/index.cjs.map +1 -0
  159. package/dist/store/index.d.cts +491 -0
  160. package/dist/store/index.d.ts +491 -0
  161. package/dist/store/index.js +34 -0
  162. package/dist/store/index.js.map +1 -0
  163. package/dist/strategy-BSxFXGzb.d.cts +110 -0
  164. package/dist/strategy-BSxFXGzb.d.ts +110 -0
  165. package/dist/strategy-D-SrOLCl.d.cts +548 -0
  166. package/dist/strategy-D-SrOLCl.d.ts +548 -0
  167. package/dist/sync/index.cjs +1062 -0
  168. package/dist/sync/index.cjs.map +1 -0
  169. package/dist/sync/index.d.cts +42 -0
  170. package/dist/sync/index.d.ts +42 -0
  171. package/dist/sync/index.js +28 -0
  172. package/dist/sync/index.js.map +1 -0
  173. package/dist/team/index.cjs +1233 -0
  174. package/dist/team/index.cjs.map +1 -0
  175. package/dist/team/index.d.cts +117 -0
  176. package/dist/team/index.d.ts +117 -0
  177. package/dist/team/index.js +39 -0
  178. package/dist/team/index.js.map +1 -0
  179. package/dist/tx/index.cjs +212 -0
  180. package/dist/tx/index.cjs.map +1 -0
  181. package/dist/tx/index.d.cts +20 -0
  182. package/dist/tx/index.d.ts +20 -0
  183. package/dist/tx/index.js +20 -0
  184. package/dist/tx/index.js.map +1 -0
  185. package/dist/types-BZpCZB8N.d.ts +7526 -0
  186. package/dist/types-Bfs0qr5F.d.cts +7526 -0
  187. package/dist/ulid-COREQ2RQ.js +9 -0
  188. package/dist/ulid-COREQ2RQ.js.map +1 -0
  189. package/dist/util/index.cjs +230 -0
  190. package/dist/util/index.cjs.map +1 -0
  191. package/dist/util/index.d.cts +77 -0
  192. package/dist/util/index.d.ts +77 -0
  193. package/dist/util/index.js +190 -0
  194. package/dist/util/index.js.map +1 -0
  195. package/package.json +244 -0
@@ -0,0 +1,491 @@
1
+ import { at as NoydbStore, bD as NoydbBundleStore } from '../types-BZpCZB8N.js';
2
+ export { aT as BUNDLE_STORE_POLICY, bh as INDEXED_STORE_POLICY, bM as PullMode, bO as PullPolicy, bQ as PushMode, bS as PushPolicy, c8 as SyncPolicy, c9 as SyncScheduler, ca as SyncSchedulerStatus } from '../types-BZpCZB8N.js';
3
+ import '../lazy-builder-BwEoBQZ9.js';
4
+ import '../predicate-SBHmi6D0.js';
5
+ import '../strategy-D-SrOLCl.js';
6
+ import '../strategy-BSxFXGzb.js';
7
+ import '../index-BRHBCmLt.js';
8
+
9
+ interface WrapBundleStoreOptions {
10
+ /**
11
+ * When `true` (default), every `put()` and `delete()` flushes the full
12
+ * vault snapshot to the bundle backend. Set to `false` for bulk operations
13
+ * and call `store.flush(vaultId)` manually.
14
+ */
15
+ autoFlush?: boolean;
16
+ }
17
+ interface WrappedBundleNoydbStore extends NoydbStore {
18
+ /** Manually flush the in-memory snapshot to the bundle backend. */
19
+ flush(vaultId: string): Promise<void>;
20
+ /**
21
+ * Run a batch of mutations without flushing until the callback completes.
22
+ * A single flush is performed at the end.
23
+ */
24
+ batch(vaultId: string, fn: () => Promise<void>): Promise<void>;
25
+ }
26
+ /**
27
+ * Convert a `NoydbBundleStore` (blob-oriented read/write with OCC) into the
28
+ * standard six-method `NoydbStore` interface expected by `createNoydb({ store })`.
29
+ *
30
+ * Bundle stores operate on the entire vault as a single serialised unit —
31
+ * ideal for backends like Google Drive, WebDAV, or iCloud Drive that work
32
+ * best with whole-file I/O rather than per-record KV operations.
33
+ *
34
+ * ## Optimistic concurrency
35
+ *
36
+ * The wrapper tracks the `version` token from the last `readBundle` and
37
+ * passes it as `expectedVersion` on every flush. On
38
+ * `BundleVersionConflictError`, it re-reads, merges the remote snapshot
39
+ * (last-write-wins per record key), and retries (max 3 attempts).
40
+ *
41
+ * ## Flush modes
42
+ *
43
+ * By default, flushes on every mutation (O(vault size) per write). Options:
44
+ * - `autoFlush: false` + explicit `store.flush(vaultId)` calls
45
+ * - `store.batch(vaultId, async () => { ... })` — defers flush until end
46
+ * - Pair with `syncPolicy: { push: { mode: 'debounce' } }` from
47
+ */
48
+ declare function wrapBundleStore(bundle: NoydbBundleStore, options?: WrapBundleStoreOptions): WrappedBundleNoydbStore;
49
+ /**
50
+ * Type-safe factory helper for `NoydbBundleStore` implementations,
51
+ * analogous to `createStore` for KV stores.
52
+ */
53
+ declare function createBundleStore<TOptions>(factory: (options: TOptions) => NoydbBundleStore): (options: TOptions) => NoydbBundleStore;
54
+
55
+ /**
56
+ * Store router / multiplexer.
57
+ *
58
+ * Dispatches `NoydbStore` operations to different backends based on
59
+ * collection type, record size, record age, collection name, or vault name.
60
+ *
61
+ * ```ts
62
+ * const db = await createNoydb({
63
+ * store: routeStore({
64
+ * default: dynamo({ table: 'myapp' }),
65
+ * blobs: s3Store({ bucket: 'myapp-blobs' }),
66
+ * }),
67
+ * })
68
+ * ```
69
+ *
70
+ * @module
71
+ */
72
+
73
+ /**
74
+ * Size-tiered blob routing configuration.
75
+ *
76
+ * Routes blob chunks to different stores based on byte size. Small blobs
77
+ * (under `threshold`) stay in the primary or `small` store; large blobs
78
+ * go to `large`. This lets you keep DynamoDB as the default while sending
79
+ * large binary objects to S3.
80
+ */
81
+ interface BlobStoreRoute {
82
+ /** Store for small blobs (under threshold). Falls back to `default`. */
83
+ readonly small?: NoydbStore;
84
+ /** Store for large blobs (over threshold). */
85
+ readonly large: NoydbStore;
86
+ /** Size threshold in bytes. Default: `400 * 1024` (DynamoDB item limit). */
87
+ readonly threshold?: number;
88
+ }
89
+ /**
90
+ * Blob lifecycle management policies evaluated during `compact()`.
91
+ *
92
+ * Controls orphan cleanup, cold-tier archival, and hard deletion of
93
+ * blobs that are no longer referenced by any record.
94
+ */
95
+ interface BlobLifecyclePolicy {
96
+ /** Delete orphan blobs (refCount: 0) after this many days. Default: 7. */
97
+ readonly orphanRetentionDays?: number;
98
+ /** Move blobs not accessed in this many days to the cold blob store. */
99
+ readonly archiveAfterDays?: number;
100
+ /** Store for archived blobs. Required if archiveAfterDays is set. */
101
+ readonly archiveStore?: NoydbStore;
102
+ /** Hard-delete archived blobs after this many days. */
103
+ readonly expireAfterDays?: number;
104
+ }
105
+ /**
106
+ * Age-based hot/cold tiering configuration.
107
+ *
108
+ * Records whose `_ts` timestamp is older than `coldAfterDays` are migrated
109
+ * to the `cold` store during `compact()`. Reads transparently fall through
110
+ * to the cold store when the hot store returns null, so callers don't need
111
+ * to know which tier a record lives in.
112
+ */
113
+ interface AgeRoute {
114
+ /** Store for records older than the cutoff. */
115
+ readonly cold: NoydbStore;
116
+ /** Days after last modification before a record is cold-eligible. */
117
+ readonly coldAfterDays: number;
118
+ /**
119
+ * Collections that participate in age tiering.
120
+ * Empty array or omitted = all user collections (excluding `_` prefixed).
121
+ */
122
+ readonly collections?: string[];
123
+ }
124
+ /**
125
+ * Options for `routeStore()` — the store multiplexer.
126
+ *
127
+ * At minimum, provide a `default` store. All other fields are optional
128
+ * extensions for specific routing scenarios (blobs → S3, geographic sharding,
129
+ * age-based tiering, etc.).
130
+ */
131
+ interface RouteStoreOptions {
132
+ /** Default store for all unmatched operations. */
133
+ readonly default: NoydbStore;
134
+ /**
135
+ * Route blob chunk data to a separate store.
136
+ * - Pass a `NoydbStore` for simple prefix routing (all chunks → that store).
137
+ * - Pass `{ small?, large, threshold? }` for size-tiered routing.
138
+ */
139
+ readonly blobs?: NoydbStore | BlobStoreRoute;
140
+ /** Route all blob metadata (index, slots, versions) to the blobs store too. Default: false. */
141
+ readonly routeBlobMeta?: boolean;
142
+ /** Route specific user collections to dedicated stores. */
143
+ readonly routes?: Record<string, NoydbStore>;
144
+ /** Route by vault name (prefix patterns, e.g. `'EU-'`). */
145
+ readonly vaultRoutes?: Record<string, NoydbStore>;
146
+ /**
147
+ * Age-based tiering: records older than `coldAfterDays` are read from
148
+ * the cold store. A background `compact()` method migrates them.
149
+ */
150
+ readonly age?: AgeRoute;
151
+ /**
152
+ * Content-aware blob routing.
153
+ * Route blob chunks by MIME type glob pattern. The MIME type is stored
154
+ * in `BlobObject` and matched at read time via `storeHint`.
155
+ */
156
+ readonly blobRoutes?: Record<string, NoydbStore>;
157
+ /**
158
+ * Blob lifecycle policies.
159
+ * Evaluated during `compact()`.
160
+ */
161
+ readonly blobLifecycle?: BlobLifecyclePolicy;
162
+ /**
163
+ * Quota-aware overflow.
164
+ * When the default store's usage exceeds the threshold, new writes
165
+ * overflow to the specified store.
166
+ */
167
+ readonly overflow?: NoydbStore;
168
+ /**
169
+ * Quota threshold (0-1). Default: 0.8 (overflow at 80% usage).
170
+ * Only effective when `overflow` is set.
171
+ */
172
+ readonly quotaThreshold?: number;
173
+ }
174
+ /**
175
+ * Named route that can be overridden or suspended at runtime.
176
+ *
177
+ * Built-in names: `'default'`, `'blobs'`, `'cold'`.
178
+ * Custom names: any collection name from `routes`, any vault prefix from
179
+ * `vaultRoutes`, or any sync target label.
180
+ */
181
+ type OverrideTarget = 'default' | 'blobs' | 'cold' | (string & {});
182
+ /**
183
+ * Options for `RoutedNoydbStore.override()`.
184
+ *
185
+ * Controls whether the new store is pre-populated with data from the
186
+ * original store before the switch takes effect.
187
+ */
188
+ interface OverrideOptions {
189
+ /**
190
+ * Hydrate the override store from the original before activating.
191
+ * - `true` — copy all data for all vaults.
192
+ * - `string[]` — copy only named collections.
193
+ * Makes `override()` async — returns a Promise.
194
+ */
195
+ hydrate?: boolean | string[];
196
+ }
197
+ /**
198
+ * Options for `RoutedNoydbStore.suspend()`.
199
+ *
200
+ * A suspended route becomes a null store: reads return null/[], writes
201
+ * are dropped (or buffered if `queue: true`). Useful for maintenance
202
+ * windows or restricted-network scenarios.
203
+ */
204
+ interface SuspendOptions {
205
+ /**
206
+ * Buffer write operations during suspension. On `resume()`, queued
207
+ * writes are replayed against the restored store.
208
+ */
209
+ queue?: boolean;
210
+ /**
211
+ * Maximum queued operations. When exceeded, oldest entries are dropped.
212
+ * Default: 10_000.
213
+ */
214
+ maxQueueSize?: number;
215
+ }
216
+ /**
217
+ * Snapshot of the current override and suspend state of a `RoutedNoydbStore`.
218
+ * Returned by `routeStatus()` for diagnostics and health dashboards.
219
+ */
220
+ interface RouteStatus {
221
+ /** Active overrides: route name → override store name. */
222
+ readonly overrides: Record<string, string>;
223
+ /** Currently suspended routes. */
224
+ readonly suspended: string[];
225
+ /** Queued writes per suspended route (only for routes suspended with `queue: true`). */
226
+ readonly queued: Record<string, number>;
227
+ }
228
+ /**
229
+ * Extended `NoydbStore` returned by `routeStore()`.
230
+ *
231
+ * Satisfies the full `NoydbStore` contract plus adds runtime control
232
+ * methods for overriding, suspending, and inspecting routes.
233
+ */
234
+ interface RoutedNoydbStore extends NoydbStore {
235
+ /**
236
+ * Migrate records older than the age cutoff from the hot store to the
237
+ * cold store. Only applies when `age` is configured. Returns the number
238
+ * of records migrated.
239
+ */
240
+ compact(vault: string): Promise<number>;
241
+ /**
242
+ * Override a named route at runtime.
243
+ *
244
+ * The override persists until `clearOverride()` is called or the
245
+ * instance is closed. In-flight operations complete on the original
246
+ * store; new operations use the override.
247
+ *
248
+ * Options:
249
+ * - `hydrate: true` — async: copies all data from the original store
250
+ * into the override before activating the switch.
251
+ * - `hydrate: ['invoices', 'clients']` — copies only named collections.
252
+ *
253
+ * Use cases:
254
+ * - Shared device: `await store.override('default', memory(), { hydrate: true })`
255
+ * - Restricted network: `store.override('blobs', localFile(...))`
256
+ */
257
+ override(route: OverrideTarget, store: NoydbStore, opts?: OverrideOptions): void | Promise<void>;
258
+ /** Clear a runtime override, reverting to the original store. */
259
+ clearOverride(route: OverrideTarget): void;
260
+ /**
261
+ * Suspend a route entirely. Operations to suspended stores become
262
+ * no-ops (puts silently dropped, gets return null, lists return []).
263
+ *
264
+ * Options:
265
+ * - `queue: true` — buffer write operations (put/delete) during
266
+ * suspension. When `resume()` is called, queued writes are replayed
267
+ * against the restored store.
268
+ *
269
+ * Returns a `SuspendHandle` when `queue: true`, for inspecting queue state.
270
+ */
271
+ suspend(route: OverrideTarget, opts?: SuspendOptions): void;
272
+ /**
273
+ * Resume a previously suspended route.
274
+ * If the route was suspended with `queue: true`, replays queued writes.
275
+ * Returns the number of replayed operations.
276
+ */
277
+ resume(route: OverrideTarget): Promise<number>;
278
+ /** Snapshot the current override/suspend state for diagnostics. */
279
+ routeStatus(): RouteStatus;
280
+ }
281
+ /**
282
+ * Create a store multiplexer that dispatches operations to different backends
283
+ * based on collection type, record size, record age, vault prefix, or
284
+ * runtime overrides.
285
+ *
286
+ * ```ts
287
+ * const store = routeStore({
288
+ * default: dynamo({ table: 'myapp' }),
289
+ * blobs: s3({ bucket: 'myapp-blobs' }),
290
+ * routes: { auditLog: s3({ bucket: 'myapp-audit' }) },
291
+ * })
292
+ * ```
293
+ *
294
+ * The returned store satisfies `NoydbStore` and can be passed directly to
295
+ * `createNoydb({ store })`. It also exposes additional methods
296
+ * (`override`, `suspend`, `resume`, `routeStatus`, `compact`) for runtime
297
+ * control and maintenance.
298
+ */
299
+ declare function routeStore(opts: RouteStoreOptions): RoutedNoydbStore;
300
+
301
+ /**
302
+ * Store middleware — composable interceptors for NoydbStore.
303
+ *
304
+ * ```ts
305
+ * const resilient = wrapStore(
306
+ * dynamo({ table: 'myapp' }),
307
+ * withRetry({ maxRetries: 3 }),
308
+ * withLogging({ level: 'debug' }),
309
+ * withCache({ ttlMs: 60_000 }),
310
+ * )
311
+ * ```
312
+ *
313
+ * Each middleware is `(next: NoydbStore) => NoydbStore`. They compose
314
+ * left-to-right: first middleware is outermost (processes requests first,
315
+ * responses last).
316
+ *
317
+ * @module
318
+ */
319
+
320
+ /**
321
+ * A store middleware function.
322
+ *
323
+ * Takes the next store in the chain and returns a wrapped store. Middlewares
324
+ * compose left-to-right via `wrapStore()`: the first argument is outermost
325
+ * (first to intercept requests, last to process responses).
326
+ *
327
+ * ```ts
328
+ * const mw: StoreMiddleware = (next) => ({
329
+ * ...next,
330
+ * async get(vault, collection, id) {
331
+ * console.log('get', id)
332
+ * return next.get(vault, collection, id)
333
+ * },
334
+ * })
335
+ * ```
336
+ */
337
+ type StoreMiddleware = (next: NoydbStore) => NoydbStore;
338
+ /**
339
+ * Wrap a store with one or more middlewares. Middlewares compose left-to-right.
340
+ */
341
+ declare function wrapStore(store: NoydbStore, ...middlewares: StoreMiddleware[]): NoydbStore;
342
+ /** Options for `withRetry()`. */
343
+ interface RetryOptions {
344
+ /** Maximum retry attempts. Default: 3. */
345
+ maxRetries?: number;
346
+ /** Base backoff delay in ms. Default: 500. */
347
+ backoffMs?: number;
348
+ /** Jitter factor (0-1). Adds random delay up to `backoffMs * jitter`. Default: 0.3. */
349
+ jitter?: number;
350
+ /** Only retry on these error codes. Default: retry all errors. */
351
+ retryOn?: string[];
352
+ }
353
+ /**
354
+ * Middleware that retries failed store operations with exponential backoff
355
+ * and optional jitter. Useful for transient network errors on DynamoDB/S3.
356
+ *
357
+ * ```ts
358
+ * wrapStore(dynamo({ table: 'myapp' }), withRetry({ maxRetries: 5, retryOn: ['NETWORK_ERROR'] }))
359
+ * ```
360
+ */
361
+ declare function withRetry(opts?: RetryOptions): StoreMiddleware;
362
+ /** Log level for `withLogging()`. Maps to standard console method names. */
363
+ type LogLevel = 'debug' | 'info' | 'warn' | 'error';
364
+ /** Options for `withLogging()`. */
365
+ interface LoggingOptions {
366
+ /** Minimum log level. Default: 'info'. */
367
+ level?: LogLevel;
368
+ /** Custom logger. Default: console. */
369
+ logger?: {
370
+ debug(msg: string, ...args: unknown[]): void;
371
+ info(msg: string, ...args: unknown[]): void;
372
+ warn(msg: string, ...args: unknown[]): void;
373
+ error(msg: string, ...args: unknown[]): void;
374
+ };
375
+ /** Log the data payload (envelope contents). Default: false (privacy). */
376
+ logData?: boolean;
377
+ }
378
+ /**
379
+ * Middleware that logs every store operation with its method name, arguments,
380
+ * and elapsed duration. Privacy-safe by default: envelope payloads are not
381
+ * logged unless `logData: true` is set.
382
+ */
383
+ declare function withLogging(opts?: LoggingOptions): StoreMiddleware;
384
+ /**
385
+ * Data emitted to `MetricsOptions.onOperation` after every store call.
386
+ *
387
+ * Carries method name, vault/collection/id context, elapsed duration,
388
+ * and success/failure status. Wire this into your metrics pipeline
389
+ * (DataDog, Prometheus, CloudWatch) to get per-operation latency histograms.
390
+ */
391
+ interface StoreOperation {
392
+ method: 'get' | 'put' | 'delete' | 'list' | 'loadAll' | 'saveAll';
393
+ vault: string;
394
+ collection?: string;
395
+ id?: string;
396
+ durationMs: number;
397
+ success: boolean;
398
+ error?: Error;
399
+ }
400
+ /** Options for `withMetrics()`. */
401
+ interface MetricsOptions {
402
+ /** Called after every store operation. */
403
+ onOperation: (op: StoreOperation) => void;
404
+ }
405
+ /**
406
+ * Middleware that calls `onOperation` after every store method with timing
407
+ * and success/failure data. Designed for low-overhead integration with
408
+ * metrics systems — the callback is synchronous and fire-and-forget.
409
+ */
410
+ declare function withMetrics(opts: MetricsOptions): StoreMiddleware;
411
+ /**
412
+ * Options for `withCircuitBreaker()`.
413
+ *
414
+ * The circuit breaker moves through three states:
415
+ * - `closed`: normal operation.
416
+ * - `open`: store is failing; all calls return fallback values immediately.
417
+ * - `half-open`: one probe call after `resetTimeoutMs` — success closes, failure re-opens.
418
+ */
419
+ interface CircuitBreakerOptions {
420
+ /** Number of consecutive failures before opening the circuit. Default: 5. */
421
+ failureThreshold?: number;
422
+ /** Time in ms before attempting to half-open the circuit. Default: 30_000. */
423
+ resetTimeoutMs?: number;
424
+ /** Called when the circuit opens (store becomes unavailable). */
425
+ onOpen?: () => void;
426
+ /** Called when the circuit closes (store recovers). */
427
+ onClose?: () => void;
428
+ }
429
+ /**
430
+ * Middleware that implements the circuit-breaker pattern.
431
+ *
432
+ * When the wrapped store fails `failureThreshold` consecutive times, the
433
+ * circuit opens: subsequent calls return safe fallback values (`null`, `[]`,
434
+ * `{}`) without hitting the store. After `resetTimeoutMs` the circuit
435
+ * half-opens and allows one probe — success closes the circuit, failure
436
+ * keeps it open. Pair with `withRetry` to handle transient errors before
437
+ * they trip the circuit.
438
+ */
439
+ declare function withCircuitBreaker(opts?: CircuitBreakerOptions): StoreMiddleware;
440
+ /**
441
+ * Options for `withCache()`.
442
+ *
443
+ * The cache is a read-through LRU that caches individual record fetches
444
+ * (`get`). Writes (`put`, `delete`) invalidate the relevant cache entry
445
+ * immediately. `list`, `loadAll`, and `saveAll` bypass the cache.
446
+ *
447
+ * Named `StoreCacheOptions` to distinguish from `CacheOptions` in
448
+ * `@noy-db/hub/collection`, which controls the in-memory decrypted-record LRU.
449
+ */
450
+ interface StoreCacheOptions {
451
+ /** Maximum cached entries. Default: 500. */
452
+ maxEntries?: number;
453
+ /** Cache TTL in ms. Default: 60_000 (1 minute). 0 = no expiry. */
454
+ ttlMs?: number;
455
+ }
456
+ /**
457
+ * Middleware that adds a read-through LRU cache for `get()` calls.
458
+ *
459
+ * Reduces latency for frequently-read records (e.g. lookup tables, user
460
+ * profiles) by serving repeat reads from memory. Because NOYDB records are
461
+ * encrypted at rest, caching envelopes is safe — the cache holds ciphertext,
462
+ * not plaintext. For write-heavy workloads, the cache provides little benefit
463
+ * and should be omitted to avoid the invalidation overhead.
464
+ */
465
+ declare function withCache(opts?: StoreCacheOptions): StoreMiddleware;
466
+ interface HealthCheckOptions {
467
+ /** Ping interval in ms. Default: 30_000. */
468
+ checkIntervalMs?: number;
469
+ /** Suspend after N consecutive ping failures. Default: 3. */
470
+ suspendAfterFailures?: number;
471
+ /** Resume after N consecutive ping successes. Default: 1. */
472
+ resumeAfterSuccess?: number;
473
+ /** Called when the store is auto-suspended. */
474
+ onSuspend?: () => void;
475
+ /** Called when the store is auto-resumed. */
476
+ onResume?: () => void;
477
+ /**
478
+ * Custom health check. Default: calls `store.ping()` if available,
479
+ * otherwise attempts a `list()` on a sentinel collection.
480
+ */
481
+ check?: () => Promise<boolean>;
482
+ }
483
+ /**
484
+ * Auto-suspends a store when health checks fail, auto-resumes when they recover.
485
+ *
486
+ * When suspended, `get` returns null, `put`/`delete` are no-ops, `list` returns [].
487
+ * This is identical to the `NullStore` behavior from `routeStore.suspend()`.
488
+ */
489
+ declare function withHealthCheck(opts?: HealthCheckOptions): StoreMiddleware;
490
+
491
+ export { type AgeRoute, type BlobLifecyclePolicy, type BlobStoreRoute, type CircuitBreakerOptions, type HealthCheckOptions, type LogLevel, type LoggingOptions, type MetricsOptions, type OverrideOptions, type OverrideTarget, type RetryOptions, type RouteStatus, type RouteStoreOptions, type RoutedNoydbStore, type StoreCacheOptions, type StoreMiddleware, type StoreOperation, type SuspendOptions, type WrapBundleStoreOptions, type WrappedBundleNoydbStore, createBundleStore, routeStore, withCache, withCircuitBreaker, withHealthCheck, withLogging, withMetrics, withRetry, wrapBundleStore, wrapStore };
@@ -0,0 +1,34 @@
1
+ import {
2
+ createBundleStore,
3
+ routeStore,
4
+ withCache,
5
+ withCircuitBreaker,
6
+ withHealthCheck,
7
+ withLogging,
8
+ withMetrics,
9
+ withRetry,
10
+ wrapBundleStore,
11
+ wrapStore
12
+ } from "../chunk-USKYUS74.js";
13
+ import {
14
+ BUNDLE_STORE_POLICY,
15
+ INDEXED_STORE_POLICY,
16
+ SyncScheduler
17
+ } from "../chunk-2QR2PQTT.js";
18
+ import "../chunk-ACLDOTNQ.js";
19
+ export {
20
+ BUNDLE_STORE_POLICY,
21
+ INDEXED_STORE_POLICY,
22
+ SyncScheduler,
23
+ createBundleStore,
24
+ routeStore,
25
+ withCache,
26
+ withCircuitBreaker,
27
+ withHealthCheck,
28
+ withLogging,
29
+ withMetrics,
30
+ withRetry,
31
+ wrapBundleStore,
32
+ wrapStore
33
+ };
34
+ //# sourceMappingURL=index.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"sources":[],"sourcesContent":[],"mappings":"","names":[]}
@@ -0,0 +1,110 @@
1
+ /**
2
+ * CRDT state types, merge logic, and build helpers.
3
+ * per-collection CRDT mode: 'lww-map' | 'rga' | 'yjs'
4
+ *
5
+ * The encrypted envelope wraps the CRDT state (not the resolved snapshot).
6
+ * Adapters only ever see ciphertext. `collection.get(id)` returns the
7
+ * resolved snapshot; `collection.getRaw(id)` returns the full CRDT state.
8
+ */
9
+ /** Per-collection CRDT mode. */
10
+ type CrdtMode = 'lww-map' | 'rga' | 'yjs';
11
+ /**
12
+ * Per-field last-write-wins registers.
13
+ * Each field carries its latest value and the ISO timestamp of the last write.
14
+ * Merge: for each field, keep the entry with the lexicographically higher `ts`.
15
+ */
16
+ interface LwwMapState {
17
+ readonly _crdt: 'lww-map';
18
+ readonly fields: Record<string, {
19
+ readonly v: unknown;
20
+ readonly ts: string;
21
+ }>;
22
+ }
23
+ /**
24
+ * Simplified Replicated Growable Array.
25
+ * Items are assigned stable NID (noy-db id) strings on first insertion.
26
+ * Deleted items are tracked as tombstones so concurrent removals commute.
27
+ *
28
+ * The resolved snapshot is the ordered list of non-tombstoned `v` values.
29
+ */
30
+ interface RgaState {
31
+ readonly _crdt: 'rga';
32
+ readonly items: ReadonlyArray<{
33
+ readonly nid: string;
34
+ readonly v: unknown;
35
+ }>;
36
+ readonly tombstones: readonly string[];
37
+ }
38
+ /**
39
+ * Yjs binary state marker. `update` is base64(Y.encodeStateAsUpdate()).
40
+ * Core stores and retrieves the blob opaquely. `@noy-db/yjs` is responsible
41
+ * for encoding, decoding, and merging via `Y.mergeUpdates`.
42
+ * Core falls back to last-write-wins (higher `_v`) for conflict resolution.
43
+ */
44
+ interface YjsState {
45
+ readonly _crdt: 'yjs';
46
+ /** base64-encoded Y.encodeStateAsUpdate() bytes. */
47
+ readonly update: string;
48
+ }
49
+ type CrdtState = LwwMapState | RgaState | YjsState;
50
+ /**
51
+ * Resolve a CRDT state into the end-user record snapshot.
52
+ *
53
+ * - `lww-map` → `Record<string, unknown>` (field values extracted from registers)
54
+ * - `rga` → `unknown[]` (non-tombstoned items in insertion order)
55
+ * - `yjs` → `string` (base64 update blob; use @noy-db/yjs for a Y.Doc)
56
+ */
57
+ declare function resolveCrdtSnapshot(state: CrdtState): unknown;
58
+ /**
59
+ * Merge two CRDT states produced by concurrent writes.
60
+ * Called by the collection-level conflict resolver registered with SyncEngine.
61
+ *
62
+ * For `yjs`: core cannot merge Yjs without importing the `yjs` package.
63
+ * The caller must handle that case by falling back to the higher-`_v` envelope.
64
+ */
65
+ declare function mergeCrdtStates(a: CrdtState, b: CrdtState): CrdtState;
66
+ /**
67
+ * Build (or update) an lww-map state from a new record.
68
+ *
69
+ * All fields in the new record win at timestamp `now`.
70
+ * Fields present in the existing state but absent from the new record
71
+ * are preserved (they were written by another device).
72
+ */
73
+ declare function buildLwwMapState(record: Record<string, unknown>, existing: LwwMapState | undefined, now: string): LwwMapState;
74
+ /**
75
+ * Build (or update) an RGA state from a new array.
76
+ *
77
+ * Existing items are matched to new elements by deep-equality of their `v`.
78
+ * Unmatched existing items are tombstoned. New elements that have no existing
79
+ * match get a fresh NID via `generateNid()`.
80
+ */
81
+ declare function buildRgaState(arr: unknown[], existing: RgaState | undefined, generateNid: () => string): RgaState;
82
+
83
+ /**
84
+ * Strategy seam between core Collection and the optional CRDT
85
+ * subsystem. Core imports `CrdtStrategy` as a TYPE-ONLY symbol and
86
+ * `NO_CRDT` as a minimal runtime stub.
87
+ *
88
+ * The state-construction / merge / snapshot-resolution helpers —
89
+ * `buildLwwMapState`, `buildRgaState`, `mergeCrdtStates`,
90
+ * `resolveCrdtSnapshot` — are only reachable from `withCrdt()` in
91
+ * `./active.ts`, which is only exported through the `@noy-db/hub/crdt`
92
+ * subpath. Consumers without CRDT mode configured never pull the
93
+ * ~221 LOC into their bundle.
94
+ *
95
+ * @internal
96
+ */
97
+
98
+ /**
99
+ * Seam interface. `@internal`.
100
+ *
101
+ * @internal
102
+ */
103
+ interface CrdtStrategy {
104
+ buildLwwMapState(record: Record<string, unknown>, previous: LwwMapState | undefined, now: string): LwwMapState;
105
+ buildRgaState(items: readonly unknown[], previous: RgaState | undefined, idGen: () => string): RgaState;
106
+ mergeCrdtStates(local: CrdtState, remote: CrdtState): CrdtState;
107
+ resolveCrdtSnapshot(state: CrdtState): unknown;
108
+ }
109
+
110
+ export { type CrdtStrategy as C, type LwwMapState as L, type RgaState as R, type YjsState as Y, type CrdtMode as a, type CrdtState as b, buildLwwMapState as c, buildRgaState as d, mergeCrdtStates as m, resolveCrdtSnapshot as r };