@peers-app/peers-sdk 0.23.4 → 0.23.6

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 (75) hide show
  1. package/dist/context/data-context.d.ts +36 -5
  2. package/dist/context/data-context.js +44 -9
  3. package/dist/context/user-context.d.ts +44 -0
  4. package/dist/context/user-context.js +91 -12
  5. package/dist/contracts/__tests__/contract-provider-router.test.js +26 -0
  6. package/dist/contracts/__tests__/contract-resolvers.test.js +44 -0
  7. package/dist/contracts/__tests__/registry.test.js +104 -0
  8. package/dist/contracts/contract-provider-router.d.ts +21 -0
  9. package/dist/contracts/contract-provider-router.js +31 -5
  10. package/dist/contracts/contract-proxy.d.ts +3 -0
  11. package/dist/contracts/contract-proxy.js +3 -0
  12. package/dist/contracts/contract-resolvers.d.ts +21 -3
  13. package/dist/contracts/contract-resolvers.js +105 -32
  14. package/dist/contracts/index.d.ts +3 -3
  15. package/dist/contracts/registry.d.ts +59 -0
  16. package/dist/contracts/registry.js +155 -25
  17. package/dist/contracts/system-contracts.js +3 -1
  18. package/dist/data/index.d.ts +1 -0
  19. package/dist/data/index.js +1 -0
  20. package/dist/data/orm/types.d.ts +19 -0
  21. package/dist/data/orm/types.js +11 -0
  22. package/dist/data/package-table-identity.d.ts +46 -0
  23. package/dist/data/package-table-identity.js +71 -0
  24. package/dist/data/package-table-identity.test.d.ts +1 -0
  25. package/dist/data/package-table-identity.test.js +46 -0
  26. package/dist/data/package-version-resolver.d.ts +13 -0
  27. package/dist/data/package-version-resolver.js +142 -6
  28. package/dist/data/package-version-resolver.test.js +42 -0
  29. package/dist/data/persistent-var-identity.d.ts +37 -0
  30. package/dist/data/persistent-var-identity.js +69 -0
  31. package/dist/data/persistent-vars.d.ts +3 -5
  32. package/dist/data/persistent-vars.js +25 -13
  33. package/dist/data/persistent-vars.package-scope.test.d.ts +1 -0
  34. package/dist/data/persistent-vars.package-scope.test.js +27 -0
  35. package/dist/data/tools.d.ts +3 -3
  36. package/dist/package-installer/index.d.ts +1 -0
  37. package/dist/package-installer/index.js +1 -0
  38. package/dist/package-installer/package-cloner.d.ts +1 -1
  39. package/dist/package-installer/package-cloner.js +11 -16
  40. package/dist/package-installer/package-cloner.test.js +5 -3
  41. package/dist/package-installer/package-creator.d.ts +4 -3
  42. package/dist/package-installer/package-creator.js +13 -5
  43. package/dist/package-installer/package-creator.test.js +19 -0
  44. package/dist/package-installer/package-dev-tools.d.ts +30 -0
  45. package/dist/package-installer/package-dev-tools.js +63 -0
  46. package/dist/package-installer/package-dev-tools.test.d.ts +1 -0
  47. package/dist/package-installer/package-dev-tools.test.js +64 -0
  48. package/dist/package-loader/contract-package-loader.js +20 -8
  49. package/dist/package-loader/contract-package-loader.test.js +16 -0
  50. package/dist/package-loader/index.d.ts +4 -0
  51. package/dist/package-loader/index.js +4 -0
  52. package/dist/package-loader/isolated-artifact.d.ts +233 -0
  53. package/dist/package-loader/isolated-artifact.js +643 -0
  54. package/dist/package-loader/isolated-artifact.test.d.ts +1 -0
  55. package/dist/package-loader/isolated-artifact.test.js +270 -0
  56. package/dist/package-loader/isolated-persistent-var-gateway.d.ts +20 -0
  57. package/dist/package-loader/isolated-persistent-var-gateway.js +106 -0
  58. package/dist/package-loader/isolated-persistent-var-gateway.test.d.ts +1 -0
  59. package/dist/package-loader/isolated-persistent-var-gateway.test.js +56 -0
  60. package/dist/package-loader/isolated-runtime.d.ts +229 -0
  61. package/dist/package-loader/isolated-runtime.js +37 -0
  62. package/dist/package-loader/isolated-table-gateway.d.ts +16 -0
  63. package/dist/package-loader/isolated-table-gateway.js +375 -0
  64. package/dist/package-loader/isolated-table-gateway.test.d.ts +1 -0
  65. package/dist/package-loader/isolated-table-gateway.test.js +206 -0
  66. package/dist/package-loader/isolated-value.d.ts +14 -0
  67. package/dist/package-loader/isolated-value.js +63 -0
  68. package/dist/package-loader/package-loader.d.ts +123 -4
  69. package/dist/package-loader/package-loader.js +417 -46
  70. package/dist/package-loader/package-loader.test.js +478 -12
  71. package/dist/package-loader/resolve-consumed-contracts.d.ts +3 -3
  72. package/dist/package-loader/resolve-consumed-contracts.js +18 -10
  73. package/dist/utils.d.ts +21 -2
  74. package/dist/utils.js +46 -7
  75. 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 endpointKey = routeKey(call.contractId, call.version, authorization.dataContextId);
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
- /** Look up the resolver for a contract version, if one is registered. */
32
- export declare function getContractResolver(contractId: string, version: number): ContractResolver | undefined;
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((0, types_1.contractKey)(contractId, version), resolver);
26
+ function registerContractResolver(contractId, version, resolver, opts = {}) {
27
+ resolvers.set(resolverKey(contractId, version, opts.providerPackageId), resolver);
25
28
  }
26
- /** Look up the resolver for a contract version, if one is registered. */
27
- function getContractResolver(contractId, version) {
28
- return resolvers.get((0, types_1.contractKey)(contractId, version));
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
- resolveEndpoint: async ({ contractId, version, dataContextId, context, notify }) => {
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
- const resolution = await resolver({ dataContext });
138
- const localResolution = resolveVariable
139
- ? {
140
- ...resolution,
141
- toolContext: {
142
- dataContextId: dataContext.dataContextId,
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
- resolveEndpoint: async ({ contractId, version, dataContextId, notify }) => {
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
- const resolution = await resolver({ dataContext });
182
- return (0, contract_proxy_1.createContractProviderEndpoint)(resolution, { notify });
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
  *