@powerhousedao/switchboard 6.2.3-dev.5 → 6.2.3-dev.51

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 (143) hide show
  1. package/.tsbuild/test/attachments/byte-grants.test.d.ts +2 -0
  2. package/.tsbuild/test/attachments/byte-grants.test.d.ts.map +1 -0
  3. package/.tsbuild/test/attachments/byte-routes-read-gate.integration.test.d.ts +2 -0
  4. package/.tsbuild/test/attachments/byte-routes-read-gate.integration.test.d.ts.map +1 -0
  5. package/.tsbuild/test/attachments/reserve-metadata-parity.test.d.ts +2 -0
  6. package/.tsbuild/test/attachments/reserve-metadata-parity.test.d.ts.map +1 -0
  7. package/.tsbuild/test/attachments/url-signer.test.d.ts +2 -0
  8. package/.tsbuild/test/attachments/url-signer.test.d.ts.map +1 -0
  9. package/.tsbuild/test/boot-create-signature-policy.test.d.ts +2 -0
  10. package/.tsbuild/test/boot-create-signature-policy.test.d.ts.map +1 -0
  11. package/.tsbuild/test/boot-mcp-enabled.test.d.ts +2 -0
  12. package/.tsbuild/test/boot-mcp-enabled.test.d.ts.map +1 -0
  13. package/.tsbuild/test/boot-privacy.test.d.ts +2 -0
  14. package/.tsbuild/test/boot-privacy.test.d.ts.map +1 -0
  15. package/.tsbuild/test/boot-unsupported-stored-documents.test.d.ts +2 -0
  16. package/.tsbuild/test/boot-unsupported-stored-documents.test.d.ts.map +1 -0
  17. package/.tsbuild/test/boot-without-renown.test.d.ts +2 -0
  18. package/.tsbuild/test/boot-without-renown.test.d.ts.map +1 -0
  19. package/.tsbuild/test/boot-without-require-signatures.test.d.ts +2 -0
  20. package/.tsbuild/test/boot-without-require-signatures.test.d.ts.map +1 -0
  21. package/.tsbuild/test/boot-worker-trust-policy.test.d.ts +2 -0
  22. package/.tsbuild/test/boot-worker-trust-policy.test.d.ts.map +1 -0
  23. package/.tsbuild/test/boot-workflow-singleton-conflict.test.d.ts +2 -0
  24. package/.tsbuild/test/boot-workflow-singleton-conflict.test.d.ts.map +1 -0
  25. package/.tsbuild/test/boot-workflow-singleton-retry.test.d.ts +2 -0
  26. package/.tsbuild/test/boot-workflow-singleton-retry.test.d.ts.map +1 -0
  27. package/.tsbuild/test/builder-defaults.test.d.ts +2 -0
  28. package/.tsbuild/test/builder-defaults.test.d.ts.map +1 -0
  29. package/.tsbuild/test/create-signature-policy.test.d.ts +2 -0
  30. package/.tsbuild/test/create-signature-policy.test.d.ts.map +1 -0
  31. package/.tsbuild/test/durable-node-fs-pg16.test.d.ts +2 -0
  32. package/.tsbuild/test/durable-node-fs-pg16.test.d.ts.map +1 -0
  33. package/.tsbuild/test/fatal-shutdown.test.d.ts +2 -0
  34. package/.tsbuild/test/fatal-shutdown.test.d.ts.map +1 -0
  35. package/.tsbuild/test/mcp-flag.test.d.ts +2 -0
  36. package/.tsbuild/test/mcp-flag.test.d.ts.map +1 -0
  37. package/.tsbuild/test/observability-signals.test.d.ts +2 -0
  38. package/.tsbuild/test/observability-signals.test.d.ts.map +1 -0
  39. package/.tsbuild/test/pglite-preflight.test.d.ts +2 -0
  40. package/.tsbuild/test/pglite-preflight.test.d.ts.map +1 -0
  41. package/.tsbuild/test/renown-trust-policy.test.d.ts +2 -0
  42. package/.tsbuild/test/renown-trust-policy.test.d.ts.map +1 -0
  43. package/.tsbuild/test/snapshot-writer.d.ts +18 -0
  44. package/.tsbuild/test/snapshot-writer.d.ts.map +1 -0
  45. package/.tsbuild/test/unsupported-stored-documents.test.d.ts +2 -0
  46. package/.tsbuild/test/unsupported-stored-documents.test.d.ts.map +1 -0
  47. package/.tsbuild/test/workflow/harness.d.ts +56 -0
  48. package/.tsbuild/test/workflow/harness.d.ts.map +1 -0
  49. package/.tsbuild/test/workflow/oauth.test.d.ts +2 -0
  50. package/.tsbuild/test/workflow/oauth.test.d.ts.map +1 -0
  51. package/.tsbuild/test/workflow/resolvers.test.d.ts +2 -0
  52. package/.tsbuild/test/workflow/resolvers.test.d.ts.map +1 -0
  53. package/.tsbuild/test/workflow/webhook-dedupe.test.d.ts +2 -0
  54. package/.tsbuild/test/workflow/webhook-dedupe.test.d.ts.map +1 -0
  55. package/.tsbuild/test/workflow/webhook-signed.test.d.ts +2 -0
  56. package/.tsbuild/test/workflow/webhook-signed.test.d.ts.map +1 -0
  57. package/.tsbuild/test/workflow/webhook-trigger-test.test.d.ts +2 -0
  58. package/.tsbuild/test/workflow/webhook-trigger-test.test.d.ts.map +1 -0
  59. package/.tsbuild/test/workflow/webhook-unsigned.test.d.ts +2 -0
  60. package/.tsbuild/test/workflow/webhook-unsigned.test.d.ts.map +1 -0
  61. package/.tsbuild/test/workflow-reactor-access.test.d.ts +2 -0
  62. package/.tsbuild/test/workflow-reactor-access.test.d.ts.map +1 -0
  63. package/.tsbuild/test/workflow-reactor-enforcement.test.d.ts +2 -0
  64. package/.tsbuild/test/workflow-reactor-enforcement.test.d.ts.map +1 -0
  65. package/.tsbuild/test/workflow-read-gate.test.d.ts +2 -0
  66. package/.tsbuild/test/workflow-read-gate.test.d.ts.map +1 -0
  67. package/.tsbuild/test/workflow-runtime.test.d.ts +2 -0
  68. package/.tsbuild/test/workflow-runtime.test.d.ts.map +1 -0
  69. package/.tsbuild/tsconfig.tsbuildinfo +1 -1
  70. package/.tsbuild/tsdown.config.d.ts.map +1 -1
  71. package/.tsbuild/vitest.config.d.ts.map +1 -1
  72. package/Auth.md +94 -0
  73. package/CHANGELOG.md +541 -0
  74. package/README.md +35 -0
  75. package/dist/index.d.mts +2 -1
  76. package/dist/index.mjs +48 -49
  77. package/dist/index.mjs.map +1 -1
  78. package/dist/install-packages.d.mts +2 -1
  79. package/dist/install-packages.mjs +2 -2
  80. package/dist/install-packages.mjs.map +1 -1
  81. package/dist/migrate.d.mts +2 -1
  82. package/dist/migrate.mjs +4 -3
  83. package/dist/migrate.mjs.map +1 -1
  84. package/dist/server-J9fpd42v.mjs +3549 -0
  85. package/dist/server-J9fpd42v.mjs.map +1 -0
  86. package/dist/server.d.mts +155 -30
  87. package/dist/server.d.mts.map +1 -1
  88. package/dist/server.mjs +4 -5
  89. package/dist/{utils-Baw7rThP.mjs → utils-uaBlzyjS.mjs} +15 -9
  90. package/dist/utils-uaBlzyjS.mjs.map +1 -0
  91. package/dist/utils.d.mts +4 -5
  92. package/dist/utils.d.mts.map +1 -1
  93. package/dist/utils.mjs +3 -3
  94. package/package.json +22 -18
  95. package/test/attachment-reference-read-model.test.ts +6 -1
  96. package/test/attachments/auth.test.ts +85 -0
  97. package/test/attachments/byte-grants.test.ts +290 -0
  98. package/test/attachments/byte-routes-read-gate.integration.test.ts +314 -0
  99. package/test/attachments/download-target.test.ts +201 -32
  100. package/test/attachments/index.test.ts +34 -3
  101. package/test/attachments/reserve-metadata-parity.test.ts +96 -0
  102. package/test/attachments/routes-integration.test.ts +60 -4
  103. package/test/attachments/routes.test.ts +166 -23
  104. package/test/attachments/service-config.test.ts +13 -3
  105. package/test/attachments/url-signer.test.ts +105 -0
  106. package/test/boot-create-signature-policy.test.ts +108 -0
  107. package/test/boot-mcp-enabled.test.ts +121 -0
  108. package/test/boot-privacy.test.ts +243 -0
  109. package/test/boot-unsupported-stored-documents.test.ts +213 -0
  110. package/test/boot-without-renown.test.ts +81 -0
  111. package/test/boot-without-require-signatures.test.ts +74 -0
  112. package/test/boot-worker-trust-policy.test.ts +90 -0
  113. package/test/boot-workflow-singleton-conflict.test.ts +107 -0
  114. package/test/boot-workflow-singleton-retry.test.ts +133 -0
  115. package/test/builder-defaults.test.ts +80 -0
  116. package/test/create-signature-policy.test.ts +69 -0
  117. package/test/durable-node-fs-pg16.test.ts +80 -0
  118. package/test/fatal-shutdown.test.ts +165 -0
  119. package/test/mcp-flag.test.ts +56 -0
  120. package/test/observability-signals.test.ts +131 -0
  121. package/test/pglite-dialect.test.ts +217 -2
  122. package/test/pglite-preflight.test.ts +313 -0
  123. package/test/pglite-version.test.ts +9 -1
  124. package/test/renown-trust-policy.test.ts +315 -0
  125. package/test/snapshot-writer.ts +94 -0
  126. package/test/unsupported-stored-documents.test.ts +72 -0
  127. package/test/worker-pool.test.ts +27 -1
  128. package/test/workflow/harness.ts +289 -0
  129. package/test/workflow/oauth.test.ts +214 -0
  130. package/test/workflow/resolvers.test.ts +357 -0
  131. package/test/workflow/webhook-dedupe.test.ts +295 -0
  132. package/test/workflow/webhook-signed.test.ts +509 -0
  133. package/test/workflow/webhook-trigger-test.test.ts +82 -0
  134. package/test/workflow/webhook-unsigned.test.ts +345 -0
  135. package/test/workflow-reactor-access.test.ts +384 -0
  136. package/test/workflow-reactor-enforcement.test.ts +808 -0
  137. package/test/workflow-read-gate.test.ts +213 -0
  138. package/test/workflow-runtime.test.ts +1067 -0
  139. package/tsconfig.json +9 -3
  140. package/tsdown.config.ts +3 -1
  141. package/dist/server-CiKkVE6g.mjs +0 -1555
  142. package/dist/server-CiKkVE6g.mjs.map +0 -1
  143. package/dist/utils-Baw7rThP.mjs.map +0 -1
package/dist/server.d.mts CHANGED
@@ -1,12 +1,41 @@
1
1
  import { ILogger } from "document-model";
2
- import { ChannelScheme, IDocumentModelLoader, IReactorClient, InProcessReactorClientModule, JwtHandler, ReactorBuilder, ReactorClientBuilder, ReactorFeatureFlags, SignerConfig } from "@powerhousedao/reactor";
2
+ import "@powerhousedao/reactor-api/pglite-node";
3
+ import { ChannelScheme, Database, IDocumentModelLoader, IReactorClient, InProcessReactorClientModule, JwtHandler, ModelManifestEntry, PoolInstrumentation, ReactorBuilder, ReactorClientBuilder, ReactorFeatureFlags, ReactorStorageFacts, SignerConfig, UnsupportedStoredDocuments, UnsupportedStoredProtocolError } from "@powerhousedao/reactor";
3
4
  import { AttachmentReferenceProjectionCapability } from "@powerhousedao/reactor-api";
4
5
  import { IAttachmentService } from "@powerhousedao/reactor-attachments";
5
6
  import { IRenown } from "@renown/sdk/node";
7
+ import { Kysely } from "kysely";
8
+ import { IErasureService } from "@powerhousedao/reactor-privacy";
6
9
  import { DriveInput } from "@powerhousedao/shared/document-drive";
10
+ import { DocumentModelModule, ISigner, SignaturePolicy, UpgradeManifest } from "@powerhousedao/shared/document-model";
11
+ import "@electric-sql/pglite";
12
+ import "@powerhousedao/reactor-workflow";
13
+ import "@powerhousedao/shared/processors";
7
14
  import { IRenown as IRenown$1 } from "@renown/sdk";
8
- import { DocumentModelModule, UpgradeManifest } from "@powerhousedao/shared/document-model";
9
-
15
+ //#region src/pglite-version.d.ts
16
+ declare const SUPPORTED_PG_MAJORS: readonly [16, 17];
17
+ type SupportedPgMajor = (typeof SUPPORTED_PG_MAJORS)[number];
18
+ //#endregion
19
+ //#region src/privacy.d.mts
20
+ type PrivacyOptions = {
21
+ /** Wins over PH_PRIVACY_ENABLED. */
22
+ enabled?: boolean;
23
+ /** Wins over PH_PRIVACY_DEPLOYMENT_SECRET. */
24
+ deploymentSecret?: string;
25
+ /** The reactor's signer, for a caller-provided reactor. */
26
+ signer?: ISigner;
27
+ };
28
+ //#endregion
29
+ //#region src/workflow-runtime.d.mts
30
+ /** Whether the operation intake is indexing. Same shape as the attachment
31
+ * reference projection, because it is the same limitation. */
32
+ type WorkflowTriggersCapability = {
33
+ status: "available";
34
+ } | {
35
+ status: "unavailable";
36
+ reason: "in-process-reactor-module-unavailable" | "live-read-model-registration-unsupported" | "workflow-singleton-lost";
37
+ };
38
+ //#endregion
10
39
  //#region src/types.d.ts
11
40
  /**
12
41
  * Drive container document type chosen for the boot-time default drive. The
@@ -14,27 +43,28 @@ import { DocumentModelModule, UpgradeManifest } from "@powerhousedao/shared/docu
14
43
  * `powerhouse/reactor-drive` is wired through `addDefaultReactorDrive` and
15
44
  * uses the relationship-based child graph.
16
45
  */
17
- type SwitchboardDriveDocumentType = "powerhouse/document-drive" | "powerhouse/reactor-drive";
46
+ export type SwitchboardDriveDocumentType = "powerhouse/document-drive" | "powerhouse/reactor-drive";
18
47
  /** A {@link DriveInput} extended with the optional drive-container type. */
19
- type SwitchboardDriveInput = DriveInput & {
48
+ export type SwitchboardDriveInput = DriveInput & {
20
49
  documentType?: SwitchboardDriveDocumentType;
21
50
  };
22
- type StorageOptions = {
51
+ export type StorageOptions = {
23
52
  type: "filesystem" | "memory" | "postgres" | "browser";
24
53
  filesystemPath?: string;
25
54
  postgresUrl?: string;
26
55
  };
27
- type IdentityOptions = {
28
- /** Path to the keypair file. Defaults to ~/.ph/keypair.json */keypairPath?: string;
56
+ export type IdentityOptions = {
57
+ /** Path to the keypair file. Defaults to ~/.ph/keypair.json */
58
+ keypairPath?: string;
29
59
  /**
30
60
  * If true, won't start without an existing keypair.
31
61
  * Use this to ensure the switchboard only runs with an authenticated identity.
32
62
  */
33
- requireExisting?: boolean; /** Base url of the Renown instance to use */
34
- baseUrl?: string; /** If true, unsigned actions will be rejected */
35
- requireSignatures?: boolean;
63
+ requireExisting?: boolean;
64
+ /** Base url of the Renown instance to use */
65
+ baseUrl?: string;
36
66
  };
37
- type StartServerOptions = {
67
+ export type StartServerOptions = {
38
68
  /**
39
69
  * Pre-built ReactorClientModule (typically from
40
70
  * `@powerhousedao/reactor#ReactorClientBuilder.buildModule`). When set, the
@@ -56,6 +86,14 @@ type StartServerOptions = {
56
86
  * pieces as needed.
57
87
  */
58
88
  reactor?: InProcessReactorClientModule;
89
+ /**
90
+ * Route uncaught exceptions, and unhandled rejections nothing else listens
91
+ * for, through the reactor's SIGTERM shutdown, so PGlite stores are flushed
92
+ * before the process exits with code 1. Installed once the switchboard's own reactor is built;
93
+ * ignored when `reactor` is passed. For process entry points only, since
94
+ * it adds process-wide listeners.
95
+ */
96
+ fatalErrorShutdown?: boolean;
59
97
  /**
60
98
  * Registry URL for the HttpPackageLoader. Enables `PackagesSubgraph`
61
99
  * (install/uninstall mutations) plus dynamic package resolution.
@@ -85,9 +123,19 @@ type StartServerOptions = {
85
123
  * When configured, the switchboard will load the keypair from `ph login`
86
124
  * and can authenticate with remote services on behalf of the user.
87
125
  */
88
- identity?: IdentityOptions; /** Base URL for the attachment service; defaults to `PH_SWITCHBOARD_PUBLIC_URL` then `http(s)://localhost:${port}`. */
126
+ identity?: IdentityOptions;
127
+ /** Base URL for the attachment service; defaults to `PH_SWITCHBOARD_PUBLIC_URL` then `http(s)://localhost:${port}`. */
89
128
  attachmentServiceUrl?: string;
129
+ /** Mount the MCP server at `/mcp`. On by default; `false` wins over
130
+ * MCP_ENABLED, which can turn it off but never on. */
90
131
  mcp?: boolean;
132
+ /** Powerhouse workflows: the runtime, its subgraph, its webhooks and its
133
+ * document models. Wins over PH_WORKFLOWS_ENABLED and the config file. */
134
+ workflows?: {
135
+ enabled?: boolean;
136
+ };
137
+ /** The GDPR add-on; off unless this or PH_PRIVACY_ENABLED turns it on. */
138
+ privacy?: PrivacyOptions;
91
139
  processorConfig?: Map<string, unknown>;
92
140
  disableLocalPackages?: boolean;
93
141
  enableDocumentModelSubgraphs?: boolean;
@@ -144,12 +192,36 @@ type StartServerOptions = {
144
192
  enabled?: boolean;
145
193
  dbPoolSize?: number;
146
194
  };
195
+ /**
196
+ * Stored documents at protocol versions this build does not run: "refuse"
197
+ * (the default) fails the boot with a StoredDocumentsRefusedError;
198
+ * "read-only" starts with a warning and keeps those documents read-only.
199
+ * Unset falls back to the REACTOR_UNSUPPORTED_STORED_DOCUMENTS env var.
200
+ * Ignored when `reactor` is passed.
201
+ */
202
+ unsupportedStoredDocuments?: UnsupportedStoredDocuments;
147
203
  };
148
- type SwitchboardReactor = {
204
+ export type SwitchboardReactor = {
149
205
  defaultDriveUrl: string | undefined;
150
- reactor: IReactorClient; /** Switchboard-backed remote attachment service over its own `/attachments/*` API, for downstream consumers. */
151
- attachmentService: IAttachmentService; /** Whether the authoritative attachment-reference projection is active. */
152
- attachmentReferenceProjection: AttachmentReferenceProjectionCapability; /** The Renown instance if identity was initialized */
206
+ reactor: IReactorClient;
207
+ /** Switchboard-backed remote attachment service over its own `/attachments/*` API, for downstream consumers. */
208
+ attachmentService: IAttachmentService;
209
+ /** Whether the authoritative attachment-reference projection is active. */
210
+ attachmentReferenceProjection: AttachmentReferenceProjectionCapability;
211
+ /** Whether the workflow runtime's operation intake is indexing. Undefined
212
+ * when workflows are off; unavailable means no document trigger fires. */
213
+ workflowTriggers?: WorkflowTriggersCapability;
214
+ /** Whether workflows are on, after the option, PH_WORKFLOWS_ENABLED and the config file. */
215
+ workflowsEnabled: boolean;
216
+ /** The boot list of importable models workers and workflow pieces load; empty when none are resolved. */
217
+ modelManifest(): ModelManifestEntry[];
218
+ /** Present when the privacy add-on runs: its erasure service. */
219
+ privacy?: {
220
+ erasure: IErasureService;
221
+ };
222
+ /** Whether `/mcp` is mounted, after the option and MCP_ENABLED. */
223
+ mcpEnabled: boolean;
224
+ /** The Renown instance if identity was initialized */
153
225
  renown: IRenown$1 | null;
154
226
  /**
155
227
  * Port the HTTP server actually bound to. May differ from the requested
@@ -173,29 +245,57 @@ type SwitchboardReactor = {
173
245
  //#endregion
174
246
  //#region src/builder-defaults.d.mts
175
247
  type SwitchboardReactorDefaultsOptions = {
176
- documentModels?: DocumentModelModule[]; /** Upgrade manifests for versioned models, one per document type. */
177
- upgradeManifests?: UpgradeManifest<readonly number[]>[]; /** Default true. */
248
+ documentModels?: DocumentModelModule[];
249
+ /** Upgrade manifests for versioned models, one per document type. */
250
+ upgradeManifests?: UpgradeManifest<readonly number[]>[];
251
+ /** Default true. */
178
252
  includeBaseModels?: boolean;
179
253
  /**
180
254
  * Channel scheme. Defaults to `ChannelScheme.SWITCHBOARD`, which populates
181
255
  * `reactorModule.syncModule.syncManager` — required by reactor-api. Set
182
- * to `false` only if the caller will configure a scheme themselves.
256
+ * to `false` if the caller configures sync itself (`withChannelScheme` or
257
+ * `withSync`); the builder refuses both together.
183
258
  */
184
- channelScheme?: ChannelScheme | false; /** Defaults to true. Set false when the caller owns SIGINT handling. */
185
- signalHandlers?: boolean; /** Executor tuning. Omit to use the reactor's own defaults. */
259
+ channelScheme?: ChannelScheme | false;
260
+ /** Defaults to true. Set false when the caller owns SIGINT handling. */
261
+ signalHandlers?: boolean;
262
+ /** Executor tuning. Omit to use the reactor's own defaults. */
186
263
  executorConfig?: {
187
264
  maxSkipThreshold?: number;
188
265
  featureFlags?: Partial<ReactorFeatureFlags>;
189
- }; /** Wire dynamic document-model loading via HTTP. */
266
+ };
267
+ /** Wire dynamic document-model loading via HTTP. */
190
268
  documentModelLoader?: IDocumentModelLoader;
191
269
  logger?: ILogger;
192
270
  /**
193
- * Identity signer (typically from `getRenownSignerConfig`). Applied to the
194
- * `ReactorClientBuilder`; omit for unsigned operation.
271
+ * Identity signer (typically from `getRenownSignerConfig`). Signs client
272
+ * writes and the operations the executor synthesizes, in pooled workers
273
+ * through `workerSigner`; omit for unsigned operation.
195
274
  */
196
275
  signer?: SignerConfig;
276
+ /**
277
+ * Which keys may sign as which users (typically from
278
+ * `getRenownTrustPolicyConfig`); wins over one carried by `signer`.
279
+ */
280
+ trustPolicy?: Pick<SignerConfig, "trustPolicy" | "workerTrustPolicy">;
281
+ /** What the client creates new documents as; see `resolveCreateSignaturePolicy`. */
282
+ createSignaturePolicy?: SignaturePolicy;
197
283
  };
198
- declare function applySwitchboardReactorDefaults(reactorBuilder: ReactorBuilder, clientBuilder: ReactorClientBuilder, options?: SwitchboardReactorDefaultsOptions): void;
284
+ export declare function applySwitchboardReactorDefaults(reactorBuilder: ReactorBuilder, clientBuilder: ReactorClientBuilder, options?: SwitchboardReactorDefaultsOptions): void;
285
+ //#endregion
286
+ //#region src/unsupported-stored-documents.d.mts
287
+ /** From REACTOR_UNSUPPORTED_STORED_DOCUMENTS; `input` wins when defined. */
288
+ export declare function resolveUnsupportedStoredDocuments(input: UnsupportedStoredDocuments | undefined, env: NodeJS.ProcessEnv): UnsupportedStoredDocuments;
289
+ /** The reactor refused to start over documents this build does not run. */
290
+ export declare class StoredDocumentsRefusedError extends Error {
291
+ readonly versions: readonly {
292
+ protocol: string;
293
+ version: number;
294
+ }[];
295
+ readonly documents: number;
296
+ constructor(cause: UnsupportedStoredProtocolError);
297
+ static isError(error: unknown): error is StoredDocumentsRefusedError;
298
+ }
199
299
  //#endregion
200
300
  //#region src/server.d.mts
201
301
  /**
@@ -203,9 +303,33 @@ declare function applySwitchboardReactorDefaults(reactorBuilder: ReactorBuilder,
203
303
  * the port is free, false if the OS reports it in use. Any other error is
204
304
  * surfaced so we don't silently mask real issues (permissions, bad host, …).
205
305
  */
206
- declare function isPortAvailable(port: number): Promise<boolean>;
306
+ export declare function isPortAvailable(port: number): Promise<boolean>;
307
+ /**
308
+ * The reactor's storage handle, plus the pool instrumentation when that
309
+ * storage is Postgres. The PGlite branch has no `pg.Pool` at all, so the
310
+ * instrumentation is absent rather than optional-by-convention.
311
+ */
312
+ type ReactorStorage = {
313
+ kysely: Kysely<Database>;
314
+ poolInstrumentation: PoolInstrumentation | undefined;
315
+ storageFacts: ReactorStorageFacts;
316
+ };
317
+ export declare function createReactorKysely(opts: {
318
+ reactorDbUrl: string | undefined;
319
+ reactorPgliteDir: string | null;
320
+ reactorPgliteMajor: SupportedPgMajor | null;
321
+ inMemory: boolean;
322
+ /**
323
+ * Resolved lazily: only the Postgres branch has a host pool, and
324
+ * {@link resolveHostPoolSize} throws on a bad REACTOR_DB_POOL_SIZE_HOST.
325
+ * Called eagerly it would fail a PGlite-backed server over a value that
326
+ * path never reads.
327
+ */
328
+ hostPoolSize: () => number;
329
+ logger: ILogger;
330
+ }): Promise<ReactorStorage>;
207
331
  /** Derive the remote attachment service config for switchboard's own `/attachments/*` API. */
208
- declare function deriveAttachmentServiceConfig(options: Pick<StartServerOptions, "attachmentServiceUrl" | "https">, serverPort: number, renown: IRenown | null): {
332
+ export declare function deriveAttachmentServiceConfig(options: Pick<StartServerOptions, "attachmentServiceUrl" | "https">, serverPort: number, renown: IRenown | null): {
209
333
  remoteUrl: string;
210
334
  jwtHandler: JwtHandler | undefined;
211
335
  };
@@ -226,7 +350,8 @@ declare function deriveAttachmentServiceConfig(options: Pick<StartServerOptions,
226
350
  * trigger the `withShutdownHook` chain that disposes the api. Programmatic
227
351
  * full teardown isn't currently exposed — wire it via SIGINT/SIGTERM.
228
352
  */
229
- declare const startSwitchboard: (options?: StartServerOptions) => Promise<SwitchboardReactor>;
353
+ export declare const startSwitchboard: (options?: StartServerOptions) => Promise<SwitchboardReactor>;
230
354
  //#endregion
231
- export { IdentityOptions, StartServerOptions, StorageOptions, SwitchboardDriveDocumentType, SwitchboardDriveInput, SwitchboardReactor, type SwitchboardReactorDefaultsOptions, applySwitchboardReactorDefaults, deriveAttachmentServiceConfig, isPortAvailable, startSwitchboard };
355
+ export type { SwitchboardReactorDefaultsOptions, WorkflowTriggersCapability };
356
+ export {};
232
357
  //# sourceMappingURL=server.d.mts.map
@@ -1 +1 @@
1
- {"version":3,"file":"server.d.mts","names":[],"sources":["../src/types.ts","../src/builder-defaults.mts","../src/server.mts"],"mappings":";;;;;;;;;;;;;;;AAgBA;KAAY,4BAAA;;KAKA,qBAAA,GAAwB,UAAA;EAClC,YAAA,GAAe,4BAAA;AAAA;AAAA,KAGL,cAAA;EACV,IAAA;EACA,cAAA;EACA,WAAA;AAAA;AAAA,KAGU,eAAA;EATiC,+DAW3C,WAAA;EARU;;;;EAaV,eAAA,YAXA;EAcA,OAAA,WAbW;EAgBX,iBAAA;AAAA;AAAA,KAGU,kBAAA;;;;;;;;;AAAZ;;;;;;;;;;;;EAqBE,OAAA,GAAU,4BAAA;EAQV;;;;;;EADA,WAAA;EACA,UAAA;EACA,IAAA;EAYA;;;;;EANA,UAAA;EACA,GAAA;EACA,MAAA;EACA,KAAA,GAAQ,qBAAA;EACR,QAAA;EACA,YAAA;EACA,KAAA;IAEM,OAAA;IACA,QAAA;EAAA;EA0CN;;;;;EAjCA,QAAA,GAAW,eAAA,EAyDT;EAvDF,oBAAA;EACA,GAAA;EACA,eAAA,GAAkB,GAAA;EAClB,oBAAA;EACA,4BAAA;;;;;;EAMA,mBAAA;EACA,MAAA,GAAS,OAAA;EA2Ec;;;;;;;;;EAjEvB,aAAA;EAoDA;;;;;;;;AC5JF;EDkHE,cAAA;;;;;;;;;EASA,UAAA;IACE,UAAA;IACA,mBAAA;IACA,gBAAA;EAAA;ECxHF;;;;;;;;;EDmIA,gBAAA;IACE,OAAA;IACA,UAAA;EAAA;AAAA;AAAA,KAIQ,kBAAA;EACV,eAAA;EACA,OAAA,EAAS,cAAA,ECpHY;EDsHrB,iBAAA,EAAmB,kBAAA,EChGL;EDkGd,6BAAA,EAA+B,uCAAA;EAE/B,MAAA,EAAQ,SAAA;EClGO;;;;EDuGf,IAAA;ECxGA;;;;;;;;;;ACyDF;;EF4DE,QAAA,QAAgB,OAAA;AAAA;;;KCzKN,iCAAA;EAIV,cAAA,GAAiB,mBAAA;EAEjB,gBAAA,GAAmB,eAAA;EAEnB,iBAAA;;ADZF;;;;ECkBE,aAAA,GAAgB,aAAA,UDbN;ECeV,cAAA;EAEA,cAAA;IACE,gBAAA;IACA,YAAA,GAAe,OAAA,CAAQ,mBAAA;EAAA,GDlBkB;ECqB3C,mBAAA,GAAsB,oBAAA;EACtB,MAAA,GAAS,OAAA;EDnBe;;;;ECwBxB,MAAA,GAAS,YAAA;AAAA;AAAA,iBAsBK,+BAAA,CACd,cAAA,EAAgB,cAAA,EAChB,aAAA,EAAe,oBAAA,EACf,OAAA,GAAS,iCAAA;;;;;;;;iBCuDK,eAAA,CAAgB,IAAA,WAAe,OAAA;;iBA0H/B,6BAAA,CACd,OAAA,EAAS,IAAA,CAAK,kBAAA,qCACd,UAAA,UACA,MAAA,EAAQ,OAAA;EACL,SAAA;EAAmB,UAAA,EAAY,UAAA;AAAA;;AF1OpC;;;;;;;;;AAIA;;;;;;;cEogCa,gBAAA,GACX,OAAA,GAAS,kBAAA,KACR,OAAA,CAAQ,kBAAA"}
1
+ {"version":3,"file":"server.d.mts","names":[],"sources":["../src/pglite-version.ts","../src/privacy.mts","../src/workflow-runtime.mts","../src/types.ts","../src/builder-defaults.mts","../src/unsupported-stored-documents.mts","../src/server.mts"],"mappings":";;;;;;;;;;;;;;;cASa;KACD,2BAA2B;;;KCe3B;;EAEV;;EAEA;;EAEA,SAAS;;;;;;KCkCC;EACN;;EAEA;EACA;;;;;;;;;;YC/CM;;YAKA,wBAAwB;EAClC,eAAe;;YAGL;EACV;EACA;EACA;;YAGU;;EAEV;;;;;EAKA;;EAGA;;YAGU;;;;;;;;;;;;;;;;;;;;;EAqBV,UAAU;;;;;;;;EAQV;;;;;;;EAOA;EACA;EACA;;;;;;EAMA;EACA;EACA;EACA,QAAQ;EACR;EACA;EACA;IAEM;IACA;;;;;;;EASN,WAAW;;EAEX;;;EAGA;;;EAGA;IACE;;;EAGF,UAAU;EACV,kBAAkB;EAClB;EACA;;;;;;EAMA;EACA,SAAS;;;;;;;;;;EAUT;;;;;;;;;;EAUA;;;;;;;;;EASA;IACE;IACA;IACA;;;;;;;;;;;EAWF;IACE;IACA;;;;;;;;;EASF,6BAA6B;;YAGnB;EACV;EACA,SAAS;;EAET,mBAAmB;;EAEnB,+BAA+B;;;EAG/B,mBAAmB;;EAEnB;;EAEA,iBAAiB;;EAEjB;IAAY,SAAS;;;EAErB;;EAEA,QAAQ;;;;;EAKR;;;;;;;;;;;;;EAaA,gBAAgB;;;;KC/MN;EAIV,iBAAiB;;EAEjB,mBAAmB;;EAEnB;;;;;;;EAOA,gBAAgB;;EAEhB;;EAEA;IACE;IACA,eAAe,QAAQ;;;EAGzB,sBAAsB;EACtB,SAAS;;;;;;EAMT,SAAS;;;;;EAKT,cAAc,KAAK;;EAEnB,wBAAwB;;wBAsBV,gCACd,gBAAgB,gBAChB,eAAe,sBACf,UAAS;;;;wBC5EK,kCACd,OAAO,wCACP,KAAK,OAAO,aACX;;qBAaU,oCAAoC;WACtC;IAAqB;IAAkB;;WACvC;EAET,YAAY,OAAO;SAcZ,QAAQ,iBAAiB,SAAS;;;;;;;;;wBCkL3B,gBAAgB,eAAe;;;;;;KA6D1C;EACH,QAAQ,OAAO;EACf,qBAAqB;EACrB,cAAc;;wBAGM,oBAAoB;EACxC;EACA;EACA,oBAAoB;EACpB;;;;;;;EAOA;EACA,QAAQ;IACN,QAAQ;;wBA4DI,8BACd,SAAS,KAAK,uDACd,oBACA,QAAQ;EACL;EAAmB,YAAY;;;;;;;;;;;;;;;;;;;qBAk/BvB,mBAAgB,UAClB,uBACR,QAAQ"}
package/dist/server.mjs CHANGED
@@ -1,6 +1,5 @@
1
1
  #!/usr/bin/env node
2
- import { i as applySwitchboardReactorDefaults, n as isPortAvailable, r as startSwitchboard, t as deriveAttachmentServiceConfig } from "./server-CiKkVE6g.mjs";
3
- import "./utils-Baw7rThP.mjs";
4
- export { applySwitchboardReactorDefaults, deriveAttachmentServiceConfig, isPortAvailable, startSwitchboard };
5
- !function(){try{var e="undefined"!=typeof window?window:"undefined"!=typeof global?global:"undefined"!=typeof globalThis?globalThis:"undefined"!=typeof self?self:{},n=(new e.Error).stack;n&&(e._sentryDebugIds=e._sentryDebugIds||{},e._sentryDebugIds[n]="43d97572-0a08-5683-83a3-d8477151600e")}catch(e){}}();
6
- //# debugId=43d97572-0a08-5683-83a3-d8477151600e
2
+ import { a as StoredDocumentsRefusedError, i as startSwitchboard, n as deriveAttachmentServiceConfig, o as resolveUnsupportedStoredDocuments, r as isPortAvailable, s as applySwitchboardReactorDefaults, t as createReactorKysely } from "./server-J9fpd42v.mjs";
3
+ export { StoredDocumentsRefusedError, applySwitchboardReactorDefaults, createReactorKysely, deriveAttachmentServiceConfig, isPortAvailable, resolveUnsupportedStoredDocuments, startSwitchboard };
4
+ !function(){try{var e="undefined"!=typeof window?window:"undefined"!=typeof global?global:"undefined"!=typeof globalThis?globalThis:"undefined"!=typeof self?self:{},n=(new e.Error).stack;n&&(e._sentryDebugIds=e._sentryDebugIds||{},e._sentryDebugIds[n]="b1cfc1e4-6226-5b66-81fa-c82cbc28b4ee")}catch(e){}}();
5
+ //# debugId=b1cfc1e4-6226-5b66-81fa-c82cbc28b4ee
@@ -1,8 +1,16 @@
1
1
 
2
- !function(){try{var e="undefined"!=typeof window?window:"undefined"!=typeof global?global:"undefined"!=typeof globalThis?globalThis:"undefined"!=typeof self?self:{},n=(new e.Error).stack;n&&(e._sentryDebugIds=e._sentryDebugIds||{},e._sentryDebugIds[n]="686dcce6-c280-5558-89dd-a18a7e514cdf")}catch(e){}}();
2
+ !function(){try{var e="undefined"!=typeof window?window:"undefined"!=typeof global?global:"undefined"!=typeof globalThis?globalThis:"undefined"!=typeof self?self:{},n=(new e.Error).stack;n&&(e._sentryDebugIds=e._sentryDebugIds||{},e._sentryDebugIds[n]="5ece528d-aafb-5305-a04d-e0c45c8c30a3")}catch(e){}}();
3
3
  import { reactorDriveCreateDocument, reactorDriveCreateState } from "@powerhousedao/reactor-drive";
4
4
  import { driveCreateDocument, driveCreateState } from "@powerhousedao/shared/document-drive";
5
+ import { withSignaturePolicy } from "@powerhousedao/shared/document-model";
5
6
  //#region src/utils.mts
7
+ /**
8
+ * A configured id pins the drive, and only a legacy drive can take a chosen
9
+ * id; otherwise the client's creation default applies.
10
+ */
11
+ async function underCreatePolicy(client, document, id) {
12
+ return id ? withSignaturePolicy(document, "legacy", { id }) : withSignaturePolicy(document, await client.getCreateSignaturePolicy());
13
+ }
6
14
  async function addDefaultDrive(client, drive, serverPort) {
7
15
  let driveId = drive.id;
8
16
  if (!driveId || driveId.length === 0) driveId = drive.slug;
@@ -13,7 +21,7 @@ async function addDefaultDrive(client, drive, serverPort) {
13
21
  } catch {}
14
22
  if (existingDrive) return `http://localhost:${serverPort}/d/${driveId}`;
15
23
  const { global } = driveCreateState();
16
- const document = driveCreateDocument({
24
+ const document = await underCreatePolicy(client, driveCreateDocument({
17
25
  global: {
18
26
  ...global,
19
27
  name: drive.global.name,
@@ -25,8 +33,7 @@ async function addDefaultDrive(client, drive, serverPort) {
25
33
  listeners: drive.local?.listeners ?? [],
26
34
  triggers: drive.local?.triggers ?? []
27
35
  }
28
- });
29
- if (drive.id && drive.id.length > 0) document.header.id = drive.id;
36
+ }), drive.id);
30
37
  if (drive.slug && drive.slug.length > 0) document.header.slug = drive.slug;
31
38
  if (drive.global.name) document.header.name = drive.global.name;
32
39
  if (drive.preferredEditor) document.header.meta = { preferredEditor: drive.preferredEditor };
@@ -47,7 +54,7 @@ async function addDefaultReactorDrive(client, drive, serverPort) {
47
54
  } catch {}
48
55
  if (existingDrive) return `http://localhost:${serverPort}/d/${driveId}`;
49
56
  const { global, local } = reactorDriveCreateState();
50
- const document = reactorDriveCreateDocument({
57
+ const document = await underCreatePolicy(client, reactorDriveCreateDocument({
51
58
  global: {
52
59
  ...global,
53
60
  name: drive.global.name,
@@ -58,8 +65,7 @@ async function addDefaultReactorDrive(client, drive, serverPort) {
58
65
  availableOffline: drive.local?.availableOffline ?? local.availableOffline,
59
66
  sharingType: drive.local?.sharingType ?? local.sharingType
60
67
  }
61
- });
62
- if (drive.id && drive.id.length > 0) document.header.id = drive.id;
68
+ }), drive.id);
63
69
  if (drive.slug && drive.slug.length > 0) document.header.slug = drive.slug;
64
70
  if (drive.global.name) document.header.name = drive.global.name;
65
71
  if (drive.preferredEditor) document.header.meta = { preferredEditor: drive.preferredEditor };
@@ -76,5 +82,5 @@ function isPostgresUrl(url) {
76
82
  //#endregion
77
83
  export { addDefaultReactorDrive as n, isPostgresUrl as r, addDefaultDrive as t };
78
84
 
79
- //# sourceMappingURL=utils-Baw7rThP.mjs.map
80
- //# debugId=686dcce6-c280-5558-89dd-a18a7e514cdf
85
+ //# sourceMappingURL=utils-uaBlzyjS.mjs.map
86
+ //# debugId=5ece528d-aafb-5305-a04d-e0c45c8c30a3
@@ -0,0 +1 @@
1
+ {"version":3,"file":"utils-uaBlzyjS.mjs","sources":["../src/utils.mts"],"sourcesContent":["import type { IReactorClient } from \"@powerhousedao/reactor\";\nimport {\n reactorDriveCreateDocument,\n reactorDriveCreateState,\n} from \"@powerhousedao/reactor-drive\";\nimport {\n driveCreateDocument,\n driveCreateState,\n} from \"@powerhousedao/shared/document-drive\";\nimport type { DriveInput } from \"@powerhousedao/shared/document-drive\";\nimport {\n withSignaturePolicy,\n type PHDocument,\n} from \"@powerhousedao/shared/document-model\";\n\n/**\n * A configured id pins the drive, and only a legacy drive can take a chosen\n * id; otherwise the client's creation default applies.\n */\nasync function underCreatePolicy<TDocument extends PHDocument>(\n client: IReactorClient,\n document: TDocument,\n id: string | undefined,\n): Promise<TDocument> {\n return id\n ? withSignaturePolicy(document, \"legacy\", { id })\n : withSignaturePolicy(document, await client.getCreateSignaturePolicy());\n}\n\nexport async function addDefaultDrive(\n client: IReactorClient,\n drive: DriveInput,\n serverPort: number,\n) {\n let driveId = drive.id;\n if (!driveId || driveId.length === 0) {\n driveId = drive.slug;\n }\n\n if (!driveId || driveId.length === 0) {\n throw new Error(\"Invalid Drive Id\");\n }\n\n // check if the drive already exists\n let existingDrive;\n try {\n existingDrive = await client.get(driveId);\n } catch {\n //\n }\n\n // already exists, return the existing drive url\n if (existingDrive) {\n return `http://localhost:${serverPort}/d/${driveId}`;\n }\n\n const { global } = driveCreateState();\n const created = driveCreateDocument({\n global: {\n ...global,\n name: drive.global.name,\n icon: drive.global.icon ?? global.icon,\n },\n local: {\n availableOffline: drive.local?.availableOffline ?? false,\n sharingType: drive.local?.sharingType ?? \"public\",\n listeners: drive.local?.listeners ?? [],\n triggers: drive.local?.triggers ?? [],\n },\n });\n\n const document = await underCreatePolicy(client, created, drive.id);\n if (drive.slug && drive.slug.length > 0) {\n document.header.slug = drive.slug;\n }\n if (drive.global.name) {\n document.header.name = drive.global.name;\n }\n if (drive.preferredEditor) {\n document.header.meta = { preferredEditor: drive.preferredEditor };\n }\n\n try {\n await client.create(document);\n } catch (e) {\n const errorMessage = e instanceof Error ? e.message : String(e);\n if (!errorMessage.includes(\"already exists\")) {\n throw e;\n }\n }\n\n return `http://localhost:${serverPort}/d/${driveId}`;\n}\n\nexport async function addDefaultReactorDrive(\n client: IReactorClient,\n drive: DriveInput,\n serverPort: number,\n) {\n let driveId = drive.id;\n if (!driveId || driveId.length === 0) {\n driveId = drive.slug;\n }\n\n if (!driveId || driveId.length === 0) {\n throw new Error(\"Invalid Drive Id\");\n }\n\n let existingDrive;\n try {\n existingDrive = await client.get(driveId);\n } catch {\n //\n }\n\n if (existingDrive) {\n return `http://localhost:${serverPort}/d/${driveId}`;\n }\n\n const { global, local } = reactorDriveCreateState();\n const created = reactorDriveCreateDocument({\n global: {\n ...global,\n name: drive.global.name,\n icon: drive.global.icon ?? global.icon,\n },\n local: {\n ...local,\n availableOffline: drive.local?.availableOffline ?? local.availableOffline,\n sharingType: drive.local?.sharingType ?? local.sharingType,\n },\n });\n\n const document = await underCreatePolicy(client, created, drive.id);\n if (drive.slug && drive.slug.length > 0) {\n document.header.slug = drive.slug;\n }\n if (drive.global.name) {\n document.header.name = drive.global.name;\n }\n if (drive.preferredEditor) {\n document.header.meta = { preferredEditor: drive.preferredEditor };\n }\n\n try {\n await client.create(document);\n } catch (e) {\n const errorMessage = e instanceof Error ? e.message : String(e);\n if (!errorMessage.includes(\"already exists\")) {\n throw e;\n }\n }\n\n return `http://localhost:${serverPort}/d/${driveId}`;\n}\n\nexport function isPostgresUrl(url: string) {\n return url.startsWith(\"postgresql\") || url.startsWith(\"postgres\");\n}\n"],"names":[],"mappings":"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","debug_id":"5ece528d-aafb-5305-a04d-e0c45c8c30a3"}
package/dist/utils.d.mts CHANGED
@@ -1,10 +1,9 @@
1
1
  import { IReactorClient } from "@powerhousedao/reactor";
2
2
  import { DriveInput } from "@powerhousedao/shared/document-drive";
3
-
4
3
  //#region src/utils.d.mts
5
- declare function addDefaultDrive(client: IReactorClient, drive: DriveInput, serverPort: number): Promise<string>;
6
- declare function addDefaultReactorDrive(client: IReactorClient, drive: DriveInput, serverPort: number): Promise<string>;
7
- declare function isPostgresUrl(url: string): boolean;
4
+ export declare function addDefaultDrive(client: IReactorClient, drive: DriveInput, serverPort: number): Promise<string>;
5
+ export declare function addDefaultReactorDrive(client: IReactorClient, drive: DriveInput, serverPort: number): Promise<string>;
6
+ export declare function isPostgresUrl(url: string): boolean;
8
7
  //#endregion
9
- export { addDefaultDrive, addDefaultReactorDrive, isPostgresUrl };
8
+ export {};
10
9
  //# sourceMappingURL=utils.d.mts.map
@@ -1 +1 @@
1
- {"version":3,"file":"utils.d.mts","names":[],"sources":["../src/utils.mts"],"mappings":";;;;iBAWsB,eAAA,CACpB,MAAA,EAAQ,cAAA,EACR,KAAA,EAAO,UAAA,EACP,UAAA,WAAkB,OAAA;AAAA,iBAgEE,sBAAA,CACpB,MAAA,EAAQ,cAAA,EACR,KAAA,EAAO,UAAA,EACP,UAAA,WAAkB,OAAA;AAAA,iBA6DJ,aAAA,CAAc,GAAA"}
1
+ {"version":3,"file":"utils.d.mts","names":[],"sources":["../src/utils.mts"],"mappings":";;;wBA6BsB,gBACpB,QAAQ,gBACR,OAAO,YACP,qBAAkB;wBA8DE,uBACpB,QAAQ,gBACR,OAAO,YACP,qBAAkB;wBA2DJ,cAAc"}
package/dist/utils.mjs CHANGED
@@ -1,4 +1,4 @@
1
- import { n as addDefaultReactorDrive, r as isPostgresUrl, t as addDefaultDrive } from "./utils-Baw7rThP.mjs";
1
+ import { n as addDefaultReactorDrive, r as isPostgresUrl, t as addDefaultDrive } from "./utils-uaBlzyjS.mjs";
2
2
  export { addDefaultDrive, addDefaultReactorDrive, isPostgresUrl };
3
- !function(){try{var e="undefined"!=typeof window?window:"undefined"!=typeof global?global:"undefined"!=typeof globalThis?globalThis:"undefined"!=typeof self?self:{},n=(new e.Error).stack;n&&(e._sentryDebugIds=e._sentryDebugIds||{},e._sentryDebugIds[n]="8227e60f-e412-513a-b0cb-502740b7f818")}catch(e){}}();
4
- //# debugId=8227e60f-e412-513a-b0cb-502740b7f818
3
+ !function(){try{var e="undefined"!=typeof window?window:"undefined"!=typeof global?global:"undefined"!=typeof globalThis?globalThis:"undefined"!=typeof self?self:{},n=(new e.Error).stack;n&&(e._sentryDebugIds=e._sentryDebugIds||{},e._sentryDebugIds[n]="e030fa72-327e-52e2-9ac0-68feb4ef300a")}catch(e){}}();
4
+ //# debugId=e030fa72-327e-52e2-9ac0-68feb4ef300a
package/package.json CHANGED
@@ -1,7 +1,7 @@
1
1
  {
2
2
  "name": "@powerhousedao/switchboard",
3
3
  "type": "module",
4
- "version": "6.2.3-dev.5",
4
+ "version": "6.2.3-dev.51",
5
5
  "main": "dist/index.mjs",
6
6
  "exports": {
7
7
  ".": {
@@ -41,7 +41,7 @@
41
41
  "@openfeature/core": "1.9.1",
42
42
  "@openfeature/env-var-provider": "0.3.1",
43
43
  "@openfeature/server-sdk": "1.19.0",
44
- "@powerhousedao/config": "6.2.3-dev.5",
44
+ "@powerhousedao/config": "6.2.3-dev.51",
45
45
  "@opentelemetry/api": "^1.9.0",
46
46
  "@opentelemetry/exporter-metrics-otlp-http": "^0.218.0",
47
47
  "@opentelemetry/exporter-trace-otlp-http": "^0.218.0",
@@ -55,36 +55,40 @@
55
55
  "@opentelemetry/sdk-node": "^0.218.0",
56
56
  "@opentelemetry/sdk-trace-base": "^2.7.1",
57
57
  "@opentelemetry/semantic-conventions": "^1.41.1",
58
- "@powerhousedao/opentelemetry-instrumentation-reactor": "6.2.3-dev.5",
59
- "@powerhousedao/reactor": "6.2.3-dev.5",
60
- "@powerhousedao/shared": "6.2.3-dev.5",
61
- "@powerhousedao/vetra": "6.2.3-dev.5",
62
- "@powerhousedao/reactor-api": "6.2.3-dev.5",
63
- "@powerhousedao/reactor-attachments": "6.2.3-dev.5",
64
- "@powerhousedao/reactor-drive": "6.2.3-dev.5",
65
- "@powerhousedao/reactor-group": "6.2.3-dev.5",
66
- "@powerhousedao/pglite-fs": "6.2.3-dev.5",
58
+ "@powerhousedao/opentelemetry-instrumentation-reactor": "6.2.3-dev.51",
59
+ "@powerhousedao/reactor": "6.2.3-dev.51",
60
+ "@powerhousedao/shared": "6.2.3-dev.51",
61
+ "@powerhousedao/vetra": "6.2.3-dev.51",
62
+ "@powerhousedao/reactor-api": "6.2.3-dev.51",
63
+ "@powerhousedao/reactor-attachments": "6.2.3-dev.51",
64
+ "@powerhousedao/reactor-drive": "6.2.3-dev.51",
65
+ "@powerhousedao/reactor-group": "6.2.3-dev.51",
66
+ "@powerhousedao/reactor-privacy": "6.2.3-dev.51",
67
+ "@powerhousedao/reactor-workflow": "6.2.3-dev.51",
68
+ "@powerhousedao/workflow": "6.2.3-dev.51",
67
69
  "@pyroscope/nodejs": "^0.4.5",
68
- "@renown/sdk": "6.2.3-dev.5",
70
+ "@renown/sdk": "6.2.3-dev.51",
69
71
  "@sentry/node": "^10.53.1",
70
72
  "@sentry/opentelemetry": "^10.53.1",
71
- "document-model": "6.2.3-dev.5",
73
+ "document-model": "6.2.3-dev.51",
72
74
  "dotenv": "^16.4.7",
73
- "express": "^4.21.2",
75
+ "express": "^4.22.1",
76
+ "graphql": "^16",
77
+ "graphql-tag": "^2",
74
78
  "kysely": "0.28.16",
75
79
  "kysely-pglite-dialect": "1.2.0",
76
80
  "pg": "8.18.0",
77
- "vite": "8.0.10"
81
+ "vite": "8.3.0"
78
82
  },
79
83
  "devDependencies": {
80
84
  "@types/express": "^4.17.25",
81
85
  "@types/node": "25.2.3",
82
86
  "@types/pg": "8.16.0",
83
- "tsdown": "0.21.1",
87
+ "tsdown": "0.23.0",
84
88
  "concurrently": "9.2.1",
85
89
  "nodemon": "3.1.11",
86
90
  "react": "19.2.6",
87
- "vitest": "4.1.1"
91
+ "vitest": "5.0.3"
88
92
  },
89
93
  "peerDependencies": {
90
94
  "react": ">=19.0.0"
@@ -92,7 +96,7 @@
92
96
  "scripts": {
93
97
  "tsc": "tsc",
94
98
  "test": "vitest run",
95
- "lint": "eslint",
99
+ "lint": "cd ../.. && oxlint apps/switchboard",
96
100
  "build": "tsdown && pnpm run install-packages",
97
101
  "start": "node dist/index.mjs",
98
102
  "start:profile": "mkdir -p .prof && node --cpu-prof --cpu-prof-dir=.prof dist/index.mjs",
@@ -232,6 +232,8 @@ describe("Switchboard attachment-reference read model registration", () => {
232
232
  writtenOrdinals.push(...references.map(({ ordinal }) => ordinal));
233
233
  await attachmentReferenceIndex.store.addReferences(references);
234
234
  },
235
+ removeDocuments: (documentIds) =>
236
+ attachmentReferenceIndex.store.removeDocuments(documentIds),
235
237
  };
236
238
 
237
239
  const coordinator =
@@ -283,7 +285,10 @@ describe("Switchboard attachment-reference read model registration", () => {
283
285
  .withReadModelCoordinator(customCoordinator)
284
286
  .buildModule();
285
287
  const addReferences = vi.fn();
286
- const writer = { addReferences } as IAttachmentReferenceWriter;
288
+ const writer: IAttachmentReferenceWriter = {
289
+ addReferences,
290
+ removeDocuments: vi.fn(),
291
+ };
287
292
 
288
293
  await expect(
289
294
  registerAttachmentReferenceReadModelOnModule(
@@ -342,6 +342,91 @@ describe("requireAuth", () => {
342
342
  });
343
343
  });
344
344
 
345
+ /**
346
+ * The deployment-wide floor. These routes never pass the GraphQL fetch chain,
347
+ * so `REQUIRE_AUTHENTICATED_CALLER` reaches them through this option instead
348
+ * — including on the routes that opt into `allowAnonymous`, which says the
349
+ * handler can decide without identity, not that the server will serve callers
350
+ * it cannot name.
351
+ */
352
+ describe("requireAuthenticatedCaller", () => {
353
+ const anonymousUnderOpenPolicy = () =>
354
+ makeAuthService(() =>
355
+ Promise.resolve({ user: undefined, admins: [], auth_enabled: false }),
356
+ );
357
+
358
+ it("refuses a missing bearer even with auth disabled, where today it passes", async () => {
359
+ const { service } = anonymousUnderOpenPolicy();
360
+ const handler = vi.fn<NodeHandler>();
361
+ const wrapped = requireAuth(service, handler, {
362
+ requireAuthenticatedCaller: true,
363
+ });
364
+
365
+ const res = makeRes();
366
+ await wrapped(makeReq({ headers: {} }), res);
367
+
368
+ expect(res.statusCode).toBe(401);
369
+ expect(JSON.parse(res._body)).toEqual({
370
+ error: "Authentication required",
371
+ });
372
+ expect(handler).not.toHaveBeenCalled();
373
+ });
374
+
375
+ it("overrides allowAnonymous", async () => {
376
+ const { service } = anonymousUnderOpenPolicy();
377
+ const handler = vi.fn<NodeHandler>();
378
+ const wrapped = requireAuth(service, handler, {
379
+ allowAnonymous: true,
380
+ requireAuthenticatedCaller: true,
381
+ });
382
+
383
+ const res = makeRes();
384
+ await wrapped(makeReq({ headers: {} }), res);
385
+
386
+ expect(res.statusCode).toBe(401);
387
+ expect(handler).not.toHaveBeenCalled();
388
+ });
389
+
390
+ it("still serves a verified caller", async () => {
391
+ const { service } = makeAuthService(() =>
392
+ Promise.resolve({
393
+ user: { address: "0x123", chainId: 1, networkId: "mainnet" },
394
+ admins: [],
395
+ auth_enabled: false,
396
+ }),
397
+ );
398
+ const handler = vi.fn<NodeHandler>();
399
+ const wrapped = requireAuth(service, handler, {
400
+ allowAnonymous: true,
401
+ requireAuthenticatedCaller: true,
402
+ });
403
+
404
+ const req = makeReq({ headers: { authorization: "Bearer good-token" } });
405
+ const res = makeRes();
406
+ await wrapped(req, res);
407
+
408
+ expect(res.statusCode).toBe(200);
409
+ expect(handler).toHaveBeenCalledWith(req, res, undefined, {
410
+ user: { address: "0x123", chainId: 1, networkId: "mainnet" },
411
+ authEnabled: false,
412
+ });
413
+ });
414
+
415
+ it("leaves every route as it was when the deployment has not set it", async () => {
416
+ const { service } = anonymousUnderOpenPolicy();
417
+ const handler = vi.fn<NodeHandler>();
418
+ const wrapped = requireAuth(service, handler, {
419
+ requireAuthenticatedCaller: false,
420
+ });
421
+
422
+ const res = makeRes();
423
+ await wrapped(makeReq({ headers: {} }), res);
424
+
425
+ expect(res.statusCode).toBe(200);
426
+ expect(handler).toHaveBeenCalledTimes(1);
427
+ });
428
+ });
429
+
345
430
  it("calls verifyBearer with undefined when no authorization header is present", async () => {
346
431
  const { service, spy } = makeAuthService(() =>
347
432
  Promise.resolve({