@peers-app/peers-sdk 0.21.1 → 0.21.3
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__/contract-resolvers.test.js +94 -0
- package/dist/contracts/__tests__/host-contract-transport.test.d.ts +1 -0
- package/dist/contracts/__tests__/host-contract-transport.test.js +51 -0
- 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 +61 -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/contract-resolvers.d.ts +20 -0
- package/dist/contracts/contract-resolvers.js +57 -0
- package/dist/contracts/create-local-consumer.d.ts +12 -0
- package/dist/contracts/create-local-consumer.js +19 -0
- package/dist/contracts/host-contract-transport.d.ts +38 -0
- package/dist/contracts/host-contract-transport.js +107 -0
- package/dist/contracts/index.d.ts +8 -4
- package/dist/contracts/index.js +29 -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 +10 -0
- package/dist/contracts/system/index.js +38 -0
- package/dist/contracts/system/logs-contract.d.ts +18 -1
- package/dist/contracts/system/logs-contract.js +8 -2
- package/dist/contracts/system/network-contracts.d.ts +231 -0
- package/dist/contracts/system/network-contracts.js +192 -0
- 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-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 +8 -0
- package/dist/package-loader/package-loader.js +17 -1
- package/dist/package-loader/package-loader.test.js +17 -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/system-ids.d.ts +4 -0
- package/dist/system-ids.js +5 -1
- package/package.json +1 -1
|
@@ -1,324 +1,66 @@
|
|
|
1
1
|
"use strict";
|
|
2
2
|
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
-
const field_type_1 = require("../../types/field-type");
|
|
4
3
|
const utils_1 = require("../../utils");
|
|
5
4
|
const registry_1 = require("../registry");
|
|
6
|
-
|
|
7
|
-
function makeContract(overrides = {}) {
|
|
5
|
+
function makeDefinition(contractId, version, name = "Test Contract") {
|
|
8
6
|
return {
|
|
9
|
-
contractId
|
|
10
|
-
version
|
|
11
|
-
|
|
12
|
-
|
|
7
|
+
contractId,
|
|
8
|
+
version,
|
|
9
|
+
devTag: "dev",
|
|
10
|
+
name,
|
|
11
|
+
description: "test",
|
|
13
12
|
tables: [],
|
|
14
13
|
tools: [],
|
|
15
14
|
observables: [],
|
|
16
|
-
|
|
15
|
+
events: [],
|
|
17
16
|
};
|
|
18
17
|
}
|
|
19
|
-
describe("ContractRegistry", () => {
|
|
18
|
+
describe("ContractRegistry.selectProvider", () => {
|
|
19
|
+
const contractId = (0, utils_1.newid)();
|
|
20
|
+
const packageA = (0, utils_1.newid)();
|
|
21
|
+
const packageB = (0, utils_1.newid)();
|
|
22
|
+
const packageC = (0, utils_1.newid)();
|
|
20
23
|
let registry;
|
|
21
24
|
beforeEach(() => {
|
|
22
25
|
registry = new registry_1.ContractRegistry();
|
|
26
|
+
registry.register(packageA, makeDefinition(contractId, 1, "A"));
|
|
27
|
+
registry.register(packageB, makeDefinition(contractId, 1, "B"));
|
|
23
28
|
});
|
|
24
|
-
|
|
25
|
-
|
|
26
|
-
const def = makeContract({
|
|
27
|
-
tables: [
|
|
28
|
-
{
|
|
29
|
-
name: "Tasks",
|
|
30
|
-
description: "d",
|
|
31
|
-
primaryKeyName: "taskId",
|
|
32
|
-
fields: [{ name: "taskId", type: field_type_1.FieldType.id }],
|
|
33
|
-
},
|
|
34
|
-
],
|
|
35
|
-
});
|
|
36
|
-
const pkgId = (0, utils_1.newid)();
|
|
37
|
-
const result = registry.register(pkgId, def);
|
|
38
|
-
expect(result.valid).toBe(true);
|
|
39
|
-
const resolved = registry.resolve(DEFAULT_CONTRACT_ID, 1);
|
|
40
|
-
expect(resolved).toBeDefined();
|
|
41
|
-
expect(resolved?.tables[0].name).toBe("Tasks");
|
|
42
|
-
});
|
|
43
|
-
it("returns the provider package ID", () => {
|
|
44
|
-
const def = makeContract();
|
|
45
|
-
const pkgId = (0, utils_1.newid)();
|
|
46
|
-
registry.register(pkgId, def);
|
|
47
|
-
expect(registry.getProviderPackageId(DEFAULT_CONTRACT_ID, 1)).toBe(pkgId);
|
|
48
|
-
});
|
|
49
|
-
it("returns undefined for unregistered contracts", () => {
|
|
50
|
-
const unknownId = (0, utils_1.newid)();
|
|
51
|
-
expect(registry.resolve(unknownId, 1)).toBeUndefined();
|
|
52
|
-
expect(registry.getProviderPackageId(unknownId, 1)).toBeUndefined();
|
|
53
|
-
});
|
|
54
|
-
it("auto-activates the first registered provider", () => {
|
|
55
|
-
const def = makeContract();
|
|
56
|
-
const pkgA = (0, utils_1.newid)();
|
|
57
|
-
registry.register(pkgA, def);
|
|
58
|
-
expect(registry.getProviderPackageId(DEFAULT_CONTRACT_ID, 1)).toBe(pkgA);
|
|
59
|
-
});
|
|
60
|
-
it("does not auto-switch when a second provider is registered", () => {
|
|
61
|
-
const def = makeContract();
|
|
62
|
-
const pkgA = (0, utils_1.newid)();
|
|
63
|
-
const pkgB = (0, utils_1.newid)();
|
|
64
|
-
registry.register(pkgA, def);
|
|
65
|
-
registry.register(pkgB, def);
|
|
66
|
-
expect(registry.getProviderPackageId(DEFAULT_CONTRACT_ID, 1)).toBe(pkgA);
|
|
67
|
-
});
|
|
29
|
+
it("returns registered provider ids in registration order", () => {
|
|
30
|
+
expect(registry.getRegisteredProviderIds(contractId, 1)).toEqual([packageA, packageB]);
|
|
68
31
|
});
|
|
69
|
-
|
|
70
|
-
|
|
71
|
-
|
|
72
|
-
const pkgA = (0, utils_1.newid)();
|
|
73
|
-
const pkgB = (0, utils_1.newid)();
|
|
74
|
-
registry.register(pkgA, def);
|
|
75
|
-
registry.register(pkgB, def);
|
|
76
|
-
const switched = registry.setActiveProvider(DEFAULT_CONTRACT_ID, 1, pkgB);
|
|
77
|
-
expect(switched).toBe(true);
|
|
78
|
-
expect(registry.getProviderPackageId(DEFAULT_CONTRACT_ID, 1)).toBe(pkgB);
|
|
79
|
-
});
|
|
80
|
-
it("returns false if the target package is not registered", () => {
|
|
81
|
-
const def = makeContract();
|
|
82
|
-
const pkgA = (0, utils_1.newid)();
|
|
83
|
-
const unknownPkg = (0, utils_1.newid)();
|
|
84
|
-
registry.register(pkgA, def);
|
|
85
|
-
const switched = registry.setActiveProvider(DEFAULT_CONTRACT_ID, 1, unknownPkg);
|
|
86
|
-
expect(switched).toBe(false);
|
|
87
|
-
expect(registry.getProviderPackageId(DEFAULT_CONTRACT_ID, 1)).toBe(pkgA);
|
|
88
|
-
});
|
|
89
|
-
it("returns false for unknown contracts", () => {
|
|
90
|
-
const unknownId = (0, utils_1.newid)();
|
|
91
|
-
const pkgA = (0, utils_1.newid)();
|
|
92
|
-
expect(registry.setActiveProvider(unknownId, 1, pkgA)).toBe(false);
|
|
93
|
-
});
|
|
32
|
+
it("selects the active provider when no preference is given", () => {
|
|
33
|
+
const selected = registry.selectProvider({ contractId, version: 1 });
|
|
34
|
+
expect(selected?.providerPackageId).toBe(packageA);
|
|
94
35
|
});
|
|
95
|
-
|
|
96
|
-
|
|
97
|
-
|
|
98
|
-
|
|
99
|
-
|
|
100
|
-
|
|
101
|
-
|
|
102
|
-
expect(registry.getProviderPackageId(DEFAULT_CONTRACT_ID, 1)).toBeUndefined();
|
|
103
|
-
});
|
|
104
|
-
it("falls back to next provider when active is removed", () => {
|
|
105
|
-
const def = makeContract();
|
|
106
|
-
const pkgA = (0, utils_1.newid)();
|
|
107
|
-
const pkgB = (0, utils_1.newid)();
|
|
108
|
-
registry.register(pkgA, def);
|
|
109
|
-
registry.register(pkgB, def);
|
|
110
|
-
registry.unregister(pkgA);
|
|
111
|
-
expect(registry.getProviderPackageId(DEFAULT_CONTRACT_ID, 1)).toBe(pkgB);
|
|
112
|
-
});
|
|
113
|
-
it("is a no-op for unknown packages", () => {
|
|
114
|
-
const unknownPkg = (0, utils_1.newid)();
|
|
115
|
-
expect(() => registry.unregister(unknownPkg)).not.toThrow();
|
|
116
|
-
});
|
|
117
|
-
it("handles a package that provides multiple contracts", () => {
|
|
118
|
-
const contractId1 = (0, utils_1.newid)();
|
|
119
|
-
const contractId2 = (0, utils_1.newid)();
|
|
120
|
-
const def1 = makeContract({ contractId: contractId1 });
|
|
121
|
-
const def2 = makeContract({ contractId: contractId2 });
|
|
122
|
-
const pkgA = (0, utils_1.newid)();
|
|
123
|
-
registry.register(pkgA, def1);
|
|
124
|
-
registry.register(pkgA, def2);
|
|
125
|
-
registry.unregister(pkgA);
|
|
126
|
-
expect(registry.resolve(contractId1, 1)).toBeUndefined();
|
|
127
|
-
expect(registry.resolve(contractId2, 1)).toBeUndefined();
|
|
128
|
-
});
|
|
36
|
+
it("selects the first preferred provider that is registered", () => {
|
|
37
|
+
const dep = {
|
|
38
|
+
contractId,
|
|
39
|
+
version: 1,
|
|
40
|
+
providerPackageIds: [packageC, packageB, packageA],
|
|
41
|
+
};
|
|
42
|
+
expect(registry.selectProvider(dep)?.providerPackageId).toBe(packageB);
|
|
129
43
|
});
|
|
130
|
-
|
|
131
|
-
|
|
132
|
-
|
|
133
|
-
|
|
134
|
-
|
|
135
|
-
|
|
136
|
-
|
|
137
|
-
|
|
138
|
-
const result = registry.checkConsumerDependencies([
|
|
139
|
-
{ contractId: tasksId, version: 1 },
|
|
140
|
-
{ contractId: authId, version: 1 },
|
|
141
|
-
]);
|
|
142
|
-
expect(result.satisfied).toHaveLength(2);
|
|
143
|
-
expect(result.missing).toHaveLength(0);
|
|
144
|
-
});
|
|
145
|
-
it("reports missing when no provider exists", () => {
|
|
146
|
-
const tasksId = (0, utils_1.newid)();
|
|
147
|
-
const authId = (0, utils_1.newid)();
|
|
148
|
-
const pkgA = (0, utils_1.newid)();
|
|
149
|
-
registry.register(pkgA, makeContract({ contractId: tasksId }));
|
|
150
|
-
const result = registry.checkConsumerDependencies([
|
|
151
|
-
{ contractId: tasksId, version: 1 },
|
|
152
|
-
{ contractId: authId, version: 1 },
|
|
153
|
-
]);
|
|
154
|
-
expect(result.satisfied).toHaveLength(1);
|
|
155
|
-
expect(result.missing).toHaveLength(1);
|
|
156
|
-
expect(result.missing[0].contractId).toBe(authId);
|
|
157
|
-
});
|
|
158
|
-
it("reports all missing when registry is empty", () => {
|
|
159
|
-
const tasksId = (0, utils_1.newid)();
|
|
160
|
-
const result = registry.checkConsumerDependencies([{ contractId: tasksId, version: 1 }]);
|
|
161
|
-
expect(result.satisfied).toHaveLength(0);
|
|
162
|
-
expect(result.missing).toHaveLength(1);
|
|
163
|
-
});
|
|
164
|
-
it("returns empty lists for empty consumer list", () => {
|
|
165
|
-
const result = registry.checkConsumerDependencies([]);
|
|
166
|
-
expect(result.satisfied).toHaveLength(0);
|
|
167
|
-
expect(result.missing).toHaveLength(0);
|
|
168
|
-
});
|
|
44
|
+
it("falls back to the active provider when preferred are missing and fallback is enabled", () => {
|
|
45
|
+
const dep = {
|
|
46
|
+
contractId,
|
|
47
|
+
version: 1,
|
|
48
|
+
providerPackageIds: [packageC],
|
|
49
|
+
fallbackToDefaultProvider: true,
|
|
50
|
+
};
|
|
51
|
+
expect(registry.selectProvider(dep)?.providerPackageId).toBe(packageA);
|
|
169
52
|
});
|
|
170
|
-
|
|
171
|
-
|
|
172
|
-
|
|
173
|
-
|
|
174
|
-
|
|
175
|
-
|
|
176
|
-
|
|
177
|
-
|
|
178
|
-
fields: [{ name: "id", type: field_type_1.FieldType.id }],
|
|
179
|
-
},
|
|
180
|
-
],
|
|
181
|
-
});
|
|
182
|
-
const pkgA = (0, utils_1.newid)();
|
|
183
|
-
registry.register(pkgA, def1);
|
|
184
|
-
const def2 = makeContract({
|
|
185
|
-
tables: [
|
|
186
|
-
{
|
|
187
|
-
name: "T",
|
|
188
|
-
description: "d",
|
|
189
|
-
primaryKeyName: "id",
|
|
190
|
-
fields: [
|
|
191
|
-
{ name: "id", type: field_type_1.FieldType.id },
|
|
192
|
-
{ name: "extra", type: field_type_1.FieldType.string },
|
|
193
|
-
],
|
|
194
|
-
},
|
|
195
|
-
],
|
|
196
|
-
});
|
|
197
|
-
const pkgB = (0, utils_1.newid)();
|
|
198
|
-
const result = registry.register(pkgB, def2);
|
|
199
|
-
expect(result.valid).toBe(false);
|
|
200
|
-
expect(result.errors[0].message).toContain("frozen");
|
|
201
|
-
});
|
|
202
|
-
it("allows re-registration of a dev contract with a different shape", () => {
|
|
203
|
-
const def1 = makeContract({
|
|
204
|
-
devTag: "dev",
|
|
205
|
-
tables: [
|
|
206
|
-
{
|
|
207
|
-
name: "T",
|
|
208
|
-
description: "d",
|
|
209
|
-
primaryKeyName: "id",
|
|
210
|
-
fields: [{ name: "id", type: field_type_1.FieldType.id }],
|
|
211
|
-
},
|
|
212
|
-
],
|
|
213
|
-
});
|
|
214
|
-
const pkgA = (0, utils_1.newid)();
|
|
215
|
-
registry.register(pkgA, def1);
|
|
216
|
-
const def2 = makeContract({
|
|
217
|
-
devTag: "dev",
|
|
218
|
-
tables: [
|
|
219
|
-
{
|
|
220
|
-
name: "T",
|
|
221
|
-
description: "d",
|
|
222
|
-
primaryKeyName: "id",
|
|
223
|
-
fields: [
|
|
224
|
-
{ name: "id", type: field_type_1.FieldType.id },
|
|
225
|
-
{ name: "extra", type: field_type_1.FieldType.string },
|
|
226
|
-
],
|
|
227
|
-
},
|
|
228
|
-
],
|
|
229
|
-
});
|
|
230
|
-
const pkgB = (0, utils_1.newid)();
|
|
231
|
-
const result = registry.register(pkgB, def2);
|
|
232
|
-
expect(result.valid).toBe(true);
|
|
233
|
-
});
|
|
234
|
-
it("rejects dev registration after a stable version exists", () => {
|
|
235
|
-
const stableDef = makeContract({
|
|
236
|
-
tables: [
|
|
237
|
-
{
|
|
238
|
-
name: "T",
|
|
239
|
-
description: "d",
|
|
240
|
-
primaryKeyName: "id",
|
|
241
|
-
fields: [{ name: "id", type: field_type_1.FieldType.id }],
|
|
242
|
-
},
|
|
243
|
-
],
|
|
244
|
-
});
|
|
245
|
-
const pkgA = (0, utils_1.newid)();
|
|
246
|
-
registry.register(pkgA, stableDef);
|
|
247
|
-
const devDef = makeContract({
|
|
248
|
-
devTag: "dev",
|
|
249
|
-
tables: [
|
|
250
|
-
{
|
|
251
|
-
name: "T",
|
|
252
|
-
description: "d",
|
|
253
|
-
primaryKeyName: "id",
|
|
254
|
-
fields: [{ name: "id", type: field_type_1.FieldType.id }],
|
|
255
|
-
},
|
|
256
|
-
],
|
|
257
|
-
});
|
|
258
|
-
const pkgB = (0, utils_1.newid)();
|
|
259
|
-
const result = registry.register(pkgB, devDef);
|
|
260
|
-
expect(result.valid).toBe(false);
|
|
261
|
-
expect(result.errors[0].message).toContain("frozen");
|
|
262
|
-
});
|
|
263
|
-
it("allows dev-to-stable transition, then rejects subsequent dev registration", () => {
|
|
264
|
-
const devDef = makeContract({
|
|
265
|
-
devTag: "dev",
|
|
266
|
-
tables: [
|
|
267
|
-
{
|
|
268
|
-
name: "T",
|
|
269
|
-
description: "d",
|
|
270
|
-
primaryKeyName: "id",
|
|
271
|
-
fields: [{ name: "id", type: field_type_1.FieldType.id }],
|
|
272
|
-
},
|
|
273
|
-
],
|
|
274
|
-
});
|
|
275
|
-
const pkgA = (0, utils_1.newid)();
|
|
276
|
-
registry.register(pkgA, devDef);
|
|
277
|
-
const stableDef = makeContract({
|
|
278
|
-
tables: [
|
|
279
|
-
{
|
|
280
|
-
name: "T",
|
|
281
|
-
description: "d",
|
|
282
|
-
primaryKeyName: "id",
|
|
283
|
-
fields: [
|
|
284
|
-
{ name: "id", type: field_type_1.FieldType.id },
|
|
285
|
-
{ name: "title", type: field_type_1.FieldType.string },
|
|
286
|
-
],
|
|
287
|
-
},
|
|
288
|
-
],
|
|
289
|
-
});
|
|
290
|
-
const pkgB = (0, utils_1.newid)();
|
|
291
|
-
const stableResult = registry.register(pkgB, stableDef);
|
|
292
|
-
expect(stableResult.valid).toBe(true);
|
|
293
|
-
const devDef2 = makeContract({
|
|
294
|
-
devTag: "dev",
|
|
295
|
-
tables: [
|
|
296
|
-
{
|
|
297
|
-
name: "T",
|
|
298
|
-
description: "d",
|
|
299
|
-
primaryKeyName: "id",
|
|
300
|
-
fields: [{ name: "id", type: field_type_1.FieldType.id }],
|
|
301
|
-
},
|
|
302
|
-
],
|
|
303
|
-
});
|
|
304
|
-
const pkgC = (0, utils_1.newid)();
|
|
305
|
-
const devResult = registry.register(pkgC, devDef2);
|
|
306
|
-
expect(devResult.valid).toBe(false);
|
|
307
|
-
expect(devResult.errors[0].message).toContain("frozen");
|
|
308
|
-
});
|
|
53
|
+
it("returns undefined when preferred are missing and fallback is disabled", () => {
|
|
54
|
+
const dep = {
|
|
55
|
+
contractId,
|
|
56
|
+
version: 1,
|
|
57
|
+
providerPackageIds: [packageC],
|
|
58
|
+
fallbackToDefaultProvider: false,
|
|
59
|
+
};
|
|
60
|
+
expect(registry.selectProvider(dep)).toBeUndefined();
|
|
309
61
|
});
|
|
310
|
-
|
|
311
|
-
|
|
312
|
-
|
|
313
|
-
const pkgA = (0, utils_1.newid)();
|
|
314
|
-
registry.register(pkgA, def);
|
|
315
|
-
const stored = registry.getDefinition(DEFAULT_CONTRACT_ID, 1);
|
|
316
|
-
expect(stored).toBeDefined();
|
|
317
|
-
expect(stored?.name).toBe("My Contract");
|
|
318
|
-
});
|
|
319
|
-
it("returns undefined for unknown contracts", () => {
|
|
320
|
-
const unknownId = (0, utils_1.newid)();
|
|
321
|
-
expect(registry.getDefinition(unknownId, 1)).toBeUndefined();
|
|
322
|
-
});
|
|
62
|
+
it("returns undefined when no providers are registered", () => {
|
|
63
|
+
const empty = new registry_1.ContractRegistry();
|
|
64
|
+
expect(empty.selectProvider({ contractId, version: 1 })).toBeUndefined();
|
|
323
65
|
});
|
|
324
66
|
});
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
import "../system";
|
|
@@ -0,0 +1,61 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
+
const system_ids_1 = require("../../system-ids");
|
|
4
|
+
const utils_1 = require("../../utils");
|
|
5
|
+
const contract_resolvers_1 = require("../contract-resolvers");
|
|
6
|
+
const registry_1 = require("../registry");
|
|
7
|
+
const system_contracts_1 = require("../system-contracts");
|
|
8
|
+
// Populate the catalog with built-in system contracts.
|
|
9
|
+
require("../system");
|
|
10
|
+
describe("system contract catalog", () => {
|
|
11
|
+
it("self-registers the built-in system contracts", () => {
|
|
12
|
+
const ids = (0, system_contracts_1.listSystemContracts)()
|
|
13
|
+
.map((entry) => entry.contractId)
|
|
14
|
+
.filter(Boolean);
|
|
15
|
+
expect(ids).toEqual(expect.arrayContaining([
|
|
16
|
+
system_ids_1.logsContractId,
|
|
17
|
+
system_ids_1.deviceOperationsContractId,
|
|
18
|
+
system_ids_1.networkDiagnosticsContractId,
|
|
19
|
+
system_ids_1.networkControlContractId,
|
|
20
|
+
]));
|
|
21
|
+
});
|
|
22
|
+
it("registers the Logs live resolver", async () => {
|
|
23
|
+
await new Promise((resolve) => queueMicrotask(resolve));
|
|
24
|
+
expect((0, contract_resolvers_1.getContractResolver)(system_ids_1.logsContractId, 1)).toEqual(expect.any(Function));
|
|
25
|
+
});
|
|
26
|
+
it("installSystemContracts seeds a registry with system providers", () => {
|
|
27
|
+
const registry = new registry_1.ContractRegistry();
|
|
28
|
+
(0, system_contracts_1.installSystemContracts)(registry);
|
|
29
|
+
expect(registry.resolve(system_ids_1.logsContractId, 1)?.name).toBe("System Logs");
|
|
30
|
+
expect(registry.getProviderPackageId(system_ids_1.logsContractId, 1)).toBe(system_ids_1.peersSystemPackageId);
|
|
31
|
+
expect(registry.resolve(system_ids_1.deviceOperationsContractId, 1)?.name).toBe("System Device Operations");
|
|
32
|
+
expect(registry.getProviderPackageId(system_ids_1.deviceOperationsContractId, 1)).toBe(system_ids_1.peersSystemPackageId);
|
|
33
|
+
expect(registry.resolve(system_ids_1.networkDiagnosticsContractId, 1)?.name).toBe("System Network Diagnostics");
|
|
34
|
+
expect(registry.getProviderPackageId(system_ids_1.networkDiagnosticsContractId, 1)).toBe(system_ids_1.peersSystemPackageId);
|
|
35
|
+
expect(registry.resolve(system_ids_1.networkControlContractId, 1)?.name).toBe("System Network Control");
|
|
36
|
+
expect(registry.getProviderPackageId(system_ids_1.networkControlContractId, 1)).toBe(system_ids_1.peersSystemPackageId);
|
|
37
|
+
});
|
|
38
|
+
it("registerSystemContract makes new contracts installable without loader changes", () => {
|
|
39
|
+
const fakeContractId = (0, utils_1.newid)();
|
|
40
|
+
const providerPackageId = (0, utils_1.newid)();
|
|
41
|
+
(0, system_contracts_1.registerSystemContract)({
|
|
42
|
+
providerPackageId,
|
|
43
|
+
contractId: fakeContractId,
|
|
44
|
+
version: 1,
|
|
45
|
+
getDefinition: () => ({
|
|
46
|
+
contractId: fakeContractId,
|
|
47
|
+
version: 1,
|
|
48
|
+
devTag: "dev",
|
|
49
|
+
name: "Fake System Contract",
|
|
50
|
+
description: "test",
|
|
51
|
+
tables: [],
|
|
52
|
+
tools: [],
|
|
53
|
+
observables: [],
|
|
54
|
+
events: [],
|
|
55
|
+
}),
|
|
56
|
+
});
|
|
57
|
+
const registry = new registry_1.ContractRegistry();
|
|
58
|
+
(0, system_contracts_1.installSystemContracts)(registry);
|
|
59
|
+
expect(registry.getProviderPackageId(fakeContractId, 1)).toBe(providerPackageId);
|
|
60
|
+
});
|
|
61
|
+
});
|
|
@@ -1,7 +1,8 @@
|
|
|
1
1
|
import type { ITableDefinition } from "../data/orm/table-definitions.type";
|
|
2
2
|
import type { IToolInstance } from "../data/tools";
|
|
3
|
+
import type { IContractConsumer, IContractConsumerBase } from "./contract-proxy";
|
|
3
4
|
import type { IExtractableTableDef, IExtractableToolInstance } from "./extract";
|
|
4
|
-
import type { IAlsoImplementsDeclaration, IContractDefinition, IContractEvent, IContractObservable, IPackageDefinitionResult } from "./types";
|
|
5
|
+
import type { IAlsoImplementsDeclaration, IConsumedContractHandle, IConsumedContractOptions, IContractDefinition, IContractEvent, IContractObservable, IPackageDefinitionResult } from "./types";
|
|
5
6
|
/**
|
|
6
7
|
* Scoped builder for a single contract within a package. Returned by
|
|
7
8
|
* `PackageBuilder.contract()`.
|
|
@@ -56,6 +57,27 @@ export declare class ContractBuilder {
|
|
|
56
57
|
tableDefinitions: ITableDefinition[];
|
|
57
58
|
};
|
|
58
59
|
}
|
|
60
|
+
/**
|
|
61
|
+
* Create a deferred consumed-contract handle. Settlement is SDK-owned via
|
|
62
|
+
* {@link settleConsumedContractHandle} / {@link rejectConsumedContractHandle}.
|
|
63
|
+
*
|
|
64
|
+
* @internal
|
|
65
|
+
*/
|
|
66
|
+
export declare function createConsumedContractHandle<T extends IContractConsumerBase | undefined = IContractConsumerBase | undefined>(): IConsumedContractHandle<T>;
|
|
67
|
+
/**
|
|
68
|
+
* Resolve a consumed-contract handle with a live proxy, or `undefined` for an
|
|
69
|
+
* unmatched optional dependency. One-shot — throws if already settled.
|
|
70
|
+
*
|
|
71
|
+
* @internal Used by the package-loader when settling `consumes` handles.
|
|
72
|
+
*/
|
|
73
|
+
export declare function settleConsumedContractHandle(handle: IConsumedContractHandle<IContractConsumerBase | undefined>, consumer: IContractConsumerBase | undefined): void;
|
|
74
|
+
/**
|
|
75
|
+
* Reject a consumed-contract handle (e.g. required dependency missing).
|
|
76
|
+
* One-shot — throws if already settled.
|
|
77
|
+
*
|
|
78
|
+
* @internal Used by the package-loader when settling `consumes` handles.
|
|
79
|
+
*/
|
|
80
|
+
export declare function rejectConsumedContractHandle(handle: IConsumedContractHandle<IContractConsumerBase | undefined>, reason: unknown): void;
|
|
59
81
|
/**
|
|
60
82
|
* Top-level builder passed to the `definePackage` callback.
|
|
61
83
|
*
|
|
@@ -95,8 +117,27 @@ export declare class PackageBuilder {
|
|
|
95
117
|
contract(contractId: string, version: number, name: string): ContractBuilder;
|
|
96
118
|
/**
|
|
97
119
|
* Declare a dependency on another package's contract.
|
|
120
|
+
*
|
|
121
|
+
* Returns a deferred handle immediately. Await `handle.consumer` from
|
|
122
|
+
* runtime code after package definition — not inside this callback — so
|
|
123
|
+
* package loading stays non-blocking. The package-loader settles the
|
|
124
|
+
* promise once providers are registered (follow-up work).
|
|
125
|
+
*
|
|
126
|
+
* Pass a type argument to narrow the resolved consumer beyond the default
|
|
127
|
+
* {@link IContractConsumer} shape, e.g. `pkg.consumes<ILogsConsumer>(id, 1)`.
|
|
128
|
+
* Typed consumers need only extend {@link IContractConsumerBase}.
|
|
129
|
+
*
|
|
130
|
+
* @typeParam T - Consumer proxy type (defaults to {@link IContractConsumer}).
|
|
131
|
+
* @param contractId - Must be a valid peer ID (25-char alphanumeric from `newid()`).
|
|
132
|
+
* @param version - Positive integer version number.
|
|
133
|
+
* @param opts - Optional dependency and provider-preference options.
|
|
98
134
|
*/
|
|
99
|
-
consumes(contractId: string, version: number
|
|
135
|
+
consumes<T extends IContractConsumerBase = IContractConsumer>(contractId: string, version: number, opts: IConsumedContractOptions & {
|
|
136
|
+
optional: true;
|
|
137
|
+
}): IConsumedContractHandle<T | undefined>;
|
|
138
|
+
consumes<T extends IContractConsumerBase = IContractConsumer>(contractId: string, version: number, opts?: Omit<IConsumedContractOptions, "optional"> & {
|
|
139
|
+
optional?: false;
|
|
140
|
+
}): IConsumedContractHandle<T>;
|
|
100
141
|
/** @internal Finalize and return the package definition result. */
|
|
101
142
|
_build(): IPackageDefinitionResult;
|
|
102
143
|
}
|
|
@@ -1,6 +1,9 @@
|
|
|
1
1
|
"use strict";
|
|
2
2
|
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
3
|
exports.PackageBuilder = exports.ContractBuilder = void 0;
|
|
4
|
+
exports.createConsumedContractHandle = createConsumedContractHandle;
|
|
5
|
+
exports.settleConsumedContractHandle = settleConsumedContractHandle;
|
|
6
|
+
exports.rejectConsumedContractHandle = rejectConsumedContractHandle;
|
|
4
7
|
exports.definePackage = definePackage;
|
|
5
8
|
const utils_1 = require("../utils");
|
|
6
9
|
const extract_1 = require("./extract");
|
|
@@ -103,6 +106,61 @@ class ContractBuilder {
|
|
|
103
106
|
}
|
|
104
107
|
}
|
|
105
108
|
exports.ContractBuilder = ContractBuilder;
|
|
109
|
+
const consumedContractDeferreds = new WeakMap();
|
|
110
|
+
/**
|
|
111
|
+
* Create a deferred consumed-contract handle. Settlement is SDK-owned via
|
|
112
|
+
* {@link settleConsumedContractHandle} / {@link rejectConsumedContractHandle}.
|
|
113
|
+
*
|
|
114
|
+
* @internal
|
|
115
|
+
*/
|
|
116
|
+
function createConsumedContractHandle() {
|
|
117
|
+
let resolve;
|
|
118
|
+
let reject;
|
|
119
|
+
const consumer = new Promise((res, rej) => {
|
|
120
|
+
resolve = res;
|
|
121
|
+
reject = rej;
|
|
122
|
+
});
|
|
123
|
+
// Avoid unhandled-rejection noise when the package-loader settles with an
|
|
124
|
+
// error before any package code awaits the handle.
|
|
125
|
+
consumer.catch(() => { });
|
|
126
|
+
const handle = { consumer };
|
|
127
|
+
consumedContractDeferreds.set(handle, { resolve, reject, settled: false });
|
|
128
|
+
return handle;
|
|
129
|
+
}
|
|
130
|
+
/**
|
|
131
|
+
* Resolve a consumed-contract handle with a live proxy, or `undefined` for an
|
|
132
|
+
* unmatched optional dependency. One-shot — throws if already settled.
|
|
133
|
+
*
|
|
134
|
+
* @internal Used by the package-loader when settling `consumes` handles.
|
|
135
|
+
*/
|
|
136
|
+
function settleConsumedContractHandle(handle, consumer) {
|
|
137
|
+
const deferred = consumedContractDeferreds.get(handle);
|
|
138
|
+
if (!deferred) {
|
|
139
|
+
throw new Error("Unknown consumed-contract handle");
|
|
140
|
+
}
|
|
141
|
+
if (deferred.settled) {
|
|
142
|
+
throw new Error("Consumed-contract handle has already been settled");
|
|
143
|
+
}
|
|
144
|
+
deferred.settled = true;
|
|
145
|
+
deferred.resolve(consumer);
|
|
146
|
+
}
|
|
147
|
+
/**
|
|
148
|
+
* Reject a consumed-contract handle (e.g. required dependency missing).
|
|
149
|
+
* One-shot — throws if already settled.
|
|
150
|
+
*
|
|
151
|
+
* @internal Used by the package-loader when settling `consumes` handles.
|
|
152
|
+
*/
|
|
153
|
+
function rejectConsumedContractHandle(handle, reason) {
|
|
154
|
+
const deferred = consumedContractDeferreds.get(handle);
|
|
155
|
+
if (!deferred) {
|
|
156
|
+
throw new Error("Unknown consumed-contract handle");
|
|
157
|
+
}
|
|
158
|
+
if (deferred.settled) {
|
|
159
|
+
throw new Error("Consumed-contract handle has already been settled");
|
|
160
|
+
}
|
|
161
|
+
deferred.settled = true;
|
|
162
|
+
deferred.reject(reason);
|
|
163
|
+
}
|
|
106
164
|
/**
|
|
107
165
|
* Top-level builder passed to the `definePackage` callback.
|
|
108
166
|
*
|
|
@@ -165,14 +223,30 @@ class PackageBuilder {
|
|
|
165
223
|
this._contracts.push(builder);
|
|
166
224
|
return builder;
|
|
167
225
|
}
|
|
168
|
-
|
|
169
|
-
* Declare a dependency on another package's contract.
|
|
170
|
-
*/
|
|
171
|
-
consumes(contractId, version) {
|
|
226
|
+
consumes(contractId, version, opts) {
|
|
172
227
|
if (!(0, utils_1.isid)(contractId)) {
|
|
173
228
|
throw new Error(`consumes contractId must be a valid peer ID (25-char alphanumeric), got "${contractId}"`);
|
|
174
229
|
}
|
|
175
|
-
|
|
230
|
+
if (version < 1 || !Number.isInteger(version)) {
|
|
231
|
+
throw new Error(`consumes version must be a positive integer, got ${version}`);
|
|
232
|
+
}
|
|
233
|
+
if (opts?.providerPackageIds) {
|
|
234
|
+
for (const providerPackageId of opts.providerPackageIds) {
|
|
235
|
+
if (!(0, utils_1.isid)(providerPackageId)) {
|
|
236
|
+
throw new Error(`consumes providerPackageIds entries must be valid peer IDs (25-char alphanumeric), got "${providerPackageId}"`);
|
|
237
|
+
}
|
|
238
|
+
}
|
|
239
|
+
}
|
|
240
|
+
const handle = createConsumedContractHandle();
|
|
241
|
+
this._consumes.push({
|
|
242
|
+
contractId,
|
|
243
|
+
version,
|
|
244
|
+
optional: opts?.optional,
|
|
245
|
+
providerPackageIds: opts?.providerPackageIds ? [...opts.providerPackageIds] : undefined,
|
|
246
|
+
fallbackToDefaultProvider: opts?.fallbackToDefaultProvider,
|
|
247
|
+
handle,
|
|
248
|
+
});
|
|
249
|
+
return handle;
|
|
176
250
|
}
|
|
177
251
|
/** @internal Finalize and return the package definition result. */
|
|
178
252
|
_build() {
|