@powerhousedao/switchboard 6.2.3-dev.35 → 6.2.3-dev.37

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.
@@ -1 +1 @@
1
- {"version":3,"file":"server.d.mts","names":[],"sources":["../src/privacy.mts","../src/workflow-runtime.mts","../src/types.ts","../src/builder-defaults.mts","../src/unsupported-stored-documents.mts","../src/server.mts"],"mappings":";;;;;;;;;;;;KAyBY;;EAEV;;EAEA;;EAEA,SAAS;;;;;;KCsBC;EACN;;EAEA;EACA;;;;;;;;;;YCpCM;;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;IAAY,SAAS;;;EAErB;;EAEA,QAAQ;;;;;EAKR;;;;;;;;;;;;;EAaA,gBAAgB;;;;KC5MN;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;;;;wBC3EK,kCACd,OAAO,wCACP,KAAK,OAAO,aACX;;qBAaU,oCAAoC;WACtC;IAAqB;IAAkB;;WACvC;EAET,YAAY,OAAO;SAcZ,QAAQ,iBAAiB,SAAS;;;;;;;;;wBCyH3B,gBAAgB,eAAe;;wBAwI/B,8BACd,SAAS,KAAK,uDACd,oBACA,QAAQ;EACL;EAAmB,YAAY;;;;;;;;;;;;;;;;;;;qBA88BvB,mBAAgB,UAClB,uBACR,QAAQ"}
1
+ {"version":3,"file":"server.d.mts","names":[],"sources":["../src/privacy.mts","../src/workflow-runtime.mts","../src/types.ts","../src/builder-defaults.mts","../src/unsupported-stored-documents.mts","../src/server.mts"],"mappings":";;;;;;;;;;;;KAyBY;;EAEV;;EAEA;;EAEA,SAAS;;;;;;KCsBC;EACN;;EAEA;EACA;;;;;;;;;;YCpCM;;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;IAAY,SAAS;;;EAErB;;EAEA,QAAQ;;;;;EAKR;;;;;;;;;;;;;EAaA,gBAAgB;;;;KC5MN;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;;;;wBC3EK,kCACd,OAAO,wCACP,KAAK,OAAO,aACX;;qBAaU,oCAAoC;WACtC;IAAqB;IAAkB;;WACvC;EAET,YAAY,OAAO;SAcZ,QAAQ,iBAAiB,SAAS;;;;;;;;;wBCyH3B,gBAAgB,eAAe;;wBAwI/B,8BACd,SAAS,KAAK,uDACd,oBACA,QAAQ;EACL;EAAmB,YAAY;;;;;;;;;;;;;;;;;;;qBAg9BvB,mBAAgB,UAClB,uBACR,QAAQ"}
package/dist/server.mjs CHANGED
@@ -1,5 +1,5 @@
1
1
  #!/usr/bin/env node
2
- import { a as resolveUnsupportedStoredDocuments, i as StoredDocumentsRefusedError, n as isPortAvailable, o as applySwitchboardReactorDefaults, r as startSwitchboard, t as deriveAttachmentServiceConfig } from "./server-CXAp5TOI.mjs";
2
+ import { a as resolveUnsupportedStoredDocuments, i as StoredDocumentsRefusedError, n as isPortAvailable, o as applySwitchboardReactorDefaults, r as startSwitchboard, t as deriveAttachmentServiceConfig } from "./server-D3CYuEka.mjs";
3
3
  export { StoredDocumentsRefusedError, applySwitchboardReactorDefaults, 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]="91c41927-1b39-5750-b103-5886cde48ae6")}catch(e){}}();
5
- //# debugId=91c41927-1b39-5750-b103-5886cde48ae6
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]="784a735c-87ca-55fa-bea5-af4fb82863ba")}catch(e){}}();
5
+ //# debugId=784a735c-87ca-55fa-bea5-af4fb82863ba
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.35",
4
+ "version": "6.2.3-dev.37",
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.35",
44
+ "@powerhousedao/config": "6.2.3-dev.37",
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,23 +55,23 @@
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.35",
59
- "@powerhousedao/reactor": "6.2.3-dev.35",
60
- "@powerhousedao/shared": "6.2.3-dev.35",
61
- "@powerhousedao/vetra": "6.2.3-dev.35",
62
- "@powerhousedao/reactor-api": "6.2.3-dev.35",
63
- "@powerhousedao/reactor-attachments": "6.2.3-dev.35",
64
- "@powerhousedao/reactor-drive": "6.2.3-dev.35",
65
- "@powerhousedao/reactor-group": "6.2.3-dev.35",
66
- "@powerhousedao/reactor-privacy": "6.2.3-dev.35",
67
- "@powerhousedao/reactor-workflow": "6.2.3-dev.35",
68
- "@powerhousedao/workflow": "6.2.3-dev.35",
69
- "@powerhousedao/pglite-fs": "6.2.3-dev.35",
58
+ "@powerhousedao/opentelemetry-instrumentation-reactor": "6.2.3-dev.37",
59
+ "@powerhousedao/reactor": "6.2.3-dev.37",
60
+ "@powerhousedao/shared": "6.2.3-dev.37",
61
+ "@powerhousedao/vetra": "6.2.3-dev.37",
62
+ "@powerhousedao/reactor-api": "6.2.3-dev.37",
63
+ "@powerhousedao/reactor-attachments": "6.2.3-dev.37",
64
+ "@powerhousedao/reactor-drive": "6.2.3-dev.37",
65
+ "@powerhousedao/reactor-group": "6.2.3-dev.37",
66
+ "@powerhousedao/reactor-privacy": "6.2.3-dev.37",
67
+ "@powerhousedao/reactor-workflow": "6.2.3-dev.37",
68
+ "@powerhousedao/workflow": "6.2.3-dev.37",
69
+ "@powerhousedao/pglite-fs": "6.2.3-dev.37",
70
70
  "@pyroscope/nodejs": "^0.4.5",
71
- "@renown/sdk": "6.2.3-dev.35",
71
+ "@renown/sdk": "6.2.3-dev.37",
72
72
  "@sentry/node": "^10.53.1",
73
73
  "@sentry/opentelemetry": "^10.53.1",
74
- "document-model": "6.2.3-dev.35",
74
+ "document-model": "6.2.3-dev.37",
75
75
  "dotenv": "^16.4.7",
76
76
  "express": "^4.22.1",
77
77
  "graphql": "^16",
@@ -94,7 +94,10 @@ function makeAccess(result: AttachmentAccessResult | Error) {
94
94
  result instanceof Error ? Promise.reject(result) : Promise.resolve(result),
95
95
  );
96
96
  return {
97
- access: { canReadAttachment } as IAttachmentAccessService,
97
+ access: {
98
+ canReadAttachment,
99
+ admitCaller: () => Promise.resolve({ kind: "admitted" }),
100
+ } as IAttachmentAccessService,
98
101
  canReadAttachment,
99
102
  };
100
103
  }
@@ -91,7 +91,13 @@ function makeAccess(result: AttachmentAccessResult): {
91
91
  spy: ReturnType<typeof vi.fn>;
92
92
  } {
93
93
  const spy = vi.fn().mockResolvedValue(result);
94
- return { access: { canReadAttachment: spy }, spy };
94
+ return {
95
+ access: {
96
+ canReadAttachment: spy,
97
+ admitCaller: () => Promise.resolve({ kind: "admitted" }),
98
+ },
99
+ spy,
100
+ };
95
101
  }
96
102
 
97
103
  function makeAttachments(opts: {
@@ -0,0 +1,96 @@
1
+ import {
2
+ InvalidAttachmentMetadata,
3
+ validateReserveMetadata,
4
+ type ReserveMetadata,
5
+ } from "@powerhousedao/reactor-attachments";
6
+ import { describe, expect, it } from "vitest";
7
+ import { parseReserveOptions } from "../../src/attachments/routes.js";
8
+
9
+ type Case = [name: string, meta: Record<string, unknown>];
10
+
11
+ const base = { mimeType: "text/plain", fileName: "note.txt" };
12
+
13
+ // The download route's setHeader throws on each of these.
14
+ const headerBreaking: Case[] = [
15
+ ["CRLF before a parameter", { ...base, mimeType: "text/plain\r\n;a=b" }],
16
+ ["LF after a ;", { ...base, mimeType: "text/plain;\na=b" }],
17
+ ["a control char quoted", { ...base, mimeType: 'text/plain; a="\x01"' }],
18
+ ["a DEL quoted", { ...base, mimeType: 'text/plain; a="\x7f"' }],
19
+ ["a char above 0xFF quoted", { ...base, mimeType: 'text/plain;a="\u0100"' }],
20
+ ];
21
+
22
+ const cases: Case[] = [
23
+ ["plain metadata", base],
24
+ ["an extension", { ...base, extension: "txt" }],
25
+ ["a null extension", { ...base, extension: null }],
26
+ ["a parameter", { ...base, mimeType: "text/plain; charset=utf-8" }],
27
+ ["a quoted parameter", { ...base, mimeType: 'text/plain; a="b c"' }],
28
+ ["a unicode file name", { ...base, fileName: "résumé.pdf" }],
29
+ ["a 255-char mimeType", { ...base, mimeType: `a/${"b".repeat(253)}` }],
30
+ ["a 256-char mimeType", { ...base, mimeType: `a/${"b".repeat(254)}` }],
31
+ ["a 255-char fileName", { ...base, fileName: "f".repeat(255) }],
32
+ ["a 256-char fileName", { ...base, fileName: "f".repeat(256) }],
33
+ ["an empty mimeType", { ...base, mimeType: "" }],
34
+ ["an empty fileName", { ...base, fileName: "" }],
35
+ ["an empty extension", { ...base, extension: "" }],
36
+ ["a mimeType with no slash", { ...base, mimeType: "text" }],
37
+ ["a mimeType with no subtype", { ...base, mimeType: "text/" }],
38
+ ["a mimeType with no type", { ...base, mimeType: "/plain" }],
39
+ ["a mimeType with two slashes", { ...base, mimeType: "text/plain/x" }],
40
+ ["a mimeType with a space", { ...base, mimeType: "text plain" }],
41
+ ["a mimeType with a dangling ;", { ...base, mimeType: "text/plain;" }],
42
+ ["a non-string mimeType", { ...base, mimeType: 5 }],
43
+ ["a trailing CRLF in mimeType", { ...base, mimeType: "text/plain\r\n" }],
44
+ [
45
+ "an injected header in mimeType",
46
+ { ...base, mimeType: "text/plain\nX-Injected: 1" },
47
+ ],
48
+ ["a NUL in mimeType", { ...base, mimeType: "text/pl\x00ain" }],
49
+ ...headerBreaking,
50
+ ["a NUL in fileName", { ...base, fileName: "a\x00b" }],
51
+ ["a LF in fileName", { ...base, fileName: "a\nb" }],
52
+ ["a CR in fileName", { ...base, fileName: "a\rb" }],
53
+ ["a tab in fileName", { ...base, fileName: "a\tb" }],
54
+ ["a DEL in fileName", { ...base, fileName: "a\x7fb" }],
55
+ ["a non-string fileName", { ...base, fileName: null }],
56
+ ["a slash in extension", { ...base, extension: "a/b" }],
57
+ ["a backslash in extension", { ...base, extension: "a\\b" }],
58
+ ["a bare slash extension", { ...base, extension: "/" }],
59
+ ["a non-string extension", { ...base, extension: 5 }],
60
+ ];
61
+
62
+ function routeAccepts(meta: Record<string, unknown>): boolean {
63
+ return parseReserveOptions(meta) !== null;
64
+ }
65
+
66
+ function validatorAccepts(meta: Record<string, unknown>): boolean {
67
+ try {
68
+ validateReserveMetadata(meta as ReserveMetadata);
69
+ return true;
70
+ } catch (err) {
71
+ if (err instanceof InvalidAttachmentMetadata) return false;
72
+ throw err;
73
+ }
74
+ }
75
+
76
+ describe("reserve metadata parity between the route and validateReserveMetadata", () => {
77
+ it("covers both accepted and rejected metadata", () => {
78
+ const verdicts = cases.map(([, meta]) => routeAccepts(meta));
79
+ expect(verdicts).toContain(true);
80
+ expect(verdicts).toContain(false);
81
+ });
82
+
83
+ it.each(cases)("agrees on %s", (_name, meta) => {
84
+ expect(validatorAccepts(meta)).toBe(routeAccepts(meta));
85
+ });
86
+ });
87
+
88
+ describe("header-breaking mimeType values", () => {
89
+ it.each(headerBreaking)("the route rejects %s", (_name, meta) => {
90
+ expect(routeAccepts(meta)).toBe(false);
91
+ });
92
+
93
+ it.each(headerBreaking)("the validator rejects %s", (_name, meta) => {
94
+ expect(validatorAccepts(meta)).toBe(false);
95
+ });
96
+ });
@@ -31,6 +31,7 @@ const ALLOW_ALL: IAttachmentAccessService = {
31
31
  documentId: request.documentId as never,
32
32
  ref: request.attachmentRef as never,
33
33
  }),
34
+ admitCaller: () => Promise.resolve({ kind: "admitted" }),
34
35
  };
35
36
 
36
37
  describe("attachment routes through the real Express middleware stack", () => {
@@ -39,6 +39,7 @@ const ALLOW_ALL: IAttachmentAccessService = {
39
39
  documentId: request.documentId as never,
40
40
  ref: request.attachmentRef as never,
41
41
  }),
42
+ admitCaller: () => Promise.resolve({ kind: "admitted" }),
42
43
  };
43
44
  const grantedDownload = (attachments: AttachmentBuildResult) =>
44
45
  makeDownloadHandler(attachments, ALLOW_ALL, null);