@powerhousedao/switchboard 6.0.2-staging.2 → 6.0.2-staging.3

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 (85) hide show
  1. package/Auth.md +45 -27
  2. package/CHANGELOG.md +1416 -104
  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-BMtyzhoR.mjs +291 -0
  14. package/dist/server-BMtyzhoR.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 +33 -27
  24. package/tsconfig.json +6 -3
  25. package/tsdown.config.ts +16 -0
  26. package/vitest.config.ts +2 -6
  27. package/Dockerfile +0 -86
  28. package/dist/src/clients/redis.d.ts +0 -5
  29. package/dist/src/clients/redis.d.ts.map +0 -1
  30. package/dist/src/clients/redis.js +0 -48
  31. package/dist/src/clients/redis.js.map +0 -1
  32. package/dist/src/config.d.ts +0 -12
  33. package/dist/src/config.d.ts.map +0 -1
  34. package/dist/src/config.js +0 -33
  35. package/dist/src/config.js.map +0 -1
  36. package/dist/src/feature-flags.d.ts +0 -2
  37. package/dist/src/feature-flags.d.ts.map +0 -1
  38. package/dist/src/feature-flags.js +0 -9
  39. package/dist/src/feature-flags.js.map +0 -1
  40. package/dist/src/index.d.ts +0 -3
  41. package/dist/src/index.d.ts.map +0 -1
  42. package/dist/src/index.js +0 -49
  43. package/dist/src/index.js.map +0 -1
  44. package/dist/src/install-packages.d.ts +0 -2
  45. package/dist/src/install-packages.d.ts.map +0 -1
  46. package/dist/src/install-packages.js +0 -36
  47. package/dist/src/install-packages.js.map +0 -1
  48. package/dist/src/metrics.d.ts +0 -7
  49. package/dist/src/metrics.d.ts.map +0 -1
  50. package/dist/src/metrics.js +0 -34
  51. package/dist/src/metrics.js.map +0 -1
  52. package/dist/src/migrate.d.ts +0 -3
  53. package/dist/src/migrate.d.ts.map +0 -1
  54. package/dist/src/migrate.js +0 -65
  55. package/dist/src/migrate.js.map +0 -1
  56. package/dist/src/profiler.d.ts +0 -9
  57. package/dist/src/profiler.d.ts.map +0 -1
  58. package/dist/src/profiler.js +0 -43
  59. package/dist/src/profiler.js.map +0 -1
  60. package/dist/src/renown.d.ts +0 -24
  61. package/dist/src/renown.d.ts.map +0 -1
  62. package/dist/src/renown.js +0 -45
  63. package/dist/src/renown.js.map +0 -1
  64. package/dist/src/server.d.ts +0 -5
  65. package/dist/src/server.d.ts.map +0 -1
  66. package/dist/src/server.js +0 -282
  67. package/dist/src/server.js.map +0 -1
  68. package/dist/src/types.d.ts +0 -66
  69. package/dist/src/types.d.ts.map +0 -1
  70. package/dist/src/types.js +0 -2
  71. package/dist/src/types.js.map +0 -1
  72. package/dist/src/utils.d.ts +0 -5
  73. package/dist/src/utils.d.ts.map +0 -1
  74. package/dist/src/utils.js +0 -62
  75. package/dist/src/utils.js.map +0 -1
  76. package/dist/test/metrics.test.d.ts +0 -2
  77. package/dist/test/metrics.test.d.ts.map +0 -1
  78. package/dist/test/metrics.test.js +0 -121
  79. package/dist/test/metrics.test.js.map +0 -1
  80. package/dist/tsconfig.tsbuildinfo +0 -1
  81. package/dist/vitest.config.d.ts +0 -3
  82. package/dist/vitest.config.d.ts.map +0 -1
  83. package/dist/vitest.config.js +0 -15
  84. package/dist/vitest.config.js.map +0 -1
  85. package/entrypoint.sh +0 -17
@@ -0,0 +1 @@
1
+ {"version":3,"file":"server-BMtyzhoR.mjs","names":["vetraDocumentModels","documentModels","vetraProcessorFactory"],"sources":["../src/feature-flags.ts","../src/renown.ts","../src/server.mts"],"sourcesContent":["import { EnvVarProvider } from \"@openfeature/env-var-provider\";\nimport { OpenFeature } from \"@openfeature/server-sdk\";\n\nexport async function initFeatureFlags() {\n // for now, we're only using env vars for feature flags\n const provider = new EnvVarProvider();\n\n await OpenFeature.setProviderAndWait(provider);\n\n return OpenFeature.getClient();\n}\n","import type { SignerConfig } from \"@powerhousedao/reactor\";\nimport {\n createSignatureVerifier,\n DEFAULT_RENOWN_URL,\n NodeKeyStorage,\n RenownBuilder,\n RenownCryptoBuilder,\n type IRenown,\n} from \"@renown/sdk/node\";\nimport { childLogger } from \"document-model\";\n\nconst logger = childLogger([\"switchboard\", \"renown\"]);\n\nexport interface RenownOptions {\n /** Path to the keypair file. Defaults to .ph/.keypair.json in cwd */\n keypairPath?: string;\n /** If true, won't generate a new keypair if none exists */\n requireExisting?: boolean;\n /** Base url of the Renown instance to use */\n baseUrl?: string;\n}\n\n/**\n * Initialize Renown for the Switchboard instance.\n * This allows Switchboard to authenticate with remote services\n * using the same identity established during `ph login`.\n */\nexport async function initRenown(\n options: RenownOptions = {},\n): Promise<IRenown | null> {\n const {\n keypairPath,\n requireExisting = false,\n baseUrl = DEFAULT_RENOWN_URL,\n } = options;\n\n const keyStorage = new NodeKeyStorage(keypairPath, {\n logger,\n });\n\n // Check if we have an existing keypair\n const existingKeyPair = await keyStorage.loadKeyPair();\n\n if (!existingKeyPair && requireExisting) {\n throw new Error(\n \"No existing keypair found and requireExisting is true. \" +\n 'Run \"ph login\" to create one.',\n );\n }\n\n if (!existingKeyPair) {\n logger.info(\"No existing keypair found. A new one will be generated.\");\n }\n\n const renownCrypto = await new RenownCryptoBuilder()\n .withKeyPairStorage(keyStorage)\n .build();\n\n const renown = await new RenownBuilder(\"switchboard\", {})\n .withCrypto(renownCrypto)\n .withBaseUrl(baseUrl)\n .build();\n\n logger.info(\"Switchboard identity initialized: @did\", renownCrypto.did);\n\n return renown;\n}\n\n/**\n * Get the signer config for the given renown instance.\n *\n * @param renown - The renown instance\n * @param requireSignature - If true, unsigned actions are rejected\n */\nexport function getRenownSignerConfig(\n renown: IRenown,\n requireSignature?: boolean,\n): SignerConfig {\n return {\n signer: renown.signer,\n verifier: createSignatureVerifier(requireSignature),\n };\n}\n","#!/usr/bin/env node\nimport { PGlite } from \"@electric-sql/pglite\";\nimport { metrics } from \"@opentelemetry/api\";\nimport { getConfig } from \"@powerhousedao/config/node\";\nimport { ReactorInstrumentation } from \"@powerhousedao/opentelemetry-instrumentation-reactor\";\nimport {\n ChannelScheme,\n EventBus,\n ReactorBuilder,\n ReactorClientBuilder,\n driveCollectionId,\n parseDriveUrl,\n type Database,\n} from \"@powerhousedao/reactor\";\nimport {\n HttpPackageLoader,\n ImportPackageLoader,\n PackageManagementService,\n PackagesSubgraph,\n getUniqueDocumentModels,\n initializeAndStartAPI,\n type IPackageLoader,\n} from \"@powerhousedao/reactor-api\";\nimport { httpsHooksPath } from \"@powerhousedao/reactor-api/https-hooks\";\nimport {\n VitePackageLoader,\n createViteLogger,\n startViteServer,\n} from \"@powerhousedao/reactor-api/vite\";\nimport { driveDocumentModelModule } from \"@powerhousedao/shared/document-drive\";\nimport type { DocumentModelModule } from \"@powerhousedao/shared/document-model\";\nimport { documentModels as vetraDocumentModels } from \"@powerhousedao/vetra\";\nimport { processorFactory as vetraProcessorFactory } from \"@powerhousedao/vetra/processors\";\nimport type { IRenown } from \"@renown/sdk/node\";\nimport * as Sentry from \"@sentry/node\";\nimport {\n childLogger,\n documentModelDocumentModelModule,\n setLogLevel,\n type ILogger,\n} from \"document-model\";\nimport dotenv from \"dotenv\";\nimport { Kysely, PostgresDialect } from \"kysely\";\nimport { PGliteDialect } from \"kysely-pglite-dialect\";\nimport net from \"node:net\";\nimport { register } from \"node:module\";\nimport path from \"path\";\nimport { Pool } from \"pg\";\nimport { initFeatureFlags } from \"./feature-flags.js\";\nimport { getRenownSignerConfig, initRenown } from \"./renown.js\";\nimport type { StartServerOptions, SwitchboardReactor } from \"./types.js\";\nimport { addDefaultDrive, isPostgresUrl } from \"./utils.mjs\";\n\nconst defaultLogger = childLogger([\"switchboard\"]);\n\nconst LogLevel = (process.env.LOG_LEVEL as ILogger[\"level\"] | \"\") || \"info\";\nsetLogLevel(LogLevel);\n\ndotenv.config();\n\n// Feature flag constants\nconst DOCUMENT_MODEL_SUBGRAPHS_ENABLED = \"DOCUMENT_MODEL_SUBGRAPHS_ENABLED\";\nconst DOCUMENT_MODEL_SUBGRAPHS_ENABLED_DEFAULT = true;\nconst REQUIRE_SIGNATURES = \"REQUIRE_SIGNATURES\";\nconst REQUIRE_SIGNATURES_DEFAULT = false;\n\nif (process.env.SENTRY_DSN) {\n defaultLogger.info(\n \"Initialized Sentry with env: @env\",\n process.env.SENTRY_ENV,\n );\n Sentry.init({\n dsn: process.env.SENTRY_DSN,\n environment: process.env.SENTRY_ENV,\n // Match the version tag uploaded by release-branch.yml so source maps\n // resolve. Populated by the CI (WORKSPACE_VERSION) or npm at runtime.\n release:\n process.env.SENTRY_RELEASE ||\n (process.env.npm_package_version\n ? `v${process.env.npm_package_version}`\n : undefined),\n });\n}\n\nconst DEFAULT_PORT = process.env.PORT ? Number(process.env.PORT) : 4001;\n\n// How many ports forward from the requested one we will try before giving up.\nconst PORT_FALLBACK_ATTEMPTS = 20;\n\n/**\n * Attempt to bind a throwaway TCP server to the given port. Resolves true if\n * the port is free, false if the OS reports it in use. Any other error is\n * surfaced so we don't silently mask real issues (permissions, bad host, …).\n */\nexport function isPortAvailable(port: number): Promise<boolean> {\n return new Promise((resolve, reject) => {\n const tester = net.createServer();\n tester.once(\"error\", (err: NodeJS.ErrnoException) => {\n if (err.code === \"EADDRINUSE\" || err.code === \"EACCES\") {\n resolve(false);\n } else {\n reject(err);\n }\n });\n tester.once(\"listening\", () => {\n tester.close(() => resolve(true));\n });\n // Bind on the unspecified IPv6 address so we detect collisions with both\n // IPv6 and IPv4 listeners (Node maps `::` to dual-stack on most systems).\n tester.listen({ port, host: \"::\" });\n });\n}\n\nasync function resolveServerPort(\n requested: number,\n strictPort: boolean,\n logger: ILogger,\n): Promise<number> {\n if (strictPort) return requested;\n for (let i = 0; i < PORT_FALLBACK_ATTEMPTS; i++) {\n const candidate = requested + i;\n if (await isPortAvailable(candidate)) {\n if (candidate !== requested) {\n logger.info(\n `Port ${requested} is in use. Falling back to port ${candidate}.`,\n );\n }\n return candidate;\n }\n }\n // Couldn't find a free port in the window; let the caller surface the\n // original EADDRINUSE when the real bind attempts runs.\n return requested;\n}\n\nasync function initServer(\n serverPort: number,\n options: StartServerOptions,\n renown: IRenown | null,\n) {\n // Register the global MeterProvider before ReactorInstrumentation is\n // constructed. setGlobalMeterProvider is a one-way door — once set it cannot\n // be unset — so this must happen before initializeClient calls\n // instrumentation.start() → createMetrics() → metrics.getMeter().\n if (options.meterProvider) {\n metrics.setGlobalMeterProvider(options.meterProvider);\n }\n\n const {\n dev,\n packages = [],\n remoteDrives = [],\n logger = defaultLogger,\n } = options;\n logger.level = LogLevel;\n const dbPath = options.dbPath ?? process.env.DATABASE_URL;\n\n // use postgres url for read model storage if available, otherwise use local PGlite path\n const readModelPath = dbPath || \".ph/read-storage\";\n\n // HTTP registry package loading\n const configPath =\n options.configFile ?? path.join(process.cwd(), \"powerhouse.config.json\");\n const config = getConfig(configPath);\n const registryUrl = process.env.PH_REGISTRY_URL ?? config.packageRegistryUrl;\n const registryPackages = process.env.PH_REGISTRY_PACKAGES;\n const dynamicModelLoading =\n options.dynamicModelLoading ?? process.env.DYNAMIC_MODEL_LOADING === \"true\";\n let httpLoader: HttpPackageLoader | undefined;\n\n if (registryUrl) {\n // Register HTTP/HTTPS module loader hooks for dynamic package imports\n register(httpsHooksPath, import.meta.url);\n httpLoader = new HttpPackageLoader({ registryUrl });\n registryPackages?.split(\",\").forEach((p) => {\n const name = p.trim();\n if (!packages.includes(name)) {\n packages.push(name);\n }\n });\n }\n\n const reactorLogger = logger.child([\"reactor\"]);\n const initializeClient = async (documentModels: DocumentModelModule[]) => {\n const eventBus = new EventBus();\n const builder = new ReactorBuilder()\n .withEventBus(eventBus)\n .withDocumentModels(\n getUniqueDocumentModels([\n documentModelDocumentModelModule,\n driveDocumentModelModule,\n ...vetraDocumentModels,\n ...documentModels,\n ]),\n )\n .withChannelScheme(ChannelScheme.SWITCHBOARD)\n .withSignalHandlers()\n .withLogger(reactorLogger);\n\n const maxSkipThreshold = parseInt(process.env.MAX_SKIP_THRESHOLD ?? \"\", 10);\n if (!isNaN(maxSkipThreshold) && maxSkipThreshold > 0) {\n builder.withExecutorConfig({ maxSkipThreshold });\n logger.info(`Reactor maxSkipThreshold set to ${maxSkipThreshold}`);\n }\n\n const reactorDbUrl = process.env.PH_REACTOR_DATABASE_URL;\n if (reactorDbUrl && isPostgresUrl(reactorDbUrl)) {\n const connectionString = reactorDbUrl.includes(\"?\")\n ? reactorDbUrl\n : `${reactorDbUrl}?sslmode=disable`;\n const pool = new Pool({ connectionString });\n const kysely = new Kysely<Database>({\n dialect: new PostgresDialect({ pool }),\n });\n builder.withKysely(kysely);\n logger.info(\"Using PostgreSQL for reactor storage\");\n } else {\n const pglitePath = \"./.ph/reactor-storage\";\n const pglite = new PGlite(pglitePath);\n const kysely = new Kysely<Database>({\n dialect: new PGliteDialect(pglite),\n });\n builder.withKysely(kysely);\n logger.info(\"Using PGlite for reactor storage\");\n }\n\n if (httpLoader && dynamicModelLoading) {\n builder.withDocumentModelLoader(httpLoader.documentModelLoader);\n }\n\n const clientBuilder = new ReactorClientBuilder().withReactorBuilder(\n builder,\n );\n\n if (renown) {\n const signerConfig = getRenownSignerConfig(\n renown,\n options.identity?.requireSignatures,\n );\n clientBuilder.withSigner(signerConfig);\n }\n\n const module = await clientBuilder.buildModule();\n\n if (module.reactorModule) {\n const instrumentation = new ReactorInstrumentation(module.reactorModule);\n instrumentation.start();\n reactorLogger.info(\"Reactor metrics instrumentation started\");\n }\n\n return module;\n };\n\n let defaultDriveUrl: undefined | string = undefined;\n\n // TODO get path from powerhouse config\n // start vite server if dev mode is enabled\n const basePath = process.cwd();\n const viteLogger = createViteLogger(logger);\n const vite = dev\n ? await startViteServer(process.cwd(), viteLogger)\n : undefined;\n\n // get paths to local document models\n if (!options.disableLocalPackages) {\n packages.push(basePath);\n }\n\n // create loaders\n const packageLoaders: IPackageLoader[] = [];\n if (vite) {\n packageLoaders.push(VitePackageLoader.build(vite));\n } else {\n packageLoaders.push(new ImportPackageLoader());\n }\n if (httpLoader) {\n packageLoaders.push(httpLoader);\n registryPackages?.split(\",\").forEach((p) => {\n const name = p.trim();\n if (!packages.includes(name)) {\n packages.push(name);\n }\n });\n }\n\n const apiLogger = logger.child([\"reactor-api\"]);\n const api = await initializeAndStartAPI(\n initializeClient,\n {\n port: serverPort,\n dbPath: readModelPath,\n https: options.https,\n packageLoaders: packageLoaders.length > 0 ? packageLoaders : undefined,\n packages: packages,\n processorConfig: options.processorConfig,\n processors: {\n \"@powerhousedao/vetra\": [vetraProcessorFactory],\n },\n configFile:\n options.configFile ??\n path.join(process.cwd(), \"powerhouse.config.json\"),\n mcp: options.mcp ?? true,\n logger: apiLogger,\n enableDocumentModelSubgraphs: options.enableDocumentModelSubgraphs,\n },\n \"switchboard\",\n );\n\n if (process.env.SENTRY_DSN) {\n // Register Sentry error handler after all routes are established.\n // The adapter calls the framework-specific Sentry setup internally.\n api.httpAdapter.setupSentryErrorHandler(Sentry);\n }\n\n const { client, graphqlManager, documentModelRegistry } = api;\n\n // Wire up dynamic package management if HTTP loader is configured\n if (httpLoader) {\n const packageManagementService = new PackageManagementService({\n defaultRegistryUrl: registryUrl,\n httpLoader,\n documentModelRegistry,\n });\n\n packageManagementService.setOnModelsChanged(() => {\n graphqlManager.regenerateDocumentModelSubgraphs().catch(logger.error);\n });\n\n const packagesSubgraph = new PackagesSubgraph({\n relationalDb: undefined as never,\n analyticsStore: undefined as never,\n reactorClient: client,\n graphqlManager,\n syncManager: api.syncManager,\n path: graphqlManager.getBasePath(),\n packageManagementService,\n });\n\n void graphqlManager\n .registerSubgraphInstance(packagesSubgraph, \"graphql\", false)\n .then(() => graphqlManager.updateRouter())\n .catch((error: unknown) => {\n logger.error(\"Failed to register packages subgraph: @error\", error);\n });\n }\n\n // Create default drive if provided\n if (options.drive) {\n if (!renown) {\n throw new Error(\"Cannot create default drive without Renown identity\");\n }\n\n defaultDriveUrl = await addDefaultDrive(client, options.drive, serverPort);\n }\n\n // add vite middleware after express app is initialized if applicable\n if (vite) {\n api.httpAdapter.mountRawMiddleware(vite.middlewares);\n }\n\n // Connect to remote drives AFTER packages are loaded\n if (remoteDrives.length > 0) {\n for (const remoteDriveUrl of remoteDrives) {\n let driveId: string | undefined;\n\n try {\n const { syncManager } = api;\n const parsed = parseDriveUrl(remoteDriveUrl);\n driveId = parsed.driveId;\n const remoteName = `remote-drive-${driveId}-${crypto.randomUUID()}`;\n await syncManager.add(remoteName, driveCollectionId(\"main\", driveId), {\n type: \"gql\",\n parameters: { url: parsed.graphqlEndpoint },\n });\n logger.debug(\"Remote drive @remoteDriveUrl synced\", remoteDriveUrl);\n } catch (error) {\n if (\n error instanceof Error &&\n error.message.includes(\"already exists\")\n ) {\n logger.debug(\n \"Remote drive already added: @remoteDriveUrl\",\n remoteDriveUrl,\n );\n driveId = remoteDriveUrl.split(\"/\").pop();\n } else {\n logger.error(\n \"Failed to connect to remote drive @remoteDriveUrl: @error\",\n remoteDriveUrl,\n error,\n );\n }\n } finally {\n // Construct local URL once in finally block\n if (!defaultDriveUrl && driveId) {\n const protocol = options.https ? \"https\" : \"http\";\n defaultDriveUrl = `${protocol}://localhost:${serverPort}/d/${driveId}`;\n }\n }\n }\n }\n\n return {\n defaultDriveUrl,\n api,\n reactor: client,\n renown,\n port: serverPort,\n };\n}\n\nexport const startSwitchboard = async (\n options: StartServerOptions = {},\n): Promise<SwitchboardReactor> => {\n const requestedPort = options.port ?? DEFAULT_PORT;\n const logger = options.logger ?? defaultLogger;\n const serverPort = await resolveServerPort(\n requestedPort,\n options.strictPort ?? false,\n logger,\n );\n\n // Initialize feature flags\n const featureFlags = await initFeatureFlags();\n\n const enableDocumentModelSubgraphs = await featureFlags.getBooleanValue(\n DOCUMENT_MODEL_SUBGRAPHS_ENABLED,\n options.enableDocumentModelSubgraphs ??\n DOCUMENT_MODEL_SUBGRAPHS_ENABLED_DEFAULT,\n );\n\n options.enableDocumentModelSubgraphs = enableDocumentModelSubgraphs;\n\n const requireSignatures =\n options.identity?.requireSignatures ??\n (await featureFlags.getBooleanValue(\n REQUIRE_SIGNATURES,\n REQUIRE_SIGNATURES_DEFAULT,\n ));\n options.identity = { ...options.identity, requireSignatures };\n\n logger.info(\n \"Feature flags: @flags\",\n JSON.stringify(\n {\n DOCUMENT_MODEL_SUBGRAPHS_ENABLED: enableDocumentModelSubgraphs,\n REQUIRE_SIGNATURES: requireSignatures,\n },\n null,\n 2,\n ),\n );\n\n // Initialize Renown if identity options are provided or keypair exists\n let renown: IRenown | null = null;\n try {\n renown = await initRenown(options.identity);\n } catch (e) {\n logger.warn(\"Failed to initialize ConnectCrypto: @error\", e);\n if (options.identity?.requireExisting) {\n throw new Error(\n 'Identity required but failed to initialize. Run \"ph login\" first.',\n );\n }\n }\n\n try {\n return await initServer(serverPort, options, renown);\n } catch (e) {\n Sentry.captureException(e);\n logger.error(\"App crashed: @error\", e);\n throw e;\n }\n};\n\nexport * from \"./types.js\";\n\nif (import.meta.main) {\n await startSwitchboard();\n}\n"],"mappings":"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"}
@@ -0,0 +1,93 @@
1
+ import { ILogger } from "document-model";
2
+ import { MeterProvider } from "@opentelemetry/api";
3
+ import { IReactorClient } from "@powerhousedao/reactor";
4
+ import { DriveInput } from "@powerhousedao/shared/document-drive";
5
+ import { IRenown } from "@renown/sdk";
6
+
7
+ //#region src/types.d.ts
8
+ type StorageOptions = {
9
+ type: "filesystem" | "memory" | "postgres" | "browser";
10
+ filesystemPath?: string;
11
+ postgresUrl?: string;
12
+ };
13
+ type IdentityOptions = {
14
+ /** Path to the keypair file. Defaults to ~/.ph/keypair.json */keypairPath?: string;
15
+ /**
16
+ * If true, won't start without an existing keypair.
17
+ * Use this to ensure the switchboard only runs with an authenticated identity.
18
+ */
19
+ requireExisting?: boolean; /** Base url of the Renown instance to use */
20
+ baseUrl?: string; /** If true, unsigned actions will be rejected */
21
+ requireSignatures?: boolean;
22
+ };
23
+ type StartServerOptions = {
24
+ configFile?: string;
25
+ port?: number;
26
+ /**
27
+ * If true, fail immediately when the requested port is in use instead of
28
+ * falling back to the next free port. Matches the semantics of Vite's
29
+ * `--strictPort` flag that flows through the `ph vetra` command.
30
+ */
31
+ strictPort?: boolean;
32
+ dev?: boolean;
33
+ dbPath?: string;
34
+ drive?: DriveInput;
35
+ packages?: string[];
36
+ remoteDrives?: string[];
37
+ https?: {
38
+ keyPath: string;
39
+ certPath: string;
40
+ } | boolean | undefined;
41
+ auth?: {
42
+ enabled: boolean;
43
+ guests: string[];
44
+ users: string[];
45
+ admins: string[];
46
+ };
47
+ /**
48
+ * Identity options for Renown.
49
+ * When configured, the switchboard will load the keypair from `ph login`
50
+ * and can authenticate with remote services on behalf of the user.
51
+ */
52
+ identity?: IdentityOptions;
53
+ mcp?: boolean;
54
+ processorConfig?: Map<string, unknown>;
55
+ disableLocalPackages?: boolean;
56
+ enableDocumentModelSubgraphs?: boolean;
57
+ /**
58
+ * When true, enables dynamic loading of document models from the registry
59
+ * when an unknown document type is encountered during sync.
60
+ * Disabled by default — enable with DYNAMIC_MODEL_LOADING=true env var.
61
+ */
62
+ dynamicModelLoading?: boolean;
63
+ logger?: ILogger;
64
+ /**
65
+ * OpenTelemetry MeterProvider to register as the global provider before
66
+ * ReactorInstrumentation starts. Must be provided here rather than set
67
+ * externally to guarantee the registration happens before
68
+ * instrumentation.start() reads the global provider via metrics.getMeter().
69
+ */
70
+ meterProvider?: MeterProvider;
71
+ };
72
+ type SwitchboardReactor = {
73
+ defaultDriveUrl: string | undefined;
74
+ reactor: IReactorClient; /** The Renown instance if identity was initialized */
75
+ renown: IRenown | null;
76
+ /**
77
+ * Port the HTTP server actually bound to. May differ from the requested
78
+ * port when the requested port was in use and fallback kicked in.
79
+ */
80
+ port: number;
81
+ };
82
+ //#endregion
83
+ //#region src/server.d.mts
84
+ /**
85
+ * Attempt to bind a throwaway TCP server to the given port. Resolves true if
86
+ * the port is free, false if the OS reports it in use. Any other error is
87
+ * surfaced so we don't silently mask real issues (permissions, bad host, …).
88
+ */
89
+ declare function isPortAvailable(port: number): Promise<boolean>;
90
+ declare const startSwitchboard: (options?: StartServerOptions) => Promise<SwitchboardReactor>;
91
+ //#endregion
92
+ export { IdentityOptions, StartServerOptions, StorageOptions, SwitchboardReactor, isPortAvailable, startSwitchboard };
93
+ //# sourceMappingURL=server.d.mts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"server.d.mts","names":[],"sources":["../src/types.ts","../src/server.mts"],"mappings":";;;;;;;KAMY,cAAA;EACV,IAAA;EACA,cAAA;EACA,WAAA;AAAA;AAAA,KAGU,eAAA;EALV,+DAOA,WAAA;EALA;;;AAGF;EAOE,eAAA;EAGA,OAAA,WARA;EAWA,iBAAA;AAAA;AAAA,KAGU,kBAAA;EACV,UAAA;EACA,IAAA;EAFU;;;;;EAQV,UAAA;EACA,GAAA;EACA,MAAA;EACA,KAAA,GAAQ,UAAA;EACR,QAAA;EACA,YAAA;EACA,KAAA;IAEM,OAAA;IACA,QAAA;EAAA;EAIN,IAAA;IACE,OAAA;IACA,MAAA;IACA,KAAA;IACA,MAAA;EAAA;EARI;;;;;EAeN,QAAA,GAAW,eAAA;EACX,GAAA;EACA,eAAA,GAAkB,GAAA;EAClB,oBAAA;EACA,4BAAA;EAFkB;;;;;EAQlB,mBAAA;EACA,MAAA,GAAS,OAAA;EAOO;;;AAGlB;;;EAHE,aAAA,GAAgB,aAAA;AAAA;AAAA,KAGN,kBAAA;EACV,eAAA;EACA,OAAA,EAAS,cAAA,EAED;EAAR,MAAA,EAAQ,OAAA;EAKJ;;;;EAAJ,IAAA;AAAA;;;;;;;;iBCIc,eAAA,CAAgB,IAAA,WAAe,OAAA;AAAA,cA6TlC,gBAAA,GACX,OAAA,GAAS,kBAAA,KACR,OAAA,CAAQ,kBAAA"}
@@ -0,0 +1,4 @@
1
+ #!/usr/bin/env node
2
+ import { n as startSwitchboard, t as isPortAvailable } from "./server-BMtyzhoR.mjs";
3
+ import "./utils-DFl0ezBT.mjs";
4
+ export { isPortAvailable, startSwitchboard };
@@ -0,0 +1,44 @@
1
+ import { driveCreateDocument, driveCreateState } from "@powerhousedao/shared/document-drive";
2
+ import "@powerhousedao/shared/document-model";
3
+ //#region src/utils.mts
4
+ async function addDefaultDrive(client, drive, serverPort) {
5
+ let driveId = drive.id;
6
+ if (!driveId || driveId.length === 0) driveId = drive.slug;
7
+ if (!driveId || driveId.length === 0) throw new Error("Invalid Drive Id");
8
+ let existingDrive;
9
+ try {
10
+ existingDrive = await client.get(driveId);
11
+ } catch {}
12
+ if (existingDrive) return `http://localhost:${serverPort}/d/${driveId}`;
13
+ const { global } = driveCreateState();
14
+ const document = driveCreateDocument({
15
+ global: {
16
+ ...global,
17
+ name: drive.global.name,
18
+ icon: drive.global.icon ?? global.icon
19
+ },
20
+ local: {
21
+ availableOffline: drive.local?.availableOffline ?? false,
22
+ sharingType: drive.local?.sharingType ?? "public",
23
+ listeners: drive.local?.listeners ?? [],
24
+ triggers: drive.local?.triggers ?? []
25
+ }
26
+ });
27
+ if (drive.id && drive.id.length > 0) document.header.id = drive.id;
28
+ if (drive.slug && drive.slug.length > 0) document.header.slug = drive.slug;
29
+ if (drive.global.name) document.header.name = drive.global.name;
30
+ if (drive.preferredEditor) document.header.meta = { preferredEditor: drive.preferredEditor };
31
+ try {
32
+ await client.create(document);
33
+ } catch (e) {
34
+ if (!(e instanceof Error ? e.message : String(e)).includes("already exists")) throw e;
35
+ }
36
+ return `http://localhost:${serverPort}/d/${driveId}`;
37
+ }
38
+ function isPostgresUrl(url) {
39
+ return url.startsWith("postgresql") || url.startsWith("postgres");
40
+ }
41
+ //#endregion
42
+ export { isPostgresUrl as n, addDefaultDrive as t };
43
+
44
+ //# sourceMappingURL=utils-DFl0ezBT.mjs.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"utils-DFl0ezBT.mjs","names":[],"sources":["../src/utils.mts"],"sourcesContent":["import type { IReactorClient } from \"@powerhousedao/reactor\";\nimport type { DocumentDriveDocument } from \"@powerhousedao/shared/document-drive\";\nimport {\n driveCreateDocument,\n driveCreateState,\n} from \"@powerhousedao/shared/document-drive\";\nimport type { DriveInput } from \"@powerhousedao/shared/document-drive\";\nimport { generateId } from \"@powerhousedao/shared/document-model\";\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 document = 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 if (drive.id && drive.id.length > 0) {\n document.header.id = drive.id;\n }\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"],"mappings":";;;AASA,eAAsB,gBACpB,QACA,OACA,YACA;CACA,IAAI,UAAU,MAAM;AACpB,KAAI,CAAC,WAAW,QAAQ,WAAW,EACjC,WAAU,MAAM;AAGlB,KAAI,CAAC,WAAW,QAAQ,WAAW,EACjC,OAAM,IAAI,MAAM,mBAAmB;CAIrC,IAAI;AACJ,KAAI;AACF,kBAAgB,MAAM,OAAO,IAAI,QAAQ;SACnC;AAKR,KAAI,cACF,QAAO,oBAAoB,WAAW,KAAK;CAG7C,MAAM,EAAE,WAAW,kBAAkB;CACrC,MAAM,WAAW,oBAAoB;EACnC,QAAQ;GACN,GAAG;GACH,MAAM,MAAM,OAAO;GACnB,MAAM,MAAM,OAAO,QAAQ,OAAO;GACnC;EACD,OAAO;GACL,kBAAkB,MAAM,OAAO,oBAAoB;GACnD,aAAa,MAAM,OAAO,eAAe;GACzC,WAAW,MAAM,OAAO,aAAa,EAAE;GACvC,UAAU,MAAM,OAAO,YAAY,EAAE;GACtC;EACF,CAAC;AAEF,KAAI,MAAM,MAAM,MAAM,GAAG,SAAS,EAChC,UAAS,OAAO,KAAK,MAAM;AAE7B,KAAI,MAAM,QAAQ,MAAM,KAAK,SAAS,EACpC,UAAS,OAAO,OAAO,MAAM;AAE/B,KAAI,MAAM,OAAO,KACf,UAAS,OAAO,OAAO,MAAM,OAAO;AAEtC,KAAI,MAAM,gBACR,UAAS,OAAO,OAAO,EAAE,iBAAiB,MAAM,iBAAiB;AAGnE,KAAI;AACF,QAAM,OAAO,OAAO,SAAS;UACtB,GAAG;AAEV,MAAI,EADiB,aAAa,QAAQ,EAAE,UAAU,OAAO,EAAE,EAC7C,SAAS,iBAAiB,CAC1C,OAAM;;AAIV,QAAO,oBAAoB,WAAW,KAAK;;AAG7C,SAAgB,cAAc,KAAa;AACzC,QAAO,IAAI,WAAW,aAAa,IAAI,IAAI,WAAW,WAAW"}
@@ -0,0 +1,9 @@
1
+ import { IReactorClient } from "@powerhousedao/reactor";
2
+ import { DriveInput } from "@powerhousedao/shared/document-drive";
3
+
4
+ //#region src/utils.d.mts
5
+ declare function addDefaultDrive(client: IReactorClient, drive: DriveInput, serverPort: number): Promise<string>;
6
+ declare function isPostgresUrl(url: string): boolean;
7
+ //#endregion
8
+ export { addDefaultDrive, isPostgresUrl };
9
+ //# sourceMappingURL=utils.d.mts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"utils.d.mts","names":[],"sources":["../src/utils.mts"],"mappings":";;;;iBASsB,eAAA,CACpB,MAAA,EAAQ,cAAA,EACR,KAAA,EAAO,UAAA,EACP,UAAA,WAAkB,OAAA;AAAA,iBAgEJ,aAAA,CAAc,GAAA"}
package/dist/utils.mjs ADDED
@@ -0,0 +1,2 @@
1
+ import { n as isPostgresUrl, t as addDefaultDrive } from "./utils-DFl0ezBT.mjs";
2
+ export { addDefaultDrive, isPostgresUrl };
package/package.json CHANGED
@@ -1,27 +1,27 @@
1
1
  {
2
2
  "name": "@powerhousedao/switchboard",
3
3
  "type": "module",
4
- "version": "6.0.2-staging.2",
5
- "main": "dist/src/index.js",
4
+ "version": "6.0.2-staging.3",
5
+ "main": "dist/index.mjs",
6
6
  "exports": {
7
7
  ".": {
8
- "import": "./dist/src/index.js",
9
- "types": "./dist/src/index.d.ts"
8
+ "types": "./dist/index.d.mts",
9
+ "import": "./dist/index.mjs"
10
10
  },
11
11
  "./server": {
12
- "import": "./dist/src/server.js",
13
- "types": "./dist/src/server.d.ts"
12
+ "types": "./dist/server.d.mts",
13
+ "import": "./dist/server.mjs"
14
14
  },
15
15
  "./utils": {
16
- "import": "./dist/src/utils.js",
17
- "types": "./dist/src/utils.d.ts"
16
+ "types": "./dist/utils.d.mts",
17
+ "import": "./dist/utils.mjs"
18
18
  }
19
19
  },
20
20
  "engines": {
21
21
  "node": ">=24.0.0"
22
22
  },
23
23
  "bin": {
24
- "switchboard": "dist/src/index.js"
24
+ "switchboard": "dist/index.mjs"
25
25
  },
26
26
  "repository": {
27
27
  "type": "git",
@@ -43,37 +43,43 @@
43
43
  "@sentry/node": "^9.6.1",
44
44
  "dotenv": "^16.4.7",
45
45
  "express": "^4.21.2",
46
- "kysely": "0.28.11",
46
+ "kysely": "0.28.16",
47
47
  "kysely-pglite-dialect": "1.2.0",
48
48
  "pg": "8.18.0",
49
- "redis": "^4.7.0",
50
- "@powerhousedao/config": "6.0.2-staging.2",
51
- "@renown/sdk": "6.0.2-staging.2",
52
- "@powerhousedao/reactor": "6.0.2-staging.2",
53
- "document-model": "6.0.2-staging.2",
54
- "@powerhousedao/opentelemetry-instrumentation-reactor": "6.0.2-staging.2",
55
- "@powerhousedao/reactor-api": "6.0.2-staging.2",
56
- "document-drive": "6.0.2-staging.2"
49
+ "vite": "8.0.8",
50
+ "@powerhousedao/config": "6.0.2-staging.3",
51
+ "@powerhousedao/opentelemetry-instrumentation-reactor": "6.0.2-staging.3",
52
+ "@powerhousedao/shared": "6.0.2-staging.3",
53
+ "@powerhousedao/vetra": "6.0.2-staging.3",
54
+ "@powerhousedao/reactor": "6.0.2-staging.3",
55
+ "@powerhousedao/reactor-api": "6.0.2-staging.3",
56
+ "document-model": "6.0.2-staging.3",
57
+ "@renown/sdk": "6.0.2-staging.3"
57
58
  },
58
59
  "devDependencies": {
59
60
  "@types/express": "^4.17.25",
60
61
  "@types/node": "25.2.3",
61
62
  "@types/pg": "8.16.0",
63
+ "tsdown": "0.21.1",
62
64
  "concurrently": "9.2.1",
63
65
  "nodemon": "3.1.11",
64
- "vitest": "3.2.4"
66
+ "react": "19.2.4",
67
+ "vitest": "4.1.1"
68
+ },
69
+ "peerDependencies": {
70
+ "react": ">=19.0.0"
65
71
  },
66
72
  "scripts": {
67
73
  "tsc": "tsc",
68
74
  "test": "vitest run",
69
75
  "lint": "eslint",
70
- "build:misc": "pnpm run install-packages",
71
- "start": "node dist/src/index.js",
72
- "start:profile": "mkdir -p .prof && node --cpu-prof --cpu-prof-dir=.prof dist/src/index.js",
73
- "start:profile:bun": "mkdir -p .prof && bun --cpu-prof --cpu-prof-dir=.prof dist/src/index.js",
74
- "dev": "concurrently -P 'pnpm -w run tsc --watch' 'nodemon --trace-warnings --watch \"../..\" -e ts,tsx,js,json dist/src/index.js -- {@}' --",
75
- "install-packages": "node dist/src/install-packages.js",
76
- "migrate": "node dist/src/migrate.js",
77
- "migrate:status": "node dist/src/migrate.js status"
76
+ "build": "tsdown && pnpm run install-packages",
77
+ "start": "node dist/index.mjs",
78
+ "start:profile": "mkdir -p .prof && node --cpu-prof --cpu-prof-dir=.prof dist/index.mjs",
79
+ "start:profile:bun": "mkdir -p .prof && bun --cpu-prof --cpu-prof-dir=.prof dist/index.mjs",
80
+ "dev": "concurrently -P 'pnpm -w run tsc --watch' 'nodemon --trace-warnings --watch \"../..\" -e ts,tsx,js,json dist/index.mjs -- {@}' --",
81
+ "install-packages": "node dist/install-packages.mjs",
82
+ "migrate": "node dist/migrate.mjs",
83
+ "migrate:status": "node dist/migrate.mjs status"
78
84
  }
79
85
  }
package/tsconfig.json CHANGED
@@ -9,9 +9,6 @@
9
9
  {
10
10
  "path": "../../packages/config"
11
11
  },
12
- {
13
- "path": "../../packages/document-drive"
14
- },
15
12
  {
16
13
  "path": "../../packages/document-model"
17
14
  },
@@ -26,6 +23,12 @@
26
23
  },
27
24
  {
28
25
  "path": "../../packages/renown"
26
+ },
27
+ {
28
+ "path": "../../packages/shared"
29
+ },
30
+ {
31
+ "path": "../../packages/vetra"
29
32
  }
30
33
  ]
31
34
  }
@@ -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
+ });
package/vitest.config.ts CHANGED
@@ -4,12 +4,8 @@ export default defineConfig({
4
4
  test: {
5
5
  pool: "forks",
6
6
  environment: "node",
7
- poolOptions: {
8
- forks: {
9
- singleFork: true,
10
- isolate: true,
11
- },
12
- },
7
+ isolate: true,
8
+ maxWorkers: 1,
13
9
  include: ["test/**/*.test.ts"],
14
10
  },
15
11
  });
package/Dockerfile DELETED
@@ -1,86 +0,0 @@
1
- # Build stage
2
- FROM node:24-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:24-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,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
@@ -1 +0,0 @@
1
- {"version":3,"file":"feature-flags.js","sourceRoot":"","sources":["../../src/feature-flags.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,cAAc,EAAE,MAAM,+BAA+B,CAAC;AAC/D,OAAO,EAAE,WAAW,EAAE,MAAM,yBAAyB,CAAC;AAEtD,MAAM,CAAC,KAAK,UAAU,gBAAgB;IACpC,uDAAuD;IACvD,MAAM,QAAQ,GAAG,IAAI,cAAc,EAAE,CAAC;IAEtC,MAAM,WAAW,CAAC,kBAAkB,CAAC,QAAQ,CAAC,CAAC;IAE/C,OAAO,WAAW,CAAC,SAAS,EAAE,CAAC;AACjC,CAAC"}
@@ -1,3 +0,0 @@
1
- #!/usr/bin/env node
2
- export {};
3
- //# sourceMappingURL=index.d.ts.map
@@ -1 +0,0 @@
1
- {"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../src/index.ts"],"names":[],"mappings":""}