@powerhousedao/switchboard 6.0.0-dev.14 → 6.0.0-dev.140

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 (48) hide show
  1. package/Auth.md +45 -27
  2. package/CHANGELOG.md +1139 -5
  3. package/README.md +13 -12
  4. package/dist/src/config.d.ts +1 -1
  5. package/dist/src/config.d.ts.map +1 -1
  6. package/dist/src/index.js +33 -5
  7. package/dist/src/index.js.map +1 -1
  8. package/dist/src/metrics.d.ts +7 -0
  9. package/dist/src/metrics.d.ts.map +1 -0
  10. package/dist/src/metrics.js +34 -0
  11. package/dist/src/metrics.js.map +1 -0
  12. package/dist/src/profiler.d.ts +6 -1
  13. package/dist/src/profiler.d.ts.map +1 -1
  14. package/dist/src/profiler.js +31 -5
  15. package/dist/src/profiler.js.map +1 -1
  16. package/dist/src/renown.d.ts +24 -0
  17. package/dist/src/renown.d.ts.map +1 -0
  18. package/dist/src/renown.js +45 -0
  19. package/dist/src/renown.js.map +1 -0
  20. package/dist/src/server.d.ts +0 -1
  21. package/dist/src/server.d.ts.map +1 -1
  22. package/dist/src/server.js +149 -162
  23. package/dist/src/server.js.map +1 -1
  24. package/dist/src/types.d.ts +27 -18
  25. package/dist/src/types.d.ts.map +1 -1
  26. package/dist/src/utils.d.ts +2 -3
  27. package/dist/src/utils.d.ts.map +1 -1
  28. package/dist/src/utils.js +3 -32
  29. package/dist/src/utils.js.map +1 -1
  30. package/dist/test/metrics.test.d.ts +2 -0
  31. package/dist/test/metrics.test.d.ts.map +1 -0
  32. package/dist/test/metrics.test.js +121 -0
  33. package/dist/test/metrics.test.js.map +1 -0
  34. package/dist/tsconfig.tsbuildinfo +1 -1
  35. package/dist/vitest.config.d.ts +3 -0
  36. package/dist/vitest.config.d.ts.map +1 -0
  37. package/dist/vitest.config.js +11 -0
  38. package/dist/vitest.config.js.map +1 -0
  39. package/package.json +34 -25
  40. package/test/metrics.test.ts +202 -0
  41. package/tsconfig.json +17 -4
  42. package/vitest.config.ts +11 -0
  43. package/Dockerfile +0 -86
  44. package/dist/src/connect-crypto.d.ts +0 -41
  45. package/dist/src/connect-crypto.d.ts.map +0 -1
  46. package/dist/src/connect-crypto.js +0 -127
  47. package/dist/src/connect-crypto.js.map +0 -1
  48. package/entrypoint.sh +0 -17
package/README.md CHANGED
@@ -50,6 +50,7 @@ docker compose -f packages/reactor/docker-compose.yml up -d
50
50
  ```
51
51
 
52
52
  This starts:
53
+
53
54
  - PostgreSQL on port `5433` (mapped from container port 5432)
54
55
  - Adminer (database UI) on port `8080`
55
56
 
@@ -94,22 +95,21 @@ pnpm add -g @powerhousedao/switchboard
94
95
 
95
96
  ## 🏃‍♂️ Quick Start
96
97
 
97
-
98
98
  ## ⚙️ Configuration
99
99
 
100
100
  ### Environment Variables
101
101
 
102
- | Variable | Description | Default |
103
- | ---------------------------- | ---------------------------------- | --------------------- |
104
- | `PORT` | Server port | `4001` |
105
- | `DATABASE_URL` | Database connection string | `./.ph/drive-storage` |
106
- | `PH_REACTOR_DATABASE_URL` | PostgreSQL URL (takes precedence) | - |
107
- | `REDIS_URL` | Redis connection URL | - |
108
- | `REDIS_TLS_URL` | Redis TLS connection URL | - |
109
- | `SENTRY_DSN` | Sentry DSN for error tracking | - |
110
- | `SENTRY_ENV` | Sentry environment | - |
111
- | `PYROSCOPE_SERVER_ADDRESS` | Pyroscope server address | - |
112
- | `FEATURE_REACTORV2_ENABLED` | Enable Reactor v2 subgraph feature | `false` |
102
+ | Variable | Description | Default |
103
+ | --------------------------- | ---------------------------------- | --------------------- |
104
+ | `PORT` | Server port | `4001` |
105
+ | `DATABASE_URL` | Database connection string | `./.ph/drive-storage` |
106
+ | `PH_REACTOR_DATABASE_URL` | PostgreSQL URL (takes precedence) | - |
107
+ | `REDIS_URL` | Redis connection URL | - |
108
+ | `REDIS_TLS_URL` | Redis TLS connection URL | - |
109
+ | `SENTRY_DSN` | Sentry DSN for error tracking | - |
110
+ | `SENTRY_ENV` | Sentry environment | - |
111
+ | `PYROSCOPE_SERVER_ADDRESS` | Pyroscope server address | - |
112
+ | `FEATURE_REACTORV2_ENABLED` | Enable Reactor v2 subgraph feature | `false` |
113
113
 
114
114
  ### Authentication Configuration
115
115
 
@@ -245,6 +245,7 @@ ph switchboard --db-path postgresql://user:pass@localhost:5432/db --migrate-stat
245
245
  #### Environment Variables for Migrations
246
246
 
247
247
  The migration commands check for a PostgreSQL URL in this order:
248
+
248
249
  1. `PH_REACTOR_DATABASE_URL`
249
250
  2. `DATABASE_URL`
250
251
  3. Config file (`powerhouse.config.json` -> `switchboard.database.url`)
@@ -1,4 +1,4 @@
1
- import type { DriveInput } from "document-drive";
1
+ import type { DriveInput } from "@powerhousedao/shared/document-drive";
2
2
  interface Config {
3
3
  database: {
4
4
  url: string;
@@ -1 +1 @@
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
+ {"version":3,"file":"config.d.ts","sourceRoot":"","sources":["../../src/config.ts"],"names":[],"mappings":"AAIA,OAAO,KAAK,EAAE,UAAU,EAAE,MAAM,sCAAsC,CAAC;AAGvE,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"}
package/dist/src/index.js CHANGED
@@ -1,7 +1,12 @@
1
1
  #!/usr/bin/env node
2
+ import * as Sentry from "@sentry/node";
3
+ import { childLogger } from "document-model";
2
4
  import { config } from "./config.js";
5
+ import { createMeterProviderFromEnv } from "./metrics.js";
6
+ import { initProfilerFromEnv } from "./profiler.js";
3
7
  import { startSwitchboard } from "./server.js";
4
- function ensureNodeVersion(minVersion = "22") {
8
+ const logger = childLogger(["switchboard"]);
9
+ function ensureNodeVersion(minVersion = "24") {
5
10
  const version = process.versions.node;
6
11
  if (!version) {
7
12
  return;
@@ -12,10 +17,33 @@ function ensureNodeVersion(minVersion = "22") {
12
17
  }
13
18
  }
14
19
  // Ensure minimum Node.js version
15
- ensureNodeVersion("22");
16
- process.on("SIGINT", () => {
20
+ ensureNodeVersion("24");
21
+ const meterProvider = createMeterProviderFromEnv({
22
+ OTEL_EXPORTER_OTLP_ENDPOINT: process.env.OTEL_EXPORTER_OTLP_ENDPOINT,
23
+ OTEL_METRIC_EXPORT_INTERVAL: process.env.OTEL_METRIC_EXPORT_INTERVAL,
24
+ OTEL_SERVICE_NAME: process.env.OTEL_SERVICE_NAME,
25
+ });
26
+ async function shutdown() {
17
27
  console.log("\nShutting down...");
28
+ // Flush final metrics before exit. Races against a 5s deadline so an
29
+ // unresponsive OTLP endpoint cannot exhaust terminationGracePeriodSeconds.
30
+ await Promise.race([
31
+ meterProvider?.shutdown().catch(() => undefined),
32
+ new Promise((resolve) => setTimeout(resolve, 5_000)),
33
+ ]);
18
34
  process.exit(0);
19
- });
20
- startSwitchboard(config).catch(console.error);
35
+ }
36
+ // SIGINT: Ctrl-C in development; SIGTERM: graceful shutdown in Docker/Kubernetes
37
+ process.on("SIGINT", shutdown);
38
+ process.on("SIGTERM", shutdown);
39
+ if (process.env.PYROSCOPE_SERVER_ADDRESS) {
40
+ try {
41
+ await initProfilerFromEnv(process.env);
42
+ }
43
+ catch (e) {
44
+ Sentry.captureException(e);
45
+ logger.error("Error starting profiler: @error", e);
46
+ }
47
+ }
48
+ startSwitchboard({ ...config, meterProvider }).catch(console.error);
21
49
  //# sourceMappingURL=index.js.map
@@ -1 +1 @@
1
- {"version":3,"file":"index.js","sourceRoot":"","sources":["../../src/index.ts"],"names":[],"mappings":";AACA,OAAO,EAAE,MAAM,EAAE,MAAM,aAAa,CAAC;AACrC,OAAO,EAAE,gBAAgB,EAAE,MAAM,aAAa,CAAC;AAE/C,SAAS,iBAAiB,CAAC,UAAU,GAAG,IAAI;IAC1C,MAAM,OAAO,GAAG,OAAO,CAAC,QAAQ,CAAC,IAAI,CAAC;IACtC,IAAI,CAAC,OAAO,EAAE,CAAC;QACb,OAAO;IACT,CAAC;IAED,IAAI,OAAO,GAAG,UAAU,EAAE,CAAC;QACzB,OAAO,CAAC,KAAK,CACX,gBAAgB,UAAU,4CAA4C,OAAO,EAAE,CAChF,CAAC;QACF,OAAO,CAAC,IAAI,CAAC,CAAC,CAAC,CAAC;IAClB,CAAC;AACH,CAAC;AACD,iCAAiC;AACjC,iBAAiB,CAAC,IAAI,CAAC,CAAC;AAExB,OAAO,CAAC,EAAE,CAAC,QAAQ,EAAE,GAAG,EAAE;IACxB,OAAO,CAAC,GAAG,CAAC,oBAAoB,CAAC,CAAC;IAClC,OAAO,CAAC,IAAI,CAAC,CAAC,CAAC,CAAC;AAClB,CAAC,CAAC,CAAC;AAEH,gBAAgB,CAAC,MAAM,CAAC,CAAC,KAAK,CAAC,OAAO,CAAC,KAAK,CAAC,CAAC"}
1
+ {"version":3,"file":"index.js","sourceRoot":"","sources":["../../src/index.ts"],"names":[],"mappings":";AACA,OAAO,KAAK,MAAM,MAAM,cAAc,CAAC;AACvC,OAAO,EAAE,WAAW,EAAE,MAAM,gBAAgB,CAAC;AAC7C,OAAO,EAAE,MAAM,EAAE,MAAM,aAAa,CAAC;AACrC,OAAO,EAAE,0BAA0B,EAAE,MAAM,cAAc,CAAC;AAC1D,OAAO,EAAE,mBAAmB,EAAE,MAAM,eAAe,CAAC;AACpD,OAAO,EAAE,gBAAgB,EAAE,MAAM,aAAa,CAAC;AAE/C,MAAM,MAAM,GAAG,WAAW,CAAC,CAAC,aAAa,CAAC,CAAC,CAAC;AAE5C,SAAS,iBAAiB,CAAC,UAAU,GAAG,IAAI;IAC1C,MAAM,OAAO,GAAG,OAAO,CAAC,QAAQ,CAAC,IAAI,CAAC;IACtC,IAAI,CAAC,OAAO,EAAE,CAAC;QACb,OAAO;IACT,CAAC;IAED,IAAI,OAAO,GAAG,UAAU,EAAE,CAAC;QACzB,OAAO,CAAC,KAAK,CACX,gBAAgB,UAAU,4CAA4C,OAAO,EAAE,CAChF,CAAC;QACF,OAAO,CAAC,IAAI,CAAC,CAAC,CAAC,CAAC;IAClB,CAAC;AACH,CAAC;AACD,iCAAiC;AACjC,iBAAiB,CAAC,IAAI,CAAC,CAAC;AAExB,MAAM,aAAa,GAAG,0BAA0B,CAAC;IAC/C,2BAA2B,EAAE,OAAO,CAAC,GAAG,CAAC,2BAA2B;IACpE,2BAA2B,EAAE,OAAO,CAAC,GAAG,CAAC,2BAA2B;IACpE,iBAAiB,EAAE,OAAO,CAAC,GAAG,CAAC,iBAAiB;CACjD,CAAC,CAAC;AAEH,KAAK,UAAU,QAAQ;IACrB,OAAO,CAAC,GAAG,CAAC,oBAAoB,CAAC,CAAC;IAClC,qEAAqE;IACrE,2EAA2E;IAC3E,MAAM,OAAO,CAAC,IAAI,CAAC;QACjB,aAAa,EAAE,QAAQ,EAAE,CAAC,KAAK,CAAC,GAAG,EAAE,CAAC,SAAS,CAAC;QAChD,IAAI,OAAO,CAAO,CAAC,OAAO,EAAE,EAAE,CAAC,UAAU,CAAC,OAAO,EAAE,KAAK,CAAC,CAAC;KAC3D,CAAC,CAAC;IACH,OAAO,CAAC,IAAI,CAAC,CAAC,CAAC,CAAC;AAClB,CAAC;AAED,iFAAiF;AACjF,OAAO,CAAC,EAAE,CAAC,QAAQ,EAAE,QAAQ,CAAC,CAAC;AAC/B,OAAO,CAAC,EAAE,CAAC,SAAS,EAAE,QAAQ,CAAC,CAAC;AAEhC,IAAI,OAAO,CAAC,GAAG,CAAC,wBAAwB,EAAE,CAAC;IACzC,IAAI,CAAC;QACH,MAAM,mBAAmB,CAAC,OAAO,CAAC,GAAG,CAAC,CAAC;IACzC,CAAC;IAAC,OAAO,CAAC,EAAE,CAAC;QACX,MAAM,CAAC,gBAAgB,CAAC,CAAC,CAAC,CAAC;QAC3B,MAAM,CAAC,KAAK,CAAC,iCAAiC,EAAE,CAAC,CAAC,CAAC;IACrD,CAAC;AACH,CAAC;AAED,gBAAgB,CAAC,EAAE,GAAG,MAAM,EAAE,aAAa,EAAE,CAAC,CAAC,KAAK,CAAC,OAAO,CAAC,KAAK,CAAC,CAAC"}
@@ -0,0 +1,7 @@
1
+ import { MeterProvider } from "@opentelemetry/sdk-metrics";
2
+ export declare function createMeterProviderFromEnv(env: {
3
+ OTEL_EXPORTER_OTLP_ENDPOINT?: string;
4
+ OTEL_METRIC_EXPORT_INTERVAL?: string;
5
+ OTEL_SERVICE_NAME?: string;
6
+ }): MeterProvider | undefined;
7
+ //# sourceMappingURL=metrics.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"metrics.d.ts","sourceRoot":"","sources":["../../src/metrics.ts"],"names":[],"mappings":"AAEA,OAAO,EACL,aAAa,EAEd,MAAM,4BAA4B,CAAC;AAKpC,wBAAgB,0BAA0B,CAAC,GAAG,EAAE;IAC9C,2BAA2B,CAAC,EAAE,MAAM,CAAC;IACrC,2BAA2B,CAAC,EAAE,MAAM,CAAC;IACrC,iBAAiB,CAAC,EAAE,MAAM,CAAC;CAC5B,GAAG,aAAa,GAAG,SAAS,CA8B5B"}
@@ -0,0 +1,34 @@
1
+ import { OTLPMetricExporter } from "@opentelemetry/exporter-metrics-otlp-http";
2
+ import { Resource } from "@opentelemetry/resources";
3
+ import { MeterProvider, PeriodicExportingMetricReader, } from "@opentelemetry/sdk-metrics";
4
+ import { childLogger } from "document-model";
5
+ const logger = childLogger(["switchboard", "metrics"]);
6
+ export function createMeterProviderFromEnv(env) {
7
+ const endpoint = env.OTEL_EXPORTER_OTLP_ENDPOINT;
8
+ if (!endpoint)
9
+ return undefined;
10
+ const parsed = parseInt(env.OTEL_METRIC_EXPORT_INTERVAL ?? "", 10);
11
+ const exportIntervalMillis = Number.isFinite(parsed) && parsed > 0 ? parsed : 5_000;
12
+ const base = endpoint.replace(/\/$/, "");
13
+ const exporterUrl = base.endsWith("/v1/metrics")
14
+ ? base
15
+ : `${base}/v1/metrics`;
16
+ logger.info(`Initializing OpenTelemetry metrics exporter at: ${endpoint}`);
17
+ const meterProvider = new MeterProvider({
18
+ resource: new Resource({
19
+ "service.name": env.OTEL_SERVICE_NAME ?? "switchboard",
20
+ }),
21
+ readers: [
22
+ new PeriodicExportingMetricReader({
23
+ exporter: new OTLPMetricExporter({
24
+ url: exporterUrl,
25
+ }),
26
+ exportIntervalMillis,
27
+ exportTimeoutMillis: Math.max(exportIntervalMillis - 250, 1),
28
+ }),
29
+ ],
30
+ });
31
+ logger.info(`Metrics export enabled (interval: ${exportIntervalMillis}ms)`);
32
+ return meterProvider;
33
+ }
34
+ //# sourceMappingURL=metrics.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"metrics.js","sourceRoot":"","sources":["../../src/metrics.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,kBAAkB,EAAE,MAAM,2CAA2C,CAAC;AAC/E,OAAO,EAAE,QAAQ,EAAE,MAAM,0BAA0B,CAAC;AACpD,OAAO,EACL,aAAa,EACb,6BAA6B,GAC9B,MAAM,4BAA4B,CAAC;AACpC,OAAO,EAAE,WAAW,EAAE,MAAM,gBAAgB,CAAC;AAE7C,MAAM,MAAM,GAAG,WAAW,CAAC,CAAC,aAAa,EAAE,SAAS,CAAC,CAAC,CAAC;AAEvD,MAAM,UAAU,0BAA0B,CAAC,GAI1C;IACC,MAAM,QAAQ,GAAG,GAAG,CAAC,2BAA2B,CAAC;IACjD,IAAI,CAAC,QAAQ;QAAE,OAAO,SAAS,CAAC;IAEhC,MAAM,MAAM,GAAG,QAAQ,CAAC,GAAG,CAAC,2BAA2B,IAAI,EAAE,EAAE,EAAE,CAAC,CAAC;IACnE,MAAM,oBAAoB,GACxB,MAAM,CAAC,QAAQ,CAAC,MAAM,CAAC,IAAI,MAAM,GAAG,CAAC,CAAC,CAAC,CAAC,MAAM,CAAC,CAAC,CAAC,KAAK,CAAC;IAEzD,MAAM,IAAI,GAAG,QAAQ,CAAC,OAAO,CAAC,KAAK,EAAE,EAAE,CAAC,CAAC;IACzC,MAAM,WAAW,GAAG,IAAI,CAAC,QAAQ,CAAC,aAAa,CAAC;QAC9C,CAAC,CAAC,IAAI;QACN,CAAC,CAAC,GAAG,IAAI,aAAa,CAAC;IAEzB,MAAM,CAAC,IAAI,CAAC,mDAAmD,QAAQ,EAAE,CAAC,CAAC;IAC3E,MAAM,aAAa,GAAG,IAAI,aAAa,CAAC;QACtC,QAAQ,EAAE,IAAI,QAAQ,CAAC;YACrB,cAAc,EAAE,GAAG,CAAC,iBAAiB,IAAI,aAAa;SACvD,CAAC;QACF,OAAO,EAAE;YACP,IAAI,6BAA6B,CAAC;gBAChC,QAAQ,EAAE,IAAI,kBAAkB,CAAC;oBAC/B,GAAG,EAAE,WAAW;iBACjB,CAAC;gBACF,oBAAoB;gBACpB,mBAAmB,EAAE,IAAI,CAAC,GAAG,CAAC,oBAAoB,GAAG,GAAG,EAAE,CAAC,CAAC;aAC7D,CAAC;SACH;KACF,CAAC,CAAC;IACH,MAAM,CAAC,IAAI,CAAC,qCAAqC,oBAAoB,KAAK,CAAC,CAAC;IAC5E,OAAO,aAAa,CAAC;AACvB,CAAC"}
@@ -1,4 +1,9 @@
1
1
  import type { PyroscopeConfig } from "@pyroscope/nodejs";
2
2
  export declare function initProfilerFromEnv(env: typeof process.env): Promise<void>;
3
- export declare function initProfiler(options?: PyroscopeConfig): Promise<void>;
3
+ interface ProfilerFlags {
4
+ wallEnabled?: boolean;
5
+ heapEnabled?: boolean;
6
+ }
7
+ export declare function initProfiler(options?: PyroscopeConfig, flags?: ProfilerFlags): Promise<void>;
8
+ export {};
4
9
  //# sourceMappingURL=profiler.d.ts.map
@@ -1 +1 @@
1
- {"version":3,"file":"profiler.d.ts","sourceRoot":"","sources":["../../src/profiler.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,eAAe,EAAE,MAAM,mBAAmB,CAAC;AAEzD,wBAAsB,mBAAmB,CAAC,GAAG,EAAE,OAAO,OAAO,CAAC,GAAG,iBAehE;AAED,wBAAsB,YAAY,CAAC,OAAO,CAAC,EAAE,eAAe,iBAK3D"}
1
+ {"version":3,"file":"profiler.d.ts","sourceRoot":"","sources":["../../src/profiler.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,eAAe,EAAE,MAAM,mBAAmB,CAAC;AAEzD,wBAAsB,mBAAmB,CAAC,GAAG,EAAE,OAAO,OAAO,CAAC,GAAG,iBAgChE;AAED,UAAU,aAAa;IACrB,WAAW,CAAC,EAAE,OAAO,CAAC;IACtB,WAAW,CAAC,EAAE,OAAO,CAAC;CACvB;AAED,wBAAsB,YAAY,CAChC,OAAO,CAAC,EAAE,eAAe,EACzB,KAAK,GAAE,aAAyD,iBAqBjE"}
@@ -1,17 +1,43 @@
1
1
  export async function initProfilerFromEnv(env) {
2
- const { PYROSCOPE_SERVER_ADDRESS: serverAddress, PYROSCOPE_APPLICATION_NAME: appName, PYROSCOPE_USER: basicAuthUser, PYROSCOPE_PASSWORD: basicAuthPassword, } = env;
2
+ const { PYROSCOPE_SERVER_ADDRESS: serverAddress, PYROSCOPE_APPLICATION_NAME: appName, PYROSCOPE_USER: basicAuthUser, PYROSCOPE_PASSWORD: basicAuthPassword, PYROSCOPE_WALL_ENABLED: wallEnabled, PYROSCOPE_HEAP_ENABLED: heapEnabled, } = env;
3
3
  const options = {
4
4
  serverAddress,
5
5
  appName,
6
6
  basicAuthUser,
7
7
  basicAuthPassword,
8
+ // Wall profiling captures wall-clock time (includes async I/O waits)
9
+ // This shows GraphQL resolvers even when waiting for database
10
+ wall: {
11
+ samplingDurationMs: 10000, // 10 second sampling windows
12
+ samplingIntervalMicros: 10000, // 10ms sampling interval (100 samples/sec)
13
+ collectCpuTime: true, // Also collect CPU time alongside wall time
14
+ },
15
+ // Heap profiling for memory allocation tracking
16
+ heap: {
17
+ samplingIntervalBytes: 512 * 1024, // Sample every 512KB allocated
18
+ stackDepth: 64, // Capture deeper stacks for better context
19
+ },
8
20
  };
9
- return initProfiler(options);
21
+ return initProfiler(options, {
22
+ wallEnabled: wallEnabled !== "false",
23
+ heapEnabled: heapEnabled === "true",
24
+ });
10
25
  }
11
- export async function initProfiler(options) {
26
+ export async function initProfiler(options, flags = { wallEnabled: true, heapEnabled: false }) {
12
27
  console.log("Initializing Pyroscope profiler at:", options?.serverAddress);
13
- const Pyroscope = await import("@pyroscope/nodejs");
28
+ console.log(" Wall profiling:", flags.wallEnabled ? "enabled" : "disabled");
29
+ console.log(" Heap profiling:", flags.heapEnabled ? "enabled" : "disabled");
30
+ const { default: Pyroscope } = await import("@pyroscope/nodejs");
14
31
  Pyroscope.init(options);
15
- Pyroscope.start();
32
+ // Start wall profiling (captures async I/O time - shows resolvers)
33
+ if (flags.wallEnabled) {
34
+ Pyroscope.startWallProfiling();
35
+ }
36
+ // Start CPU profiling (captures CPU-bound work)
37
+ Pyroscope.startCpuProfiling();
38
+ // Optionally start heap profiling (memory allocations)
39
+ if (flags.heapEnabled) {
40
+ Pyroscope.startHeapProfiling();
41
+ }
16
42
  }
17
43
  //# sourceMappingURL=profiler.js.map
@@ -1 +1 @@
1
- {"version":3,"file":"profiler.js","sourceRoot":"","sources":["../../src/profiler.ts"],"names":[],"mappings":"AAEA,MAAM,CAAC,KAAK,UAAU,mBAAmB,CAAC,GAAuB;IAC/D,MAAM,EACJ,wBAAwB,EAAE,aAAa,EACvC,0BAA0B,EAAE,OAAO,EACnC,cAAc,EAAE,aAAa,EAC7B,kBAAkB,EAAE,iBAAiB,GACtC,GAAG,GAAG,CAAC;IAER,MAAM,OAAO,GAAoB;QAC/B,aAAa;QACb,OAAO;QACP,aAAa;QACb,iBAAiB;KAClB,CAAC;IACF,OAAO,YAAY,CAAC,OAAO,CAAC,CAAC;AAC/B,CAAC;AAED,MAAM,CAAC,KAAK,UAAU,YAAY,CAAC,OAAyB;IAC1D,OAAO,CAAC,GAAG,CAAC,qCAAqC,EAAE,OAAO,EAAE,aAAa,CAAC,CAAC;IAC3E,MAAM,SAAS,GAAG,MAAM,MAAM,CAAC,mBAAmB,CAAC,CAAC;IACpD,SAAS,CAAC,IAAI,CAAC,OAAO,CAAC,CAAC;IACxB,SAAS,CAAC,KAAK,EAAE,CAAC;AACpB,CAAC"}
1
+ {"version":3,"file":"profiler.js","sourceRoot":"","sources":["../../src/profiler.ts"],"names":[],"mappings":"AAEA,MAAM,CAAC,KAAK,UAAU,mBAAmB,CAAC,GAAuB;IAC/D,MAAM,EACJ,wBAAwB,EAAE,aAAa,EACvC,0BAA0B,EAAE,OAAO,EACnC,cAAc,EAAE,aAAa,EAC7B,kBAAkB,EAAE,iBAAiB,EACrC,sBAAsB,EAAE,WAAW,EACnC,sBAAsB,EAAE,WAAW,GACpC,GAAG,GAAG,CAAC;IAER,MAAM,OAAO,GAAoB;QAC/B,aAAa;QACb,OAAO;QACP,aAAa;QACb,iBAAiB;QACjB,qEAAqE;QACrE,8DAA8D;QAC9D,IAAI,EAAE;YACJ,kBAAkB,EAAE,KAAK,EAAE,6BAA6B;YACxD,sBAAsB,EAAE,KAAK,EAAE,2CAA2C;YAC1E,cAAc,EAAE,IAAI,EAAE,4CAA4C;SACnE;QACD,gDAAgD;QAChD,IAAI,EAAE;YACJ,qBAAqB,EAAE,GAAG,GAAG,IAAI,EAAE,+BAA+B;YAClE,UAAU,EAAE,EAAE,EAAE,2CAA2C;SAC5D;KACF,CAAC;IACF,OAAO,YAAY,CAAC,OAAO,EAAE;QAC3B,WAAW,EAAE,WAAW,KAAK,OAAO;QACpC,WAAW,EAAE,WAAW,KAAK,MAAM;KACpC,CAAC,CAAC;AACL,CAAC;AAOD,MAAM,CAAC,KAAK,UAAU,YAAY,CAChC,OAAyB,EACzB,QAAuB,EAAE,WAAW,EAAE,IAAI,EAAE,WAAW,EAAE,KAAK,EAAE;IAEhE,OAAO,CAAC,GAAG,CAAC,qCAAqC,EAAE,OAAO,EAAE,aAAa,CAAC,CAAC;IAC3E,OAAO,CAAC,GAAG,CAAC,mBAAmB,EAAE,KAAK,CAAC,WAAW,CAAC,CAAC,CAAC,SAAS,CAAC,CAAC,CAAC,UAAU,CAAC,CAAC;IAC7E,OAAO,CAAC,GAAG,CAAC,mBAAmB,EAAE,KAAK,CAAC,WAAW,CAAC,CAAC,CAAC,SAAS,CAAC,CAAC,CAAC,UAAU,CAAC,CAAC;IAE7E,MAAM,EAAE,OAAO,EAAE,SAAS,EAAE,GAAG,MAAM,MAAM,CAAC,mBAAmB,CAAC,CAAC;IACjE,SAAS,CAAC,IAAI,CAAC,OAAO,CAAC,CAAC;IAExB,mEAAmE;IACnE,IAAI,KAAK,CAAC,WAAW,EAAE,CAAC;QACtB,SAAS,CAAC,kBAAkB,EAAE,CAAC;IACjC,CAAC;IAED,gDAAgD;IAChD,SAAS,CAAC,iBAAiB,EAAE,CAAC;IAE9B,uDAAuD;IACvD,IAAI,KAAK,CAAC,WAAW,EAAE,CAAC;QACtB,SAAS,CAAC,kBAAkB,EAAE,CAAC;IACjC,CAAC;AACH,CAAC"}
@@ -0,0 +1,24 @@
1
+ import type { SignerConfig } from "@powerhousedao/reactor";
2
+ import { type IRenown } from "@renown/sdk/node";
3
+ export interface RenownOptions {
4
+ /** Path to the keypair file. Defaults to .ph/.keypair.json in cwd */
5
+ keypairPath?: string;
6
+ /** If true, won't generate a new keypair if none exists */
7
+ requireExisting?: boolean;
8
+ /** Base url of the Renown instance to use */
9
+ baseUrl?: string;
10
+ }
11
+ /**
12
+ * Initialize Renown for the Switchboard instance.
13
+ * This allows Switchboard to authenticate with remote services
14
+ * using the same identity established during `ph login`.
15
+ */
16
+ export declare function initRenown(options?: RenownOptions): Promise<IRenown | null>;
17
+ /**
18
+ * Get the signer config for the given renown instance.
19
+ *
20
+ * @param renown - The renown instance
21
+ * @param requireSignature - If true, unsigned actions are rejected
22
+ */
23
+ export declare function getRenownSignerConfig(renown: IRenown, requireSignature?: boolean): SignerConfig;
24
+ //# sourceMappingURL=renown.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"renown.d.ts","sourceRoot":"","sources":["../../src/renown.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,YAAY,EAAE,MAAM,wBAAwB,CAAC;AAC3D,OAAO,EAML,KAAK,OAAO,EACb,MAAM,kBAAkB,CAAC;AAK1B,MAAM,WAAW,aAAa;IAC5B,qEAAqE;IACrE,WAAW,CAAC,EAAE,MAAM,CAAC;IACrB,2DAA2D;IAC3D,eAAe,CAAC,EAAE,OAAO,CAAC;IAC1B,6CAA6C;IAC7C,OAAO,CAAC,EAAE,MAAM,CAAC;CAClB;AAED;;;;GAIG;AACH,wBAAsB,UAAU,CAC9B,OAAO,GAAE,aAAkB,GAC1B,OAAO,CAAC,OAAO,GAAG,IAAI,CAAC,CAqCzB;AAED;;;;;GAKG;AACH,wBAAgB,qBAAqB,CACnC,MAAM,EAAE,OAAO,EACf,gBAAgB,CAAC,EAAE,OAAO,GACzB,YAAY,CAKd"}
@@ -0,0 +1,45 @@
1
+ import { createSignatureVerifier, DEFAULT_RENOWN_URL, NodeKeyStorage, RenownBuilder, RenownCryptoBuilder, } from "@renown/sdk/node";
2
+ import { childLogger } from "document-model";
3
+ const logger = childLogger(["switchboard", "renown"]);
4
+ /**
5
+ * Initialize Renown for the Switchboard instance.
6
+ * This allows Switchboard to authenticate with remote services
7
+ * using the same identity established during `ph login`.
8
+ */
9
+ export async function initRenown(options = {}) {
10
+ const { keypairPath, requireExisting = false, baseUrl = DEFAULT_RENOWN_URL, } = options;
11
+ const keyStorage = new NodeKeyStorage(keypairPath, {
12
+ logger,
13
+ });
14
+ // Check if we have an existing keypair
15
+ const existingKeyPair = await keyStorage.loadKeyPair();
16
+ if (!existingKeyPair && requireExisting) {
17
+ throw new Error("No existing keypair found and requireExisting is true. " +
18
+ 'Run "ph login" to create one.');
19
+ }
20
+ if (!existingKeyPair) {
21
+ logger.info("No existing keypair found. A new one will be generated.");
22
+ }
23
+ const renownCrypto = await new RenownCryptoBuilder()
24
+ .withKeyPairStorage(keyStorage)
25
+ .build();
26
+ const renown = await new RenownBuilder("switchboard", {})
27
+ .withCrypto(renownCrypto)
28
+ .withBaseUrl(baseUrl)
29
+ .build();
30
+ logger.info("Switchboard identity initialized: @did", renownCrypto.did);
31
+ return renown;
32
+ }
33
+ /**
34
+ * Get the signer config for the given renown instance.
35
+ *
36
+ * @param renown - The renown instance
37
+ * @param requireSignature - If true, unsigned actions are rejected
38
+ */
39
+ export function getRenownSignerConfig(renown, requireSignature) {
40
+ return {
41
+ signer: renown.signer,
42
+ verifier: createSignatureVerifier(requireSignature),
43
+ };
44
+ }
45
+ //# sourceMappingURL=renown.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"renown.js","sourceRoot":"","sources":["../../src/renown.ts"],"names":[],"mappings":"AACA,OAAO,EACL,uBAAuB,EACvB,kBAAkB,EAClB,cAAc,EACd,aAAa,EACb,mBAAmB,GAEpB,MAAM,kBAAkB,CAAC;AAC1B,OAAO,EAAE,WAAW,EAAE,MAAM,gBAAgB,CAAC;AAE7C,MAAM,MAAM,GAAG,WAAW,CAAC,CAAC,aAAa,EAAE,QAAQ,CAAC,CAAC,CAAC;AAWtD;;;;GAIG;AACH,MAAM,CAAC,KAAK,UAAU,UAAU,CAC9B,UAAyB,EAAE;IAE3B,MAAM,EACJ,WAAW,EACX,eAAe,GAAG,KAAK,EACvB,OAAO,GAAG,kBAAkB,GAC7B,GAAG,OAAO,CAAC;IAEZ,MAAM,UAAU,GAAG,IAAI,cAAc,CAAC,WAAW,EAAE;QACjD,MAAM;KACP,CAAC,CAAC;IAEH,uCAAuC;IACvC,MAAM,eAAe,GAAG,MAAM,UAAU,CAAC,WAAW,EAAE,CAAC;IAEvD,IAAI,CAAC,eAAe,IAAI,eAAe,EAAE,CAAC;QACxC,MAAM,IAAI,KAAK,CACb,yDAAyD;YACvD,+BAA+B,CAClC,CAAC;IACJ,CAAC;IAED,IAAI,CAAC,eAAe,EAAE,CAAC;QACrB,MAAM,CAAC,IAAI,CAAC,yDAAyD,CAAC,CAAC;IACzE,CAAC;IAED,MAAM,YAAY,GAAG,MAAM,IAAI,mBAAmB,EAAE;SACjD,kBAAkB,CAAC,UAAU,CAAC;SAC9B,KAAK,EAAE,CAAC;IAEX,MAAM,MAAM,GAAG,MAAM,IAAI,aAAa,CAAC,aAAa,EAAE,EAAE,CAAC;SACtD,UAAU,CAAC,YAAY,CAAC;SACxB,WAAW,CAAC,OAAO,CAAC;SACpB,KAAK,EAAE,CAAC;IAEX,MAAM,CAAC,IAAI,CAAC,wCAAwC,EAAE,YAAY,CAAC,GAAG,CAAC,CAAC;IAExE,OAAO,MAAM,CAAC;AAChB,CAAC;AAED;;;;;GAKG;AACH,MAAM,UAAU,qBAAqB,CACnC,MAAe,EACf,gBAA0B;IAE1B,OAAO;QACL,MAAM,EAAE,MAAM,CAAC,MAAM;QACrB,QAAQ,EAAE,uBAAuB,CAAC,gBAAgB,CAAC;KACpD,CAAC;AACJ,CAAC"}
@@ -1,6 +1,5 @@
1
1
  #!/usr/bin/env node
2
2
  import type { StartServerOptions, SwitchboardReactor } from "./types.js";
3
3
  export declare const startSwitchboard: (options?: StartServerOptions) => Promise<SwitchboardReactor>;
4
- export { getBearerToken, getConnectCrypto, getConnectDid, } from "./connect-crypto.js";
5
4
  export * from "./types.js";
6
5
  //# sourceMappingURL=server.d.ts.map
@@ -1 +1 @@
1
- {"version":3,"file":"server.d.ts","sourceRoot":"","sources":["../../src/server.ts"],"names":[],"mappings":";AA6CA,OAAO,KAAK,EAAE,kBAAkB,EAAE,kBAAkB,EAAE,MAAM,YAAY,CAAC;AAkTzE,eAAO,MAAM,gBAAgB,GAC3B,UAAS,kBAAuB,KAC/B,OAAO,CAAC,kBAAkB,CAiE5B,CAAC;AAEF,OAAO,EACL,cAAc,EACd,gBAAgB,EAChB,aAAa,GACd,MAAM,qBAAqB,CAAC;AAC7B,cAAc,YAAY,CAAC"}
1
+ {"version":3,"file":"server.d.ts","sourceRoot":"","sources":["../../src/server.ts"],"names":[],"mappings":";AAgDA,OAAO,KAAK,EAAE,kBAAkB,EAAE,kBAAkB,EAAE,MAAM,YAAY,CAAC;AA0SzE,eAAO,MAAM,gBAAgB,GAC3B,UAAS,kBAAuB,KAC/B,OAAO,CAAC,kBAAkB,CAwD5B,CAAC;AAEF,cAAc,YAAY,CAAC"}