@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
|
@@ -2,6 +2,10 @@
|
|
|
2
2
|
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
3
|
exports.PackageLoader = void 0;
|
|
4
4
|
exports.setDefaultRequire = setDefaultRequire;
|
|
5
|
+
const contract_provider_router_1 = require("../contracts/contract-provider-router");
|
|
6
|
+
const contract_proxy_1 = require("../contracts/contract-proxy");
|
|
7
|
+
const contract_resolvers_1 = require("../contracts/contract-resolvers");
|
|
8
|
+
const contract_transport_1 = require("../contracts/contract-transport");
|
|
5
9
|
const registry_1 = require("../contracts/registry");
|
|
6
10
|
const system_contracts_1 = require("../contracts/system-contracts");
|
|
7
11
|
const files_1 = require("../data/files");
|
|
@@ -11,51 +15,329 @@ const packages_1 = require("../data/packages");
|
|
|
11
15
|
const tools_1 = require("../data/tools");
|
|
12
16
|
const tools_2 = require("../tools");
|
|
13
17
|
const contract_package_loader_1 = require("./contract-package-loader");
|
|
18
|
+
const isolated_artifact_1 = require("./isolated-artifact");
|
|
19
|
+
const isolated_persistent_var_gateway_1 = require("./isolated-persistent-var-gateway");
|
|
20
|
+
const isolated_runtime_1 = require("./isolated-runtime");
|
|
21
|
+
const isolated_table_gateway_1 = require("./isolated-table-gateway");
|
|
14
22
|
const resolve_consumed_contracts_1 = require("./resolve-consumed-contracts");
|
|
15
23
|
// Ensure built-in system contracts are cataloged before any PackageLoader installs them.
|
|
16
24
|
require("../contracts/system");
|
|
25
|
+
function isolatedContractLifecycle(packageVersion) {
|
|
26
|
+
return {
|
|
27
|
+
contractLifecycle: packageVersion?.versionTag === "dev" || packageVersion?.versionTag === "beta"
|
|
28
|
+
? "mutable"
|
|
29
|
+
: "stable",
|
|
30
|
+
packageVersionId: packageVersion?.packageVersionId,
|
|
31
|
+
packageVersion: packageVersion?.version,
|
|
32
|
+
versionTag: packageVersion?.versionTag,
|
|
33
|
+
};
|
|
34
|
+
}
|
|
35
|
+
/**
|
|
36
|
+
* Loads package versions for one {@link DataContext}.
|
|
37
|
+
*
|
|
38
|
+
* Isolated artifacts (magic-header JSON) are installed without host
|
|
39
|
+
* evaluation. Legacy `package.bundle.js` files still evaluate in-process.
|
|
40
|
+
*/
|
|
17
41
|
class PackageLoader {
|
|
18
42
|
dataContext;
|
|
43
|
+
/** Host-injected SDK module used as the `peers-sdk` / `PeersSDK` require. */
|
|
19
44
|
static PeersSDK;
|
|
45
|
+
/** Host-injected Zod module used as the `zod` require. */
|
|
20
46
|
static Zod;
|
|
21
47
|
packageInstances = {};
|
|
22
48
|
/** Packages that were installed via the contract-based path (tools/assistants/tables already saved with packageId). */
|
|
23
49
|
contractInstalledPackages = new Set();
|
|
50
|
+
/** Packages installed through the isolated runtime (no host eval). */
|
|
51
|
+
isolatedPackageIds = new Set();
|
|
24
52
|
/**
|
|
25
53
|
* In-memory contract providers for this data context. Seeded with system
|
|
26
54
|
* contracts at construction; package providers are added via
|
|
27
|
-
* {@link installContractPackage}.
|
|
55
|
+
* {@link installContractPackage} or the isolated runtime.
|
|
28
56
|
*/
|
|
29
57
|
contractRegistry;
|
|
58
|
+
/** Optional isolated-provider supervisor created from the host factory. */
|
|
59
|
+
isolatedRuntime;
|
|
60
|
+
/** Optional host `require` used when reading local bundles or evaluating legacy packages. */
|
|
30
61
|
require = undefined;
|
|
62
|
+
/**
|
|
63
|
+
* @param dataContext - Owning personal or group data context. Its
|
|
64
|
+
* `tableContainer` must already be assigned so isolated packages that
|
|
65
|
+
* declare tables receive a host gateway.
|
|
66
|
+
*/
|
|
31
67
|
constructor(dataContext) {
|
|
32
68
|
this.dataContext = dataContext;
|
|
33
69
|
this.contractRegistry = new registry_1.ContractRegistry();
|
|
34
70
|
(0, system_contracts_1.installSystemContracts)(this.contractRegistry);
|
|
71
|
+
const factory = (0, isolated_runtime_1.getIsolatedPackageRuntimeFactory)();
|
|
72
|
+
if (factory) {
|
|
73
|
+
this.isolatedRuntime = factory({
|
|
74
|
+
registry: this.contractRegistry,
|
|
75
|
+
dataContextId: dataContext.dataContextId,
|
|
76
|
+
tableGateway: dataContext.tableContainer
|
|
77
|
+
? (0, isolated_table_gateway_1.createIsolatedPackageTableGateway)(dataContext)
|
|
78
|
+
: undefined,
|
|
79
|
+
persistentVarGateway: dataContext.userContext
|
|
80
|
+
? (0, isolated_persistent_var_gateway_1.createIsolatedPackagePersistentVarGateway)(dataContext)
|
|
81
|
+
: undefined,
|
|
82
|
+
providerGateway: {
|
|
83
|
+
resolveEndpoint: (request) => this.resolveContractEndpoint(request, {
|
|
84
|
+
providerPackageId: request.providerPackageId,
|
|
85
|
+
resolverOnly: true,
|
|
86
|
+
}),
|
|
87
|
+
},
|
|
88
|
+
});
|
|
89
|
+
}
|
|
35
90
|
}
|
|
36
|
-
/**
|
|
91
|
+
/**
|
|
92
|
+
* Returns true if a package was installed via the contract-based
|
|
93
|
+
* `definePackage()` path or as an isolated artifact.
|
|
94
|
+
*
|
|
95
|
+
* @param packageId - Package to query.
|
|
96
|
+
*/
|
|
37
97
|
isContractInstalled(packageId) {
|
|
38
98
|
return this.contractInstalledPackages.has(packageId);
|
|
39
99
|
}
|
|
100
|
+
/**
|
|
101
|
+
* Returns true if `packageId` was installed as an isolated artifact.
|
|
102
|
+
*
|
|
103
|
+
* @param packageId - Package to query.
|
|
104
|
+
*/
|
|
105
|
+
isIsolatedInstalled(packageId) {
|
|
106
|
+
return this.isolatedPackageIds.has(packageId);
|
|
107
|
+
}
|
|
108
|
+
/** Return whether this host configured an isolated-package runtime. */
|
|
109
|
+
supportsIsolatedPackages() {
|
|
110
|
+
return this.isolatedRuntime !== undefined;
|
|
111
|
+
}
|
|
112
|
+
/**
|
|
113
|
+
* Return the active provider selected by this data context's trusted registry.
|
|
114
|
+
*
|
|
115
|
+
* @param contractId - Target contract identity.
|
|
116
|
+
* @param version - Target contract version.
|
|
117
|
+
*/
|
|
118
|
+
getActiveContractProviderPackageId(contractId, version) {
|
|
119
|
+
return this.contractRegistry.getProviderPackageId(contractId, version);
|
|
120
|
+
}
|
|
121
|
+
/**
|
|
122
|
+
* Resolve one authorized endpoint through the registry-selected provider.
|
|
123
|
+
*
|
|
124
|
+
* Isolated providers are delegated to the host runtime; resolver-backed
|
|
125
|
+
* providers are looked up by provider package. Contracts that predate package
|
|
126
|
+
* registration may still use their legacy unscoped resolver.
|
|
127
|
+
* Provider identity comes only from trusted registry/options state, never
|
|
128
|
+
* from an {@link import("../contracts/contract-proxy").IContractCall}.
|
|
129
|
+
*
|
|
130
|
+
* @param request - Authorized contract route and notification sink.
|
|
131
|
+
* @param opts - Trusted provider override and host-only resolver capabilities.
|
|
132
|
+
* @throws If no provider or matching endpoint implementation is available.
|
|
133
|
+
*/
|
|
134
|
+
async resolveContractEndpoint(request, opts = {}) {
|
|
135
|
+
const providerPackageId = opts.providerPackageId ??
|
|
136
|
+
request.providerPackageId ??
|
|
137
|
+
this.contractRegistry.getProviderPackageId(request.contractId, request.version);
|
|
138
|
+
if (!providerPackageId) {
|
|
139
|
+
const legacyResolver = (0, contract_resolvers_1.getContractResolver)(request.contractId, request.version);
|
|
140
|
+
if (!legacyResolver) {
|
|
141
|
+
throw new Error(`No contract provider registered for ${request.contractId} v${request.version}`);
|
|
142
|
+
}
|
|
143
|
+
const resolution = await legacyResolver({ dataContext: this.dataContext });
|
|
144
|
+
const localResolution = opts.resolveVariable
|
|
145
|
+
? {
|
|
146
|
+
...resolution,
|
|
147
|
+
toolContext: {
|
|
148
|
+
dataContextId: this.dataContext.dataContextId,
|
|
149
|
+
getVariable: opts.resolveVariable,
|
|
150
|
+
},
|
|
151
|
+
}
|
|
152
|
+
: resolution;
|
|
153
|
+
return (0, contract_proxy_1.createContractProviderEndpoint)(localResolution, {
|
|
154
|
+
context: request.context,
|
|
155
|
+
notify: request.notify,
|
|
156
|
+
});
|
|
157
|
+
}
|
|
158
|
+
if (!this.contractRegistry
|
|
159
|
+
.getRegisteredProviderIds(request.contractId, request.version)
|
|
160
|
+
.includes(providerPackageId)) {
|
|
161
|
+
throw new Error(`Package ${providerPackageId} is not a registered provider for ${request.contractId} v${request.version}`);
|
|
162
|
+
}
|
|
163
|
+
const trustedRequest = {
|
|
164
|
+
...request,
|
|
165
|
+
providerPackageId,
|
|
166
|
+
};
|
|
167
|
+
if (!opts.resolverOnly && this.isolatedRuntime?.isInstalled(providerPackageId)) {
|
|
168
|
+
const isolatedEndpoint = await this.isolatedRuntime.resolveEndpoint(trustedRequest);
|
|
169
|
+
if (!isolatedEndpoint) {
|
|
170
|
+
throw new Error(`Isolated provider ${providerPackageId} could not resolve ${request.contractId} v${request.version}`);
|
|
171
|
+
}
|
|
172
|
+
return isolatedEndpoint;
|
|
173
|
+
}
|
|
174
|
+
const implementation = this.contractRegistry.getProviderImplementation(request.contractId, request.version, providerPackageId) ?? {
|
|
175
|
+
contractId: request.contractId,
|
|
176
|
+
version: request.version,
|
|
177
|
+
};
|
|
178
|
+
const resolver = (0, contract_resolvers_1.getContractResolver)(implementation.contractId, implementation.version, providerPackageId);
|
|
179
|
+
if (!resolver) {
|
|
180
|
+
throw new Error(`Provider ${providerPackageId} has no live resolver for ${request.contractId} v${request.version}`);
|
|
181
|
+
}
|
|
182
|
+
const resolution = await resolver({ dataContext: this.dataContext });
|
|
183
|
+
const localResolution = opts.resolveVariable
|
|
184
|
+
? {
|
|
185
|
+
...resolution,
|
|
186
|
+
toolContext: {
|
|
187
|
+
dataContextId: this.dataContext.dataContextId,
|
|
188
|
+
getVariable: opts.resolveVariable,
|
|
189
|
+
},
|
|
190
|
+
}
|
|
191
|
+
: resolution;
|
|
192
|
+
const endpoint = (0, contract_proxy_1.createContractProviderEndpoint)(localResolution, {
|
|
193
|
+
context: request.context,
|
|
194
|
+
notify: (notification) => request.notify({
|
|
195
|
+
...notification,
|
|
196
|
+
contractId: request.contractId,
|
|
197
|
+
}),
|
|
198
|
+
});
|
|
199
|
+
if (implementation.contractId === request.contractId &&
|
|
200
|
+
implementation.version === request.version) {
|
|
201
|
+
return endpoint;
|
|
202
|
+
}
|
|
203
|
+
return {
|
|
204
|
+
handleCall: (call, context) => endpoint.handleCall({
|
|
205
|
+
...call,
|
|
206
|
+
contractId: implementation.contractId,
|
|
207
|
+
version: implementation.version,
|
|
208
|
+
}, context),
|
|
209
|
+
dispose: () => endpoint.dispose(),
|
|
210
|
+
};
|
|
211
|
+
}
|
|
212
|
+
/**
|
|
213
|
+
* Bind a legacy package's declared consume to its selected provider.
|
|
214
|
+
*
|
|
215
|
+
* The returned proxy can target either a resolver-backed or isolated provider.
|
|
216
|
+
* Its provider choice is captured from {@link ContractRegistry.selectProvider}
|
|
217
|
+
* before any consumer call payload is processed.
|
|
218
|
+
*
|
|
219
|
+
* @param dependency - Validated package consume declaration.
|
|
220
|
+
* @returns A live consumer proxy, or `undefined` when no provider matches.
|
|
221
|
+
*/
|
|
222
|
+
async resolveConsumedContract(dependency) {
|
|
223
|
+
const selected = this.contractRegistry.selectProvider(dependency);
|
|
224
|
+
if (!selected) {
|
|
225
|
+
return undefined;
|
|
226
|
+
}
|
|
227
|
+
const providerPackageId = selected.providerPackageId;
|
|
228
|
+
const [consumerTransport, providerTransport] = (0, contract_transport_1.inProcessTransportPair)();
|
|
229
|
+
const router = (0, contract_provider_router_1.createContractProviderRouter)(providerTransport, {
|
|
230
|
+
authorizeCall: () => ({
|
|
231
|
+
dataContextId: this.dataContext.dataContextId,
|
|
232
|
+
context: { dataContext: this.dataContext },
|
|
233
|
+
}),
|
|
234
|
+
resolveProviderPackageId: () => providerPackageId,
|
|
235
|
+
resolveEndpoint: (request) => this.resolveContractEndpoint(request, { providerPackageId }),
|
|
236
|
+
});
|
|
237
|
+
const consumer = (0, contract_proxy_1.createContractConsumer)(selected.definition, consumerTransport, {
|
|
238
|
+
dataContextId: this.dataContext.dataContextId,
|
|
239
|
+
});
|
|
240
|
+
const dispose = consumer.dispose.bind(consumer);
|
|
241
|
+
consumer.dispose = () => {
|
|
242
|
+
dispose();
|
|
243
|
+
router.dispose();
|
|
244
|
+
};
|
|
245
|
+
return consumer;
|
|
246
|
+
}
|
|
247
|
+
/**
|
|
248
|
+
* Resolve a sandbox-backed provider endpoint when this context owns an
|
|
249
|
+
* isolated provider for the requested contract.
|
|
250
|
+
*
|
|
251
|
+
* @param request - Authorized contract/version/data-context route.
|
|
252
|
+
*/
|
|
253
|
+
async resolveIsolatedEndpoint(request) {
|
|
254
|
+
const providerPackageId = request.providerPackageId ??
|
|
255
|
+
this.contractRegistry.getProviderPackageId(request.contractId, request.version);
|
|
256
|
+
if (!this.isolatedRuntime ||
|
|
257
|
+
!providerPackageId ||
|
|
258
|
+
!this.isolatedRuntime.isInstalled(providerPackageId)) {
|
|
259
|
+
return undefined;
|
|
260
|
+
}
|
|
261
|
+
return this.isolatedRuntime.resolveEndpoint({ ...request, providerPackageId });
|
|
262
|
+
}
|
|
263
|
+
/**
|
|
264
|
+
* Stop an isolated worker (if any) and drop the in-memory package instance.
|
|
265
|
+
*
|
|
266
|
+
* @param packageId - Package to unload.
|
|
267
|
+
*/
|
|
268
|
+
async unloadPackage(packageId) {
|
|
269
|
+
if (this.isolatedRuntime?.isInstalled(packageId)) {
|
|
270
|
+
await this.isolatedRuntime.uninstall(packageId);
|
|
271
|
+
}
|
|
272
|
+
this.contractRegistry.unregister(packageId);
|
|
273
|
+
this.isolatedPackageIds.delete(packageId);
|
|
274
|
+
this.contractInstalledPackages.delete(packageId);
|
|
275
|
+
delete this.packageInstances[packageId];
|
|
276
|
+
}
|
|
277
|
+
/**
|
|
278
|
+
* Dispose the isolated runtime for this data context.
|
|
279
|
+
*/
|
|
280
|
+
async dispose() {
|
|
281
|
+
if (this.isolatedRuntime) {
|
|
282
|
+
await this.isolatedRuntime.dispose();
|
|
283
|
+
}
|
|
284
|
+
this.isolatedPackageIds.clear();
|
|
285
|
+
this.contractInstalledPackages.clear();
|
|
286
|
+
this.packageInstances = {};
|
|
287
|
+
}
|
|
288
|
+
/**
|
|
289
|
+
* Resolve and load every non-disabled package in this data context.
|
|
290
|
+
* Disabled packages that were previously loaded are unloaded.
|
|
291
|
+
*
|
|
292
|
+
* @param opts - Forwarded to {@link resolveDevicePackageVersion}.
|
|
293
|
+
*/
|
|
40
294
|
async loadAllPackages(opts) {
|
|
41
295
|
const packages = await (0, packages_1.Packages)(this.dataContext).list();
|
|
42
|
-
await Promise.all(packages
|
|
43
|
-
|
|
44
|
-
|
|
296
|
+
await Promise.all(packages.map(async (pkg) => {
|
|
297
|
+
if (pkg.disabled) {
|
|
298
|
+
await this.unloadPackage(pkg.packageId);
|
|
299
|
+
return;
|
|
300
|
+
}
|
|
301
|
+
try {
|
|
302
|
+
await (0, package_version_resolver_1.resolveDevicePackageVersion)(pkg, this.dataContext, opts);
|
|
303
|
+
}
|
|
304
|
+
catch (error) {
|
|
305
|
+
console.warn(`[PackageLoader] Failed to load package "${pkg.name}" (${pkg.packageId}):`, error instanceof Error ? error.message : String(error));
|
|
306
|
+
}
|
|
307
|
+
}));
|
|
45
308
|
}
|
|
309
|
+
/**
|
|
310
|
+
* Load one package version into this data context.
|
|
311
|
+
*
|
|
312
|
+
* Isolated artifacts are parsed and installed without evaluating provider
|
|
313
|
+
* source. A recognized but malformed isolated envelope fails closed and
|
|
314
|
+
* never falls back to `new Function`. When `localPath` points at a rebuilt
|
|
315
|
+
* isolated `dist/package.bundle.js`, that disk artifact wins over a stale
|
|
316
|
+
* stored Files bundle so local-dev packages pick up new contract versions.
|
|
317
|
+
*
|
|
318
|
+
* @param pkg - Package row.
|
|
319
|
+
* @param opts - Optional force reload, local path fallback, and PV id.
|
|
320
|
+
*/
|
|
46
321
|
async loadPackage(pkg, opts) {
|
|
322
|
+
if (pkg.disabled) {
|
|
323
|
+
await this.unloadPackage(pkg.packageId);
|
|
324
|
+
return undefined;
|
|
325
|
+
}
|
|
47
326
|
if (this.packageInstances[pkg.packageId] && !opts?.force) {
|
|
48
327
|
return this.packageInstances[pkg.packageId];
|
|
49
328
|
}
|
|
50
329
|
const localPath = opts?.localPath;
|
|
330
|
+
let selectedPackageVersion;
|
|
51
331
|
try {
|
|
52
332
|
let bundleCode = "";
|
|
333
|
+
let usingLocalBundle = false;
|
|
53
334
|
let bundleFileId;
|
|
54
335
|
const pvId = opts?.packageVersionId ?? pkg.activePackageVersionId;
|
|
55
336
|
if (pvId) {
|
|
56
337
|
try {
|
|
57
338
|
const pv = await (0, package_versions_1.PackageVersions)(this.dataContext).get(pvId);
|
|
58
339
|
if (pv) {
|
|
340
|
+
selectedPackageVersion = pv;
|
|
59
341
|
bundleFileId = pv.packageBundleFileId;
|
|
60
342
|
}
|
|
61
343
|
}
|
|
@@ -76,25 +358,33 @@ class PackageLoader {
|
|
|
76
358
|
else {
|
|
77
359
|
console.warn(`Package ${pkg.name} does not have a bundle file defined.`);
|
|
78
360
|
}
|
|
79
|
-
|
|
80
|
-
|
|
81
|
-
|
|
361
|
+
if (localPath && selectedPackageVersion?.versionTag === "dev") {
|
|
362
|
+
const localBundleCode = this._readLocalBundle(localPath);
|
|
363
|
+
if (localBundleCode) {
|
|
364
|
+
bundleCode = localBundleCode;
|
|
365
|
+
usingLocalBundle = true;
|
|
366
|
+
}
|
|
82
367
|
}
|
|
83
368
|
if (!bundleCode)
|
|
84
369
|
return;
|
|
85
|
-
return this.
|
|
370
|
+
return await this._loadBundle(pkg, bundleCode, selectedPackageVersion, usingLocalBundle, opts?.force === true);
|
|
86
371
|
}
|
|
87
372
|
catch (err) {
|
|
88
|
-
|
|
89
|
-
|
|
373
|
+
if (isIsolatedArtifactError(err)) {
|
|
374
|
+
throw err;
|
|
375
|
+
}
|
|
376
|
+
if (localPath && selectedPackageVersion?.versionTag === "dev") {
|
|
90
377
|
console.warn(`[PackageLoader] Stored bundle failed for ${pkg.name}, trying local path fallback`, err.message);
|
|
91
378
|
try {
|
|
92
379
|
const localBundleCode = this._readLocalBundle(localPath);
|
|
93
380
|
if (localBundleCode) {
|
|
94
|
-
return this.
|
|
381
|
+
return await this._loadBundle(pkg, localBundleCode, selectedPackageVersion, true, opts?.force === true);
|
|
95
382
|
}
|
|
96
383
|
}
|
|
97
384
|
catch (localErr) {
|
|
385
|
+
if (isIsolatedArtifactError(localErr)) {
|
|
386
|
+
throw localErr;
|
|
387
|
+
}
|
|
98
388
|
console.debug(`Could not load local bundle for ${pkg.name}`, localErr);
|
|
99
389
|
}
|
|
100
390
|
}
|
|
@@ -117,40 +407,100 @@ class PackageLoader {
|
|
|
117
407
|
}
|
|
118
408
|
/**
|
|
119
409
|
* Post-correction: if the package definition carries a version string,
|
|
120
|
-
* update the
|
|
121
|
-
*
|
|
410
|
+
* update the selected IPackageVersion record to match — but only when that
|
|
411
|
+
* selected version is the mutable `dev` working copy. Never rewrite
|
|
122
412
|
* beta/stable version labels from a local package.json bump.
|
|
123
413
|
*/
|
|
124
|
-
correctPackageVersion(pkg,
|
|
125
|
-
if (!
|
|
126
|
-
|
|
127
|
-
|
|
414
|
+
async correctPackageVersion(pkg, selectedPackageVersion, declaredVersion) {
|
|
415
|
+
if (!selectedPackageVersion ||
|
|
416
|
+
selectedPackageVersion.versionTag !== "dev" ||
|
|
417
|
+
!declaredVersion ||
|
|
418
|
+
selectedPackageVersion.version === declaredVersion) {
|
|
128
419
|
return;
|
|
129
|
-
|
|
130
|
-
|
|
131
|
-
.
|
|
132
|
-
|
|
133
|
-
|
|
134
|
-
|
|
135
|
-
|
|
136
|
-
|
|
137
|
-
|
|
138
|
-
|
|
139
|
-
|
|
140
|
-
|
|
141
|
-
|
|
142
|
-
|
|
143
|
-
|
|
144
|
-
|
|
145
|
-
|
|
146
|
-
|
|
420
|
+
}
|
|
421
|
+
try {
|
|
422
|
+
const packageVersionHash = (0, package_versions_1.computePackageVersionHash)(declaredVersion, selectedPackageVersion.versionTag, selectedPackageVersion.packageBundleFileHash, selectedPackageVersion.routesBundleFileHash, selectedPackageVersion.uiBundleFileHash);
|
|
423
|
+
// Version is part of both the content hash and the author-signed
|
|
424
|
+
// payload — clear any prior author signature so it cannot go stale.
|
|
425
|
+
const { packageAuthorSignature: _staleSig, ...rest } = selectedPackageVersion;
|
|
426
|
+
await (0, package_versions_1.PackageVersions)(this.dataContext).signAndSave({
|
|
427
|
+
...rest,
|
|
428
|
+
version: declaredVersion,
|
|
429
|
+
packageVersionHash,
|
|
430
|
+
});
|
|
431
|
+
selectedPackageVersion.version = declaredVersion;
|
|
432
|
+
selectedPackageVersion.packageVersionHash = packageVersionHash;
|
|
433
|
+
}
|
|
434
|
+
catch (error) {
|
|
435
|
+
console.warn(`[PackageLoader] Failed to correct version for ${pkg.name}:`, error instanceof Error ? error.message : String(error));
|
|
436
|
+
}
|
|
437
|
+
}
|
|
438
|
+
async _loadBundle(pkg, bundleCode, selectedPackageVersion, usingLocalBundle, force) {
|
|
439
|
+
if ((0, isolated_artifact_1.looksLikeIsolatedPackageArtifact)(bundleCode)) {
|
|
440
|
+
try {
|
|
441
|
+
const artifact = (0, isolated_artifact_1.parseIsolatedPackageArtifact)(bundleCode);
|
|
442
|
+
return await this._installIsolated(pkg, artifact, selectedPackageVersion, usingLocalBundle, force);
|
|
147
443
|
}
|
|
148
|
-
|
|
149
|
-
|
|
150
|
-
|
|
151
|
-
}
|
|
444
|
+
catch (err) {
|
|
445
|
+
throw wrapIsolatedArtifactError(err);
|
|
446
|
+
}
|
|
447
|
+
}
|
|
448
|
+
const replacingIsolated = this.isolatedRuntime?.isInstalled(pkg.packageId) ?? false;
|
|
449
|
+
const instance = await this._evaluateBundle(pkg, bundleCode, selectedPackageVersion, force);
|
|
450
|
+
if (!instance) {
|
|
451
|
+
return undefined;
|
|
452
|
+
}
|
|
453
|
+
if (replacingIsolated && this.isolatedRuntime) {
|
|
454
|
+
await this.isolatedRuntime.uninstall(pkg.packageId, {
|
|
455
|
+
preserveRegistry: this.contractInstalledPackages.has(pkg.packageId),
|
|
456
|
+
});
|
|
457
|
+
this.isolatedPackageIds.delete(pkg.packageId);
|
|
458
|
+
}
|
|
459
|
+
return instance;
|
|
460
|
+
}
|
|
461
|
+
async _installIsolated(pkg, artifact, selectedPackageVersion, usingLocalBundle, force) {
|
|
462
|
+
if (artifact.manifest.packageId !== pkg.packageId) {
|
|
463
|
+
throw wrapIsolatedArtifactError(new Error(`Isolated packageId mismatch: artifact has "${artifact.manifest.packageId}" but DB record has "${pkg.packageId}"`));
|
|
464
|
+
}
|
|
465
|
+
if (!selectedPackageVersion) {
|
|
466
|
+
throw wrapIsolatedArtifactError(new Error(`No selected PackageVersion is available for isolated package ${pkg.packageId}`));
|
|
467
|
+
}
|
|
468
|
+
if (artifact.manifest.version !== selectedPackageVersion.version) {
|
|
469
|
+
if (usingLocalBundle && selectedPackageVersion.versionTag === "dev") {
|
|
470
|
+
await this.correctPackageVersion(pkg, selectedPackageVersion, artifact.manifest.version);
|
|
471
|
+
if (artifact.manifest.version !== selectedPackageVersion.version) {
|
|
472
|
+
throw wrapIsolatedArtifactError(new Error(`Could not correct selected dev PackageVersion to isolated artifact version "${artifact.manifest.version}"`));
|
|
473
|
+
}
|
|
474
|
+
}
|
|
475
|
+
else {
|
|
476
|
+
throw wrapIsolatedArtifactError(new Error(`Isolated package version mismatch: artifact has "${artifact.manifest.version}" but selected PackageVersion has "${selectedPackageVersion.version}"`));
|
|
477
|
+
}
|
|
478
|
+
}
|
|
479
|
+
if (!this.isolatedRuntime) {
|
|
480
|
+
await this.unloadPackage(pkg.packageId);
|
|
481
|
+
console.warn(`[PackageLoader] Skipping isolated package "${pkg.name}" because this host does not provide an isolated runtime.`);
|
|
482
|
+
return undefined;
|
|
483
|
+
}
|
|
484
|
+
const installOptions = isolatedContractLifecycle(selectedPackageVersion);
|
|
485
|
+
if (this.isolatedRuntime.isInstalled(pkg.packageId)) {
|
|
486
|
+
if (!force) {
|
|
487
|
+
return this.packageInstances[pkg.packageId];
|
|
488
|
+
}
|
|
489
|
+
await this.isolatedRuntime.replace(artifact, installOptions);
|
|
490
|
+
}
|
|
491
|
+
else {
|
|
492
|
+
await this.isolatedRuntime.install(artifact, installOptions);
|
|
493
|
+
}
|
|
494
|
+
this.isolatedPackageIds.add(pkg.packageId);
|
|
495
|
+
this.contractInstalledPackages.add(pkg.packageId);
|
|
496
|
+
const instance = {
|
|
497
|
+
packageId: artifact.manifest.packageId,
|
|
498
|
+
appNavs: artifact.manifest.appNavs,
|
|
499
|
+
};
|
|
500
|
+
this.packageInstances[pkg.packageId] = instance;
|
|
501
|
+
return instance;
|
|
152
502
|
}
|
|
153
|
-
async _evaluateBundle(pkg, bundleCode) {
|
|
503
|
+
async _evaluateBundle(pkg, bundleCode, selectedPackageVersion, force) {
|
|
154
504
|
// Node.js built-in modules that do not exist in React Native (and would cause
|
|
155
505
|
// a fatal native error if passed through to RN's require). We block them here
|
|
156
506
|
// and throw a descriptive JS Error instead, which the surrounding try/catch
|
|
@@ -187,14 +537,16 @@ class PackageLoader {
|
|
|
187
537
|
const moduleExports = {};
|
|
188
538
|
const module = { exports: moduleExports };
|
|
189
539
|
const customRequire = (moduleId) => {
|
|
190
|
-
const _require =
|
|
540
|
+
const _require = this.require ??
|
|
541
|
+
defaultRequire ??
|
|
542
|
+
(typeof require === "function" ? require : undefined);
|
|
191
543
|
if (!_require) {
|
|
192
544
|
throw new Error("You must set the `require` function in package loader before loading a package");
|
|
193
545
|
}
|
|
194
546
|
switch (moduleId) {
|
|
195
547
|
case "peers-sdk":
|
|
196
548
|
case "PeersSDK":
|
|
197
|
-
return PackageLoader.PeersSDK || _require("
|
|
549
|
+
return PackageLoader.PeersSDK || _require("@peers-app/peers-sdk");
|
|
198
550
|
case "zod":
|
|
199
551
|
return PackageLoader.Zod || _require("zod");
|
|
200
552
|
default:
|
|
@@ -221,12 +573,12 @@ class PackageLoader {
|
|
|
221
573
|
if (packageDefinition.packageId !== pkg.packageId) {
|
|
222
574
|
console.warn(`[PackageLoader] packageId mismatch: definition has "${packageDefinition.packageId}" but DB record has "${pkg.packageId}"`);
|
|
223
575
|
}
|
|
576
|
+
await (0, resolve_consumed_contracts_1.resolveConsumedContracts)(this.dataContext, this.contractRegistry, packageDefinition);
|
|
224
577
|
await (0, contract_package_loader_1.installContractPackage)(this.dataContext, packageDefinition, {
|
|
225
578
|
registry: this.contractRegistry,
|
|
226
579
|
});
|
|
227
|
-
await (0, resolve_consumed_contracts_1.resolveConsumedContracts)(this.dataContext, this.contractRegistry, packageDefinition);
|
|
228
580
|
this.contractInstalledPackages.add(packageDefinition.packageId);
|
|
229
|
-
this.correctPackageVersion(pkg, packageDefinition);
|
|
581
|
+
await this.correctPackageVersion(pkg, selectedPackageVersion, packageDefinition.version);
|
|
230
582
|
// Build a proper IPeersPackage from the contract definition so callers
|
|
231
583
|
// (e.g. package-installer) can read appNavs, assistants, etc.
|
|
232
584
|
const contractPackageInstance = {
|
|
@@ -241,7 +593,6 @@ class PackageLoader {
|
|
|
241
593
|
}
|
|
242
594
|
// Legacy path: extract IPeersPackage for backward compat
|
|
243
595
|
const packageInstance = bundleExports?.exports || bundleExports?.package || bundleExports?.default || bundleExports;
|
|
244
|
-
this.packageInstances[pkg.packageId] = packageInstance;
|
|
245
596
|
if (packageInstance && typeof packageInstance === "object") {
|
|
246
597
|
packageInstance.toolInstances?.forEach((toolInstance) => {
|
|
247
598
|
(0, tools_2.registerTool)(toolInstance);
|
|
@@ -252,6 +603,11 @@ class PackageLoader {
|
|
|
252
603
|
overwrite: true,
|
|
253
604
|
});
|
|
254
605
|
});
|
|
606
|
+
if (force && this.contractInstalledPackages.has(pkg.packageId)) {
|
|
607
|
+
this.contractRegistry.unregister(pkg.packageId);
|
|
608
|
+
this.contractInstalledPackages.delete(pkg.packageId);
|
|
609
|
+
}
|
|
610
|
+
this.packageInstances[pkg.packageId] = packageInstance;
|
|
255
611
|
return packageInstance;
|
|
256
612
|
}
|
|
257
613
|
return;
|
|
@@ -263,7 +619,22 @@ class PackageLoader {
|
|
|
263
619
|
}
|
|
264
620
|
}
|
|
265
621
|
exports.PackageLoader = PackageLoader;
|
|
622
|
+
const ISOLATED_ARTIFACT_ERROR = "IsolatedPackageArtifactError";
|
|
623
|
+
function wrapIsolatedArtifactError(err) {
|
|
624
|
+
const error = err instanceof Error ? err : new Error(String(err));
|
|
625
|
+
error.name = ISOLATED_ARTIFACT_ERROR;
|
|
626
|
+
return error;
|
|
627
|
+
}
|
|
628
|
+
function isIsolatedArtifactError(err) {
|
|
629
|
+
return err instanceof Error && err.name === ISOLATED_ARTIFACT_ERROR;
|
|
630
|
+
}
|
|
266
631
|
let defaultRequire;
|
|
632
|
+
/**
|
|
633
|
+
* Set the process-wide `require` used when a {@link PackageLoader} instance
|
|
634
|
+
* does not supply its own.
|
|
635
|
+
*
|
|
636
|
+
* @param require - Host `require` function.
|
|
637
|
+
*/
|
|
267
638
|
function setDefaultRequire(require) {
|
|
268
639
|
defaultRequire = require;
|
|
269
640
|
}
|