@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
@@ -2,6 +2,7 @@ type ObservableFn<T> = {
2
2
  (): T;
3
3
  (newValue: T): T;
4
4
  };
5
+ /** Handle returned by `subscribe`; `dispose` stops the notifications. */
5
6
  export type Subscription = {
6
7
  dispose: () => void;
7
8
  };
@@ -10,14 +11,53 @@ type ObservableProps<T> = {
10
11
  notifySubscribers: () => void;
11
12
  subscriberCount: () => number;
12
13
  };
13
- export type Observable<T> = ObservableFn<T> & ObservableProps<T>;
14
+ declare const writableObservable: unique symbol;
15
+ declare const observableValue: unique symbol;
16
+ /** A subscribable value that consumers can read with `obs()`. */
17
+ export type ReadonlyObservable<T> = (() => T) & ObservableProps<T> & {
18
+ readonly [writableObservable]?: boolean;
19
+ };
20
+ /** A readable, writable, subscribable value: `obs()` reads it and `obs(value)` writes it. */
21
+ export type Observable<T> = ObservableFn<T> & ReadonlyObservable<T> & {
22
+ readonly [writableObservable]?: true;
23
+ readonly [observableValue]?: {
24
+ accept(value: T): T;
25
+ };
26
+ };
27
+ /**
28
+ * A writable observable that must accept exactly `T`, including in its subscribers. Use for
29
+ * a declared writable source; unlike ordinary observable assignments, this checks writes
30
+ * strictly and rejects a source whose value type is narrower than the declaration.
31
+ */
32
+ export type InvariantObservable<T> = Observable<T> & {
33
+ readonly [observableValue]?: {
34
+ accept: (value: T) => T;
35
+ };
36
+ };
37
+ /**
38
+ * Create an observable. Writing a value that isn't `===` the current one notifies subscribers.
39
+ *
40
+ * @param initialValue - The starting value.
41
+ */
14
42
  export declare function observable<T>(initialValue: T): Observable<T>;
43
+ /** Create an observable that starts `undefined`. */
15
44
  export declare function observable<T = undefined>(): Observable<T | undefined>;
45
+ /**
46
+ * An observable derived from other observables: `read` runs again when any observable it read
47
+ * changes. Pass `{ read, write }` to make it writable.
48
+ *
49
+ * @param fn - The read function, or read and write functions.
50
+ */
16
51
  export declare function computed<T>(fn: {
17
52
  read: () => T;
18
53
  write?: (val: T) => void;
19
54
  } | (() => T)): Observable<T>;
55
+ /** Test an observable while preserving a known read-only view. */
56
+ export declare function isSubscribable<T>(obj: ReadonlyObservable<T>): obj is ReadonlyObservable<T>;
57
+ /** True when an untyped value is an observable. */
20
58
  export declare function isSubscribable(obj: any): obj is Observable<any>;
21
- export declare function unwrapObservable<T>(obj: T | Observable<T>): T;
59
+ /** The observable's current value, or `obj` itself when it isn't an observable. */
60
+ export declare function unwrapObservable<T>(obj: T | ReadonlyObservable<T>): T;
61
+ /** Keep two observables equal: a change to either is written to the other. */
22
62
  export declare function linkObservables<T>(obs1: Observable<T>, obs2: Observable<T>): Subscription;
23
63
  export {};
@@ -5,10 +5,19 @@ exports.computed = computed;
5
5
  exports.isSubscribable = isSubscribable;
6
6
  exports.unwrapObservable = unwrapObservable;
7
7
  exports.linkObservables = linkObservables;
8
- const lodash_1 = require("lodash");
9
- const utils_1 = require("./utils");
10
- const _ = require("lodash");
8
+ /**
9
+ * Observables: a value you call to read (`obs()`) or write (`obs(value)`), with subscribers
10
+ * notified on each change. Persistent variables and computed values build on them.
11
+ *
12
+ * This module has no dependency beyond peer ids, so isolated package bundles can use it.
13
+ */
14
+ const peer_id_1 = require("./peer-id");
11
15
  const runningComputes = {};
16
+ /**
17
+ * Create an observable, starting at `initialValue`.
18
+ *
19
+ * @param initialValue - The starting value.
20
+ */
12
21
  function observable(initialValue) {
13
22
  let value = initialValue;
14
23
  const subscribers = [];
@@ -46,12 +55,18 @@ function observable(initialValue) {
46
55
  obs.subscriberCount = () => subscribers.length;
47
56
  return obs;
48
57
  }
58
+ /**
59
+ * An observable derived from other observables: `read` runs again when any observable it read
60
+ * changes. Pass `{ read, write }` to make it writable.
61
+ *
62
+ * @param fn - The read function, or read and write functions.
63
+ */
49
64
  function computed(fn) {
50
- const read = _.isFunction(fn) ? fn : fn.read;
51
- const write = _.isFunction(fn) ? undefined : fn.write;
65
+ const read = typeof fn === "function" ? fn : fn.read;
66
+ const write = typeof fn === "function" ? undefined : fn.write;
52
67
  // compute dependencies and initial value;
53
68
  const dependencies = [];
54
- const runId = (0, utils_1.newid)();
69
+ const runId = (0, peer_id_1.newid)();
55
70
  runningComputes[runId] = dependencies;
56
71
  const _obs = observable(read());
57
72
  delete runningComputes[runId];
@@ -84,18 +99,21 @@ function computed(fn) {
84
99
  }
85
100
  };
86
101
  // subscribe to dependencies
87
- (0, lodash_1.uniq)(dependencies).forEach((dep) => {
102
+ [...new Set(dependencies)].forEach((dep) => {
88
103
  dep.subscribe(onDepChange);
89
104
  });
90
105
  Object.assign(obs, _obs);
91
106
  return obs;
92
107
  }
108
+ /** True when `obj` is an observable. */
93
109
  function isSubscribable(obj) {
94
110
  return obj && typeof obj === "function" && obj.subscribe && obj.notifySubscribers;
95
111
  }
112
+ /** The observable's current value, or `obj` itself when it isn't an observable. */
96
113
  function unwrapObservable(obj) {
97
114
  return isSubscribable(obj) ? obj() : obj;
98
115
  }
116
+ /** Keep two observables equal: a change to either is written to the other. */
99
117
  function linkObservables(obs1, obs2) {
100
118
  const sub1 = obs1.subscribe((value) => {
101
119
  if (value !== obs2()) {
@@ -0,0 +1,60 @@
1
+ import { type IIsolatedPackageManifest } from "../package-loader/isolated-artifact";
2
+ /** Where the package is and where its build goes. */
3
+ export interface IPackageBuildOptions {
4
+ /** The package's root, holding its `package.json`. Defaults to the current directory. */
5
+ root?: string;
6
+ /** The declaration module, relative to `root`. Defaults to `src/package.ts`. */
7
+ entry?: string;
8
+ /** The output directory, relative to `root`. Defaults to `dist`. */
9
+ outDir?: string;
10
+ }
11
+ /** What {@link buildPackage} wrote. */
12
+ export interface IPackageBuildResult {
13
+ manifest: IIsolatedPackageManifest;
14
+ manifestPath: string;
15
+ artifactPath: string;
16
+ /** Size of the bundled provider source, in characters. */
17
+ providerChars: number;
18
+ }
19
+ /** A running package watcher. Dispose it to stop watching and release esbuild. */
20
+ export interface IPackageWatcher {
21
+ dispose(): Promise<void>;
22
+ }
23
+ /**
24
+ * Bundle a TypeScript or JavaScript module for Node, the way the build loads `src/package.ts`,
25
+ * and return its exports. Its installed imports resolve from the package at `root`.
26
+ *
27
+ * @param root - The package root, whose esbuild compiles the module.
28
+ * @param entry - The module's path.
29
+ */
30
+ export declare function loadPackageModule(root: string, entry: string): Promise<unknown>;
31
+ /**
32
+ * The generate-manifest step: write `dist/manifest.json` from the package's declarations.
33
+ *
34
+ * @param buildOptions - Package root, declaration entry, and output directory.
35
+ */
36
+ export declare function generatePackageManifest(buildOptions?: IPackageBuildOptions): Promise<{
37
+ manifest: IIsolatedPackageManifest;
38
+ manifestPath: string;
39
+ }>;
40
+ /**
41
+ * Build the package's manifest from its declarations, validated, without writing it or checking
42
+ * it against `frozen-contracts.json` (`peers-package contract freeze` does that itself).
43
+ *
44
+ * @param buildOptions - Package root and declaration entry.
45
+ */
46
+ export declare function packageManifest(buildOptions?: IPackageBuildOptions): Promise<IIsolatedPackageManifest>;
47
+ /**
48
+ * Generate the manifest, bundle the provider for the sandbox, and write `dist/package.bundle.js`.
49
+ *
50
+ * @param buildOptions - Package root, declaration entry, and output directory.
51
+ */
52
+ export declare function buildPackage(buildOptions?: IPackageBuildOptions): Promise<IPackageBuildResult>;
53
+ /**
54
+ * Build once, then rebuild whenever a source file changes. Resolves once watching starts.
55
+ *
56
+ * @param buildOptions - Package root, declaration entry, and output directory.
57
+ * @param onBuild - Called after each build, with its result or error.
58
+ * @returns A handle that stops watching when disposed.
59
+ */
60
+ export declare function watchPackage(buildOptions?: IPackageBuildOptions, onBuild?: (result: IPackageBuildResult | Error) => void): Promise<IPackageWatcher>;
@@ -0,0 +1,312 @@
1
+ "use strict";
2
+ Object.defineProperty(exports, "__esModule", { value: true });
3
+ exports.loadPackageModule = loadPackageModule;
4
+ exports.generatePackageManifest = generatePackageManifest;
5
+ exports.packageManifest = packageManifest;
6
+ exports.buildPackage = buildPackage;
7
+ exports.watchPackage = watchPackage;
8
+ /**
9
+ * `peers-package`: build an isolated package from its declarations (Node only).
10
+ *
11
+ * `manifest` is the generate-manifest step: it loads `src/package.ts` in Node and writes the
12
+ * manifest, plain JSON in Peers IR, to `dist/manifest.json`. `build` also bundles the same
13
+ * `src/package.ts` for the sandbox and writes `dist/package.bundle.js`, the artifact the
14
+ * Runtime installs. esbuild comes from the package's own dependencies.
15
+ */
16
+ const promises_1 = require("node:fs/promises");
17
+ const node_module_1 = require("node:module");
18
+ const path = require("node:path");
19
+ const manifest_1 = require("../define/manifest");
20
+ const isolated_artifact_1 = require("../package-loader/isolated-artifact");
21
+ const freeze_contracts_1 = require("./freeze-contracts");
22
+ /** Source text SES rejects before running it, with what to tell the author. */
23
+ const SES_REJECTED_PATTERNS = [
24
+ { pattern: /(?:<!--|-->)/, what: "an HTML comment token (<!-- or -->)" },
25
+ {
26
+ pattern: /(^|[^.]|\.\.\.)\bimport(\s*(?:\(|\/[/*]))/,
27
+ what: "import( or import followed by a comment",
28
+ },
29
+ { pattern: /(^|[^.])\beval(\s*\()/, what: "a direct eval(...) call" },
30
+ ];
31
+ const NODE_BUILTINS = [...node_module_1.builtinModules, ...node_module_1.builtinModules.map((name) => `node:${name}`)];
32
+ function resolveOptions(options) {
33
+ const root = path.resolve(options.root ?? process.cwd());
34
+ const packageRequire = (0, node_module_1.createRequire)(path.join(root, "package.json"));
35
+ let esbuild;
36
+ try {
37
+ esbuild = packageRequire("esbuild");
38
+ }
39
+ catch {
40
+ throw new Error(`peers-package needs esbuild in ${root}. Install it: npm install --save-dev esbuild`);
41
+ }
42
+ return {
43
+ root,
44
+ entry: path.resolve(root, options.entry ?? "src/package.ts"),
45
+ outDir: path.resolve(root, options.outDir ?? "dist"),
46
+ esbuild,
47
+ require: packageRequire,
48
+ };
49
+ }
50
+ /** Node compilation used to load the declaration without bundling its installed libraries. */
51
+ function definitionBuildOptions(entry, outfile) {
52
+ return {
53
+ entryPoints: [entry],
54
+ outfile,
55
+ bundle: true,
56
+ platform: "node",
57
+ format: "cjs",
58
+ target: "node20",
59
+ packages: "external",
60
+ logLevel: "silent",
61
+ };
62
+ }
63
+ /** Bundle the declaration module for Node and load its default export. */
64
+ async function loadDefinition(options) {
65
+ const loaded = (await loadModule(options, options.entry));
66
+ const definition = loaded.default;
67
+ if (definition?.kind !== "package") {
68
+ throw new Error(`${path.relative(options.root, options.entry)} must export default definePackage(...)`);
69
+ }
70
+ return definition;
71
+ }
72
+ /**
73
+ * Bundle a TypeScript or JavaScript module for Node, the way the build loads `src/package.ts`,
74
+ * and return its exports. Its installed imports resolve from the package at `root`.
75
+ *
76
+ * @param root - The package root, whose esbuild compiles the module.
77
+ * @param entry - The module's path.
78
+ */
79
+ async function loadPackageModule(root, entry) {
80
+ const options = resolveOptions({ root });
81
+ return loadModule(options, path.resolve(entry));
82
+ }
83
+ /** Bundle one module for Node and load it, then forget it and its installed imports. */
84
+ async function loadModule(options, entry) {
85
+ // External imports must resolve from the package, even when --out-dir is elsewhere, so the
86
+ // compiled declaration goes under the package's node_modules/.cache: git and npm ignore it,
87
+ // so a build killed before cleanup (Ctrl-C while watching) leaves nothing in the source tree.
88
+ // Use a unique directory so concurrent builds cannot overwrite or remove each other's code.
89
+ const cacheDir = path.join(options.root, "node_modules", ".cache", "peers-package");
90
+ await (0, promises_1.mkdir)(cacheDir, { recursive: true });
91
+ const temporaryDir = await (0, promises_1.mkdtemp)(path.join(cacheDir, "definition-"));
92
+ const outfile = path.join(temporaryDir, "definition.cjs");
93
+ const definitionRequire = (0, node_module_1.createRequire)(outfile);
94
+ let cacheKey;
95
+ let previousModules;
96
+ try {
97
+ await options.esbuild.build(definitionBuildOptions(entry, outfile));
98
+ cacheKey = definitionRequire.resolve(outfile);
99
+ previousModules = new Set(Object.keys(definitionRequire.cache));
100
+ return definitionRequire(outfile);
101
+ }
102
+ finally {
103
+ const previous = previousModules;
104
+ if (previous) {
105
+ // The entry is bundled, but its installed dependencies are external. A watch rebuild
106
+ // must reload those too, including dependencies loaded before an evaluation failed.
107
+ const cache = definitionRequire.cache;
108
+ const pending = Object.keys(cache).filter((key) => !previous.has(key));
109
+ if (cacheKey)
110
+ pending.push(cacheKey);
111
+ const seen = new Set();
112
+ while (pending.length) {
113
+ const key = pending.pop();
114
+ if (seen.has(key))
115
+ continue;
116
+ seen.add(key);
117
+ for (const child of cache[key]?.children ?? [])
118
+ pending.push(child.id);
119
+ delete cache[key];
120
+ }
121
+ }
122
+ await (0, promises_1.rm)(temporaryDir, { recursive: true, force: true });
123
+ }
124
+ }
125
+ /**
126
+ * Check a manifest without changing it: validation fills in defaults on what it's given. Strict,
127
+ * so a field key this SDK doesn't know (a typo in hand-written IR) fails the build.
128
+ */
129
+ function validateManifest(manifest, providerSource = "void 0;") {
130
+ (0, isolated_artifact_1.validateIsolatedPackageArtifact)({ manifest: structuredClone(manifest), providerSource }, { strict: true });
131
+ }
132
+ /** The package's manifest from its declarations, validated. */
133
+ async function validManifest(options) {
134
+ // frozen-contracts.json gives the shapes of older versions a contract also implements.
135
+ const manifest = (0, manifest_1.buildPackageManifest)(await loadDefinition(options), {
136
+ frozen: await (0, freeze_contracts_1.readFrozenContracts)(options.root),
137
+ });
138
+ validateManifest(manifest);
139
+ return manifest;
140
+ }
141
+ /** The package's manifest, validated and checked against the contracts it froze. */
142
+ async function checkedManifest(options) {
143
+ const manifest = await validManifest(options);
144
+ await (0, freeze_contracts_1.assertFrozenContracts)(options.root, manifest);
145
+ return manifest;
146
+ }
147
+ async function writeManifest(options) {
148
+ return saveManifest(options, await checkedManifest(options));
149
+ }
150
+ async function saveManifest(options, manifest) {
151
+ const manifestPath = path.join(options.outDir, "manifest.json");
152
+ await (0, promises_1.mkdir)(options.outDir, { recursive: true });
153
+ await (0, promises_1.writeFile)(manifestPath, `${JSON.stringify(manifest, null, 2)}\n`, "utf8");
154
+ return { manifest, manifestPath };
155
+ }
156
+ /** esbuild options for the provider bundle: the declaration plus `servePackage`. */
157
+ function providerBuildOptions(options, manifest, plugins = []) {
158
+ const sandbox = manifest.executionMode !== "privileged";
159
+ const sdkRoot = path.dirname(options.require.resolve("@peers-app/peers-sdk/package.json"));
160
+ const zodPath = (0, node_module_1.createRequire)(path.join(sdkRoot, "package.json")).resolve("zod");
161
+ const singleZod = {
162
+ name: "peers-package-single-zod",
163
+ setup(build) {
164
+ // One zod for the package and the SDK, so schemas from both mix.
165
+ build.onResolve({ filter: /^zod$/ }, () => ({ path: zodPath }));
166
+ },
167
+ };
168
+ return {
169
+ stdin: {
170
+ contents: [
171
+ `import definition from ${JSON.stringify(options.entry)};`,
172
+ `import { servePackage } from "@peers-app/peers-sdk/define";`,
173
+ "servePackage(definition);",
174
+ ].join("\n"),
175
+ resolveDir: options.root,
176
+ sourcefile: "peers-package-provider.js",
177
+ loader: "js",
178
+ },
179
+ bundle: true,
180
+ write: false,
181
+ format: "iife",
182
+ target: "es2022",
183
+ // The sandbox is a worker with web globals and no Node builtins. A privileged provider runs
184
+ // in Node with `require`.
185
+ platform: sandbox ? "browser" : "node",
186
+ // Leave Node builtins to libraries' own guarded `require`s; the sandbox has none.
187
+ external: sandbox ? NODE_BUILTINS : [],
188
+ define: { "process.env.NODE_ENV": '"production"' },
189
+ // Also strips comments: SES rejects some text even inside a comment.
190
+ minifyWhitespace: true,
191
+ legalComments: "none",
192
+ logLevel: "silent",
193
+ plugins: [singleZod, ...plugins],
194
+ };
195
+ }
196
+ function assertSesCompatible(source, manifest) {
197
+ if (manifest.executionMode === "privileged") {
198
+ return;
199
+ }
200
+ for (const { pattern, what } of SES_REJECTED_PATTERNS) {
201
+ const match = pattern.exec(source);
202
+ if (match) {
203
+ const at = match.index + match[0].length;
204
+ const snippet = source.slice(Math.max(0, at - 60), at + 20).replace(/\s+/g, " ");
205
+ throw new Error(`The provider bundle contains ${what}, which the sandbox rejects even inside a string. Near: …${snippet}…`);
206
+ }
207
+ }
208
+ }
209
+ async function writeArtifact(options, manifest, providerSource) {
210
+ assertSesCompatible(providerSource, manifest);
211
+ validateManifest(manifest, providerSource);
212
+ const artifactPath = path.join(options.outDir, "package.bundle.js");
213
+ await (0, promises_1.mkdir)(options.outDir, { recursive: true });
214
+ await (0, promises_1.writeFile)(artifactPath, `${isolated_artifact_1.ISOLATED_PACKAGE_MAGIC}\n${JSON.stringify({ manifest, providerSource })}\n`, "utf8");
215
+ return artifactPath;
216
+ }
217
+ /**
218
+ * The generate-manifest step: write `dist/manifest.json` from the package's declarations.
219
+ *
220
+ * @param buildOptions - Package root, declaration entry, and output directory.
221
+ */
222
+ async function generatePackageManifest(buildOptions = {}) {
223
+ return writeManifest(resolveOptions(buildOptions));
224
+ }
225
+ /**
226
+ * Build the package's manifest from its declarations, validated, without writing it or checking
227
+ * it against `frozen-contracts.json` (`peers-package contract freeze` does that itself).
228
+ *
229
+ * @param buildOptions - Package root and declaration entry.
230
+ */
231
+ async function packageManifest(buildOptions = {}) {
232
+ return validManifest(resolveOptions(buildOptions));
233
+ }
234
+ /**
235
+ * Generate the manifest, bundle the provider for the sandbox, and write `dist/package.bundle.js`.
236
+ *
237
+ * @param buildOptions - Package root, declaration entry, and output directory.
238
+ */
239
+ async function buildPackage(buildOptions = {}) {
240
+ const options = resolveOptions(buildOptions);
241
+ const manifest = await checkedManifest(options);
242
+ const output = await options.esbuild.build(providerBuildOptions(options, manifest));
243
+ const providerSource = output.outputFiles?.[0]?.text ?? "";
244
+ const artifactPath = await writeArtifact(options, manifest, providerSource);
245
+ const { manifestPath } = await saveManifest(options, manifest);
246
+ return { manifest, manifestPath, artifactPath, providerChars: providerSource.length };
247
+ }
248
+ /**
249
+ * Build once, then rebuild whenever a source file changes. Resolves once watching starts.
250
+ *
251
+ * @param buildOptions - Package root, declaration entry, and output directory.
252
+ * @param onBuild - Called after each build, with its result or error.
253
+ * @returns A handle that stops watching when disposed.
254
+ */
255
+ async function watchPackage(buildOptions = {}, onBuild = () => undefined) {
256
+ const options = resolveOptions(buildOptions);
257
+ const manifest = await validManifest(options);
258
+ let mode = manifest.executionMode ?? "sandbox";
259
+ let disposed = false;
260
+ let restart = Promise.resolve();
261
+ let context;
262
+ const rebuild = {
263
+ name: "peers-package-write",
264
+ setup(build) {
265
+ build.onEnd(async () => {
266
+ if (disposed)
267
+ return;
268
+ try {
269
+ // Recreate the provider's options from the current declaration on every rebuild:
270
+ // executionMode can change which platform and dependency exports must be bundled.
271
+ const latest = await buildPackage(buildOptions);
272
+ onBuild(latest);
273
+ const nextMode = latest.manifest.executionMode ?? "sandbox";
274
+ if (nextMode !== mode) {
275
+ mode = nextMode;
276
+ // Dispose after this onEnd returns: awaiting disposal here would deadlock it.
277
+ // Recreate the watch graph too, so browser/node conditional dependencies are watched.
278
+ restart = restart
279
+ .then(async () => {
280
+ await context.dispose();
281
+ if (disposed)
282
+ return;
283
+ context = await options.esbuild.context(providerBuildOptions(options, latest.manifest, [rebuild]));
284
+ await context.watch();
285
+ })
286
+ .catch((error) => {
287
+ onBuild(error instanceof Error ? error : new Error(String(error)));
288
+ });
289
+ }
290
+ }
291
+ catch (error) {
292
+ onBuild(error instanceof Error ? error : new Error(String(error)));
293
+ }
294
+ });
295
+ },
296
+ };
297
+ context = await options.esbuild.context(providerBuildOptions(options, manifest, [rebuild]));
298
+ try {
299
+ await context.watch();
300
+ return {
301
+ async dispose() {
302
+ disposed = true;
303
+ await restart;
304
+ await context.dispose();
305
+ },
306
+ };
307
+ }
308
+ catch (error) {
309
+ await context.dispose();
310
+ throw error;
311
+ }
312
+ }
@@ -0,0 +1 @@
1
+ export {};