@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
@@ -0,0 +1,164 @@
1
+ /**
2
+ * @module
3
+ * Hook types and runners for the Rig.
4
+ *
5
+ * Security model:
6
+ * - Before-hooks THROW to reject an operation. The caller must catch explicitly.
7
+ * No silent aborts — if validation fails, it's an exception.
8
+ * - After-hooks OBSERVE but cannot modify the result.
9
+ * They can throw if a post-condition is violated.
10
+ * - Hooks are immutable after init. Want different hooks? Create a new rig.
11
+ * - One function per hook. Need composition? Compose on your end.
12
+ *
13
+ * Pure module — no Rig dependency, testable in isolation.
14
+ */
15
+ import type { B3ndError, Output, ProgramResult } from "../types/types.js";
16
+ /**
17
+ * Context for a send hook.
18
+ *
19
+ * `message` is the input tuple the host application is putting on the
20
+ * wire. Send hooks fire per-tuple; before-hooks may rewrite the tuple
21
+ * by returning `{ ctx: { message: newTuple } }`.
22
+ */
23
+ export interface SendCtx {
24
+ message: Output;
25
+ }
26
+ /** Context for a receive hook. */
27
+ export interface ReceiveCtx {
28
+ uri: string;
29
+ data: unknown;
30
+ }
31
+ /**
32
+ * Context for a read hook.
33
+ *
34
+ * Carries only the `url` — an opaque locator string the framework
35
+ * passes through unchanged. If a hook needs to inspect the locator's
36
+ * grammar it brings its own parser. Before-hooks may rewrite the
37
+ * locator by returning `{ ctx: { url: newUrl } }`; the rig dispatches
38
+ * the returned locator unchanged.
39
+ *
40
+ * If you need to manipulate downstream behavior more invasively, wrap
41
+ * the executing client itself rather than threading transformations
42
+ * through the rig.
43
+ */
44
+ export interface ReadCtx {
45
+ url: string;
46
+ }
47
+ /**
48
+ * Before-hook. Runs before the operation.
49
+ *
50
+ * - Return `void` to proceed unchanged.
51
+ * - Return `{ ctx }` to replace the context (e.g. rewrite a URI).
52
+ * - **Throw** to reject the operation.
53
+ */
54
+ export type BeforeHook<C> = (ctx: Readonly<C>) => void | {
55
+ ctx: C;
56
+ } | Promise<void | {
57
+ ctx: C;
58
+ }>;
59
+ /**
60
+ * After-hook. Runs after the operation completes.
61
+ *
62
+ * Cannot modify the result. Use for logging, auditing, or enforcement.
63
+ * Throw if a post-condition is violated.
64
+ */
65
+ export type AfterHook<C> = (ctx: Readonly<C>, result: unknown) => void | Promise<void>;
66
+ /** Where in the pipeline the error occurred. */
67
+ export type ErrorPhase = "process" | "handle" | "route" | "reaction";
68
+ /**
69
+ * Context passed to the `onError` hook.
70
+ *
71
+ * Carries enough detail to identify the failing pipeline stage and
72
+ * the tuple involved. Optional fields are populated per phase:
73
+ *
74
+ * - `process` — `input`, `error`, `cause` (when an exception was thrown)
75
+ * - `handle` — `input`, `classification`, `error`, `cause`
76
+ * - `route` — `input`, `emission`, `connectionId`, `error`, `errorDetail`
77
+ * - `reaction`— `input`, `emission`, `pattern`, `error`, `cause`
78
+ */
79
+ export interface ErrorHookCtx {
80
+ /** Which pipeline stage produced the error. */
81
+ readonly phase: ErrorPhase;
82
+ /** The original input tuple driving this slice of work. */
83
+ readonly input: Output;
84
+ /** For `route` and `reaction`, the emission being dispatched. */
85
+ readonly emission?: Output;
86
+ /** For `route`, the stable ID of the connection that rejected. */
87
+ readonly connectionId?: string;
88
+ /** For `handle`, the classification produced by `process()`. */
89
+ readonly classification?: ProgramResult;
90
+ /** For `reaction`, the URI pattern that matched. */
91
+ readonly pattern?: string;
92
+ /** Human-readable error message. */
93
+ readonly error: string;
94
+ /** Structured error info when the underlying client returned one. */
95
+ readonly errorDetail?: B3ndError;
96
+ /** The original thrown value, when an exception occurred. */
97
+ readonly cause?: unknown;
98
+ }
99
+ /**
100
+ * Error hook — called synchronously (in the catch path) for every
101
+ * error the rig observes during a `send`/`receive` operation.
102
+ *
103
+ * **Throw to abort.** A throw propagates up through the operation
104
+ * handle: `await op` rejects with the thrown value, `await op.settled`
105
+ * rejects, and any in-flight reactions/routes for the operation stop
106
+ * being dispatched. (Routes already in flight at the underlying client
107
+ * cannot be unrun; the rig stops scheduling new ones.)
108
+ *
109
+ * **Return** to let the rig keep going with normal error handling: the
110
+ * affected tuple records `accepted: false`, the corresponding
111
+ * direction-level `*:error` event fires, and the operation's other
112
+ * tuples continue.
113
+ *
114
+ * Use the hook for fail-fast policies (drop the whole batch on first
115
+ * program rejection), structured error reporting, or to convert
116
+ * specific phases into application-level exceptions.
117
+ */
118
+ export type OnErrorHook = (ctx: Readonly<ErrorHookCtx>) => void | Promise<void>;
119
+ /** The full set of hooks for all operations. Frozen after init. */
120
+ export interface RigHooks {
121
+ readonly beforeSend: BeforeHook<SendCtx> | null;
122
+ readonly afterSend: AfterHook<SendCtx> | null;
123
+ readonly beforeReceive: BeforeHook<ReceiveCtx> | null;
124
+ readonly afterReceive: AfterHook<ReceiveCtx> | null;
125
+ readonly beforeRead: BeforeHook<ReadCtx> | null;
126
+ readonly afterRead: AfterHook<ReadCtx> | null;
127
+ readonly onError: OnErrorHook | null;
128
+ }
129
+ /** Config shape for hooks on RigConfig. */
130
+ export interface HooksConfig {
131
+ beforeSend?: BeforeHook<SendCtx>;
132
+ afterSend?: AfterHook<SendCtx>;
133
+ beforeReceive?: BeforeHook<ReceiveCtx>;
134
+ afterReceive?: AfterHook<ReceiveCtx>;
135
+ beforeRead?: BeforeHook<ReadCtx>;
136
+ afterRead?: AfterHook<ReadCtx>;
137
+ /** Synchronous error hook — throw to abort the operation. */
138
+ onError?: OnErrorHook;
139
+ }
140
+ /** Create frozen hooks from config. */
141
+ export declare function resolveHooks(config?: HooksConfig): RigHooks;
142
+ /**
143
+ * Run the onError hook with a given context. Returns `true` if the
144
+ * hook threw — the caller is expected to propagate the throw and
145
+ * abort the operation. Returns `false` if the hook returned normally
146
+ * (or there is no hook installed) — the caller proceeds with normal
147
+ * error handling.
148
+ *
149
+ * The hook's own throw is re-thrown by this runner so the call site
150
+ * sees it. Returning `true` here is just a convenience for call sites
151
+ * that want to branch.
152
+ */
153
+ export declare function runOnError(hook: OnErrorHook | null, ctx: ErrorHookCtx): Promise<void>;
154
+ /**
155
+ * Run a before-hook. Returns the (possibly replaced) context.
156
+ * Throws if the hook throws — this is the rejection mechanism.
157
+ */
158
+ export declare function runBefore<C>(hook: BeforeHook<C> | null, ctx: C): Promise<C>;
159
+ /**
160
+ * Run an after-hook. The result is passed as read-only context.
161
+ * After-hooks cannot modify the result.
162
+ */
163
+ export declare function runAfter<C>(hook: AfterHook<C> | null, ctx: C, result: unknown): Promise<void>;
164
+ //# sourceMappingURL=hooks.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"hooks.d.ts","sourceRoot":"","sources":["../../../../../../../../src/deps/jsr.io/@bandeira-tech/b3nd-core/0.22.0/src/rig/hooks.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,67 @@
1
+ /**
2
+ * @module
3
+ * Hook types and runners for the Rig.
4
+ *
5
+ * Security model:
6
+ * - Before-hooks THROW to reject an operation. The caller must catch explicitly.
7
+ * No silent aborts — if validation fails, it's an exception.
8
+ * - After-hooks OBSERVE but cannot modify the result.
9
+ * They can throw if a post-condition is violated.
10
+ * - Hooks are immutable after init. Want different hooks? Create a new rig.
11
+ * - One function per hook. Need composition? Compose on your end.
12
+ *
13
+ * Pure module — no Rig dependency, testable in isolation.
14
+ */
15
+ // ── Factory ──
16
+ /** Create frozen hooks from config. */
17
+ export function resolveHooks(config) {
18
+ return Object.freeze({
19
+ beforeSend: config?.beforeSend ?? null,
20
+ afterSend: config?.afterSend ?? null,
21
+ beforeReceive: config?.beforeReceive ?? null,
22
+ afterReceive: config?.afterReceive ?? null,
23
+ beforeRead: config?.beforeRead ?? null,
24
+ afterRead: config?.afterRead ?? null,
25
+ onError: config?.onError ?? null,
26
+ });
27
+ }
28
+ /**
29
+ * Run the onError hook with a given context. Returns `true` if the
30
+ * hook threw — the caller is expected to propagate the throw and
31
+ * abort the operation. Returns `false` if the hook returned normally
32
+ * (or there is no hook installed) — the caller proceeds with normal
33
+ * error handling.
34
+ *
35
+ * The hook's own throw is re-thrown by this runner so the call site
36
+ * sees it. Returning `true` here is just a convenience for call sites
37
+ * that want to branch.
38
+ */
39
+ export async function runOnError(hook, ctx) {
40
+ if (!hook)
41
+ return;
42
+ // Hook may be sync or return a promise. Await it; throws propagate.
43
+ await hook(ctx);
44
+ }
45
+ // ── Runners ──
46
+ /**
47
+ * Run a before-hook. Returns the (possibly replaced) context.
48
+ * Throws if the hook throws — this is the rejection mechanism.
49
+ */
50
+ export async function runBefore(hook, ctx) {
51
+ if (!hook)
52
+ return ctx;
53
+ const result = await hook(ctx);
54
+ if (result != null && typeof result === "object" && "ctx" in result) {
55
+ return result.ctx;
56
+ }
57
+ return ctx;
58
+ }
59
+ /**
60
+ * Run an after-hook. The result is passed as read-only context.
61
+ * After-hooks cannot modify the result.
62
+ */
63
+ export async function runAfter(hook, ctx, result) {
64
+ if (!hook)
65
+ return;
66
+ await hook(ctx, result);
67
+ }
@@ -0,0 +1,99 @@
1
+ /**
2
+ * @module
3
+ * Identity — unified keypair bundle for b3nd.
4
+ *
5
+ * Wraps Ed25519 signing + X25519 encryption into a single object.
6
+ * Deterministic derivation from seed, or fresh random generation.
7
+ */
8
+ import { type AuthenticatedMessage, type EncryptedPayload } from "../encrypt/mod.js";
9
+ /**
10
+ * Portable identity data — JSON-serializable for persistence.
11
+ *
12
+ * Store this in localStorage, a file, or a database to restore
13
+ * a full signing+encryption identity across sessions.
14
+ */
15
+ export interface ExportedIdentity {
16
+ /** Ed25519 public key hex. */
17
+ signingPublicKeyHex: string;
18
+ /** Ed25519 private key hex (PKCS8). Present only for full identities. */
19
+ signingPrivateKeyHex?: string;
20
+ /** X25519 public encryption key hex. */
21
+ encryptionPublicKeyHex: string;
22
+ /** X25519 private encryption key hex (PKCS8). Present only for full identities. */
23
+ encryptionPrivateKeyHex?: string;
24
+ }
25
+ /**
26
+ * Identity bundles signing (Ed25519) and encryption (X25519) keypairs.
27
+ *
28
+ * It can be created with full private keys (for signing/decrypting)
29
+ * or as a public-only identity (for addressing/encrypting to others).
30
+ */
31
+ export declare class Identity {
32
+ /** Ed25519 public key hex — the user's address on the network. */
33
+ readonly pubkey: string;
34
+ /** X25519 public encryption key hex. */
35
+ readonly encryptionPubkey: string;
36
+ /** Whether this identity has a signing private key (can sign messages). */
37
+ readonly canSign: boolean;
38
+ /** Whether this identity has an encryption private key (can decrypt). */
39
+ readonly canEncrypt: boolean;
40
+ private readonly _signingPrivateKey;
41
+ private readonly _encryptionPrivateKey;
42
+ private constructor();
43
+ /** Generate a fresh random identity. */
44
+ static generate(): Promise<Identity>;
45
+ /** Derive a deterministic identity from a seed string. */
46
+ static fromSeed(seed: string): Promise<Identity>;
47
+ /** Create identity from an Ed25519 PEM private key. */
48
+ static fromPem(signingPem: string, pubkeyHex: string, encryptionPrivateKeyHex?: string, encryptionPublicKeyHex?: string): Promise<Identity>;
49
+ /** Create a public-only identity (for addressing others). Cannot sign or decrypt. */
50
+ static publicOnly(keys: {
51
+ signing: string;
52
+ encryption?: string;
53
+ }): Identity;
54
+ /**
55
+ * Reconstruct an Identity from exported data.
56
+ *
57
+ * @example Persist across browser sessions
58
+ * ```typescript
59
+ * // Save
60
+ * const exported = await identity.export();
61
+ * localStorage.setItem("b3nd-id", JSON.stringify(exported));
62
+ *
63
+ * // Restore
64
+ * const saved = JSON.parse(localStorage.getItem("b3nd-id")!);
65
+ * const identity = await Identity.fromExport(saved);
66
+ * ```
67
+ */
68
+ static fromExport(data: ExportedIdentity): Promise<Identity>;
69
+ /** Sign a payload — returns `{ pubkey, signature }` auth entry. */
70
+ sign(payload: unknown): Promise<{
71
+ pubkey: string;
72
+ signature: string;
73
+ }>;
74
+ /** Wrap a payload into an AuthenticatedMessage with this identity's signature. */
75
+ signMessage<T>(payload: T): Promise<AuthenticatedMessage<T>>;
76
+ /** Verify a signature against this identity's public key. */
77
+ verify(payload: unknown, signature: string): Promise<boolean>;
78
+ /** Encrypt data for a recipient's public encryption key. */
79
+ encrypt(data: Uint8Array, recipientEncPubkeyHex: string): Promise<EncryptedPayload>;
80
+ /** Decrypt data sent to this identity. */
81
+ decrypt(payload: EncryptedPayload): Promise<Uint8Array>;
82
+ /**
83
+ * Export this identity to a JSON-serializable object.
84
+ *
85
+ * For full identities (with private keys), exports everything needed
86
+ * to reconstruct the identity later via `Identity.fromExport()`.
87
+ * For public-only identities, only public keys are exported.
88
+ */
89
+ export(): Promise<ExportedIdentity>;
90
+ /**
91
+ * Get the signer object for use with managed-node and other APIs
92
+ * that expect `{ privateKey: CryptoKey; publicKeyHex: string }`.
93
+ */
94
+ get signer(): {
95
+ privateKey: CryptoKey;
96
+ publicKeyHex: string;
97
+ };
98
+ }
99
+ //# sourceMappingURL=identity.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"identity.d.ts","sourceRoot":"","sources":["../../../../../../../../src/deps/jsr.io/@bandeira-tech/b3nd-core/0.22.0/src/rig/identity.ts"],"names":[],"mappings":"AAAA;;;;;;GAMG;AAEH,OAAO,EACL,KAAK,oBAAoB,EAMzB,KAAK,gBAAgB,EAMtB,MAAM,mBAAmB,CAAC;AAG3B;;;;;GAKG;AACH,MAAM,WAAW,gBAAgB;IAC/B,8BAA8B;IAC9B,mBAAmB,EAAE,MAAM,CAAC;IAC5B,yEAAyE;IACzE,oBAAoB,CAAC,EAAE,MAAM,CAAC;IAC9B,wCAAwC;IACxC,sBAAsB,EAAE,MAAM,CAAC;IAC/B,mFAAmF;IACnF,uBAAuB,CAAC,EAAE,MAAM,CAAC;CAClC;AAED;;;;;GAKG;AACH,qBAAa,QAAQ;IACnB,kEAAkE;IAClE,QAAQ,CAAC,MAAM,EAAE,MAAM,CAAC;IACxB,wCAAwC;IACxC,QAAQ,CAAC,gBAAgB,EAAE,MAAM,CAAC;IAClC,2EAA2E;IAC3E,QAAQ,CAAC,OAAO,EAAE,OAAO,CAAC;IAC1B,yEAAyE;IACzE,QAAQ,CAAC,UAAU,EAAE,OAAO,CAAC;IAE7B,OAAO,CAAC,QAAQ,CAAC,kBAAkB,CAAmB;IACtD,OAAO,CAAC,QAAQ,CAAC,qBAAqB,CAAmB;IAEzD,OAAO;IAgBP,wCAAwC;WAC3B,QAAQ,IAAI,OAAO,CAAC,QAAQ,CAAC;IAW1C,0DAA0D;WAC7C,QAAQ,CAAC,IAAI,EAAE,MAAM,GAAG,OAAO,CAAC,QAAQ,CAAC;IAWtD,uDAAuD;WAC1C,OAAO,CAClB,UAAU,EAAE,MAAM,EAClB,SAAS,EAAE,MAAM,EACjB,uBAAuB,CAAC,EAAE,MAAM,EAChC,sBAAsB,CAAC,EAAE,MAAM,GAC9B,OAAO,CAAC,QAAQ,CAAC;IAwCpB,qFAAqF;IACrF,MAAM,CAAC,UAAU,CAAC,IAAI,EAAE;QACtB,OAAO,EAAE,MAAM,CAAC;QAChB,UAAU,CAAC,EAAE,MAAM,CAAC;KACrB,GAAG,QAAQ;IASZ;;;;;;;;;;;;;OAaG;WACU,UAAU,CAAC,IAAI,EAAE,gBAAgB,GAAG,OAAO,CAAC,QAAQ,CAAC;IAoClE,mEAAmE;IAC7D,IAAI,CAAC,OAAO,EAAE,OAAO,GAAG,OAAO,CAAC;QAAE,MAAM,EAAE,MAAM,CAAC;QAAC,SAAS,EAAE,MAAM,CAAA;KAAE,CAAC;IAQ5E,kFAAkF;IAClF,WAAW,CAAC,CAAC,EAAE,OAAO,EAAE,CAAC,GAAG,OAAO,CAAC,oBAAoB,CAAC,CAAC,CAAC,CAAC;IAY5D,6DAA6D;IAC7D,MAAM,CAAC,OAAO,EAAE,OAAO,EAAE,SAAS,EAAE,MAAM,GAAG,OAAO,CAAC,OAAO,CAAC;IAI7D,4DAA4D;IAC5D,OAAO,CACL,IAAI,EAAE,UAAU,EAChB,qBAAqB,EAAE,MAAM,GAC5B,OAAO,CAAC,gBAAgB,CAAC;IAI5B,0CAA0C;IAC1C,OAAO,CAAC,OAAO,EAAE,gBAAgB,GAAG,OAAO,CAAC,UAAU,CAAC;IASvD;;;;;;OAMG;IACG,MAAM,IAAI,OAAO,CAAC,gBAAgB,CAAC;IAyBzC;;;OAGG;IACH,IAAI,MAAM,IAAI;QAAE,UAAU,EAAE,SAAS,CAAC;QAAC,YAAY,EAAE,MAAM,CAAA;KAAE,CAQ5D;CACF"}
@@ -0,0 +1,190 @@
1
+ /**
2
+ * @module
3
+ * Identity — unified keypair bundle for b3nd.
4
+ *
5
+ * Wraps Ed25519 signing + X25519 encryption into a single object.
6
+ * Deterministic derivation from seed, or fresh random generation.
7
+ */
8
+ import { createAuthenticatedMessage, decrypt as asymDecrypt, deriveEncryptionKeyPairFromSeed, deriveSigningKeyPairFromSeed, encrypt as asymEncrypt, generateEncryptionKeyPair, generateSigningKeyPair, pemToCryptoKey, sign as edSign, verify as edVerify, } from "../encrypt/mod.js";
9
+ import { decodeHex, encodeHex } from "../encoding/encoding.js";
10
+ /**
11
+ * Identity bundles signing (Ed25519) and encryption (X25519) keypairs.
12
+ *
13
+ * It can be created with full private keys (for signing/decrypting)
14
+ * or as a public-only identity (for addressing/encrypting to others).
15
+ */
16
+ export class Identity {
17
+ /** Ed25519 public key hex — the user's address on the network. */
18
+ pubkey;
19
+ /** X25519 public encryption key hex. */
20
+ encryptionPubkey;
21
+ /** Whether this identity has a signing private key (can sign messages). */
22
+ canSign;
23
+ /** Whether this identity has an encryption private key (can decrypt). */
24
+ canEncrypt;
25
+ _signingPrivateKey;
26
+ _encryptionPrivateKey;
27
+ constructor(opts) {
28
+ this.pubkey = opts.pubkey;
29
+ this.encryptionPubkey = opts.encryptionPubkey;
30
+ this._signingPrivateKey = opts.signingPrivateKey;
31
+ this._encryptionPrivateKey = opts.encryptionPrivateKey;
32
+ this.canSign = opts.signingPrivateKey !== null;
33
+ this.canEncrypt = opts.encryptionPrivateKey !== null;
34
+ }
35
+ // ── Factory methods ──
36
+ /** Generate a fresh random identity. */
37
+ static async generate() {
38
+ const signing = await generateSigningKeyPair();
39
+ const encryption = await generateEncryptionKeyPair();
40
+ return new Identity({
41
+ pubkey: signing.publicKeyHex,
42
+ encryptionPubkey: encryption.publicKeyHex,
43
+ signingPrivateKey: signing.privateKey,
44
+ encryptionPrivateKey: encryption.privateKey,
45
+ });
46
+ }
47
+ /** Derive a deterministic identity from a seed string. */
48
+ static async fromSeed(seed) {
49
+ const signing = await deriveSigningKeyPairFromSeed(seed);
50
+ const encryption = await deriveEncryptionKeyPairFromSeed(seed);
51
+ return new Identity({
52
+ pubkey: signing.publicKeyHex,
53
+ encryptionPubkey: encryption.publicKeyHex,
54
+ signingPrivateKey: signing.privateKey,
55
+ encryptionPrivateKey: encryption.privateKey,
56
+ });
57
+ }
58
+ /** Create identity from an Ed25519 PEM private key. */
59
+ static async fromPem(signingPem, pubkeyHex, encryptionPrivateKeyHex, encryptionPublicKeyHex) {
60
+ const signingPrivateKey = await pemToCryptoKey(signingPem, "Ed25519");
61
+ let encPrivKey = null;
62
+ let encPubHex = encryptionPublicKeyHex || "";
63
+ if (encryptionPrivateKeyHex) {
64
+ const privBytes = decodeHex(encryptionPrivateKeyHex).buffer;
65
+ encPrivKey = await crypto.subtle.importKey("pkcs8", privBytes, { name: "X25519", namedCurve: "X25519" }, true, ["deriveBits"]);
66
+ if (!encPubHex) {
67
+ // Derive public from private via JWK round-trip
68
+ const jwk = await crypto.subtle.exportKey("jwk", encPrivKey);
69
+ const pub = await crypto.subtle.importKey("jwk", { kty: jwk.kty, crv: jwk.crv, x: jwk.x, key_ops: [] }, { name: "X25519", namedCurve: "X25519" }, true, []);
70
+ encPubHex = encodeHex(new Uint8Array(await crypto.subtle.exportKey("raw", pub)));
71
+ }
72
+ }
73
+ return new Identity({
74
+ pubkey: pubkeyHex,
75
+ encryptionPubkey: encPubHex,
76
+ signingPrivateKey,
77
+ encryptionPrivateKey: encPrivKey,
78
+ });
79
+ }
80
+ /** Create a public-only identity (for addressing others). Cannot sign or decrypt. */
81
+ static publicOnly(keys) {
82
+ return new Identity({
83
+ pubkey: keys.signing,
84
+ encryptionPubkey: keys.encryption || "",
85
+ signingPrivateKey: null,
86
+ encryptionPrivateKey: null,
87
+ });
88
+ }
89
+ /**
90
+ * Reconstruct an Identity from exported data.
91
+ *
92
+ * @example Persist across browser sessions
93
+ * ```typescript
94
+ * // Save
95
+ * const exported = await identity.export();
96
+ * localStorage.setItem("b3nd-id", JSON.stringify(exported));
97
+ *
98
+ * // Restore
99
+ * const saved = JSON.parse(localStorage.getItem("b3nd-id")!);
100
+ * const identity = await Identity.fromExport(saved);
101
+ * ```
102
+ */
103
+ static async fromExport(data) {
104
+ let signingPrivateKey = null;
105
+ let encryptionPrivateKey = null;
106
+ if (data.signingPrivateKeyHex) {
107
+ const pkcs8Bytes = decodeHex(data.signingPrivateKeyHex);
108
+ signingPrivateKey = await crypto.subtle.importKey("pkcs8", pkcs8Bytes.buffer, { name: "Ed25519", namedCurve: "Ed25519" }, true, ["sign"]);
109
+ }
110
+ if (data.encryptionPrivateKeyHex) {
111
+ const pkcs8Bytes = decodeHex(data.encryptionPrivateKeyHex);
112
+ encryptionPrivateKey = await crypto.subtle.importKey("pkcs8", pkcs8Bytes.buffer, { name: "X25519", namedCurve: "X25519" }, true, ["deriveBits"]);
113
+ }
114
+ return new Identity({
115
+ pubkey: data.signingPublicKeyHex,
116
+ encryptionPubkey: data.encryptionPublicKeyHex,
117
+ signingPrivateKey,
118
+ encryptionPrivateKey,
119
+ });
120
+ }
121
+ // ── Operations ──
122
+ /** Sign a payload — returns `{ pubkey, signature }` auth entry. */
123
+ async sign(payload) {
124
+ if (!this._signingPrivateKey) {
125
+ throw new Error("Cannot sign: this is a public-only identity");
126
+ }
127
+ const signature = await edSign(this._signingPrivateKey, payload);
128
+ return { pubkey: this.pubkey, signature };
129
+ }
130
+ /** Wrap a payload into an AuthenticatedMessage with this identity's signature. */
131
+ signMessage(payload) {
132
+ if (!this._signingPrivateKey) {
133
+ return Promise.reject(new Error("Cannot sign: this is a public-only identity"));
134
+ }
135
+ return createAuthenticatedMessage(payload, [{
136
+ privateKey: this._signingPrivateKey,
137
+ publicKeyHex: this.pubkey,
138
+ }]);
139
+ }
140
+ /** Verify a signature against this identity's public key. */
141
+ verify(payload, signature) {
142
+ return edVerify(this.pubkey, signature, payload);
143
+ }
144
+ /** Encrypt data for a recipient's public encryption key. */
145
+ encrypt(data, recipientEncPubkeyHex) {
146
+ return asymEncrypt(data, recipientEncPubkeyHex);
147
+ }
148
+ /** Decrypt data sent to this identity. */
149
+ decrypt(payload) {
150
+ if (!this._encryptionPrivateKey) {
151
+ return Promise.reject(new Error("Cannot decrypt: no encryption private key"));
152
+ }
153
+ return asymDecrypt(payload, this._encryptionPrivateKey);
154
+ }
155
+ /**
156
+ * Export this identity to a JSON-serializable object.
157
+ *
158
+ * For full identities (with private keys), exports everything needed
159
+ * to reconstruct the identity later via `Identity.fromExport()`.
160
+ * For public-only identities, only public keys are exported.
161
+ */
162
+ async export() {
163
+ const result = {
164
+ signingPublicKeyHex: this.pubkey,
165
+ encryptionPublicKeyHex: this.encryptionPubkey,
166
+ };
167
+ if (this._signingPrivateKey) {
168
+ const pkcs8 = await crypto.subtle.exportKey("pkcs8", this._signingPrivateKey);
169
+ result.signingPrivateKeyHex = encodeHex(new Uint8Array(pkcs8));
170
+ }
171
+ if (this._encryptionPrivateKey) {
172
+ const pkcs8 = await crypto.subtle.exportKey("pkcs8", this._encryptionPrivateKey);
173
+ result.encryptionPrivateKeyHex = encodeHex(new Uint8Array(pkcs8));
174
+ }
175
+ return result;
176
+ }
177
+ /**
178
+ * Get the signer object for use with managed-node and other APIs
179
+ * that expect `{ privateKey: CryptoKey; publicKeyHex: string }`.
180
+ */
181
+ get signer() {
182
+ if (!this._signingPrivateKey) {
183
+ throw new Error("Cannot get signer: this is a public-only identity");
184
+ }
185
+ return {
186
+ privateKey: this._signingPrivateKey,
187
+ publicKeyHex: this.pubkey,
188
+ };
189
+ }
190
+ }