@peers-app/peers-sdk 0.19.14 → 0.20.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 (86) hide show
  1. package/dist/contracts/__tests__/builder.test.js +24 -0
  2. package/dist/contracts/__tests__/contract-events.test.d.ts +1 -0
  3. package/dist/contracts/__tests__/contract-events.test.js +199 -0
  4. package/dist/contracts/__tests__/contract-observables.test.d.ts +1 -0
  5. package/dist/contracts/__tests__/contract-observables.test.js +290 -0
  6. package/dist/contracts/__tests__/contract-provider-router.test.d.ts +1 -0
  7. package/dist/contracts/__tests__/contract-provider-router.test.js +193 -0
  8. package/dist/contracts/__tests__/contract-proxy.test.d.ts +1 -0
  9. package/dist/contracts/__tests__/contract-proxy.test.js +424 -0
  10. package/dist/contracts/__tests__/contract-resolvers.test.d.ts +1 -0
  11. package/dist/contracts/__tests__/contract-resolvers.test.js +148 -0
  12. package/dist/contracts/__tests__/contract-subscription-lifecycle.test.d.ts +1 -0
  13. package/dist/contracts/__tests__/contract-subscription-lifecycle.test.js +353 -0
  14. package/dist/contracts/__tests__/contract-table-events.test.d.ts +1 -0
  15. package/dist/contracts/__tests__/contract-table-events.test.js +209 -0
  16. package/dist/contracts/__tests__/contract-transport.test.d.ts +1 -0
  17. package/dist/contracts/__tests__/contract-transport.test.js +163 -0
  18. package/dist/contracts/__tests__/persistent-registry.test.d.ts +1 -0
  19. package/dist/contracts/__tests__/persistent-registry.test.js +109 -0
  20. package/dist/contracts/__tests__/playground.test.d.ts +1 -0
  21. package/dist/contracts/__tests__/playground.test.js +213 -0
  22. package/dist/contracts/__tests__/validate.test.js +122 -0
  23. package/dist/contracts/builder.d.ts +9 -1
  24. package/dist/contracts/builder.js +13 -0
  25. package/dist/contracts/contract-provider-router.d.ts +72 -0
  26. package/dist/contracts/contract-provider-router.js +164 -0
  27. package/dist/contracts/contract-proxy.d.ts +333 -0
  28. package/dist/contracts/contract-proxy.js +663 -0
  29. package/dist/contracts/contract-resolvers.d.ts +66 -0
  30. package/dist/contracts/contract-resolvers.js +138 -0
  31. package/dist/contracts/contract-transport.d.ts +94 -0
  32. package/dist/contracts/contract-transport.js +159 -0
  33. package/dist/contracts/contracts.table.d.ts +1 -1
  34. package/dist/contracts/contracts.table.js +2 -2
  35. package/dist/contracts/index.d.ts +7 -1
  36. package/dist/contracts/index.js +34 -1
  37. package/dist/contracts/persistent-registry.js +3 -1
  38. package/dist/contracts/system/device-operations-contract.d.ts +72 -0
  39. package/dist/contracts/system/device-operations-contract.js +110 -0
  40. package/dist/contracts/system/logs-contract.d.ts +24 -0
  41. package/dist/contracts/system/logs-contract.js +60 -0
  42. package/dist/contracts/types.d.ts +27 -4
  43. package/dist/contracts/validate.d.ts +2 -2
  44. package/dist/contracts/validate.js +44 -2
  45. package/dist/data/assistants.d.ts +4 -4
  46. package/dist/data/channels.d.ts +1 -1
  47. package/dist/data/devices.d.ts +1 -1
  48. package/dist/data/embeddings.d.ts +1 -1
  49. package/dist/data/group-secret.d.ts +21 -0
  50. package/dist/data/group-secret.js +53 -0
  51. package/dist/data/index.d.ts +1 -0
  52. package/dist/data/index.js +1 -0
  53. package/dist/data/messages.d.ts +1 -1
  54. package/dist/data/orm/decorators.d.ts +6 -0
  55. package/dist/data/orm/decorators.js +21 -0
  56. package/dist/data/package-versions.d.ts +2 -2
  57. package/dist/data/peer-types.d.ts +1 -1
  58. package/dist/data/persistent-vars.d.ts +17 -0
  59. package/dist/data/persistent-vars.js +115 -35
  60. package/dist/data/persistent-vars.migration.test.d.ts +1 -0
  61. package/dist/data/persistent-vars.migration.test.js +133 -0
  62. package/dist/data/table-definitions-table.d.ts +1 -1
  63. package/dist/data/tool-tests.d.ts +1 -1
  64. package/dist/data/tools.d.ts +1 -1
  65. package/dist/data/user-trust-levels.d.ts +3 -1
  66. package/dist/data/user-trust-levels.js +2 -1
  67. package/dist/data/user-trust-levels.test.d.ts +1 -0
  68. package/dist/data/user-trust-levels.test.js +37 -0
  69. package/dist/data/voice-messages.d.ts +1 -1
  70. package/dist/data/workflow-logs.d.ts +1 -1
  71. package/dist/data/workflow-runs.d.ts +2 -2
  72. package/dist/data/workflows.d.ts +3 -3
  73. package/dist/device/binary-peer-connection-v2.d.ts +2 -0
  74. package/dist/device/binary-peer-connection-v2.js +12 -2
  75. package/dist/device/binary-peer-connection-v2.test.js +23 -0
  76. package/dist/device/get-trust-level-fn.d.ts +6 -0
  77. package/dist/device/get-trust-level-fn.js +12 -7
  78. package/dist/device/get-trust-level-fn.test.js +16 -2
  79. package/dist/logging/console-logs.table.d.ts +3 -0
  80. package/dist/logging/console-logs.table.js +2 -1
  81. package/dist/rpc-types.d.ts +37 -0
  82. package/dist/rpc-types.js +13 -0
  83. package/dist/system-ids.d.ts +25 -0
  84. package/dist/system-ids.js +26 -1
  85. package/dist/types/workflow.d.ts +4 -4
  86. package/package.json +1 -1
@@ -0,0 +1,333 @@
1
+ import type { Table } from "../data/orm/table";
2
+ import type { IToolInstance } from "../data/tools";
3
+ import type { Event, ISubscriptionResult } from "../events";
4
+ import { type Observable } from "../observable";
5
+ import { type IContractTransport } from "./contract-transport";
6
+ import type { IContractDefinition } from "./types";
7
+ /**
8
+ * The RPC event name used to proxy a single {@link IContractCall} over a
9
+ * {@link Connection} (`connection.emit(CONTRACT_CALL_RPC, call)` on the consumer
10
+ * side; `connection.exposeRPC(CONTRACT_CALL_RPC, handler)` on the provider side).
11
+ *
12
+ * Alias of {@link CONTRACT_REQUEST_CHANNEL} — the fixed request/response channel of an
13
+ * {@link IContractTransport}. Kept for existing provider registrations that reference it.
14
+ */
15
+ export declare const CONTRACT_CALL_RPC = "contractCall";
16
+ /** The kind of contract member being invoked. */
17
+ export type ContractMemberType = "table" | "tool" | "observable" | "event";
18
+ /**
19
+ * A single, fully-serializable invocation against a contract member. This is the
20
+ * wire format passed between a contract **consumer** (which produces it) and a
21
+ * contract **provider** (which executes it) regardless of transport — same process,
22
+ * another iframe, or a remote device connection.
23
+ */
24
+ export interface IContractCall {
25
+ /** Target contract id. */
26
+ contractId: string;
27
+ /** Target contract version. */
28
+ version: number;
29
+ /** Which kind of member is being invoked. */
30
+ member: ContractMemberType;
31
+ /** Name of the table / tool / observable within the contract. */
32
+ name: string;
33
+ /**
34
+ * Operation to perform on the member:
35
+ * - `table`: the table method name (`"list"`, `"get"`, `"save"`, …), or the reserved
36
+ * `"subscribe"` / `"unsubscribe"` to (un)subscribe to a table event (see
37
+ * {@link IContractCall.event}). A `Table` has no methods by those names, so they are
38
+ * safe to reserve.
39
+ * - `tool`: always `"run"`
40
+ * - `observable`: `"get"` / `"set"` for one-shot reads/writes, or the reserved
41
+ * `"subscribe"` / `"unsubscribe"` to (un)subscribe to the observable's value-change
42
+ * stream. Unlike events, observable streaming is *not* consumer-gated: the consumer
43
+ * subscribes implicitly when its proxy is built (see {@link IContractConsumer.observables}).
44
+ * - `event`: `"subscribe"` or `"unsubscribe"`
45
+ */
46
+ operation: string;
47
+ /** Positional arguments for the operation. */
48
+ args: unknown[];
49
+ /**
50
+ * Optional data context (group) requested by the consumer. The trusted provider host
51
+ * selects the canonical route; the current user-context provider defaults an omitted
52
+ * id to the local provider user's personal context.
53
+ */
54
+ dataContextId?: string;
55
+ /**
56
+ * For any subscription call (a generic `event`, a table `dataChanged`, or an observable
57
+ * value stream): the consumer-chosen id that ties a `"subscribe"` (and its later
58
+ * `"unsubscribe"`) to the {@link IContractNotification}s pushed back for it. Globally
59
+ * unique so a shared transport can multiplex many subscriptions.
60
+ */
61
+ subscriptionId?: string;
62
+ /**
63
+ * For a `table` member with a `"subscribe"` / `"unsubscribe"` operation: names the
64
+ * table event to subscribe to. Currently always `"dataChanged"`, which is also the
65
+ * default when absent. Not used by generic `event` members — those carry the event
66
+ * name in {@link IContractCall.name}.
67
+ */
68
+ event?: string;
69
+ }
70
+ /**
71
+ * A provider→consumer push delivered on {@link CONTRACT_NOTIFY_CHANNEL}. The consumer
72
+ * routes it purely by {@link IContractNotification.subscriptionId} to the handler that
73
+ * registered that id, so notifications for other consumers' subscriptions on a shared
74
+ * transport are simply ignored.
75
+ */
76
+ export interface IContractNotification {
77
+ /** The subscription this payload belongs to (matches an earlier `event.subscribe`). */
78
+ subscriptionId: string;
79
+ /** The event payload emitted by the provider. */
80
+ value: unknown;
81
+ /** Originating contract id — informational, for debugging/logging only. */
82
+ contractId?: string;
83
+ /** Originating event name — informational, for debugging/logging only. */
84
+ name?: string;
85
+ }
86
+ /**
87
+ * The consumer-side proxy for a single contract table. Any accessed name is forwarded
88
+ * as a remote method call returning a promise, **except** `dataChanged`, which is a
89
+ * subscribable that rides the notify channel like a generic event (subscription-gated).
90
+ *
91
+ * Declared as an intersection so `dataChanged` type-checks as a subscribable while
92
+ * `.list(...)`, `.save(...)`, etc. still type-check as async methods. This is a widening
93
+ * of precise per-table typing (deferred to a later phase).
94
+ */
95
+ export type IContractTableProxy = Record<string, (...args: any[]) => Promise<any>> & {
96
+ /**
97
+ * Subscribe to the provider table's `dataChanged` event over the transport.
98
+ * Subscription-gated and refcounted exactly like a generic contract event; returns an
99
+ * {@link ISubscriptionResult} whose `unsubscribe()` stops delivery.
100
+ */
101
+ dataChanged: {
102
+ subscribe(handler: (event: any) => void): ISubscriptionResult;
103
+ };
104
+ };
105
+ /**
106
+ * A live proxy over a contract, handed to a **consumer**. Every member access is
107
+ * turned into an {@link IContractCall} and dispatched through the transport, so the
108
+ * consumer interacts with the contract identically no matter where the provider runs.
109
+ */
110
+ export interface IContractConsumer {
111
+ contractId: string;
112
+ version: number;
113
+ /**
114
+ * `tables[name].<method>(...args)` → the remote table method's result, or
115
+ * `tables[name].dataChanged.subscribe(handler)` → a subscription to the remote table's
116
+ * `dataChanged` event (see {@link IContractTableProxy}).
117
+ */
118
+ tables: Record<string, IContractTableProxy>;
119
+ /** `tools[name](...args)` → the remote tool's result. */
120
+ tools: Record<string, (...args: any[]) => Promise<any>>;
121
+ /**
122
+ * `observables[name]` is a live, callable {@link Observable} that mirrors the provider's
123
+ * observable: call it with no args to read the latest streamed value synchronously, or
124
+ * with a value to write it when the contract marks it writable (fire-and-forget;
125
+ * durability is awaitable via {@link IContractConsumer.loadingPromise}). A read-only
126
+ * write throws before changing the mirror or emitting. Unlike events and table `dataChanged`,
127
+ * observable streaming is *not* subscription-gated — the consumer subscribes implicitly
128
+ * when the proxy is built and the provider always streams changes, so the mirror is kept
129
+ * current for synchronous reads (see decision 4 in the implementation doc).
130
+ */
131
+ observables: Record<string, Observable<any>>;
132
+ /**
133
+ * `events[name].subscribe(handler)` → registers `handler` for provider pushes of that
134
+ * event and asks the provider to start sending. Returns an {@link ISubscriptionResult}
135
+ * whose `unsubscribe()` stops delivery and tells the provider to stop sending — the same
136
+ * shape as the local {@link Event} API, so consumers subscribe identically regardless of
137
+ * where the provider runs.
138
+ */
139
+ events: Record<string, {
140
+ subscribe: (handler: (value: any) => void) => ISubscriptionResult;
141
+ }>;
142
+ /**
143
+ * Resolves once every observable's initial snapshot has loaded (so reads are meaningful),
144
+ * then is re-chained on each local observable write so `await consumer.loadingPromise`
145
+ * also awaits write durability. Mirrors the persistent-var `loadingPromise` pattern
146
+ * ([`persistent-vars.ts`](../data/persistent-vars.ts)). Always resolves (never rejects);
147
+ * a failed writable set is logged once and leaves the optimistic mirror in place until
148
+ * the next provider push reconciles it.
149
+ */
150
+ loadingPromise: Promise<void>;
151
+ /**
152
+ * Idempotently detach everything this consumer opened: generic events, table events,
153
+ * always-on observable streams, observable write observers, and its notify listener.
154
+ * New remote table/tool calls and subscriptions reject after disposal; cached observable
155
+ * reads remain available, but observable writes throw.
156
+ */
157
+ dispose(): void;
158
+ }
159
+ /**
160
+ * Build the **consumer** side of a contract proxy from a contract definition and a
161
+ * transport. Member names come from the contract shape; table members are backed by a
162
+ * `Proxy` that forwards accessed method names. The provider accepts only standard data
163
+ * operations and custom methods marked by `ProxyClientTableMethodCalls`.
164
+ *
165
+ * Every access is turned into an {@link IContractCall} sent on the transport's fixed
166
+ * {@link CONTRACT_REQUEST_CHANNEL}; the resolved ack is the provider's return value.
167
+ *
168
+ * The consumer also subscribes to provider pushes: `events[name].subscribe(handler)` and
169
+ * `tables[name].dataChanged.subscribe(handler)` both send a `"subscribe"` request and
170
+ * demultiplex provider pushes arriving on {@link CONTRACT_NOTIFY_CHANNEL} by their
171
+ * `subscriptionId` (shared `subscribeVia` path). Observables use the same push channel but
172
+ * are *not* gated: each `observables[name]` is a live {@link Observable} mirror that subscribes
173
+ * implicitly at creation, loads an initial snapshot (awaitable via
174
+ * {@link IContractConsumer.loadingPromise}), and streams every subsequent change; local writes
175
+ * send a fire-and-forget `set`. Call {@link IContractConsumer.dispose} to remove the notify
176
+ * listener and unsubscribe every stream. Read-only observable writes are rejected on both
177
+ * consumer and provider boundaries. Disposal is idempotent and prevents new remote operations;
178
+ * cached observable reads remain available afterward.
179
+ *
180
+ * @param contract The contract definition (shape) being consumed.
181
+ * @param transport Bidirectional channel to the provider; requests go out on
182
+ * {@link CONTRACT_REQUEST_CHANNEL}, notifications arrive on {@link CONTRACT_NOTIFY_CHANNEL}.
183
+ * @param opts.dataContextId Optional data context to scope every call to.
184
+ */
185
+ export declare function createContractConsumer(contract: IContractDefinition, transport: IContractTransport, opts?: {
186
+ dataContextId?: string;
187
+ }): IContractConsumer;
188
+ /**
189
+ * The live implementation a **provider** dispatches contract calls to. This is the
190
+ * runtime-callable counterpart to {@link IResolvedContract} (which additionally tracks
191
+ * the providing package); the proxy layer only needs the live members.
192
+ */
193
+ export interface IContractResolution {
194
+ contractId: string;
195
+ version: number;
196
+ tables?: Record<string, Table<any>>;
197
+ tools?: Record<string, IToolInstance>;
198
+ observables?: Record<string, Observable<any>>;
199
+ /**
200
+ * Provider-owned write policy for live observables. A `set` is allowed only when the
201
+ * matching entry is explicitly `true`; crafted calls cannot bypass a contract's
202
+ * read-only declaration.
203
+ */
204
+ observableWritability?: Record<string, boolean>;
205
+ /**
206
+ * Live events the provider forwards from, keyed by contract event name. A
207
+ * {@link createContractProviderEndpoint} subscribes to these on demand and passes
208
+ * their payloads to its configured notification sink.
209
+ */
210
+ events?: Record<string, Event<any>>;
211
+ }
212
+ /** Identity of the caller, supplied by the transport layer for permission checks. */
213
+ export interface IContractCallContext {
214
+ /** User id of the caller (e.g. the remote device's user), if known. */
215
+ callerUserId?: string;
216
+ /** User id of the local device executing the call. */
217
+ localUserId?: string;
218
+ }
219
+ /**
220
+ * A gate that decides whether a given call is allowed. Runs before dispatch on the
221
+ * provider side. Return `false` (or throw) to deny.
222
+ */
223
+ export type ContractPermissionCheck = (call: IContractCall, context: IContractCallContext) => boolean | Promise<boolean>;
224
+ /**
225
+ * Legacy gate that allows calls only when caller and provider user ids match.
226
+ *
227
+ * @deprecated Production connection routing uses the signed-identity, provider-personal
228
+ * Self-trust policy in `createUserContextContractProviderRouter`. Keep this helper only
229
+ * for compatibility and isolated in-process providers that intentionally need the old gate.
230
+ */
231
+ export declare const sameUserContractPermissionCheck: ContractPermissionCheck;
232
+ /**
233
+ * Build the **provider** side of a contract proxy: an async handler that permission-checks
234
+ * an {@link IContractCall} and dispatches it to the live table method / tool fn / observable
235
+ * accessor in the given resolution. Table dispatch is constrained to standard serializable
236
+ * data operations plus custom methods explicitly marked by `ProxyClientTableMethodCalls`;
237
+ * internal helpers, event properties, document/cursor helpers, and prototype properties
238
+ * are not remotely callable.
239
+ *
240
+ * @param resolution The live contract implementation to dispatch to.
241
+ * @param opts.permissionCheck Optional gate run before every dispatch.
242
+ */
243
+ export declare function createContractProvider(resolution: IContractResolution, opts?: {
244
+ permissionCheck?: ContractPermissionCheck;
245
+ }): (call: IContractCall, context?: IContractCallContext) => Promise<any>;
246
+ /** Options for {@link createContractProviderSession}. */
247
+ export interface IContractProviderSessionOptions {
248
+ /** Gate run before every request and every event `subscribe` (see {@link ContractPermissionCheck}). */
249
+ permissionCheck?: ContractPermissionCheck;
250
+ /**
251
+ * Caller identity used for permission checks when the transport does not deliver a
252
+ * per-call {@link IContractCallContext} as the request handler's second argument.
253
+ * In-process wiring typically sets this; a real connection supplies context per call.
254
+ */
255
+ context?: IContractCallContext;
256
+ }
257
+ /**
258
+ * A stateful provider endpoint bound to a single {@link IContractTransport}. Unlike the
259
+ * stateless {@link createContractProvider}, a session also handles subscriptions on every
260
+ * streamable member: generic `event` members, table events (`table` member with
261
+ * `subscribe`/`unsubscribe`, e.g. `dataChanged`), and observable value streams (`observable`
262
+ * member with `subscribe`/`unsubscribe`). It tracks per-consumer subscriptions and pushes
263
+ * matching payloads back independently on {@link CONTRACT_NOTIFY_CHANNEL}. Duplicate
264
+ * subscription ids are rejected without disturbing the existing subscription. Call
265
+ * {@link IContractProviderSession.dispose} to remove the request listener and detach every
266
+ * live subscription.
267
+ */
268
+ export interface IContractProviderSession {
269
+ /** Tear down the request listener and all live subscriptions. */
270
+ dispose(): void;
271
+ }
272
+ /**
273
+ * Delivers a provider notification to the transport or host router that owns an
274
+ * {@link IContractProviderEndpoint}.
275
+ */
276
+ export type ContractNotificationSink = (notification: IContractNotification) => Promise<unknown>;
277
+ /** Options for {@link createContractProviderEndpoint}. */
278
+ export interface IContractProviderEndpointOptions {
279
+ /** Delivers subscription payloads without binding the endpoint to a transport. */
280
+ notify: ContractNotificationSink;
281
+ /** Optional defense-in-depth gate run before calls and subscription creation. */
282
+ permissionCheck?: ContractPermissionCheck;
283
+ /** Default caller identity when {@link IContractProviderEndpoint.handleCall} omits it. */
284
+ context?: IContractCallContext;
285
+ }
286
+ /**
287
+ * Stateful provider dispatcher independent of any particular transport. A host router can
288
+ * cache one endpoint per contract/version/data-context route, or a transport-bound provider
289
+ * session can wrap it for backward compatibility.
290
+ */
291
+ export interface IContractProviderEndpoint {
292
+ /**
293
+ * Dispatch a request/response or subscription call. Subscribe operations are permission
294
+ * checked and tracked; unsubscribe is idempotent and intentionally skips reauthorization.
295
+ */
296
+ handleCall(call: IContractCall, context?: IContractCallContext): Promise<any>;
297
+ /** Detach every live subscription. Idempotent. */
298
+ dispose(): void;
299
+ }
300
+ /**
301
+ * Build a stateful **provider endpoint**: it serves the same request/response dispatch as
302
+ * {@link createContractProvider} for table/tool/observable calls, and additionally serves
303
+ * subscriptions on any streamable member — generic `event` calls, table events (a `table`
304
+ * member with `"subscribe"` / `"unsubscribe"`, resolving `dataChanged` by default), and
305
+ * observable value streams (an `observable` member with `"subscribe"` / `"unsubscribe"`;
306
+ * `get`/`set` still flow to the stateless dispatch).
307
+ *
308
+ * The live source — an {@link Event} (`resolution.events[name]` or a table's `dataChanged`)
309
+ * or an {@link Observable} (`resolution.observables[name]`) — is only subscribed to while at
310
+ * least one consumer holds a subscription (refcounted by a resolved key), and each payload is
311
+ * fanned out through the supplied {@link ContractNotificationSink} as an
312
+ * {@link IContractNotification}. The endpoint owns no request listener, which lets a
313
+ * connection-wide router multiplex many endpoints through one request channel and later
314
+ * substitute sandbox-backed endpoint implementations.
315
+ *
316
+ * @param resolution The live contract implementation to dispatch to and stream from.
317
+ * @param opts Notification sink plus optional permission gate and default context.
318
+ */
319
+ export declare function createContractProviderEndpoint(resolution: IContractResolution, opts: IContractProviderEndpointOptions): IContractProviderEndpoint;
320
+ /**
321
+ * Build the backward-compatible transport-bound provider session. The session owns the
322
+ * transport's request listener while its underlying {@link IContractProviderEndpoint} owns
323
+ * request dispatch and live subscription state.
324
+ *
325
+ * Use {@link createContractProviderEndpoint} behind a connection-wide router when multiple
326
+ * contracts or data contexts share one transport.
327
+ *
328
+ * @param resolution The live contract implementation to dispatch to and stream from.
329
+ * @param transport Requests arrive on {@link CONTRACT_REQUEST_CHANNEL}; notifications are
330
+ * emitted on {@link CONTRACT_NOTIFY_CHANNEL}.
331
+ * @param opts Optional permission gate and default caller context.
332
+ */
333
+ export declare function createContractProviderSession(resolution: IContractResolution, transport: IContractTransport, opts?: IContractProviderSessionOptions): IContractProviderSession;