@peers-app/peers-sdk 0.27.2 → 0.27.4

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (260) hide show
  1. package/dist/contracts/contract-proxy.d.ts +7 -0
  2. package/dist/contracts/contract-proxy.js +19 -2
  3. package/dist/contracts/create-local-consumer.js +16 -1
  4. package/dist/contracts/index.d.ts +2 -0
  5. package/dist/contracts/index.js +2 -0
  6. package/dist/contracts/system/index.d.ts +2 -0
  7. package/dist/contracts/system/index.js +2 -0
  8. package/dist/contracts/system/invites-contract.js +2 -1
  9. package/dist/contracts/system/sync-check-contract.d.ts +97 -0
  10. package/dist/contracts/system/sync-check-contract.js +115 -0
  11. package/dist/contracts/tool-arguments.d.ts +15 -0
  12. package/dist/contracts/tool-arguments.js +41 -0
  13. package/dist/contracts/tool-catalog-service.js +2 -12
  14. package/dist/data/change-tracking.d.ts +40 -0
  15. package/dist/data/change-tracking.js +89 -0
  16. package/dist/data/orm/types.d.ts +24 -7
  17. package/dist/data/orm/types.js +97 -24
  18. package/dist/data/persistent-vars.d.ts +5 -0
  19. package/dist/data/persistent-vars.js +24 -6
  20. package/dist/define/manifest.js +6 -34
  21. package/dist/package-loader/package-loader.js +27 -22
  22. package/dist/system-ids.d.ts +5 -0
  23. package/dist/system-ids.js +6 -1
  24. package/package.json +4 -2
  25. package/dist/context/user-context-identity.test.d.ts +0 -1
  26. package/dist/context/user-context-identity.test.js +0 -220
  27. package/dist/contracts/__tests__/action-dispatch.test.d.ts +0 -1
  28. package/dist/contracts/__tests__/action-dispatch.test.js +0 -319
  29. package/dist/contracts/__tests__/also-implements.test.d.ts +0 -1
  30. package/dist/contracts/__tests__/also-implements.test.js +0 -110
  31. package/dist/contracts/__tests__/builder.test.d.ts +0 -1
  32. package/dist/contracts/__tests__/builder.test.js +0 -669
  33. package/dist/contracts/__tests__/contract-events.test.d.ts +0 -1
  34. package/dist/contracts/__tests__/contract-events.test.js +0 -199
  35. package/dist/contracts/__tests__/contract-observables.test.d.ts +0 -1
  36. package/dist/contracts/__tests__/contract-observables.test.js +0 -290
  37. package/dist/contracts/__tests__/contract-provider-router.test.d.ts +0 -1
  38. package/dist/contracts/__tests__/contract-provider-router.test.js +0 -315
  39. package/dist/contracts/__tests__/contract-proxy.test.d.ts +0 -1
  40. package/dist/contracts/__tests__/contract-proxy.test.js +0 -657
  41. package/dist/contracts/__tests__/contract-resolvers.test.d.ts +0 -1
  42. package/dist/contracts/__tests__/contract-resolvers.test.js +0 -758
  43. package/dist/contracts/__tests__/contract-subscription-lifecycle.test.d.ts +0 -1
  44. package/dist/contracts/__tests__/contract-subscription-lifecycle.test.js +0 -353
  45. package/dist/contracts/__tests__/contract-table-events.test.d.ts +0 -1
  46. package/dist/contracts/__tests__/contract-table-events.test.js +0 -209
  47. package/dist/contracts/__tests__/contract-transport.test.d.ts +0 -1
  48. package/dist/contracts/__tests__/contract-transport.test.js +0 -163
  49. package/dist/contracts/__tests__/extract.test.d.ts +0 -1
  50. package/dist/contracts/__tests__/extract.test.js +0 -145
  51. package/dist/contracts/__tests__/frozen-contracts.test.d.ts +0 -1
  52. package/dist/contracts/__tests__/frozen-contracts.test.js +0 -191
  53. package/dist/contracts/__tests__/generic-tool-dispatch.test.d.ts +0 -1
  54. package/dist/contracts/__tests__/generic-tool-dispatch.test.js +0 -130
  55. package/dist/contracts/__tests__/host-contract-client.test.d.ts +0 -1
  56. package/dist/contracts/__tests__/host-contract-client.test.js +0 -793
  57. package/dist/contracts/__tests__/host-contract-consumer.test.d.ts +0 -1
  58. package/dist/contracts/__tests__/host-contract-consumer.test.js +0 -163
  59. package/dist/contracts/__tests__/host-contract-transport.test.d.ts +0 -1
  60. package/dist/contracts/__tests__/host-contract-transport.test.js +0 -66
  61. package/dist/contracts/__tests__/integration.test.d.ts +0 -1
  62. package/dist/contracts/__tests__/integration.test.js +0 -348
  63. package/dist/contracts/__tests__/legacy-removal.test.d.ts +0 -1
  64. package/dist/contracts/__tests__/legacy-removal.test.js +0 -128
  65. package/dist/contracts/__tests__/persistent-registry.test.d.ts +0 -1
  66. package/dist/contracts/__tests__/persistent-registry.test.js +0 -109
  67. package/dist/contracts/__tests__/playground.test.d.ts +0 -1
  68. package/dist/contracts/__tests__/playground.test.js +0 -216
  69. package/dist/contracts/__tests__/registry.test.d.ts +0 -1
  70. package/dist/contracts/__tests__/registry.test.js +0 -238
  71. package/dist/contracts/__tests__/remote-contract-transport.test.d.ts +0 -1
  72. package/dist/contracts/__tests__/remote-contract-transport.test.js +0 -119
  73. package/dist/contracts/__tests__/system-contracts.test.d.ts +0 -1
  74. package/dist/contracts/__tests__/system-contracts.test.js +0 -247
  75. package/dist/contracts/__tests__/target-dispatch.d.ts +0 -11
  76. package/dist/contracts/__tests__/target-dispatch.js +0 -24
  77. package/dist/contracts/__tests__/tool-catalog-inventory.test.d.ts +0 -1
  78. package/dist/contracts/__tests__/tool-catalog-inventory.test.js +0 -44
  79. package/dist/contracts/__tests__/tool-catalog-service.test.d.ts +0 -1
  80. package/dist/contracts/__tests__/tool-catalog-service.test.js +0 -482
  81. package/dist/contracts/__tests__/tool-catalog.test.d.ts +0 -1
  82. package/dist/contracts/__tests__/tool-catalog.test.js +0 -1199
  83. package/dist/contracts/__tests__/validate.test.d.ts +0 -1
  84. package/dist/contracts/__tests__/validate.test.js +0 -991
  85. package/dist/contracts/__tests__/workflow-context.test.d.ts +0 -1
  86. package/dist/contracts/__tests__/workflow-context.test.js +0 -50
  87. package/dist/data/access-level.test.d.ts +0 -1
  88. package/dist/data/access-level.test.js +0 -53
  89. package/dist/data/change-tracking.test.d.ts +0 -1
  90. package/dist/data/change-tracking.test.js +0 -62
  91. package/dist/data/files/files.test.d.ts +0 -1
  92. package/dist/data/files/files.test.js +0 -770
  93. package/dist/data/group-members.test.d.ts +0 -1
  94. package/dist/data/group-members.test.js +0 -336
  95. package/dist/data/group-share.test.d.ts +0 -1
  96. package/dist/data/group-share.test.js +0 -110
  97. package/dist/data/groups.test.d.ts +0 -1
  98. package/dist/data/groups.test.js +0 -153
  99. package/dist/data/orm/cursor.test.d.ts +0 -1
  100. package/dist/data/orm/cursor.test.js +0 -314
  101. package/dist/data/orm/data-query.mongo.test.d.ts +0 -1
  102. package/dist/data/orm/data-query.mongo.test.js +0 -367
  103. package/dist/data/orm/data-query.sqlite.test.d.ts +0 -1
  104. package/dist/data/orm/data-query.sqlite.test.js +0 -365
  105. package/dist/data/orm/data-query.test.d.ts +0 -1
  106. package/dist/data/orm/data-query.test.js +0 -545
  107. package/dist/data/orm/dependency-injection.test.d.ts +0 -1
  108. package/dist/data/orm/dependency-injection.test.js +0 -171
  109. package/dist/data/orm/event-registry.test.d.ts +0 -1
  110. package/dist/data/orm/event-registry.test.js +0 -44
  111. package/dist/data/orm/multi-cursors.test.d.ts +0 -1
  112. package/dist/data/orm/multi-cursors.test.js +0 -463
  113. package/dist/data/orm/sql.data-source.test.d.ts +0 -1
  114. package/dist/data/orm/sql.data-source.test.js +0 -731
  115. package/dist/data/orm/table-container-events.test.d.ts +0 -1
  116. package/dist/data/orm/table-container-events.test.js +0 -101
  117. package/dist/data/orm/table-container.test.d.ts +0 -1
  118. package/dist/data/orm/table-container.test.js +0 -273
  119. package/dist/data/orm/table.event-source.test.d.ts +0 -1
  120. package/dist/data/orm/table.event-source.test.js +0 -331
  121. package/dist/data/orm/types.test.d.ts +0 -1
  122. package/dist/data/orm/types.test.js +0 -409
  123. package/dist/data/package-table-identity.test.d.ts +0 -1
  124. package/dist/data/package-table-identity.test.js +0 -46
  125. package/dist/data/package-version-permissions.test.d.ts +0 -1
  126. package/dist/data/package-version-permissions.test.js +0 -107
  127. package/dist/data/package-version-resolver.test.d.ts +0 -4
  128. package/dist/data/package-version-resolver.test.js +0 -543
  129. package/dist/data/package-versions.test.d.ts +0 -1
  130. package/dist/data/package-versions.test.js +0 -227
  131. package/dist/data/persistent-vars.conflict.test.d.ts +0 -1
  132. package/dist/data/persistent-vars.conflict.test.js +0 -126
  133. package/dist/data/persistent-vars.migration.test.d.ts +0 -1
  134. package/dist/data/persistent-vars.migration.test.js +0 -133
  135. package/dist/data/persistent-vars.package-scope.test.d.ts +0 -1
  136. package/dist/data/persistent-vars.package-scope.test.js +0 -27
  137. package/dist/data/sync-recovery-queue.test.d.ts +0 -1
  138. package/dist/data/sync-recovery-queue.test.js +0 -215
  139. package/dist/data/table-signing.test.d.ts +0 -1
  140. package/dist/data/table-signing.test.js +0 -118
  141. package/dist/data/tool-access.test.d.ts +0 -1
  142. package/dist/data/tool-access.test.js +0 -166
  143. package/dist/data/user-permissions.test.d.ts +0 -1
  144. package/dist/data/user-permissions.test.js +0 -305
  145. package/dist/data/user-trust-levels.test.d.ts +0 -1
  146. package/dist/data/user-trust-levels.test.js +0 -37
  147. package/dist/define/also-implements.test.d.ts +0 -1
  148. package/dist/define/also-implements.test.js +0 -123
  149. package/dist/define/declare-contract.test.d.ts +0 -1
  150. package/dist/define/declare-contract.test.js +0 -573
  151. package/dist/define/define.test.d.ts +0 -1
  152. package/dist/define/define.test.js +0 -1010
  153. package/dist/define/empty-fields.test.d.ts +0 -1
  154. package/dist/define/empty-fields.test.js +0 -55
  155. package/dist/define/events-observables.test.d.ts +0 -1
  156. package/dist/define/events-observables.test.js +0 -1013
  157. package/dist/define/serve-members.test.d.ts +0 -1
  158. package/dist/define/serve-members.test.js +0 -630
  159. package/dist/define/vars.test.d.ts +0 -1
  160. package/dist/define/vars.test.js +0 -39
  161. package/dist/device/binary-peer-connection-v2.test.d.ts +0 -1
  162. package/dist/device/binary-peer-connection-v2.test.js +0 -730
  163. package/dist/device/binary-peer-connection.test.d.ts +0 -1
  164. package/dist/device/binary-peer-connection.test.js +0 -184
  165. package/dist/device/connection.test.d.ts +0 -1
  166. package/dist/device/connection.test.js +0 -613
  167. package/dist/device/device-election.test.d.ts +0 -1
  168. package/dist/device/device-election.test.js +0 -516
  169. package/dist/device/device.test.d.ts +0 -1
  170. package/dist/device/device.test.js +0 -243
  171. package/dist/device/frame-cipher.test.d.ts +0 -1
  172. package/dist/device/frame-cipher.test.js +0 -219
  173. package/dist/device/get-trust-level-fn.test.d.ts +0 -1
  174. package/dist/device/get-trust-level-fn.test.js +0 -685
  175. package/dist/device/streamed-socket.test.d.ts +0 -1
  176. package/dist/device/streamed-socket.test.js +0 -216
  177. package/dist/device/tx-encoding.test.d.ts +0 -1
  178. package/dist/device/tx-encoding.test.js +0 -295
  179. package/dist/device-pairing/cpace.test.d.ts +0 -1
  180. package/dist/device-pairing/cpace.test.js +0 -116
  181. package/dist/device-pairing/device-pairing.test.d.ts +0 -1
  182. package/dist/device-pairing/device-pairing.test.js +0 -211
  183. package/dist/hlc.test.d.ts +0 -1
  184. package/dist/hlc.test.js +0 -45
  185. package/dist/host-credentials.test.d.ts +0 -1
  186. package/dist/host-credentials.test.js +0 -88
  187. package/dist/identity/account-email.test.d.ts +0 -1
  188. package/dist/identity/account-email.test.js +0 -59
  189. package/dist/identity/anchor-document.test.d.ts +0 -1
  190. package/dist/identity/anchor-document.test.js +0 -16
  191. package/dist/identity/anchor-resolution.test.d.ts +0 -1
  192. package/dist/identity/anchor-resolution.test.js +0 -130
  193. package/dist/identity/key-change.test.d.ts +0 -1
  194. package/dist/identity/key-change.test.js +0 -811
  195. package/dist/invites/group-approval.test.d.ts +0 -1
  196. package/dist/invites/group-approval.test.js +0 -223
  197. package/dist/invites/invite-token.test.d.ts +0 -1
  198. package/dist/invites/invite-token.test.js +0 -123
  199. package/dist/keys.test.d.ts +0 -1
  200. package/dist/keys.test.js +0 -336
  201. package/dist/logging/console-logger.test.d.ts +0 -1
  202. package/dist/logging/console-logger.test.js +0 -300
  203. package/dist/logging/console-logs.table.test.d.ts +0 -1
  204. package/dist/logging/console-logs.table.test.js +0 -156
  205. package/dist/observable.test.d.ts +0 -1
  206. package/dist/observable.test.js +0 -309
  207. package/dist/package-build/build-package.test.d.ts +0 -1
  208. package/dist/package-build/build-package.test.js +0 -204
  209. package/dist/package-build/contract-add.test.d.ts +0 -1
  210. package/dist/package-build/contract-add.test.js +0 -467
  211. package/dist/package-build/freeze-contracts.test.d.ts +0 -1
  212. package/dist/package-build/freeze-contracts.test.js +0 -355
  213. package/dist/package-installer/package-author-signing.test.d.ts +0 -1
  214. package/dist/package-installer/package-author-signing.test.js +0 -200
  215. package/dist/package-installer/package-cloner.test.d.ts +0 -1
  216. package/dist/package-installer/package-cloner.test.js +0 -278
  217. package/dist/package-installer/package-creator.test.d.ts +0 -1
  218. package/dist/package-installer/package-creator.test.js +0 -908
  219. package/dist/package-installer/package-dev-tools.test.d.ts +0 -1
  220. package/dist/package-installer/package-dev-tools.test.js +0 -64
  221. package/dist/package-installer/package-installer.test.d.ts +0 -1
  222. package/dist/package-installer/package-installer.test.js +0 -882
  223. package/dist/package-installer/package-propagation.test.d.ts +0 -1
  224. package/dist/package-installer/package-propagation.test.js +0 -1269
  225. package/dist/package-installer/package-publisher.test.d.ts +0 -1
  226. package/dist/package-installer/package-publisher.test.js +0 -153
  227. package/dist/package-installer/package-remote-checker.test.d.ts +0 -1
  228. package/dist/package-installer/package-remote-checker.test.js +0 -334
  229. package/dist/package-installer/package-seed-installer.test.d.ts +0 -1
  230. package/dist/package-installer/package-seed-installer.test.js +0 -123
  231. package/dist/package-installer/package-tarball.test.d.ts +0 -1
  232. package/dist/package-installer/package-tarball.test.js +0 -75
  233. package/dist/package-installer/peers-core-installer.test.d.ts +0 -1
  234. package/dist/package-installer/peers-core-installer.test.js +0 -49
  235. package/dist/package-installer/peers-core-trust-anchor.test.d.ts +0 -1
  236. package/dist/package-installer/peers-core-trust-anchor.test.js +0 -155
  237. package/dist/package-loader/contract-package-loader.test.d.ts +0 -1
  238. package/dist/package-loader/contract-package-loader.test.js +0 -274
  239. package/dist/package-loader/host-authority-loading.test.d.ts +0 -1
  240. package/dist/package-loader/host-authority-loading.test.js +0 -104
  241. package/dist/package-loader/host-dispatch-policy.test.d.ts +0 -1
  242. package/dist/package-loader/host-dispatch-policy.test.js +0 -56
  243. package/dist/package-loader/isolated-artifact.test.d.ts +0 -1
  244. package/dist/package-loader/isolated-artifact.test.js +0 -688
  245. package/dist/package-loader/isolated-persistent-var-gateway.test.d.ts +0 -1
  246. package/dist/package-loader/isolated-persistent-var-gateway.test.js +0 -56
  247. package/dist/package-loader/isolated-table-gateway.test.d.ts +0 -1
  248. package/dist/package-loader/isolated-table-gateway.test.js +0 -633
  249. package/dist/package-loader/package-loader.test.d.ts +0 -1
  250. package/dist/package-loader/package-loader.test.js +0 -1764
  251. package/dist/package-loader/resolve-consumed-contracts.test.d.ts +0 -1
  252. package/dist/package-loader/resolve-consumed-contracts.test.js +0 -166
  253. package/dist/serial-json.compat.test.d.ts +0 -1
  254. package/dist/serial-json.compat.test.js +0 -369
  255. package/dist/serial-json.test.d.ts +0 -1
  256. package/dist/serial-json.test.js +0 -401
  257. package/dist/testing/mock-host-contract.test.d.ts +0 -1
  258. package/dist/testing/mock-host-contract.test.js +0 -782
  259. package/dist/utils.test.d.ts +0 -1
  260. 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 {};