@peers-app/peers-sdk 0.23.4 → 0.23.5
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/data-context.d.ts +36 -5
- package/dist/context/data-context.js +44 -9
- package/dist/context/user-context.d.ts +44 -0
- package/dist/context/user-context.js +91 -12
- package/dist/contracts/__tests__/contract-provider-router.test.js +26 -0
- package/dist/contracts/__tests__/contract-resolvers.test.js +44 -0
- package/dist/contracts/__tests__/registry.test.js +104 -0
- package/dist/contracts/contract-provider-router.d.ts +21 -0
- package/dist/contracts/contract-provider-router.js +31 -5
- package/dist/contracts/contract-proxy.d.ts +3 -0
- package/dist/contracts/contract-proxy.js +3 -0
- package/dist/contracts/contract-resolvers.d.ts +21 -3
- package/dist/contracts/contract-resolvers.js +105 -32
- package/dist/contracts/index.d.ts +3 -3
- package/dist/contracts/registry.d.ts +59 -0
- package/dist/contracts/registry.js +155 -25
- package/dist/contracts/system-contracts.js +3 -1
- package/dist/data/index.d.ts +1 -0
- package/dist/data/index.js +1 -0
- package/dist/data/orm/types.d.ts +19 -0
- package/dist/data/orm/types.js +11 -0
- package/dist/data/package-table-identity.d.ts +46 -0
- package/dist/data/package-table-identity.js +71 -0
- package/dist/data/package-table-identity.test.d.ts +1 -0
- package/dist/data/package-table-identity.test.js +46 -0
- package/dist/data/package-version-resolver.d.ts +13 -0
- package/dist/data/package-version-resolver.js +142 -6
- package/dist/data/package-version-resolver.test.js +42 -0
- package/dist/data/persistent-var-identity.d.ts +37 -0
- package/dist/data/persistent-var-identity.js +69 -0
- package/dist/data/persistent-vars.d.ts +3 -5
- package/dist/data/persistent-vars.js +25 -13
- package/dist/data/persistent-vars.package-scope.test.d.ts +1 -0
- package/dist/data/persistent-vars.package-scope.test.js +27 -0
- package/dist/data/tools.d.ts +3 -3
- package/dist/package-loader/contract-package-loader.js +20 -8
- package/dist/package-loader/contract-package-loader.test.js +16 -0
- package/dist/package-loader/index.d.ts +4 -0
- package/dist/package-loader/index.js +4 -0
- package/dist/package-loader/isolated-artifact.d.ts +233 -0
- package/dist/package-loader/isolated-artifact.js +643 -0
- package/dist/package-loader/isolated-artifact.test.d.ts +1 -0
- package/dist/package-loader/isolated-artifact.test.js +270 -0
- package/dist/package-loader/isolated-persistent-var-gateway.d.ts +20 -0
- package/dist/package-loader/isolated-persistent-var-gateway.js +106 -0
- package/dist/package-loader/isolated-persistent-var-gateway.test.d.ts +1 -0
- package/dist/package-loader/isolated-persistent-var-gateway.test.js +56 -0
- package/dist/package-loader/isolated-runtime.d.ts +229 -0
- package/dist/package-loader/isolated-runtime.js +37 -0
- package/dist/package-loader/isolated-table-gateway.d.ts +16 -0
- package/dist/package-loader/isolated-table-gateway.js +375 -0
- package/dist/package-loader/isolated-table-gateway.test.d.ts +1 -0
- package/dist/package-loader/isolated-table-gateway.test.js +206 -0
- package/dist/package-loader/isolated-value.d.ts +14 -0
- package/dist/package-loader/isolated-value.js +63 -0
- package/dist/package-loader/package-loader.d.ts +123 -4
- package/dist/package-loader/package-loader.js +417 -46
- package/dist/package-loader/package-loader.test.js +478 -12
- package/dist/package-loader/resolve-consumed-contracts.d.ts +3 -3
- package/dist/package-loader/resolve-consumed-contracts.js +18 -10
- package/dist/utils.d.ts +21 -2
- package/dist/utils.js +46 -7
- package/package.json +1 -1
|
@@ -26,6 +26,11 @@ export interface IContractProviderEndpointRequest {
|
|
|
26
26
|
contractId: string;
|
|
27
27
|
/** Target contract version. */
|
|
28
28
|
version: number;
|
|
29
|
+
/**
|
|
30
|
+
* Provider selected by trusted host state. This value is never copied from
|
|
31
|
+
* an {@link IContractCall} or other guest payload.
|
|
32
|
+
*/
|
|
33
|
+
providerPackageId?: string;
|
|
29
34
|
/** Canonical data context returned by the authorization hook. */
|
|
30
35
|
dataContextId?: string;
|
|
31
36
|
/** Authorized caller context for this route. */
|
|
@@ -40,10 +45,20 @@ export interface IContractProviderEndpointRequest {
|
|
|
40
45
|
* endpoint. The router caches the result until disposal.
|
|
41
46
|
*/
|
|
42
47
|
export type ContractProviderEndpointResolver = (request: IContractProviderEndpointRequest) => IContractProviderEndpoint | Promise<IContractProviderEndpoint>;
|
|
48
|
+
/**
|
|
49
|
+
* Resolves the provider package selected by trusted host state for one
|
|
50
|
+
* authorized route. The result participates in endpoint cache identity.
|
|
51
|
+
*/
|
|
52
|
+
export type ContractProviderPackageResolver = (request: IContractProviderEndpointRequest) => string | undefined | Promise<string | undefined>;
|
|
43
53
|
/** Options for {@link createContractProviderRouter}. */
|
|
44
54
|
export interface IContractProviderRouterOptions {
|
|
45
55
|
/** Trusted host gate invoked before endpoint lookup or provider resolution. */
|
|
46
56
|
authorizeCall: ContractCallAuthorizer;
|
|
57
|
+
/**
|
|
58
|
+
* Optional active-provider lookup. Supplying it makes endpoint caches
|
|
59
|
+
* provider-aware and automatically selects a new endpoint after a provider switch.
|
|
60
|
+
*/
|
|
61
|
+
resolveProviderPackageId?: ContractProviderPackageResolver;
|
|
47
62
|
/** Resolves an endpoint after authorization succeeds. */
|
|
48
63
|
resolveEndpoint: ContractProviderEndpointResolver;
|
|
49
64
|
/** Caller identity derived from the trusted underlying connection/session. */
|
|
@@ -51,6 +66,12 @@ export interface IContractProviderRouterOptions {
|
|
|
51
66
|
}
|
|
52
67
|
/** A connection-wide owner of contract request routing and endpoint lifecycle. */
|
|
53
68
|
export interface IContractProviderRouter {
|
|
69
|
+
/**
|
|
70
|
+
* Dispose cached endpoints owned by a provider, for example after package
|
|
71
|
+
* replacement or uninstall. Existing subscription routes for those endpoints
|
|
72
|
+
* are dropped.
|
|
73
|
+
*/
|
|
74
|
+
invalidateProvider(providerPackageId: string): void;
|
|
54
75
|
/** Remove the request handler and dispose every resolved provider endpoint. */
|
|
55
76
|
dispose(): void;
|
|
56
77
|
}
|
|
@@ -2,7 +2,7 @@
|
|
|
2
2
|
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
3
|
exports.createContractProviderRouter = createContractProviderRouter;
|
|
4
4
|
const contract_transport_1 = require("./contract-transport");
|
|
5
|
-
const routeKey = (contractId, version, dataContextId) => JSON.stringify([contractId, version, dataContextId ?? null]);
|
|
5
|
+
const routeKey = (contractId, version, providerPackageId, dataContextId) => JSON.stringify([contractId, version, providerPackageId ?? null, dataContextId ?? null]);
|
|
6
6
|
/**
|
|
7
7
|
* Own the sole {@link CONTRACT_REQUEST_CHANNEL} handler for a shared connection.
|
|
8
8
|
*
|
|
@@ -35,7 +35,7 @@ function createContractProviderRouter(transport, opts) {
|
|
|
35
35
|
if (cached) {
|
|
36
36
|
return cached.promise;
|
|
37
37
|
}
|
|
38
|
-
const entry = {};
|
|
38
|
+
const entry = { providerPackageId: request.providerPackageId };
|
|
39
39
|
entry.promise = Promise.resolve()
|
|
40
40
|
.then(() => opts.resolveEndpoint(request))
|
|
41
41
|
.then((endpoint) => {
|
|
@@ -102,14 +102,19 @@ function createContractProviderRouter(transport, opts) {
|
|
|
102
102
|
...call,
|
|
103
103
|
dataContextId: authorization.dataContextId,
|
|
104
104
|
};
|
|
105
|
-
const
|
|
106
|
-
const endpoint = await getEndpoint(endpointKey, {
|
|
105
|
+
const endpointRequest = {
|
|
107
106
|
contractId: call.contractId,
|
|
108
107
|
version: call.version,
|
|
109
108
|
dataContextId: authorization.dataContextId,
|
|
110
109
|
context,
|
|
111
110
|
notify,
|
|
112
|
-
}
|
|
111
|
+
};
|
|
112
|
+
const providerPackageId = opts.resolveProviderPackageId
|
|
113
|
+
? await opts.resolveProviderPackageId(endpointRequest)
|
|
114
|
+
: undefined;
|
|
115
|
+
endpointRequest.providerPackageId = providerPackageId;
|
|
116
|
+
const endpointKey = routeKey(call.contractId, call.version, providerPackageId, authorization.dataContextId);
|
|
117
|
+
const endpoint = await getEndpoint(endpointKey, endpointRequest);
|
|
113
118
|
const result = await endpoint.handleCall(routedCall, context);
|
|
114
119
|
if (isSubscribe && subscriptionId) {
|
|
115
120
|
const subscriptionRoute = {
|
|
@@ -141,6 +146,27 @@ function createContractProviderRouter(transport, opts) {
|
|
|
141
146
|
};
|
|
142
147
|
const offRequest = transport.on(contract_transport_1.CONTRACT_REQUEST_CHANNEL, handleAuthorizedCall);
|
|
143
148
|
return {
|
|
149
|
+
invalidateProvider(providerPackageId) {
|
|
150
|
+
const invalidatedKeys = new Set();
|
|
151
|
+
for (const [key, entry] of endpointEntries) {
|
|
152
|
+
if (entry.providerPackageId !== providerPackageId) {
|
|
153
|
+
continue;
|
|
154
|
+
}
|
|
155
|
+
invalidatedKeys.add(key);
|
|
156
|
+
endpointEntries.delete(key);
|
|
157
|
+
if (entry.endpoint) {
|
|
158
|
+
entry.endpoint.dispose();
|
|
159
|
+
}
|
|
160
|
+
else {
|
|
161
|
+
void entry.promise.then((endpoint) => endpoint.dispose()).catch(() => { });
|
|
162
|
+
}
|
|
163
|
+
}
|
|
164
|
+
for (const [subscriptionId, route] of subscriptionRoutes) {
|
|
165
|
+
if (invalidatedKeys.has(route.endpointKey)) {
|
|
166
|
+
subscriptionRoutes.delete(subscriptionId);
|
|
167
|
+
}
|
|
168
|
+
}
|
|
169
|
+
},
|
|
144
170
|
dispose() {
|
|
145
171
|
if (disposed) {
|
|
146
172
|
return;
|
|
@@ -221,6 +221,9 @@ export interface IContractToolContext {
|
|
|
221
221
|
* Every access is turned into an {@link IContractCall} sent on the transport's fixed
|
|
222
222
|
* {@link CONTRACT_REQUEST_CHANNEL}; the resolved ack is the provider's return value.
|
|
223
223
|
*
|
|
224
|
+
* Provider-only tables are omitted from {@link IContractConsumer.tables}; consumers must
|
|
225
|
+
* call a declared provider method instead of raw CRUD.
|
|
226
|
+
*
|
|
224
227
|
* The consumer also subscribes to provider pushes: `events[name].subscribe(handler)` and
|
|
225
228
|
* `tables[name].dataChanged.subscribe(handler)` both send a `"subscribe"` request and
|
|
226
229
|
* demultiplex provider pushes arriving on {@link CONTRACT_NOTIFY_CHANNEL} by their
|
|
@@ -51,6 +51,9 @@ exports.CONTRACT_CALL_RPC = contract_transport_1.CONTRACT_REQUEST_CHANNEL;
|
|
|
51
51
|
* Every access is turned into an {@link IContractCall} sent on the transport's fixed
|
|
52
52
|
* {@link CONTRACT_REQUEST_CHANNEL}; the resolved ack is the provider's return value.
|
|
53
53
|
*
|
|
54
|
+
* Provider-only tables are omitted from {@link IContractConsumer.tables}; consumers must
|
|
55
|
+
* call a declared provider method instead of raw CRUD.
|
|
56
|
+
*
|
|
54
57
|
* The consumer also subscribes to provider pushes: `events[name].subscribe(handler)` and
|
|
55
58
|
* `tables[name].dataChanged.subscribe(handler)` both send a `"subscribe"` request and
|
|
56
59
|
* demultiplex provider pushes arriving on {@link CONTRACT_NOTIFY_CHANNEL} by their
|
|
@@ -14,12 +14,23 @@ export type ContractResolver = (ctx: {
|
|
|
14
14
|
}) => IContractResolution | Promise<IContractResolution>;
|
|
15
15
|
/** Input supplied to a trusted local host when a package tool resolves a pvar. */
|
|
16
16
|
export interface ILocalContractVariableRequest {
|
|
17
|
+
/** Data context that owns the persistent variable. */
|
|
17
18
|
dataContext: DataContext;
|
|
19
|
+
/** Persistent-variable name requested by the tool. */
|
|
18
20
|
variableName: string;
|
|
21
|
+
/** Tool id making the request (for host policy / logging). */
|
|
19
22
|
requestingToolId: string;
|
|
20
23
|
}
|
|
21
24
|
/** Host callback that resolves plaintext only inside a local provider process. */
|
|
22
25
|
export type LocalContractVariableResolver = (request: ILocalContractVariableRequest) => Promise<string>;
|
|
26
|
+
/** Options for a provider-scoped {@link registerContractResolver} registration. */
|
|
27
|
+
export interface IContractResolverRegistrationOptions {
|
|
28
|
+
/**
|
|
29
|
+
* Provider package that owns this resolver. Omit for the legacy unscoped
|
|
30
|
+
* resolver used as a compatibility fallback.
|
|
31
|
+
*/
|
|
32
|
+
providerPackageId?: string;
|
|
33
|
+
}
|
|
23
34
|
/** Connection-authenticated identity fields used to authorize remote contract calls. */
|
|
24
35
|
export type ContractRemoteIdentity = Pick<IDeviceInfo, "deviceId" | "userId" | "publicKey" | "publicBoxKey">;
|
|
25
36
|
/**
|
|
@@ -27,9 +38,16 @@ export type ContractRemoteIdentity = Pick<IDeviceInfo, "deviceId" | "userId" | "
|
|
|
27
38
|
* Later registrations for the same contract+version replace earlier ones (matching the
|
|
28
39
|
* registry's "latest provider wins for dev contracts" behavior).
|
|
29
40
|
*/
|
|
30
|
-
export declare function registerContractResolver(contractId: string, version: number, resolver: ContractResolver): void;
|
|
31
|
-
/**
|
|
32
|
-
|
|
41
|
+
export declare function registerContractResolver(contractId: string, version: number, resolver: ContractResolver, opts?: IContractResolverRegistrationOptions): void;
|
|
42
|
+
/**
|
|
43
|
+
* Look up a resolver for a contract version.
|
|
44
|
+
*
|
|
45
|
+
* When `providerPackageId` is supplied, an exact provider-scoped resolver wins
|
|
46
|
+
* and the legacy unscoped registration remains the compatibility fallback.
|
|
47
|
+
* An unscoped lookup may use a sole scoped resolver for callers that have not
|
|
48
|
+
* yet adopted provider selection; multiple scoped providers remain ambiguous.
|
|
49
|
+
*/
|
|
50
|
+
export declare function getContractResolver(contractId: string, version: number, providerPackageId?: string): ContractResolver | undefined;
|
|
33
51
|
/**
|
|
34
52
|
* Check whether a connection-authenticated remote identity has full contract authority.
|
|
35
53
|
*
|
|
@@ -15,17 +15,49 @@ const contract_provider_router_1 = require("./contract-provider-router");
|
|
|
15
15
|
const contract_proxy_1 = require("./contract-proxy");
|
|
16
16
|
const types_1 = require("./types");
|
|
17
17
|
const resolvers = new Map();
|
|
18
|
+
const resolverKey = (contractId, version, providerPackageId) => providerPackageId
|
|
19
|
+
? `${(0, types_1.contractKey)(contractId, version)}#provider:${providerPackageId}`
|
|
20
|
+
: (0, types_1.contractKey)(contractId, version);
|
|
18
21
|
/**
|
|
19
22
|
* Register the resolver that provides the live implementation for a contract version.
|
|
20
23
|
* Later registrations for the same contract+version replace earlier ones (matching the
|
|
21
24
|
* registry's "latest provider wins for dev contracts" behavior).
|
|
22
25
|
*/
|
|
23
|
-
function registerContractResolver(contractId, version, resolver) {
|
|
24
|
-
resolvers.set((
|
|
26
|
+
function registerContractResolver(contractId, version, resolver, opts = {}) {
|
|
27
|
+
resolvers.set(resolverKey(contractId, version, opts.providerPackageId), resolver);
|
|
25
28
|
}
|
|
26
|
-
/**
|
|
27
|
-
|
|
28
|
-
|
|
29
|
+
/**
|
|
30
|
+
* Look up a resolver for a contract version.
|
|
31
|
+
*
|
|
32
|
+
* When `providerPackageId` is supplied, an exact provider-scoped resolver wins
|
|
33
|
+
* and the legacy unscoped registration remains the compatibility fallback.
|
|
34
|
+
* An unscoped lookup may use a sole scoped resolver for callers that have not
|
|
35
|
+
* yet adopted provider selection; multiple scoped providers remain ambiguous.
|
|
36
|
+
*/
|
|
37
|
+
function getContractResolver(contractId, version, providerPackageId) {
|
|
38
|
+
const unscoped = resolvers.get(resolverKey(contractId, version));
|
|
39
|
+
if (providerPackageId) {
|
|
40
|
+
const scoped = resolvers.get(resolverKey(contractId, version, providerPackageId));
|
|
41
|
+
if (scoped) {
|
|
42
|
+
return scoped;
|
|
43
|
+
}
|
|
44
|
+
return unscoped;
|
|
45
|
+
}
|
|
46
|
+
if (unscoped) {
|
|
47
|
+
return unscoped;
|
|
48
|
+
}
|
|
49
|
+
const providerPrefix = `${(0, types_1.contractKey)(contractId, version)}#provider:`;
|
|
50
|
+
let onlyScopedResolver;
|
|
51
|
+
for (const [key, resolver] of resolvers) {
|
|
52
|
+
if (!key.startsWith(providerPrefix)) {
|
|
53
|
+
continue;
|
|
54
|
+
}
|
|
55
|
+
if (onlyScopedResolver) {
|
|
56
|
+
return undefined;
|
|
57
|
+
}
|
|
58
|
+
onlyScopedResolver = resolver;
|
|
59
|
+
}
|
|
60
|
+
return onlyScopedResolver;
|
|
29
61
|
}
|
|
30
62
|
/**
|
|
31
63
|
* Check whether a connection-authenticated remote identity has full contract authority.
|
|
@@ -91,6 +123,41 @@ function getAuthorizedLocalDataContext(userContext, requestedId) {
|
|
|
91
123
|
}
|
|
92
124
|
return userContext.getDataContext(dataContextId);
|
|
93
125
|
}
|
|
126
|
+
function getActiveProviderPackageId(dataContext, contractId, version) {
|
|
127
|
+
return dataContext.packageLoader?.getActiveContractProviderPackageId?.(contractId, version);
|
|
128
|
+
}
|
|
129
|
+
async function resolveDataContextEndpoint(dataContext, request, resolveVariable) {
|
|
130
|
+
if (dataContext.packageLoader?.resolveContractEndpoint) {
|
|
131
|
+
return dataContext.packageLoader.resolveContractEndpoint(request, {
|
|
132
|
+
resolveVariable: resolveVariable
|
|
133
|
+
? (variableName, requestingToolId) => resolveVariable({ dataContext, variableName, requestingToolId })
|
|
134
|
+
: undefined,
|
|
135
|
+
});
|
|
136
|
+
}
|
|
137
|
+
// Transitional fallback for hosts/tests that provide a partial DataContext.
|
|
138
|
+
const isolatedEndpoint = await dataContext.packageLoader?.resolveIsolatedEndpoint?.(request);
|
|
139
|
+
if (isolatedEndpoint) {
|
|
140
|
+
return isolatedEndpoint;
|
|
141
|
+
}
|
|
142
|
+
const resolver = getContractResolver(request.contractId, request.version, request.providerPackageId);
|
|
143
|
+
if (!resolver) {
|
|
144
|
+
throw new Error(`No contract provider registered for ${request.contractId} v${request.version}`);
|
|
145
|
+
}
|
|
146
|
+
const resolution = await resolver({ dataContext });
|
|
147
|
+
const localResolution = resolveVariable
|
|
148
|
+
? {
|
|
149
|
+
...resolution,
|
|
150
|
+
toolContext: {
|
|
151
|
+
dataContextId: dataContext.dataContextId,
|
|
152
|
+
getVariable: (variableName, requestingToolId) => resolveVariable({ dataContext, variableName, requestingToolId }),
|
|
153
|
+
},
|
|
154
|
+
}
|
|
155
|
+
: resolution;
|
|
156
|
+
return (0, contract_proxy_1.createContractProviderEndpoint)(localResolution, {
|
|
157
|
+
context: request.context,
|
|
158
|
+
notify: request.notify,
|
|
159
|
+
});
|
|
160
|
+
}
|
|
94
161
|
/**
|
|
95
162
|
* Create a provider router for one authenticated UI-to-local-host session.
|
|
96
163
|
*
|
|
@@ -127,24 +194,15 @@ function createLocalUserContextContractProviderRouter(transport, opts) {
|
|
|
127
194
|
context,
|
|
128
195
|
};
|
|
129
196
|
},
|
|
130
|
-
|
|
197
|
+
resolveProviderPackageId: async ({ contractId, version, dataContextId }) => {
|
|
131
198
|
const userContext = await getUserContext();
|
|
132
|
-
const resolver = getContractResolver(contractId, version);
|
|
133
|
-
if (!resolver) {
|
|
134
|
-
throw new Error(`No contract provider registered for ${contractId} v${version}`);
|
|
135
|
-
}
|
|
136
199
|
const dataContext = getAuthorizedLocalDataContext(userContext, dataContextId);
|
|
137
|
-
|
|
138
|
-
|
|
139
|
-
|
|
140
|
-
|
|
141
|
-
|
|
142
|
-
|
|
143
|
-
getVariable: (variableName, requestingToolId) => resolveVariable({ dataContext, variableName, requestingToolId }),
|
|
144
|
-
},
|
|
145
|
-
}
|
|
146
|
-
: resolution;
|
|
147
|
-
return (0, contract_proxy_1.createContractProviderEndpoint)(localResolution, { context, notify });
|
|
200
|
+
return getActiveProviderPackageId(dataContext, contractId, version);
|
|
201
|
+
},
|
|
202
|
+
resolveEndpoint: async (request) => {
|
|
203
|
+
const userContext = await getUserContext();
|
|
204
|
+
const dataContext = getAuthorizedLocalDataContext(userContext, request.dataContextId);
|
|
205
|
+
return resolveDataContextEndpoint(dataContext, request, resolveVariable);
|
|
148
206
|
},
|
|
149
207
|
});
|
|
150
208
|
}
|
|
@@ -172,14 +230,13 @@ function createUserContextContractProviderRouter(transport, opts) {
|
|
|
172
230
|
return (0, contract_provider_router_1.createContractProviderRouter)(transport, {
|
|
173
231
|
context,
|
|
174
232
|
authorizeCall: (call) => authorizeUserContextCall(call, userContext, remoteIdentity),
|
|
175
|
-
|
|
176
|
-
const resolver = getContractResolver(contractId, version);
|
|
177
|
-
if (!resolver) {
|
|
178
|
-
throw new Error(`No contract provider registered for ${contractId} v${version}`);
|
|
179
|
-
}
|
|
233
|
+
resolveProviderPackageId: ({ contractId, version, dataContextId }) => {
|
|
180
234
|
const dataContext = userContext.getDataContext(dataContextId || userContext.userId);
|
|
181
|
-
|
|
182
|
-
|
|
235
|
+
return getActiveProviderPackageId(dataContext, contractId, version);
|
|
236
|
+
},
|
|
237
|
+
resolveEndpoint: (request) => {
|
|
238
|
+
const dataContext = userContext.getDataContext(request.dataContextId || userContext.userId);
|
|
239
|
+
return resolveDataContextEndpoint(dataContext, request);
|
|
183
240
|
},
|
|
184
241
|
});
|
|
185
242
|
}
|
|
@@ -198,15 +255,31 @@ function createUserContextContractProviderRouter(transport, opts) {
|
|
|
198
255
|
async function handleContractCall(call, opts) {
|
|
199
256
|
const { userContext, remoteIdentity } = opts;
|
|
200
257
|
const authorization = await authorizeUserContextCall(call, userContext, remoteIdentity);
|
|
201
|
-
const resolver = getContractResolver(call.contractId, call.version);
|
|
202
|
-
if (!resolver) {
|
|
203
|
-
throw new Error(`No contract provider registered for ${call.contractId} v${call.version}`);
|
|
204
|
-
}
|
|
205
258
|
const routedCall = {
|
|
206
259
|
...call,
|
|
207
260
|
dataContextId: authorization.dataContextId,
|
|
208
261
|
};
|
|
209
262
|
const dataContext = userContext.getDataContext(authorization.dataContextId || userContext.userId);
|
|
263
|
+
if (dataContext.packageLoader?.resolveContractEndpoint) {
|
|
264
|
+
const endpoint = await dataContext.packageLoader.resolveContractEndpoint({
|
|
265
|
+
contractId: call.contractId,
|
|
266
|
+
version: call.version,
|
|
267
|
+
providerPackageId: getActiveProviderPackageId(dataContext, call.contractId, call.version),
|
|
268
|
+
dataContextId: authorization.dataContextId,
|
|
269
|
+
context: authorization.context ?? {},
|
|
270
|
+
notify: async () => undefined,
|
|
271
|
+
});
|
|
272
|
+
try {
|
|
273
|
+
return await endpoint.handleCall(routedCall, authorization.context);
|
|
274
|
+
}
|
|
275
|
+
finally {
|
|
276
|
+
endpoint.dispose();
|
|
277
|
+
}
|
|
278
|
+
}
|
|
279
|
+
const resolver = getContractResolver(call.contractId, call.version);
|
|
280
|
+
if (!resolver) {
|
|
281
|
+
throw new Error(`No contract provider registered for ${call.contractId} v${call.version}`);
|
|
282
|
+
}
|
|
210
283
|
const resolution = await resolver({ dataContext });
|
|
211
284
|
const provider = (0, contract_proxy_1.createContractProvider)(resolution);
|
|
212
285
|
return provider(routedCall, authorization.context);
|
|
@@ -1,15 +1,15 @@
|
|
|
1
1
|
export { ContractBuilder, definePackage, PackageBuilder } from "./builder";
|
|
2
|
-
export { type ContractCallAuthorizer, type ContractProviderEndpointResolver, createContractProviderRouter, type IAuthorizedContractRoute, type IContractProviderEndpointRequest, type IContractProviderRouter, type IContractProviderRouterOptions, } from "./contract-provider-router";
|
|
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
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 ILocalContractVariableRequest, isSelfTrustedContractCaller, type LocalContractVariableResolver, registerContractResolver, } from "./contract-resolvers";
|
|
5
|
+
export { type ContractRemoteIdentity, type ContractResolver, createLocalUserContextContractProviderRouter, createUserContextContractProviderRouter, getContractResolver, handleContractCall, type IContractResolverRegistrationOptions, type ILocalContractVariableRequest, isSelfTrustedContractCaller, type LocalContractVariableResolver, registerContractResolver, } 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";
|
|
9
9
|
export { extractTableShape, extractToolShape, type IExtractableTableDef, type IExtractableToolInstance, setSchemaToFieldsFn, } from "./extract";
|
|
10
10
|
export { getHostContractTransport, type HostContractTransportListener, registerHostContractTransport, subscribeHostContractTransport, waitForHostContractTransport, } from "./host-contract-transport";
|
|
11
11
|
export { PersistentContractRegistry } from "./persistent-registry";
|
|
12
|
-
export { ContractRegistry } from "./registry";
|
|
12
|
+
export { ContractRegistry, type IContractProviderRegistration } from "./registry";
|
|
13
13
|
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
14
|
export { getLogsContractDefinition, type ILogsConsumer, LOGS_CONTRACT_VERSION, resolveLogsContract, } from "./system/logs-contract";
|
|
15
15
|
export * from "./system/network-contracts";
|
|
@@ -1,4 +1,14 @@
|
|
|
1
1
|
import type { IAlsoImplementsDeclaration, IConsumedContract, IContractDefinition, IValidationResult } from "./types";
|
|
2
|
+
/**
|
|
3
|
+
* One contract-provider registration in an atomic
|
|
4
|
+
* {@link ContractRegistry.registerBatch} operation.
|
|
5
|
+
*/
|
|
6
|
+
export interface IContractProviderRegistration {
|
|
7
|
+
/** Contract shape implemented by the provider package. */
|
|
8
|
+
definition: IContractDefinition;
|
|
9
|
+
/** Older contract shapes this implementation also satisfies. */
|
|
10
|
+
alsoImplements?: IAlsoImplementsDeclaration[];
|
|
11
|
+
}
|
|
2
12
|
/**
|
|
3
13
|
* Per-group contract registry. Maps contract identities (contractId + version)
|
|
4
14
|
* to their active provider. In V1 this is in-memory only; persistence will
|
|
@@ -27,6 +37,41 @@ export declare class ContractRegistry {
|
|
|
27
37
|
* @returns Validation result. If invalid the provider is not registered.
|
|
28
38
|
*/
|
|
29
39
|
register(providerPackageId: string, definition: IContractDefinition, alsoImplementsDecls?: IAlsoImplementsDeclaration[]): IValidationResult;
|
|
40
|
+
/**
|
|
41
|
+
* Atomically register every contract supplied by one provider package.
|
|
42
|
+
*
|
|
43
|
+
* Frozen-shape and `alsoImplements` checks run against a candidate registry
|
|
44
|
+
* containing the whole batch, so declarations may reference another
|
|
45
|
+
* contract in the same install. If any entry fails, no definition, provider,
|
|
46
|
+
* active-provider pointer, or reverse index is changed.
|
|
47
|
+
*
|
|
48
|
+
* @param providerPackageId - Trusted identity of the provider package.
|
|
49
|
+
* @param registrations - Contract definitions and compatibility declarations.
|
|
50
|
+
* @returns The combined validation result.
|
|
51
|
+
*/
|
|
52
|
+
registerBatch(providerPackageId: string, registrations: readonly IContractProviderRegistration[]): IValidationResult;
|
|
53
|
+
/**
|
|
54
|
+
* Atomically replace the complete contract set for one provider package.
|
|
55
|
+
*
|
|
56
|
+
* Validation runs before the existing provider entries are touched. Active
|
|
57
|
+
* selections remain on this package for contract versions it still provides;
|
|
58
|
+
* removed versions fall back according to ordinary unregister semantics.
|
|
59
|
+
*
|
|
60
|
+
* @param providerPackageId - Trusted provider package identity.
|
|
61
|
+
* @param registrations - Complete replacement set.
|
|
62
|
+
* @returns Validation result; invalid replacements leave the registry unchanged.
|
|
63
|
+
*/
|
|
64
|
+
replaceBatch(providerPackageId: string, registrations: readonly IContractProviderRegistration[]): IValidationResult;
|
|
65
|
+
/**
|
|
66
|
+
* Validate a complete provider registration batch without changing registry state.
|
|
67
|
+
*
|
|
68
|
+
* @param providerPackageId - Trusted provider package identity.
|
|
69
|
+
* @param registrations - Definitions and compatibility declarations to validate.
|
|
70
|
+
* @returns Combined validation result.
|
|
71
|
+
*/
|
|
72
|
+
validateBatch(providerPackageId: string, registrations: readonly IContractProviderRegistration[]): IValidationResult;
|
|
73
|
+
private commitRegistrations;
|
|
74
|
+
private commitProvider;
|
|
30
75
|
/**
|
|
31
76
|
* Switch the active provider for a contract to a different registered package.
|
|
32
77
|
* Returns false if the target package is not a registered provider for that contract.
|
|
@@ -44,6 +89,20 @@ export declare class ContractRegistry {
|
|
|
44
89
|
* Includes inactive providers.
|
|
45
90
|
*/
|
|
46
91
|
getRegisteredProviderIds(contractId: string, version: number): string[];
|
|
92
|
+
/**
|
|
93
|
+
* Resolve the concrete contract implementation selected for one provider.
|
|
94
|
+
*
|
|
95
|
+
* For a direct registration this matches the requested contract. For an
|
|
96
|
+
* `alsoImplements` alias it identifies the newer compatible implementation.
|
|
97
|
+
*
|
|
98
|
+
* @param contractId - Consumer-requested contract identity.
|
|
99
|
+
* @param version - Consumer-requested contract version.
|
|
100
|
+
* @param providerPackageId - Registry-selected provider package.
|
|
101
|
+
*/
|
|
102
|
+
getProviderImplementation(contractId: string, version: number, providerPackageId: string): {
|
|
103
|
+
contractId: string;
|
|
104
|
+
version: number;
|
|
105
|
+
} | undefined;
|
|
47
106
|
/**
|
|
48
107
|
* Pick a provider for a consumed-contract declaration.
|
|
49
108
|
*
|