@onlyne/lib 3.1.0 → 3.2.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (121) hide show
  1. package/README.md +4 -3
  2. package/dist/awaited.d.ts +43 -0
  3. package/dist/awaited.d.ts.map +1 -0
  4. package/dist/awaited.js +82 -0
  5. package/dist/awaited.js.map +1 -0
  6. package/dist/client.d.ts +140 -0
  7. package/dist/client.d.ts.map +1 -0
  8. package/dist/client.js +1772 -0
  9. package/dist/client.js.map +1 -0
  10. package/dist/core.d.ts +36 -0
  11. package/dist/core.d.ts.map +1 -0
  12. package/dist/core.js +122 -0
  13. package/dist/core.js.map +1 -0
  14. package/dist/delivery.d.ts +120 -0
  15. package/dist/delivery.d.ts.map +1 -0
  16. package/dist/delivery.js +117 -0
  17. package/dist/delivery.js.map +1 -0
  18. package/dist/discovery.d.ts +35 -0
  19. package/dist/discovery.d.ts.map +1 -0
  20. package/dist/discovery.js +306 -0
  21. package/dist/discovery.js.map +1 -0
  22. package/dist/domains.d.ts +29 -0
  23. package/dist/domains.d.ts.map +1 -0
  24. package/dist/domains.js +267 -0
  25. package/dist/domains.js.map +1 -0
  26. package/dist/history.d.ts +13 -0
  27. package/dist/history.d.ts.map +1 -0
  28. package/dist/history.js +143 -0
  29. package/dist/history.js.map +1 -0
  30. package/dist/http.d.ts +20 -0
  31. package/dist/http.d.ts.map +1 -0
  32. package/dist/http.js +88 -0
  33. package/dist/http.js.map +1 -0
  34. package/{src/index.ts → dist/index.d.ts} +2 -0
  35. package/dist/index.d.ts.map +1 -0
  36. package/dist/index.js +15 -0
  37. package/dist/index.js.map +1 -0
  38. package/dist/keys.d.ts +97 -0
  39. package/dist/keys.d.ts.map +1 -0
  40. package/dist/keys.js +679 -0
  41. package/dist/keys.js.map +1 -0
  42. package/dist/memory.d.ts +9 -0
  43. package/dist/memory.d.ts.map +1 -0
  44. package/dist/memory.js +35 -0
  45. package/dist/memory.js.map +1 -0
  46. package/dist/messages.d.ts +64 -0
  47. package/dist/messages.d.ts.map +1 -0
  48. package/dist/messages.js +480 -0
  49. package/dist/messages.js.map +1 -0
  50. package/dist/node.d.ts +26 -0
  51. package/dist/node.d.ts.map +1 -0
  52. package/dist/node.js +59 -0
  53. package/dist/node.js.map +1 -0
  54. package/dist/resolve.d.ts +18 -0
  55. package/dist/resolve.d.ts.map +1 -0
  56. package/dist/resolve.js +37 -0
  57. package/dist/resolve.js.map +1 -0
  58. package/dist/resources.d.ts +25 -0
  59. package/dist/resources.d.ts.map +1 -0
  60. package/dist/resources.js +782 -0
  61. package/dist/resources.js.map +1 -0
  62. package/dist/routes/domains.d.ts +4 -0
  63. package/dist/routes/domains.d.ts.map +1 -0
  64. package/dist/routes/domains.js +42 -0
  65. package/dist/routes/domains.js.map +1 -0
  66. package/dist/routes/grants.d.ts +8 -0
  67. package/dist/routes/grants.d.ts.map +1 -0
  68. package/dist/routes/grants.js +32 -0
  69. package/dist/routes/grants.js.map +1 -0
  70. package/dist/routes/public.d.ts +4 -0
  71. package/dist/routes/public.d.ts.map +1 -0
  72. package/dist/routes/public.js +62 -0
  73. package/dist/routes/public.js.map +1 -0
  74. package/dist/routes/resources.d.ts +8 -0
  75. package/dist/routes/resources.d.ts.map +1 -0
  76. package/dist/routes/resources.js +87 -0
  77. package/dist/routes/resources.js.map +1 -0
  78. package/dist/routes/shared.d.ts +77 -0
  79. package/dist/routes/shared.d.ts.map +1 -0
  80. package/dist/routes/shared.js +349 -0
  81. package/dist/routes/shared.js.map +1 -0
  82. package/dist/routes/threads.d.ts +8 -0
  83. package/dist/routes/threads.d.ts.map +1 -0
  84. package/dist/routes/threads.js +113 -0
  85. package/dist/routes/threads.js.map +1 -0
  86. package/dist/routes/trust.d.ts +4 -0
  87. package/dist/routes/trust.d.ts.map +1 -0
  88. package/dist/routes/trust.js +36 -0
  89. package/dist/routes/trust.js.map +1 -0
  90. package/dist/stream.d.ts +20 -0
  91. package/dist/stream.d.ts.map +1 -0
  92. package/dist/stream.js +141 -0
  93. package/dist/stream.js.map +1 -0
  94. package/dist/threads.d.ts +79 -0
  95. package/dist/threads.d.ts.map +1 -0
  96. package/dist/threads.js +480 -0
  97. package/dist/threads.js.map +1 -0
  98. package/dist/transport.d.ts +45 -0
  99. package/dist/transport.d.ts.map +1 -0
  100. package/dist/transport.js +175 -0
  101. package/dist/transport.js.map +1 -0
  102. package/dist/types.d.ts +809 -0
  103. package/dist/types.d.ts.map +1 -0
  104. package/dist/types.js +9 -0
  105. package/dist/types.js.map +1 -0
  106. package/package.json +16 -8
  107. package/src/client.ts +0 -1745
  108. package/src/core.ts +0 -114
  109. package/src/discovery.ts +0 -275
  110. package/src/domains.ts +0 -213
  111. package/src/history.ts +0 -139
  112. package/src/http.ts +0 -852
  113. package/src/keys.ts +0 -642
  114. package/src/memory.ts +0 -34
  115. package/src/messages.ts +0 -409
  116. package/src/node.ts +0 -63
  117. package/src/resolve.ts +0 -39
  118. package/src/resources.ts +0 -745
  119. package/src/threads.ts +0 -409
  120. package/src/transport.ts +0 -211
  121. package/src/types.ts +0 -428
package/src/types.ts DELETED
@@ -1,428 +0,0 @@
1
- export type Json = null | boolean | number | string | Json[] | { [key: string]: Json };
2
- export type NodeId = string;
3
- export type DomainId = string;
4
- export interface DomainMembership {
5
- domain_id: DomainId; node_id: NodeId; state: 'active' | 'left'; revision: string;
6
- }
7
- export interface DomainMutation extends Mutation { expected_revision?: string }
8
- export interface DomainDiscovery {
9
- domain_id: DomainId; members: DomainMembership[]; unavailable: NodeId[];
10
- }
11
- export interface DiscoveryCandidate {
12
- node_id: NodeId; instance_id: string; base_url: string; last_seen: string;
13
- }
14
- export interface DiscoveryRecord extends DiscoveryCandidate {
15
- source: string; received_at: string; expires_at: string;
16
- verified_at?: string; membership?: DomainMembership | null; error?: Failure;
17
- }
18
- export interface ServiceDescription {
19
- protocol: 'onlyne/3'; node_id: NodeId; instance_id: string; base_url: string;
20
- features: string[]; authentication: string[];
21
- domain: DomainId | null; membership: DomainMembership | null;
22
- }
23
- export interface ThreadRef { owner: NodeId; id: string }
24
- export interface MessageRef { sender: NodeId; id: string }
25
- export interface ResourceRef { owner: NodeId; id: string }
26
- export type ErrorCode = 'invalid_request' | 'unauthenticated' | 'forbidden' | 'not_a_member' | 'not_found' | 'id_conflict' | 'revision_conflict' | 'request_in_progress' | 'conflict' | 'thread_closed' | 'context_lost' | 'retry_window_expired' | 'cursor_expired' | 'payload_too_large' | 'unsupported_media_type' | 'unsupported_delivery' | 'ambiguous_target' | 'ambiguous_resource' | 'capacity_exceeded' | 'internal' | 'unavailable' | 'decision_unavailable';
27
- export interface Failure { code: ErrorCode; message: string; retryable: boolean; details?: Json }
28
- export interface Auth { actor: NodeId; sender?: NodeId; reply_authority?: NodeId }
29
- export interface Transaction {
30
- get<T>(key: string): Promise<T | undefined>;
31
- put<T>(key: string, value: T): Promise<void>;
32
- delete(key: string): Promise<void>;
33
- scan<T>(prefix: string): Promise<Array<{ key: string; value: T }>>;
34
- }
35
- export interface Storage {
36
- readonly guarantee: 'durable' | 'binding-defined';
37
- /** Serializable, atomic commit. Rejecting the callback rolls back every write. */
38
- transaction<T>(work: (tx: Transaction) => Promise<T>): Promise<T>;
39
- }
40
- export interface Page<T> { items: T[]; next_cursor: string | null }
41
- export interface Mutation { idempotency_key: string; retry_until: string }
42
- export interface DeliveryPlan { response: 'none' | 'async' | 'await'; execution: 'existing' | 'new'; context?: string }
43
- export interface Message {
44
- id: string;
45
- sender: NodeId;
46
- delivery_kind: string;
47
- msg: string;
48
- meta?: {
49
- thread?: ThreadRef;
50
- in_reply_to?: MessageRef;
51
- relation?: 'reply' | 'followup';
52
- mentions?: string[];
53
- parts?: Json[];
54
- data?: { [key: string]: Json };
55
- };
56
- }
57
- export interface SendRequest extends Mutation { message: Message; target_endpoint: NodeId; plan: DeliveryPlan }
58
- export interface Receipt {
59
- message_ref: MessageRef; receipt_id: string; guarantee: Storage['guarantee'];
60
- thread_ref: ThreadRef; seq: string; plan: DeliveryPlan;
61
- thread_created?: boolean; previous_seq?: string;
62
- /**
63
- * The message this one answers, in the identity the owner stored: the sender's
64
- * `{thread,seq}` spelling is resolved before delivery, so this is the pair every
65
- * later read agrees on. Absent when the message answers nothing.
66
- */
67
- in_reply_to?: MessageRef;
68
- }
69
- export interface Entry {
70
- thread_ref: ThreadRef; seq: string; message: Message; authenticated_author: NodeId;
71
- reply_authority: NodeId; at: string;
72
- }
73
- export interface ReadScope { peers?: NodeId[]; since_seq?: string; related_to?: MessageRef }
74
- export interface Member { peer: NodeId; state: 'requested' | 'active' | 'revoked' | 'denied'; access: Array<'read' | 'post'>; read_scope: ReadScope; revision: string }
75
- export interface Thread {
76
- thread_ref: ThreadRef; title: string; state: 'open' | 'closed'; next_seq: string;
77
- event_seq: string; created_at: string; closed_at: string | null;
78
- messages_until?: string;
79
- }
80
- /**
81
- * A thread this node was invited into and does not own. Every field here comes from a record
82
- * this node already holds; the owner's title, state and member table are filled in only by a
83
- * caller that could ask the owner, and a row that could not ask keeps the failure instead of
84
- * inventing them.
85
- */
86
- export interface JoinedThread {
87
- thread_ref: ThreadRef;
88
- /** The highest sequence this node holds a local record for; `0` when it holds none. */
89
- last_seq: string;
90
- /** Distinct messages this node holds for the thread. */
91
- message_count: number;
92
- /** A participant never owns the member table, so this view is read-only by construction. */
93
- read_only: true;
94
- title?: string;
95
- state?: Thread['state'];
96
- members?: Member[];
97
- /** The owner could not be asked; the row stays listed with what the local records prove. */
98
- unavailable?: Failure;
99
- }
100
- /** One thread record with its member table: what the describe read answers, here or at the owner. */
101
- export interface ThreadDescription { thread: Thread; members: Member[] }
102
- export interface Attention {
103
- obligation_id: string; recipient: NodeId; thread_ref: ThreadRef; seq: string;
104
- message_ref: MessageRef; authenticated_author: NodeId; acked: boolean;
105
- disposition?: 'expired';
106
- plan?: DeliveryPlan;
107
- entry?: Entry;
108
- }
109
- export interface Grant {
110
- id: string; recipient: NodeId; thread_ref: ThreadRef; revision: string; acked: boolean;
111
- /**
112
- * Set on a re-issued notice: the ref the recipient learned under the previous owner. The
113
- * recipient stores the new known row and drops the one this names, so a renamed owner does
114
- * not leave a second row pointing at an endpoint that no longer exists.
115
- */
116
- previous_thread_ref?: ThreadRef;
117
- }
118
- export interface Event {
119
- id: string; type: 'message' | 'membership' | 'thread_closed' | 'resource_event' | 'operation';
120
- thread_ref?: ThreadRef; resource_ref?: ResourceRef; message_ref?: MessageRef; data: Json;
121
- }
122
- export interface PageOptions { cursor?: string; page_size?: number }
123
- export interface MessageQuery extends PageOptions { attention?: 'inbox' | 'thread'; since_seq?: string; peer?: NodeId; related_to?: MessageRef }
124
- export interface ReplyPermit {
125
- message_ref: MessageRef; grantee: NodeId; landing: ThreadRef; expires_at: string;
126
- remaining: number; revoked: boolean; followup: boolean;
127
- }
128
- /**
129
- * RFC 0006 §3: the resource's runtime state. `binding` is the one pointer events route
130
- * through; `log_readers` is a separate authorization for the append-only log, and a
131
- * handover never touches it (§6).
132
- */
133
- export interface Resource {
134
- resource_ref: ResourceRef; kind: string; operations: string[];
135
- binding: { handler: NodeId; cursor: string };
136
- log_readers: NodeId[]; revision: string;
137
- event_seq: string; retention_ms: number; data?: Json;
138
- }
139
- /** RFC 0006 §5: an event belongs to the resource, never to a recipient list. */
140
- export interface ResourceEvent {
141
- resource_ref: ResourceRef; event_id: string; source_id: string;
142
- data: Json; at: string; expires_at: string; expired: boolean;
143
- }
144
- /** RFC 0006 §6: the log query. `since` is exclusive, the same side of the cursor an ack names. */
145
- export interface LogQuery extends PageOptions { since?: string }
146
- /** What an ack answers: the handler's confirmed position, not the event it named. */
147
- export interface AckReceipt { resource_ref: ResourceRef; cursor: string }
148
- /** RFC 0006 §4.3: the probe an endpoint sends to the node it wants to become handler. */
149
- export interface HandoverProbe {
150
- operation_id: string; resource: ResourceRef; kind: string; operations: string[];
151
- metadata?: Json; initiator: NodeId; cursor: string; deadline: string;
152
- }
153
- export type ProbeAnswer =
154
- | { answer: 'accept'; cursor: string }
155
- | { answer: 'reject'; reason: string };
156
- export interface OperationRequest extends Mutation {
157
- operation_id: string; operation: string; expected_revision?: string; data?: Json;
158
- }
159
- export interface OperationResult {
160
- operation_id: string; state: 'committed' | 'pending' | 'aborted' | 'unknown';
161
- data?: Json; error?: Failure;
162
- }
163
- export interface OperationRecord {
164
- actor: NodeId; request: OperationRequest; digest: string; result: OperationResult;
165
- resource_ref: ResourceRef; accepted_at: string; authorized_revision: string;
166
- }
167
- export interface Outbound {
168
- request: SendRequest; expected_author: NodeId; state: 'pending' | 'accepted' | 'refused' | 'unknown';
169
- receipt?: Receipt; error?: Failure; created_at?: string;
170
- /** The peer this send addresses when it differs from the endpoint that stores the entry. */
171
- addressee?: NodeId;
172
- /** The caller's own spelling of the addressee, when it differs from the resolved node id. */
173
- requested?: string;
174
- }
175
- export interface HistoryMessage {
176
- message_ref: MessageRef; message: Message; direction: 'in' | 'out';
177
- thread_ref?: ThreadRef; seq?: string; at: string | null;
178
- delivery: Outbound['state'] | 'received'; consumption?: 'pending' | 'consumed';
179
- settlement?: AttentionSettlement;
180
- guarantee?: Storage['guarantee']; error?: Failure;
181
- }
182
- export interface Conversation {
183
- id: MessageRef; title: string; thread_refs: ThreadRef[]; messages: HistoryMessage[];
184
- last_at: string | null;
185
- }
186
- export interface HistoryQuery extends PageOptions { thread?: ThreadRef; message?: MessageRef }
187
- export type AttentionSettlement =
188
- | { via: 'handover'; resource_ref: ResourceRef; handler: NodeId; revision: string; at: string }
189
- | { via: 'undeliverable'; resource_ref: ResourceRef; reason: 'resource-unavailable'; at: string };
190
- /**
191
- * `injected` closes the local delivery obligation after observed consumption or an explicit
192
- * settlement. A settlement records why delivery ended without claiming model consumption.
193
- */
194
- export interface LocalAttention {
195
- attention: Attention; context?: string; injected: boolean; settlement?: AttentionSettlement;
196
- resource_check_failures?: number;
197
- }
198
- export interface Target { node_id: NodeId; base_url: string; headers?: Record<string, string> }
199
- export interface Transport {
200
- request<T>(target: NodeId, method: string, path: string, body?: unknown, signal?: AbortSignal): Promise<T>;
201
- }
202
- export interface MsgInput { delivery_kind: string; msg: string; meta?: Record<string, Json> }
203
- export interface PreparedSend { to: NodeId; message: Message; plan: DeliveryPlan }
204
- export type ResourceReadQuery =
205
- | ({ op: 'list'; owners?: NodeId[] } & PageOptions)
206
- | { op: 'describe'; resource: ResourceRef }
207
- | ({ op: 'log'; resource: ResourceRef } & LogQuery)
208
- | { op: 'event'; resource: ResourceRef; event_id: string }
209
- | ({ op: 'operations'; resource: ResourceRef } & PageOptions)
210
- | { op: 'status'; resource: ResourceRef; operation_id: string };
211
- export interface ResourceInventory {
212
- owners: Array<{ owner: NodeId; page: Page<Resource> } | { owner: NodeId; error: Failure }>;
213
- }
214
- export type ResourceReadResult = ResourceInventory | Resource | Page<ResourceEvent> | ResourceEvent | Page<OperationRecord> | OperationRecord;
215
- export type Action =
216
- | { kind: 'domain'; op: 'create' | 'join' | 'leave' | 'list' | 'describe' | 'discover'; domain_id?: DomainId; expected_revision?: string }
217
- | { kind: 'send'; to: NodeId; thread?: ThreadRef; context?: string; in_reply_to?: MessageRef; relation?: 'reply' | 'followup'; mentions?: NodeId[]; response: DeliveryPlan['response']; execution: DeliveryPlan['execution'] }
218
- | { kind: 'read'; scope: 'directory' | 'neighbors' | 'threads' | 'inbox' | 'messages' | 'message' | 'evidence'; thread?: ThreadRef; message?: MessageRef; seq?: string; cursor?: string; page_size?: number; attention?: 'inbox' | 'thread' }
219
- | { kind: 'read'; scope: 'resources'; query: ResourceReadQuery }
220
- | { kind: 'thread'; op: 'create' | 'close' | 'list' | 'describe' | 'member_add' | 'member_remove'; thread?: ThreadRef; to?: NodeId; title?: string }
221
- | { kind: 'resource'; resource: ResourceRef; operation: string; data?: Json; expected_revision?: string };
222
- /**
223
- * One lifecycle transition of the local node, emitted for offline diagnosis. Every field is an
224
- * identifier, a state name or a count: message bodies and credentials never appear here.
225
- */
226
- export type TraceEvent =
227
- | { event: 'inbound.received'; obligation: string; thread: ThreadRef; seq: string; sender: NodeId; relation?: 'reply' | 'followup'; valid: boolean; context?: string; injected: boolean }
228
- | { event: 'inbound.duplicate'; sender: NodeId; message: string }
229
- | { event: 'inbound.acked'; obligation: string; thread: ThreadRef; seq: string }
230
- | { event: 'inbound.inject'; thread: ThreadRef; seq: string; context: string; outcome: InjectOutcome; reason?: string }
231
- | { event: 'inbound.settled'; thread: ThreadRef; seq: string; settlement: AttentionSettlement }
232
- | { event: 'inbound.resource-check.failed'; thread: ThreadRef; seq: string; resource_ref: ResourceRef; code: ErrorCode; attempts: number }
233
- | { event: 'consumption.confirmed'; thread: ThreadRef; seq: string; context: string; via: 'fragment' | 'tool_result' }
234
- | { event: 'outbound.admitted'; sender: NodeId; message: string; target: string; state: string; guarantee?: string; code?: string; resolved?: NodeId }
235
- | { event: 'outbound.redriven'; sender: NodeId; message: string; target: string }
236
- | { event: 'outbound.expired'; sender: NodeId; message: string; code: string }
237
- | { event: 'await.settled'; thread: ThreadRef; seq: string; waiters: number }
238
- /**
239
- * A known owner this node could not reconcile, written at most once per (owner, thread, code)
240
- * per window. `attempts` is how many failed passes that one line accounts for, the suppressed
241
- * duplicates included; the local rows a failed pull never reached are still owed, not dropped.
242
- */
243
- | { event: 'reconcile.failed'; owner: NodeId; thread: string; code: ErrorCode; message: string; attempts: number };
244
- /** What the host did with one inbound entry, reported back with the injection result. */
245
- export type InjectOutcome = 'delivered' | 'queued' | 'waiting' | 'skipped' | 'consumed';
246
- export interface Runtime {
247
- supports(plan: DeliveryPlan, message?: Message): Promise<boolean>;
248
- /** Submission returns consumed:false; an observed request boundary may confirm it later. */
249
- inject(entry: Entry, context?: string, plan?: DeliveryPlan): Promise<{ context: string; consumed: boolean; outcome?: InjectOutcome }>;
250
- todo?(entry: Entry, context: string): Promise<void>;
251
- /**
252
- * RFC 0017 §5: the one notification channel. The node calls it for every committed
253
- * trust transition, every inbound entry, and after each maintenance pass that changed
254
- * the pending-work answer. A host that renders from these events never polls storage
255
- * on its own; a host that misses one still converges on the next maintenance pass.
256
- */
257
- notify(event: NotifyEvent): void;
258
- /**
259
- * Optional structured trace. The node calls it on every lifecycle transition; the host maps
260
- * it onto its own log, so a delivery can be followed from admission to consumption offline.
261
- */
262
- trace?(event: TraceEvent): void;
263
- /**
264
- * Called by the host once it observes that the model consumed an `await` tool result
265
- * (RFC 0008 §5). The library records that as the shared consumption for the entry's
266
- * `(context, ThreadRef, seq)`, so the automatic fragment does not present it again.
267
- */
268
- confirmToolResult?(entry: Entry, context: string): Promise<void>;
269
- }
270
- export interface ResourceDriver {
271
- validate(resource: Resource, operation: string, data: Json | undefined): Promise<void>;
272
- execute(resource: Resource, request: OperationRequest, signal?: AbortSignal): Promise<Omit<OperationResult, 'operation_id'>>;
273
- query?(resource: Resource, operation_id: string): Promise<Omit<OperationResult, 'operation_id'>>;
274
- }
275
- /** RFC 0017 key material the host hands the library: the signing key and the public key it proves. */
276
- export interface KeyMaterial {
277
- readonly private_key: Uint8Array;
278
- readonly public_key: Uint8Array;
279
- }
280
-
281
- /** Load-or-create the node identity key; storage is the host's choice (RFC 0017 §2). */
282
- export type KeyHook = (() => Promise<KeyMaterial>) & { replace?(material: KeyMaterial): Promise<void> };
283
-
284
- export interface KeyIdentity {
285
- node_id: NodeId;
286
- public_key: string;
287
- fingerprint: string;
288
- }
289
-
290
- export interface TrustSeed { node_id: NodeId; fingerprint: string }
291
-
292
- export interface TrustStatement {
293
- node_id: NodeId;
294
- target: NodeId;
295
- public_key: string;
296
- target_fingerprint: string;
297
- base_url: string;
298
- approved: boolean;
299
- nonce: string;
300
- timestamp: number;
301
- signature: string;
302
- previous_signature?: string;
303
- /**
304
- * Set on a reply: the nonce of the request this statement answers. A sender settles its
305
- * delivery obligation only on a reply that echoes the nonce it sent (RFC 0017 §3.5).
306
- */
307
- reply_nonce?: string;
308
- }
309
-
310
- /**
311
- * The observable stage of one trust relation, derived only from the approval halves
312
- * (RFC 0017 §3). A host renders and decides from this value; it never re-derives
313
- * the stage from the raw halves.
314
- */
315
- export type TrustPhase = 'invited' | 'requested' | 'exchanged' | 'revoked';
316
-
317
- /** RFC 0017 §5: what changed when the node calls `runtime.notify`. */
318
- export type NotifyEvent =
319
- | { event: 'work-pending'; pending: boolean }
320
- | { event: 'trust'; cause: 'local-request' | 'local-accept' | 'local-revoke' | 'peer-statement' | 'rotation'; phase: TrustPhase; entry: TrustEntry; previous?: TrustEntry }
321
- | { event: 'inbound'; thread: ThreadRef; seq: string; sender: NodeId };
322
-
323
- /** RFC 0017 §3: one exchange, as one object. `begin` hands this to the host. */
324
- export interface KeyExchange {
325
- /** The peer the host named; the statement proves this identity, never a guess from discovery. */
326
- readonly node_id: NodeId;
327
- /** The fingerprint the peer's live key lookup proved at `begin` time. */
328
- readonly fingerprint: string;
329
- readonly public_key: string;
330
- readonly base_url: string;
331
- /**
332
- * Commits local approval and sends the signed introduction. `fingerprint` must repeat
333
- * the value shown to the user: a changed key between display and commit fails here.
334
- */
335
- confirm(fingerprint: string): Promise<TrustEntry>;
336
- }
337
-
338
- /** One trust-table row: a peer's verified public key and the exchange state. */
339
- export interface TrustEntry {
340
- readonly node_id: NodeId;
341
- readonly public_key: string;
342
- readonly fingerprint: string;
343
- readonly state: 'pending' | 'trusted' | 'revoked';
344
- readonly first_seen: string;
345
- readonly last_checked: string;
346
- readonly local_approved: boolean;
347
- readonly remote_approved: boolean;
348
- readonly base_url: string;
349
- readonly history?: string[];
350
- }
351
-
352
- /** The stage derived from the approval halves; the single source hosts read (RFC 0017 §3). */
353
- export function trustPhase(entry: Pick<TrustEntry, 'local_approved' | 'remote_approved' | 'state'>): TrustPhase {
354
- if (entry.state === 'revoked') return 'revoked';
355
- if (entry.local_approved && entry.remote_approved) return 'exchanged';
356
- return entry.local_approved ? 'requested' : 'invited';
357
- }
358
-
359
- /**
360
- * What an admission policy may read. The policy runs inside the admission transaction, so it
361
- * MUST read through this view and MUST NOT open a storage transaction of its own: the outer
362
- * transaction still holds the store, and a nested one waits on it forever.
363
- */
364
- export interface AdmissionContext {
365
- /** The peer's exchange stage, or undefined when the two nodes never exchanged keys. */
366
- trust(node: NodeId): Promise<TrustPhase | undefined>;
367
- }
368
-
369
- export interface Plugins {
370
- storage: Storage;
371
- authenticate(request: Request): Promise<Auth | null>;
372
- keys?: KeyHook;
373
- trust_seeds?: TrustSeed[];
374
- resolve(node: NodeId): Promise<Target>;
375
- decide(input: MsgInput): Promise<Action>;
376
- runtime?: Runtime;
377
- /** When true, candidate exchange allows loopback addresses (useful in local dev & testing). */
378
- allow_loopback?: boolean;
379
- /** Supplied when the host wants the library to own the maintenance loop (RFC 0017 §6). */
380
- maintenanceClock?: MaintenanceClock;
381
- resources?: ResourceDriver;
382
- /** The host may adopt a dynamic resource after HTTP authentication and request parsing. */
383
- prepareResourceOperation?(auth: Auth, ref: ResourceRef, request: OperationRequest): Promise<void>;
384
- transport?: Transport;
385
- mayAdmit?(actor: NodeId, thread: ThreadRef, context: AdmissionContext): Promise<boolean>;
386
- /** Owner policy permitting a first-contact thread and membership for this actor. */
387
- inboundThread?(actor: NodeId, context: AdmissionContext): Promise<boolean>;
388
- /**
389
- * Target-side handover policy (RFC 0006 §4.3): whether this node takes over the resource
390
- * a probe names. The probe's `metadata` is what it judges from; `sender` is the endpoint
391
- * whose signature the probe carried. A node without this hook accepts every well-formed
392
- * probe from an authenticated peer.
393
- */
394
- handoverProbe?(probe: HandoverProbe, sender: NodeId): Promise<ProbeAnswer>;
395
- directory?(): Promise<Json>;
396
- executionContexts?(): Promise<Json>;
397
- domainCandidates?(domain_id: DomainId): Promise<NodeId[]>;
398
- /** Resolves a thread-local mention alias to the member node it names. */
399
- mention?(alias: string, thread: ThreadRef): Promise<NodeId>;
400
- /** Observed nodes with trust state; the same rows onlyne://neighbors renders. */
401
- neighbors?(): Promise<unknown>;
402
- }
403
- export interface NodeOptions {
404
- node_id: NodeId; base_url: string; plugins: Plugins;
405
- instance_id?: string; authentication?: string[];
406
- request_bytes?: number; retry_max_ms?: number; wait_ms?: number;
407
- /**
408
- * The trusted tick source, required at construction (RFC 0017 §6). Every protocol
409
- * clock read — transcript windows, nonce expiry, retry gates — goes through `now`,
410
- * and every nonce through `id`. A host that cannot supply an unguessable `id` must
411
- * refuse to run a keyed node instead of falling back to a default.
412
- */
413
- now: () => number;
414
- id: () => string;
415
- }
416
-
417
- /**
418
- * RFC 0017 §6: the timer primitives the library's maintenance loop needs. Supplying
419
- * them opts into `client.runMaintenance`, the loop the library owns: cadence, wake
420
- * handling and the pending-work re-arm all live there, so a host cannot poll at a
421
- * rate the protocol does not sanction. `setTimer` is one-shot: it calls `run` once and
422
- * the loop re-arms, so a host that repeats the callback breaks the cadence contract.
423
- * Every clock read goes through `NodeOptions.now`; the clock carries no second time source.
424
- */
425
- export interface MaintenanceClock {
426
- setTimer(ms: number, run: () => void): unknown;
427
- clearTimer(handle: unknown): void;
428
- }