@peers-app/peers-sdk 0.26.6 → 0.27.1

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 (189) hide show
  1. package/README.md +3 -1
  2. package/bin/peers-package.js +13 -0
  3. package/define/package.json +4 -0
  4. package/dist/contracts/__tests__/action-dispatch.test.js +56 -76
  5. package/dist/contracts/__tests__/also-implements.test.d.ts +1 -0
  6. package/dist/contracts/__tests__/also-implements.test.js +110 -0
  7. package/dist/contracts/__tests__/builder.test.js +45 -0
  8. package/dist/contracts/__tests__/contract-resolvers.test.js +134 -4
  9. package/dist/contracts/__tests__/frozen-contracts.test.d.ts +1 -0
  10. package/dist/contracts/__tests__/frozen-contracts.test.js +191 -0
  11. package/dist/contracts/__tests__/generic-tool-dispatch.test.js +13 -56
  12. package/dist/contracts/__tests__/host-contract-client.test.d.ts +1 -0
  13. package/dist/contracts/__tests__/host-contract-client.test.js +793 -0
  14. package/dist/contracts/__tests__/host-contract-transport.test.js +15 -0
  15. package/dist/contracts/__tests__/registry.test.js +68 -0
  16. package/dist/contracts/__tests__/target-dispatch.d.ts +11 -0
  17. package/dist/contracts/__tests__/target-dispatch.js +24 -0
  18. package/dist/contracts/__tests__/tool-catalog-service.test.js +37 -1
  19. package/dist/contracts/__tests__/tool-catalog.test.js +12 -3
  20. package/dist/contracts/__tests__/validate.test.js +177 -7
  21. package/dist/contracts/__tests__/workflow-context.test.js +0 -11
  22. package/dist/contracts/builder.d.ts +16 -2
  23. package/dist/contracts/builder.js +44 -3
  24. package/dist/contracts/contract-definition-schema.d.ts +251 -0
  25. package/dist/contracts/contract-definition-schema.js +48 -0
  26. package/dist/contracts/contract-provider-router.d.ts +2 -0
  27. package/dist/contracts/contract-provider-router.js +5 -2
  28. package/dist/contracts/contract-proxy.d.ts +52 -18
  29. package/dist/contracts/contract-proxy.js +144 -203
  30. package/dist/contracts/contract-resolvers.d.ts +6 -4
  31. package/dist/contracts/contract-resolvers.js +32 -9
  32. package/dist/contracts/frozen-contracts.d.ts +59 -0
  33. package/dist/contracts/frozen-contracts.js +86 -0
  34. package/dist/contracts/host-contract-client.d.ts +134 -0
  35. package/dist/contracts/host-contract-client.js +396 -0
  36. package/dist/contracts/host-contract-transport.d.ts +2 -0
  37. package/dist/contracts/host-contract-transport.js +8 -0
  38. package/dist/contracts/index.d.ts +6 -4
  39. package/dist/contracts/index.js +11 -5
  40. package/dist/contracts/registry.d.ts +31 -1
  41. package/dist/contracts/registry.js +100 -6
  42. package/dist/contracts/system/contract-catalog-contract.d.ts +61 -6
  43. package/dist/contracts/system/contract-catalog-contract.js +17 -5
  44. package/dist/contracts/tool-catalog-service.js +26 -6
  45. package/dist/contracts/tool-catalog.d.ts +1 -1
  46. package/dist/contracts/tool-catalog.js +4 -1
  47. package/dist/contracts/types.d.ts +32 -2
  48. package/dist/contracts/validate.d.ts +16 -1
  49. package/dist/contracts/validate.js +139 -25
  50. package/dist/data/change-tracking.d.ts +17 -5
  51. package/dist/data/change-tracking.js +22 -6
  52. package/dist/data/change-tracking.test.d.ts +1 -0
  53. package/dist/data/change-tracking.test.js +62 -0
  54. package/dist/data/create-group.js +1 -1
  55. package/dist/data/group-members.d.ts +14 -0
  56. package/dist/data/group-members.js +36 -0
  57. package/dist/data/group-members.test.js +49 -0
  58. package/dist/data/orm/sql.data-source.d.ts +9 -0
  59. package/dist/data/orm/sql.data-source.js +47 -2
  60. package/dist/data/orm/sql.data-source.test.js +142 -0
  61. package/dist/data/orm/table-container.js +9 -9
  62. package/dist/data/orm/table-container.test.js +44 -0
  63. package/dist/data/orm/types.d.ts +41 -1
  64. package/dist/data/orm/types.js +159 -28
  65. package/dist/data/orm/types.test.js +129 -0
  66. package/dist/data/peer-types.d.ts +8 -62
  67. package/dist/data/persistent-vars.d.ts +4 -1
  68. package/dist/data/persistent-vars.js +7 -2
  69. package/dist/data/tools.d.ts +29 -221
  70. package/dist/define/also-implements.test.d.ts +1 -0
  71. package/dist/define/also-implements.test.js +123 -0
  72. package/dist/define/context.d.ts +77 -0
  73. package/dist/define/context.js +2 -0
  74. package/dist/define/contract-ref.d.ts +177 -0
  75. package/dist/define/contract-ref.js +67 -0
  76. package/dist/define/declare-contract.d.ts +167 -0
  77. package/dist/define/declare-contract.js +220 -0
  78. package/dist/define/declare-contract.test.d.ts +1 -0
  79. package/dist/define/declare-contract.test.js +573 -0
  80. package/dist/define/define-package.d.ts +203 -0
  81. package/dist/define/define-package.js +289 -0
  82. package/dist/define/define.test.d.ts +1 -0
  83. package/dist/define/define.test.js +1010 -0
  84. package/dist/define/empty-fields.d.ts +15 -0
  85. package/dist/define/empty-fields.js +134 -0
  86. package/dist/define/empty-fields.test.d.ts +1 -0
  87. package/dist/define/empty-fields.test.js +55 -0
  88. package/dist/define/events-observables.test.d.ts +1 -0
  89. package/dist/define/events-observables.test.js +1013 -0
  90. package/dist/define/events.d.ts +81 -0
  91. package/dist/define/events.js +81 -0
  92. package/dist/define/generated-field.d.ts +20 -0
  93. package/dist/define/generated-field.js +25 -0
  94. package/dist/define/index.d.ts +28 -0
  95. package/dist/define/index.js +62 -0
  96. package/dist/define/lazy-members.d.ts +8 -0
  97. package/dist/define/lazy-members.js +38 -0
  98. package/dist/define/manifest.d.ts +63 -0
  99. package/dist/define/manifest.js +653 -0
  100. package/dist/define/observables.d.ts +146 -0
  101. package/dist/define/observables.js +187 -0
  102. package/dist/define/serve-members.d.ts +21 -0
  103. package/dist/define/serve-members.js +152 -0
  104. package/dist/define/serve-members.test.d.ts +1 -0
  105. package/dist/define/serve-members.test.js +630 -0
  106. package/dist/define/serve.d.ts +22 -0
  107. package/dist/define/serve.js +58 -0
  108. package/dist/define/system-contracts.d.ts +41 -0
  109. package/dist/define/system-contracts.js +21 -0
  110. package/dist/define/table-handle.d.ts +13 -0
  111. package/dist/define/table-handle.js +36 -0
  112. package/dist/define/table.d.ts +128 -0
  113. package/dist/define/table.js +122 -0
  114. package/dist/define/tool.d.ts +129 -0
  115. package/dist/define/tool.js +91 -0
  116. package/dist/define/vars.d.ts +82 -0
  117. package/dist/define/vars.js +256 -0
  118. package/dist/define/vars.test.d.ts +1 -0
  119. package/dist/define/vars.test.js +39 -0
  120. package/dist/define/wire-value.d.ts +12 -0
  121. package/dist/define/wire-value.js +76 -0
  122. package/dist/define/worker-state.d.ts +15 -0
  123. package/dist/define/worker-state.js +45 -0
  124. package/dist/device/tx-encoding.test.js +10 -0
  125. package/dist/index.d.ts +3 -0
  126. package/dist/index.js +5 -1
  127. package/dist/invites/group-approval.js +4 -2
  128. package/dist/invites/group-approval.test.js +2 -0
  129. package/dist/observable.d.ts +42 -2
  130. package/dist/observable.js +25 -7
  131. package/dist/package-build/build-package.d.ts +60 -0
  132. package/dist/package-build/build-package.js +312 -0
  133. package/dist/package-build/build-package.test.d.ts +1 -0
  134. package/dist/package-build/build-package.test.js +204 -0
  135. package/dist/package-build/cli.d.ts +7 -0
  136. package/dist/package-build/cli.js +218 -0
  137. package/dist/package-build/contract-add.d.ts +35 -0
  138. package/dist/package-build/contract-add.js +97 -0
  139. package/dist/package-build/contract-add.test.d.ts +1 -0
  140. package/dist/package-build/contract-add.test.js +467 -0
  141. package/dist/package-build/contract-source.d.ts +59 -0
  142. package/dist/package-build/contract-source.js +471 -0
  143. package/dist/package-build/freeze-contracts.d.ts +56 -0
  144. package/dist/package-build/freeze-contracts.js +198 -0
  145. package/dist/package-build/freeze-contracts.test.d.ts +1 -0
  146. package/dist/package-build/freeze-contracts.test.js +355 -0
  147. package/dist/package-installer/package-creator.d.ts +4 -0
  148. package/dist/package-installer/package-creator.js +57 -16
  149. package/dist/package-installer/package-creator.test.js +86 -0
  150. package/dist/package-loader/contract-members.d.ts +53 -0
  151. package/dist/package-loader/contract-members.js +31 -0
  152. package/dist/package-loader/contract-package-loader.js +5 -1
  153. package/dist/package-loader/contract-package-loader.test.js +11 -0
  154. package/dist/package-loader/host-authority-loading.test.js +9 -5
  155. package/dist/package-loader/index.d.ts +1 -0
  156. package/dist/package-loader/index.js +1 -0
  157. package/dist/package-loader/isolated-artifact.d.ts +80 -17
  158. package/dist/package-loader/isolated-artifact.js +257 -51
  159. package/dist/package-loader/isolated-artifact.test.js +294 -21
  160. package/dist/package-loader/isolated-runtime.d.ts +22 -7
  161. package/dist/package-loader/isolated-table-gateway.js +30 -11
  162. package/dist/package-loader/isolated-table-gateway.test.js +243 -0
  163. package/dist/package-loader/package-loader.d.ts +8 -1
  164. package/dist/package-loader/package-loader.js +39 -20
  165. package/dist/package-loader/package-loader.test.js +47 -0
  166. package/dist/peer-id.d.ts +25 -0
  167. package/dist/peer-id.js +99 -0
  168. package/dist/serial-json.compat.test.d.ts +1 -0
  169. package/dist/serial-json.compat.test.js +369 -0
  170. package/dist/serial-json.d.ts +41 -5
  171. package/dist/serial-json.js +216 -157
  172. package/dist/serial-json.oracle.d.ts +21 -0
  173. package/dist/serial-json.oracle.js +222 -0
  174. package/dist/serial-json.test.js +315 -0
  175. package/dist/testing/index.d.ts +4 -0
  176. package/dist/testing/index.js +8 -0
  177. package/dist/testing/mock-host-contract.d.ts +123 -0
  178. package/dist/testing/mock-host-contract.js +434 -0
  179. package/dist/testing/mock-host-contract.test.d.ts +1 -0
  180. package/dist/testing/mock-host-contract.test.js +782 -0
  181. package/dist/types/field-type.d.ts +35 -18
  182. package/dist/types/field-type.js +4 -1
  183. package/dist/types/zod-types.d.ts +9 -0
  184. package/dist/types/zod-types.js +8 -2
  185. package/dist/utils.d.ts +22 -25
  186. package/dist/utils.js +45 -92
  187. package/dist/utils.test.js +36 -0
  188. package/package.json +9 -2
  189. package/testing/package.json +4 -0
@@ -0,0 +1,203 @@
1
+ import type { IExposedContract } from "../contracts/types";
2
+ import type { IIsolatedContractEvent, IIsolatedContractObservable, IIsolatedPackageNetwork } from "../package-loader/isolated-artifact";
3
+ import type { IAppNav } from "../types/app-nav";
4
+ import type { IPackageContext } from "./context";
5
+ import type { IContractRef } from "./contract-ref";
6
+ import type { IContractDeclaration } from "./declare-contract";
7
+ import { type IPackageEvent } from "./events";
8
+ import { type IPackageObservable, type IPackageObservableDeclaration } from "./observables";
9
+ import type { IPackageTable } from "./table";
10
+ import { type IPackageTool, type IPackageToolDeclaration } from "./tool";
11
+ /**
12
+ * An observable on a provided contract: from `defineObservable`, or Peers IR (with its
13
+ * `persistentVar` binding) for a contract defined elsewhere.
14
+ */
15
+ export type PackageContractObservable = IPackageObservable | IIsolatedContractObservable;
16
+ /**
17
+ * An observable on a declared contract: from `declareObservable` (or `defineObservable`), or
18
+ * Peers IR.
19
+ */
20
+ export type PackageContractObservableDeclaration = IPackageObservableDeclaration | IIsolatedContractObservable;
21
+ /** An event on a provided contract: from `defineEvent`, or Peers IR for a contract defined elsewhere. */
22
+ export type PackageContractEvent = IPackageEvent<any> | IIsolatedContractEvent;
23
+ /** Options for {@link PackageBuilder.consumes}. */
24
+ export interface IPackageConsumeOptions {
25
+ /** The package works without a provider; calls fail until one is installed. */
26
+ optional?: boolean;
27
+ /** Accept only these providers. */
28
+ providerPackageIds?: string[];
29
+ /** Fall back to the group's default provider when none of `providerPackageIds` is installed. */
30
+ fallbackToDefaultProvider?: boolean;
31
+ }
32
+ /** A contract the package consumes. */
33
+ export interface IPackageConsumedContract extends IPackageConsumeOptions {
34
+ /** The reference handlers call it through. */
35
+ readonly ref: IContractRef<unknown>;
36
+ }
37
+ /**
38
+ * A contract version this contract also implements, so its consumers are served by this
39
+ * contract's handlers: an older version of the same contract, by number (the package's
40
+ * `frozen-contracts.json` gives its shape when the package builds), or another contract's
41
+ * declaration from `declareContract`. The contract's shape must satisfy each one.
42
+ */
43
+ export type AlsoImplementsTarget = number | IContractDeclaration<any, any, any, any, any, any>;
44
+ /** What {@link defineContract} takes. Omitted member lists are empty. */
45
+ export interface IPackageContractDefinition<Id extends string = string, V extends number = number, Tables extends readonly IPackageTable<any>[] = readonly IPackageTable<any>[], Tools extends readonly IPackageTool<any, any>[] = readonly IPackageTool<any, any>[], Observables extends readonly PackageContractObservable[] = readonly PackageContractObservable[], Events extends readonly PackageContractEvent[] = readonly PackageContractEvent[]> {
46
+ /** The contract's id, from `newid()`. */
47
+ contractId: Id;
48
+ /** The contract's version, a positive integer. */
49
+ version: V;
50
+ /** Human-readable name. */
51
+ name: string;
52
+ /** What the contract is for. */
53
+ description?: string;
54
+ /** Tables the contract exposes. Each becomes one of the providing package's tables. */
55
+ tables?: Tables;
56
+ /** Tools the contract provides. */
57
+ tools?: Tools;
58
+ /** Observables the contract exposes, from `defineObservable` (or IR with a `persistentVar`). */
59
+ observables?: Observables;
60
+ /** Events the contract may emit, from `defineEvent` (or IR). */
61
+ events?: Events;
62
+ /**
63
+ * Older versions of this contract (by number) or other contracts (by declaration) whose
64
+ * consumers this contract's handlers also serve: a backwards-compatible change keeps serving
65
+ * the versions before it. Each must be satisfied by this contract's shape.
66
+ */
67
+ alsoImplements?: readonly AlsoImplementsTarget[];
68
+ }
69
+ /**
70
+ * A contract's id, version, and members: what a contract from {@link defineContract} and a
71
+ * declaration from `declareContract` share. Contract references are typed from it.
72
+ */
73
+ export interface IContractMembers<Id extends string = string, V extends number = number, Tables extends readonly IPackageTable<any>[] = readonly IPackageTable<any>[], Tools extends readonly IPackageToolDeclaration<any, any>[] = readonly IPackageToolDeclaration<any, any>[], Observables extends readonly PackageContractObservableDeclaration[] = readonly PackageContractObservableDeclaration[], Events extends readonly PackageContractEvent[] = readonly PackageContractEvent[]> {
74
+ /** The contract's id. */
75
+ readonly contractId: Id;
76
+ /** The contract's version. */
77
+ readonly version: V;
78
+ /** Human-readable name. */
79
+ readonly name: string;
80
+ /** What the contract is for. */
81
+ readonly description?: string;
82
+ /** Tables the contract exposes. */
83
+ readonly tables: Readonly<Tables>;
84
+ /** Tools the contract provides. */
85
+ readonly tools: Readonly<Tools>;
86
+ /** Observables the contract exposes. */
87
+ readonly observables: Readonly<Observables>;
88
+ /** Events the contract may emit. */
89
+ readonly events: Readonly<Events>;
90
+ }
91
+ /**
92
+ * A contract declared with {@link defineContract}: its id, version, and members, implemented.
93
+ * A package provides it with `pkg.provides(contract)`. Its type carries every member's name and
94
+ * shape, so `contractRef<typeof Contract>(contractId, version)` gives consumers (the package's
95
+ * UIs, other packages) typed calls without importing the handlers.
96
+ */
97
+ export interface IPackageContract<Id extends string = string, V extends number = number, Tables extends readonly IPackageTable<any>[] = readonly IPackageTable<any>[], Tools extends readonly IPackageTool<any, any>[] = readonly IPackageTool<any, any>[], Observables extends readonly PackageContractObservable[] = readonly PackageContractObservable[], Events extends readonly PackageContractEvent[] = readonly PackageContractEvent[]> extends IContractMembers<Id, V, Tables, Tools, Observables, Events> {
98
+ /** Marks a provided contract. */
99
+ readonly kind: "contract";
100
+ /**
101
+ * Other contracts the package provides whose tools this contract's consumers may call on it,
102
+ * from `implementContract(declaration, { exposes })`. Not part of the contract's shape.
103
+ */
104
+ readonly exposes?: readonly IExposedContract[];
105
+ /** Contract versions this contract also implements (see {@link AlsoImplementsTarget}). */
106
+ readonly alsoImplements?: readonly AlsoImplementsTarget[];
107
+ }
108
+ /**
109
+ * Declare a contract: its id, version, name, and the tables, tools, observables, and events it
110
+ * exposes. Export it from `src/package.ts` and provide it with `pkg.provides(contract)`; a UI or
111
+ * another package references it with `contractRef<typeof Contract>(contractId, version)`.
112
+ *
113
+ * @param definition - Id, version, name, description, and members.
114
+ */
115
+ export declare function defineContract<Id extends string, V extends number, Tables extends readonly IPackageTable<any>[] = [], Tools extends readonly IPackageTool<any, any>[] = [], Observables extends readonly PackageContractObservable[] = [], Events extends readonly PackageContractEvent[] = []>(definition: IPackageContractDefinition<Id, V, Tables, Tools, Observables, Events>): IPackageContract<Id, V, Tables, Tools, Observables, Events>;
116
+ /**
117
+ * True for a contract from {@link defineContract}.
118
+ *
119
+ * @param value - What was passed to `pkg.provides`.
120
+ */
121
+ export declare function isPackageContract(value: unknown): value is IPackageContract;
122
+ /**
123
+ * Everything the Runtime needs to know about a package: its tools, events, observables, and
124
+ * tables, the contracts it provides, and the contracts it consumes. `peers-package` turns it
125
+ * into the manifest; inside the worker, `servePackage` registers its tools.
126
+ */
127
+ export interface IPackageDefinition {
128
+ /** Marks a package definition. */
129
+ readonly kind: "package";
130
+ readonly packageId: string;
131
+ readonly version: string;
132
+ /** `sandbox` (the default) or `privileged`. */
133
+ readonly executionMode?: "sandbox" | "privileged";
134
+ /** Hosts System HTTP may reach for this package, and its credentials. */
135
+ readonly network?: IIsolatedPackageNetwork;
136
+ readonly appNavs: readonly IAppNav[];
137
+ /** Every table the package owns: private ones and the ones its contracts expose. */
138
+ readonly tables: readonly IPackageTable[];
139
+ readonly provides: readonly IPackageContract[];
140
+ readonly consumes: readonly IPackageConsumedContract[];
141
+ /** Run when the package's worker starts, in the order they were added. */
142
+ readonly startHooks: readonly PackageStartHook[];
143
+ }
144
+ /**
145
+ * Background work for when the package's worker starts. Its `ctx` belongs to no call: it can use
146
+ * the package's own tables and variables, but calls to other contracts are refused.
147
+ */
148
+ export type PackageStartHook = (ctx: IPackageContext) => unknown;
149
+ /** The builder {@link definePackage} passes its callback. */
150
+ export declare class PackageBuilder {
151
+ /** The package's id, from `newid()`. */
152
+ packageId: string;
153
+ /** The package's version, usually from `package.json`. */
154
+ version: string;
155
+ /** `sandbox` (the default) or `privileged`, which needs an operator's trust. */
156
+ executionMode?: "sandbox" | "privileged";
157
+ /** Hosts System HTTP may reach for this package. */
158
+ network?: IIsolatedPackageNetwork;
159
+ /** Entries in the app's navigation. */
160
+ appNavs: IAppNav[];
161
+ /** Tables only this package uses. Tables a contract exposes don't need listing here. */
162
+ tables: IPackageTable<any>[];
163
+ private readonly provided;
164
+ private readonly consumed;
165
+ private readonly starts;
166
+ /**
167
+ * Run `fn` each time the package's worker starts, after the package's variables load and
168
+ * before its in-memory observables publish, so a value set here is the first one readers
169
+ * see. The worker waits for it, and a failure fails the start, so catch what can fail and
170
+ * don't await long-running work.
171
+ *
172
+ * `ctx` belongs to no call: use it for the package's own tables, and to watch or load
173
+ * state. Calls to other contracts, such as System HTTP, are refused outside a call; to fetch
174
+ * in the background, schedule one of the package's own tools with System Scheduler.
175
+ *
176
+ * @param fn - Called with the worker's `ctx`.
177
+ */
178
+ onStart(fn: PackageStartHook): void;
179
+ /**
180
+ * Provide a contract: this package serves its tools and holds its tables, observables, and
181
+ * events.
182
+ *
183
+ * @param contract - From {@link defineContract}.
184
+ */
185
+ provides(contract: IPackageContract<any, any, any, any, any, any>): void;
186
+ /**
187
+ * Consume a contract another package provides. Handlers call it through `ref(ctx)`.
188
+ *
189
+ * @param ref - From `contractRef(contractId, version)`.
190
+ * @param options - Optional dependency and provider selection.
191
+ */
192
+ consumes(ref: IContractRef<any>, options?: IPackageConsumeOptions): void;
193
+ /** @internal Check and freeze the definition. */
194
+ _build(): IPackageDefinition;
195
+ }
196
+ /**
197
+ * Declare a package: the contracts it provides (from {@link defineContract}), the contracts it
198
+ * consumes, and its private tables. Export the result as the default export of
199
+ * `src/package.ts`.
200
+ *
201
+ * @param fn - Fills in the {@link PackageBuilder}.
202
+ */
203
+ export declare function definePackage(fn: (pkg: PackageBuilder) => void): IPackageDefinition;
@@ -0,0 +1,289 @@
1
+ "use strict";
2
+ Object.defineProperty(exports, "__esModule", { value: true });
3
+ exports.PackageBuilder = void 0;
4
+ exports.defineContract = defineContract;
5
+ exports.isPackageContract = isPackageContract;
6
+ exports.definePackage = definePackage;
7
+ const peer_id_1 = require("../peer-id");
8
+ const events_1 = require("./events");
9
+ const observables_1 = require("./observables");
10
+ const tool_1 = require("./tool");
11
+ /**
12
+ * Declare a contract: its id, version, name, and the tables, tools, observables, and events it
13
+ * exposes. Export it from `src/package.ts` and provide it with `pkg.provides(contract)`; a UI or
14
+ * another package references it with `contractRef<typeof Contract>(contractId, version)`.
15
+ *
16
+ * @param definition - Id, version, name, description, and members.
17
+ */
18
+ function defineContract(definition) {
19
+ const { contractId, version, name, description } = definition ?? {};
20
+ if (typeof name !== "string" || name.trim() === "") {
21
+ throw new Error("defineContract requires a name");
22
+ }
23
+ const label = `Contract ${name} (${contractId}@${version})`;
24
+ if (!(0, peer_id_1.isid)(contractId)) {
25
+ throw new Error(`${label} needs a 25-character contract id from newid()`);
26
+ }
27
+ if (!Number.isInteger(version) || version < 1) {
28
+ throw new Error(`${label} version must be a positive integer`);
29
+ }
30
+ if (description !== undefined && typeof description !== "string") {
31
+ throw new Error(`${label} description must be a string`);
32
+ }
33
+ const members = (list, what) => {
34
+ if (list === undefined) {
35
+ return [];
36
+ }
37
+ if (!Array.isArray(list)) {
38
+ throw new Error(`${label} ${what} must be an array`);
39
+ }
40
+ return list;
41
+ };
42
+ const alsoImplements = alsoImplementsTargets(definition.alsoImplements, contractId, version, label);
43
+ const tables = members(definition.tables, "tables");
44
+ const tools = members(definition.tools, "tools");
45
+ const observables = members(definition.observables, "observables");
46
+ const events = members(definition.events, "events");
47
+ const unique = (names, kind, memberName) => {
48
+ if (names.has(memberName)) {
49
+ throw new Error(`${label} declares ${kind} "${memberName}" twice`);
50
+ }
51
+ names.add(memberName);
52
+ };
53
+ const tableNames = new Set();
54
+ for (const table of tables) {
55
+ if (table?.kind !== "table") {
56
+ throw new Error(`${label} lists something that isn't a table from defineTable`);
57
+ }
58
+ unique(tableNames, "table", table.definition.name);
59
+ }
60
+ const toolNames = new Set();
61
+ for (const tool of tools) {
62
+ if (tool?.kind !== "tool") {
63
+ throw new Error(`${label} lists something that isn't a tool from defineTool`);
64
+ }
65
+ if (!(0, tool_1.isImplementedTool)(tool)) {
66
+ throw new Error(`${label} tool "${tool.definition.name}" has no handler; to declare a contract other packages implement, use declareContract and implementContract`);
67
+ }
68
+ unique(toolNames, "tool", tool.definition.name);
69
+ }
70
+ const observableNames = new Set();
71
+ for (const observable of observables) {
72
+ const observableName = (0, observables_1.isPackageObservable)(observable)
73
+ ? observable.definition.name
74
+ : observable?.name;
75
+ if (typeof observableName !== "string") {
76
+ throw new Error(`${label} lists an observable that isn't from defineObservable or Peers IR`);
77
+ }
78
+ if (!(0, observables_1.isPackageObservable)(observable) && !observable.persistentVar) {
79
+ throw new Error(`${label} observable "${observableName}" is IR without a persistentVar; declare an in-memory observable with defineObservable`);
80
+ }
81
+ if ((0, observables_1.isPackageObservable)(observable) && !(0, observables_1.isImplementedObservable)(observable)) {
82
+ throw new Error(`${label} observable "${observableName}" has no source; to declare a contract other packages implement, use declareContract and implementContract`);
83
+ }
84
+ unique(observableNames, "observable", observableName);
85
+ }
86
+ const eventNames = new Set();
87
+ for (const event of events) {
88
+ const eventName = (0, events_1.isPackageEvent)(event)
89
+ ? event.definition.name
90
+ : event?.name;
91
+ if (typeof eventName !== "string") {
92
+ throw new Error(`${label} lists an event that isn't from defineEvent or Peers IR`);
93
+ }
94
+ unique(eventNames, "event", eventName);
95
+ }
96
+ return Object.freeze({
97
+ kind: "contract",
98
+ contractId,
99
+ version,
100
+ name,
101
+ ...(description === undefined ? {} : { description }),
102
+ tables: Object.freeze([...tables]),
103
+ tools: Object.freeze([...tools]),
104
+ observables: Object.freeze([...observables]),
105
+ events: Object.freeze([...events]),
106
+ ...(alsoImplements.length ? { alsoImplements: Object.freeze(alsoImplements) } : {}),
107
+ });
108
+ }
109
+ /** Check a contract's `alsoImplements`: older versions by number, or other contracts' declarations. */
110
+ function alsoImplementsTargets(value, contractId, version, label) {
111
+ if (value === undefined)
112
+ return [];
113
+ if (!Array.isArray(value)) {
114
+ throw new Error(`${label} alsoImplements must be a list of versions or declarations`);
115
+ }
116
+ const seen = new Set();
117
+ return value.map((target) => {
118
+ let key;
119
+ if (typeof target === "number") {
120
+ if (!Number.isInteger(target) || target < 1) {
121
+ throw new Error(`${label} alsoImplements version ${target} must be a positive integer`);
122
+ }
123
+ key = `${contractId}@${target}`;
124
+ }
125
+ else {
126
+ const declaration = target;
127
+ if (declaration?.kind !== "contract-ref" ||
128
+ declaration.declaration?.kind !== "contract-declaration") {
129
+ throw new Error(`${label} alsoImplements takes version numbers and declarations from declareContract`);
130
+ }
131
+ key = `${declaration.contractId}@${declaration.version}`;
132
+ }
133
+ if (key === `${contractId}@${version}`) {
134
+ throw new Error(`${label} can't also implement itself`);
135
+ }
136
+ // Its own older versions come from frozen-contracts.json, the shapes its releases froze.
137
+ if (typeof target !== "number" && target.contractId === contractId) {
138
+ throw new Error(`${label} alsoImplements takes its own contract's older versions by number, not by declaration`);
139
+ }
140
+ if (typeof target === "number" && target > version) {
141
+ throw new Error(`${label} alsoImplements v${target} must be older than v${version}`);
142
+ }
143
+ if (seen.has(key)) {
144
+ throw new Error(`${label} also implements ${key} twice`);
145
+ }
146
+ seen.add(key);
147
+ return target;
148
+ });
149
+ }
150
+ /**
151
+ * True for a contract from {@link defineContract}.
152
+ *
153
+ * @param value - What was passed to `pkg.provides`.
154
+ */
155
+ function isPackageContract(value) {
156
+ return value?.kind === "contract";
157
+ }
158
+ /** The builder {@link definePackage} passes its callback. */
159
+ class PackageBuilder {
160
+ /** The package's id, from `newid()`. */
161
+ packageId = "";
162
+ /** The package's version, usually from `package.json`. */
163
+ version = "";
164
+ /** `sandbox` (the default) or `privileged`, which needs an operator's trust. */
165
+ executionMode;
166
+ /** Hosts System HTTP may reach for this package. */
167
+ network;
168
+ /** Entries in the app's navigation. */
169
+ appNavs = [];
170
+ /** Tables only this package uses. Tables a contract exposes don't need listing here. */
171
+ tables = [];
172
+ provided = [];
173
+ consumed = [];
174
+ starts = [];
175
+ /**
176
+ * Run `fn` each time the package's worker starts, after the package's variables load and
177
+ * before its in-memory observables publish, so a value set here is the first one readers
178
+ * see. The worker waits for it, and a failure fails the start, so catch what can fail and
179
+ * don't await long-running work.
180
+ *
181
+ * `ctx` belongs to no call: use it for the package's own tables, and to watch or load
182
+ * state. Calls to other contracts, such as System HTTP, are refused outside a call; to fetch
183
+ * in the background, schedule one of the package's own tools with System Scheduler.
184
+ *
185
+ * @param fn - Called with the worker's `ctx`.
186
+ */
187
+ onStart(fn) {
188
+ if (typeof fn !== "function") {
189
+ throw new Error("pkg.onStart takes a function");
190
+ }
191
+ this.starts.push(fn);
192
+ }
193
+ /**
194
+ * Provide a contract: this package serves its tools and holds its tables, observables, and
195
+ * events.
196
+ *
197
+ * @param contract - From {@link defineContract}.
198
+ */
199
+ provides(contract) {
200
+ if (!isPackageContract(contract)) {
201
+ throw new Error(contract?.declaration
202
+ ? "pkg.provides takes a contract: implement a declaration with implementContract first"
203
+ : "pkg.provides takes a contract from defineContract or implementContract");
204
+ }
205
+ this.provided.push(contract);
206
+ }
207
+ /**
208
+ * Consume a contract another package provides. Handlers call it through `ref(ctx)`.
209
+ *
210
+ * @param ref - From `contractRef(contractId, version)`.
211
+ * @param options - Optional dependency and provider selection.
212
+ */
213
+ consumes(ref, options = {}) {
214
+ this.consumed.push({ ref, ...options });
215
+ }
216
+ /** @internal Check and freeze the definition. */
217
+ _build() {
218
+ if (!(0, peer_id_1.isid)(this.packageId)) {
219
+ throw new Error(`packageId must be a 25-character peer id from newid(), got "${this.packageId}"`);
220
+ }
221
+ if (typeof this.version !== "string" || this.version.trim() === "") {
222
+ throw new Error("A package must set version");
223
+ }
224
+ const tables = new Map();
225
+ const addTable = (table, where) => {
226
+ if (table?.kind !== "table") {
227
+ throw new Error(`${where} lists something that isn't a table from defineTable`);
228
+ }
229
+ const existing = tables.get(table.definition.name);
230
+ if (existing && existing !== table) {
231
+ throw new Error(`Two different tables are named "${table.definition.name}"`);
232
+ }
233
+ tables.set(table.definition.name, table);
234
+ };
235
+ for (const table of this.tables) {
236
+ addTable(table, "pkg.tables");
237
+ }
238
+ const contractKeys = new Set();
239
+ for (const contract of this.provided) {
240
+ const key = `${contract.contractId}@${contract.version}`;
241
+ if (contractKeys.has(key)) {
242
+ throw new Error(`Contract ${contract.name} (${key}) is provided twice`);
243
+ }
244
+ contractKeys.add(key);
245
+ for (const table of contract.tables) {
246
+ addTable(table, `Contract ${contract.name} (${key})`);
247
+ }
248
+ }
249
+ const provides = [...this.provided];
250
+ for (const contract of provides) {
251
+ for (const exposed of contract.exposes ?? []) {
252
+ const exposedKey = `${exposed.contractId}@${exposed.version}`;
253
+ if (!contractKeys.has(exposedKey)) {
254
+ throw new Error(`Contract ${contract.name} (${contract.contractId}@${contract.version}) exposes ${exposedKey}, which the package doesn't provide; add it with pkg.provides`);
255
+ }
256
+ }
257
+ }
258
+ for (const { ref } of this.consumed) {
259
+ if (ref?.kind !== "contract-ref") {
260
+ throw new Error("pkg.consumes takes a reference from contractRef(contractId, version)");
261
+ }
262
+ }
263
+ return Object.freeze({
264
+ kind: "package",
265
+ packageId: this.packageId,
266
+ version: this.version,
267
+ ...(this.executionMode === undefined ? {} : { executionMode: this.executionMode }),
268
+ ...(this.network === undefined ? {} : { network: this.network }),
269
+ appNavs: Object.freeze([...this.appNavs]),
270
+ tables: Object.freeze([...tables.values()]),
271
+ provides: Object.freeze(provides),
272
+ consumes: Object.freeze(this.consumed.map((consumed) => Object.freeze({ ...consumed }))),
273
+ startHooks: Object.freeze([...this.starts]),
274
+ });
275
+ }
276
+ }
277
+ exports.PackageBuilder = PackageBuilder;
278
+ /**
279
+ * Declare a package: the contracts it provides (from {@link defineContract}), the contracts it
280
+ * consumes, and its private tables. Export the result as the default export of
281
+ * `src/package.ts`.
282
+ *
283
+ * @param fn - Fills in the {@link PackageBuilder}.
284
+ */
285
+ function definePackage(fn) {
286
+ const pkg = new PackageBuilder();
287
+ fn(pkg);
288
+ return pkg._build();
289
+ }
@@ -0,0 +1 @@
1
+ export {};