@promptbook/cli 0.112.0-88 → 0.112.0-90

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 (27) hide show
  1. package/apps/agents-server/next.config.ts +58 -3
  2. package/apps/agents-server/src/database/ensureAutomaticDatabaseMigrations.ts +8 -1
  3. package/apps/agents-server/src/database/runDatabaseMigrations.ts +31 -1
  4. package/apps/agents-server/src/database/sqlite/$provideLocalSqliteSupabase.ts +2 -2
  5. package/apps/agents-server/src/middleware/createMiddlewareRequestContext.ts +1 -1
  6. package/apps/agents-server/src/tools/$provideServer.ts +27 -0
  7. package/apps/agents-server/src/utils/serverRegistry.ts +117 -3
  8. package/esm/apps/agents-server/src/utils/serverRegistry.d.ts +6 -0
  9. package/esm/index.es.js +348 -17
  10. package/esm/index.es.js.map +1 -1
  11. package/esm/src/cli/cli-commands/agents-server/buildAgentsServer.d.ts +31 -0
  12. package/esm/src/cli/cli-commands/agents-server/startAgentsServer.d.ts +6 -0
  13. package/esm/src/version.d.ts +1 -1
  14. package/package.json +5 -3
  15. package/src/cli/cli-commands/agents-server/buildAgentsServer.ts +330 -8
  16. package/src/cli/cli-commands/agents-server/run.ts +2 -1
  17. package/src/cli/cli-commands/agents-server/startAgentsServer.ts +40 -16
  18. package/src/other/templates/getTemplatesPipelineCollection.ts +691 -794
  19. package/src/version.ts +2 -2
  20. package/src/versions.txt +2 -0
  21. package/umd/apps/agents-server/src/utils/serverRegistry.d.ts +6 -0
  22. package/umd/index.umd.js +346 -15
  23. package/umd/index.umd.js.map +1 -1
  24. package/umd/src/cli/cli-commands/agents-server/buildAgentsServer.d.ts +31 -0
  25. package/umd/src/cli/cli-commands/agents-server/startAgentsServer.d.ts +6 -0
  26. package/umd/src/version.d.ts +1 -1
  27. package/src/wizard/test/sub/subsub/subsubsub/.promptbook/executions-cache/8/c/report-whoami-6e340b9cffb37a98.json +0 -104
package/esm/index.es.js CHANGED
@@ -1,8 +1,8 @@
1
1
  import colors from 'colors';
2
2
  import commander, { Option } from 'commander';
3
3
  import _spaceTrim, { spaceTrim as spaceTrim$1 } from 'spacetrim';
4
- import { writeFile, stat, mkdir, readFile, readdir, unlink, appendFile, rm, rename, access, constants, watch, rmdir } from 'fs/promises';
5
- import { join, resolve, basename, relative, isAbsolute, dirname, extname } from 'path';
4
+ import { writeFile, stat, mkdir, readFile, rm, cp, lstat, symlink, readdir, unlink, appendFile, rename, access, constants, watch, rmdir } from 'fs/promises';
5
+ import { join, resolve, dirname, relative, basename, delimiter, isAbsolute, extname } from 'path';
6
6
  import { spawn } from 'child_process';
7
7
  import { createHash, randomBytes } from 'crypto';
8
8
  import * as fs from 'fs';
@@ -58,7 +58,7 @@ const BOOK_LANGUAGE_VERSION = '2.0.0';
58
58
  * @generated
59
59
  * @see https://github.com/webgptorg/promptbook
60
60
  */
61
- const PROMPTBOOK_ENGINE_VERSION = '0.112.0-88';
61
+ const PROMPTBOOK_ENGINE_VERSION = '0.112.0-90';
62
62
  /**
63
63
  * TODO: string_promptbook_version should be constrained to the all versions of Promptbook engine
64
64
  * Note: [💞] Ignore a discrepancy between file name and entity name
@@ -3102,6 +3102,31 @@ const AGENTS_SERVER_NEXT_BUILD_ID_FILENAME = 'BUILD_ID';
3102
3102
  * @private internal constant of `ptbk agents-server`
3103
3103
  */
3104
3104
  const DEFAULT_AGENTS_SERVER_NEXT_DIST_DIRECTORY_NAME = '.next';
3105
+ /**
3106
+ * Environment variable passed to the bundled Next app so webpack can resolve dependencies
3107
+ * installed beside `ptbk` even when the app sources are materialized into a project cache.
3108
+ *
3109
+ * @private internal constant of `ptbk agents-server`
3110
+ */
3111
+ const PTBK_AGENTS_SERVER_NODE_MODULES_PATH_ENV = 'PTBK_AGENTS_SERVER_NODE_MODULES_PATH';
3112
+ /**
3113
+ * Environment variable used only by the CLI-owned production build.
3114
+ *
3115
+ * @private internal constant of `ptbk agents-server`
3116
+ */
3117
+ const PTBK_AGENTS_SERVER_IGNORE_NEXT_VALIDATION_ENV = 'PTBK_AGENTS_SERVER_IGNORE_NEXT_VALIDATION';
3118
+ /**
3119
+ * Runtime copy metadata filename stored in the project-local materialized app root.
3120
+ *
3121
+ * @private internal constant of `ptbk agents-server`
3122
+ */
3123
+ const AGENTS_SERVER_MATERIALIZED_RUNTIME_CACHE_FILENAME = '.ptbk-agents-server-runtime-cache.json';
3124
+ /**
3125
+ * Directory segment used for Node package installs.
3126
+ *
3127
+ * @private internal constant of `ptbk agents-server`
3128
+ */
3129
+ const NODE_MODULES_DIRECTORY_NAME = 'node_modules';
3105
3130
  /**
3106
3131
  * Runtime paths copied into the CLI package and used by the Agents Server production build.
3107
3132
  *
@@ -3146,26 +3171,33 @@ const AGENTS_SERVER_BUILD_INPUT_TEST_FILE_PATTERN = /\.(?:spec|test)\.[jt]sx?$/i
3146
3171
  */
3147
3172
  async function ensureAgentsServerBuild(options = {}) {
3148
3173
  var _a, _b, _c, _d;
3149
- const appPath = (_a = options.appPath) !== null && _a !== void 0 ? _a : (await resolveAgentsServerAppPath());
3150
- const environment = (_b = options.environment) !== null && _b !== void 0 ? _b : process.env;
3174
+ const environment = (_a = options.environment) !== null && _a !== void 0 ? _a : process.env;
3151
3175
  const nextCliPath = resolveNextCliPath();
3176
+ const nodeModulesPath = resolveNodeModulesPath(nextCliPath);
3177
+ const appPath = await resolveAgentsServerBuildAppPath({
3178
+ sourceAppPath: (_b = options.appPath) !== null && _b !== void 0 ? _b : (await resolveAgentsServerAppPath()),
3179
+ nodeModulesPath,
3180
+ });
3181
+ const buildEnvironment = createAgentsServerRuntimeEnvironment(environment, nodeModulesPath, {
3182
+ isNextValidationIgnored: isAgentsServerAppPathMaterialized(appPath),
3183
+ });
3152
3184
  if (!options.isBuildForced &&
3153
3185
  (await isAgentsServerBuildCacheCurrent({
3154
3186
  appPath,
3155
- environment,
3187
+ environment: buildEnvironment,
3156
3188
  }))) {
3157
3189
  (_c = options.onBuildEvent) === null || _c === void 0 ? void 0 : _c.call(options, 'Using the cached Agents Server Next app build.');
3158
- return { appPath, nextCliPath };
3190
+ return { appPath, nextCliPath, nodeModulesPath };
3159
3191
  }
3160
3192
  (_d = options.onBuildEvent) === null || _d === void 0 ? void 0 : _d.call(options, 'Building the Agents Server Next app.');
3161
3193
  await runNextBuild({
3162
3194
  appPath,
3163
- environment,
3195
+ environment: buildEnvironment,
3164
3196
  nextCliPath,
3165
3197
  onBuildOutput: options.onBuildOutput,
3166
3198
  });
3167
- await writeAgentsServerBuildCache({ appPath, environment });
3168
- return { appPath, nextCliPath };
3199
+ await writeAgentsServerBuildCache({ appPath, environment: buildEnvironment });
3200
+ return { appPath, nextCliPath, nodeModulesPath };
3169
3201
  }
3170
3202
  /**
3171
3203
  * Returns true when the production build marker and source fingerprint still match.
@@ -3221,6 +3253,165 @@ async function resolveAgentsServerAppPath() {
3221
3253
  ${candidates.map((candidate) => `- \`${candidate}\``).join('\n')}
3222
3254
  `));
3223
3255
  }
3256
+ /**
3257
+ * Adds dependency-resolution environment required by the materialized Agents Server runtime.
3258
+ *
3259
+ * @private internal utility of `ptbk agents-server`
3260
+ */
3261
+ function createAgentsServerRuntimeEnvironment(environment, nodeModulesPath, options = {}) {
3262
+ return {
3263
+ ...environment,
3264
+ NODE_PATH: mergeNodePath(nodeModulesPath, environment.NODE_PATH),
3265
+ [PTBK_AGENTS_SERVER_NODE_MODULES_PATH_ENV]: nodeModulesPath,
3266
+ ...(options.isNextValidationIgnored
3267
+ ? {
3268
+ [PTBK_AGENTS_SERVER_IGNORE_NEXT_VALIDATION_ENV]: 'true',
3269
+ }
3270
+ : {}),
3271
+ };
3272
+ }
3273
+ /**
3274
+ * Uses the source checkout app directly, but copies npm-packaged app sources out of `node_modules`.
3275
+ *
3276
+ * @private internal utility of `ptbk agents-server`
3277
+ */
3278
+ async function resolveAgentsServerBuildAppPath(options) {
3279
+ if (!isPathInsideNodeModules(options.sourceAppPath)) {
3280
+ return options.sourceAppPath;
3281
+ }
3282
+ const sourceRuntimeRootPath = resolve(options.sourceAppPath, '..', '..');
3283
+ const materializedRuntimeRootPath = resolvePromptbookTemporaryPath(process.cwd(), 'agents-server', 'runtime');
3284
+ await synchronizeMaterializedAgentsServerRuntime({
3285
+ materializedRuntimeRootPath,
3286
+ nodeModulesPath: options.nodeModulesPath,
3287
+ sourceAppPath: options.sourceAppPath,
3288
+ sourceRuntimeRootPath,
3289
+ });
3290
+ return join(materializedRuntimeRootPath, 'apps', 'agents-server');
3291
+ }
3292
+ /**
3293
+ * Copies the bundled runtime into the launch project when the original app lives under `node_modules`.
3294
+ */
3295
+ async function synchronizeMaterializedAgentsServerRuntime(options) {
3296
+ const sourceFingerprint = await createAgentsServerBuildSourceFingerprint(options.sourceAppPath);
3297
+ const runtimeCache = await readAgentsServerMaterializedRuntimeCache(options.materializedRuntimeRootPath);
3298
+ const isRuntimeCurrent = (runtimeCache === null || runtimeCache === void 0 ? void 0 : runtimeCache.version) === AGENTS_SERVER_BUILD_CACHE_VERSION &&
3299
+ runtimeCache.sourceFingerprint === sourceFingerprint &&
3300
+ (await isAgentsServerAppPath(join(options.materializedRuntimeRootPath, 'apps', 'agents-server')));
3301
+ if (!isRuntimeCurrent) {
3302
+ await rm(options.materializedRuntimeRootPath, { recursive: true, force: true });
3303
+ await mkdir(options.materializedRuntimeRootPath, { recursive: true });
3304
+ for (const relativeInputPath of AGENTS_SERVER_BUILD_INPUT_RELATIVE_PATHS) {
3305
+ await copyAgentsServerRuntimePath({
3306
+ destinationPath: join(options.materializedRuntimeRootPath, relativeInputPath),
3307
+ sourcePath: join(options.sourceRuntimeRootPath, relativeInputPath),
3308
+ });
3309
+ }
3310
+ await assertMaterializedAgentsServerAppExists(options.materializedRuntimeRootPath);
3311
+ await writeAgentsServerMaterializedRuntimeCache(options.materializedRuntimeRootPath, sourceFingerprint);
3312
+ }
3313
+ await ensureMaterializedRuntimeNodeModulesLink({
3314
+ materializedRuntimeRootPath: options.materializedRuntimeRootPath,
3315
+ nodeModulesPath: options.nodeModulesPath,
3316
+ });
3317
+ }
3318
+ /**
3319
+ * Verifies that the materialized runtime contains a usable Next app before caching it.
3320
+ */
3321
+ async function assertMaterializedAgentsServerAppExists(materializedRuntimeRootPath) {
3322
+ const materializedAppPath = join(materializedRuntimeRootPath, 'apps', 'agents-server');
3323
+ if (await isAgentsServerAppPath(materializedAppPath)) {
3324
+ return;
3325
+ }
3326
+ throw new NotAllowed(spaceTrim$1(`
3327
+ Cannot prepare the bundled Agents Server runtime.
3328
+
3329
+ The materialized app path is missing required files:
3330
+ \`${materializedAppPath}\`
3331
+ `));
3332
+ }
3333
+ /**
3334
+ * Copies one source path into the materialized runtime, skipping generated or private files.
3335
+ */
3336
+ async function copyAgentsServerRuntimePath(options) {
3337
+ let sourceStats;
3338
+ try {
3339
+ sourceStats = await stat(options.sourcePath);
3340
+ }
3341
+ catch (_a) {
3342
+ return;
3343
+ }
3344
+ await mkdir(dirname(options.destinationPath), { recursive: true });
3345
+ if (sourceStats.isDirectory()) {
3346
+ await cp(options.sourcePath, options.destinationPath, {
3347
+ recursive: true,
3348
+ filter: (sourcePath) => shouldCopyAgentsServerRuntimePath(sourcePath, options.sourcePath),
3349
+ });
3350
+ return;
3351
+ }
3352
+ if (sourceStats.isFile() && shouldCopyAgentsServerRuntimePath(options.sourcePath, dirname(options.sourcePath))) {
3353
+ await cp(options.sourcePath, options.destinationPath);
3354
+ }
3355
+ }
3356
+ /**
3357
+ * Excludes build artifacts, dependency folders, private env files, and test sources.
3358
+ */
3359
+ function shouldCopyAgentsServerRuntimePath(sourcePath, sourceRootPath) {
3360
+ const sourceRelativePath = relative(sourceRootPath, sourcePath).replace(/\\/gu, '/');
3361
+ const sourcePathSegments = sourceRelativePath.split('/').filter(Boolean);
3362
+ const sourceBasename = basename(sourcePath);
3363
+ if (sourcePathSegments.some((sourcePathSegment) => AGENTS_SERVER_BUILD_INPUT_EXCLUDED_DIRECTORY_NAMES.has(sourcePathSegment))) {
3364
+ return false;
3365
+ }
3366
+ if (sourceBasename.startsWith('.env')) {
3367
+ return false;
3368
+ }
3369
+ return !AGENTS_SERVER_BUILD_INPUT_TEST_FILE_PATTERN.test(sourceBasename);
3370
+ }
3371
+ /**
3372
+ * Links the materialized runtime back to the package dependency tree used by the installed CLI.
3373
+ */
3374
+ async function ensureMaterializedRuntimeNodeModulesLink(options) {
3375
+ const nodeModulesLinkPath = join(options.materializedRuntimeRootPath, NODE_MODULES_DIRECTORY_NAME);
3376
+ try {
3377
+ const existingLinkStats = await lstat(nodeModulesLinkPath);
3378
+ await rm(nodeModulesLinkPath, {
3379
+ force: true,
3380
+ recursive: existingLinkStats.isDirectory() && !existingLinkStats.isSymbolicLink(),
3381
+ });
3382
+ }
3383
+ catch (_a) {
3384
+ // The link does not exist yet.
3385
+ }
3386
+ await symlink(options.nodeModulesPath, nodeModulesLinkPath, process.platform === 'win32' ? 'junction' : 'dir');
3387
+ }
3388
+ /**
3389
+ * Reads and validates materialized runtime metadata.
3390
+ */
3391
+ async function readAgentsServerMaterializedRuntimeCache(materializedRuntimeRootPath) {
3392
+ try {
3393
+ const serializedRuntimeCache = await readFile(join(materializedRuntimeRootPath, AGENTS_SERVER_MATERIALIZED_RUNTIME_CACHE_FILENAME), 'utf-8');
3394
+ const runtimeCache = JSON.parse(serializedRuntimeCache);
3395
+ if (runtimeCache.version !== AGENTS_SERVER_BUILD_CACHE_VERSION ||
3396
+ typeof runtimeCache.sourceFingerprint !== 'string') {
3397
+ return undefined;
3398
+ }
3399
+ return runtimeCache;
3400
+ }
3401
+ catch (_a) {
3402
+ return undefined;
3403
+ }
3404
+ }
3405
+ /**
3406
+ * Persists the source fingerprint used for the materialized runtime copy.
3407
+ */
3408
+ async function writeAgentsServerMaterializedRuntimeCache(materializedRuntimeRootPath, sourceFingerprint) {
3409
+ const runtimeCache = {
3410
+ version: AGENTS_SERVER_BUILD_CACHE_VERSION,
3411
+ sourceFingerprint,
3412
+ };
3413
+ await writeFile(join(materializedRuntimeRootPath, AGENTS_SERVER_MATERIALIZED_RUNTIME_CACHE_FILENAME), `${JSON.stringify(runtimeCache, null, 4)}\n`, 'utf-8');
3414
+ }
3224
3415
  /**
3225
3416
  * Runs the finite Next production build used by local Agents Server commands.
3226
3417
  */
@@ -3345,6 +3536,41 @@ function resolveAgentsServerBuildOutputPath(options) {
3345
3536
  var _a;
3346
3537
  return resolve(options.appPath, ((_a = options.environment) === null || _a === void 0 ? void 0 : _a.NEXT_DIST_DIR) || DEFAULT_AGENTS_SERVER_NEXT_DIST_DIRECTORY_NAME);
3347
3538
  }
3539
+ /**
3540
+ * Returns true when the app path points at the project-local materialized runtime.
3541
+ */
3542
+ function isAgentsServerAppPathMaterialized(appPath) {
3543
+ const normalizedAppPath = appPath.replace(/\\/gu, '/');
3544
+ const normalizedMaterializedRuntimePath = resolvePromptbookTemporaryPath(process.cwd(), 'agents-server', 'runtime').replace(/\\/gu, '/');
3545
+ return normalizedAppPath.includes(normalizedMaterializedRuntimePath);
3546
+ }
3547
+ /**
3548
+ * Returns true when one path is nested below a `node_modules` segment.
3549
+ */
3550
+ function isPathInsideNodeModules(path) {
3551
+ return path.split(/[\\/]+/u).includes(NODE_MODULES_DIRECTORY_NAME);
3552
+ }
3553
+ /**
3554
+ * Resolves the dependency root that contains the installed Next CLI.
3555
+ */
3556
+ function resolveNodeModulesPath(nextCliPath) {
3557
+ const normalizedNextCliPath = nextCliPath.replace(/\\/gu, '/');
3558
+ const marker = `/${NODE_MODULES_DIRECTORY_NAME}/next/`;
3559
+ const markerIndex = normalizedNextCliPath.lastIndexOf(marker);
3560
+ if (markerIndex === -1) {
3561
+ return resolve(nextCliPath, '..', '..', '..');
3562
+ }
3563
+ return normalizedNextCliPath.slice(0, markerIndex + marker.length - '/next/'.length);
3564
+ }
3565
+ /**
3566
+ * Prepends one dependency root to `NODE_PATH` while preserving any existing value.
3567
+ */
3568
+ function mergeNodePath(nodeModulesPath, nodePath) {
3569
+ if (!nodePath) {
3570
+ return nodeModulesPath;
3571
+ }
3572
+ return `${nodeModulesPath}${delimiter}${nodePath}`;
3573
+ }
3348
3574
  /**
3349
3575
  * Returns true when one path exists as a regular file.
3350
3576
  */
@@ -35880,6 +36106,12 @@ const PTBK_AGENTS_SERVER_DATABASE_ENV = 'PTBK_AGENTS_SERVER_DATABASE';
35880
36106
  * @private internal constant of `ptbk agents-server`
35881
36107
  */
35882
36108
  const PTBK_AGENTS_SERVER_SQLITE_PATH_ENV = 'PTBK_AGENTS_SERVER_SQLITE_PATH';
36109
+ /**
36110
+ * Optional hostname used by the internal Next server.
36111
+ *
36112
+ * @private internal constant of `ptbk agents-server`
36113
+ */
36114
+ const PTBK_HOSTNAME_ENV = 'PTBK_HOSTNAME';
35883
36115
  /**
35884
36116
  * Entropy size for the local-only token shared by the CLI pump and the Next app.
35885
36117
  *
@@ -35911,7 +36143,7 @@ async function startAgentsServer(options) {
35911
36143
  };
35912
36144
  process.once('exit', processExitHandler);
35913
36145
  try {
35914
- const { nextCliPath } = await ensureAgentsServerBuild({
36146
+ const buildArtifacts = await ensureAgentsServerBuild({
35915
36147
  appPath: runtimePaths.appPath,
35916
36148
  environment: childEnvironment,
35917
36149
  isBuildForced: options.isBuildForced,
@@ -35931,17 +36163,22 @@ async function startAgentsServer(options) {
35931
36163
  });
35932
36164
  },
35933
36165
  });
36166
+ const runtimeChildEnvironment = createAgentsServerRuntimeEnvironment(childEnvironment, buildArtifacts.nodeModulesPath);
36167
+ const builtRuntimePaths = {
36168
+ ...runtimePaths,
36169
+ appPath: buildArtifacts.appPath,
36170
+ };
35934
36171
  nextServerProcess = startNextServer({
35935
- nextCliPath,
36172
+ nextCliPath: buildArtifacts.nextCliPath,
35936
36173
  options,
35937
- runtimePaths,
35938
- childEnvironment,
36174
+ runtimePaths: builtRuntimePaths,
36175
+ childEnvironment: runtimeChildEnvironment,
35939
36176
  logStreams,
35940
36177
  state,
35941
36178
  });
35942
36179
  stopUserChatJobWorkerPump = startUserChatJobWorkerPump({
35943
36180
  port: options.port,
35944
- environment: childEnvironment,
36181
+ environment: runtimeChildEnvironment,
35945
36182
  logStreams,
35946
36183
  state,
35947
36184
  });
@@ -35967,6 +36204,8 @@ async function startAgentsServer(options) {
35967
36204
  }
35968
36205
  /**
35969
36206
  * Loads launch-directory `.env` values without overriding explicit process environment.
36207
+ *
36208
+ * @private internal utility of `ptbk agents-server`
35970
36209
  */
35971
36210
  function loadAgentsServerProjectEnvironment(launchWorkingDirectory) {
35972
36211
  dotenv.config({ path: join(launchWorkingDirectory, AGENTS_SERVER_PROJECT_ENV_FILE_NAME) });
@@ -35991,8 +36230,15 @@ async function resolveAgentsServerRuntimePaths() {
35991
36230
  * Starts the production Next server and wires its logs into the foreground dashboard.
35992
36231
  */
35993
36232
  function startNextServer(options) {
36233
+ var _a;
35994
36234
  logRunnerEvent(options.logStreams.runner, 'Starting the Agents Server Next process.');
35995
- const commandProcess = spawn(process.execPath, [options.nextCliPath, 'start', '--port', String(options.options.port)], {
36235
+ const nextArguments = [options.nextCliPath, 'start', '--port', String(options.options.port)];
36236
+ const hostname = (_a = options.childEnvironment[PTBK_HOSTNAME_ENV]) === null || _a === void 0 ? void 0 : _a.trim();
36237
+ if (hostname) {
36238
+ nextArguments.push('--hostname', hostname);
36239
+ logRunnerEvent(options.logStreams.runner, `Binding Agents Server Next process to ${hostname}.`);
36240
+ }
36241
+ const commandProcess = spawn(process.execPath, nextArguments, {
35996
36242
  cwd: options.runtimePaths.appPath,
35997
36243
  env: options.childEnvironment,
35998
36244
  stdio: ['ignore', 'pipe', 'pipe'],
@@ -36324,6 +36570,7 @@ function $initializeAgentsServerBuildCommand(program) {
36324
36570
  command.description('Build the Agents Server Next app for later local startup');
36325
36571
  command.action(handleActionErrors(async () => {
36326
36572
  console.info(colors.gray('Building Promptbook Agents Server.'));
36573
+ loadAgentsServerProjectEnvironment(process.cwd());
36327
36574
  await ensureAgentsServerBuild({ isBuildForced: true });
36328
36575
  }));
36329
36576
  }
@@ -67356,6 +67603,38 @@ const SERVER_ENVIRONMENT = {
67356
67603
  * Global source-of-truth table for server routing and migration targeting.
67357
67604
  */
67358
67605
  const SERVER_REGISTRY_TABLE_NAME = '_Server';
67606
+ /**
67607
+ * Environment variable with comma-separated standalone server domains.
67608
+ */
67609
+ const SERVERS_ENV_NAME = 'SERVERS';
67610
+ /**
67611
+ * Stable timestamp used by virtual server records derived from environment variables.
67612
+ */
67613
+ const ENVIRONMENT_SERVER_TIMESTAMP = '1970-01-01T00:00:00.000Z';
67614
+ /**
67615
+ * Loads virtual server records from the comma-separated `SERVERS` environment variable.
67616
+ *
67617
+ * @returns Server records with deterministic table prefixes derived from normalized domains.
67618
+ */
67619
+ function listEnvironmentRegisteredServers() {
67620
+ const rawServers = process.env[SERVERS_ENV_NAME];
67621
+ if (!rawServers) {
67622
+ return [];
67623
+ }
67624
+ const normalizedDomains = uniqueStrings$1(rawServers
67625
+ .split(',')
67626
+ .map((server) => normalizeServerDomain(server))
67627
+ .filter((server) => Boolean(server)));
67628
+ return normalizedDomains.map((domain, index) => ({
67629
+ id: -(index + 1),
67630
+ name: domain,
67631
+ environment: SERVER_ENVIRONMENT.PRODUCTION,
67632
+ domain,
67633
+ tablePrefix: buildEnvironmentServerTablePrefix(domain),
67634
+ createdAt: ENVIRONMENT_SERVER_TIMESTAMP,
67635
+ updatedAt: ENVIRONMENT_SERVER_TIMESTAMP,
67636
+ }));
67637
+ }
67359
67638
  /**
67360
67639
  * Normalizes one raw `_Server` row and validates required fields.
67361
67640
  *
@@ -67476,6 +67755,39 @@ function hasHttpProtocol(value) {
67476
67755
  function isDefaultPortForProtocol(protocol, port) {
67477
67756
  return (protocol === 'http:' && port === '80') || (protocol === 'https:' && port === '443');
67478
67757
  }
67758
+ /**
67759
+ * Builds a deterministic table prefix from a normalized domain.
67760
+ *
67761
+ * @param domain - Normalized server domain.
67762
+ * @returns Prefix such as `server_www_example_com_`.
67763
+ */
67764
+ function buildEnvironmentServerTablePrefix(domain) {
67765
+ const prefixSuffix = domain
67766
+ .toLowerCase()
67767
+ .replace(/-/gu, '_dash_')
67768
+ .replace(/\./gu, '_')
67769
+ .replace(/:/gu, '_port_')
67770
+ .replace(/[^a-z0-9_]/gu, '_')
67771
+ .replace(/_+/gu, '_')
67772
+ .replace(/^_+|_+$/gu, '');
67773
+ return `server_${prefixSuffix}_`;
67774
+ }
67775
+ /**
67776
+ * Deduplicates non-empty strings while preserving input order.
67777
+ *
67778
+ * @param values - Raw string values.
67779
+ * @returns Unique non-empty strings.
67780
+ */
67781
+ function uniqueStrings$1(values) {
67782
+ const uniqueValues = [];
67783
+ for (const value of values) {
67784
+ if (!value || uniqueValues.includes(value)) {
67785
+ continue;
67786
+ }
67787
+ uniqueValues.push(value);
67788
+ }
67789
+ return uniqueValues;
67790
+ }
67479
67791
 
67480
67792
  /**
67481
67793
  * SQL query used to load all registered servers in a deterministic order.
@@ -67834,7 +68146,7 @@ async function resolveDatabaseMigrationRuntimeConfiguration(logger = console) {
67834
68146
  const client = await createPostgresClient(connectionString);
67835
68147
  try {
67836
68148
  await client.connect();
67837
- const registeredServers = await listRegisteredServersFromDatabase(client);
68149
+ const registeredServers = mergeRegisteredServers(await listRegisteredServersFromDatabase(client), listEnvironmentRegisteredServers());
67838
68150
  const hasExplicitDefaultPrefix = process.env[SUPABASE_TABLE_PREFIX_ENV_NAME] !== undefined;
67839
68151
  const configuredPrefixes = uniquePrefixes([
67840
68152
  ...(hasExplicitDefaultPrefix
@@ -67995,6 +68307,25 @@ function uniquePrefixes(prefixes) {
67995
68307
  }
67996
68308
  return result;
67997
68309
  }
68310
+ /**
68311
+ * Combines database and environment registry rows, keeping database rows authoritative.
68312
+ *
68313
+ * @param databaseServers - Persistent `_Server` rows.
68314
+ * @param environmentServers - Virtual rows derived from `SERVERS`.
68315
+ * @returns Merged rows without duplicate domains.
68316
+ */
68317
+ function mergeRegisteredServers(databaseServers, environmentServers) {
68318
+ const seenDomains = new Set(databaseServers.map((server) => server.domain));
68319
+ const mergedServers = [...databaseServers];
68320
+ for (const environmentServer of environmentServers) {
68321
+ if (seenDomains.has(environmentServer.domain)) {
68322
+ continue;
68323
+ }
68324
+ mergedServers.push(environmentServer);
68325
+ seenDomains.add(environmentServer.domain);
68326
+ }
68327
+ return mergedServers;
68328
+ }
67998
68329
  /**
67999
68330
  * Creates one PostgreSQL client using the lazily loaded `pg` package.
68000
68331
  *