@peers-app/peers-sdk 0.27.3 → 0.27.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/contracts/contract-proxy.d.ts +7 -0
- package/dist/contracts/contract-proxy.js +19 -2
- package/dist/contracts/contract-transport.d.ts +2 -1
- package/dist/contracts/contract-transport.js +24 -2
- package/dist/contracts/create-local-consumer.js +16 -1
- package/dist/contracts/index.d.ts +2 -0
- package/dist/contracts/index.js +2 -0
- package/dist/contracts/system/index.d.ts +2 -0
- package/dist/contracts/system/index.js +2 -0
- package/dist/contracts/system/invites-contract.js +2 -1
- package/dist/contracts/system/sync-check-contract.d.ts +97 -0
- package/dist/contracts/system/sync-check-contract.js +115 -0
- package/dist/contracts/tool-arguments.d.ts +15 -0
- package/dist/contracts/tool-arguments.js +41 -0
- package/dist/contracts/tool-catalog-service.js +2 -12
- package/dist/contracts/tool-catalog.js +6 -2
- package/dist/data/change-tracking.d.ts +40 -0
- package/dist/data/change-tracking.js +89 -0
- package/dist/data/orm/types.d.ts +24 -7
- package/dist/data/orm/types.js +97 -24
- package/dist/define/manifest.js +6 -34
- package/dist/device/binary-peer-connection-v2.d.ts +7 -15
- package/dist/device/binary-peer-connection-v2.js +14 -30
- package/dist/device/connection.d.ts +34 -43
- package/dist/device/connection.js +188 -186
- package/dist/device/device.d.ts +1 -8
- package/dist/device/device.js +1 -30
- package/dist/device/socket.type.d.ts +6 -12
- package/dist/package-loader/package-loader.js +27 -22
- package/dist/system-ids.d.ts +5 -0
- package/dist/system-ids.js +6 -1
- package/package.json +4 -2
- package/dist/context/user-context-identity.test.d.ts +0 -1
- package/dist/context/user-context-identity.test.js +0 -220
- package/dist/contracts/__tests__/action-dispatch.test.d.ts +0 -1
- package/dist/contracts/__tests__/action-dispatch.test.js +0 -319
- package/dist/contracts/__tests__/also-implements.test.d.ts +0 -1
- package/dist/contracts/__tests__/also-implements.test.js +0 -110
- package/dist/contracts/__tests__/builder.test.d.ts +0 -1
- package/dist/contracts/__tests__/builder.test.js +0 -669
- package/dist/contracts/__tests__/contract-events.test.d.ts +0 -1
- package/dist/contracts/__tests__/contract-events.test.js +0 -199
- package/dist/contracts/__tests__/contract-observables.test.d.ts +0 -1
- package/dist/contracts/__tests__/contract-observables.test.js +0 -290
- package/dist/contracts/__tests__/contract-provider-router.test.d.ts +0 -1
- package/dist/contracts/__tests__/contract-provider-router.test.js +0 -315
- package/dist/contracts/__tests__/contract-proxy.test.d.ts +0 -1
- package/dist/contracts/__tests__/contract-proxy.test.js +0 -657
- package/dist/contracts/__tests__/contract-resolvers.test.d.ts +0 -1
- package/dist/contracts/__tests__/contract-resolvers.test.js +0 -758
- package/dist/contracts/__tests__/contract-subscription-lifecycle.test.d.ts +0 -1
- package/dist/contracts/__tests__/contract-subscription-lifecycle.test.js +0 -353
- package/dist/contracts/__tests__/contract-table-events.test.d.ts +0 -1
- package/dist/contracts/__tests__/contract-table-events.test.js +0 -209
- package/dist/contracts/__tests__/contract-transport.test.d.ts +0 -1
- package/dist/contracts/__tests__/contract-transport.test.js +0 -163
- package/dist/contracts/__tests__/extract.test.d.ts +0 -1
- package/dist/contracts/__tests__/extract.test.js +0 -145
- package/dist/contracts/__tests__/frozen-contracts.test.d.ts +0 -1
- package/dist/contracts/__tests__/frozen-contracts.test.js +0 -191
- package/dist/contracts/__tests__/generic-tool-dispatch.test.d.ts +0 -1
- package/dist/contracts/__tests__/generic-tool-dispatch.test.js +0 -130
- package/dist/contracts/__tests__/host-contract-client.test.d.ts +0 -1
- package/dist/contracts/__tests__/host-contract-client.test.js +0 -793
- package/dist/contracts/__tests__/host-contract-consumer.test.d.ts +0 -1
- package/dist/contracts/__tests__/host-contract-consumer.test.js +0 -163
- package/dist/contracts/__tests__/host-contract-transport.test.d.ts +0 -1
- package/dist/contracts/__tests__/host-contract-transport.test.js +0 -66
- package/dist/contracts/__tests__/integration.test.d.ts +0 -1
- package/dist/contracts/__tests__/integration.test.js +0 -348
- package/dist/contracts/__tests__/legacy-removal.test.d.ts +0 -1
- package/dist/contracts/__tests__/legacy-removal.test.js +0 -128
- package/dist/contracts/__tests__/persistent-registry.test.d.ts +0 -1
- package/dist/contracts/__tests__/persistent-registry.test.js +0 -109
- package/dist/contracts/__tests__/playground.test.d.ts +0 -1
- package/dist/contracts/__tests__/playground.test.js +0 -216
- package/dist/contracts/__tests__/registry.test.d.ts +0 -1
- package/dist/contracts/__tests__/registry.test.js +0 -238
- package/dist/contracts/__tests__/remote-contract-transport.test.d.ts +0 -1
- package/dist/contracts/__tests__/remote-contract-transport.test.js +0 -119
- package/dist/contracts/__tests__/system-contracts.test.d.ts +0 -1
- package/dist/contracts/__tests__/system-contracts.test.js +0 -247
- package/dist/contracts/__tests__/target-dispatch.d.ts +0 -11
- package/dist/contracts/__tests__/target-dispatch.js +0 -24
- package/dist/contracts/__tests__/tool-catalog-inventory.test.d.ts +0 -1
- package/dist/contracts/__tests__/tool-catalog-inventory.test.js +0 -44
- package/dist/contracts/__tests__/tool-catalog-service.test.d.ts +0 -1
- package/dist/contracts/__tests__/tool-catalog-service.test.js +0 -482
- package/dist/contracts/__tests__/tool-catalog.test.d.ts +0 -1
- package/dist/contracts/__tests__/tool-catalog.test.js +0 -1199
- package/dist/contracts/__tests__/validate.test.d.ts +0 -1
- package/dist/contracts/__tests__/validate.test.js +0 -991
- package/dist/contracts/__tests__/workflow-context.test.d.ts +0 -1
- package/dist/contracts/__tests__/workflow-context.test.js +0 -50
- package/dist/data/access-level.test.d.ts +0 -1
- package/dist/data/access-level.test.js +0 -53
- package/dist/data/change-tracking.test.d.ts +0 -1
- package/dist/data/change-tracking.test.js +0 -62
- package/dist/data/files/files.test.d.ts +0 -1
- package/dist/data/files/files.test.js +0 -770
- package/dist/data/group-members.test.d.ts +0 -1
- package/dist/data/group-members.test.js +0 -336
- package/dist/data/group-share.test.d.ts +0 -1
- package/dist/data/group-share.test.js +0 -110
- package/dist/data/groups.test.d.ts +0 -1
- package/dist/data/groups.test.js +0 -153
- package/dist/data/orm/cursor.test.d.ts +0 -1
- package/dist/data/orm/cursor.test.js +0 -314
- package/dist/data/orm/data-query.mongo.test.d.ts +0 -1
- package/dist/data/orm/data-query.mongo.test.js +0 -367
- package/dist/data/orm/data-query.sqlite.test.d.ts +0 -1
- package/dist/data/orm/data-query.sqlite.test.js +0 -365
- package/dist/data/orm/data-query.test.d.ts +0 -1
- package/dist/data/orm/data-query.test.js +0 -545
- package/dist/data/orm/dependency-injection.test.d.ts +0 -1
- package/dist/data/orm/dependency-injection.test.js +0 -171
- package/dist/data/orm/event-registry.test.d.ts +0 -1
- package/dist/data/orm/event-registry.test.js +0 -44
- package/dist/data/orm/multi-cursors.test.d.ts +0 -1
- package/dist/data/orm/multi-cursors.test.js +0 -463
- package/dist/data/orm/sql.data-source.test.d.ts +0 -1
- package/dist/data/orm/sql.data-source.test.js +0 -731
- package/dist/data/orm/table-container-events.test.d.ts +0 -1
- package/dist/data/orm/table-container-events.test.js +0 -101
- package/dist/data/orm/table-container.test.d.ts +0 -1
- package/dist/data/orm/table-container.test.js +0 -273
- package/dist/data/orm/table.event-source.test.d.ts +0 -1
- package/dist/data/orm/table.event-source.test.js +0 -331
- package/dist/data/orm/types.test.d.ts +0 -1
- package/dist/data/orm/types.test.js +0 -409
- package/dist/data/package-table-identity.test.d.ts +0 -1
- package/dist/data/package-table-identity.test.js +0 -46
- package/dist/data/package-version-permissions.test.d.ts +0 -1
- package/dist/data/package-version-permissions.test.js +0 -107
- package/dist/data/package-version-resolver.test.d.ts +0 -4
- package/dist/data/package-version-resolver.test.js +0 -543
- package/dist/data/package-versions.test.d.ts +0 -1
- package/dist/data/package-versions.test.js +0 -227
- package/dist/data/persistent-vars.conflict.test.d.ts +0 -1
- package/dist/data/persistent-vars.conflict.test.js +0 -126
- package/dist/data/persistent-vars.migration.test.d.ts +0 -1
- package/dist/data/persistent-vars.migration.test.js +0 -133
- package/dist/data/persistent-vars.package-scope.test.d.ts +0 -1
- package/dist/data/persistent-vars.package-scope.test.js +0 -27
- package/dist/data/sync-recovery-queue.test.d.ts +0 -1
- package/dist/data/sync-recovery-queue.test.js +0 -215
- package/dist/data/table-signing.test.d.ts +0 -1
- package/dist/data/table-signing.test.js +0 -118
- package/dist/data/tool-access.test.d.ts +0 -1
- package/dist/data/tool-access.test.js +0 -166
- package/dist/data/user-permissions.test.d.ts +0 -1
- package/dist/data/user-permissions.test.js +0 -305
- package/dist/data/user-trust-levels.test.d.ts +0 -1
- package/dist/data/user-trust-levels.test.js +0 -37
- package/dist/define/also-implements.test.d.ts +0 -1
- package/dist/define/also-implements.test.js +0 -123
- package/dist/define/declare-contract.test.d.ts +0 -1
- package/dist/define/declare-contract.test.js +0 -573
- package/dist/define/define.test.d.ts +0 -1
- package/dist/define/define.test.js +0 -1010
- package/dist/define/empty-fields.test.d.ts +0 -1
- package/dist/define/empty-fields.test.js +0 -55
- package/dist/define/events-observables.test.d.ts +0 -1
- package/dist/define/events-observables.test.js +0 -1013
- package/dist/define/serve-members.test.d.ts +0 -1
- package/dist/define/serve-members.test.js +0 -630
- package/dist/define/vars.test.d.ts +0 -1
- package/dist/define/vars.test.js +0 -39
- package/dist/device/binary-peer-connection-v2.test.d.ts +0 -1
- package/dist/device/binary-peer-connection-v2.test.js +0 -730
- package/dist/device/binary-peer-connection.d.ts +0 -58
- package/dist/device/binary-peer-connection.js +0 -516
- package/dist/device/binary-peer-connection.test.d.ts +0 -1
- package/dist/device/binary-peer-connection.test.js +0 -184
- package/dist/device/connection.test.d.ts +0 -1
- package/dist/device/connection.test.js +0 -613
- package/dist/device/device-election.test.d.ts +0 -1
- package/dist/device/device-election.test.js +0 -516
- package/dist/device/device.test.d.ts +0 -1
- package/dist/device/device.test.js +0 -243
- package/dist/device/frame-cipher.test.d.ts +0 -1
- package/dist/device/frame-cipher.test.js +0 -219
- package/dist/device/get-trust-level-fn.test.d.ts +0 -1
- package/dist/device/get-trust-level-fn.test.js +0 -685
- package/dist/device/streamed-socket.d.ts +0 -23
- package/dist/device/streamed-socket.js +0 -255
- package/dist/device/streamed-socket.test.d.ts +0 -1
- package/dist/device/streamed-socket.test.js +0 -216
- package/dist/device/tx-encoding.test.d.ts +0 -1
- package/dist/device/tx-encoding.test.js +0 -295
- package/dist/device-pairing/cpace.test.d.ts +0 -1
- package/dist/device-pairing/cpace.test.js +0 -116
- package/dist/device-pairing/device-pairing.test.d.ts +0 -1
- package/dist/device-pairing/device-pairing.test.js +0 -211
- package/dist/hlc.test.d.ts +0 -1
- package/dist/hlc.test.js +0 -45
- package/dist/host-credentials.test.d.ts +0 -1
- package/dist/host-credentials.test.js +0 -88
- package/dist/identity/account-email.test.d.ts +0 -1
- package/dist/identity/account-email.test.js +0 -59
- package/dist/identity/anchor-document.test.d.ts +0 -1
- package/dist/identity/anchor-document.test.js +0 -16
- package/dist/identity/anchor-resolution.test.d.ts +0 -1
- package/dist/identity/anchor-resolution.test.js +0 -130
- package/dist/identity/key-change.test.d.ts +0 -1
- package/dist/identity/key-change.test.js +0 -811
- package/dist/invites/group-approval.test.d.ts +0 -1
- package/dist/invites/group-approval.test.js +0 -223
- package/dist/invites/invite-token.test.d.ts +0 -1
- package/dist/invites/invite-token.test.js +0 -123
- package/dist/keys.test.d.ts +0 -1
- package/dist/keys.test.js +0 -336
- package/dist/logging/console-logger.test.d.ts +0 -1
- package/dist/logging/console-logger.test.js +0 -300
- package/dist/logging/console-logs.table.test.d.ts +0 -1
- package/dist/logging/console-logs.table.test.js +0 -156
- package/dist/observable.test.d.ts +0 -1
- package/dist/observable.test.js +0 -309
- package/dist/package-build/build-package.test.d.ts +0 -1
- package/dist/package-build/build-package.test.js +0 -204
- package/dist/package-build/contract-add.test.d.ts +0 -1
- package/dist/package-build/contract-add.test.js +0 -467
- package/dist/package-build/freeze-contracts.test.d.ts +0 -1
- package/dist/package-build/freeze-contracts.test.js +0 -355
- package/dist/package-installer/package-author-signing.test.d.ts +0 -1
- package/dist/package-installer/package-author-signing.test.js +0 -200
- package/dist/package-installer/package-cloner.test.d.ts +0 -1
- package/dist/package-installer/package-cloner.test.js +0 -278
- package/dist/package-installer/package-creator.test.d.ts +0 -1
- package/dist/package-installer/package-creator.test.js +0 -908
- package/dist/package-installer/package-dev-tools.test.d.ts +0 -1
- package/dist/package-installer/package-dev-tools.test.js +0 -64
- package/dist/package-installer/package-installer.test.d.ts +0 -1
- package/dist/package-installer/package-installer.test.js +0 -882
- package/dist/package-installer/package-propagation.test.d.ts +0 -1
- package/dist/package-installer/package-propagation.test.js +0 -1269
- package/dist/package-installer/package-publisher.test.d.ts +0 -1
- package/dist/package-installer/package-publisher.test.js +0 -153
- package/dist/package-installer/package-remote-checker.test.d.ts +0 -1
- package/dist/package-installer/package-remote-checker.test.js +0 -334
- package/dist/package-installer/package-seed-installer.test.d.ts +0 -1
- package/dist/package-installer/package-seed-installer.test.js +0 -123
- package/dist/package-installer/package-tarball.test.d.ts +0 -1
- package/dist/package-installer/package-tarball.test.js +0 -75
- package/dist/package-installer/peers-core-installer.test.d.ts +0 -1
- package/dist/package-installer/peers-core-installer.test.js +0 -49
- package/dist/package-installer/peers-core-trust-anchor.test.d.ts +0 -1
- package/dist/package-installer/peers-core-trust-anchor.test.js +0 -155
- package/dist/package-loader/contract-package-loader.test.d.ts +0 -1
- package/dist/package-loader/contract-package-loader.test.js +0 -274
- package/dist/package-loader/host-authority-loading.test.d.ts +0 -1
- package/dist/package-loader/host-authority-loading.test.js +0 -104
- package/dist/package-loader/host-dispatch-policy.test.d.ts +0 -1
- package/dist/package-loader/host-dispatch-policy.test.js +0 -56
- package/dist/package-loader/isolated-artifact.test.d.ts +0 -1
- package/dist/package-loader/isolated-artifact.test.js +0 -688
- package/dist/package-loader/isolated-persistent-var-gateway.test.d.ts +0 -1
- package/dist/package-loader/isolated-persistent-var-gateway.test.js +0 -56
- package/dist/package-loader/isolated-table-gateway.test.d.ts +0 -1
- package/dist/package-loader/isolated-table-gateway.test.js +0 -633
- package/dist/package-loader/package-loader.test.d.ts +0 -1
- package/dist/package-loader/package-loader.test.js +0 -1764
- package/dist/package-loader/resolve-consumed-contracts.test.d.ts +0 -1
- package/dist/package-loader/resolve-consumed-contracts.test.js +0 -166
- package/dist/serial-json.compat.test.d.ts +0 -1
- package/dist/serial-json.compat.test.js +0 -369
- package/dist/serial-json.test.d.ts +0 -1
- package/dist/serial-json.test.js +0 -401
- package/dist/testing/mock-host-contract.test.d.ts +0 -1
- package/dist/testing/mock-host-contract.test.js +0 -782
- package/dist/utils.test.d.ts +0 -1
- package/dist/utils.test.js +0 -232
|
@@ -1,573 +0,0 @@
|
|
|
1
|
-
"use strict";
|
|
2
|
-
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
-
const isolated_artifact_1 = require("../package-loader/isolated-artifact");
|
|
4
|
-
const peer_id_1 = require("../peer-id");
|
|
5
|
-
const index_1 = require("./index");
|
|
6
|
-
const manifest_1 = require("./manifest");
|
|
7
|
-
const observables_1 = require("./observables");
|
|
8
|
-
const serve_members_1 = require("./serve-members");
|
|
9
|
-
/** A ctx whose host calls are recorded and answered by `answer`. */
|
|
10
|
-
function fakeContext(answer = () => null) {
|
|
11
|
-
const calls = [];
|
|
12
|
-
const ctx = new Proxy({}, {
|
|
13
|
-
get(_target, method) {
|
|
14
|
-
return async (...args) => {
|
|
15
|
-
calls.push([method, ...args]);
|
|
16
|
-
return answer(method, args);
|
|
17
|
-
};
|
|
18
|
-
},
|
|
19
|
-
});
|
|
20
|
-
return { ctx, calls };
|
|
21
|
-
}
|
|
22
|
-
const contractId = (0, peer_id_1.newid)();
|
|
23
|
-
const invokeInput = index_1.z.object({
|
|
24
|
-
tool: index_1.z.string().describe("Catalog tool name."),
|
|
25
|
-
args: index_1.z.object({}).passthrough().optional().describe("Arguments for that tool."),
|
|
26
|
-
});
|
|
27
|
-
const invokeOutput = index_1.z.object({
|
|
28
|
-
result: index_1.z.unknown().optional(),
|
|
29
|
-
speech: index_1.z.string().optional(),
|
|
30
|
-
});
|
|
31
|
-
const catalogSchema = index_1.z.object({ name: index_1.z.string(), slug: index_1.z.string() });
|
|
32
|
-
const alert = (0, index_1.defineEvent)({
|
|
33
|
-
name: "alert",
|
|
34
|
-
description: "Something needs attention.",
|
|
35
|
-
payloadSchema: index_1.z.object({ title: index_1.z.string(), detail: index_1.z.string().optional() }),
|
|
36
|
-
});
|
|
37
|
-
const Notes = (0, index_1.defineTable)({
|
|
38
|
-
name: "Notes",
|
|
39
|
-
description: "Notes.",
|
|
40
|
-
primaryKeyName: "noteId",
|
|
41
|
-
schema: index_1.z.object({ noteId: index_1.zodPeerId, text: index_1.z.string() }),
|
|
42
|
-
});
|
|
43
|
-
const invokeShape = {
|
|
44
|
-
name: "invoke",
|
|
45
|
-
usageDescription: "Run one catalog tool.",
|
|
46
|
-
accessLevel: index_1.AccessLevel.Reader,
|
|
47
|
-
authorityPropagation: "preserve",
|
|
48
|
-
inputSchema: invokeInput,
|
|
49
|
-
outputSchema: invokeOutput,
|
|
50
|
-
};
|
|
51
|
-
const Skill = (0, index_1.declareContract)({
|
|
52
|
-
contractId,
|
|
53
|
-
version: 1,
|
|
54
|
-
name: "Skill",
|
|
55
|
-
description: "A skill.",
|
|
56
|
-
tables: [Notes],
|
|
57
|
-
tools: [(0, index_1.declareTool)(invokeShape)],
|
|
58
|
-
observables: [
|
|
59
|
-
(0, index_1.declareObservable)({ name: "skill", description: "The catalog.", schema: catalogSchema }),
|
|
60
|
-
],
|
|
61
|
-
events: [alert],
|
|
62
|
-
});
|
|
63
|
-
const catalog = (0, index_1.deviceVar)(`skill-${(0, peer_id_1.newid)()}`, { defaultValue: { name: "Timers", slug: "timers" } });
|
|
64
|
-
const handler = async ({ tool }) => ({ speech: tool });
|
|
65
|
-
const packageId = (0, peer_id_1.newid)();
|
|
66
|
-
function manifestOf(contract) {
|
|
67
|
-
return (0, manifest_1.buildPackageManifest)((0, index_1.definePackage)((pkg) => {
|
|
68
|
-
pkg.packageId = packageId;
|
|
69
|
-
pkg.version = "1.0.0";
|
|
70
|
-
pkg.provides(contract);
|
|
71
|
-
}));
|
|
72
|
-
}
|
|
73
|
-
describe("declareContract", () => {
|
|
74
|
-
test("the declaration is a typed reference that can pick a provider", async () => {
|
|
75
|
-
const { ctx, calls } = fakeContext((method) => method === "callConsumedTool" ? { speech: "ok" } : { name: "Timers", slug: "timers" });
|
|
76
|
-
const result = await Skill(ctx, { providerPackageId: "p1" }).tools.invoke({ tool: "list" });
|
|
77
|
-
const speech = result.speech;
|
|
78
|
-
expect(speech).toBe("ok");
|
|
79
|
-
const value = await Skill(ctx).observables.skill.get();
|
|
80
|
-
expect(value?.slug).toBe("timers");
|
|
81
|
-
await Skill(ctx, { providerPackageId: "p2" }).observables.skill.get();
|
|
82
|
-
expect(calls).toStrictEqual([
|
|
83
|
-
["callConsumedTool", contractId, 1, "invoke", { tool: "list" }, { providerPackageId: "p1" }],
|
|
84
|
-
["getConsumedObservable", contractId, 1, "skill"],
|
|
85
|
-
["getConsumedObservable", contractId, 1, "skill", { providerPackageId: "p2" }],
|
|
86
|
-
]);
|
|
87
|
-
await expect(Skill(ctx, { providerPackageId: "p1" }).tables.Notes.list()).rejects.toThrow(/can't pick a provider/);
|
|
88
|
-
expect(() => Skill(ctx, { providerPackageId: 3 })).toThrow(/package id/);
|
|
89
|
-
for (const providerPackageId of ["", " "]) {
|
|
90
|
-
expect(() => Skill(ctx, { providerPackageId })).toThrow(/non-empty package id/);
|
|
91
|
-
}
|
|
92
|
-
// @ts-expect-error the skill observable is read-only
|
|
93
|
-
expect(typeof Skill(ctx).observables.skill.set).toBe("function");
|
|
94
|
-
// @ts-expect-error invoke needs a tool name
|
|
95
|
-
void Skill(ctx).tools.invoke({});
|
|
96
|
-
expect((0, index_1.isContractDeclaration)(Skill)).toBe(true);
|
|
97
|
-
expect(Skill.declaration.tools.map((tool) => tool.definition.name)).toEqual(["invoke"]);
|
|
98
|
-
});
|
|
99
|
-
test("type-only references and implementation helpers accept the declaration's type", async () => {
|
|
100
|
-
const Literal = (0, index_1.declareContract)({
|
|
101
|
-
contractId: "00muxgugn6xvs8f2r80ru205t",
|
|
102
|
-
version: 3,
|
|
103
|
-
name: "Literal",
|
|
104
|
-
});
|
|
105
|
-
(0, index_1.contractRef)(Literal.contractId, Literal.version);
|
|
106
|
-
// @ts-expect-error the declared id is preserved
|
|
107
|
-
(0, index_1.contractRef)("00mvhostclient00000000001", 3);
|
|
108
|
-
// @ts-expect-error the declared version is preserved
|
|
109
|
-
(0, index_1.contractRef)(Literal.contractId, 4);
|
|
110
|
-
const implementation = {
|
|
111
|
-
tools: { invoke: ({ tool }) => ({ speech: tool }) },
|
|
112
|
-
observables: { skill: catalog },
|
|
113
|
-
};
|
|
114
|
-
const implemented = (0, index_1.implementContract)(Skill, implementation);
|
|
115
|
-
expect(implemented.tools[0].definition.name).toBe("invoke");
|
|
116
|
-
const Ref = (0, index_1.contractRef)(contractId, 1);
|
|
117
|
-
const { ctx } = fakeContext(() => ({ speech: "typed" }));
|
|
118
|
-
const result = await Ref(ctx).tools.invoke({ tool: "list" });
|
|
119
|
-
const speech = result.speech;
|
|
120
|
-
expect(speech).toBe("typed");
|
|
121
|
-
// @ts-expect-error the declared version is 1
|
|
122
|
-
(0, index_1.contractRef)(contractId, 2);
|
|
123
|
-
// @ts-expect-error a type-only reference still requires the tool's input
|
|
124
|
-
void Ref(ctx).tools.invoke({});
|
|
125
|
-
// @ts-expect-error the observable remains read-only through a type-only reference
|
|
126
|
-
void Ref(ctx).observables.skill.set;
|
|
127
|
-
const values = {
|
|
128
|
-
skill: { name: "Timers", slug: "timers" },
|
|
129
|
-
};
|
|
130
|
-
const writable = { skill: false };
|
|
131
|
-
const rows = { Notes: { noteId: (0, peer_id_1.newid)(), text: "typed" } };
|
|
132
|
-
const inputs = rows;
|
|
133
|
-
const payloads = { alert: { title: "typed" } };
|
|
134
|
-
expect([values.skill.slug, writable.skill, inputs.Notes.text, payloads.alert.title]).toEqual([
|
|
135
|
-
"timers",
|
|
136
|
-
false,
|
|
137
|
-
"typed",
|
|
138
|
-
"typed",
|
|
139
|
-
]);
|
|
140
|
-
});
|
|
141
|
-
test("members written inline in the lists keep their names, types, and writability", async () => {
|
|
142
|
-
const tool = (name, inputSchema) => ({
|
|
143
|
-
name,
|
|
144
|
-
usageDescription: "A tool.",
|
|
145
|
-
accessLevel: index_1.AccessLevel.Reader,
|
|
146
|
-
inputSchema,
|
|
147
|
-
outputSchema: index_1.z.object({ ok: index_1.z.boolean() }),
|
|
148
|
-
});
|
|
149
|
-
const Inline = (0, index_1.declareContract)({
|
|
150
|
-
contractId: (0, peer_id_1.newid)(),
|
|
151
|
-
version: 1,
|
|
152
|
-
name: "Inline",
|
|
153
|
-
tools: [
|
|
154
|
-
(0, index_1.declareTool)(tool("count", index_1.z.object({ n: index_1.z.number() }))),
|
|
155
|
-
(0, index_1.declareTool)(tool("label", index_1.z.object({ text: index_1.z.string() }))),
|
|
156
|
-
],
|
|
157
|
-
observables: [
|
|
158
|
-
(0, index_1.declareObservable)({
|
|
159
|
-
name: "level",
|
|
160
|
-
description: "Level.",
|
|
161
|
-
schema: index_1.z.number(),
|
|
162
|
-
writable: true,
|
|
163
|
-
}),
|
|
164
|
-
(0, index_1.declareObservable)({ name: "mode", description: "Mode.", schema: index_1.z.string() }),
|
|
165
|
-
],
|
|
166
|
-
events: [
|
|
167
|
-
(0, index_1.defineEvent)({
|
|
168
|
-
name: "counted",
|
|
169
|
-
description: "C.",
|
|
170
|
-
payloadSchema: index_1.z.object({ n: index_1.z.number() }),
|
|
171
|
-
}),
|
|
172
|
-
(0, index_1.defineEvent)({
|
|
173
|
-
name: "labeled",
|
|
174
|
-
description: "L.",
|
|
175
|
-
payloadSchema: index_1.z.object({ t: index_1.z.string() }),
|
|
176
|
-
}),
|
|
177
|
-
],
|
|
178
|
-
});
|
|
179
|
-
const { ctx } = fakeContext(() => ({ ok: true }));
|
|
180
|
-
await Inline(ctx).tools.label({ text: "a" });
|
|
181
|
-
// @ts-expect-error each tool keeps its own input
|
|
182
|
-
void Inline(ctx).tools.label({ n: 1 });
|
|
183
|
-
// @ts-expect-error a name the contract doesn't declare
|
|
184
|
-
void Inline(ctx).tools.other;
|
|
185
|
-
// @ts-expect-error a read-only observable stays read-only beside a writable one
|
|
186
|
-
void Inline(ctx).observables.mode.set;
|
|
187
|
-
const values = { level: 1, mode: "on" };
|
|
188
|
-
// @ts-expect-error each observable keeps its own value type
|
|
189
|
-
values.mode = 1;
|
|
190
|
-
const payloads = {
|
|
191
|
-
counted: { n: 1 },
|
|
192
|
-
labeled: { t: "a" },
|
|
193
|
-
};
|
|
194
|
-
// @ts-expect-error each event keeps its own payload
|
|
195
|
-
payloads.labeled = { n: 1 };
|
|
196
|
-
// Handlers are typed per tool, and a read-only source may sit beside a writable one.
|
|
197
|
-
const implemented = (0, index_1.implementContract)(Inline, {
|
|
198
|
-
tools: {
|
|
199
|
-
count: ({ n }) => ({ ok: n > 0 }),
|
|
200
|
-
label: ({ text }) => ({ ok: text.length > 0 }),
|
|
201
|
-
},
|
|
202
|
-
observables: { level: (0, index_1.observable)(0), mode: (0, index_1.observable)("on") },
|
|
203
|
-
});
|
|
204
|
-
expect(implemented.tools.map((member) => member.definition.name)).toEqual(["count", "label"]);
|
|
205
|
-
const Defined = (0, index_1.defineContract)({
|
|
206
|
-
contractId: (0, peer_id_1.newid)(),
|
|
207
|
-
version: 1,
|
|
208
|
-
name: "Defined",
|
|
209
|
-
tools: [
|
|
210
|
-
(0, index_1.defineTool)({
|
|
211
|
-
...tool("count", index_1.z.object({ n: index_1.z.number() })),
|
|
212
|
-
handler: ({ n }) => ({ ok: n > 0 }),
|
|
213
|
-
}),
|
|
214
|
-
],
|
|
215
|
-
observables: [
|
|
216
|
-
(0, index_1.defineObservable)({
|
|
217
|
-
name: "level",
|
|
218
|
-
description: "Level.",
|
|
219
|
-
schema: index_1.z.number(),
|
|
220
|
-
writable: true,
|
|
221
|
-
source: (0, index_1.observable)(0),
|
|
222
|
-
}),
|
|
223
|
-
(0, index_1.defineObservable)({
|
|
224
|
-
name: "mode",
|
|
225
|
-
description: "Mode.",
|
|
226
|
-
schema: index_1.z.string(),
|
|
227
|
-
source: (0, index_1.observable)("on"),
|
|
228
|
-
}),
|
|
229
|
-
],
|
|
230
|
-
});
|
|
231
|
-
const Ref = (0, index_1.contractRef)(Defined.contractId, 1);
|
|
232
|
-
// @ts-expect-error defineContract's inline members keep their names too
|
|
233
|
-
void Ref(ctx).tools.other;
|
|
234
|
-
// @ts-expect-error and their writability
|
|
235
|
-
void Ref(ctx).observables.mode.set;
|
|
236
|
-
});
|
|
237
|
-
test("a tools-only reference can still have a tool named declaration", async () => {
|
|
238
|
-
const Ref = (0, index_1.contractRef)(contractId, 1);
|
|
239
|
-
const { ctx } = fakeContext(() => ({ speech: "done" }));
|
|
240
|
-
const { speech } = await Ref(ctx).tools.declaration({ label: "ready" });
|
|
241
|
-
const value = speech;
|
|
242
|
-
expect(value).toBe("done");
|
|
243
|
-
});
|
|
244
|
-
test("observable writes forward the provider and snapshot values, with no options by default", async () => {
|
|
245
|
-
const State = (0, index_1.declareContract)({
|
|
246
|
-
contractId: (0, peer_id_1.newid)(),
|
|
247
|
-
version: 1,
|
|
248
|
-
name: "State",
|
|
249
|
-
observables: [
|
|
250
|
-
(0, index_1.declareObservable)({
|
|
251
|
-
name: "value",
|
|
252
|
-
description: "Writable state.",
|
|
253
|
-
schema: index_1.z.object({ label: index_1.z.string(), detail: index_1.z.string().optional() }),
|
|
254
|
-
writable: true,
|
|
255
|
-
}),
|
|
256
|
-
],
|
|
257
|
-
});
|
|
258
|
-
const { ctx, calls } = fakeContext((_method, args) => args[3]);
|
|
259
|
-
const value = { label: "ready", detail: undefined };
|
|
260
|
-
await State(ctx).observables.value.set(value);
|
|
261
|
-
await State(ctx, { providerPackageId: "p1" }).observables.value.set(value);
|
|
262
|
-
expect(calls).toEqual([
|
|
263
|
-
["setConsumedObservable", State.contractId, 1, "value", { label: "ready" }],
|
|
264
|
-
[
|
|
265
|
-
"setConsumedObservable",
|
|
266
|
-
State.contractId,
|
|
267
|
-
1,
|
|
268
|
-
"value",
|
|
269
|
-
{ label: "ready" },
|
|
270
|
-
{ providerPackageId: "p1" },
|
|
271
|
-
],
|
|
272
|
-
]);
|
|
273
|
-
expect(Object.hasOwn(value, "detail")).toBe(true);
|
|
274
|
-
});
|
|
275
|
-
test("an empty whole observable value is null on the bridge, including a write's reply", async () => {
|
|
276
|
-
const State = (0, index_1.declareContract)({
|
|
277
|
-
contractId: (0, peer_id_1.newid)(),
|
|
278
|
-
version: 1,
|
|
279
|
-
name: "State",
|
|
280
|
-
observables: [
|
|
281
|
-
(0, index_1.declareObservable)({
|
|
282
|
-
name: "value",
|
|
283
|
-
description: "Optional state.",
|
|
284
|
-
schema: index_1.z.string().optional(),
|
|
285
|
-
writable: true,
|
|
286
|
-
}),
|
|
287
|
-
],
|
|
288
|
-
});
|
|
289
|
-
const source = (0, index_1.observable)();
|
|
290
|
-
const Implemented = (0, index_1.implementContract)(State, { observables: { value: source } });
|
|
291
|
-
const handlers = [];
|
|
292
|
-
(0, serve_members_1.serveContractMembers)(Implemented, (_name, handler) => handlers.push(handler));
|
|
293
|
-
const { ctx } = fakeContext((method, args) => handlers[0]({
|
|
294
|
-
member: "observable",
|
|
295
|
-
name: "value",
|
|
296
|
-
operation: method === "getConsumedObservable" ? "get" : "set",
|
|
297
|
-
args: method === "getConsumedObservable" ? [] : [args[3] ?? null],
|
|
298
|
-
}, ctx));
|
|
299
|
-
await (0, index_1.startPackage)((0, index_1.definePackage)((pkg) => {
|
|
300
|
-
pkg.packageId = (0, peer_id_1.newid)();
|
|
301
|
-
pkg.version = "1.0.0";
|
|
302
|
-
pkg.provides(Implemented);
|
|
303
|
-
}), fakeContext().ctx);
|
|
304
|
-
const read = await State(ctx).observables.value.get();
|
|
305
|
-
// The type must allow what the provider's member handler actually returns.
|
|
306
|
-
const emptyRead = null;
|
|
307
|
-
expect(read).toBe(emptyRead);
|
|
308
|
-
// A provider's subscribers can adjust the value before it replies to the write.
|
|
309
|
-
source.subscribe(() => source(undefined));
|
|
310
|
-
const written = await State(ctx).observables.value.set("clear");
|
|
311
|
-
const emptyWrite = null;
|
|
312
|
-
expect(written).toBe(emptyWrite);
|
|
313
|
-
// @ts-expect-error undefined crosses the bridge as null, which this schema refuses
|
|
314
|
-
const missingWrite = State(ctx).observables.value.set(undefined);
|
|
315
|
-
await expect(missingWrite).rejects.toThrow(/null/);
|
|
316
|
-
});
|
|
317
|
-
test("a consumer lists the declaration itself", () => {
|
|
318
|
-
const manifest = (0, manifest_1.buildPackageManifest)((0, index_1.definePackage)((pkg) => {
|
|
319
|
-
pkg.packageId = (0, peer_id_1.newid)();
|
|
320
|
-
pkg.version = "1.0.0";
|
|
321
|
-
pkg.consumes(Skill, { optional: true });
|
|
322
|
-
}));
|
|
323
|
-
expect(manifest.consumes).toEqual([{ contractId, version: 1, optional: true }]);
|
|
324
|
-
});
|
|
325
|
-
test("refuses members that carry an implementation", () => {
|
|
326
|
-
const base = { contractId, version: 1, name: "Bad" };
|
|
327
|
-
expect(() => (0, index_1.declareContract)({ ...base, tools: [(0, index_1.defineTool)({ ...invokeShape, handler })] })).toThrow('tool "invoke" has a handler');
|
|
328
|
-
expect(() => (0, index_1.declareContract)({
|
|
329
|
-
...base,
|
|
330
|
-
observables: [
|
|
331
|
-
(0, index_1.defineObservable)({
|
|
332
|
-
name: "skill",
|
|
333
|
-
description: "The catalog.",
|
|
334
|
-
schema: catalogSchema,
|
|
335
|
-
source: (0, index_1.observable)({ name: "a", slug: "a" }),
|
|
336
|
-
}),
|
|
337
|
-
],
|
|
338
|
-
})).toThrow('observable "skill" has a source');
|
|
339
|
-
class NotesTable extends index_1.PackageTable {
|
|
340
|
-
}
|
|
341
|
-
expect(() => (0, index_1.declareContract)({
|
|
342
|
-
...base,
|
|
343
|
-
tables: [(0, index_1.defineTable)({ ...Notes.definition, tableClass: NotesTable })],
|
|
344
|
-
})).toThrow('table "Notes" has a tableClass');
|
|
345
|
-
expect(() => (0, index_1.declareContract)({ ...base, contractId: "short" })).toThrow(/25-character/);
|
|
346
|
-
expect(() => (0, index_1.declareContract)({ ...base, tools: [(0, index_1.declareTool)(invokeShape), (0, index_1.declareTool)(invokeShape)] })).toThrow(/twice/);
|
|
347
|
-
expect(() => (0, index_1.declareTool)({ ...invokeShape, handler })).toThrow(/takes no handler/);
|
|
348
|
-
expect(() => (0, index_1.declareObservable)({
|
|
349
|
-
name: "skill",
|
|
350
|
-
description: "The catalog.",
|
|
351
|
-
schema: catalogSchema,
|
|
352
|
-
source: (0, index_1.observable)(null),
|
|
353
|
-
})).toThrow(/takes no source/);
|
|
354
|
-
});
|
|
355
|
-
test("recognizing an observable declaration does not claim it has a source", () => {
|
|
356
|
-
const declared = (0, index_1.declareObservable)({
|
|
357
|
-
name: "value",
|
|
358
|
-
description: "Value.",
|
|
359
|
-
schema: index_1.z.number(),
|
|
360
|
-
});
|
|
361
|
-
expect((0, observables_1.isPackageObservable)(declared)).toBe(true);
|
|
362
|
-
expect((0, observables_1.isImplementedObservable)(declared)).toBe(false);
|
|
363
|
-
if ((0, observables_1.isPackageObservable)(declared)) {
|
|
364
|
-
// @ts-expect-error recognizing the observable kind does not add an implementation
|
|
365
|
-
void declared.definition.source;
|
|
366
|
-
}
|
|
367
|
-
const implemented = (0, index_1.defineObservable)({
|
|
368
|
-
name: "value",
|
|
369
|
-
description: "Value.",
|
|
370
|
-
schema: index_1.z.number(),
|
|
371
|
-
source: (0, index_1.observable)(0),
|
|
372
|
-
});
|
|
373
|
-
expect((0, observables_1.isImplementedObservable)(implemented)).toBe(true);
|
|
374
|
-
});
|
|
375
|
-
});
|
|
376
|
-
describe("implementContract", () => {
|
|
377
|
-
test("only read-only declarations accept a source with a narrower value type", () => {
|
|
378
|
-
const shape = {
|
|
379
|
-
name: "mode",
|
|
380
|
-
description: "The mode.",
|
|
381
|
-
schema: index_1.z.enum(["on", "off"]),
|
|
382
|
-
};
|
|
383
|
-
const ReadOnly = (0, index_1.declareContract)({
|
|
384
|
-
contractId: (0, peer_id_1.newid)(),
|
|
385
|
-
version: 1,
|
|
386
|
-
name: "Read-only mode",
|
|
387
|
-
observables: [(0, index_1.declareObservable)(shape)],
|
|
388
|
-
});
|
|
389
|
-
const Writable = (0, index_1.declareContract)({
|
|
390
|
-
contractId: (0, peer_id_1.newid)(),
|
|
391
|
-
version: 1,
|
|
392
|
-
name: "Writable mode",
|
|
393
|
-
observables: [(0, index_1.declareObservable)({ ...shape, writable: true })],
|
|
394
|
-
});
|
|
395
|
-
const narrow = (0, index_1.observable)("on");
|
|
396
|
-
// Read-only consumers can't give the narrower source a value outside its own type.
|
|
397
|
-
(0, index_1.implementContract)(ReadOnly, { observables: { mode: narrow } });
|
|
398
|
-
(0, index_1.implementContract)(Writable, {
|
|
399
|
-
// @ts-expect-error this source's subscribers only accept "on", but consumers can write "off"
|
|
400
|
-
observables: { mode: narrow },
|
|
401
|
-
});
|
|
402
|
-
(0, index_1.implementContract)(Writable, {
|
|
403
|
-
// @ts-expect-error explicit type arguments must also reject a narrower writable source
|
|
404
|
-
observables: { mode: narrow },
|
|
405
|
-
});
|
|
406
|
-
const invalid = {
|
|
407
|
-
// @ts-expect-error a typed implementation must reject a narrower writable source too
|
|
408
|
-
observables: { mode: narrow },
|
|
409
|
-
};
|
|
410
|
-
// Read-only sources keep their covariance even in a typed implementation.
|
|
411
|
-
const readOnly = { observables: { mode: narrow } };
|
|
412
|
-
(0, index_1.implementContract)(ReadOnly, readOnly);
|
|
413
|
-
void invalid;
|
|
414
|
-
const source = (0, index_1.observable)("on");
|
|
415
|
-
const implemented = (0, index_1.implementContract)(Writable, { observables: { mode: source } });
|
|
416
|
-
expect(implemented.observables[0].definition.source).toBe(source);
|
|
417
|
-
// Explicit declaration type arguments keep valid implementations working too.
|
|
418
|
-
(0, index_1.implementContract)(Writable, { observables: { mode: source } });
|
|
419
|
-
expect(() => (0, index_1.implementContract)(Writable, {
|
|
420
|
-
// @ts-expect-error the source map must still refuse undeclared names
|
|
421
|
-
observables: { mode: source, extra: source },
|
|
422
|
-
})).toThrow('declares no observable "extra"');
|
|
423
|
-
});
|
|
424
|
-
test("the manifest is the declared shape with the provider's handler and source", async () => {
|
|
425
|
-
const Implemented = (0, index_1.implementContract)(Skill, {
|
|
426
|
-
tools: { invoke: { handler, timeoutMs: 90_000 } },
|
|
427
|
-
observables: { skill: catalog },
|
|
428
|
-
});
|
|
429
|
-
const [declaredTool] = Skill.declaration.tools;
|
|
430
|
-
const [declaredObservable] = Skill.declaration.observables;
|
|
431
|
-
const Same = (0, index_1.defineContract)({
|
|
432
|
-
contractId,
|
|
433
|
-
version: 1,
|
|
434
|
-
name: "Skill",
|
|
435
|
-
description: "A skill.",
|
|
436
|
-
tables: [Notes],
|
|
437
|
-
tools: [(0, index_1.defineTool)({ ...declaredTool.definition, timeoutMs: 90_000, handler })],
|
|
438
|
-
observables: [
|
|
439
|
-
(0, index_1.defineObservable)({ ...declaredObservable.definition, source: catalog }),
|
|
440
|
-
],
|
|
441
|
-
events: [alert],
|
|
442
|
-
});
|
|
443
|
-
const manifest = manifestOf(Implemented);
|
|
444
|
-
expect(manifest).toEqual(manifestOf(Same));
|
|
445
|
-
const [tool] = manifest.provides[0].tools;
|
|
446
|
-
expect(tool).toMatchObject({
|
|
447
|
-
name: "invoke",
|
|
448
|
-
suggestedAccessLevel: index_1.AccessLevel.Reader,
|
|
449
|
-
authorityPropagation: "preserve",
|
|
450
|
-
timeoutMs: 90_000,
|
|
451
|
-
});
|
|
452
|
-
expect(manifest.provides[0].observables?.[0].persistentVar).toMatchObject({
|
|
453
|
-
scope: "device",
|
|
454
|
-
defaultValue: { name: "Timers", slug: "timers" },
|
|
455
|
-
});
|
|
456
|
-
expect(() => (0, isolated_artifact_1.validateIsolatedPackageArtifact)({ manifest, providerSource: "void 0;" }, { strict: true })).not.toThrow();
|
|
457
|
-
const { ctx } = fakeContext();
|
|
458
|
-
// The declared schema parses the input, empty optional fields left out.
|
|
459
|
-
await expect((0, index_1.runPackageTool)(Implemented.tools[0], { tool: "list", args: null }, ctx)).resolves.toEqual({ speech: "list" });
|
|
460
|
-
});
|
|
461
|
-
test("the declaration's event goes out on the implemented contract", async () => {
|
|
462
|
-
const Implemented = (0, index_1.implementContract)(Skill, {
|
|
463
|
-
tools: { invoke: handler },
|
|
464
|
-
observables: { skill: catalog },
|
|
465
|
-
});
|
|
466
|
-
const calls = [];
|
|
467
|
-
const ctx = {
|
|
468
|
-
emitContractEvent: async (...args) => {
|
|
469
|
-
calls.push(args);
|
|
470
|
-
return null;
|
|
471
|
-
},
|
|
472
|
-
getOwnedPersistentVar: async () => null,
|
|
473
|
-
watchOwnedPersistentVar: async () => () => undefined,
|
|
474
|
-
};
|
|
475
|
-
await (0, index_1.startPackage)((0, index_1.definePackage)((pkg) => {
|
|
476
|
-
pkg.packageId = (0, peer_id_1.newid)();
|
|
477
|
-
pkg.version = "1.0.0";
|
|
478
|
-
pkg.provides(Implemented);
|
|
479
|
-
}), ctx);
|
|
480
|
-
await alert.emit({ title: "Done" });
|
|
481
|
-
expect(calls).toEqual([[contractId, 1, "alert", { title: "Done" }]]);
|
|
482
|
-
});
|
|
483
|
-
test("refuses a missing, extra, or unknown member", () => {
|
|
484
|
-
const observables = { skill: catalog };
|
|
485
|
-
expect(() => (0, index_1.implementContract)(Skill, { tools: {}, observables })).toThrow('implement tool "invoke" with a handler');
|
|
486
|
-
expect(() => (0, index_1.implementContract)(Skill, {
|
|
487
|
-
tools: { invoke: handler, other: handler },
|
|
488
|
-
observables,
|
|
489
|
-
})).toThrow('declares no tool "other"');
|
|
490
|
-
expect(() => (0, index_1.implementContract)(Skill, { tools: { invoke: handler }, observables: {} })).toThrow('implement observable "skill" with a source');
|
|
491
|
-
expect(() => (0, index_1.implementContract)(Skill, {
|
|
492
|
-
tools: { invoke: { handler, accessLevel: 0 } },
|
|
493
|
-
observables,
|
|
494
|
-
})).toThrow(/handler and timeoutMs only, not accessLevel/);
|
|
495
|
-
expect(() => (0, index_1.implementContract)(Skill, {
|
|
496
|
-
tools: { invoke: handler },
|
|
497
|
-
observables,
|
|
498
|
-
tables: {},
|
|
499
|
-
})).toThrow(/tools, observables, exposes, and alsoImplements, not tables/);
|
|
500
|
-
expect(() => (0, index_1.implementContract)((0, index_1.defineContract)({ contractId, version: 1, name: "X" }), {})).toThrow(/takes a declaration/);
|
|
501
|
-
// Types follow the declaration.
|
|
502
|
-
(0, index_1.implementContract)(Skill, {
|
|
503
|
-
// @ts-expect-error speech is a string
|
|
504
|
-
tools: { invoke: () => ({ speech: 1 }) },
|
|
505
|
-
observables,
|
|
506
|
-
});
|
|
507
|
-
(0, index_1.implementContract)(Skill, {
|
|
508
|
-
tools: { invoke: handler },
|
|
509
|
-
// @ts-expect-error the source must hold the declared value
|
|
510
|
-
observables: { skill: (0, index_1.observable)(3) },
|
|
511
|
-
});
|
|
512
|
-
});
|
|
513
|
-
test("exposes other contracts the package provides, outside the contract's shape", () => {
|
|
514
|
-
const News = (0, index_1.defineContract)({
|
|
515
|
-
contractId: (0, peer_id_1.newid)(),
|
|
516
|
-
version: 1,
|
|
517
|
-
name: "News",
|
|
518
|
-
tools: [
|
|
519
|
-
(0, index_1.defineTool)({
|
|
520
|
-
name: "headlines",
|
|
521
|
-
usageDescription: "Recent headlines.",
|
|
522
|
-
accessLevel: index_1.AccessLevel.Reader,
|
|
523
|
-
inputSchema: index_1.z.object({}),
|
|
524
|
-
outputSchema: index_1.z.object({}),
|
|
525
|
-
handler: async () => ({}),
|
|
526
|
-
}),
|
|
527
|
-
],
|
|
528
|
-
});
|
|
529
|
-
const members = { tools: { invoke: handler }, observables: { skill: catalog } };
|
|
530
|
-
const Implemented = (0, index_1.implementContract)(Skill, { ...members, exposes: [News] });
|
|
531
|
-
expect(Implemented.exposes).toEqual([{ contractId: News.contractId, version: 1 }]);
|
|
532
|
-
// A reference names the contract as well as the contract itself does.
|
|
533
|
-
expect((0, index_1.implementContract)(Skill, { ...members, exposes: [(0, index_1.contractRef)(News.contractId, 1)] }).exposes).toEqual(Implemented.exposes);
|
|
534
|
-
const manifest = (0, manifest_1.buildPackageManifest)((0, index_1.definePackage)((pkg) => {
|
|
535
|
-
pkg.packageId = packageId;
|
|
536
|
-
pkg.version = "1.0.0";
|
|
537
|
-
pkg.provides(News);
|
|
538
|
-
pkg.provides(Implemented);
|
|
539
|
-
}));
|
|
540
|
-
expect(manifest.provides[1].exposes).toEqual([{ contractId: News.contractId, version: 1 }]);
|
|
541
|
-
expect(manifest.provides[0]).not.toHaveProperty("exposes");
|
|
542
|
-
// The validator fills in defaults, so it checks a copy.
|
|
543
|
-
expect(() => (0, isolated_artifact_1.validateIsolatedPackageArtifact)({ manifest: JSON.parse(JSON.stringify(manifest)), providerSource: "void 0;" }, { strict: true })).not.toThrow();
|
|
544
|
-
// Everything but `exposes` is the contract as implemented without it.
|
|
545
|
-
const { exposes: _exposes, ...shape } = manifest.provides[1];
|
|
546
|
-
expect(shape).toEqual(manifestOf((0, index_1.implementContract)(Skill, members)).provides[0]);
|
|
547
|
-
// An implementation without `exposes` carries none.
|
|
548
|
-
expect((0, index_1.implementContract)(Skill, members)).not.toHaveProperty("exposes");
|
|
549
|
-
});
|
|
550
|
-
test("refuses exposing itself, a contract twice, or one the package doesn't provide", () => {
|
|
551
|
-
const members = { tools: { invoke: handler }, observables: { skill: catalog } };
|
|
552
|
-
const other = { contractId: (0, peer_id_1.newid)(), version: 1 };
|
|
553
|
-
expect(() => (0, index_1.implementContract)(Skill, { ...members, exposes: [Skill] })).toThrow(/can't expose itself/);
|
|
554
|
-
expect(() => (0, index_1.implementContract)(Skill, { ...members, exposes: [other, other] })).toThrow(/exposes .* twice/);
|
|
555
|
-
expect(() => (0, index_1.implementContract)(Skill, { ...members, exposes: other })).toThrow(/exposes must be a list of contracts/);
|
|
556
|
-
expect(() => (0, index_1.implementContract)(Skill, { ...members, exposes: [{ contractId: "x", version: 1 }] })).toThrow(/with an id and version/);
|
|
557
|
-
expect(() => (0, index_1.definePackage)((pkg) => {
|
|
558
|
-
pkg.packageId = (0, peer_id_1.newid)();
|
|
559
|
-
pkg.version = "1.0.0";
|
|
560
|
-
pkg.provides((0, index_1.implementContract)(Skill, { ...members, exposes: [other] }));
|
|
561
|
-
})).toThrow(/exposes .*, which the package doesn't provide; add it with pkg.provides/);
|
|
562
|
-
});
|
|
563
|
-
test("defineContract and pkg.provides refuse what isn't implemented", () => {
|
|
564
|
-
const base = { contractId, version: 1, name: "X" };
|
|
565
|
-
expect(() => (0, index_1.defineContract)({ ...base, tools: [Skill.declaration.tools[0]] })).toThrow(/has no handler; .*declareContract and implementContract/);
|
|
566
|
-
expect(() => (0, index_1.defineContract)({ ...base, observables: [Skill.declaration.observables[0]] })).toThrow(/has no source/);
|
|
567
|
-
expect(() => (0, index_1.definePackage)((pkg) => {
|
|
568
|
-
pkg.packageId = (0, peer_id_1.newid)();
|
|
569
|
-
pkg.version = "1.0.0";
|
|
570
|
-
pkg.provides(Skill);
|
|
571
|
-
})).toThrow(/implementContract first/);
|
|
572
|
-
});
|
|
573
|
-
});
|
|
@@ -1 +0,0 @@
|
|
|
1
|
-
export {};
|