@peers-app/peers-sdk 0.26.5 → 0.27.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +3 -1
- package/bin/peers-package.js +13 -0
- package/define/package.json +4 -0
- package/dist/contracts/__tests__/action-dispatch.test.js +56 -76
- package/dist/contracts/__tests__/also-implements.test.d.ts +1 -0
- package/dist/contracts/__tests__/also-implements.test.js +110 -0
- package/dist/contracts/__tests__/builder.test.js +45 -0
- package/dist/contracts/__tests__/contract-resolvers.test.js +134 -4
- package/dist/contracts/__tests__/frozen-contracts.test.d.ts +1 -0
- package/dist/contracts/__tests__/frozen-contracts.test.js +191 -0
- package/dist/contracts/__tests__/generic-tool-dispatch.test.js +13 -56
- package/dist/contracts/__tests__/host-contract-client.test.d.ts +1 -0
- package/dist/contracts/__tests__/host-contract-client.test.js +793 -0
- package/dist/contracts/__tests__/host-contract-transport.test.js +15 -0
- package/dist/contracts/__tests__/registry.test.js +68 -0
- package/dist/contracts/__tests__/target-dispatch.d.ts +11 -0
- package/dist/contracts/__tests__/target-dispatch.js +24 -0
- package/dist/contracts/__tests__/tool-catalog-service.test.js +37 -1
- package/dist/contracts/__tests__/tool-catalog.test.js +12 -3
- package/dist/contracts/__tests__/validate.test.js +177 -7
- package/dist/contracts/__tests__/workflow-context.test.js +0 -11
- package/dist/contracts/builder.d.ts +16 -2
- package/dist/contracts/builder.js +44 -3
- package/dist/contracts/contract-definition-schema.d.ts +251 -0
- package/dist/contracts/contract-definition-schema.js +48 -0
- package/dist/contracts/contract-provider-router.d.ts +2 -0
- package/dist/contracts/contract-provider-router.js +5 -2
- package/dist/contracts/contract-proxy.d.ts +52 -18
- package/dist/contracts/contract-proxy.js +144 -203
- package/dist/contracts/contract-resolvers.d.ts +6 -4
- package/dist/contracts/contract-resolvers.js +32 -9
- package/dist/contracts/frozen-contracts.d.ts +59 -0
- package/dist/contracts/frozen-contracts.js +86 -0
- package/dist/contracts/host-contract-client.d.ts +134 -0
- package/dist/contracts/host-contract-client.js +396 -0
- package/dist/contracts/host-contract-transport.d.ts +2 -0
- package/dist/contracts/host-contract-transport.js +8 -0
- package/dist/contracts/index.d.ts +6 -4
- package/dist/contracts/index.js +11 -5
- package/dist/contracts/registry.d.ts +31 -1
- package/dist/contracts/registry.js +100 -6
- package/dist/contracts/system/contract-catalog-contract.d.ts +61 -6
- package/dist/contracts/system/contract-catalog-contract.js +17 -5
- package/dist/contracts/tool-catalog-service.js +26 -6
- package/dist/contracts/tool-catalog.d.ts +1 -1
- package/dist/contracts/tool-catalog.js +4 -1
- package/dist/contracts/types.d.ts +32 -2
- package/dist/contracts/validate.d.ts +16 -1
- package/dist/contracts/validate.js +139 -25
- package/dist/data/change-tracking.d.ts +17 -5
- package/dist/data/change-tracking.js +22 -6
- package/dist/data/change-tracking.test.d.ts +1 -0
- package/dist/data/change-tracking.test.js +62 -0
- package/dist/data/group-members.d.ts +6 -1
- package/dist/data/group-members.js +12 -4
- package/dist/data/groups.d.ts +6 -1
- package/dist/data/groups.js +12 -4
- package/dist/data/orm/sql.data-source.d.ts +9 -0
- package/dist/data/orm/sql.data-source.js +47 -2
- package/dist/data/orm/sql.data-source.test.js +142 -0
- package/dist/data/orm/table-container.js +9 -9
- package/dist/data/orm/table-container.test.js +44 -0
- package/dist/data/orm/types.d.ts +41 -1
- package/dist/data/orm/types.js +159 -28
- package/dist/data/orm/types.test.js +129 -0
- package/dist/data/package-versions.d.ts +5 -1
- package/dist/data/package-versions.js +11 -4
- package/dist/data/packages.d.ts +7 -1
- package/dist/data/packages.js +13 -4
- package/dist/data/peer-types.d.ts +8 -62
- package/dist/data/persistent-vars.d.ts +4 -1
- package/dist/data/persistent-vars.js +7 -2
- package/dist/data/table-signing.test.d.ts +1 -0
- package/dist/data/table-signing.test.js +118 -0
- package/dist/data/tools.d.ts +29 -221
- package/dist/data/users.d.ts +1 -2
- package/dist/data/users.js +8 -5
- package/dist/define/also-implements.test.d.ts +1 -0
- package/dist/define/also-implements.test.js +123 -0
- package/dist/define/context.d.ts +77 -0
- package/dist/define/context.js +2 -0
- package/dist/define/contract-ref.d.ts +177 -0
- package/dist/define/contract-ref.js +67 -0
- package/dist/define/declare-contract.d.ts +167 -0
- package/dist/define/declare-contract.js +220 -0
- package/dist/define/declare-contract.test.d.ts +1 -0
- package/dist/define/declare-contract.test.js +573 -0
- package/dist/define/define-package.d.ts +203 -0
- package/dist/define/define-package.js +289 -0
- package/dist/define/define.test.d.ts +1 -0
- package/dist/define/define.test.js +1010 -0
- package/dist/define/empty-fields.d.ts +15 -0
- package/dist/define/empty-fields.js +134 -0
- package/dist/define/empty-fields.test.d.ts +1 -0
- package/dist/define/empty-fields.test.js +55 -0
- package/dist/define/events-observables.test.d.ts +1 -0
- package/dist/define/events-observables.test.js +1013 -0
- package/dist/define/events.d.ts +81 -0
- package/dist/define/events.js +81 -0
- package/dist/define/generated-field.d.ts +20 -0
- package/dist/define/generated-field.js +25 -0
- package/dist/define/index.d.ts +28 -0
- package/dist/define/index.js +62 -0
- package/dist/define/lazy-members.d.ts +8 -0
- package/dist/define/lazy-members.js +38 -0
- package/dist/define/manifest.d.ts +63 -0
- package/dist/define/manifest.js +653 -0
- package/dist/define/observables.d.ts +146 -0
- package/dist/define/observables.js +187 -0
- package/dist/define/serve-members.d.ts +21 -0
- package/dist/define/serve-members.js +152 -0
- package/dist/define/serve-members.test.d.ts +1 -0
- package/dist/define/serve-members.test.js +630 -0
- package/dist/define/serve.d.ts +22 -0
- package/dist/define/serve.js +58 -0
- package/dist/define/system-contracts.d.ts +41 -0
- package/dist/define/system-contracts.js +21 -0
- package/dist/define/table-handle.d.ts +13 -0
- package/dist/define/table-handle.js +36 -0
- package/dist/define/table.d.ts +128 -0
- package/dist/define/table.js +122 -0
- package/dist/define/tool.d.ts +129 -0
- package/dist/define/tool.js +91 -0
- package/dist/define/vars.d.ts +82 -0
- package/dist/define/vars.js +256 -0
- package/dist/define/vars.test.d.ts +1 -0
- package/dist/define/vars.test.js +39 -0
- package/dist/define/wire-value.d.ts +12 -0
- package/dist/define/wire-value.js +76 -0
- package/dist/define/worker-state.d.ts +15 -0
- package/dist/define/worker-state.js +45 -0
- package/dist/device/tx-encoding.test.js +10 -0
- package/dist/index.d.ts +3 -0
- package/dist/index.js +5 -1
- package/dist/observable.d.ts +42 -2
- package/dist/observable.js +25 -7
- package/dist/package-build/build-package.d.ts +60 -0
- package/dist/package-build/build-package.js +312 -0
- package/dist/package-build/build-package.test.d.ts +1 -0
- package/dist/package-build/build-package.test.js +204 -0
- package/dist/package-build/cli.d.ts +7 -0
- package/dist/package-build/cli.js +218 -0
- package/dist/package-build/contract-add.d.ts +35 -0
- package/dist/package-build/contract-add.js +97 -0
- package/dist/package-build/contract-add.test.d.ts +1 -0
- package/dist/package-build/contract-add.test.js +467 -0
- package/dist/package-build/contract-source.d.ts +59 -0
- package/dist/package-build/contract-source.js +471 -0
- package/dist/package-build/freeze-contracts.d.ts +56 -0
- package/dist/package-build/freeze-contracts.js +198 -0
- package/dist/package-build/freeze-contracts.test.d.ts +1 -0
- package/dist/package-build/freeze-contracts.test.js +355 -0
- package/dist/package-installer/package-creator.d.ts +4 -0
- package/dist/package-installer/package-creator.js +57 -16
- package/dist/package-installer/package-creator.test.js +86 -0
- package/dist/package-loader/contract-members.d.ts +53 -0
- package/dist/package-loader/contract-members.js +31 -0
- package/dist/package-loader/contract-package-loader.js +5 -1
- package/dist/package-loader/contract-package-loader.test.js +11 -0
- package/dist/package-loader/host-authority-loading.test.js +9 -5
- package/dist/package-loader/index.d.ts +1 -0
- package/dist/package-loader/index.js +1 -0
- package/dist/package-loader/isolated-artifact.d.ts +80 -17
- package/dist/package-loader/isolated-artifact.js +257 -51
- package/dist/package-loader/isolated-artifact.test.js +294 -21
- package/dist/package-loader/isolated-runtime.d.ts +22 -7
- package/dist/package-loader/isolated-table-gateway.js +30 -11
- package/dist/package-loader/isolated-table-gateway.test.js +243 -0
- package/dist/package-loader/package-loader.d.ts +8 -1
- package/dist/package-loader/package-loader.js +39 -20
- package/dist/package-loader/package-loader.test.js +47 -0
- package/dist/peer-id.d.ts +25 -0
- package/dist/peer-id.js +99 -0
- package/dist/serial-json.compat.test.d.ts +1 -0
- package/dist/serial-json.compat.test.js +369 -0
- package/dist/serial-json.d.ts +41 -5
- package/dist/serial-json.js +216 -157
- package/dist/serial-json.oracle.d.ts +21 -0
- package/dist/serial-json.oracle.js +222 -0
- package/dist/serial-json.test.js +315 -0
- package/dist/testing/index.d.ts +4 -0
- package/dist/testing/index.js +8 -0
- package/dist/testing/mock-host-contract.d.ts +123 -0
- package/dist/testing/mock-host-contract.js +434 -0
- package/dist/testing/mock-host-contract.test.d.ts +1 -0
- package/dist/testing/mock-host-contract.test.js +782 -0
- package/dist/types/field-type.d.ts +35 -18
- package/dist/types/field-type.js +4 -1
- package/dist/types/zod-types.d.ts +9 -0
- package/dist/types/zod-types.js +8 -2
- package/dist/utils.d.ts +1 -25
- package/dist/utils.js +10 -90
- package/package.json +9 -2
- 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 {};
|