@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.
Files changed (272) 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/contract-transport.d.ts +2 -1
  4. package/dist/contracts/contract-transport.js +24 -2
  5. package/dist/contracts/create-local-consumer.js +16 -1
  6. package/dist/contracts/index.d.ts +2 -0
  7. package/dist/contracts/index.js +2 -0
  8. package/dist/contracts/system/index.d.ts +2 -0
  9. package/dist/contracts/system/index.js +2 -0
  10. package/dist/contracts/system/invites-contract.js +2 -1
  11. package/dist/contracts/system/sync-check-contract.d.ts +97 -0
  12. package/dist/contracts/system/sync-check-contract.js +115 -0
  13. package/dist/contracts/tool-arguments.d.ts +15 -0
  14. package/dist/contracts/tool-arguments.js +41 -0
  15. package/dist/contracts/tool-catalog-service.js +2 -12
  16. package/dist/contracts/tool-catalog.js +6 -2
  17. package/dist/data/change-tracking.d.ts +40 -0
  18. package/dist/data/change-tracking.js +89 -0
  19. package/dist/data/orm/types.d.ts +24 -7
  20. package/dist/data/orm/types.js +97 -24
  21. package/dist/define/manifest.js +6 -34
  22. package/dist/device/binary-peer-connection-v2.d.ts +7 -15
  23. package/dist/device/binary-peer-connection-v2.js +14 -30
  24. package/dist/device/connection.d.ts +34 -43
  25. package/dist/device/connection.js +188 -186
  26. package/dist/device/device.d.ts +1 -8
  27. package/dist/device/device.js +1 -30
  28. package/dist/device/socket.type.d.ts +6 -12
  29. package/dist/package-loader/package-loader.js +27 -22
  30. package/dist/system-ids.d.ts +5 -0
  31. package/dist/system-ids.js +6 -1
  32. package/package.json +4 -2
  33. package/dist/context/user-context-identity.test.d.ts +0 -1
  34. package/dist/context/user-context-identity.test.js +0 -220
  35. package/dist/contracts/__tests__/action-dispatch.test.d.ts +0 -1
  36. package/dist/contracts/__tests__/action-dispatch.test.js +0 -319
  37. package/dist/contracts/__tests__/also-implements.test.d.ts +0 -1
  38. package/dist/contracts/__tests__/also-implements.test.js +0 -110
  39. package/dist/contracts/__tests__/builder.test.d.ts +0 -1
  40. package/dist/contracts/__tests__/builder.test.js +0 -669
  41. package/dist/contracts/__tests__/contract-events.test.d.ts +0 -1
  42. package/dist/contracts/__tests__/contract-events.test.js +0 -199
  43. package/dist/contracts/__tests__/contract-observables.test.d.ts +0 -1
  44. package/dist/contracts/__tests__/contract-observables.test.js +0 -290
  45. package/dist/contracts/__tests__/contract-provider-router.test.d.ts +0 -1
  46. package/dist/contracts/__tests__/contract-provider-router.test.js +0 -315
  47. package/dist/contracts/__tests__/contract-proxy.test.d.ts +0 -1
  48. package/dist/contracts/__tests__/contract-proxy.test.js +0 -657
  49. package/dist/contracts/__tests__/contract-resolvers.test.d.ts +0 -1
  50. package/dist/contracts/__tests__/contract-resolvers.test.js +0 -758
  51. package/dist/contracts/__tests__/contract-subscription-lifecycle.test.d.ts +0 -1
  52. package/dist/contracts/__tests__/contract-subscription-lifecycle.test.js +0 -353
  53. package/dist/contracts/__tests__/contract-table-events.test.d.ts +0 -1
  54. package/dist/contracts/__tests__/contract-table-events.test.js +0 -209
  55. package/dist/contracts/__tests__/contract-transport.test.d.ts +0 -1
  56. package/dist/contracts/__tests__/contract-transport.test.js +0 -163
  57. package/dist/contracts/__tests__/extract.test.d.ts +0 -1
  58. package/dist/contracts/__tests__/extract.test.js +0 -145
  59. package/dist/contracts/__tests__/frozen-contracts.test.d.ts +0 -1
  60. package/dist/contracts/__tests__/frozen-contracts.test.js +0 -191
  61. package/dist/contracts/__tests__/generic-tool-dispatch.test.d.ts +0 -1
  62. package/dist/contracts/__tests__/generic-tool-dispatch.test.js +0 -130
  63. package/dist/contracts/__tests__/host-contract-client.test.d.ts +0 -1
  64. package/dist/contracts/__tests__/host-contract-client.test.js +0 -793
  65. package/dist/contracts/__tests__/host-contract-consumer.test.d.ts +0 -1
  66. package/dist/contracts/__tests__/host-contract-consumer.test.js +0 -163
  67. package/dist/contracts/__tests__/host-contract-transport.test.d.ts +0 -1
  68. package/dist/contracts/__tests__/host-contract-transport.test.js +0 -66
  69. package/dist/contracts/__tests__/integration.test.d.ts +0 -1
  70. package/dist/contracts/__tests__/integration.test.js +0 -348
  71. package/dist/contracts/__tests__/legacy-removal.test.d.ts +0 -1
  72. package/dist/contracts/__tests__/legacy-removal.test.js +0 -128
  73. package/dist/contracts/__tests__/persistent-registry.test.d.ts +0 -1
  74. package/dist/contracts/__tests__/persistent-registry.test.js +0 -109
  75. package/dist/contracts/__tests__/playground.test.d.ts +0 -1
  76. package/dist/contracts/__tests__/playground.test.js +0 -216
  77. package/dist/contracts/__tests__/registry.test.d.ts +0 -1
  78. package/dist/contracts/__tests__/registry.test.js +0 -238
  79. package/dist/contracts/__tests__/remote-contract-transport.test.d.ts +0 -1
  80. package/dist/contracts/__tests__/remote-contract-transport.test.js +0 -119
  81. package/dist/contracts/__tests__/system-contracts.test.d.ts +0 -1
  82. package/dist/contracts/__tests__/system-contracts.test.js +0 -247
  83. package/dist/contracts/__tests__/target-dispatch.d.ts +0 -11
  84. package/dist/contracts/__tests__/target-dispatch.js +0 -24
  85. package/dist/contracts/__tests__/tool-catalog-inventory.test.d.ts +0 -1
  86. package/dist/contracts/__tests__/tool-catalog-inventory.test.js +0 -44
  87. package/dist/contracts/__tests__/tool-catalog-service.test.d.ts +0 -1
  88. package/dist/contracts/__tests__/tool-catalog-service.test.js +0 -482
  89. package/dist/contracts/__tests__/tool-catalog.test.d.ts +0 -1
  90. package/dist/contracts/__tests__/tool-catalog.test.js +0 -1199
  91. package/dist/contracts/__tests__/validate.test.d.ts +0 -1
  92. package/dist/contracts/__tests__/validate.test.js +0 -991
  93. package/dist/contracts/__tests__/workflow-context.test.d.ts +0 -1
  94. package/dist/contracts/__tests__/workflow-context.test.js +0 -50
  95. package/dist/data/access-level.test.d.ts +0 -1
  96. package/dist/data/access-level.test.js +0 -53
  97. package/dist/data/change-tracking.test.d.ts +0 -1
  98. package/dist/data/change-tracking.test.js +0 -62
  99. package/dist/data/files/files.test.d.ts +0 -1
  100. package/dist/data/files/files.test.js +0 -770
  101. package/dist/data/group-members.test.d.ts +0 -1
  102. package/dist/data/group-members.test.js +0 -336
  103. package/dist/data/group-share.test.d.ts +0 -1
  104. package/dist/data/group-share.test.js +0 -110
  105. package/dist/data/groups.test.d.ts +0 -1
  106. package/dist/data/groups.test.js +0 -153
  107. package/dist/data/orm/cursor.test.d.ts +0 -1
  108. package/dist/data/orm/cursor.test.js +0 -314
  109. package/dist/data/orm/data-query.mongo.test.d.ts +0 -1
  110. package/dist/data/orm/data-query.mongo.test.js +0 -367
  111. package/dist/data/orm/data-query.sqlite.test.d.ts +0 -1
  112. package/dist/data/orm/data-query.sqlite.test.js +0 -365
  113. package/dist/data/orm/data-query.test.d.ts +0 -1
  114. package/dist/data/orm/data-query.test.js +0 -545
  115. package/dist/data/orm/dependency-injection.test.d.ts +0 -1
  116. package/dist/data/orm/dependency-injection.test.js +0 -171
  117. package/dist/data/orm/event-registry.test.d.ts +0 -1
  118. package/dist/data/orm/event-registry.test.js +0 -44
  119. package/dist/data/orm/multi-cursors.test.d.ts +0 -1
  120. package/dist/data/orm/multi-cursors.test.js +0 -463
  121. package/dist/data/orm/sql.data-source.test.d.ts +0 -1
  122. package/dist/data/orm/sql.data-source.test.js +0 -731
  123. package/dist/data/orm/table-container-events.test.d.ts +0 -1
  124. package/dist/data/orm/table-container-events.test.js +0 -101
  125. package/dist/data/orm/table-container.test.d.ts +0 -1
  126. package/dist/data/orm/table-container.test.js +0 -273
  127. package/dist/data/orm/table.event-source.test.d.ts +0 -1
  128. package/dist/data/orm/table.event-source.test.js +0 -331
  129. package/dist/data/orm/types.test.d.ts +0 -1
  130. package/dist/data/orm/types.test.js +0 -409
  131. package/dist/data/package-table-identity.test.d.ts +0 -1
  132. package/dist/data/package-table-identity.test.js +0 -46
  133. package/dist/data/package-version-permissions.test.d.ts +0 -1
  134. package/dist/data/package-version-permissions.test.js +0 -107
  135. package/dist/data/package-version-resolver.test.d.ts +0 -4
  136. package/dist/data/package-version-resolver.test.js +0 -543
  137. package/dist/data/package-versions.test.d.ts +0 -1
  138. package/dist/data/package-versions.test.js +0 -227
  139. package/dist/data/persistent-vars.conflict.test.d.ts +0 -1
  140. package/dist/data/persistent-vars.conflict.test.js +0 -126
  141. package/dist/data/persistent-vars.migration.test.d.ts +0 -1
  142. package/dist/data/persistent-vars.migration.test.js +0 -133
  143. package/dist/data/persistent-vars.package-scope.test.d.ts +0 -1
  144. package/dist/data/persistent-vars.package-scope.test.js +0 -27
  145. package/dist/data/sync-recovery-queue.test.d.ts +0 -1
  146. package/dist/data/sync-recovery-queue.test.js +0 -215
  147. package/dist/data/table-signing.test.d.ts +0 -1
  148. package/dist/data/table-signing.test.js +0 -118
  149. package/dist/data/tool-access.test.d.ts +0 -1
  150. package/dist/data/tool-access.test.js +0 -166
  151. package/dist/data/user-permissions.test.d.ts +0 -1
  152. package/dist/data/user-permissions.test.js +0 -305
  153. package/dist/data/user-trust-levels.test.d.ts +0 -1
  154. package/dist/data/user-trust-levels.test.js +0 -37
  155. package/dist/define/also-implements.test.d.ts +0 -1
  156. package/dist/define/also-implements.test.js +0 -123
  157. package/dist/define/declare-contract.test.d.ts +0 -1
  158. package/dist/define/declare-contract.test.js +0 -573
  159. package/dist/define/define.test.d.ts +0 -1
  160. package/dist/define/define.test.js +0 -1010
  161. package/dist/define/empty-fields.test.d.ts +0 -1
  162. package/dist/define/empty-fields.test.js +0 -55
  163. package/dist/define/events-observables.test.d.ts +0 -1
  164. package/dist/define/events-observables.test.js +0 -1013
  165. package/dist/define/serve-members.test.d.ts +0 -1
  166. package/dist/define/serve-members.test.js +0 -630
  167. package/dist/define/vars.test.d.ts +0 -1
  168. package/dist/define/vars.test.js +0 -39
  169. package/dist/device/binary-peer-connection-v2.test.d.ts +0 -1
  170. package/dist/device/binary-peer-connection-v2.test.js +0 -730
  171. package/dist/device/binary-peer-connection.d.ts +0 -58
  172. package/dist/device/binary-peer-connection.js +0 -516
  173. package/dist/device/binary-peer-connection.test.d.ts +0 -1
  174. package/dist/device/binary-peer-connection.test.js +0 -184
  175. package/dist/device/connection.test.d.ts +0 -1
  176. package/dist/device/connection.test.js +0 -613
  177. package/dist/device/device-election.test.d.ts +0 -1
  178. package/dist/device/device-election.test.js +0 -516
  179. package/dist/device/device.test.d.ts +0 -1
  180. package/dist/device/device.test.js +0 -243
  181. package/dist/device/frame-cipher.test.d.ts +0 -1
  182. package/dist/device/frame-cipher.test.js +0 -219
  183. package/dist/device/get-trust-level-fn.test.d.ts +0 -1
  184. package/dist/device/get-trust-level-fn.test.js +0 -685
  185. package/dist/device/streamed-socket.d.ts +0 -23
  186. package/dist/device/streamed-socket.js +0 -255
  187. package/dist/device/streamed-socket.test.d.ts +0 -1
  188. package/dist/device/streamed-socket.test.js +0 -216
  189. package/dist/device/tx-encoding.test.d.ts +0 -1
  190. package/dist/device/tx-encoding.test.js +0 -295
  191. package/dist/device-pairing/cpace.test.d.ts +0 -1
  192. package/dist/device-pairing/cpace.test.js +0 -116
  193. package/dist/device-pairing/device-pairing.test.d.ts +0 -1
  194. package/dist/device-pairing/device-pairing.test.js +0 -211
  195. package/dist/hlc.test.d.ts +0 -1
  196. package/dist/hlc.test.js +0 -45
  197. package/dist/host-credentials.test.d.ts +0 -1
  198. package/dist/host-credentials.test.js +0 -88
  199. package/dist/identity/account-email.test.d.ts +0 -1
  200. package/dist/identity/account-email.test.js +0 -59
  201. package/dist/identity/anchor-document.test.d.ts +0 -1
  202. package/dist/identity/anchor-document.test.js +0 -16
  203. package/dist/identity/anchor-resolution.test.d.ts +0 -1
  204. package/dist/identity/anchor-resolution.test.js +0 -130
  205. package/dist/identity/key-change.test.d.ts +0 -1
  206. package/dist/identity/key-change.test.js +0 -811
  207. package/dist/invites/group-approval.test.d.ts +0 -1
  208. package/dist/invites/group-approval.test.js +0 -223
  209. package/dist/invites/invite-token.test.d.ts +0 -1
  210. package/dist/invites/invite-token.test.js +0 -123
  211. package/dist/keys.test.d.ts +0 -1
  212. package/dist/keys.test.js +0 -336
  213. package/dist/logging/console-logger.test.d.ts +0 -1
  214. package/dist/logging/console-logger.test.js +0 -300
  215. package/dist/logging/console-logs.table.test.d.ts +0 -1
  216. package/dist/logging/console-logs.table.test.js +0 -156
  217. package/dist/observable.test.d.ts +0 -1
  218. package/dist/observable.test.js +0 -309
  219. package/dist/package-build/build-package.test.d.ts +0 -1
  220. package/dist/package-build/build-package.test.js +0 -204
  221. package/dist/package-build/contract-add.test.d.ts +0 -1
  222. package/dist/package-build/contract-add.test.js +0 -467
  223. package/dist/package-build/freeze-contracts.test.d.ts +0 -1
  224. package/dist/package-build/freeze-contracts.test.js +0 -355
  225. package/dist/package-installer/package-author-signing.test.d.ts +0 -1
  226. package/dist/package-installer/package-author-signing.test.js +0 -200
  227. package/dist/package-installer/package-cloner.test.d.ts +0 -1
  228. package/dist/package-installer/package-cloner.test.js +0 -278
  229. package/dist/package-installer/package-creator.test.d.ts +0 -1
  230. package/dist/package-installer/package-creator.test.js +0 -908
  231. package/dist/package-installer/package-dev-tools.test.d.ts +0 -1
  232. package/dist/package-installer/package-dev-tools.test.js +0 -64
  233. package/dist/package-installer/package-installer.test.d.ts +0 -1
  234. package/dist/package-installer/package-installer.test.js +0 -882
  235. package/dist/package-installer/package-propagation.test.d.ts +0 -1
  236. package/dist/package-installer/package-propagation.test.js +0 -1269
  237. package/dist/package-installer/package-publisher.test.d.ts +0 -1
  238. package/dist/package-installer/package-publisher.test.js +0 -153
  239. package/dist/package-installer/package-remote-checker.test.d.ts +0 -1
  240. package/dist/package-installer/package-remote-checker.test.js +0 -334
  241. package/dist/package-installer/package-seed-installer.test.d.ts +0 -1
  242. package/dist/package-installer/package-seed-installer.test.js +0 -123
  243. package/dist/package-installer/package-tarball.test.d.ts +0 -1
  244. package/dist/package-installer/package-tarball.test.js +0 -75
  245. package/dist/package-installer/peers-core-installer.test.d.ts +0 -1
  246. package/dist/package-installer/peers-core-installer.test.js +0 -49
  247. package/dist/package-installer/peers-core-trust-anchor.test.d.ts +0 -1
  248. package/dist/package-installer/peers-core-trust-anchor.test.js +0 -155
  249. package/dist/package-loader/contract-package-loader.test.d.ts +0 -1
  250. package/dist/package-loader/contract-package-loader.test.js +0 -274
  251. package/dist/package-loader/host-authority-loading.test.d.ts +0 -1
  252. package/dist/package-loader/host-authority-loading.test.js +0 -104
  253. package/dist/package-loader/host-dispatch-policy.test.d.ts +0 -1
  254. package/dist/package-loader/host-dispatch-policy.test.js +0 -56
  255. package/dist/package-loader/isolated-artifact.test.d.ts +0 -1
  256. package/dist/package-loader/isolated-artifact.test.js +0 -688
  257. package/dist/package-loader/isolated-persistent-var-gateway.test.d.ts +0 -1
  258. package/dist/package-loader/isolated-persistent-var-gateway.test.js +0 -56
  259. package/dist/package-loader/isolated-table-gateway.test.d.ts +0 -1
  260. package/dist/package-loader/isolated-table-gateway.test.js +0 -633
  261. package/dist/package-loader/package-loader.test.d.ts +0 -1
  262. package/dist/package-loader/package-loader.test.js +0 -1764
  263. package/dist/package-loader/resolve-consumed-contracts.test.d.ts +0 -1
  264. package/dist/package-loader/resolve-consumed-contracts.test.js +0 -166
  265. package/dist/serial-json.compat.test.d.ts +0 -1
  266. package/dist/serial-json.compat.test.js +0 -369
  267. package/dist/serial-json.test.d.ts +0 -1
  268. package/dist/serial-json.test.js +0 -401
  269. package/dist/testing/mock-host-contract.test.d.ts +0 -1
  270. package/dist/testing/mock-host-contract.test.js +0 -782
  271. package/dist/utils.test.d.ts +0 -1
  272. package/dist/utils.test.js +0 -232
@@ -1,467 +0,0 @@
1
- "use strict";
2
- Object.defineProperty(exports, "__esModule", { value: true });
3
- const promises_1 = require("node:fs/promises");
4
- const node_os_1 = require("node:os");
5
- const path = require("node:path");
6
- const ts = require("typescript");
7
- const validate_1 = require("../contracts/validate");
8
- const declare_contract_1 = require("../define/declare-contract");
9
- const manifest_1 = require("../define/manifest");
10
- const isolated_artifact_1 = require("../package-loader/isolated-artifact");
11
- const peer_id_1 = require("../peer-id");
12
- const field_type_1 = require("../types/field-type");
13
- const build_package_1 = require("./build-package");
14
- const cli_1 = require("./cli");
15
- const contract_add_1 = require("./contract-add");
16
- const contract_source_1 = require("./contract-source");
17
- const sdkRoot = path.resolve(__dirname, "../..");
18
- const contractId = (0, peer_id_1.newid)();
19
- let root;
20
- /** A declaration covering schema-inferred IR features. Hand-written IR is tested separately. */
21
- const richDeclaration = `
22
- import {
23
- AccessLevel, declareContract, declareObservable, declareTool, defineEvent, defineTable, z,
24
- zodPeerId,
25
- } from "@peers-app/peers-sdk/define";
26
-
27
- enum Level { Low = 1, High = 2 }
28
- const place = z.object({
29
- city: z.string().describe("City."),
30
- unit: z.enum(["F", "C"]).optional(),
31
- zone: z.string().nullish(),
32
- });
33
-
34
- const Places = defineTable({
35
- name: "Places",
36
- description: "Places.",
37
- primaryKeyName: "placeId",
38
- schema: z.object({
39
- placeId: zodPeerId,
40
- label: z.string(),
41
- at: z.date().optional(),
42
- tags: z.array(z.string()),
43
- }),
44
- versionNumber: 3,
45
- });
46
-
47
- export const Rich = declareContract({
48
- contractId: ${JSON.stringify(contractId)},
49
- version: 2,
50
- name: "Rich Things",
51
- description: "Every shape the IR carries.",
52
- tables: [Places],
53
- tools: [
54
- declareTool({
55
- name: "plan",
56
- usageDescription: "Plan a trip.",
57
- accessLevel: AccessLevel.Writer,
58
- remoteAccessLevel: AccessLevel.Admin,
59
- inputSchema: z.object({
60
- place,
61
- places: z.array(place).optional(),
62
- level: z.nativeEnum(Level),
63
- size: z.union([z.literal("small"), z.literal(3)]),
64
- mode: z.literal("fast"),
65
- when: z.date(),
66
- anything: z.unknown().optional(),
67
- count: z.number().int().min(1).default(5),
68
- extra: z.record(z.string()).optional(),
69
- }),
70
- outputSchema: z.object({ ok: z.boolean(), ids: z.array(zodPeerId) }),
71
- }),
72
- declareTool({
73
- name: "skim",
74
- usageDescription: "Skim.",
75
- accessLevel: AccessLevel.Reader,
76
- authorityPropagation: "preserve",
77
- inputSchema: z.object({}),
78
- outputSchema: z.object({ note: z.string().optional() }),
79
- }),
80
- ],
81
- observables: [
82
- declareObservable({
83
- name: "state",
84
- description: "Current state, or null.",
85
- schema: z.object({ on: z.boolean(), place }).nullable(),
86
- writable: true,
87
- }),
88
- declareObservable({ name: "count", description: "A count.", schema: z.number() }),
89
- declareObservable({ name: "names", description: "Names.", schema: z.array(z.string()) }),
90
- declareObservable({
91
- name: "transformed",
92
- description: "The original code's transform is not part of the IR.",
93
- schema: z.number().transform(String),
94
- }),
95
- declareObservable({ name: "level", description: "A numeric enum.", schema: z.nativeEnum(Level) }),
96
- ],
97
- events: [
98
- defineEvent({
99
- name: "place-changed",
100
- description: "A place moved.",
101
- payloadSchema: z.object({ placeId: zodPeerId, place, at: z.date() }),
102
- }),
103
- defineEvent({ name: "ping", description: "No payload." }),
104
- ],
105
- });
106
- `;
107
- beforeEach(async () => {
108
- root = await (0, promises_1.mkdtemp)(path.join((0, node_os_1.tmpdir)(), "peers-contract-add-test-"));
109
- await (0, promises_1.mkdir)(path.join(root, "src"));
110
- await (0, promises_1.mkdir)(path.join(root, "node_modules/@peers-app"), { recursive: true });
111
- await (0, promises_1.symlink)(sdkRoot, path.join(root, "node_modules/@peers-app/peers-sdk"), "dir");
112
- await (0, promises_1.symlink)(path.dirname(require.resolve("esbuild/package.json")), path.join(root, "node_modules/esbuild"), "dir");
113
- await (0, promises_1.writeFile)(path.join(root, "package.json"), '{"name":"contract-add-probe","version":"1.0.0"}');
114
- await (0, promises_1.writeFile)(path.join(root, "src/rich.ts"), richDeclaration);
115
- });
116
- afterEach(async () => {
117
- await (0, promises_1.rm)(root, { recursive: true, force: true });
118
- });
119
- /** The IR of the declaration a module exports. */
120
- async function irOf(file, exportName) {
121
- const loaded = (await (0, build_package_1.loadPackageModule)(root, file));
122
- const value = loaded[exportName];
123
- if (!(0, declare_contract_1.isContractDeclaration)(value))
124
- throw new Error(`${exportName} isn't a declaration`);
125
- return (0, manifest_1.contractManifest)(value.declaration);
126
- }
127
- /** esbuild loads the generated file without typechecking; authors also compile it with tsc. */
128
- function checkTypes(...files) {
129
- const program = ts.createProgram(files, {
130
- noEmit: true,
131
- strict: true,
132
- noUnusedLocals: true,
133
- skipLibCheck: true,
134
- target: ts.ScriptTarget.ES2022,
135
- module: ts.ModuleKind.CommonJS,
136
- types: [],
137
- });
138
- expect(ts.formatDiagnostics(ts.getPreEmitDiagnostics(program), {
139
- getCurrentDirectory: () => root,
140
- getCanonicalFileName: (file) => file,
141
- getNewLine: () => "\n",
142
- })).toBe("");
143
- }
144
- test("a generated declaration has the source's IR, member for member", async () => {
145
- const source = path.join(root, "src/rich.ts");
146
- const result = await (0, contract_add_1.addContract)({ source: `${source}#Rich`, root });
147
- expect(path.relative(root, result.path)).toBe("src/contracts/rich-things.v2.ts");
148
- expect(result).toMatchObject({ exportName: "RichThings", changed: true });
149
- const generated = await (0, promises_1.readFile)(result.path, "utf8");
150
- expect(generated).toMatch(/^\/\/ Generated by `peers-package contract add` from /);
151
- expect(generated).toContain("export const richThingsPlaceChanged = defineEvent({");
152
- expect(generated).toContain("export type RichThingsObservables = ContractObservableValuesOf<");
153
- const original = await irOf(source, "Rich");
154
- const copy = await irOf(result.path, "RichThings");
155
- expect(copy).toEqual(original);
156
- const types = path.join(root, "src/generated-types.ts");
157
- await (0, promises_1.writeFile)(types, `
158
- import type { RichThingsObservables, RichThingsRows, RichThingsEvents } from "./contracts/rich-things.v2";
159
- export const allowed: RichThingsObservables["level"] = 1;
160
- // @ts-expect-error The IR's numeric enum admits only 1 or 2.
161
- export const refused: RichThingsObservables["level"] = 3;
162
- export const row: RichThingsRows["Places"] = { placeId: "id", label: "Place", tags: [] };
163
- export const event: RichThingsEvents["place-changed"] = { placeId: "id", place: { city: "City" }, at: new Date() };
164
- // @ts-expect-error Member maps keep each row's field types.
165
- export const badRow: RichThingsRows["Places"] = { placeId: "id", label: 4, tags: [] };
166
- `);
167
- checkTypes(result.path, types);
168
- const loaded = (await (0, build_package_1.loadPackageModule)(root, result.path));
169
- expect(loaded.RichThings.declaration.tools[1].definition.inputSchema.parse({ extra: 1 })).toEqual({ extra: 1 });
170
- // A provider built from the copy registers a shape the original's frozen version accepts.
171
- const definitions = [original, copy].map(({ contract, tables }) => (0, isolated_artifact_1.isolatedContractToDefinition)(contract, tables));
172
- expect((0, validate_1.validateImmutability)(definitions[0], definitions[1])).toEqual({ valid: true, errors: [] });
173
- expect((0, validate_1.validateImmutability)(definitions[1], definitions[0])).toEqual({ valid: true, errors: [] });
174
- });
175
- test("--check reports a missing, edited, or current declaration", async () => {
176
- const source = `${path.join(root, "src/rich.ts")}#Rich`;
177
- const check = () => (0, cli_1.main)(["contract", "add", source, "--root", root, "--check"]);
178
- const errors = jest.spyOn(console, "error").mockImplementation(() => undefined);
179
- const logs = jest.spyOn(console, "log").mockImplementation(() => undefined);
180
- try {
181
- expect(await check()).toBe(1);
182
- await expect((0, promises_1.readFile)(path.join(root, "src/contracts/rich-things.v2.ts"))).rejects.toMatchObject({ code: "ENOENT" });
183
- expect(await (0, cli_1.main)(["contract", "add", source, "--root", root])).toBe(0);
184
- expect(await check()).toBe(0);
185
- const file = path.join(root, "src/contracts/rich-things.v2.ts");
186
- // The header names the source relative to the package, however the command spelled it.
187
- expect(await (0, promises_1.readFile)(file, "utf8")).toMatch(/^\/\/ Generated by .* from src\/rich\.ts#Rich\./);
188
- const fromCwd = path.relative(process.cwd(), path.join(root, "src/rich.ts"));
189
- expect(await (0, cli_1.main)(["contract", "add", `${fromCwd}#Rich`, "--root", root, "--check"])).toBe(0);
190
- const edited = `${await (0, promises_1.readFile)(file, "utf8")}// edited\n`;
191
- await (0, promises_1.writeFile)(file, edited);
192
- expect(await check()).toBe(1);
193
- expect(await (0, promises_1.readFile)(file, "utf8")).toBe(edited);
194
- expect(errors.mock.calls.at(-1)?.[0]).toMatch(/out of date\. Run: peers-package contract add/);
195
- expect(await (0, cli_1.main)([
196
- "contract",
197
- "add",
198
- source,
199
- "--root",
200
- root,
201
- "--out-dir",
202
- "custom folder",
203
- "--name",
204
- "Trips",
205
- "--check",
206
- ])).toBe(1);
207
- expect(errors.mock.calls.at(-1)?.[0]).toContain(`--root ${root} --out-dir 'custom folder' --name Trips`);
208
- }
209
- finally {
210
- errors.mockRestore();
211
- logs.mockRestore();
212
- }
213
- });
214
- test("formats with the destination package's Biome and checks that formatted copy", async () => {
215
- await (0, promises_1.mkdir)(path.join(root, "node_modules/.bin"));
216
- await (0, promises_1.symlink)(path.join(sdkRoot, "node_modules/.bin/biome"), path.join(root, "node_modules/.bin/biome"));
217
- await (0, promises_1.writeFile)(path.join(root, "biome.json"), JSON.stringify({ formatter: { indentStyle: "tab" } }));
218
- const source = `${path.join(root, "src/rich.ts")}#Rich`;
219
- // Without @biomejs/biome in the package's node_modules, the .bin shim runs.
220
- const result = await (0, contract_add_1.addContract)({ source, root });
221
- expect(await (0, promises_1.readFile)(result.path, "utf8")).toContain("\tcontractId:");
222
- expect((await (0, contract_add_1.addContract)({ source, root, check: true })).changed).toBe(false);
223
- // With it, Biome's Node script runs (Windows can't spawn the shim), formatting the same way.
224
- await (0, promises_1.mkdir)(path.join(root, "node_modules/@biomejs"));
225
- await (0, promises_1.symlink)(path.join(sdkRoot, "node_modules/@biomejs/biome"), path.join(root, "node_modules/@biomejs/biome"), "dir");
226
- await (0, promises_1.rm)(path.join(root, "node_modules/.bin/biome"));
227
- await (0, promises_1.writeFile)(path.join(root, "node_modules/.bin/biome"), "#!/bin/sh\nexit 1\n", {
228
- mode: 0o755,
229
- });
230
- expect((await (0, contract_add_1.addContract)({ source, root, check: true })).changed).toBe(false);
231
- });
232
- test("reads a provider's manifest or artifact, choosing the contract when it provides several", async () => {
233
- const { contract, tables } = await irOf(path.join(root, "src/rich.ts"), "Rich");
234
- const other = {
235
- contractId: (0, peer_id_1.newid)(),
236
- version: 1,
237
- name: "Other",
238
- tools: [{ name: "noop", usageDescription: "Nothing.", inputFields: [], outputFields: [] }],
239
- };
240
- const manifest = {
241
- packageId: (0, peer_id_1.newid)(),
242
- version: "1.0.0",
243
- guestApi: 3,
244
- provides: [contract, other],
245
- consumes: [],
246
- tables,
247
- };
248
- expect(() => (0, contract_source_1.contractSourceFromManifest)(manifest)).toThrow(/choose one with --contract/);
249
- expect(() => (0, contract_source_1.contractSourceFromManifest)(manifest, `${(0, peer_id_1.newid)()}@1`)).toThrow(/doesn't provide/);
250
- expect((0, contract_source_1.contractSourceFromManifest)(manifest, `${contractId}@2`)).toEqual({
251
- contract,
252
- tables,
253
- });
254
- // What a provider exposes through a contract isn't part of the contract: it isn't generated.
255
- const exposing = { ...contract, exposes: [{ contractId: other.contractId, version: 1 }] };
256
- expect((0, contract_source_1.generateContractDeclaration)((0, contract_source_1.contractSourceFromManifest)({ ...manifest, provides: [exposing, other] }, `${contractId}@2`), { from: "x" }).source).toBe((0, contract_source_1.generateContractDeclaration)({ contract, tables }, { from: "x" }).source);
257
- await (0, promises_1.writeFile)(path.join(root, "manifest.json"), `\uFEFF${JSON.stringify(manifest)}`);
258
- const fromManifest = await (0, contract_add_1.addContract)({
259
- source: path.join(root, "manifest.json"),
260
- contract: `${contractId}@2`,
261
- root,
262
- outDir: "a",
263
- });
264
- await (0, promises_1.writeFile)(path.join(root, "package.bundle.js"),
265
- // Serializing validates, which fills in defaults on what it's given.
266
- (0, isolated_artifact_1.serializeIsolatedPackageArtifact)({
267
- manifest: structuredClone(manifest),
268
- providerSource: "void 0;",
269
- }));
270
- const fromArtifact = await (0, contract_add_1.addContract)({
271
- source: path.join(root, "package.bundle.js"),
272
- contract: `${contractId}@2`,
273
- root,
274
- outDir: "b",
275
- });
276
- expect(await irOf(fromManifest.path, "RichThings")).toEqual({ contract, tables });
277
- expect(await (0, promises_1.readFile)(fromArtifact.path, "utf8")).toBe((await (0, promises_1.readFile)(fromManifest.path, "utf8")).replace("from manifest.json.", "from package.bundle.js."));
278
- const windowsArtifact = path.join(root, "windows.bundle.js");
279
- await (0, promises_1.writeFile)(windowsArtifact, `\uFEFF\r\n${(await (0, promises_1.readFile)(path.join(root, "package.bundle.js"), "utf8")).replace(/\n/g, "\r\n")}`);
280
- const fromWindows = await (0, contract_add_1.addContract)({
281
- source: windowsArtifact,
282
- contract: `${contractId}@2`,
283
- root,
284
- outDir: "c",
285
- });
286
- expect(await irOf(fromWindows.path, "RichThings")).toEqual({ contract, tables });
287
- });
288
- test("reads getContractDefinition's result, taking each tool's policy from it", async () => {
289
- const { contract, tables } = await irOf(path.join(root, "src/rich.ts"), "Rich");
290
- const definition = (0, isolated_artifact_1.isolatedContractToDefinition)(contract, tables);
291
- const policy = [
292
- { name: "plan", accessLevel: 40 },
293
- { name: "skim", accessLevel: 20, authorityPropagation: "preserve" },
294
- ];
295
- const source = (0, contract_source_1.contractSourceFromDefinition)({ definition, tools: policy });
296
- // The registry keeps no table storage policy and no persistent-variable bindings.
297
- expect(source.contract.tools).toEqual(contract.tools);
298
- expect(source.tables.map(({ versionNumber: _v, ...table }) => table)).toEqual(tables.map(({ versionNumber: _v, ...table }) => table));
299
- expect(() => (0, contract_source_1.contractSourceFromDefinition)({ definition })).toThrow(/no access level/);
300
- expect(() => (0, contract_source_1.contractSourceFromDefinition)({ definition, tools: [policy[0]] })).toThrow(/Runtime reported no access level for tool "skim"/);
301
- await (0, promises_1.writeFile)(path.join(root, "definition.json"), JSON.stringify(definition));
302
- await expect((0, contract_add_1.addContract)({ source: path.join(root, "definition.json"), root })).rejects.toThrow(/use getContractDefinition's result/);
303
- await (0, promises_1.writeFile)(path.join(root, "result.json"), JSON.stringify({ definition, tools: policy }));
304
- const written = await (0, contract_add_1.addContract)({ source: path.join(root, "result.json"), root });
305
- expect((await irOf(written.path, "RichThings")).contract.tools).toEqual(contract.tools);
306
- });
307
- test("names come from the contract unless given, and must be identifiers", async () => {
308
- const { contract, tables } = await irOf(path.join(root, "src/rich.ts"), "Rich");
309
- expect((0, contract_source_1.generateContractDeclaration)({ contract, tables }, { from: "x" }).exportName).toBe("RichThings");
310
- expect((0, contract_source_1.generateContractDeclaration)({ contract, tables }, { from: "x", exportName: "Trips" }).source).toContain("export const Trips = declareContract(");
311
- const acronym = (0, contract_source_1.generateContractDeclaration)({ contract: { ...contract, name: "HTTPService" }, tables }, { from: "x" });
312
- expect(acronym.fileName).toBe("http-service.v2.ts");
313
- expect(acronym.source).toContain("export const httpServicePlaceChanged = defineEvent(");
314
- expect(() => (0, contract_source_1.generateContractDeclaration)({ contract, tables }, { from: "x", exportName: "not ok" })).toThrow(/usable export name/);
315
- for (const exportName of ["class", "z", "declareContract", "AccessLevel"]) {
316
- expect(() => (0, contract_source_1.generateContractDeclaration)({ contract, tables }, { from: "x", exportName })).toThrow(/usable export name/);
317
- }
318
- for (const exportName of ["$", "_"]) {
319
- const generated = (0, contract_source_1.generateContractDeclaration)({ contract, tables }, { from: "x", exportName });
320
- const file = path.join(root, `src/${exportName}.ts`);
321
- await (0, promises_1.writeFile)(file, generated.source);
322
- expect(await irOf(file, exportName)).toEqual({ contract, tables });
323
- }
324
- await expect((0, contract_add_1.addContract)({ source: `${path.join(root, "src/rich.ts")}#Missing`, root })).rejects.toThrow(/exports no declaration or contract named Missing/);
325
- });
326
- test("hand-written IR survives generation, including stored defaults, blobs and opaque objects", async () => {
327
- const fields = [
328
- { name: "key", type: field_type_1.FieldType.id, subType: "record" },
329
- { name: "selectedId", type: field_type_1.FieldType.id, enumValues: [contractId] },
330
- { name: "bytes", type: field_type_1.FieldType.blob },
331
- { name: "opaque", type: field_type_1.FieldType.object },
332
- { name: "literal", type: field_type_1.FieldType.any, enumValues: ["only"] },
333
- { name: "repeated", type: field_type_1.FieldType.string, enumValues: ["same", "same"] },
334
- { name: "flag", type: field_type_1.FieldType.boolean, enumValues: [true, false] },
335
- { name: "oneFlag", type: field_type_1.FieldType.boolean, enumValues: [false, false] },
336
- { name: "numericChoice", type: field_type_1.FieldType.number, enumValues: [1, 2] },
337
- { name: "numericChoices", type: field_type_1.FieldType.number, enumValues: [1, 2], isArray: true },
338
- {
339
- name: "nestedChoice",
340
- type: field_type_1.FieldType.object,
341
- fields: [{ name: "choice", type: field_type_1.FieldType.number, enumValues: [1, 2], optional: true }],
342
- },
343
- { name: "count", type: field_type_1.FieldType.number, defaultValue: 5, optional: true },
344
- { name: "requiredDefault", type: field_type_1.FieldType.number, defaultValue: 7 },
345
- { name: "plainAny", type: field_type_1.FieldType.any },
346
- { name: "anyItems", type: field_type_1.FieldType.any, isArray: true },
347
- { name: "explicit", type: field_type_1.FieldType.string, optional: false, isArray: false, description: "" },
348
- { name: "__proto__", type: field_type_1.FieldType.string },
349
- {
350
- name: "nested",
351
- type: field_type_1.FieldType.object,
352
- fields: [
353
- { name: "answer", type: field_type_1.FieldType.number, defaultValue: 42 },
354
- { name: "choice", type: field_type_1.FieldType.number, enumValues: [1, 2] },
355
- ],
356
- defaultValue: JSON.parse('{"answer":42,"choice":1,"__proto__":{"kept":true}}'),
357
- },
358
- ];
359
- const source = {
360
- contract: {
361
- contractId,
362
- version: 1,
363
- name: "Stored Fields",
364
- tools: [
365
- {
366
- name: "go",
367
- usageDescription: "Go.",
368
- suggestedAccessLevel: 20,
369
- inputFields: fields,
370
- outputFields: fields,
371
- },
372
- ],
373
- tables: [{ name: "Records" }],
374
- events: [{ name: "changed", description: "Changed.", payloadFields: fields }],
375
- observables: [
376
- {
377
- name: "explicit",
378
- description: "Explicit flags.",
379
- valueType: field_type_1.FieldType.number,
380
- value: { type: field_type_1.FieldType.number, optional: false },
381
- writable: false,
382
- },
383
- ],
384
- },
385
- tables: [{ name: "Records", description: "Records.", primaryKeyName: "key", fields }],
386
- };
387
- const generated = (0, contract_source_1.generateContractDeclaration)(source, { from: "manifest.json" });
388
- const file = path.join(root, "src/stored.ts");
389
- await (0, promises_1.writeFile)(file, generated.source);
390
- const copy = await irOf(file, "StoredFields");
391
- expect(copy).toEqual(source);
392
- const types = path.join(root, "src/stored-types.ts");
393
- await (0, promises_1.writeFile)(types, `
394
- import type { StoredFieldsEvents, StoredFieldsRows } from "./stored";
395
- // @ts-expect-error Required any fields still need a value.
396
- export const missingEventValue: Pick<StoredFieldsEvents["changed"], "plainAny"> = {};
397
- // @ts-expect-error Required any row fields still need a value.
398
- export const missingRowValue: Pick<StoredFieldsRows["Records"], "plainAny"> = {};
399
- export const event: Pick<StoredFieldsEvents["changed"], "plainAny"> = { plainAny: null };
400
- `);
401
- checkTypes(file, types);
402
- const definitions = [source, copy].map(({ contract, tables }) => (0, isolated_artifact_1.isolatedContractToDefinition)(contract, tables));
403
- expect((0, validate_1.validateImmutability)(definitions[0], definitions[1])).toEqual({ valid: true, errors: [] });
404
- expect((0, validate_1.validateImmutability)(definitions[1], definitions[0])).toEqual({ valid: true, errors: [] });
405
- const loaded = (await (0, build_package_1.loadPackageModule)(root, file));
406
- const schema = loaded.StoredFields.declaration.tools[0].definition.inputSchema;
407
- expect(schema.shape.bytes.safeParse(new Uint8Array([1, 2])).success).toBe(true);
408
- expect(schema.shape.literal.safeParse("different").success).toBe(false);
409
- expect(schema.shape.oneFlag.safeParse(false).success).toBe(true);
410
- expect(schema.shape.oneFlag.safeParse(true).success).toBe(false);
411
- expect(schema.shape.numericChoice.safeParse(3).success).toBe(false);
412
- expect(schema.shape.numericChoices.safeParse([1, 2]).success).toBe(true);
413
- expect(schema.pick({ plainAny: true }).safeParse({}).success).toBe(false);
414
- expect(schema.shape.anyItems.safeParse([undefined, null, 1]).success).toBe(true);
415
- expect(schema.shape.count.parse(undefined)).toBe(5);
416
- expect(Object.hasOwn(schema.shape, "__proto__")).toBe(true);
417
- expect(Object.hasOwn(schema.shape.nested._def.defaultValue(), "__proto__")).toBe(true);
418
- });
419
- test("source labels and member names stay data in generated TypeScript", async () => {
420
- const { contract, tables } = await irOf(path.join(root, "src/rich.ts"), "Rich");
421
- const named = {
422
- ...contract,
423
- observables: [
424
- {
425
- name: '*/\nthrow new Error("injected")\n/*',
426
- description: "A value.",
427
- valueType: field_type_1.FieldType.string,
428
- writable: false,
429
- },
430
- ],
431
- };
432
- const generated = (0, contract_source_1.generateContractDeclaration)({ contract: named, tables }, { from: 'file\nthrow new Error("injected")\n//source' });
433
- const file = path.join(root, "src/escaped.ts");
434
- await (0, promises_1.writeFile)(file, generated.source);
435
- expect((await irOf(file, "RichThings")).contract.observables).toEqual(named.observables);
436
- });
437
- test("selectors accept case-sensitive ids without rounding the version", () => {
438
- const upper = contractId.toUpperCase();
439
- expect((0, contract_source_1.parseContractSelector)(`${upper}@2`)).toEqual({ contractId: upper, version: 2 });
440
- expect(() => (0, contract_source_1.parseContractSelector)(`${contractId}@9007199254740993`)).toThrow(/Expected/);
441
- });
442
- test("JSON sources cannot inject code or paths through numeric metadata", async () => {
443
- const { contract, tables } = await irOf(path.join(root, "src/rich.ts"), "Rich");
444
- const injected = '1, injected: (() => { throw new Error("injected"); })()';
445
- const source = path.join(root, "unsafe.json");
446
- const writeManifest = async (provided, definitions) => (0, promises_1.writeFile)(source, JSON.stringify({ provides: [provided], tables: definitions }));
447
- for (const version of [injected, "../../outside", 0, 1.5, Number.MAX_SAFE_INTEGER + 1]) {
448
- await writeManifest({ ...contract, version }, tables);
449
- await expect((0, contract_add_1.addContract)({ source, root })).rejects.toThrow(/contract version/i);
450
- }
451
- for (const key of ["suggestedAccessLevel", "remoteAccessLevel"]) {
452
- for (const level of [injected, -1, 101, 1.5]) {
453
- await writeManifest({ ...contract, tools: [{ ...contract.tools[0], [key]: level }] }, tables);
454
- await expect((0, contract_add_1.addContract)({ source, root })).rejects.toThrow(/access level/i);
455
- }
456
- }
457
- await writeManifest(contract, [{ ...tables[0], versionNumber: injected }]);
458
- await expect((0, contract_add_1.addContract)({ source, root })).rejects.toThrow(/table version/i);
459
- await (0, promises_1.writeFile)(source, JSON.stringify({
460
- definition: { ...(0, isolated_artifact_1.isolatedContractToDefinition)(contract, tables), version: injected },
461
- tools: contract.tools.map((tool) => ({ name: tool.name, accessLevel: 20 })),
462
- }));
463
- await expect((0, contract_add_1.addContract)({ source, root })).rejects.toThrow(/contract version/i);
464
- await expect((0, promises_1.readFile)(path.join(root, "src/contracts/rich-things.v2.ts"))).rejects.toMatchObject({
465
- code: "ENOENT",
466
- });
467
- });
@@ -1 +0,0 @@
1
- export {};