@peers-app/peers-sdk 0.21.0 → 0.21.2
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dist/context/user-context.d.ts +10 -3
- package/dist/context/user-context.js +12 -12
- package/dist/contracts/__tests__/builder.test.js +158 -4
- package/dist/contracts/__tests__/registry.test.js +45 -303
- package/dist/contracts/__tests__/system-contracts.test.d.ts +1 -0
- package/dist/contracts/__tests__/system-contracts.test.js +52 -0
- package/dist/contracts/builder.d.ts +43 -2
- package/dist/contracts/builder.js +79 -5
- package/dist/contracts/contract-proxy.d.ts +61 -21
- package/dist/contracts/create-local-consumer.d.ts +12 -0
- package/dist/contracts/create-local-consumer.js +19 -0
- package/dist/contracts/index.d.ts +5 -3
- package/dist/contracts/index.js +8 -1
- package/dist/contracts/registry.d.ts +17 -0
- package/dist/contracts/registry.js +36 -0
- package/dist/contracts/system/device-operations-contract.js +7 -0
- package/dist/contracts/system/index.d.ts +8 -0
- package/dist/contracts/system/index.js +22 -0
- package/dist/contracts/system/logs-contract.d.ts +18 -1
- package/dist/contracts/system/logs-contract.js +8 -2
- package/dist/contracts/system-contracts.d.ts +47 -0
- package/dist/contracts/system-contracts.js +69 -0
- package/dist/contracts/types.d.ts +44 -0
- package/dist/package-installer/index.d.ts +1 -0
- package/dist/package-installer/index.js +1 -0
- package/dist/package-installer/package-author-signer.d.ts +25 -0
- package/dist/package-installer/package-author-signer.js +57 -0
- package/dist/package-installer/package-installer.d.ts +27 -0
- package/dist/package-installer/package-installer.js +88 -18
- package/dist/package-installer/package-installer.test.js +49 -0
- package/dist/package-installer/types.d.ts +1 -1
- package/dist/package-loader/contract-package-loader.test.d.ts +1 -0
- package/dist/package-loader/contract-package-loader.test.js +88 -0
- package/dist/package-loader/package-loader.d.ts +11 -3
- package/dist/package-loader/package-loader.js +31 -5
- package/dist/package-loader/package-loader.test.d.ts +1 -0
- package/dist/package-loader/package-loader.test.js +98 -0
- package/dist/package-loader/resolve-consumed-contracts.d.ts +13 -0
- package/dist/package-loader/resolve-consumed-contracts.js +55 -0
- package/dist/package-loader/resolve-consumed-contracts.test.d.ts +1 -0
- package/dist/package-loader/resolve-consumed-contracts.test.js +123 -0
- package/dist/rpc-types.d.ts +6 -0
- package/dist/rpc-types.js +2 -0
- package/package.json +1 -1
|
@@ -2,6 +2,8 @@
|
|
|
2
2
|
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
3
|
exports.PackageLoader = void 0;
|
|
4
4
|
exports.setDefaultRequire = setDefaultRequire;
|
|
5
|
+
const registry_1 = require("../contracts/registry");
|
|
6
|
+
const system_contracts_1 = require("../contracts/system-contracts");
|
|
5
7
|
const files_1 = require("../data/files");
|
|
6
8
|
const package_version_resolver_1 = require("../data/package-version-resolver");
|
|
7
9
|
const package_versions_1 = require("../data/package-versions");
|
|
@@ -9,6 +11,9 @@ const packages_1 = require("../data/packages");
|
|
|
9
11
|
const tools_1 = require("../data/tools");
|
|
10
12
|
const tools_2 = require("../tools");
|
|
11
13
|
const contract_package_loader_1 = require("./contract-package-loader");
|
|
14
|
+
const resolve_consumed_contracts_1 = require("./resolve-consumed-contracts");
|
|
15
|
+
// Ensure built-in system contracts are cataloged before any PackageLoader installs them.
|
|
16
|
+
require("../contracts/system");
|
|
12
17
|
class PackageLoader {
|
|
13
18
|
dataContext;
|
|
14
19
|
static PeersSDK;
|
|
@@ -16,9 +21,17 @@ class PackageLoader {
|
|
|
16
21
|
packageInstances = {};
|
|
17
22
|
/** Packages that were installed via the contract-based path (tools/assistants/tables already saved with packageId). */
|
|
18
23
|
contractInstalledPackages = new Set();
|
|
24
|
+
/**
|
|
25
|
+
* In-memory contract providers for this data context. Seeded with system
|
|
26
|
+
* contracts at construction; package providers are added via
|
|
27
|
+
* {@link installContractPackage}.
|
|
28
|
+
*/
|
|
29
|
+
contractRegistry;
|
|
19
30
|
require = undefined;
|
|
20
31
|
constructor(dataContext) {
|
|
21
32
|
this.dataContext = dataContext;
|
|
33
|
+
this.contractRegistry = new registry_1.ContractRegistry();
|
|
34
|
+
(0, system_contracts_1.installSystemContracts)(this.contractRegistry);
|
|
22
35
|
}
|
|
23
36
|
/** Returns true if a package was installed via the contract-based definePackage() path. */
|
|
24
37
|
isContractInstalled(packageId) {
|
|
@@ -104,9 +117,9 @@ class PackageLoader {
|
|
|
104
117
|
}
|
|
105
118
|
/**
|
|
106
119
|
* Post-correction: if the package definition carries a version string,
|
|
107
|
-
* update the active IPackageVersion record to match
|
|
108
|
-
*
|
|
109
|
-
*
|
|
120
|
+
* update the active IPackageVersion record to match — but only when that
|
|
121
|
+
* active version is the mutable `dev` working copy. Never rewrite
|
|
122
|
+
* beta/stable version labels from a local package.json bump.
|
|
110
123
|
*/
|
|
111
124
|
correctPackageVersion(pkg, def) {
|
|
112
125
|
if (!pkg.activePackageVersionId)
|
|
@@ -119,8 +132,18 @@ class PackageLoader {
|
|
|
119
132
|
.then((pv) => {
|
|
120
133
|
if (!pv)
|
|
121
134
|
return;
|
|
135
|
+
if (pv.versionTag !== "dev")
|
|
136
|
+
return;
|
|
122
137
|
if (def.version && pv.version !== def.version) {
|
|
123
|
-
|
|
138
|
+
const packageVersionHash = (0, package_versions_1.computePackageVersionHash)(def.version, pv.versionTag || "dev", pv.packageBundleFileHash, pv.routesBundleFileHash, pv.uiBundleFileHash);
|
|
139
|
+
// Version is part of both the content hash and the author-signed
|
|
140
|
+
// payload — clear any prior author signature so it cannot go stale.
|
|
141
|
+
const { packageAuthorSignature: _staleSig, ...rest } = pv;
|
|
142
|
+
return pvTable.signAndSave({
|
|
143
|
+
...rest,
|
|
144
|
+
version: def.version,
|
|
145
|
+
packageVersionHash,
|
|
146
|
+
});
|
|
124
147
|
}
|
|
125
148
|
})
|
|
126
149
|
.catch((err) => {
|
|
@@ -198,7 +221,10 @@ class PackageLoader {
|
|
|
198
221
|
if (packageDefinition.packageId !== pkg.packageId) {
|
|
199
222
|
console.warn(`[PackageLoader] packageId mismatch: definition has "${packageDefinition.packageId}" but DB record has "${pkg.packageId}"`);
|
|
200
223
|
}
|
|
201
|
-
await (0, contract_package_loader_1.installContractPackage)(this.dataContext, packageDefinition
|
|
224
|
+
await (0, contract_package_loader_1.installContractPackage)(this.dataContext, packageDefinition, {
|
|
225
|
+
registry: this.contractRegistry,
|
|
226
|
+
});
|
|
227
|
+
await (0, resolve_consumed_contracts_1.resolveConsumedContracts)(this.dataContext, this.contractRegistry, packageDefinition);
|
|
202
228
|
this.contractInstalledPackages.add(packageDefinition.packageId);
|
|
203
229
|
this.correctPackageVersion(pkg, packageDefinition);
|
|
204
230
|
// Build a proper IPeersPackage from the contract definition so callers
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
export {};
|
|
@@ -0,0 +1,98 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
+
const mockGet = jest.fn();
|
|
4
|
+
const mockSignAndSave = jest.fn();
|
|
5
|
+
const mockComputePackageVersionHash = jest.fn((version, _tag, packageBundleFileHash, _routesBundleFileHash, _uiBundleFileHash) => `hash-${version}-${packageBundleFileHash}`);
|
|
6
|
+
jest.mock("../data/package-versions", () => ({
|
|
7
|
+
PackageVersions: () => ({
|
|
8
|
+
get: (...args) => mockGet(...args),
|
|
9
|
+
signAndSave: (...args) => mockSignAndSave(...args),
|
|
10
|
+
}),
|
|
11
|
+
computePackageVersionHash: (version, versionTag, packageBundleFileHash, routesBundleFileHash, uiBundleFileHash) => mockComputePackageVersionHash(version, versionTag, packageBundleFileHash, routesBundleFileHash, uiBundleFileHash),
|
|
12
|
+
}));
|
|
13
|
+
const registry_1 = require("../contracts/registry");
|
|
14
|
+
const system_ids_1 = require("../system-ids");
|
|
15
|
+
const package_loader_1 = require("./package-loader");
|
|
16
|
+
describe("PackageLoader.correctPackageVersion", () => {
|
|
17
|
+
const activePvId = "pv-active";
|
|
18
|
+
const pkg = {
|
|
19
|
+
packageId: "pkg-1",
|
|
20
|
+
name: "Test Package",
|
|
21
|
+
activePackageVersionId: activePvId,
|
|
22
|
+
};
|
|
23
|
+
const def = { version: "0.3.6" };
|
|
24
|
+
let loader;
|
|
25
|
+
beforeEach(() => {
|
|
26
|
+
jest.clearAllMocks();
|
|
27
|
+
mockSignAndSave.mockResolvedValue(undefined);
|
|
28
|
+
loader = new package_loader_1.PackageLoader({ dataContextId: "ctx" });
|
|
29
|
+
});
|
|
30
|
+
async function correctPackageVersion() {
|
|
31
|
+
loader.correctPackageVersion(pkg, def);
|
|
32
|
+
// Flush the fire-and-forget promise chain
|
|
33
|
+
await new Promise((r) => setImmediate(r));
|
|
34
|
+
}
|
|
35
|
+
it("updates the active PV hash and clears a stale author signature", async () => {
|
|
36
|
+
mockGet.mockResolvedValue({
|
|
37
|
+
packageVersionId: activePvId,
|
|
38
|
+
version: "0.3.1",
|
|
39
|
+
versionTag: "dev",
|
|
40
|
+
packageBundleFileHash: "bundle-hash",
|
|
41
|
+
routesBundleFileHash: "routes-hash",
|
|
42
|
+
uiBundleFileHash: "ui-hash",
|
|
43
|
+
packageAuthorSignature: "stale-sig",
|
|
44
|
+
packageVersionHash: "old-hash",
|
|
45
|
+
});
|
|
46
|
+
await correctPackageVersion();
|
|
47
|
+
expect(mockComputePackageVersionHash).toHaveBeenCalledWith("0.3.6", "dev", "bundle-hash", "routes-hash", "ui-hash");
|
|
48
|
+
expect(mockSignAndSave).toHaveBeenCalledWith(expect.objectContaining({
|
|
49
|
+
packageVersionId: activePvId,
|
|
50
|
+
version: "0.3.6",
|
|
51
|
+
versionTag: "dev",
|
|
52
|
+
packageVersionHash: "hash-0.3.6-bundle-hash",
|
|
53
|
+
}));
|
|
54
|
+
expect(mockSignAndSave.mock.calls[0][0].packageAuthorSignature).toBeUndefined();
|
|
55
|
+
});
|
|
56
|
+
it("does not update the active PV when it is stable", async () => {
|
|
57
|
+
mockGet.mockResolvedValue({
|
|
58
|
+
packageVersionId: activePvId,
|
|
59
|
+
version: "0.3.5",
|
|
60
|
+
versionTag: "stable",
|
|
61
|
+
});
|
|
62
|
+
await correctPackageVersion();
|
|
63
|
+
expect(mockSignAndSave).not.toHaveBeenCalled();
|
|
64
|
+
});
|
|
65
|
+
it("does not update the active PV when it is beta", async () => {
|
|
66
|
+
mockGet.mockResolvedValue({
|
|
67
|
+
packageVersionId: activePvId,
|
|
68
|
+
version: "0.3.5",
|
|
69
|
+
versionTag: "beta",
|
|
70
|
+
});
|
|
71
|
+
await correctPackageVersion();
|
|
72
|
+
expect(mockSignAndSave).not.toHaveBeenCalled();
|
|
73
|
+
});
|
|
74
|
+
it("does nothing when the active PV version already matches", async () => {
|
|
75
|
+
mockGet.mockResolvedValue({
|
|
76
|
+
packageVersionId: activePvId,
|
|
77
|
+
version: "0.3.6",
|
|
78
|
+
versionTag: "dev",
|
|
79
|
+
});
|
|
80
|
+
await correctPackageVersion();
|
|
81
|
+
expect(mockSignAndSave).not.toHaveBeenCalled();
|
|
82
|
+
});
|
|
83
|
+
});
|
|
84
|
+
describe("PackageLoader.contractRegistry", () => {
|
|
85
|
+
it("owns an in-memory ContractRegistry per loader instance", () => {
|
|
86
|
+
const loaderA = new package_loader_1.PackageLoader({ dataContextId: "ctx-a" });
|
|
87
|
+
const loaderB = new package_loader_1.PackageLoader({ dataContextId: "ctx-b" });
|
|
88
|
+
expect(loaderA.contractRegistry).toBeInstanceOf(registry_1.ContractRegistry);
|
|
89
|
+
expect(loaderB.contractRegistry).toBeInstanceOf(registry_1.ContractRegistry);
|
|
90
|
+
expect(loaderA.contractRegistry).not.toBe(loaderB.contractRegistry);
|
|
91
|
+
});
|
|
92
|
+
it("installs system contracts into each new registry", () => {
|
|
93
|
+
const loader = new package_loader_1.PackageLoader({ dataContextId: "ctx-system" });
|
|
94
|
+
expect(loader.contractRegistry.getProviderPackageId(system_ids_1.logsContractId, 1)).toBe(system_ids_1.peersSystemPackageId);
|
|
95
|
+
expect(loader.contractRegistry.resolve(system_ids_1.logsContractId, 1)?.name).toBe("System Logs");
|
|
96
|
+
expect(loader.contractRegistry.getProviderPackageId(system_ids_1.deviceOperationsContractId, 1)).toBe(system_ids_1.peersSystemPackageId);
|
|
97
|
+
});
|
|
98
|
+
});
|
|
@@ -0,0 +1,13 @@
|
|
|
1
|
+
import type { DataContext } from "../context/data-context";
|
|
2
|
+
import type { ContractRegistry } from "../contracts/registry";
|
|
3
|
+
import type { IPackageDefinitionResult } from "../contracts/types";
|
|
4
|
+
/**
|
|
5
|
+
* Settle each deferred `consumes` handle on a package definition after its
|
|
6
|
+
* providers have been registered.
|
|
7
|
+
*
|
|
8
|
+
* A consume succeeds only when {@link ContractRegistry.selectProvider} finds a
|
|
9
|
+
* matching provider **and** a live {@link getContractResolver|ContractResolver}
|
|
10
|
+
* exists for that contract version. Missing optional deps settle to `undefined`;
|
|
11
|
+
* missing required deps reject the handle.
|
|
12
|
+
*/
|
|
13
|
+
export declare function resolveConsumedContracts(dataContext: DataContext, registry: ContractRegistry, packageDefinition: IPackageDefinitionResult): Promise<void>;
|
|
@@ -0,0 +1,55 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
+
exports.resolveConsumedContracts = resolveConsumedContracts;
|
|
4
|
+
const builder_1 = require("../contracts/builder");
|
|
5
|
+
const contract_resolvers_1 = require("../contracts/contract-resolvers");
|
|
6
|
+
const create_local_consumer_1 = require("../contracts/create-local-consumer");
|
|
7
|
+
/**
|
|
8
|
+
* Settle each deferred `consumes` handle on a package definition after its
|
|
9
|
+
* providers have been registered.
|
|
10
|
+
*
|
|
11
|
+
* A consume succeeds only when {@link ContractRegistry.selectProvider} finds a
|
|
12
|
+
* matching provider **and** a live {@link getContractResolver|ContractResolver}
|
|
13
|
+
* exists for that contract version. Missing optional deps settle to `undefined`;
|
|
14
|
+
* missing required deps reject the handle.
|
|
15
|
+
*/
|
|
16
|
+
async function resolveConsumedContracts(dataContext, registry, packageDefinition) {
|
|
17
|
+
for (const dep of packageDefinition.consumes) {
|
|
18
|
+
const handle = dep.handle;
|
|
19
|
+
if (!handle) {
|
|
20
|
+
continue;
|
|
21
|
+
}
|
|
22
|
+
try {
|
|
23
|
+
const selected = registry.selectProvider(dep);
|
|
24
|
+
if (!selected) {
|
|
25
|
+
settleMissing(dep.optional === true, handle, dep.contractId, dep.version, "no matching provider");
|
|
26
|
+
continue;
|
|
27
|
+
}
|
|
28
|
+
const resolver = (0, contract_resolvers_1.getContractResolver)(dep.contractId, dep.version);
|
|
29
|
+
if (!resolver) {
|
|
30
|
+
settleMissing(dep.optional === true, handle, dep.contractId, dep.version, `provider ${selected.providerPackageId} has no live resolver`);
|
|
31
|
+
continue;
|
|
32
|
+
}
|
|
33
|
+
const resolution = await resolver({ dataContext });
|
|
34
|
+
const consumer = (0, create_local_consumer_1.createLocalContractConsumer)(selected.definition, resolution, {
|
|
35
|
+
dataContextId: dataContext.dataContextId,
|
|
36
|
+
});
|
|
37
|
+
(0, builder_1.settleConsumedContractHandle)(handle, consumer);
|
|
38
|
+
}
|
|
39
|
+
catch (err) {
|
|
40
|
+
if (dep.optional === true) {
|
|
41
|
+
(0, builder_1.settleConsumedContractHandle)(handle, undefined);
|
|
42
|
+
}
|
|
43
|
+
else {
|
|
44
|
+
(0, builder_1.rejectConsumedContractHandle)(handle, err);
|
|
45
|
+
}
|
|
46
|
+
}
|
|
47
|
+
}
|
|
48
|
+
}
|
|
49
|
+
function settleMissing(optional, handle, contractId, version, reason) {
|
|
50
|
+
if (optional) {
|
|
51
|
+
(0, builder_1.settleConsumedContractHandle)(handle, undefined);
|
|
52
|
+
return;
|
|
53
|
+
}
|
|
54
|
+
(0, builder_1.rejectConsumedContractHandle)(handle, new Error(`Required contract ${contractId}@${version} could not be resolved: ${reason}`));
|
|
55
|
+
}
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
export {};
|
|
@@ -0,0 +1,123 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
+
const builder_1 = require("../contracts/builder");
|
|
4
|
+
const contract_resolvers_1 = require("../contracts/contract-resolvers");
|
|
5
|
+
const registry_1 = require("../contracts/registry");
|
|
6
|
+
const utils_1 = require("../utils");
|
|
7
|
+
const resolve_consumed_contracts_1 = require("./resolve-consumed-contracts");
|
|
8
|
+
describe("resolveConsumedContracts", () => {
|
|
9
|
+
const contractId = (0, utils_1.newid)();
|
|
10
|
+
const providerPackageId = (0, utils_1.newid)();
|
|
11
|
+
function mockDataContext() {
|
|
12
|
+
return { dataContextId: "test-ctx" };
|
|
13
|
+
}
|
|
14
|
+
function makeProvidingRegistry() {
|
|
15
|
+
const registry = new registry_1.ContractRegistry();
|
|
16
|
+
registry.register(providerPackageId, {
|
|
17
|
+
contractId,
|
|
18
|
+
version: 1,
|
|
19
|
+
devTag: "dev",
|
|
20
|
+
name: "Fake Contract",
|
|
21
|
+
description: "test",
|
|
22
|
+
tables: [
|
|
23
|
+
{
|
|
24
|
+
name: "Items",
|
|
25
|
+
description: "Items table",
|
|
26
|
+
primaryKeyName: "itemId",
|
|
27
|
+
fields: [],
|
|
28
|
+
},
|
|
29
|
+
],
|
|
30
|
+
tools: [],
|
|
31
|
+
observables: [],
|
|
32
|
+
events: [],
|
|
33
|
+
});
|
|
34
|
+
return registry;
|
|
35
|
+
}
|
|
36
|
+
beforeEach(() => {
|
|
37
|
+
const resolution = {
|
|
38
|
+
contractId,
|
|
39
|
+
version: 1,
|
|
40
|
+
tables: {
|
|
41
|
+
Items: {
|
|
42
|
+
list: jest.fn().mockResolvedValue([{ itemId: "1" }]),
|
|
43
|
+
count: jest.fn().mockResolvedValue(1),
|
|
44
|
+
},
|
|
45
|
+
},
|
|
46
|
+
};
|
|
47
|
+
(0, contract_resolvers_1.registerContractResolver)(contractId, 1, () => resolution);
|
|
48
|
+
});
|
|
49
|
+
it("settles a required consume with a live local consumer proxy", async () => {
|
|
50
|
+
const registry = makeProvidingRegistry();
|
|
51
|
+
let consumeHandle;
|
|
52
|
+
const packageDefinition = (0, builder_1.definePackage)((pkg) => {
|
|
53
|
+
pkg.packageId = (0, utils_1.newid)();
|
|
54
|
+
pkg.version = "1.0.0";
|
|
55
|
+
consumeHandle = pkg.consumes(contractId, 1);
|
|
56
|
+
});
|
|
57
|
+
await (0, resolve_consumed_contracts_1.resolveConsumedContracts)(mockDataContext(), registry, packageDefinition);
|
|
58
|
+
if (!consumeHandle) {
|
|
59
|
+
throw new Error("expected consume handle");
|
|
60
|
+
}
|
|
61
|
+
const consumer = (await consumeHandle.consumer);
|
|
62
|
+
expect(consumer).toBeDefined();
|
|
63
|
+
expect(consumer?.contractId).toBe(contractId);
|
|
64
|
+
expect(consumer?.version).toBe(1);
|
|
65
|
+
await expect(consumer?.tables.Items.list()).resolves.toEqual([{ itemId: "1" }]);
|
|
66
|
+
await expect(consumer?.tables.Items.count()).resolves.toBe(1);
|
|
67
|
+
});
|
|
68
|
+
it("settles optional missing consumes to undefined", async () => {
|
|
69
|
+
const registry = new registry_1.ContractRegistry();
|
|
70
|
+
let consumeHandle;
|
|
71
|
+
const packageDefinition = (0, builder_1.definePackage)((pkg) => {
|
|
72
|
+
pkg.packageId = (0, utils_1.newid)();
|
|
73
|
+
pkg.version = "1.0.0";
|
|
74
|
+
consumeHandle = pkg.consumes(contractId, 1, { optional: true });
|
|
75
|
+
});
|
|
76
|
+
await (0, resolve_consumed_contracts_1.resolveConsumedContracts)(mockDataContext(), registry, packageDefinition);
|
|
77
|
+
if (!consumeHandle) {
|
|
78
|
+
throw new Error("expected consume handle");
|
|
79
|
+
}
|
|
80
|
+
await expect(consumeHandle.consumer).resolves.toBeUndefined();
|
|
81
|
+
});
|
|
82
|
+
it("rejects required consumes when no provider is available", async () => {
|
|
83
|
+
const registry = new registry_1.ContractRegistry();
|
|
84
|
+
let consumeHandle;
|
|
85
|
+
const packageDefinition = (0, builder_1.definePackage)((pkg) => {
|
|
86
|
+
pkg.packageId = (0, utils_1.newid)();
|
|
87
|
+
pkg.version = "1.0.0";
|
|
88
|
+
consumeHandle = pkg.consumes(contractId, 1);
|
|
89
|
+
});
|
|
90
|
+
await (0, resolve_consumed_contracts_1.resolveConsumedContracts)(mockDataContext(), registry, packageDefinition);
|
|
91
|
+
if (!consumeHandle) {
|
|
92
|
+
throw new Error("expected consume handle");
|
|
93
|
+
}
|
|
94
|
+
await expect(consumeHandle.consumer).rejects.toThrow(/could not be resolved/);
|
|
95
|
+
});
|
|
96
|
+
it("treats a registered provider without a live resolver as missing", async () => {
|
|
97
|
+
const noResolverContractId = (0, utils_1.newid)();
|
|
98
|
+
const registry = new registry_1.ContractRegistry();
|
|
99
|
+
registry.register(providerPackageId, {
|
|
100
|
+
contractId: noResolverContractId,
|
|
101
|
+
version: 1,
|
|
102
|
+
devTag: "dev",
|
|
103
|
+
name: "No Resolver",
|
|
104
|
+
description: "test",
|
|
105
|
+
tables: [],
|
|
106
|
+
tools: [],
|
|
107
|
+
observables: [],
|
|
108
|
+
events: [],
|
|
109
|
+
});
|
|
110
|
+
expect((0, contract_resolvers_1.getContractResolver)(noResolverContractId, 1)).toBeUndefined();
|
|
111
|
+
let consumeHandle;
|
|
112
|
+
const packageDefinition = (0, builder_1.definePackage)((pkg) => {
|
|
113
|
+
pkg.packageId = (0, utils_1.newid)();
|
|
114
|
+
pkg.version = "1.0.0";
|
|
115
|
+
consumeHandle = pkg.consumes(noResolverContractId, 1, { optional: true });
|
|
116
|
+
});
|
|
117
|
+
await (0, resolve_consumed_contracts_1.resolveConsumedContracts)(mockDataContext(), registry, packageDefinition);
|
|
118
|
+
if (!consumeHandle) {
|
|
119
|
+
throw new Error("expected consume handle");
|
|
120
|
+
}
|
|
121
|
+
await expect(consumeHandle.consumer).resolves.toBeUndefined();
|
|
122
|
+
});
|
|
123
|
+
});
|
package/dist/rpc-types.d.ts
CHANGED
|
@@ -2,6 +2,7 @@ import type { IDeviceDatabaseQueryResult, IDeviceOperationStatus, IDeviceToolRun
|
|
|
2
2
|
import type { ITool } from "./data/tools";
|
|
3
3
|
import type { DevicePairingCeremonyAction, DevicePairingStartDestinationInput, DevicePairingStartSourceResult, DevicePairingState } from "./device-pairing";
|
|
4
4
|
import type { IConsoleLog } from "./logging/console-logs.table";
|
|
5
|
+
import type { IAppNav } from "./types/app-nav";
|
|
5
6
|
/** Named event payload sent across the frontend RPC bridge. */
|
|
6
7
|
export interface IEventData<T = any> {
|
|
7
8
|
name: string;
|
|
@@ -115,6 +116,8 @@ export declare const rpcServerCalls: {
|
|
|
115
116
|
/**
|
|
116
117
|
* Sign a package version with the package author's key (server-side only — key never leaves the server).
|
|
117
118
|
* Returns the base64url detached signature, or undefined if the signing key isn't available.
|
|
119
|
+
* Optional fields (appNavs, createdBy, createdAt) must match the PV record when present so
|
|
120
|
+
* propagation verification of the full record succeeds.
|
|
118
121
|
*/
|
|
119
122
|
signPackageAuthorVersion: (pvFields: {
|
|
120
123
|
packageId: string;
|
|
@@ -124,6 +127,9 @@ export declare const rpcServerCalls: {
|
|
|
124
127
|
packageBundleFileHash: string;
|
|
125
128
|
routesBundleFileHash?: string;
|
|
126
129
|
uiBundleFileHash?: string;
|
|
130
|
+
appNavs?: IAppNav[];
|
|
131
|
+
createdBy?: string;
|
|
132
|
+
createdAt?: string;
|
|
127
133
|
}) => Promise<string | undefined>;
|
|
128
134
|
registerWithPeersServices: () => Promise<string>;
|
|
129
135
|
appQuit: () => Promise<void>;
|
package/dist/rpc-types.js
CHANGED
|
@@ -58,6 +58,8 @@ exports.rpcServerCalls = {
|
|
|
58
58
|
/**
|
|
59
59
|
* Sign a package version with the package author's key (server-side only — key never leaves the server).
|
|
60
60
|
* Returns the base64url detached signature, or undefined if the signing key isn't available.
|
|
61
|
+
* Optional fields (appNavs, createdBy, createdAt) must match the PV record when present so
|
|
62
|
+
* propagation verification of the full record succeeds.
|
|
61
63
|
*/
|
|
62
64
|
signPackageAuthorVersion: rpcStub("signPackageAuthorVersion"),
|
|
63
65
|
registerWithPeersServices: rpcStub("registerWithPeersServices"),
|