@peers-app/peers-sdk 0.23.9 → 0.23.11
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.
- package/dist/context/user-context-singleton.js +19 -4
- package/dist/contracts/__tests__/builder.test.js +25 -0
- package/dist/contracts/__tests__/contract-provider-router.test.js +45 -0
- package/dist/contracts/__tests__/contract-proxy.test.js +67 -0
- package/dist/contracts/__tests__/contract-resolvers.test.js +133 -0
- package/dist/contracts/__tests__/remote-contract-transport.test.d.ts +1 -0
- package/dist/contracts/__tests__/remote-contract-transport.test.js +89 -0
- package/dist/contracts/builder.d.ts +47 -1
- package/dist/contracts/builder.js +80 -22
- package/dist/contracts/contract-provider-router.d.ts +6 -0
- package/dist/contracts/contract-provider-router.js +25 -3
- package/dist/contracts/contract-proxy.d.ts +41 -1
- package/dist/contracts/contract-proxy.js +103 -0
- package/dist/contracts/contract-resolvers.d.ts +47 -13
- package/dist/contracts/contract-resolvers.js +125 -35
- package/dist/contracts/extract.d.ts +4 -1
- package/dist/contracts/extract.js +3 -1
- package/dist/contracts/index.d.ts +4 -3
- package/dist/contracts/index.js +10 -2
- package/dist/contracts/remote-contract-transport.d.ts +69 -0
- package/dist/contracts/remote-contract-transport.js +95 -0
- package/dist/contracts/types.d.ts +57 -0
- package/dist/data/persistent-vars.d.ts +8 -0
- package/dist/data/persistent-vars.js +56 -11
- package/dist/data/tool-access-approvals.d.ts +2 -2
- package/dist/data/tools.d.ts +4 -0
- package/dist/data/tools.js +7 -0
- package/dist/package-loader/isolated-artifact.js +16 -1
- package/dist/package-loader/isolated-runtime.d.ts +5 -2
- package/dist/package-loader/package-loader.d.ts +15 -1
- package/dist/package-loader/package-loader.js +48 -0
- package/dist/package-loader/resolve-consumed-contracts.d.ts +6 -2
- package/dist/package-loader/resolve-consumed-contracts.js +30 -2
- package/dist/package-loader/resolve-consumed-contracts.test.js +43 -0
- package/package.json +1 -1
|
@@ -2,10 +2,14 @@
|
|
|
2
2
|
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
3
|
exports.registerContractResolver = registerContractResolver;
|
|
4
4
|
exports.getContractResolver = getContractResolver;
|
|
5
|
+
exports.verifyRemoteContractIdentity = verifyRemoteContractIdentity;
|
|
5
6
|
exports.isSelfTrustedContractCaller = isSelfTrustedContractCaller;
|
|
7
|
+
exports.authorizeRemoteContractCall = authorizeRemoteContractCall;
|
|
6
8
|
exports.createLocalUserContextContractProviderRouter = createLocalUserContextContractProviderRouter;
|
|
7
9
|
exports.createUserContextContractProviderRouter = createUserContextContractProviderRouter;
|
|
8
10
|
exports.handleContractCall = handleContractCall;
|
|
11
|
+
const access_level_1 = require("../data/access-level");
|
|
12
|
+
const group_permissions_1 = require("../data/group-permissions");
|
|
9
13
|
const user_permissions_1 = require("../data/user-permissions");
|
|
10
14
|
const user_trust_levels_1 = require("../data/user-trust-levels");
|
|
11
15
|
const users_1 = require("../data/users");
|
|
@@ -13,6 +17,7 @@ const socket_type_1 = require("../device/socket.type");
|
|
|
13
17
|
const system_ids_1 = require("../system-ids");
|
|
14
18
|
const contract_provider_router_1 = require("./contract-provider-router");
|
|
15
19
|
const contract_proxy_1 = require("./contract-proxy");
|
|
20
|
+
const remote_contract_transport_1 = require("./remote-contract-transport");
|
|
16
21
|
const types_1 = require("./types");
|
|
17
22
|
const resolvers = new Map();
|
|
18
23
|
const resolverKey = (contractId, version, providerPackageId) => providerPackageId
|
|
@@ -60,15 +65,17 @@ function getContractResolver(contractId, version, providerPackageId) {
|
|
|
60
65
|
return onlyScopedResolver;
|
|
61
66
|
}
|
|
62
67
|
/**
|
|
63
|
-
*
|
|
68
|
+
* Verify that a connection- or message-authenticated remote identity matches a valid
|
|
69
|
+
* self-signed Users record in the provider's personal or shared-group data.
|
|
64
70
|
*
|
|
65
|
-
*
|
|
66
|
-
*
|
|
67
|
-
*
|
|
71
|
+
* Unsigned discovery stubs, malformed signatures, and key mismatches fail closed. This is
|
|
72
|
+
* the identity half of remote authorization; trust and role decisions build on it.
|
|
73
|
+
*
|
|
74
|
+
* @param userContext Provider's user context whose data is searched.
|
|
75
|
+
* @param remoteIdentity Identity derived from the verified transport.
|
|
68
76
|
*/
|
|
69
|
-
async function
|
|
77
|
+
async function verifyRemoteContractIdentity(userContext, remoteIdentity) {
|
|
70
78
|
const identityContexts = [userContext.userDataContext, ...userContext.groupDataContexts.values()];
|
|
71
|
-
let hasVerifiedIdentity = false;
|
|
72
79
|
for (const dataContext of identityContexts) {
|
|
73
80
|
const user = await (0, users_1.Users)(dataContext).get(remoteIdentity.userId);
|
|
74
81
|
if (!user?.signature ||
|
|
@@ -79,38 +86,113 @@ async function isSelfTrustedContractCaller(userContext, remoteIdentity) {
|
|
|
79
86
|
}
|
|
80
87
|
try {
|
|
81
88
|
(0, user_permissions_1.verifyUserSignature)(user);
|
|
82
|
-
|
|
83
|
-
break;
|
|
89
|
+
return true;
|
|
84
90
|
}
|
|
85
91
|
catch {
|
|
86
92
|
// A different context may contain the valid signed record.
|
|
87
93
|
}
|
|
88
94
|
}
|
|
89
|
-
|
|
90
|
-
|
|
91
|
-
|
|
95
|
+
return false;
|
|
96
|
+
}
|
|
97
|
+
/**
|
|
98
|
+
* Whether the provider's personal context assigns exactly {@link TrustLevel.Self} to a
|
|
99
|
+
* (previously identity-verified) remote user. The provider's own account is always Self.
|
|
100
|
+
*/
|
|
101
|
+
async function hasSelfTrust(userContext, remoteIdentity) {
|
|
92
102
|
const trustLevel = remoteIdentity.userId === userContext.userId
|
|
93
103
|
? socket_type_1.TrustLevel.Self
|
|
94
104
|
: ((await (0, user_trust_levels_1.UserTrustLevels)(userContext.userDataContext).get(remoteIdentity.userId))
|
|
95
105
|
?.trustLevel ?? socket_type_1.TrustLevel.Unknown);
|
|
96
106
|
return trustLevel === socket_type_1.TrustLevel.Self;
|
|
97
107
|
}
|
|
98
|
-
|
|
108
|
+
/**
|
|
109
|
+
* Check whether a connection-authenticated remote identity has full contract authority.
|
|
110
|
+
*
|
|
111
|
+
* The identity must match a valid self-signed Users record in the provider's personal or
|
|
112
|
+
* shared-group data, and the provider's personal context must assign the caller exactly
|
|
113
|
+
* {@link TrustLevel.Self}. Unsigned discovery stubs and key mismatches fail closed.
|
|
114
|
+
*/
|
|
115
|
+
async function isSelfTrustedContractCaller(userContext, remoteIdentity) {
|
|
116
|
+
if (!(await verifyRemoteContractIdentity(userContext, remoteIdentity))) {
|
|
117
|
+
return false;
|
|
118
|
+
}
|
|
119
|
+
return hasSelfTrust(userContext, remoteIdentity);
|
|
120
|
+
}
|
|
121
|
+
const permissionDenied = (call, reason) => new Error(`Permission denied: ${call.member} '${call.name}'.${call.operation} on contract ${call.contractId}${reason ? ` (${reason})` : ""}`);
|
|
122
|
+
/**
|
|
123
|
+
* Authorize one inbound contract call from **another device**.
|
|
124
|
+
*
|
|
125
|
+
* Layered policy, evaluated in order:
|
|
126
|
+
* 1. Calls that still carry a `targetDeviceId` are denied: a remote caller may not use
|
|
127
|
+
* this device as a relay under its identity. The tool-access-control contract is
|
|
128
|
+
* local-only.
|
|
129
|
+
* 2. The caller's keys must match a valid signed Users record known to the provider.
|
|
130
|
+
* 3. A Self-trusted caller (the provider's own account, or an account granted exact
|
|
131
|
+
* `TrustLevel.Self`) keeps full access; an omitted data context selects the provider's
|
|
132
|
+
* personal context.
|
|
133
|
+
* 4. Any other verified caller is treated as a **group member**: the call must name a
|
|
134
|
+
* group the provider belongs to, must be a tool run, the contract definition registered
|
|
135
|
+
* for that group must mark the tool with {@link IContractTool.remoteAccessLevel}, and
|
|
136
|
+
* the caller's role in that group must meet it. Missing loader, definition, or level
|
|
137
|
+
* fails closed.
|
|
138
|
+
*
|
|
139
|
+
* @param call Inbound call.
|
|
140
|
+
* @param userContext Provider's user context.
|
|
141
|
+
* @param remoteIdentity Identity derived from the verified transport (never from the call).
|
|
142
|
+
* @returns The canonical route and caller context for the router.
|
|
143
|
+
*/
|
|
144
|
+
async function authorizeRemoteContractCall(call, userContext, remoteIdentity) {
|
|
145
|
+
if (call.targetDeviceId) {
|
|
146
|
+
throw permissionDenied(call, "remote callers cannot relay through this device");
|
|
147
|
+
}
|
|
99
148
|
if (call.contractId === system_ids_1.toolAccessControlContractId) {
|
|
100
149
|
throw new Error("Permission denied: tool access control is local-only");
|
|
101
150
|
}
|
|
102
|
-
|
|
103
|
-
|
|
104
|
-
|
|
105
|
-
|
|
106
|
-
|
|
107
|
-
|
|
108
|
-
|
|
109
|
-
|
|
151
|
+
if (!(await verifyRemoteContractIdentity(userContext, remoteIdentity))) {
|
|
152
|
+
throw permissionDenied(call, "unverified caller identity");
|
|
153
|
+
}
|
|
154
|
+
if (await hasSelfTrust(userContext, remoteIdentity)) {
|
|
155
|
+
const dataContextId = call.dataContextId || userContext.userId;
|
|
156
|
+
return {
|
|
157
|
+
dataContextId,
|
|
158
|
+
context: {
|
|
159
|
+
callerUserId: remoteIdentity.userId,
|
|
160
|
+
localUserId: userContext.userId,
|
|
161
|
+
callerDeviceId: remoteIdentity.deviceId,
|
|
162
|
+
dataContext: userContext.getDataContext(dataContextId),
|
|
163
|
+
},
|
|
164
|
+
};
|
|
165
|
+
}
|
|
166
|
+
// Group-member path: explicit shared group, tool runs only, remoteAccessLevel required.
|
|
167
|
+
const dataContextId = call.dataContextId;
|
|
168
|
+
if (!dataContextId || !userContext.groupIds().includes(dataContextId)) {
|
|
169
|
+
throw permissionDenied(call, "a shared group data context is required");
|
|
170
|
+
}
|
|
171
|
+
if (call.member !== "tool" || call.operation !== "run") {
|
|
172
|
+
throw permissionDenied(call, "only tool runs are remotely callable");
|
|
173
|
+
}
|
|
174
|
+
const dataContext = userContext.getDataContext(dataContextId);
|
|
175
|
+
const definition = dataContext.packageLoader?.contractRegistry?.getDefinition(call.contractId, call.version);
|
|
176
|
+
const tool = definition?.tools.find((entry) => entry.name === call.name);
|
|
177
|
+
if (!tool) {
|
|
178
|
+
throw permissionDenied(call, "tool is not provided in this data context");
|
|
179
|
+
}
|
|
180
|
+
if (typeof tool.remoteAccessLevel !== "number") {
|
|
181
|
+
throw permissionDenied(call, "tool is not remotely callable");
|
|
182
|
+
}
|
|
183
|
+
const requiredLevel = (0, access_level_1.resolveAccessLevel)(tool.remoteAccessLevel);
|
|
184
|
+
const callerLevel = await (0, group_permissions_1.getUserAccessLevel)(dataContext, remoteIdentity.userId);
|
|
185
|
+
if (callerLevel <= access_level_1.AccessLevel.None || callerLevel < requiredLevel) {
|
|
186
|
+
throw permissionDenied(call, `requires ${(0, access_level_1.getAccessLevelLabel)(requiredLevel)} (${requiredLevel}), caller has ${(0, access_level_1.getAccessLevelLabel)(callerLevel)} (${callerLevel})`);
|
|
110
187
|
}
|
|
111
188
|
return {
|
|
112
189
|
dataContextId,
|
|
113
|
-
context
|
|
190
|
+
context: {
|
|
191
|
+
callerUserId: remoteIdentity.userId,
|
|
192
|
+
localUserId: userContext.userId,
|
|
193
|
+
callerDeviceId: remoteIdentity.deviceId,
|
|
194
|
+
dataContext,
|
|
195
|
+
},
|
|
114
196
|
};
|
|
115
197
|
}
|
|
116
198
|
function getAuthorizedLocalDataContext(userContext, requestedId) {
|
|
@@ -127,6 +209,13 @@ function getActiveProviderPackageId(dataContext, contractId, version) {
|
|
|
127
209
|
return dataContext.packageLoader?.getActiveContractProviderPackageId?.(contractId, version);
|
|
128
210
|
}
|
|
129
211
|
async function resolveDataContextEndpoint(dataContext, request, resolveVariable) {
|
|
212
|
+
const remoteEndpoint = (0, remote_contract_transport_1.resolveRemoteTargetEndpoint)(request, {
|
|
213
|
+
localDeviceId: dataContext.userContext?.deviceId(),
|
|
214
|
+
userContext: dataContext.userContext,
|
|
215
|
+
});
|
|
216
|
+
if (remoteEndpoint) {
|
|
217
|
+
return remoteEndpoint;
|
|
218
|
+
}
|
|
130
219
|
if (dataContext.packageLoader?.resolveContractEndpoint) {
|
|
131
220
|
return dataContext.packageLoader.resolveContractEndpoint(request, {
|
|
132
221
|
resolveVariable: resolveVariable
|
|
@@ -207,29 +296,30 @@ function createLocalUserContextContractProviderRouter(transport, opts) {
|
|
|
207
296
|
});
|
|
208
297
|
}
|
|
209
298
|
/**
|
|
210
|
-
* Create the local-object provider router for one verified device
|
|
299
|
+
* Create the local-object provider router for one verified remote device, whether it is
|
|
300
|
+
* reached over a direct {@link Connection} or through device messages.
|
|
211
301
|
*
|
|
212
|
-
* The router derives caller identity from the
|
|
213
|
-
* authorizes every call before invoking a
|
|
214
|
-
* contexts to the local user's personal
|
|
215
|
-
*
|
|
216
|
-
*
|
|
217
|
-
* retain their existing behavior after authorization.
|
|
302
|
+
* The router derives caller identity from the transport owner supplied by the host,
|
|
303
|
+
* authorizes every call with {@link authorizeRemoteContractCall} before invoking a
|
|
304
|
+
* registered resolver, normalizes omitted data contexts to the local user's personal
|
|
305
|
+
* context for Self callers, and caches stateful endpoints per contract/version/data-context
|
|
306
|
+
* route. Group members reach only tools marked with `remoteAccessLevel`.
|
|
218
307
|
*
|
|
219
|
-
* @param transport Contract transport backed by one verified
|
|
308
|
+
* @param transport Contract transport backed by one verified remote device.
|
|
220
309
|
* @param opts.userContext Local user context that owns provider data.
|
|
221
|
-
* @param opts.remoteIdentity Identity derived from the verified remote
|
|
310
|
+
* @param opts.remoteIdentity Identity derived from the verified remote device.
|
|
222
311
|
*/
|
|
223
312
|
function createUserContextContractProviderRouter(transport, opts) {
|
|
224
313
|
const { userContext, remoteIdentity } = opts;
|
|
225
314
|
const context = {
|
|
226
315
|
callerUserId: remoteIdentity.userId,
|
|
227
316
|
localUserId: userContext.userId,
|
|
317
|
+
callerDeviceId: remoteIdentity.deviceId,
|
|
228
318
|
dataContext: userContext.userDataContext,
|
|
229
319
|
};
|
|
230
320
|
return (0, contract_provider_router_1.createContractProviderRouter)(transport, {
|
|
231
321
|
context,
|
|
232
|
-
authorizeCall: (call) =>
|
|
322
|
+
authorizeCall: (call) => authorizeRemoteContractCall(call, userContext, remoteIdentity),
|
|
233
323
|
resolveProviderPackageId: ({ contractId, version, dataContextId }) => {
|
|
234
324
|
const dataContext = userContext.getDataContext(dataContextId || userContext.userId);
|
|
235
325
|
return getActiveProviderPackageId(dataContext, contractId, version);
|
|
@@ -241,9 +331,9 @@ function createUserContextContractProviderRouter(transport, opts) {
|
|
|
241
331
|
});
|
|
242
332
|
}
|
|
243
333
|
/**
|
|
244
|
-
* Provider-side request/response glue: apply
|
|
245
|
-
*
|
|
246
|
-
*
|
|
334
|
+
* Provider-side request/response glue: apply {@link authorizeRemoteContractCall}, resolve
|
|
335
|
+
* the contract for the authorized data context, build a stateless provider, and execute
|
|
336
|
+
* the call.
|
|
247
337
|
*
|
|
248
338
|
* Used by transports (e.g. the connection `CONTRACT_CALL_RPC` handler) to run an inbound
|
|
249
339
|
* {@link IContractCall} against local state.
|
|
@@ -254,7 +344,7 @@ function createUserContextContractProviderRouter(transport, opts) {
|
|
|
254
344
|
*/
|
|
255
345
|
async function handleContractCall(call, opts) {
|
|
256
346
|
const { userContext, remoteIdentity } = opts;
|
|
257
|
-
const authorization = await
|
|
347
|
+
const authorization = await authorizeRemoteContractCall(call, userContext, remoteIdentity);
|
|
258
348
|
const routedCall = {
|
|
259
349
|
...call,
|
|
260
350
|
dataContextId: authorization.dataContextId,
|
|
@@ -29,6 +29,8 @@ export interface IExtractableToolInstance {
|
|
|
29
29
|
outputSchema?: {
|
|
30
30
|
fields: IField[];
|
|
31
31
|
};
|
|
32
|
+
/** See {@link IContractTool.remoteAccessLevel}. */
|
|
33
|
+
remoteAccessLevel?: number;
|
|
32
34
|
};
|
|
33
35
|
}
|
|
34
36
|
/** Override the schemaToFields implementation (useful for tests). */
|
|
@@ -41,6 +43,7 @@ export declare function setSchemaToFieldsFn(fn: (schema: z.AnyZodObject) => IFie
|
|
|
41
43
|
export declare function extractTableShape(def: IExtractableTableDef): IContractTable;
|
|
42
44
|
/**
|
|
43
45
|
* Extract the contract-level tool shape from a tool instance.
|
|
44
|
-
* Uses the tool record's `inputSchema.fields` and `outputSchema.fields
|
|
46
|
+
* Uses the tool record's `inputSchema.fields` and `outputSchema.fields`, and carries
|
|
47
|
+
* the optional `remoteAccessLevel` policy through unchanged.
|
|
45
48
|
*/
|
|
46
49
|
export declare function extractToolShape(inst: IExtractableToolInstance): IContractTool;
|
|
@@ -38,7 +38,8 @@ function extractTableShape(def) {
|
|
|
38
38
|
}
|
|
39
39
|
/**
|
|
40
40
|
* Extract the contract-level tool shape from a tool instance.
|
|
41
|
-
* Uses the tool record's `inputSchema.fields` and `outputSchema.fields
|
|
41
|
+
* Uses the tool record's `inputSchema.fields` and `outputSchema.fields`, and carries
|
|
42
|
+
* the optional `remoteAccessLevel` policy through unchanged.
|
|
42
43
|
*/
|
|
43
44
|
function extractToolShape(inst) {
|
|
44
45
|
const { tool } = inst;
|
|
@@ -47,5 +48,6 @@ function extractToolShape(inst) {
|
|
|
47
48
|
usageDescription: tool.usageDescription,
|
|
48
49
|
inputFields: tool.inputSchema?.fields ?? [],
|
|
49
50
|
outputFields: tool.outputSchema?.fields ?? [],
|
|
51
|
+
...(tool.remoteAccessLevel !== undefined ? { remoteAccessLevel: tool.remoteAccessLevel } : {}),
|
|
50
52
|
};
|
|
51
53
|
}
|
|
@@ -1,8 +1,8 @@
|
|
|
1
1
|
export { ContractBuilder, definePackage, PackageBuilder } from "./builder";
|
|
2
2
|
export { type ContractCallAuthorizer, type ContractProviderEndpointResolver, type ContractProviderPackageResolver, createContractProviderRouter, type IAuthorizedContractRoute, type IContractProviderEndpointRequest, type IContractProviderRouter, type IContractProviderRouterOptions, } from "./contract-provider-router";
|
|
3
3
|
export { ContractProviders, ContractProvidersTable, contractProvidersMetaData, contractProvidersSchema, type IContractProviderRecord, } from "./contract-providers.table";
|
|
4
|
-
export { CONTRACT_CALL_RPC, type ContractMemberType, type ContractNotificationSink, type ContractPermissionCheck, createContractConsumer, createContractProvider, createContractProviderEndpoint, createContractProviderSession, type IContractCall, type IContractCallContext, type IContractConsumer, type IContractConsumerBase, type IContractNotification, type IContractProviderEndpoint, type IContractProviderEndpointOptions, type IContractProviderSession, type IContractProviderSessionOptions, type IContractResolution, type IContractTableProxy, type IContractToolContext, type ITableProxy, sameUserContractPermissionCheck, } from "./contract-proxy";
|
|
5
|
-
export { type ContractRemoteIdentity, type ContractResolver, createLocalUserContextContractProviderRouter, createUserContextContractProviderRouter, getContractResolver, handleContractCall, type IContractResolverRegistrationOptions, type ILocalContractVariableRequest, isSelfTrustedContractCaller, type LocalContractVariableResolver, registerContractResolver, } from "./contract-resolvers";
|
|
4
|
+
export { CONTRACT_CALL_RPC, type ContractMemberType, type ContractNotificationSink, type ContractPermissionCheck, createContractConsumer, createContractProvider, createContractProviderEndpoint, createContractProviderSession, createRemoteContractConsumer, type IContractCall, type IContractCallContext, type IContractConsumer, type IContractConsumerBase, type IContractNotification, type IContractProviderEndpoint, type IContractProviderEndpointOptions, type IContractProviderSession, type IContractProviderSessionOptions, type IContractResolution, type IContractTableProxy, type IContractToolContext, type ITableProxy, sameUserContractPermissionCheck, } from "./contract-proxy";
|
|
5
|
+
export { authorizeRemoteContractCall, type ContractRemoteIdentity, type ContractResolver, createLocalUserContextContractProviderRouter, createUserContextContractProviderRouter, getContractResolver, handleContractCall, type IContractResolverRegistrationOptions, type ILocalContractVariableRequest, isSelfTrustedContractCaller, type LocalContractVariableResolver, registerContractResolver, verifyRemoteContractIdentity, } from "./contract-resolvers";
|
|
6
6
|
export { CONTRACT_NOTIFY_CHANNEL, CONTRACT_REQUEST_CHANNEL, connectionContractTransport, type IContractTransport, type IDuplexEmitter, inProcessTransportPair, } from "./contract-transport";
|
|
7
7
|
export { Contracts, ContractsTable, contractsMetaData, contractsSchema, type IContractRecord, } from "./contracts.table";
|
|
8
8
|
export { createLocalContractConsumer } from "./create-local-consumer";
|
|
@@ -10,11 +10,12 @@ export { extractTableShape, extractToolShape, type IExtractableTableDef, type IE
|
|
|
10
10
|
export { getHostContractTransport, type HostContractTransportListener, registerHostContractTransport, subscribeHostContractTransport, waitForHostContractTransport, } from "./host-contract-transport";
|
|
11
11
|
export { PersistentContractRegistry } from "./persistent-registry";
|
|
12
12
|
export { ContractRegistry, type IContractProviderRegistration } from "./registry";
|
|
13
|
+
export { createRemoteContractEndpoint, getRemoteContractTransportFactory, type IRemoteContractHost, type IRemoteContractTarget, type RemoteContractTransportFactory, resolveRemoteTargetEndpoint, setRemoteContractTransportFactory, } from "./remote-contract-transport";
|
|
13
14
|
export { DEVICE_OPERATIONS_CONTRACT_VERSION, DEVICE_OPERATIONS_MAX_QUERY_LENGTH, DEVICE_OPERATIONS_MAX_RESULT_BYTES, DEVICE_OPERATIONS_MAX_ROWS, DEVICE_OPERATIONS_MAX_TOOLS, type DeviceOperationCapability, deviceOperationsProviderPackageId, deviceOperationsToolIds, getDeviceOperationsContractDefinition, type IDeviceDatabaseQueryInput, type IDeviceDatabaseQueryResult, type IDeviceOperationStatus, type IDeviceToolListInput, type IDeviceToolLookupInput, type IDeviceToolLookupResult, type IDeviceToolRunInput, } from "./system/device-operations-contract";
|
|
14
15
|
export { getLogsContractDefinition, type ILogsConsumer, LOGS_CONTRACT_VERSION, resolveLogsContract, } from "./system/logs-contract";
|
|
15
16
|
export * from "./system/network-contracts";
|
|
16
17
|
export { getToolAccessControlContractDefinition, type IToolAccessControlConsumer, TOOL_ACCESS_CONTROL_CONTRACT_VERSION, } from "./system/tool-access-control-contract";
|
|
17
18
|
export { type ISystemContractRegistration, installSystemContracts, listSystemContracts, registerSystemContract, } from "./system-contracts";
|
|
18
|
-
export type { IAlsoImplementsDeclaration, IConsumedContract, IConsumedContractHandle, IConsumedContractOptions, IContractDefinition, IContractEvent, IContractObservable, IContractTable, IContractTool, IPackageDefinitionResult, IResolvedContract, IValidationError, IValidationResult, } from "./types";
|
|
19
|
+
export type { IAlsoImplementsDeclaration, IConsumedContract, IConsumedContractHandle, IConsumedContractOptions, IContractDefinition, IContractEvent, IContractObservable, IContractTable, IContractTool, IPackageDefinitionResult, IRemoteContract, IRemoteContractConsumer, IRemoteContractHandle, IResolvedContract, IValidationError, IValidationResult, } from "./types";
|
|
19
20
|
export { contractKey } from "./types";
|
|
20
21
|
export { validateAlsoImplements, validateImmutability, validateProviderSatisfiesContract, } from "./validate";
|
package/dist/contracts/index.js
CHANGED
|
@@ -14,8 +14,8 @@ var __exportStar = (this && this.__exportStar) || function(m, exports) {
|
|
|
14
14
|
for (var p in m) if (p !== "default" && !Object.prototype.hasOwnProperty.call(exports, p)) __createBinding(exports, m, p);
|
|
15
15
|
};
|
|
16
16
|
Object.defineProperty(exports, "__esModule", { value: true });
|
|
17
|
-
exports.
|
|
18
|
-
exports.validateProviderSatisfiesContract = exports.validateImmutability = exports.validateAlsoImplements = exports.contractKey = exports.registerSystemContract = exports.listSystemContracts = exports.installSystemContracts = exports.TOOL_ACCESS_CONTROL_CONTRACT_VERSION = void 0;
|
|
17
|
+
exports.DEVICE_OPERATIONS_MAX_TOOLS = exports.DEVICE_OPERATIONS_MAX_ROWS = exports.DEVICE_OPERATIONS_MAX_RESULT_BYTES = exports.DEVICE_OPERATIONS_MAX_QUERY_LENGTH = exports.DEVICE_OPERATIONS_CONTRACT_VERSION = exports.setRemoteContractTransportFactory = exports.resolveRemoteTargetEndpoint = exports.getRemoteContractTransportFactory = exports.createRemoteContractEndpoint = exports.ContractRegistry = exports.PersistentContractRegistry = exports.waitForHostContractTransport = exports.subscribeHostContractTransport = exports.registerHostContractTransport = exports.getHostContractTransport = exports.setSchemaToFieldsFn = exports.extractToolShape = exports.extractTableShape = exports.createLocalContractConsumer = exports.contractsSchema = exports.contractsMetaData = exports.ContractsTable = exports.Contracts = exports.inProcessTransportPair = exports.connectionContractTransport = exports.CONTRACT_REQUEST_CHANNEL = exports.CONTRACT_NOTIFY_CHANNEL = exports.verifyRemoteContractIdentity = exports.registerContractResolver = exports.isSelfTrustedContractCaller = exports.handleContractCall = exports.getContractResolver = exports.createUserContextContractProviderRouter = exports.createLocalUserContextContractProviderRouter = exports.authorizeRemoteContractCall = exports.sameUserContractPermissionCheck = exports.createRemoteContractConsumer = exports.createContractProviderSession = exports.createContractProviderEndpoint = exports.createContractProvider = exports.createContractConsumer = exports.CONTRACT_CALL_RPC = exports.contractProvidersSchema = exports.contractProvidersMetaData = exports.ContractProvidersTable = exports.ContractProviders = exports.createContractProviderRouter = exports.PackageBuilder = exports.definePackage = exports.ContractBuilder = void 0;
|
|
18
|
+
exports.validateProviderSatisfiesContract = exports.validateImmutability = exports.validateAlsoImplements = exports.contractKey = exports.registerSystemContract = exports.listSystemContracts = exports.installSystemContracts = exports.TOOL_ACCESS_CONTROL_CONTRACT_VERSION = exports.getToolAccessControlContractDefinition = exports.resolveLogsContract = exports.LOGS_CONTRACT_VERSION = exports.getLogsContractDefinition = exports.getDeviceOperationsContractDefinition = exports.deviceOperationsToolIds = exports.deviceOperationsProviderPackageId = void 0;
|
|
19
19
|
var builder_1 = require("./builder");
|
|
20
20
|
Object.defineProperty(exports, "ContractBuilder", { enumerable: true, get: function () { return builder_1.ContractBuilder; } });
|
|
21
21
|
Object.defineProperty(exports, "definePackage", { enumerable: true, get: function () { return builder_1.definePackage; } });
|
|
@@ -33,14 +33,17 @@ Object.defineProperty(exports, "createContractConsumer", { enumerable: true, get
|
|
|
33
33
|
Object.defineProperty(exports, "createContractProvider", { enumerable: true, get: function () { return contract_proxy_1.createContractProvider; } });
|
|
34
34
|
Object.defineProperty(exports, "createContractProviderEndpoint", { enumerable: true, get: function () { return contract_proxy_1.createContractProviderEndpoint; } });
|
|
35
35
|
Object.defineProperty(exports, "createContractProviderSession", { enumerable: true, get: function () { return contract_proxy_1.createContractProviderSession; } });
|
|
36
|
+
Object.defineProperty(exports, "createRemoteContractConsumer", { enumerable: true, get: function () { return contract_proxy_1.createRemoteContractConsumer; } });
|
|
36
37
|
Object.defineProperty(exports, "sameUserContractPermissionCheck", { enumerable: true, get: function () { return contract_proxy_1.sameUserContractPermissionCheck; } });
|
|
37
38
|
var contract_resolvers_1 = require("./contract-resolvers");
|
|
39
|
+
Object.defineProperty(exports, "authorizeRemoteContractCall", { enumerable: true, get: function () { return contract_resolvers_1.authorizeRemoteContractCall; } });
|
|
38
40
|
Object.defineProperty(exports, "createLocalUserContextContractProviderRouter", { enumerable: true, get: function () { return contract_resolvers_1.createLocalUserContextContractProviderRouter; } });
|
|
39
41
|
Object.defineProperty(exports, "createUserContextContractProviderRouter", { enumerable: true, get: function () { return contract_resolvers_1.createUserContextContractProviderRouter; } });
|
|
40
42
|
Object.defineProperty(exports, "getContractResolver", { enumerable: true, get: function () { return contract_resolvers_1.getContractResolver; } });
|
|
41
43
|
Object.defineProperty(exports, "handleContractCall", { enumerable: true, get: function () { return contract_resolvers_1.handleContractCall; } });
|
|
42
44
|
Object.defineProperty(exports, "isSelfTrustedContractCaller", { enumerable: true, get: function () { return contract_resolvers_1.isSelfTrustedContractCaller; } });
|
|
43
45
|
Object.defineProperty(exports, "registerContractResolver", { enumerable: true, get: function () { return contract_resolvers_1.registerContractResolver; } });
|
|
46
|
+
Object.defineProperty(exports, "verifyRemoteContractIdentity", { enumerable: true, get: function () { return contract_resolvers_1.verifyRemoteContractIdentity; } });
|
|
44
47
|
var contract_transport_1 = require("./contract-transport");
|
|
45
48
|
Object.defineProperty(exports, "CONTRACT_NOTIFY_CHANNEL", { enumerable: true, get: function () { return contract_transport_1.CONTRACT_NOTIFY_CHANNEL; } });
|
|
46
49
|
Object.defineProperty(exports, "CONTRACT_REQUEST_CHANNEL", { enumerable: true, get: function () { return contract_transport_1.CONTRACT_REQUEST_CHANNEL; } });
|
|
@@ -66,6 +69,11 @@ var persistent_registry_1 = require("./persistent-registry");
|
|
|
66
69
|
Object.defineProperty(exports, "PersistentContractRegistry", { enumerable: true, get: function () { return persistent_registry_1.PersistentContractRegistry; } });
|
|
67
70
|
var registry_1 = require("./registry");
|
|
68
71
|
Object.defineProperty(exports, "ContractRegistry", { enumerable: true, get: function () { return registry_1.ContractRegistry; } });
|
|
72
|
+
var remote_contract_transport_1 = require("./remote-contract-transport");
|
|
73
|
+
Object.defineProperty(exports, "createRemoteContractEndpoint", { enumerable: true, get: function () { return remote_contract_transport_1.createRemoteContractEndpoint; } });
|
|
74
|
+
Object.defineProperty(exports, "getRemoteContractTransportFactory", { enumerable: true, get: function () { return remote_contract_transport_1.getRemoteContractTransportFactory; } });
|
|
75
|
+
Object.defineProperty(exports, "resolveRemoteTargetEndpoint", { enumerable: true, get: function () { return remote_contract_transport_1.resolveRemoteTargetEndpoint; } });
|
|
76
|
+
Object.defineProperty(exports, "setRemoteContractTransportFactory", { enumerable: true, get: function () { return remote_contract_transport_1.setRemoteContractTransportFactory; } });
|
|
69
77
|
var device_operations_contract_1 = require("./system/device-operations-contract");
|
|
70
78
|
Object.defineProperty(exports, "DEVICE_OPERATIONS_CONTRACT_VERSION", { enumerable: true, get: function () { return device_operations_contract_1.DEVICE_OPERATIONS_CONTRACT_VERSION; } });
|
|
71
79
|
Object.defineProperty(exports, "DEVICE_OPERATIONS_MAX_QUERY_LENGTH", { enumerable: true, get: function () { return device_operations_contract_1.DEVICE_OPERATIONS_MAX_QUERY_LENGTH; } });
|
|
@@ -0,0 +1,69 @@
|
|
|
1
|
+
import type { UserContext } from "../context/user-context";
|
|
2
|
+
import type { IContractProviderEndpointRequest } from "./contract-provider-router";
|
|
3
|
+
import type { IContractProviderEndpoint } from "./contract-proxy";
|
|
4
|
+
import { type IContractTransport } from "./contract-transport";
|
|
5
|
+
/** Destination of a device-targeted contract call. */
|
|
6
|
+
export interface IRemoteContractTarget {
|
|
7
|
+
/** Device that should execute the call. */
|
|
8
|
+
deviceId: string;
|
|
9
|
+
/**
|
|
10
|
+
* Data context the call is scoped to. Required so the transport can seal the message
|
|
11
|
+
* to the right group or personal keys and the remote device can authorize membership.
|
|
12
|
+
*/
|
|
13
|
+
dataContextId: string;
|
|
14
|
+
}
|
|
15
|
+
/**
|
|
16
|
+
* Host-registered factory that produces an outbound {@link IContractTransport} to one
|
|
17
|
+
* remote device. `peers-device` registers a `sendDeviceMessage`-backed implementation;
|
|
18
|
+
* the SDK stays transport-agnostic and only knows how to ask for one.
|
|
19
|
+
*/
|
|
20
|
+
export type RemoteContractTransportFactory = (target: IRemoteContractTarget) => IContractTransport;
|
|
21
|
+
/** Trusted host state used to decide whether and how to forward a route. */
|
|
22
|
+
export interface IRemoteContractHost {
|
|
23
|
+
/** This device's id (`userContext.deviceId()`); a matching target resolves locally. */
|
|
24
|
+
localDeviceId?: string;
|
|
25
|
+
/** Owning user context, used to pick a per-context transport factory. */
|
|
26
|
+
userContext?: UserContext;
|
|
27
|
+
}
|
|
28
|
+
/**
|
|
29
|
+
* Register (or clear, with `undefined`) the factory used to reach other devices for
|
|
30
|
+
* contract tool calls. A connection manager registers one for its own `UserContext`;
|
|
31
|
+
* omitting `opts.userContext` sets the process-wide fallback. Call before any package
|
|
32
|
+
* invokes a `pkg.remote(...)` device consumer.
|
|
33
|
+
*
|
|
34
|
+
* @param factory Factory returning an outbound transport, or `undefined` to unregister.
|
|
35
|
+
* @param opts.userContext Scope the registration to one user context.
|
|
36
|
+
*/
|
|
37
|
+
export declare function setRemoteContractTransportFactory(factory: RemoteContractTransportFactory | undefined, opts?: {
|
|
38
|
+
userContext?: UserContext;
|
|
39
|
+
}): void;
|
|
40
|
+
/**
|
|
41
|
+
* Return the transport factory for a user context, falling back to the process default.
|
|
42
|
+
*
|
|
43
|
+
* @param userContext Optional owning user context.
|
|
44
|
+
*/
|
|
45
|
+
export declare function getRemoteContractTransportFactory(userContext?: UserContext): RemoteContractTransportFactory | undefined;
|
|
46
|
+
/**
|
|
47
|
+
* Shared chokepoint for trusted local hosts: when an authorized route names a device
|
|
48
|
+
* other than this one, return a forwarding endpoint; otherwise return `undefined` so the
|
|
49
|
+
* caller resolves the provider locally. A target equal to the local device is treated as
|
|
50
|
+
* local so `remote.device(myOwnDeviceId)` behaves like a plain consumer.
|
|
51
|
+
*
|
|
52
|
+
* @param request Authorized route from a router serving a *local* principal.
|
|
53
|
+
* @param host This device's id and owning user context.
|
|
54
|
+
*/
|
|
55
|
+
export declare function resolveRemoteTargetEndpoint(request: IContractProviderEndpointRequest, host: IRemoteContractHost): IContractProviderEndpoint | undefined;
|
|
56
|
+
/**
|
|
57
|
+
* Build a provider endpoint that forwards authorized calls to another device.
|
|
58
|
+
*
|
|
59
|
+
* The endpoint is created only by a trusted local host after it has authorized the
|
|
60
|
+
* *local* caller for the route. It strips {@link IContractCall.targetDeviceId} before
|
|
61
|
+
* emitting so the receiving device sees an ordinary call addressed to itself and the
|
|
62
|
+
* message is signed with this device's own identity. Only tool runs are forwarded; the
|
|
63
|
+
* router rejects other members before reaching this endpoint.
|
|
64
|
+
*
|
|
65
|
+
* @param request Authorized route whose `targetDeviceId` and `dataContextId` are set.
|
|
66
|
+
* @param factory Transport factory; defaults to the process-wide registration.
|
|
67
|
+
* @throws If no factory is available or the route lacks a target device or data context.
|
|
68
|
+
*/
|
|
69
|
+
export declare function createRemoteContractEndpoint(request: IContractProviderEndpointRequest, factory?: RemoteContractTransportFactory | undefined): IContractProviderEndpoint;
|
|
@@ -0,0 +1,95 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
+
exports.setRemoteContractTransportFactory = setRemoteContractTransportFactory;
|
|
4
|
+
exports.getRemoteContractTransportFactory = getRemoteContractTransportFactory;
|
|
5
|
+
exports.resolveRemoteTargetEndpoint = resolveRemoteTargetEndpoint;
|
|
6
|
+
exports.createRemoteContractEndpoint = createRemoteContractEndpoint;
|
|
7
|
+
const contract_transport_1 = require("./contract-transport");
|
|
8
|
+
const factoriesByUserContext = new WeakMap();
|
|
9
|
+
let defaultFactory;
|
|
10
|
+
/**
|
|
11
|
+
* Register (or clear, with `undefined`) the factory used to reach other devices for
|
|
12
|
+
* contract tool calls. A connection manager registers one for its own `UserContext`;
|
|
13
|
+
* omitting `opts.userContext` sets the process-wide fallback. Call before any package
|
|
14
|
+
* invokes a `pkg.remote(...)` device consumer.
|
|
15
|
+
*
|
|
16
|
+
* @param factory Factory returning an outbound transport, or `undefined` to unregister.
|
|
17
|
+
* @param opts.userContext Scope the registration to one user context.
|
|
18
|
+
*/
|
|
19
|
+
function setRemoteContractTransportFactory(factory, opts = {}) {
|
|
20
|
+
if (opts.userContext) {
|
|
21
|
+
if (factory) {
|
|
22
|
+
factoriesByUserContext.set(opts.userContext, factory);
|
|
23
|
+
}
|
|
24
|
+
else {
|
|
25
|
+
factoriesByUserContext.delete(opts.userContext);
|
|
26
|
+
}
|
|
27
|
+
return;
|
|
28
|
+
}
|
|
29
|
+
defaultFactory = factory;
|
|
30
|
+
}
|
|
31
|
+
/**
|
|
32
|
+
* Return the transport factory for a user context, falling back to the process default.
|
|
33
|
+
*
|
|
34
|
+
* @param userContext Optional owning user context.
|
|
35
|
+
*/
|
|
36
|
+
function getRemoteContractTransportFactory(userContext) {
|
|
37
|
+
return (userContext && factoriesByUserContext.get(userContext)) ?? defaultFactory;
|
|
38
|
+
}
|
|
39
|
+
/**
|
|
40
|
+
* Shared chokepoint for trusted local hosts: when an authorized route names a device
|
|
41
|
+
* other than this one, return a forwarding endpoint; otherwise return `undefined` so the
|
|
42
|
+
* caller resolves the provider locally. A target equal to the local device is treated as
|
|
43
|
+
* local so `remote.device(myOwnDeviceId)` behaves like a plain consumer.
|
|
44
|
+
*
|
|
45
|
+
* @param request Authorized route from a router serving a *local* principal.
|
|
46
|
+
* @param host This device's id and owning user context.
|
|
47
|
+
*/
|
|
48
|
+
function resolveRemoteTargetEndpoint(request, host) {
|
|
49
|
+
if (!request.targetDeviceId || request.targetDeviceId === host.localDeviceId) {
|
|
50
|
+
return undefined;
|
|
51
|
+
}
|
|
52
|
+
return createRemoteContractEndpoint(request, getRemoteContractTransportFactory(host.userContext));
|
|
53
|
+
}
|
|
54
|
+
/**
|
|
55
|
+
* Build a provider endpoint that forwards authorized calls to another device.
|
|
56
|
+
*
|
|
57
|
+
* The endpoint is created only by a trusted local host after it has authorized the
|
|
58
|
+
* *local* caller for the route. It strips {@link IContractCall.targetDeviceId} before
|
|
59
|
+
* emitting so the receiving device sees an ordinary call addressed to itself and the
|
|
60
|
+
* message is signed with this device's own identity. Only tool runs are forwarded; the
|
|
61
|
+
* router rejects other members before reaching this endpoint.
|
|
62
|
+
*
|
|
63
|
+
* @param request Authorized route whose `targetDeviceId` and `dataContextId` are set.
|
|
64
|
+
* @param factory Transport factory; defaults to the process-wide registration.
|
|
65
|
+
* @throws If no factory is available or the route lacks a target device or data context.
|
|
66
|
+
*/
|
|
67
|
+
function createRemoteContractEndpoint(request, factory = getRemoteContractTransportFactory()) {
|
|
68
|
+
const { targetDeviceId, dataContextId } = request;
|
|
69
|
+
if (!targetDeviceId) {
|
|
70
|
+
throw new Error("Remote contract endpoint requires a target device id");
|
|
71
|
+
}
|
|
72
|
+
if (!dataContextId) {
|
|
73
|
+
throw new Error("Remote contract endpoint requires an authorized data context id");
|
|
74
|
+
}
|
|
75
|
+
if (!factory) {
|
|
76
|
+
throw new Error(`Cannot reach device ${targetDeviceId}: no remote contract transport is registered on this host`);
|
|
77
|
+
}
|
|
78
|
+
const transport = factory({ deviceId: targetDeviceId, dataContextId });
|
|
79
|
+
let disposed = false;
|
|
80
|
+
return {
|
|
81
|
+
handleCall(call) {
|
|
82
|
+
if (disposed) {
|
|
83
|
+
return Promise.reject(new Error(`Remote contract endpoint for ${targetDeviceId} is disposed`));
|
|
84
|
+
}
|
|
85
|
+
if (call.member !== "tool" || call.operation !== "run") {
|
|
86
|
+
return Promise.reject(new Error(`Contract ${call.member} '${call.name}'.${call.operation} cannot be forwarded to a remote device`));
|
|
87
|
+
}
|
|
88
|
+
const { targetDeviceId: _stripped, ...outbound } = call;
|
|
89
|
+
return transport.emit(contract_transport_1.CONTRACT_REQUEST_CHANNEL, { ...outbound, dataContextId });
|
|
90
|
+
},
|
|
91
|
+
dispose() {
|
|
92
|
+
disposed = true;
|
|
93
|
+
},
|
|
94
|
+
};
|
|
95
|
+
}
|
|
@@ -39,6 +39,13 @@ export interface IContractTool {
|
|
|
39
39
|
usageDescription: string;
|
|
40
40
|
inputFields: IField[];
|
|
41
41
|
outputFields: IField[];
|
|
42
|
+
/**
|
|
43
|
+
* Minimum group access level (0–100) a caller on **another device** needs to run
|
|
44
|
+
* this tool. Absent means the tool is local-only: consumers on the same device can
|
|
45
|
+
* call it, but remote devices are denied. Self-trusted callers (the provider's own
|
|
46
|
+
* account) are never gated by this value. Policy only — not part of shape validation.
|
|
47
|
+
*/
|
|
48
|
+
remoteAccessLevel?: number;
|
|
42
49
|
}
|
|
43
50
|
/** Observable value exposed by a contract. */
|
|
44
51
|
export interface IContractObservable {
|
|
@@ -111,6 +118,51 @@ export interface IConsumedContract {
|
|
|
111
118
|
/** Deferred handle returned by `consumes()` for this dependency. */
|
|
112
119
|
handle?: IConsumedContractHandle<IContractConsumerBase | undefined>;
|
|
113
120
|
}
|
|
121
|
+
/**
|
|
122
|
+
* Resolved value of a {@link PackageBuilder.remote} handle: a factory of tools-only
|
|
123
|
+
* consumers whose calls execute on other devices.
|
|
124
|
+
*
|
|
125
|
+
* Unlike a consumed contract, no local provider is required — the executing device
|
|
126
|
+
* selects its own provider and authorizes the call against the caller's group role and
|
|
127
|
+
* the tool's {@link IContractTool.remoteAccessLevel}. Only `tools` are reachable on the
|
|
128
|
+
* returned consumers today; `tables`, `observables`, and `events` throw on access.
|
|
129
|
+
*
|
|
130
|
+
* @typeParam T - Consumer proxy type (defaults to {@link IContractConsumer}).
|
|
131
|
+
*/
|
|
132
|
+
export interface IRemoteContractConsumer<T extends IContractConsumerBase = IContractConsumer> {
|
|
133
|
+
contractId: string;
|
|
134
|
+
version: number;
|
|
135
|
+
/**
|
|
136
|
+
* Consumer whose tool calls run on `deviceId`. Instances are cached per device; passing
|
|
137
|
+
* this device's own id behaves like a plain local consumer.
|
|
138
|
+
*
|
|
139
|
+
* @param deviceId Device that should run the calls.
|
|
140
|
+
*/
|
|
141
|
+
device(deviceId: string): T;
|
|
142
|
+
/** Idempotently dispose every per-device consumer created by this factory. */
|
|
143
|
+
dispose(): void;
|
|
144
|
+
}
|
|
145
|
+
/**
|
|
146
|
+
* Deferred handle returned by {@link PackageBuilder.remote}.
|
|
147
|
+
*
|
|
148
|
+
* Like {@link IConsumedContractHandle}, the handle is not thenable — await
|
|
149
|
+
* {@link consumer} from runtime code after `definePackage` finishes. The
|
|
150
|
+
* package-loader settles it once the contract definition is known locally.
|
|
151
|
+
*/
|
|
152
|
+
export interface IRemoteContractHandle<T extends IContractConsumerBase = IContractConsumer> {
|
|
153
|
+
/** Resolves to the per-device consumer factory. */
|
|
154
|
+
readonly consumer: Promise<IRemoteContractConsumer<T>>;
|
|
155
|
+
}
|
|
156
|
+
/**
|
|
157
|
+
* A contract a package calls on other devices. Recorded during `definePackage`;
|
|
158
|
+
* the loader settles the handle without requiring a local provider.
|
|
159
|
+
*/
|
|
160
|
+
export interface IRemoteContract {
|
|
161
|
+
contractId: string;
|
|
162
|
+
version: number;
|
|
163
|
+
/** Deferred handle returned by `remote()` for this declaration. */
|
|
164
|
+
handle?: IRemoteContractHandle<IContractConsumerBase>;
|
|
165
|
+
}
|
|
114
166
|
/**
|
|
115
167
|
* Declares that the owning contract's implementation also satisfies another
|
|
116
168
|
* contract (single version or inclusive range).
|
|
@@ -132,6 +184,11 @@ export interface IPackageDefinitionResult {
|
|
|
132
184
|
contracts: IContractDefinition[];
|
|
133
185
|
/** Contracts this package depends on. */
|
|
134
186
|
consumes: IConsumedContract[];
|
|
187
|
+
/**
|
|
188
|
+
* Contracts this package calls on other devices via `pkg.remote()`. Optional so
|
|
189
|
+
* bundles built with an older SDK still load.
|
|
190
|
+
*/
|
|
191
|
+
remotes?: IRemoteContract[];
|
|
135
192
|
/** `alsoImplements` declarations keyed by the owning contractId+version. */
|
|
136
193
|
alsoImplements: Map<string, IAlsoImplementsDeclaration[]>;
|
|
137
194
|
/** Package-level items not part of any contract. */
|
|
@@ -123,12 +123,20 @@ export declare function groupVar<T = string>(name: string, opts?: Omit<IPersiste
|
|
|
123
123
|
/**
|
|
124
124
|
* A persistent variable that is stored only on this device, in the user's personal db.
|
|
125
125
|
* It can have a different value for each group on the device but is not synced to other devices.
|
|
126
|
+
*
|
|
127
|
+
* The record always lives in the personal db. `opts.dataContext` (or, when omitted, the
|
|
128
|
+
* current default group) only selects which group's value is addressed by suffixing the
|
|
129
|
+
* stored name with that data context id, so server-side callers that pin a group and
|
|
130
|
+
* renderer callers that follow the default group share one row.
|
|
126
131
|
*/
|
|
127
132
|
export declare function groupDeviceVar<T = string>(name: string, opts: Omit<IPersistentVarOptionsWithDefault<T>, "scope">): PersistentVar<T>;
|
|
128
133
|
export declare function groupDeviceVar<T = string>(name: string, opts?: Omit<IPersistentVarOptionsWithoutDefault<T>, "scope">): PersistentVar<T | undefined>;
|
|
129
134
|
/**
|
|
130
135
|
* A persistent variable that is stored in the user's personal db and synced across all their devices in the group.
|
|
131
136
|
* It can have a different value for each user in the group and a different value for each group the user is in.
|
|
137
|
+
*
|
|
138
|
+
* As with {@link groupDeviceVar}, the record always lives in the personal db; `opts.dataContext`
|
|
139
|
+
* only selects the group whose value is addressed.
|
|
132
140
|
*/
|
|
133
141
|
export declare function groupUserVar<T = string>(name: string, opts: Omit<IPersistentVarOptionsWithDefault<T>, "scope">): PersistentVar<T>;
|
|
134
142
|
export declare function groupUserVar<T = string>(name: string, opts?: Omit<IPersistentVarOptionsWithoutDefault<T>, "scope">): PersistentVar<T | undefined>;
|