@powerhousedao/switchboard 6.2.3-dev.3 → 6.2.3-dev.31
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/.tsbuild/test/attachments/byte-grants.test.d.ts +2 -0
- package/.tsbuild/test/attachments/byte-grants.test.d.ts.map +1 -0
- package/.tsbuild/test/attachments/byte-routes-read-gate.integration.test.d.ts +2 -0
- package/.tsbuild/test/attachments/byte-routes-read-gate.integration.test.d.ts.map +1 -0
- package/.tsbuild/test/attachments/url-signer.test.d.ts +2 -0
- package/.tsbuild/test/attachments/url-signer.test.d.ts.map +1 -0
- package/.tsbuild/test/boot-create-signature-policy.test.d.ts +2 -0
- package/.tsbuild/test/boot-create-signature-policy.test.d.ts.map +1 -0
- package/.tsbuild/test/boot-without-renown.test.d.ts +2 -0
- package/.tsbuild/test/boot-without-renown.test.d.ts.map +1 -0
- package/.tsbuild/test/boot-without-require-signatures.test.d.ts +2 -0
- package/.tsbuild/test/boot-without-require-signatures.test.d.ts.map +1 -0
- package/.tsbuild/test/boot-worker-trust-policy.test.d.ts +2 -0
- package/.tsbuild/test/boot-worker-trust-policy.test.d.ts.map +1 -0
- package/.tsbuild/test/builder-defaults.test.d.ts +2 -0
- package/.tsbuild/test/builder-defaults.test.d.ts.map +1 -0
- package/.tsbuild/test/create-signature-policy.test.d.ts +2 -0
- package/.tsbuild/test/create-signature-policy.test.d.ts.map +1 -0
- package/.tsbuild/test/fatal-shutdown.test.d.ts +2 -0
- package/.tsbuild/test/fatal-shutdown.test.d.ts.map +1 -0
- package/.tsbuild/test/renown-trust-policy.test.d.ts +2 -0
- package/.tsbuild/test/renown-trust-policy.test.d.ts.map +1 -0
- package/.tsbuild/test/workflow/harness.d.ts +56 -0
- package/.tsbuild/test/workflow/harness.d.ts.map +1 -0
- package/.tsbuild/test/workflow/oauth.test.d.ts +2 -0
- package/.tsbuild/test/workflow/oauth.test.d.ts.map +1 -0
- package/.tsbuild/test/workflow/resolvers.test.d.ts +2 -0
- package/.tsbuild/test/workflow/resolvers.test.d.ts.map +1 -0
- package/.tsbuild/test/workflow/webhook-dedupe.test.d.ts +2 -0
- package/.tsbuild/test/workflow/webhook-dedupe.test.d.ts.map +1 -0
- package/.tsbuild/test/workflow/webhook-signed.test.d.ts +2 -0
- package/.tsbuild/test/workflow/webhook-signed.test.d.ts.map +1 -0
- package/.tsbuild/test/workflow/webhook-trigger-test.test.d.ts +2 -0
- package/.tsbuild/test/workflow/webhook-trigger-test.test.d.ts.map +1 -0
- package/.tsbuild/test/workflow/webhook-unsigned.test.d.ts +2 -0
- package/.tsbuild/test/workflow/webhook-unsigned.test.d.ts.map +1 -0
- package/.tsbuild/test/workflow-read-gate.test.d.ts +2 -0
- package/.tsbuild/test/workflow-read-gate.test.d.ts.map +1 -0
- package/.tsbuild/test/workflow-runtime.test.d.ts +2 -0
- package/.tsbuild/test/workflow-runtime.test.d.ts.map +1 -0
- package/.tsbuild/tsconfig.tsbuildinfo +1 -1
- package/.tsbuild/tsdown.config.d.ts.map +1 -1
- package/.tsbuild/vitest.config.d.ts.map +1 -1
- package/Auth.md +94 -0
- package/CHANGELOG.md +299 -0
- package/README.md +14 -0
- package/dist/index.d.mts +2 -1
- package/dist/index.mjs +6 -6
- package/dist/index.mjs.map +1 -1
- package/dist/install-packages.d.mts +2 -1
- package/dist/install-packages.mjs +2 -2
- package/dist/install-packages.mjs.map +1 -1
- package/dist/migrate.d.mts +2 -1
- package/dist/migrate.mjs +4 -3
- package/dist/migrate.mjs.map +1 -1
- package/dist/{server-B2r6AQ4Q.mjs → server-CKKn0aXV.mjs} +1394 -65
- package/dist/server-CKKn0aXV.mjs.map +1 -0
- package/dist/server.d.mts +76 -28
- package/dist/server.d.mts.map +1 -1
- package/dist/server.mjs +3 -4
- package/dist/{utils-Baw7rThP.mjs → utils-uaBlzyjS.mjs} +15 -9
- package/dist/utils-uaBlzyjS.mjs.map +1 -0
- package/dist/utils.d.mts +4 -5
- package/dist/utils.d.mts.map +1 -1
- package/dist/utils.mjs +3 -3
- package/package.json +21 -17
- package/test/attachments/auth.test.ts +85 -0
- package/test/attachments/byte-grants.test.ts +287 -0
- package/test/attachments/byte-routes-read-gate.integration.test.ts +314 -0
- package/test/attachments/download-target.test.ts +194 -31
- package/test/attachments/index.test.ts +34 -3
- package/test/attachments/routes-integration.test.ts +59 -4
- package/test/attachments/routes.test.ts +165 -23
- package/test/attachments/service-config.test.ts +13 -3
- package/test/attachments/url-signer.test.ts +105 -0
- package/test/boot-create-signature-policy.test.ts +108 -0
- package/test/boot-without-renown.test.ts +81 -0
- package/test/boot-without-require-signatures.test.ts +74 -0
- package/test/boot-worker-trust-policy.test.ts +90 -0
- package/test/builder-defaults.test.ts +80 -0
- package/test/create-signature-policy.test.ts +69 -0
- package/test/fatal-shutdown.test.ts +102 -0
- package/test/renown-trust-policy.test.ts +315 -0
- package/test/workflow/harness.ts +289 -0
- package/test/workflow/oauth.test.ts +214 -0
- package/test/workflow/resolvers.test.ts +296 -0
- package/test/workflow/webhook-dedupe.test.ts +295 -0
- package/test/workflow/webhook-signed.test.ts +509 -0
- package/test/workflow/webhook-trigger-test.test.ts +82 -0
- package/test/workflow/webhook-unsigned.test.ts +345 -0
- package/test/workflow-read-gate.test.ts +145 -0
- package/test/workflow-runtime.test.ts +486 -0
- package/tsconfig.json +6 -0
- package/tsdown.config.ts +3 -1
- package/dist/server-B2r6AQ4Q.mjs.map +0 -1
- package/dist/utils-Baw7rThP.mjs.map +0 -1
package/dist/server.d.mts
CHANGED
|
@@ -4,9 +4,20 @@ import { AttachmentReferenceProjectionCapability } from "@powerhousedao/reactor-
|
|
|
4
4
|
import { IAttachmentService } from "@powerhousedao/reactor-attachments";
|
|
5
5
|
import { IRenown } from "@renown/sdk/node";
|
|
6
6
|
import { DriveInput } from "@powerhousedao/shared/document-drive";
|
|
7
|
+
import { DocumentModelModule, SignaturePolicy, UpgradeManifest } from "@powerhousedao/shared/document-model";
|
|
8
|
+
import "@powerhousedao/reactor-workflow";
|
|
9
|
+
import "@powerhousedao/shared/processors";
|
|
7
10
|
import { IRenown as IRenown$1 } from "@renown/sdk";
|
|
8
|
-
|
|
9
|
-
|
|
11
|
+
//#region src/workflow-runtime.d.mts
|
|
12
|
+
/** Whether the operation intake is indexing. Same shape as the attachment
|
|
13
|
+
* reference projection, because it is the same limitation. */
|
|
14
|
+
type WorkflowTriggersCapability = {
|
|
15
|
+
status: "available";
|
|
16
|
+
} | {
|
|
17
|
+
status: "unavailable";
|
|
18
|
+
reason: "in-process-reactor-module-unavailable" | "live-read-model-registration-unsupported";
|
|
19
|
+
};
|
|
20
|
+
//#endregion
|
|
10
21
|
//#region src/types.d.ts
|
|
11
22
|
/**
|
|
12
23
|
* Drive container document type chosen for the boot-time default drive. The
|
|
@@ -14,27 +25,28 @@ import { DocumentModelModule, UpgradeManifest } from "@powerhousedao/shared/docu
|
|
|
14
25
|
* `powerhouse/reactor-drive` is wired through `addDefaultReactorDrive` and
|
|
15
26
|
* uses the relationship-based child graph.
|
|
16
27
|
*/
|
|
17
|
-
type SwitchboardDriveDocumentType = "powerhouse/document-drive" | "powerhouse/reactor-drive";
|
|
28
|
+
export type SwitchboardDriveDocumentType = "powerhouse/document-drive" | "powerhouse/reactor-drive";
|
|
18
29
|
/** A {@link DriveInput} extended with the optional drive-container type. */
|
|
19
|
-
type SwitchboardDriveInput = DriveInput & {
|
|
30
|
+
export type SwitchboardDriveInput = DriveInput & {
|
|
20
31
|
documentType?: SwitchboardDriveDocumentType;
|
|
21
32
|
};
|
|
22
|
-
type StorageOptions = {
|
|
33
|
+
export type StorageOptions = {
|
|
23
34
|
type: "filesystem" | "memory" | "postgres" | "browser";
|
|
24
35
|
filesystemPath?: string;
|
|
25
36
|
postgresUrl?: string;
|
|
26
37
|
};
|
|
27
|
-
type IdentityOptions = {
|
|
28
|
-
/** Path to the keypair file. Defaults to ~/.ph/keypair.json */
|
|
38
|
+
export type IdentityOptions = {
|
|
39
|
+
/** Path to the keypair file. Defaults to ~/.ph/keypair.json */
|
|
40
|
+
keypairPath?: string;
|
|
29
41
|
/**
|
|
30
42
|
* If true, won't start without an existing keypair.
|
|
31
43
|
* Use this to ensure the switchboard only runs with an authenticated identity.
|
|
32
44
|
*/
|
|
33
|
-
requireExisting?: boolean;
|
|
34
|
-
|
|
35
|
-
|
|
45
|
+
requireExisting?: boolean;
|
|
46
|
+
/** Base url of the Renown instance to use */
|
|
47
|
+
baseUrl?: string;
|
|
36
48
|
};
|
|
37
|
-
type StartServerOptions = {
|
|
49
|
+
export type StartServerOptions = {
|
|
38
50
|
/**
|
|
39
51
|
* Pre-built ReactorClientModule (typically from
|
|
40
52
|
* `@powerhousedao/reactor#ReactorClientBuilder.buildModule`). When set, the
|
|
@@ -56,6 +68,14 @@ type StartServerOptions = {
|
|
|
56
68
|
* pieces as needed.
|
|
57
69
|
*/
|
|
58
70
|
reactor?: InProcessReactorClientModule;
|
|
71
|
+
/**
|
|
72
|
+
* Route uncaught exceptions, and unhandled rejections nothing else listens
|
|
73
|
+
* for, through the reactor's SIGTERM shutdown, so PGlite stores are flushed
|
|
74
|
+
* before the process exits with code 1. Installed once the switchboard's own reactor is built;
|
|
75
|
+
* ignored when `reactor` is passed. For process entry points only, since
|
|
76
|
+
* it adds process-wide listeners.
|
|
77
|
+
*/
|
|
78
|
+
fatalErrorShutdown?: boolean;
|
|
59
79
|
/**
|
|
60
80
|
* Registry URL for the HttpPackageLoader. Enables `PackagesSubgraph`
|
|
61
81
|
* (install/uninstall mutations) plus dynamic package resolution.
|
|
@@ -85,9 +105,15 @@ type StartServerOptions = {
|
|
|
85
105
|
* When configured, the switchboard will load the keypair from `ph login`
|
|
86
106
|
* and can authenticate with remote services on behalf of the user.
|
|
87
107
|
*/
|
|
88
|
-
identity?: IdentityOptions;
|
|
108
|
+
identity?: IdentityOptions;
|
|
109
|
+
/** Base URL for the attachment service; defaults to `PH_SWITCHBOARD_PUBLIC_URL` then `http(s)://localhost:${port}`. */
|
|
89
110
|
attachmentServiceUrl?: string;
|
|
90
111
|
mcp?: boolean;
|
|
112
|
+
/** Powerhouse workflows: the runtime, its subgraph, its webhooks and its
|
|
113
|
+
* document models. Wins over PH_WORKFLOWS_ENABLED and the config file. */
|
|
114
|
+
workflows?: {
|
|
115
|
+
enabled?: boolean;
|
|
116
|
+
};
|
|
91
117
|
processorConfig?: Map<string, unknown>;
|
|
92
118
|
disableLocalPackages?: boolean;
|
|
93
119
|
enableDocumentModelSubgraphs?: boolean;
|
|
@@ -145,11 +171,19 @@ type StartServerOptions = {
|
|
|
145
171
|
dbPoolSize?: number;
|
|
146
172
|
};
|
|
147
173
|
};
|
|
148
|
-
type SwitchboardReactor = {
|
|
174
|
+
export type SwitchboardReactor = {
|
|
149
175
|
defaultDriveUrl: string | undefined;
|
|
150
|
-
reactor: IReactorClient;
|
|
151
|
-
|
|
152
|
-
|
|
176
|
+
reactor: IReactorClient;
|
|
177
|
+
/** Switchboard-backed remote attachment service over its own `/attachments/*` API, for downstream consumers. */
|
|
178
|
+
attachmentService: IAttachmentService;
|
|
179
|
+
/** Whether the authoritative attachment-reference projection is active. */
|
|
180
|
+
attachmentReferenceProjection: AttachmentReferenceProjectionCapability;
|
|
181
|
+
/** Whether the workflow runtime's operation intake is indexing. Undefined
|
|
182
|
+
* when workflows are off; unavailable means no document trigger fires. */
|
|
183
|
+
workflowTriggers?: WorkflowTriggersCapability;
|
|
184
|
+
/** Whether workflows are on, after the option, PH_WORKFLOWS_ENABLED and the config file. */
|
|
185
|
+
workflowsEnabled: boolean;
|
|
186
|
+
/** The Renown instance if identity was initialized */
|
|
153
187
|
renown: IRenown$1 | null;
|
|
154
188
|
/**
|
|
155
189
|
* Port the HTTP server actually bound to. May differ from the requested
|
|
@@ -173,29 +207,42 @@ type SwitchboardReactor = {
|
|
|
173
207
|
//#endregion
|
|
174
208
|
//#region src/builder-defaults.d.mts
|
|
175
209
|
type SwitchboardReactorDefaultsOptions = {
|
|
176
|
-
documentModels?: DocumentModelModule[];
|
|
177
|
-
|
|
210
|
+
documentModels?: DocumentModelModule[];
|
|
211
|
+
/** Upgrade manifests for versioned models, one per document type. */
|
|
212
|
+
upgradeManifests?: UpgradeManifest<readonly number[]>[];
|
|
213
|
+
/** Default true. */
|
|
178
214
|
includeBaseModels?: boolean;
|
|
179
215
|
/**
|
|
180
216
|
* Channel scheme. Defaults to `ChannelScheme.SWITCHBOARD`, which populates
|
|
181
217
|
* `reactorModule.syncModule.syncManager` — required by reactor-api. Set
|
|
182
218
|
* to `false` only if the caller will configure a scheme themselves.
|
|
183
219
|
*/
|
|
184
|
-
channelScheme?: ChannelScheme | false;
|
|
185
|
-
|
|
220
|
+
channelScheme?: ChannelScheme | false;
|
|
221
|
+
/** Defaults to true. Set false when the caller owns SIGINT handling. */
|
|
222
|
+
signalHandlers?: boolean;
|
|
223
|
+
/** Executor tuning. Omit to use the reactor's own defaults. */
|
|
186
224
|
executorConfig?: {
|
|
187
225
|
maxSkipThreshold?: number;
|
|
188
226
|
featureFlags?: Partial<ReactorFeatureFlags>;
|
|
189
|
-
};
|
|
227
|
+
};
|
|
228
|
+
/** Wire dynamic document-model loading via HTTP. */
|
|
190
229
|
documentModelLoader?: IDocumentModelLoader;
|
|
191
230
|
logger?: ILogger;
|
|
192
231
|
/**
|
|
193
|
-
* Identity signer (typically from `getRenownSignerConfig`).
|
|
194
|
-
*
|
|
232
|
+
* Identity signer (typically from `getRenownSignerConfig`). Signs client
|
|
233
|
+
* writes and the operations the executor synthesizes, in pooled workers
|
|
234
|
+
* through `workerSigner`; omit for unsigned operation.
|
|
195
235
|
*/
|
|
196
236
|
signer?: SignerConfig;
|
|
237
|
+
/**
|
|
238
|
+
* Which keys may sign as which users (typically from
|
|
239
|
+
* `getRenownTrustPolicyConfig`); wins over one carried by `signer`.
|
|
240
|
+
*/
|
|
241
|
+
trustPolicy?: Pick<SignerConfig, "trustPolicy" | "workerTrustPolicy">;
|
|
242
|
+
/** What the client creates new documents as; see `resolveCreateSignaturePolicy`. */
|
|
243
|
+
createSignaturePolicy?: SignaturePolicy;
|
|
197
244
|
};
|
|
198
|
-
declare function applySwitchboardReactorDefaults(reactorBuilder: ReactorBuilder, clientBuilder: ReactorClientBuilder, options?: SwitchboardReactorDefaultsOptions): void;
|
|
245
|
+
export declare function applySwitchboardReactorDefaults(reactorBuilder: ReactorBuilder, clientBuilder: ReactorClientBuilder, options?: SwitchboardReactorDefaultsOptions): void;
|
|
199
246
|
//#endregion
|
|
200
247
|
//#region src/server.d.mts
|
|
201
248
|
/**
|
|
@@ -203,9 +250,9 @@ declare function applySwitchboardReactorDefaults(reactorBuilder: ReactorBuilder,
|
|
|
203
250
|
* the port is free, false if the OS reports it in use. Any other error is
|
|
204
251
|
* surfaced so we don't silently mask real issues (permissions, bad host, …).
|
|
205
252
|
*/
|
|
206
|
-
declare function isPortAvailable(port: number): Promise<boolean>;
|
|
253
|
+
export declare function isPortAvailable(port: number): Promise<boolean>;
|
|
207
254
|
/** 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): {
|
|
255
|
+
export declare function deriveAttachmentServiceConfig(options: Pick<StartServerOptions, "attachmentServiceUrl" | "https">, serverPort: number, renown: IRenown | null): {
|
|
209
256
|
remoteUrl: string;
|
|
210
257
|
jwtHandler: JwtHandler | undefined;
|
|
211
258
|
};
|
|
@@ -226,7 +273,8 @@ declare function deriveAttachmentServiceConfig(options: Pick<StartServerOptions,
|
|
|
226
273
|
* trigger the `withShutdownHook` chain that disposes the api. Programmatic
|
|
227
274
|
* full teardown isn't currently exposed — wire it via SIGINT/SIGTERM.
|
|
228
275
|
*/
|
|
229
|
-
declare const startSwitchboard: (options?: StartServerOptions) => Promise<SwitchboardReactor>;
|
|
276
|
+
export declare const startSwitchboard: (options?: StartServerOptions) => Promise<SwitchboardReactor>;
|
|
230
277
|
//#endregion
|
|
231
|
-
export {
|
|
278
|
+
export type { SwitchboardReactorDefaultsOptions, WorkflowTriggersCapability };
|
|
279
|
+
export {};
|
|
232
280
|
//# sourceMappingURL=server.d.mts.map
|
package/dist/server.d.mts.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"server.d.mts","names":[],"sources":["../src/types.ts","../src/builder-defaults.mts","../src/server.mts"],"mappings":"
|
|
1
|
+
{"version":3,"file":"server.d.mts","names":[],"sources":["../src/workflow-runtime.mts","../src/types.ts","../src/builder-defaults.mts","../src/server.mts"],"mappings":";;;;;;;;;;;;;KA2DY;EACN;;EAEA;EACA;;;;;;;;;;YC7CM;;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;EACA;;;EAGA;IACE;;EAEF,kBAAkB;EAClB;EACA;;;;;;EAMA;EACA,SAAS;;;;;;;;;;EAUT;;;;;;;;;;EAUA;;;;;;;;;EASA;IACE;IACA;IACA;;;;;;;;;;;EAWF;IACE;IACA;;;YAIQ;EACV;EACA,SAAS;;EAET,mBAAmB;;EAEnB,+BAA+B;;;EAG/B,mBAAmB;;EAEnB;;EAEA,QAAQ;;;;;EAKR;;;;;;;;;;;;;EAaA,gBAAgB;;;;KCzLN;EAIV,iBAAiB;;EAEjB,mBAAmB;;EAEnB;;;;;;EAMA,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;;;;;;;;wBC6DK,gBAAgB,eAAe;;wBAoI/B,8BACd,SAAS,KAAK,uDACd,oBACA,QAAQ;EACL;EAAmB,YAAY;;;;;;;;;;;;;;;;;;;qBAu5BvB,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-
|
|
3
|
-
import "./utils-Baw7rThP.mjs";
|
|
2
|
+
import { i as applySwitchboardReactorDefaults, n as isPortAvailable, r as startSwitchboard, t as deriveAttachmentServiceConfig } from "./server-CKKn0aXV.mjs";
|
|
4
3
|
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]="
|
|
6
|
-
//# debugId=
|
|
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]="fe3a107a-4dd4-530b-b8d9-ef36656e688e")}catch(e){}}();
|
|
5
|
+
//# debugId=fe3a107a-4dd4-530b-b8d9-ef36656e688e
|
|
@@ -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]="
|
|
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-
|
|
80
|
-
//# debugId=
|
|
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":";;;;;;;;;;AAmBA,eAAe,kBACb,QACA,UACA,IACoB;CACpB,OAAO,KACH,oBAAoB,UAAU,UAAU,EAAE,GAAG,CAAC,IAC9C,oBAAoB,UAAU,MAAM,OAAO,yBAAyB,CAAC;AAC3E;AAEA,eAAsB,gBACpB,QACA,OACA,YACA;CACA,IAAI,UAAU,MAAM;CACpB,IAAI,CAAC,WAAW,QAAQ,WAAW,GACjC,UAAU,MAAM;CAGlB,IAAI,CAAC,WAAW,QAAQ,WAAW,GACjC,MAAM,IAAI,MAAM,kBAAkB;CAIpC,IAAI;CACJ,IAAI;EACF,gBAAgB,MAAM,OAAO,IAAI,OAAO;CAC1C,QAAQ,CAER;CAGA,IAAI,eACF,OAAO,oBAAoB,WAAW,KAAK;CAG7C,MAAM,EAAE,WAAW,iBAAiB;CAepC,MAAM,WAAW,MAAM,kBAAkB,QAdzB,oBAAoB;EAClC,QAAQ;GACN,GAAG;GACH,MAAM,MAAM,OAAO;GACnB,MAAM,MAAM,OAAO,QAAQ,OAAO;EACpC;EACA,OAAO;GACL,kBAAkB,MAAM,OAAO,oBAAoB;GACnD,aAAa,MAAM,OAAO,eAAe;GACzC,WAAW,MAAM,OAAO,aAAa,CAAC;GACtC,UAAU,MAAM,OAAO,YAAY,CAAC;EACtC;CACF,CAEuD,GAAG,MAAM,EAAE;CAClE,IAAI,MAAM,QAAQ,MAAM,KAAK,SAAS,GACpC,SAAS,OAAO,OAAO,MAAM;CAE/B,IAAI,MAAM,OAAO,MACf,SAAS,OAAO,OAAO,MAAM,OAAO;CAEtC,IAAI,MAAM,iBACR,SAAS,OAAO,OAAO,EAAE,iBAAiB,MAAM,gBAAgB;CAGlE,IAAI;EACF,MAAM,OAAO,OAAO,QAAQ;CAC9B,SAAS,GAAG;EAEV,IAAI,EADiB,aAAa,QAAQ,EAAE,UAAU,OAAO,CAAC,EAAA,CAC5C,SAAS,gBAAgB,GACzC,MAAM;CAEV;CAEA,OAAO,oBAAoB,WAAW,KAAK;AAC7C;AAEA,eAAsB,uBACpB,QACA,OACA,YACA;CACA,IAAI,UAAU,MAAM;CACpB,IAAI,CAAC,WAAW,QAAQ,WAAW,GACjC,UAAU,MAAM;CAGlB,IAAI,CAAC,WAAW,QAAQ,WAAW,GACjC,MAAM,IAAI,MAAM,kBAAkB;CAGpC,IAAI;CACJ,IAAI;EACF,gBAAgB,MAAM,OAAO,IAAI,OAAO;CAC1C,QAAQ,CAER;CAEA,IAAI,eACF,OAAO,oBAAoB,WAAW,KAAK;CAG7C,MAAM,EAAE,QAAQ,UAAU,wBAAwB;CAclD,MAAM,WAAW,MAAM,kBAAkB,QAbzB,2BAA2B;EACzC,QAAQ;GACN,GAAG;GACH,MAAM,MAAM,OAAO;GACnB,MAAM,MAAM,OAAO,QAAQ,OAAO;EACpC;EACA,OAAO;GACL,GAAG;GACH,kBAAkB,MAAM,OAAO,oBAAoB,MAAM;GACzD,aAAa,MAAM,OAAO,eAAe,MAAM;EACjD;CACF,CAEuD,GAAG,MAAM,EAAE;CAClE,IAAI,MAAM,QAAQ,MAAM,KAAK,SAAS,GACpC,SAAS,OAAO,OAAO,MAAM;CAE/B,IAAI,MAAM,OAAO,MACf,SAAS,OAAO,OAAO,MAAM,OAAO;CAEtC,IAAI,MAAM,iBACR,SAAS,OAAO,OAAO,EAAE,iBAAiB,MAAM,gBAAgB;CAGlE,IAAI;EACF,MAAM,OAAO,OAAO,QAAQ;CAC9B,SAAS,GAAG;EAEV,IAAI,EADiB,aAAa,QAAQ,EAAE,UAAU,OAAO,CAAC,EAAA,CAC5C,SAAS,gBAAgB,GACzC,MAAM;CAEV;CAEA,OAAO,oBAAoB,WAAW,KAAK;AAC7C;AAEA,SAAgB,cAAc,KAAa;CACzC,OAAO,IAAI,WAAW,YAAY,KAAK,IAAI,WAAW,UAAU;AAClE","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 {
|
|
8
|
+
export {};
|
|
10
9
|
//# sourceMappingURL=utils.d.mts.map
|
package/dist/utils.d.mts.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"utils.d.mts","names":[],"sources":["../src/utils.mts"],"mappings":"
|
|
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-
|
|
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]="
|
|
4
|
-
//# debugId=
|
|
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.
|
|
4
|
+
"version": "6.2.3-dev.31",
|
|
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.
|
|
44
|
+
"@powerhousedao/config": "6.2.3-dev.31",
|
|
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,32 +55,36 @@
|
|
|
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.
|
|
59
|
-
"@powerhousedao/reactor": "6.2.3-dev.
|
|
60
|
-
"@powerhousedao/shared": "6.2.3-dev.
|
|
61
|
-
"@powerhousedao/vetra": "6.2.3-dev.
|
|
62
|
-
"@powerhousedao/reactor-api": "6.2.3-dev.
|
|
63
|
-
"@powerhousedao/reactor-attachments": "6.2.3-dev.
|
|
64
|
-
"@powerhousedao/reactor-drive": "6.2.3-dev.
|
|
65
|
-
"@powerhousedao/reactor-group": "6.2.3-dev.
|
|
66
|
-
"@powerhousedao/
|
|
58
|
+
"@powerhousedao/opentelemetry-instrumentation-reactor": "6.2.3-dev.31",
|
|
59
|
+
"@powerhousedao/reactor": "6.2.3-dev.31",
|
|
60
|
+
"@powerhousedao/shared": "6.2.3-dev.31",
|
|
61
|
+
"@powerhousedao/vetra": "6.2.3-dev.31",
|
|
62
|
+
"@powerhousedao/reactor-api": "6.2.3-dev.31",
|
|
63
|
+
"@powerhousedao/reactor-attachments": "6.2.3-dev.31",
|
|
64
|
+
"@powerhousedao/reactor-drive": "6.2.3-dev.31",
|
|
65
|
+
"@powerhousedao/reactor-group": "6.2.3-dev.31",
|
|
66
|
+
"@powerhousedao/reactor-workflow": "6.2.3-dev.31",
|
|
67
|
+
"@powerhousedao/workflow": "6.2.3-dev.31",
|
|
68
|
+
"@powerhousedao/pglite-fs": "6.2.3-dev.31",
|
|
67
69
|
"@pyroscope/nodejs": "^0.4.5",
|
|
68
|
-
"@renown/sdk": "6.2.3-dev.
|
|
70
|
+
"@renown/sdk": "6.2.3-dev.31",
|
|
69
71
|
"@sentry/node": "^10.53.1",
|
|
70
72
|
"@sentry/opentelemetry": "^10.53.1",
|
|
71
|
-
"document-model": "6.2.3-dev.
|
|
73
|
+
"document-model": "6.2.3-dev.31",
|
|
72
74
|
"dotenv": "^16.4.7",
|
|
73
|
-
"express": "^4.
|
|
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
|
|
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.
|
|
87
|
+
"tsdown": "0.23.0",
|
|
84
88
|
"concurrently": "9.2.1",
|
|
85
89
|
"nodemon": "3.1.11",
|
|
86
90
|
"react": "19.2.6",
|
|
@@ -92,7 +96,7 @@
|
|
|
92
96
|
"scripts": {
|
|
93
97
|
"tsc": "tsc",
|
|
94
98
|
"test": "vitest run",
|
|
95
|
-
"lint": "
|
|
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",
|
|
@@ -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({
|