@bandeira-tech/b3nd-save 0.8.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.
Files changed (177) hide show
  1. package/LICENSE +21 -0
  2. package/esm/_dnt.shims.d.ts +2 -0
  3. package/esm/_dnt.shims.d.ts.map +1 -0
  4. package/esm/_dnt.shims.js +57 -0
  5. package/esm/byte-entity-shim.d.ts +47 -0
  6. package/esm/byte-entity-shim.d.ts.map +1 -0
  7. package/esm/byte-entity-shim.js +138 -0
  8. package/esm/clients/mod.d.ts +15 -0
  9. package/esm/clients/mod.d.ts.map +1 -0
  10. package/esm/clients/mod.js +14 -0
  11. package/esm/clients/save-client.d.ts +87 -0
  12. package/esm/clients/save-client.d.ts.map +1 -0
  13. package/esm/clients/save-client.js +174 -0
  14. package/esm/deps/jsr.io/@bandeira-tech/b3nd-core/0.22.0/mod.d.ts +40 -0
  15. package/esm/deps/jsr.io/@bandeira-tech/b3nd-core/0.22.0/mod.d.ts.map +1 -0
  16. package/esm/deps/jsr.io/@bandeira-tech/b3nd-core/0.22.0/mod.js +31 -0
  17. package/esm/deps/jsr.io/@bandeira-tech/b3nd-core/0.22.0/src/client-console/client.d.ts +30 -0
  18. package/esm/deps/jsr.io/@bandeira-tech/b3nd-core/0.22.0/src/client-console/client.d.ts.map +1 -0
  19. package/esm/deps/jsr.io/@bandeira-tech/b3nd-core/0.22.0/src/client-console/client.js +70 -0
  20. package/esm/deps/jsr.io/@bandeira-tech/b3nd-core/0.22.0/src/encoding/encoding.d.ts +16 -0
  21. package/esm/deps/jsr.io/@bandeira-tech/b3nd-core/0.22.0/src/encoding/encoding.d.ts.map +1 -0
  22. package/esm/deps/jsr.io/@bandeira-tech/b3nd-core/0.22.0/src/encoding/encoding.js +50 -0
  23. package/esm/deps/jsr.io/@bandeira-tech/b3nd-core/0.22.0/src/encrypt/mod.d.ts +235 -0
  24. package/esm/deps/jsr.io/@bandeira-tech/b3nd-core/0.22.0/src/encrypt/mod.d.ts.map +1 -0
  25. package/esm/deps/jsr.io/@bandeira-tech/b3nd-core/0.22.0/src/encrypt/mod.js +619 -0
  26. package/esm/deps/jsr.io/@bandeira-tech/b3nd-core/0.22.0/src/functional-client/functional-client.d.ts +43 -0
  27. package/esm/deps/jsr.io/@bandeira-tech/b3nd-core/0.22.0/src/functional-client/functional-client.d.ts.map +1 -0
  28. package/esm/deps/jsr.io/@bandeira-tech/b3nd-core/0.22.0/src/functional-client/functional-client.js +54 -0
  29. package/esm/deps/jsr.io/@bandeira-tech/b3nd-core/0.22.0/src/match-pattern/match-pattern.d.ts +47 -0
  30. package/esm/deps/jsr.io/@bandeira-tech/b3nd-core/0.22.0/src/match-pattern/match-pattern.d.ts.map +1 -0
  31. package/esm/deps/jsr.io/@bandeira-tech/b3nd-core/0.22.0/src/match-pattern/match-pattern.js +134 -0
  32. package/esm/deps/jsr.io/@bandeira-tech/b3nd-core/0.22.0/src/network/decorators.d.ts +20 -0
  33. package/esm/deps/jsr.io/@bandeira-tech/b3nd-core/0.22.0/src/network/decorators.d.ts.map +1 -0
  34. package/esm/deps/jsr.io/@bandeira-tech/b3nd-core/0.22.0/src/network/decorators.js +34 -0
  35. package/esm/deps/jsr.io/@bandeira-tech/b3nd-core/0.22.0/src/network/network.d.ts +46 -0
  36. package/esm/deps/jsr.io/@bandeira-tech/b3nd-core/0.22.0/src/network/network.d.ts.map +1 -0
  37. package/esm/deps/jsr.io/@bandeira-tech/b3nd-core/0.22.0/src/network/network.js +131 -0
  38. package/esm/deps/jsr.io/@bandeira-tech/b3nd-core/0.22.0/src/network/peer.d.ts +27 -0
  39. package/esm/deps/jsr.io/@bandeira-tech/b3nd-core/0.22.0/src/network/peer.d.ts.map +1 -0
  40. package/esm/deps/jsr.io/@bandeira-tech/b3nd-core/0.22.0/src/network/peer.js +25 -0
  41. package/esm/deps/jsr.io/@bandeira-tech/b3nd-core/0.22.0/src/network/policies/flood.d.ts +59 -0
  42. package/esm/deps/jsr.io/@bandeira-tech/b3nd-core/0.22.0/src/network/policies/flood.d.ts.map +1 -0
  43. package/esm/deps/jsr.io/@bandeira-tech/b3nd-core/0.22.0/src/network/policies/flood.js +188 -0
  44. package/esm/deps/jsr.io/@bandeira-tech/b3nd-core/0.22.0/src/network/policies/path-vector.d.ts +35 -0
  45. package/esm/deps/jsr.io/@bandeira-tech/b3nd-core/0.22.0/src/network/policies/path-vector.d.ts.map +1 -0
  46. package/esm/deps/jsr.io/@bandeira-tech/b3nd-core/0.22.0/src/network/policies/path-vector.js +57 -0
  47. package/esm/deps/jsr.io/@bandeira-tech/b3nd-core/0.22.0/src/network/policies/tell-and-read.d.ts +117 -0
  48. package/esm/deps/jsr.io/@bandeira-tech/b3nd-core/0.22.0/src/network/policies/tell-and-read.d.ts.map +1 -0
  49. package/esm/deps/jsr.io/@bandeira-tech/b3nd-core/0.22.0/src/network/policies/tell-and-read.js +125 -0
  50. package/esm/deps/jsr.io/@bandeira-tech/b3nd-core/0.22.0/src/network/types.d.ts +112 -0
  51. package/esm/deps/jsr.io/@bandeira-tech/b3nd-core/0.22.0/src/network/types.d.ts.map +1 -0
  52. package/esm/deps/jsr.io/@bandeira-tech/b3nd-core/0.22.0/src/network/types.js +21 -0
  53. package/esm/deps/jsr.io/@bandeira-tech/b3nd-core/0.22.0/src/observe-emitter/observe-emitter.d.ts +35 -0
  54. package/esm/deps/jsr.io/@bandeira-tech/b3nd-core/0.22.0/src/observe-emitter/observe-emitter.d.ts.map +1 -0
  55. package/esm/deps/jsr.io/@bandeira-tech/b3nd-core/0.22.0/src/observe-emitter/observe-emitter.js +106 -0
  56. package/esm/deps/jsr.io/@bandeira-tech/b3nd-core/0.22.0/src/rig/connection.d.ts +88 -0
  57. package/esm/deps/jsr.io/@bandeira-tech/b3nd-core/0.22.0/src/rig/connection.d.ts.map +1 -0
  58. package/esm/deps/jsr.io/@bandeira-tech/b3nd-core/0.22.0/src/rig/connection.js +86 -0
  59. package/esm/deps/jsr.io/@bandeira-tech/b3nd-core/0.22.0/src/rig/events.d.ts +83 -0
  60. package/esm/deps/jsr.io/@bandeira-tech/b3nd-core/0.22.0/src/rig/events.d.ts.map +1 -0
  61. package/esm/deps/jsr.io/@bandeira-tech/b3nd-core/0.22.0/src/rig/events.js +115 -0
  62. package/esm/deps/jsr.io/@bandeira-tech/b3nd-core/0.22.0/src/rig/hooks.d.ts +164 -0
  63. package/esm/deps/jsr.io/@bandeira-tech/b3nd-core/0.22.0/src/rig/hooks.d.ts.map +1 -0
  64. package/esm/deps/jsr.io/@bandeira-tech/b3nd-core/0.22.0/src/rig/hooks.js +67 -0
  65. package/esm/deps/jsr.io/@bandeira-tech/b3nd-core/0.22.0/src/rig/identity.d.ts +99 -0
  66. package/esm/deps/jsr.io/@bandeira-tech/b3nd-core/0.22.0/src/rig/identity.d.ts.map +1 -0
  67. package/esm/deps/jsr.io/@bandeira-tech/b3nd-core/0.22.0/src/rig/identity.js +190 -0
  68. package/esm/deps/jsr.io/@bandeira-tech/b3nd-core/0.22.0/src/rig/operation-handle.d.ts +185 -0
  69. package/esm/deps/jsr.io/@bandeira-tech/b3nd-core/0.22.0/src/rig/operation-handle.d.ts.map +1 -0
  70. package/esm/deps/jsr.io/@bandeira-tech/b3nd-core/0.22.0/src/rig/operation-handle.js +103 -0
  71. package/esm/deps/jsr.io/@bandeira-tech/b3nd-core/0.22.0/src/rig/reactions.d.ts +58 -0
  72. package/esm/deps/jsr.io/@bandeira-tech/b3nd-core/0.22.0/src/rig/reactions.d.ts.map +1 -0
  73. package/esm/deps/jsr.io/@bandeira-tech/b3nd-core/0.22.0/src/rig/reactions.js +64 -0
  74. package/esm/deps/jsr.io/@bandeira-tech/b3nd-core/0.22.0/src/rig/rig.d.ts +295 -0
  75. package/esm/deps/jsr.io/@bandeira-tech/b3nd-core/0.22.0/src/rig/rig.d.ts.map +1 -0
  76. package/esm/deps/jsr.io/@bandeira-tech/b3nd-core/0.22.0/src/rig/rig.js +898 -0
  77. package/esm/deps/jsr.io/@bandeira-tech/b3nd-core/0.22.0/src/rig/types.d.ts +167 -0
  78. package/esm/deps/jsr.io/@bandeira-tech/b3nd-core/0.22.0/src/rig/types.d.ts.map +1 -0
  79. package/esm/deps/jsr.io/@bandeira-tech/b3nd-core/0.22.0/src/rig/types.js +5 -0
  80. package/esm/deps/jsr.io/@bandeira-tech/b3nd-core/0.22.0/src/types/types.d.ts +278 -0
  81. package/esm/deps/jsr.io/@bandeira-tech/b3nd-core/0.22.0/src/types/types.d.ts.map +1 -0
  82. package/esm/deps/jsr.io/@bandeira-tech/b3nd-core/0.22.0/src/types/types.js +89 -0
  83. package/esm/dispatch.d.ts +35 -0
  84. package/esm/dispatch.d.ts.map +1 -0
  85. package/esm/dispatch.js +40 -0
  86. package/esm/elasticsearch/mod.d.ts +31 -0
  87. package/esm/elasticsearch/mod.d.ts.map +1 -0
  88. package/esm/elasticsearch/mod.js +8 -0
  89. package/esm/elasticsearch/store.d.ts +44 -0
  90. package/esm/elasticsearch/store.d.ts.map +1 -0
  91. package/esm/elasticsearch/store.js +213 -0
  92. package/esm/entity-store.d.ts +106 -0
  93. package/esm/entity-store.d.ts.map +1 -0
  94. package/esm/entity-store.js +46 -0
  95. package/esm/entity.d.ts +125 -0
  96. package/esm/entity.d.ts.map +1 -0
  97. package/esm/entity.js +66 -0
  98. package/esm/errors.d.ts +23 -0
  99. package/esm/errors.d.ts.map +1 -0
  100. package/esm/errors.js +25 -0
  101. package/esm/fs/mod.d.ts +28 -0
  102. package/esm/fs/mod.d.ts.map +1 -0
  103. package/esm/fs/mod.js +13 -0
  104. package/esm/fs/store.d.ts +45 -0
  105. package/esm/fs/store.d.ts.map +1 -0
  106. package/esm/fs/store.js +194 -0
  107. package/esm/indexeddb/mod.d.ts +9 -0
  108. package/esm/indexeddb/mod.d.ts.map +1 -0
  109. package/esm/indexeddb/mod.js +8 -0
  110. package/esm/indexeddb/store.d.ts +47 -0
  111. package/esm/indexeddb/store.d.ts.map +1 -0
  112. package/esm/indexeddb/store.js +299 -0
  113. package/esm/ipfs/mod.d.ts +24 -0
  114. package/esm/ipfs/mod.d.ts.map +1 -0
  115. package/esm/ipfs/mod.js +13 -0
  116. package/esm/ipfs/store.d.ts +42 -0
  117. package/esm/ipfs/store.d.ts.map +1 -0
  118. package/esm/ipfs/store.js +197 -0
  119. package/esm/localstorage/mod.d.ts +9 -0
  120. package/esm/localstorage/mod.d.ts.map +1 -0
  121. package/esm/localstorage/mod.js +8 -0
  122. package/esm/localstorage/store.d.ts +45 -0
  123. package/esm/localstorage/store.d.ts.map +1 -0
  124. package/esm/localstorage/store.js +147 -0
  125. package/esm/memory/mod.d.ts +12 -0
  126. package/esm/memory/mod.d.ts.map +1 -0
  127. package/esm/memory/mod.js +11 -0
  128. package/esm/memory/store.d.ts +73 -0
  129. package/esm/memory/store.d.ts.map +1 -0
  130. package/esm/memory/store.js +300 -0
  131. package/esm/mod.d.ts +36 -0
  132. package/esm/mod.d.ts.map +1 -0
  133. package/esm/mod.js +31 -0
  134. package/esm/mongo/mod.d.ts +35 -0
  135. package/esm/mongo/mod.d.ts.map +1 -0
  136. package/esm/mongo/mod.js +8 -0
  137. package/esm/mongo/store.d.ts +42 -0
  138. package/esm/mongo/store.d.ts.map +1 -0
  139. package/esm/mongo/store.js +185 -0
  140. package/esm/package.json +3 -0
  141. package/esm/payload.d.ts +24 -0
  142. package/esm/payload.d.ts.map +1 -0
  143. package/esm/payload.js +30 -0
  144. package/esm/postgres/columns.d.ts +33 -0
  145. package/esm/postgres/columns.d.ts.map +1 -0
  146. package/esm/postgres/columns.js +51 -0
  147. package/esm/postgres/mod.d.ts +19 -0
  148. package/esm/postgres/mod.d.ts.map +1 -0
  149. package/esm/postgres/mod.js +9 -0
  150. package/esm/postgres/store.d.ts +75 -0
  151. package/esm/postgres/store.d.ts.map +1 -0
  152. package/esm/postgres/store.js +364 -0
  153. package/esm/read.d.ts +40 -0
  154. package/esm/read.d.ts.map +1 -0
  155. package/esm/read.js +67 -0
  156. package/esm/s3/mod.d.ts +23 -0
  157. package/esm/s3/mod.d.ts.map +1 -0
  158. package/esm/s3/mod.js +13 -0
  159. package/esm/s3/store.d.ts +46 -0
  160. package/esm/s3/store.d.ts.map +1 -0
  161. package/esm/s3/store.js +183 -0
  162. package/esm/sqlite/mod.d.ts +18 -0
  163. package/esm/sqlite/mod.d.ts.map +1 -0
  164. package/esm/sqlite/mod.js +8 -0
  165. package/esm/sqlite/schema.d.ts +10 -0
  166. package/esm/sqlite/schema.d.ts.map +1 -0
  167. package/esm/sqlite/schema.js +26 -0
  168. package/esm/sqlite/store.d.ts +42 -0
  169. package/esm/sqlite/store.d.ts.map +1 -0
  170. package/esm/sqlite/store.js +184 -0
  171. package/esm/types.d.ts +101 -0
  172. package/esm/types.d.ts.map +1 -0
  173. package/esm/types.js +21 -0
  174. package/esm/url.d.ts +108 -0
  175. package/esm/url.d.ts.map +1 -0
  176. package/esm/url.js +151 -0
  177. package/package.json +93 -0
package/esm/types.d.ts ADDED
@@ -0,0 +1,101 @@
1
+ /**
2
+ * Local Store types for b3nd-save.
3
+ *
4
+ * The `Store` abstraction is internal to this package. `SaveClient`
5
+ * wraps a `Store` (or `EntityStore`) and exposes a
6
+ * `ProtocolInterfaceNode` to the rest of b3nd — outside the client,
7
+ * nothing else in the framework sees a `Store`.
8
+ *
9
+ * Stores are opaque byte storage: payloads are bytes in, bytes out.
10
+ * The payload type is the `Uint8Array | ReadableStream<Uint8Array>`
11
+ * union so callers and backends can avoid materializing large
12
+ * payloads when both sides know how to stream — same shape `fetch`
13
+ * already uses for request/response bodies. Backends that have no
14
+ * native streaming path collect the stream to bytes on write and
15
+ * return `Uint8Array` on read. Backends with native streaming
16
+ * (filesystem, S3, IPFS) keep streams end-to-end.
17
+ *
18
+ * Cross-cutting types (`Output`, `ProtocolInterfaceNode`,
19
+ * `DeleteResult`, `StatusResult`) still come from b3nd-core.
20
+ */
21
+ import type { B3ndError, DeleteResult, Output, StatusResult } from "./deps/jsr.io/@bandeira-tech/b3nd-core/0.22.0/src/types/types.js";
22
+ /**
23
+ * Payload type accepted by `write` and produced by `read`.
24
+ *
25
+ * A backend may accept either shape on write and is free to return
26
+ * either shape on read — pick whichever avoids buffering when
27
+ * possible. Callers that always want bytes can collect with
28
+ * `new Response(payload).bytes()` or the equivalent helper.
29
+ */
30
+ export type StorePayload = Uint8Array | ReadableStream<Uint8Array>;
31
+ /**
32
+ * Entry for a batch write operation.
33
+ *
34
+ * @example
35
+ * ```typescript
36
+ * await store.write([
37
+ * { uri: "mutable://users/alice", payload: new TextEncoder().encode("alice") },
38
+ * ]);
39
+ * ```
40
+ */
41
+ export interface StoreEntry {
42
+ uri: string;
43
+ payload: StorePayload;
44
+ }
45
+ /**
46
+ * Per-entry result of a write operation.
47
+ *
48
+ * `errorDetail` mirrors `DeleteResult.errorDetail` — callers that want
49
+ * to react to specific failure modes (e.g. `STORAGE_ERROR` from the
50
+ * underlying driver vs. a programmer error from the store layer)
51
+ * should switch on `errorDetail.code` rather than parsing `error`.
52
+ * The `error` string remains for human-readable logs.
53
+ */
54
+ export interface StoreWriteResult {
55
+ success: boolean;
56
+ error?: string;
57
+ errorDetail?: B3ndError;
58
+ }
59
+ /**
60
+ * Optional capability reporting for a Store.
61
+ *
62
+ * Backends declare what they can do so clients can make informed
63
+ * decisions (e.g., wrap deletes + writes in a transaction when
64
+ * `atomicBatch` is true).
65
+ */
66
+ export interface StoreCapabilities {
67
+ /** Whether write + delete within a single call can be made atomic. */
68
+ atomicBatch?: boolean;
69
+ }
70
+ /**
71
+ * Store — the batch-native byte-storage abstraction.
72
+ *
73
+ * Every operation takes arrays and returns per-item results. Each
74
+ * backend optimizes for its technology (Postgres → multi-row INSERT,
75
+ * S3 → parallel PutObject, etc.).
76
+ *
77
+ * The Store knows nothing about protocols, envelopes, message
78
+ * semantics, or content shape. Read returns `Output<StorePayload>`
79
+ * for `fn=read` and `fn=ls&format=full`; `fn=ls&format=uris` returns
80
+ * `string[]`, `fn=count` returns `number`.
81
+ *
82
+ * @example
83
+ * ```typescript
84
+ * import { MemoryStore } from "@bandeira-tech/b3nd-save/memory";
85
+ * const store = new MemoryStore();
86
+ *
87
+ * await store.write([
88
+ * { uri: "mutable://app/config", payload: new TextEncoder().encode("dark") },
89
+ * ]);
90
+ * const [[uri, payload]] = await store.read(["mutable://app/config"]);
91
+ * const bytes = await new Response(payload as StorePayload).bytes();
92
+ * ```
93
+ */
94
+ export interface Store {
95
+ write(entries: StoreEntry[]): Promise<StoreWriteResult[]>;
96
+ read<T = StorePayload>(urls: string[]): Promise<Output<T>[]>;
97
+ delete(uris: string[]): Promise<DeleteResult[]>;
98
+ status(): Promise<StatusResult>;
99
+ capabilities?(): StoreCapabilities;
100
+ }
101
+ //# sourceMappingURL=types.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"types.d.ts","sourceRoot":"","sources":["../src/types.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;;;;;GAmBG;AAEH,OAAO,KAAK,EACV,SAAS,EACT,YAAY,EACZ,MAAM,EACN,YAAY,EACb,MAAM,kEAAkE,CAAC;AAE1E;;;;;;;GAOG;AACH,MAAM,MAAM,YAAY,GAAG,UAAU,GAAG,cAAc,CAAC,UAAU,CAAC,CAAC;AAEnE;;;;;;;;;GASG;AACH,MAAM,WAAW,UAAU;IACzB,GAAG,EAAE,MAAM,CAAC;IACZ,OAAO,EAAE,YAAY,CAAC;CACvB;AAED;;;;;;;;GAQG;AACH,MAAM,WAAW,gBAAgB;IAC/B,OAAO,EAAE,OAAO,CAAC;IACjB,KAAK,CAAC,EAAE,MAAM,CAAC;IACf,WAAW,CAAC,EAAE,SAAS,CAAC;CACzB;AAED;;;;;;GAMG;AACH,MAAM,WAAW,iBAAiB;IAChC,sEAAsE;IACtE,WAAW,CAAC,EAAE,OAAO,CAAC;CACvB;AAED;;;;;;;;;;;;;;;;;;;;;;;GAuBG;AACH,MAAM,WAAW,KAAK;IACpB,KAAK,CAAC,OAAO,EAAE,UAAU,EAAE,GAAG,OAAO,CAAC,gBAAgB,EAAE,CAAC,CAAC;IAC1D,IAAI,CAAC,CAAC,GAAG,YAAY,EAAE,IAAI,EAAE,MAAM,EAAE,GAAG,OAAO,CAAC,MAAM,CAAC,CAAC,CAAC,EAAE,CAAC,CAAC;IAC7D,MAAM,CAAC,IAAI,EAAE,MAAM,EAAE,GAAG,OAAO,CAAC,YAAY,EAAE,CAAC,CAAC;IAChD,MAAM,IAAI,OAAO,CAAC,YAAY,CAAC,CAAC;IAChC,YAAY,CAAC,IAAI,iBAAiB,CAAC;CACpC"}
package/esm/types.js ADDED
@@ -0,0 +1,21 @@
1
+ /**
2
+ * Local Store types for b3nd-save.
3
+ *
4
+ * The `Store` abstraction is internal to this package. `SaveClient`
5
+ * wraps a `Store` (or `EntityStore`) and exposes a
6
+ * `ProtocolInterfaceNode` to the rest of b3nd — outside the client,
7
+ * nothing else in the framework sees a `Store`.
8
+ *
9
+ * Stores are opaque byte storage: payloads are bytes in, bytes out.
10
+ * The payload type is the `Uint8Array | ReadableStream<Uint8Array>`
11
+ * union so callers and backends can avoid materializing large
12
+ * payloads when both sides know how to stream — same shape `fetch`
13
+ * already uses for request/response bodies. Backends that have no
14
+ * native streaming path collect the stream to bytes on write and
15
+ * return `Uint8Array` on read. Backends with native streaming
16
+ * (filesystem, S3, IPFS) keep streams end-to-end.
17
+ *
18
+ * Cross-cutting types (`Output`, `ProtocolInterfaceNode`,
19
+ * `DeleteResult`, `StatusResult`) still come from b3nd-core.
20
+ */
21
+ export {};
package/esm/url.d.ts ADDED
@@ -0,0 +1,108 @@
1
+ /**
2
+ * @module
3
+ * Save-layer locator grammar — parsing and constructing the urls that
4
+ * stores in this package implement.
5
+ *
6
+ * This is **save's contract with its callers**, not a framework-wide
7
+ * standard. b3nd-core treats locators opaquely; it is each client's
8
+ * choice what grammar it accepts. Stores shipped by `@bandeira-tech/b3nd-save`
9
+ * (memory, postgres, mongo, sqlite, fs, ipfs, s3, elasticsearch,
10
+ * localstorage, indexeddb) honor the grammar defined here.
11
+ *
12
+ * A **url** = a uri (the canonical resource identifier) plus a query
13
+ * string of read parameters. The uri is the routing identity used for
14
+ * storage keys and observe-match keys. The query string carries
15
+ * request-time-only directives that shape the response without
16
+ * changing identity.
17
+ *
18
+ * Grammar:
19
+ *
20
+ * <uri>[?fn=<fn>][&<param>=<value>...][&x-<ns>.<key>=<value>...]
21
+ *
22
+ * Reserved `fn` values:
23
+ * - `read` — point read (default for non-trailing-slash uris)
24
+ * - `ls` — list under a prefix (default when uri ends with `/`)
25
+ * - `count` — count of entries under a prefix
26
+ * - `x-*.*` — provider-defined extension functions
27
+ *
28
+ * Standard params (meaningful only for some fns; stores ignore the rest):
29
+ * `limit`, `page`, `cursor`, `sortBy`, `sortOrder`, `pattern`, `format`.
30
+ *
31
+ * Anything matching `x-<ns>.<key>` lands in the `ext` map and is passed
32
+ * opaquely to the executing store. Callers inspect ext entries by
33
+ * their flat string key (e.g. `ext["x-feed.cursor"]`).
34
+ */
35
+ /**
36
+ * Standard read parameters. All are optional; stores interpret the
37
+ * subset that makes sense for the requested fn and throw on the rest.
38
+ */
39
+ export interface ReadParams {
40
+ limit?: number;
41
+ page?: number;
42
+ cursor?: string;
43
+ sortBy?: string;
44
+ sortOrder?: string;
45
+ pattern?: string;
46
+ format?: string;
47
+ }
48
+ /**
49
+ * A parsed url decomposed into routing identity (`uri`), function
50
+ * (`fn`), standard read parameters (`params`), and the `x-*` extension
51
+ * bag (`ext`), plus the structural fields shared with WHATWG URL
52
+ * (`protocol`, `hostname`, `path`, `program`).
53
+ */
54
+ export interface ParsedUrl {
55
+ /** Scheme without trailing `://` (e.g. `"mutable"`, `"b3nd"`). */
56
+ protocol: string;
57
+ /** Authority segment after `protocol://` (may be empty). */
58
+ hostname: string;
59
+ /** Everything after `protocol://<hostname>`. Empty or starts with `/`. */
60
+ path: string;
61
+ /** `protocol://hostname` — the routing root above the path. */
62
+ program: string;
63
+ /** Full routing identity: `program` + `path`. Query is stripped. */
64
+ uri: string;
65
+ /** Reserved fn (`read`/`ls`/`count`) or `x-<ns>.<name>` extension. */
66
+ fn: string;
67
+ /** Standard read params (numeric ones coerced). */
68
+ params: ReadParams;
69
+ /** Bag of `x-*` extension query params (every key starts with `x-`). */
70
+ ext: Record<string, string>;
71
+ }
72
+ /**
73
+ * Parse a url into its structural fields, function, params, and extensions.
74
+ *
75
+ * Splitting rule: first `://` separates protocol from the rest; the first
76
+ * `/` in the rest separates hostname from path. Embedded `://` in the path
77
+ * (e.g. `b3nd://count/mutable://users/`) stays inside `path` — no
78
+ * special-casing.
79
+ *
80
+ * Defaults:
81
+ * - `fn=read` for uris without a trailing slash
82
+ * - `fn=ls` for uris with a trailing slash
83
+ *
84
+ * Numeric params (`limit`, `page`) are coerced; throws on NaN.
85
+ */
86
+ export declare function parseUrl(url: string): ParsedUrl;
87
+ /**
88
+ * Serialize a parsed url back to its string form. Authoritative input is
89
+ * `uri`; structural fields (`protocol`/`hostname`/`path`/`program`) are
90
+ * ignored on serialization since `uri` already contains them.
91
+ *
92
+ * Omits `fn=` when it matches the trailing-slash default. Throws if any
93
+ * `ext` key does not start with `x-`.
94
+ */
95
+ export declare function buildUrl(parsed: {
96
+ uri: string;
97
+ fn?: string;
98
+ params?: ReadParams;
99
+ ext?: Record<string, string>;
100
+ }): string;
101
+ /**
102
+ * Canonical-uri portion of a save url. The query string is
103
+ * request-time-only and never participates in routing or storage
104
+ * keying. Cheap helper for stores and callers that need the bare uri
105
+ * without paying for full parse.
106
+ */
107
+ export declare function uriOf(url: string): string;
108
+ //# sourceMappingURL=url.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"url.d.ts","sourceRoot":"","sources":["../src/url.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;GAiCG;AAIH;;;GAGG;AACH,MAAM,WAAW,UAAU;IACzB,KAAK,CAAC,EAAE,MAAM,CAAC;IACf,IAAI,CAAC,EAAE,MAAM,CAAC;IACd,MAAM,CAAC,EAAE,MAAM,CAAC;IAChB,MAAM,CAAC,EAAE,MAAM,CAAC;IAChB,SAAS,CAAC,EAAE,MAAM,CAAC;IACnB,OAAO,CAAC,EAAE,MAAM,CAAC;IACjB,MAAM,CAAC,EAAE,MAAM,CAAC;CACjB;AAED;;;;;GAKG;AACH,MAAM,WAAW,SAAS;IACxB,kEAAkE;IAClE,QAAQ,EAAE,MAAM,CAAC;IACjB,4DAA4D;IAC5D,QAAQ,EAAE,MAAM,CAAC;IACjB,0EAA0E;IAC1E,IAAI,EAAE,MAAM,CAAC;IACb,+DAA+D;IAC/D,OAAO,EAAE,MAAM,CAAC;IAChB,oEAAoE;IACpE,GAAG,EAAE,MAAM,CAAC;IACZ,sEAAsE;IACtE,EAAE,EAAE,MAAM,CAAC;IACX,mDAAmD;IACnD,MAAM,EAAE,UAAU,CAAC;IACnB,wEAAwE;IACxE,GAAG,EAAE,MAAM,CAAC,MAAM,EAAE,MAAM,CAAC,CAAC;CAC7B;AAED;;;;;;;;;;;;;GAaG;AACH,wBAAgB,QAAQ,CAAC,GAAG,EAAE,MAAM,GAAG,SAAS,CA8D/C;AAED;;;;;;;GAOG;AACH,wBAAgB,QAAQ,CAAC,MAAM,EAAE;IAC/B,GAAG,EAAE,MAAM,CAAC;IACZ,EAAE,CAAC,EAAE,MAAM,CAAC;IACZ,MAAM,CAAC,EAAE,UAAU,CAAC;IACpB,GAAG,CAAC,EAAE,MAAM,CAAC,MAAM,EAAE,MAAM,CAAC,CAAC;CAC9B,GAAG,MAAM,CAwBT;AAED;;;;;GAKG;AACH,wBAAgB,KAAK,CAAC,GAAG,EAAE,MAAM,GAAG,MAAM,CAGzC"}
package/esm/url.js ADDED
@@ -0,0 +1,151 @@
1
+ /**
2
+ * @module
3
+ * Save-layer locator grammar — parsing and constructing the urls that
4
+ * stores in this package implement.
5
+ *
6
+ * This is **save's contract with its callers**, not a framework-wide
7
+ * standard. b3nd-core treats locators opaquely; it is each client's
8
+ * choice what grammar it accepts. Stores shipped by `@bandeira-tech/b3nd-save`
9
+ * (memory, postgres, mongo, sqlite, fs, ipfs, s3, elasticsearch,
10
+ * localstorage, indexeddb) honor the grammar defined here.
11
+ *
12
+ * A **url** = a uri (the canonical resource identifier) plus a query
13
+ * string of read parameters. The uri is the routing identity used for
14
+ * storage keys and observe-match keys. The query string carries
15
+ * request-time-only directives that shape the response without
16
+ * changing identity.
17
+ *
18
+ * Grammar:
19
+ *
20
+ * <uri>[?fn=<fn>][&<param>=<value>...][&x-<ns>.<key>=<value>...]
21
+ *
22
+ * Reserved `fn` values:
23
+ * - `read` — point read (default for non-trailing-slash uris)
24
+ * - `ls` — list under a prefix (default when uri ends with `/`)
25
+ * - `count` — count of entries under a prefix
26
+ * - `x-*.*` — provider-defined extension functions
27
+ *
28
+ * Standard params (meaningful only for some fns; stores ignore the rest):
29
+ * `limit`, `page`, `cursor`, `sortBy`, `sortOrder`, `pattern`, `format`.
30
+ *
31
+ * Anything matching `x-<ns>.<key>` lands in the `ext` map and is passed
32
+ * opaquely to the executing store. Callers inspect ext entries by
33
+ * their flat string key (e.g. `ext["x-feed.cursor"]`).
34
+ */
35
+ /**
36
+ * Parse a url into its structural fields, function, params, and extensions.
37
+ *
38
+ * Splitting rule: first `://` separates protocol from the rest; the first
39
+ * `/` in the rest separates hostname from path. Embedded `://` in the path
40
+ * (e.g. `b3nd://count/mutable://users/`) stays inside `path` — no
41
+ * special-casing.
42
+ *
43
+ * Defaults:
44
+ * - `fn=read` for uris without a trailing slash
45
+ * - `fn=ls` for uris with a trailing slash
46
+ *
47
+ * Numeric params (`limit`, `page`) are coerced; throws on NaN.
48
+ */
49
+ export function parseUrl(url) {
50
+ const qIdx = url.indexOf("?");
51
+ const uri = qIdx < 0 ? url : url.slice(0, qIdx);
52
+ const query = qIdx < 0 ? "" : url.slice(qIdx + 1);
53
+ const schemeIdx = uri.indexOf("://");
54
+ let protocol = "";
55
+ let hostname = "";
56
+ let path = "";
57
+ if (schemeIdx >= 0) {
58
+ protocol = uri.slice(0, schemeIdx);
59
+ const rest = uri.slice(schemeIdx + 3);
60
+ const slash = rest.indexOf("/");
61
+ if (slash < 0) {
62
+ hostname = rest;
63
+ path = "";
64
+ }
65
+ else {
66
+ hostname = rest.slice(0, slash);
67
+ path = rest.slice(slash);
68
+ }
69
+ }
70
+ else {
71
+ path = uri;
72
+ }
73
+ const program = protocol ? `${protocol}://${hostname}` : "";
74
+ const sp = new URLSearchParams(query);
75
+ const explicitFn = sp.get("fn") ?? undefined;
76
+ const defaultFn = uri.endsWith("/") ? "ls" : "read";
77
+ const fn = explicitFn ?? defaultFn;
78
+ const params = {};
79
+ const ext = {};
80
+ for (const [key, value] of sp.entries()) {
81
+ if (key === "fn")
82
+ continue;
83
+ if (key.startsWith("x-")) {
84
+ ext[key] = value;
85
+ continue;
86
+ }
87
+ switch (key) {
88
+ case "limit":
89
+ case "page": {
90
+ const n = Number(value);
91
+ if (!Number.isFinite(n)) {
92
+ throw new Error(`Invalid ${key}: ${value}`);
93
+ }
94
+ params[key] = n;
95
+ break;
96
+ }
97
+ case "cursor":
98
+ case "sortBy":
99
+ case "sortOrder":
100
+ case "pattern":
101
+ case "format":
102
+ params[key] = value;
103
+ break;
104
+ default:
105
+ throw new Error(`Unknown read param: ${key}`);
106
+ }
107
+ }
108
+ return { protocol, hostname, path, program, uri, fn, params, ext };
109
+ }
110
+ /**
111
+ * Serialize a parsed url back to its string form. Authoritative input is
112
+ * `uri`; structural fields (`protocol`/`hostname`/`path`/`program`) are
113
+ * ignored on serialization since `uri` already contains them.
114
+ *
115
+ * Omits `fn=` when it matches the trailing-slash default. Throws if any
116
+ * `ext` key does not start with `x-`.
117
+ */
118
+ export function buildUrl(parsed) {
119
+ const { uri, fn, params, ext } = parsed;
120
+ const sp = new URLSearchParams();
121
+ const defaultFn = uri.endsWith("/") ? "ls" : "read";
122
+ if (fn && fn !== defaultFn)
123
+ sp.set("fn", fn);
124
+ if (params) {
125
+ for (const [k, v] of Object.entries(params)) {
126
+ if (v === undefined)
127
+ continue;
128
+ sp.set(k, String(v));
129
+ }
130
+ }
131
+ if (ext) {
132
+ for (const [k, v] of Object.entries(ext)) {
133
+ if (!k.startsWith("x-")) {
134
+ throw new Error(`ext keys must start with 'x-': ${k}`);
135
+ }
136
+ sp.set(k, v);
137
+ }
138
+ }
139
+ const qs = sp.toString();
140
+ return qs ? `${uri}?${qs}` : uri;
141
+ }
142
+ /**
143
+ * Canonical-uri portion of a save url. The query string is
144
+ * request-time-only and never participates in routing or storage
145
+ * keying. Cheap helper for stores and callers that need the bare uri
146
+ * without paying for full parse.
147
+ */
148
+ export function uriOf(url) {
149
+ const qIdx = url.indexOf("?");
150
+ return qIdx < 0 ? url : url.slice(0, qIdx);
151
+ }
package/package.json ADDED
@@ -0,0 +1,93 @@
1
+ {
2
+ "name": "@bandeira-tech/b3nd-save",
3
+ "version": "0.8.1",
4
+ "description": "B3nd data-saving layer: Store backends (postgres, mongo, sqlite, fs, ipfs, s3, elasticsearch, localstorage, indexeddb, memory) and Store→ProtocolInterfaceNode clients.",
5
+ "homepage": "https://github.com/bandeira-tech/b3nd-save#readme",
6
+ "repository": {
7
+ "type": "git",
8
+ "url": "git+https://github.com/bandeira-tech/b3nd-save.git"
9
+ },
10
+ "license": "MIT",
11
+ "bugs": {
12
+ "url": "https://github.com/bandeira-tech/b3nd-save/issues"
13
+ },
14
+ "module": "./esm/mod.js",
15
+ "exports": {
16
+ ".": {
17
+ "types": "./esm/mod.d.ts",
18
+ "import": "./esm/mod.js"
19
+ },
20
+ "./clients": {
21
+ "types": "./esm/clients/mod.d.ts",
22
+ "import": "./esm/clients/mod.js"
23
+ },
24
+ "./errors": {
25
+ "types": "./esm/errors.d.ts",
26
+ "import": "./esm/errors.js"
27
+ },
28
+ "./payload": {
29
+ "types": "./esm/payload.d.ts",
30
+ "import": "./esm/payload.js"
31
+ },
32
+ "./read": {
33
+ "types": "./esm/read.d.ts",
34
+ "import": "./esm/read.js"
35
+ },
36
+ "./dispatch": {
37
+ "types": "./esm/dispatch.d.ts",
38
+ "import": "./esm/dispatch.js"
39
+ },
40
+ "./memory": {
41
+ "types": "./esm/memory/mod.d.ts",
42
+ "import": "./esm/memory/mod.js"
43
+ },
44
+ "./postgres": {
45
+ "types": "./esm/postgres/mod.d.ts",
46
+ "import": "./esm/postgres/mod.js"
47
+ },
48
+ "./mongo": {
49
+ "types": "./esm/mongo/mod.d.ts",
50
+ "import": "./esm/mongo/mod.js"
51
+ },
52
+ "./sqlite": {
53
+ "types": "./esm/sqlite/mod.d.ts",
54
+ "import": "./esm/sqlite/mod.js"
55
+ },
56
+ "./fs": {
57
+ "types": "./esm/fs/mod.d.ts",
58
+ "import": "./esm/fs/mod.js"
59
+ },
60
+ "./ipfs": {
61
+ "types": "./esm/ipfs/mod.d.ts",
62
+ "import": "./esm/ipfs/mod.js"
63
+ },
64
+ "./s3": {
65
+ "types": "./esm/s3/mod.d.ts",
66
+ "import": "./esm/s3/mod.js"
67
+ },
68
+ "./elasticsearch": {
69
+ "types": "./esm/elasticsearch/mod.d.ts",
70
+ "import": "./esm/elasticsearch/mod.js"
71
+ },
72
+ "./localstorage": {
73
+ "types": "./esm/localstorage/mod.d.ts",
74
+ "import": "./esm/localstorage/mod.js"
75
+ },
76
+ "./indexeddb": {
77
+ "types": "./esm/indexeddb/mod.d.ts",
78
+ "import": "./esm/indexeddb/mod.js"
79
+ }
80
+ },
81
+ "scripts": {},
82
+ "engines": {
83
+ "node": ">=20"
84
+ },
85
+ "sideEffects": false,
86
+ "publishConfig": {
87
+ "access": "public"
88
+ },
89
+ "dependencies": {
90
+ "canonicalize": "2.0.0"
91
+ },
92
+ "_generatedBy": "dnt@dev"
93
+ }