@powerhousedao/switchboard 6.0.0-dev.21 → 6.0.0-dev.210

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 (78) hide show
  1. package/Auth.md +45 -27
  2. package/CHANGELOG.md +1638 -5
  3. package/README.md +13 -12
  4. package/dist/index.d.mts +1 -0
  5. package/dist/index.mjs +129 -0
  6. package/dist/index.mjs.map +1 -0
  7. package/dist/install-packages.d.mts +1 -0
  8. package/dist/install-packages.mjs +31 -0
  9. package/dist/install-packages.mjs.map +1 -0
  10. package/dist/migrate.d.mts +1 -0
  11. package/dist/migrate.mjs +55 -0
  12. package/dist/migrate.mjs.map +1 -0
  13. package/dist/server-8U7q7B7r.mjs +493 -0
  14. package/dist/server-8U7q7B7r.mjs.map +1 -0
  15. package/dist/server.d.mts +93 -0
  16. package/dist/server.d.mts.map +1 -0
  17. package/dist/server.mjs +4 -0
  18. package/dist/utils-DFl0ezBT.mjs +44 -0
  19. package/dist/utils-DFl0ezBT.mjs.map +1 -0
  20. package/dist/utils.d.mts +9 -0
  21. package/dist/utils.d.mts.map +1 -0
  22. package/dist/utils.mjs +2 -0
  23. package/package.json +54 -39
  24. package/test/attachments/auth.test.ts +219 -0
  25. package/test/attachments/index.test.ts +119 -0
  26. package/test/attachments/routes-integration.test.ts +103 -0
  27. package/test/attachments/routes.test.ts +501 -0
  28. package/test/metrics.test.ts +202 -0
  29. package/tsconfig.json +12 -3
  30. package/tsdown.config.ts +16 -0
  31. package/vitest.config.ts +11 -0
  32. package/Dockerfile +0 -86
  33. package/dist/src/clients/redis.d.ts +0 -5
  34. package/dist/src/clients/redis.d.ts.map +0 -1
  35. package/dist/src/clients/redis.js +0 -48
  36. package/dist/src/clients/redis.js.map +0 -1
  37. package/dist/src/config.d.ts +0 -12
  38. package/dist/src/config.d.ts.map +0 -1
  39. package/dist/src/config.js +0 -33
  40. package/dist/src/config.js.map +0 -1
  41. package/dist/src/connect-crypto.d.ts +0 -41
  42. package/dist/src/connect-crypto.d.ts.map +0 -1
  43. package/dist/src/connect-crypto.js +0 -127
  44. package/dist/src/connect-crypto.js.map +0 -1
  45. package/dist/src/feature-flags.d.ts +0 -2
  46. package/dist/src/feature-flags.d.ts.map +0 -1
  47. package/dist/src/feature-flags.js +0 -9
  48. package/dist/src/feature-flags.js.map +0 -1
  49. package/dist/src/index.d.ts +0 -3
  50. package/dist/src/index.d.ts.map +0 -1
  51. package/dist/src/index.js +0 -21
  52. package/dist/src/index.js.map +0 -1
  53. package/dist/src/install-packages.d.ts +0 -2
  54. package/dist/src/install-packages.d.ts.map +0 -1
  55. package/dist/src/install-packages.js +0 -36
  56. package/dist/src/install-packages.js.map +0 -1
  57. package/dist/src/migrate.d.ts +0 -3
  58. package/dist/src/migrate.d.ts.map +0 -1
  59. package/dist/src/migrate.js +0 -65
  60. package/dist/src/migrate.js.map +0 -1
  61. package/dist/src/profiler.d.ts +0 -4
  62. package/dist/src/profiler.d.ts.map +0 -1
  63. package/dist/src/profiler.js +0 -17
  64. package/dist/src/profiler.js.map +0 -1
  65. package/dist/src/server.d.ts +0 -6
  66. package/dist/src/server.d.ts.map +0 -1
  67. package/dist/src/server.js +0 -304
  68. package/dist/src/server.js.map +0 -1
  69. package/dist/src/types.d.ts +0 -64
  70. package/dist/src/types.d.ts.map +0 -1
  71. package/dist/src/types.js +0 -2
  72. package/dist/src/types.js.map +0 -1
  73. package/dist/src/utils.d.ts +0 -6
  74. package/dist/src/utils.d.ts.map +0 -1
  75. package/dist/src/utils.js +0 -92
  76. package/dist/src/utils.js.map +0 -1
  77. package/dist/tsconfig.tsbuildinfo +0 -1
  78. package/entrypoint.sh +0 -17
@@ -0,0 +1,202 @@
1
+ import { MeterProvider } from "@opentelemetry/sdk-metrics";
2
+ import { afterEach, describe, expect, it, vi } from "vitest";
3
+ import { createMeterProviderFromEnv } from "../src/metrics.js";
4
+
5
+ // Stub childLogger so tests don't require the full document-drive runtime
6
+ vi.mock("document-drive", () => ({
7
+ childLogger: () => ({
8
+ info: vi.fn(),
9
+ warn: vi.fn(),
10
+ error: vi.fn(),
11
+ }),
12
+ }));
13
+
14
+ const providers: MeterProvider[] = [];
15
+
16
+ afterEach(async () => {
17
+ vi.restoreAllMocks();
18
+ // Await shutdown so PeriodicExportingMetricReader timers are cleared
19
+ await Promise.all(providers.map((p) => p.shutdown()));
20
+ providers.length = 0;
21
+ });
22
+
23
+ function track(provider: MeterProvider | undefined): MeterProvider | undefined {
24
+ if (provider) providers.push(provider);
25
+ return provider;
26
+ }
27
+
28
+ function trackAsserted(provider: MeterProvider | undefined): MeterProvider {
29
+ expect(provider).toBeInstanceOf(MeterProvider);
30
+ return track(provider) as MeterProvider;
31
+ }
32
+
33
+ // These helpers access undocumented internal fields of MeterProvider and
34
+ // PeriodicExportingMetricReader. They may break if @opentelemetry/sdk-metrics
35
+ // renames its private state between major versions.
36
+ function getReader(provider: MeterProvider): {
37
+ _exportInterval: number;
38
+ _exportTimeout: number;
39
+ } {
40
+ return (
41
+ provider as unknown as {
42
+ _sharedState: {
43
+ metricCollectors: Array<{
44
+ _metricReader: { _exportInterval: number; _exportTimeout: number };
45
+ }>;
46
+ };
47
+ }
48
+ )._sharedState.metricCollectors[0]._metricReader;
49
+ }
50
+
51
+ function getExporterUrl(provider: MeterProvider): string {
52
+ return (
53
+ provider as unknown as {
54
+ _sharedState: {
55
+ metricCollectors: Array<{
56
+ _metricReader: {
57
+ _exporter: {
58
+ _delegate: {
59
+ _transport: {
60
+ _transport: { _parameters: { url: string } };
61
+ };
62
+ };
63
+ };
64
+ };
65
+ }>;
66
+ };
67
+ }
68
+ )._sharedState.metricCollectors[0]._metricReader._exporter._delegate
69
+ ._transport._transport._parameters.url;
70
+ }
71
+
72
+ function getResourceAttributes(
73
+ provider: MeterProvider,
74
+ ): Record<string, unknown> {
75
+ return (
76
+ provider as unknown as {
77
+ _sharedState: { resource: { attributes: Record<string, unknown> } };
78
+ }
79
+ )._sharedState.resource.attributes;
80
+ }
81
+
82
+ describe("createMeterProviderFromEnv", () => {
83
+ describe("when OTEL_EXPORTER_OTLP_ENDPOINT is not set", () => {
84
+ it("returns undefined", () => {
85
+ expect(createMeterProviderFromEnv({})).toBeUndefined();
86
+ });
87
+ });
88
+
89
+ describe("when OTEL_EXPORTER_OTLP_ENDPOINT is set", () => {
90
+ it("returns a MeterProvider", () => {
91
+ expect(
92
+ track(
93
+ createMeterProviderFromEnv({
94
+ OTEL_EXPORTER_OTLP_ENDPOINT: "http://localhost:4318",
95
+ }),
96
+ ),
97
+ ).toBeInstanceOf(MeterProvider);
98
+ });
99
+
100
+ it("strips trailing slash from endpoint URL without throwing", () => {
101
+ expect(() =>
102
+ track(
103
+ createMeterProviderFromEnv({
104
+ OTEL_EXPORTER_OTLP_ENDPOINT: "http://localhost:4318/",
105
+ }),
106
+ ),
107
+ ).not.toThrow();
108
+ });
109
+
110
+ it("does not double-append /v1/metrics when endpoint already includes it", () => {
111
+ const provider = trackAsserted(
112
+ createMeterProviderFromEnv({
113
+ OTEL_EXPORTER_OTLP_ENDPOINT: "http://localhost:4318/v1/metrics",
114
+ }),
115
+ );
116
+ expect(getExporterUrl(provider)).toBe("http://localhost:4318/v1/metrics");
117
+ });
118
+
119
+ it("uses 5000ms export interval by default", () => {
120
+ const provider = trackAsserted(
121
+ createMeterProviderFromEnv({
122
+ OTEL_EXPORTER_OTLP_ENDPOINT: "http://localhost:4318",
123
+ }),
124
+ );
125
+ expect(getReader(provider)._exportInterval).toBe(5000);
126
+ });
127
+
128
+ it("honours OTEL_METRIC_EXPORT_INTERVAL", () => {
129
+ const provider = trackAsserted(
130
+ createMeterProviderFromEnv({
131
+ OTEL_EXPORTER_OTLP_ENDPOINT: "http://localhost:4318",
132
+ OTEL_METRIC_EXPORT_INTERVAL: "2000",
133
+ }),
134
+ );
135
+ expect(getReader(provider)._exportInterval).toBe(2000);
136
+ });
137
+
138
+ it("falls back to 5000ms when OTEL_METRIC_EXPORT_INTERVAL is non-numeric", () => {
139
+ const provider = trackAsserted(
140
+ createMeterProviderFromEnv({
141
+ OTEL_EXPORTER_OTLP_ENDPOINT: "http://localhost:4318",
142
+ OTEL_METRIC_EXPORT_INTERVAL: "abc",
143
+ }),
144
+ );
145
+ expect(getReader(provider)._exportInterval).toBe(5000);
146
+ });
147
+
148
+ it("falls back to 5000ms when OTEL_METRIC_EXPORT_INTERVAL is zero", () => {
149
+ const provider = trackAsserted(
150
+ createMeterProviderFromEnv({
151
+ OTEL_EXPORTER_OTLP_ENDPOINT: "http://localhost:4318",
152
+ OTEL_METRIC_EXPORT_INTERVAL: "0",
153
+ }),
154
+ );
155
+ expect(getReader(provider)._exportInterval).toBe(5000);
156
+ });
157
+
158
+ it("falls back to 5000ms when OTEL_METRIC_EXPORT_INTERVAL is negative", () => {
159
+ const provider = trackAsserted(
160
+ createMeterProviderFromEnv({
161
+ OTEL_EXPORTER_OTLP_ENDPOINT: "http://localhost:4318",
162
+ OTEL_METRIC_EXPORT_INTERVAL: "-1000",
163
+ }),
164
+ );
165
+ expect(getReader(provider)._exportInterval).toBe(5000);
166
+ });
167
+
168
+ it("sets exportTimeoutMillis below exportIntervalMillis", () => {
169
+ const provider = trackAsserted(
170
+ createMeterProviderFromEnv({
171
+ OTEL_EXPORTER_OTLP_ENDPOINT: "http://localhost:4318",
172
+ OTEL_METRIC_EXPORT_INTERVAL: "1000",
173
+ }),
174
+ );
175
+ const reader = getReader(provider);
176
+ expect(reader._exportTimeout).toBeLessThan(reader._exportInterval);
177
+ });
178
+
179
+ it("uses 'switchboard' as service name by default", () => {
180
+ const provider = trackAsserted(
181
+ createMeterProviderFromEnv({
182
+ OTEL_EXPORTER_OTLP_ENDPOINT: "http://localhost:4318",
183
+ }),
184
+ );
185
+ expect(getResourceAttributes(provider)["service.name"]).toBe(
186
+ "switchboard",
187
+ );
188
+ });
189
+
190
+ it("honours OTEL_SERVICE_NAME", () => {
191
+ const provider = trackAsserted(
192
+ createMeterProviderFromEnv({
193
+ OTEL_EXPORTER_OTLP_ENDPOINT: "http://localhost:4318",
194
+ OTEL_SERVICE_NAME: "my-switchboard",
195
+ }),
196
+ );
197
+ expect(getResourceAttributes(provider)["service.name"]).toBe(
198
+ "my-switchboard",
199
+ );
200
+ });
201
+ });
202
+ });
package/tsconfig.json CHANGED
@@ -10,23 +10,32 @@
10
10
  "**/*"
11
11
  ],
12
12
  "references": [
13
+ {
14
+ "path": "../../packages/config"
15
+ },
13
16
  {
14
17
  "path": "../../packages/document-model"
15
18
  },
16
19
  {
17
- "path": "../../packages/document-drive"
20
+ "path": "../../packages/opentelemetry-instrumentation-reactor"
18
21
  },
19
22
  {
20
- "path": "../../packages/config"
23
+ "path": "../../packages/reactor"
21
24
  },
22
25
  {
23
26
  "path": "../../packages/reactor-api"
24
27
  },
28
+ {
29
+ "path": "../../packages/reactor-attachments"
30
+ },
25
31
  {
26
32
  "path": "../../packages/renown"
27
33
  },
28
34
  {
29
- "path": "../../packages/reactor"
35
+ "path": "../../packages/shared"
36
+ },
37
+ {
38
+ "path": "../../packages/vetra"
30
39
  }
31
40
  ]
32
41
  }
@@ -0,0 +1,16 @@
1
+ import { defineConfig } from "tsdown";
2
+
3
+ export default defineConfig({
4
+ entry: [
5
+ "src/index.mts",
6
+ "src/server.mts",
7
+ "src/utils.mts",
8
+ "src/install-packages.mts",
9
+ "src/migrate.mts",
10
+ ],
11
+ platform: "node",
12
+ outDir: "dist",
13
+ clean: true,
14
+ dts: true,
15
+ sourcemap: true,
16
+ });
@@ -0,0 +1,11 @@
1
+ import { defineConfig } from "vitest/config";
2
+
3
+ export default defineConfig({
4
+ test: {
5
+ pool: "forks",
6
+ environment: "node",
7
+ isolate: true,
8
+ maxWorkers: 1,
9
+ include: ["test/**/*.test.ts"],
10
+ },
11
+ });
package/Dockerfile DELETED
@@ -1,86 +0,0 @@
1
- # Build stage
2
- FROM node:22-alpine AS build
3
-
4
- WORKDIR /app
5
-
6
- # Install build dependencies
7
- RUN apk add --no-cache python3 make g++ git bash \
8
- && ln -sf /usr/bin/python3 /usr/bin/python
9
-
10
- # Setup pnpm
11
- ENV PNPM_HOME="/pnpm"
12
- ENV PATH="$PNPM_HOME:$PATH"
13
- RUN corepack enable && corepack prepare pnpm@latest --activate
14
-
15
- # Configure JSR registry
16
- RUN pnpm config set @jsr:registry https://npm.jsr.io
17
-
18
- # Build arguments
19
- ARG TAG=latest
20
- ARG PH_PACKAGES=""
21
-
22
- # Install ph-cmd, prisma, and prettier
23
- RUN pnpm add -g ph-cmd@$TAG prisma@5.17.0 prettier
24
-
25
- # Initialize project based on tag
26
- RUN case "$TAG" in \
27
- *dev*) ph init project --dev --package-manager pnpm ;; \
28
- *staging*) ph init project --staging --package-manager pnpm ;; \
29
- *) ph init project --package-manager pnpm ;; \
30
- esac
31
-
32
- WORKDIR /app/project
33
-
34
- # Install PH packages if provided
35
- RUN if [ -n "$PH_PACKAGES" ]; then \
36
- IFS=',' ; for pkg in $PH_PACKAGES; do \
37
- echo "Installing package: $pkg"; \
38
- ph install "$pkg"; \
39
- done; \
40
- fi
41
-
42
- # Regenerate Prisma client for Alpine Linux (linux-musl-openssl-3.0.x)
43
- # The document-drive package ships with darwin-arm64 binaries, we need to regenerate
44
- RUN prisma generate --schema node_modules/document-drive/dist/prisma/schema.prisma
45
-
46
- # Final stage - slim node image
47
- FROM node:22-alpine
48
-
49
- WORKDIR /app
50
-
51
- # Install runtime dependencies (curl for health checks, openssl for Prisma)
52
- RUN apk add --no-cache curl openssl
53
-
54
- # Setup pnpm
55
- ENV PNPM_HOME="/pnpm"
56
- ENV PATH="$PNPM_HOME:$PATH"
57
- RUN corepack enable && corepack prepare pnpm@latest --activate
58
-
59
- # Configure JSR registry
60
- RUN pnpm config set @jsr:registry https://npm.jsr.io
61
-
62
- # Install ph-cmd and prisma globally (needed at runtime)
63
- ARG TAG=latest
64
- RUN pnpm add -g ph-cmd@$TAG prisma@5.17.0
65
-
66
- # Copy built project from build stage
67
- COPY --from=build /app/project /app/project
68
-
69
- WORKDIR /app/project
70
-
71
- # Copy entrypoint
72
- COPY entrypoint.sh /app/entrypoint.sh
73
- RUN chmod +x /app/entrypoint.sh
74
-
75
- # Environment variables
76
- ENV NODE_ENV=production
77
- ENV PORT=3000
78
- ENV DATABASE_URL=""
79
- ENV SKIP_DB_MIGRATIONS="false"
80
-
81
- EXPOSE ${PORT}
82
-
83
- HEALTHCHECK --interval=30s --timeout=3s --start-period=30s --retries=3 \
84
- CMD curl -f http://localhost:${PORT}/health || exit 1
85
-
86
- ENTRYPOINT ["/app/entrypoint.sh"]
@@ -1,5 +0,0 @@
1
- import type { RedisClientType } from "redis";
2
- export declare let redisClient: RedisClientType | undefined;
3
- export declare const initRedis: (url: string) => Promise<RedisClientType | undefined>;
4
- export declare const closeRedis: () => Promise<void> | undefined;
5
- //# sourceMappingURL=redis.d.ts.map
@@ -1 +0,0 @@
1
- {"version":3,"file":"redis.d.ts","sourceRoot":"","sources":["../../../src/clients/redis.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,eAAe,EAAE,MAAM,OAAO,CAAC;AAG7C,eAAO,IAAI,WAAW,EAAE,eAAe,GAAG,SAAS,CAAC;AACpD,eAAO,MAAM,SAAS,GACpB,KAAK,MAAM,KACV,OAAO,CAAC,eAAe,GAAG,SAAS,CAiCrC,CAAC;AAeF,eAAO,MAAM,UAAU,iCAItB,CAAC"}
@@ -1,48 +0,0 @@
1
- import { createClient } from "redis";
2
- export let redisClient;
3
- export const initRedis = async (url) => {
4
- if (redisClient) {
5
- return redisClient;
6
- }
7
- return new Promise((resolve, reject) => {
8
- const socket = url.includes("rediss")
9
- ? {
10
- tls: true,
11
- rejectUnauthorized: false,
12
- }
13
- : undefined;
14
- redisClient = createClient({
15
- url,
16
- socket,
17
- });
18
- redisClient
19
- .connect()
20
- .then((client) => {
21
- redisClient = client;
22
- client.on("error", (err) => {
23
- console.warn("Redis Client Error", err);
24
- });
25
- resolve(client);
26
- })
27
- .catch(async (e) => {
28
- reject(e instanceof Error ? e : new Error(JSON.stringify(e)));
29
- // await redisClient.disconnect();
30
- // console.warn("Redis Client Error", e);
31
- });
32
- });
33
- };
34
- const timer = setInterval(async () => {
35
- try {
36
- if (redisClient) {
37
- await redisClient.ping();
38
- }
39
- }
40
- catch (err) {
41
- console.error("Ping Interval Error", err);
42
- }
43
- }, 1000 * 60 * 4);
44
- export const closeRedis = () => {
45
- clearInterval(timer);
46
- return redisClient?.disconnect();
47
- };
48
- //# sourceMappingURL=redis.js.map
@@ -1 +0,0 @@
1
- {"version":3,"file":"redis.js","sourceRoot":"","sources":["../../../src/clients/redis.ts"],"names":[],"mappings":"AACA,OAAO,EAAE,YAAY,EAAE,MAAM,OAAO,CAAC;AAErC,MAAM,CAAC,IAAI,WAAwC,CAAC;AACpD,MAAM,CAAC,MAAM,SAAS,GAAG,KAAK,EAC5B,GAAW,EAC2B,EAAE;IACxC,IAAI,WAAW,EAAE,CAAC;QAChB,OAAO,WAAW,CAAC;IACrB,CAAC;IAED,OAAO,IAAI,OAAO,CAAC,CAAC,OAAO,EAAE,MAAM,EAAE,EAAE;QACrC,MAAM,MAAM,GAAG,GAAG,CAAC,QAAQ,CAAC,QAAQ,CAAC;YACnC,CAAC,CAAC;gBACE,GAAG,EAAE,IAAI;gBACT,kBAAkB,EAAE,KAAK;aAC1B;YACH,CAAC,CAAC,SAAS,CAAC;QACd,WAAW,GAAG,YAAY,CAAC;YACzB,GAAG;YACH,MAAM;SACP,CAAC,CAAC;QAEH,WAAW;aACR,OAAO,EAAE;aACT,IAAI,CAAC,CAAC,MAAM,EAAE,EAAE;YACf,WAAW,GAAG,MAAM,CAAC;YAErB,MAAM,CAAC,EAAE,CAAC,OAAO,EAAE,CAAC,GAAG,EAAE,EAAE;gBACzB,OAAO,CAAC,IAAI,CAAC,oBAAoB,EAAE,GAAG,CAAC,CAAC;YAC1C,CAAC,CAAC,CAAC;YACH,OAAO,CAAC,MAAM,CAAC,CAAC;QAClB,CAAC,CAAC;aACD,KAAK,CAAC,KAAK,EAAE,CAAU,EAAE,EAAE;YAC1B,MAAM,CAAC,CAAC,YAAY,KAAK,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,IAAI,KAAK,CAAC,IAAI,CAAC,SAAS,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC;YAC9D,kCAAkC;YAClC,yCAAyC;QAC3C,CAAC,CAAC,CAAC;IACP,CAAC,CAAC,CAAC;AACL,CAAC,CAAC;AAEF,MAAM,KAAK,GAAG,WAAW,CACvB,KAAK,IAAI,EAAE;IACT,IAAI,CAAC;QACH,IAAI,WAAW,EAAE,CAAC;YAChB,MAAM,WAAW,CAAC,IAAI,EAAE,CAAC;QAC3B,CAAC;IACH,CAAC;IAAC,OAAO,GAAG,EAAE,CAAC;QACb,OAAO,CAAC,KAAK,CAAC,qBAAqB,EAAE,GAAG,CAAC,CAAC;IAC5C,CAAC;AACH,CAAC,EACD,IAAI,GAAG,EAAE,GAAG,CAAC,CACd,CAAC;AAEF,MAAM,CAAC,MAAM,UAAU,GAAG,GAAG,EAAE;IAC7B,aAAa,CAAC,KAAK,CAAC,CAAC;IAErB,OAAO,WAAW,EAAE,UAAU,EAAE,CAAC;AACnC,CAAC,CAAC"}
@@ -1,12 +0,0 @@
1
- import type { DriveInput } from "document-drive";
2
- interface Config {
3
- database: {
4
- url: string;
5
- };
6
- port: number;
7
- mcp: boolean;
8
- drive: DriveInput;
9
- }
10
- export declare const config: Config;
11
- export {};
12
- //# sourceMappingURL=config.d.ts.map
@@ -1 +0,0 @@
1
- {"version":3,"file":"config.d.ts","sourceRoot":"","sources":["../../src/config.ts"],"names":[],"mappings":"AAIA,OAAO,KAAK,EAAE,UAAU,EAAE,MAAM,gBAAgB,CAAC;AAGjD,UAAU,MAAM;IACd,QAAQ,EAAE;QACR,GAAG,EAAE,MAAM,CAAC;KACb,CAAC;IACF,IAAI,EAAE,MAAM,CAAC;IACb,GAAG,EAAE,OAAO,CAAC;IACb,KAAK,EAAE,UAAU,CAAC;CACnB;AACD,eAAO,MAAM,MAAM,EAAE,MA4BpB,CAAC"}
@@ -1,33 +0,0 @@
1
- import dotenv from "dotenv";
2
- dotenv.config();
3
- import { getConfig } from "@powerhousedao/config/node";
4
- const phConfig = getConfig();
5
- const { switchboard } = phConfig;
6
- export const config = {
7
- database: {
8
- // url: process.env.PH_SWITCHBOARD_DATABASE_URL ?? switchboard?.database?.url ?? "dev.db",
9
- url: process.env.PH_SWITCHBOARD_DATABASE_URL ??
10
- switchboard?.database?.url ??
11
- "dev.db",
12
- },
13
- port: process.env.PH_SWITCHBOARD_PORT &&
14
- !isNaN(Number(process.env.PH_SWITCHBOARD_PORT))
15
- ? Number(process.env.PH_SWITCHBOARD_PORT)
16
- : (switchboard?.port ?? 4001),
17
- mcp: true,
18
- drive: {
19
- id: "powerhouse",
20
- slug: "powerhouse",
21
- global: {
22
- name: "Powerhouse",
23
- icon: "https://ipfs.io/ipfs/QmcaTDBYn8X2psGaXe7iQ6qd8q6oqHLgxvMX9yXf7f9uP7",
24
- },
25
- local: {
26
- availableOffline: true,
27
- listeners: [],
28
- sharingType: "public",
29
- triggers: [],
30
- },
31
- },
32
- };
33
- //# sourceMappingURL=config.js.map
@@ -1 +0,0 @@
1
- {"version":3,"file":"config.js","sourceRoot":"","sources":["../../src/config.ts"],"names":[],"mappings":"AAAA,OAAO,MAAM,MAAM,QAAQ,CAAC;AAC5B,MAAM,CAAC,MAAM,EAAE,CAAC;AAEhB,OAAO,EAAE,SAAS,EAAE,MAAM,4BAA4B,CAAC;AAEvD,MAAM,QAAQ,GAAG,SAAS,EAAE,CAAC;AAC7B,MAAM,EAAE,WAAW,EAAE,GAAG,QAAQ,CAAC;AASjC,MAAM,CAAC,MAAM,MAAM,GAAW;IAC5B,QAAQ,EAAE;QACR,0FAA0F;QAC1F,GAAG,EACD,OAAO,CAAC,GAAG,CAAC,2BAA2B;YACvC,WAAW,EAAE,QAAQ,EAAE,GAAG;YAC1B,QAAQ;KACX;IACD,IAAI,EACF,OAAO,CAAC,GAAG,CAAC,mBAAmB;QAC/B,CAAC,KAAK,CAAC,MAAM,CAAC,OAAO,CAAC,GAAG,CAAC,mBAAmB,CAAC,CAAC;QAC7C,CAAC,CAAC,MAAM,CAAC,OAAO,CAAC,GAAG,CAAC,mBAAmB,CAAC;QACzC,CAAC,CAAC,CAAC,WAAW,EAAE,IAAI,IAAI,IAAI,CAAC;IACjC,GAAG,EAAE,IAAI;IACT,KAAK,EAAE;QACL,EAAE,EAAE,YAAY;QAChB,IAAI,EAAE,YAAY;QAClB,MAAM,EAAE;YACN,IAAI,EAAE,YAAY;YAClB,IAAI,EAAE,qEAAqE;SAC5E;QACD,KAAK,EAAE;YACL,gBAAgB,EAAE,IAAI;YACtB,SAAS,EAAE,EAAE;YACb,WAAW,EAAE,QAAQ;YACrB,QAAQ,EAAE,EAAE;SACb;KACF;CACF,CAAC"}
@@ -1,41 +0,0 @@
1
- import { type IConnectCrypto, type JsonWebKeyPairStorage, type JwkKeyPair } from "@renown/sdk";
2
- /**
3
- * Key storage that supports:
4
- * 1. PH_RENOWN_PRIVATE_KEY environment variable (JSON-encoded JwkKeyPair)
5
- * 2. Custom file path passed via options
6
- * 3. Falls back to file storage at .keypair.json in current working directory
7
- */
8
- export declare class SwitchboardKeyStorage implements JsonWebKeyPairStorage {
9
- #private;
10
- constructor(filePath?: string);
11
- loadKeyPair(): Promise<JwkKeyPair | undefined>;
12
- saveKeyPair(keyPair: JwkKeyPair): Promise<void>;
13
- }
14
- export interface ConnectCryptoOptions {
15
- /** Path to the keypair file. Defaults to .keypair.json in cwd */
16
- keypairPath?: string;
17
- /** If true, won't generate a new keypair if none exists */
18
- requireExisting?: boolean;
19
- }
20
- /**
21
- * Initialize ConnectCrypto for the switchboard.
22
- * This allows the switchboard to authenticate with remote services
23
- * using the same identity established during `ph login`.
24
- */
25
- export declare function initConnectCrypto(options?: ConnectCryptoOptions): Promise<IConnectCrypto | null>;
26
- /**
27
- * Get the current ConnectCrypto instance.
28
- * Returns null if not initialized.
29
- */
30
- export declare function getConnectCrypto(): IConnectCrypto | null;
31
- /**
32
- * Get the DID of the current ConnectCrypto instance.
33
- * Returns null if not initialized.
34
- */
35
- export declare function getConnectDid(): Promise<string | null>;
36
- /**
37
- * Get a bearer token for authenticating with remote services.
38
- * Returns null if ConnectCrypto is not initialized.
39
- */
40
- export declare function getBearerToken(driveUrl: string, address?: string, refresh?: boolean): Promise<string | null>;
41
- //# sourceMappingURL=connect-crypto.d.ts.map
@@ -1 +0,0 @@
1
- {"version":3,"file":"connect-crypto.d.ts","sourceRoot":"","sources":["../../src/connect-crypto.ts"],"names":[],"mappings":"AAAA,OAAO,EAEL,KAAK,cAAc,EACnB,KAAK,qBAAqB,EAC1B,KAAK,UAAU,EAChB,MAAM,aAAa,CAAC;AAUrB;;;;;GAKG;AACH,qBAAa,qBAAsB,YAAW,qBAAqB;;gBAGrD,QAAQ,CAAC,EAAE,MAAM;IAUvB,WAAW,IAAI,OAAO,CAAC,UAAU,GAAG,SAAS,CAAC;IAuB9C,WAAW,CAAC,OAAO,EAAE,UAAU,GAAG,OAAO,CAAC,IAAI,CAAC;CAgCtD;AAKD,MAAM,WAAW,oBAAoB;IACnC,iEAAiE;IACjE,WAAW,CAAC,EAAE,MAAM,CAAC;IACrB,2DAA2D;IAC3D,eAAe,CAAC,EAAE,OAAO,CAAC;CAC3B;AAED;;;;GAIG;AACH,wBAAsB,iBAAiB,CACrC,OAAO,GAAE,oBAAyB,GACjC,OAAO,CAAC,cAAc,GAAG,IAAI,CAAC,CA0BhC;AAED;;;GAGG;AACH,wBAAgB,gBAAgB,IAAI,cAAc,GAAG,IAAI,CAExD;AAED;;;GAGG;AACH,wBAAsB,aAAa,IAAI,OAAO,CAAC,MAAM,GAAG,IAAI,CAAC,CAK5D;AAED;;;GAGG;AACH,wBAAsB,cAAc,CAClC,QAAQ,EAAE,MAAM,EAChB,OAAO,CAAC,EAAE,MAAM,EAChB,OAAO,UAAQ,GACd,OAAO,CAAC,MAAM,GAAG,IAAI,CAAC,CAKxB"}
@@ -1,127 +0,0 @@
1
- import { ConnectCrypto, } from "@renown/sdk";
2
- import { existsSync, mkdirSync, readFileSync, writeFileSync } from "node:fs";
3
- import { dirname, join } from "node:path";
4
- import { childLogger } from "document-drive";
5
- const logger = childLogger(["switchboard", "connect-crypto"]);
6
- const ENV_KEY_NAME = "PH_RENOWN_PRIVATE_KEY";
7
- const DEFAULT_KEYPAIR_PATH = join(process.cwd(), ".keypair.json");
8
- /**
9
- * Key storage that supports:
10
- * 1. PH_RENOWN_PRIVATE_KEY environment variable (JSON-encoded JwkKeyPair)
11
- * 2. Custom file path passed via options
12
- * 3. Falls back to file storage at .keypair.json in current working directory
13
- */
14
- export class SwitchboardKeyStorage {
15
- #filePath;
16
- constructor(filePath) {
17
- this.#filePath = filePath || DEFAULT_KEYPAIR_PATH;
18
- // Ensure directory exists
19
- const dir = dirname(this.#filePath);
20
- if (!existsSync(dir)) {
21
- mkdirSync(dir, { recursive: true });
22
- }
23
- }
24
- async loadKeyPair() {
25
- // First check environment variable
26
- const envKey = process.env[ENV_KEY_NAME];
27
- if (envKey) {
28
- try {
29
- const keyPair = JSON.parse(envKey);
30
- // Validate it has the required structure
31
- if (keyPair.publicKey && keyPair.privateKey) {
32
- logger.debug("Loaded keypair from environment variable");
33
- return keyPair;
34
- }
35
- logger.warn(`${ENV_KEY_NAME} is set but doesn't contain valid publicKey and privateKey`);
36
- }
37
- catch (e) {
38
- logger.warn(`Failed to parse ${ENV_KEY_NAME} as JSON:`, e);
39
- }
40
- }
41
- // Fall back to file storage
42
- return this.#loadFromFile();
43
- }
44
- async saveKeyPair(keyPair) {
45
- // Don't save if using env var
46
- if (process.env[ENV_KEY_NAME]) {
47
- return;
48
- }
49
- // Save to file
50
- this.#saveToFile(keyPair);
51
- }
52
- #loadFromFile() {
53
- try {
54
- if (!existsSync(this.#filePath)) {
55
- return undefined;
56
- }
57
- const data = readFileSync(this.#filePath, "utf-8");
58
- const parsed = JSON.parse(data);
59
- const keyPair = parsed.keyPair;
60
- if (keyPair) {
61
- logger.debug(`Loaded keypair from ${this.#filePath}`);
62
- }
63
- return keyPair;
64
- }
65
- catch {
66
- return undefined;
67
- }
68
- }
69
- #saveToFile(keyPair) {
70
- const data = { keyPair };
71
- writeFileSync(this.#filePath, JSON.stringify(data, null, 2), "utf-8");
72
- logger.debug(`Saved keypair to ${this.#filePath}`);
73
- }
74
- }
75
- // Singleton instance of ConnectCrypto for the switchboard
76
- let connectCryptoInstance = null;
77
- /**
78
- * Initialize ConnectCrypto for the switchboard.
79
- * This allows the switchboard to authenticate with remote services
80
- * using the same identity established during `ph login`.
81
- */
82
- export async function initConnectCrypto(options = {}) {
83
- const { keypairPath, requireExisting = false } = options;
84
- const keyStorage = new SwitchboardKeyStorage(keypairPath);
85
- // Check if we have an existing keypair
86
- const existingKeyPair = await keyStorage.loadKeyPair();
87
- if (!existingKeyPair && requireExisting) {
88
- logger.warn("No existing keypair found and requireExisting is true. " +
89
- 'Run "ph login" to create one.');
90
- return null;
91
- }
92
- if (!existingKeyPair) {
93
- logger.info("No existing keypair found. A new one will be generated.");
94
- }
95
- connectCryptoInstance = new ConnectCrypto(keyStorage);
96
- const did = await connectCryptoInstance.did();
97
- logger.info(`Switchboard identity initialized: ${did}`);
98
- return connectCryptoInstance;
99
- }
100
- /**
101
- * Get the current ConnectCrypto instance.
102
- * Returns null if not initialized.
103
- */
104
- export function getConnectCrypto() {
105
- return connectCryptoInstance;
106
- }
107
- /**
108
- * Get the DID of the current ConnectCrypto instance.
109
- * Returns null if not initialized.
110
- */
111
- export async function getConnectDid() {
112
- if (!connectCryptoInstance) {
113
- return null;
114
- }
115
- return connectCryptoInstance.did();
116
- }
117
- /**
118
- * Get a bearer token for authenticating with remote services.
119
- * Returns null if ConnectCrypto is not initialized.
120
- */
121
- export async function getBearerToken(driveUrl, address, refresh = false) {
122
- if (!connectCryptoInstance) {
123
- return null;
124
- }
125
- return connectCryptoInstance.getBearerToken(driveUrl, address, refresh);
126
- }
127
- //# sourceMappingURL=connect-crypto.js.map
@@ -1 +0,0 @@
1
- {"version":3,"file":"connect-crypto.js","sourceRoot":"","sources":["../../src/connect-crypto.ts"],"names":[],"mappings":"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"}
@@ -1,2 +0,0 @@
1
- export declare function initFeatureFlags(): Promise<import("@openfeature/server-sdk").Client>;
2
- //# sourceMappingURL=feature-flags.d.ts.map
@@ -1 +0,0 @@
1
- {"version":3,"file":"feature-flags.d.ts","sourceRoot":"","sources":["../../src/feature-flags.ts"],"names":[],"mappings":"AAGA,wBAAsB,gBAAgB,sDAOrC"}
@@ -1,9 +0,0 @@
1
- import { EnvVarProvider } from "@openfeature/env-var-provider";
2
- import { OpenFeature } from "@openfeature/server-sdk";
3
- export async function initFeatureFlags() {
4
- // for now, we're only using env vars for feature flags
5
- const provider = new EnvVarProvider();
6
- await OpenFeature.setProviderAndWait(provider);
7
- return OpenFeature.getClient();
8
- }
9
- //# sourceMappingURL=feature-flags.js.map