@vercel/python 6.55.2 → 6.56.0

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 (2) hide show
  1. package/dist/index.js +650 -370
  2. package/package.json +5 -8
package/dist/index.js CHANGED
@@ -5032,12 +5032,29 @@ var import_fs20 = __toESM(require("fs"));
5032
5032
  var import_path21 = require("path");
5033
5033
 
5034
5034
  // src/package-versions.ts
5035
- var VERCEL_RUNTIME_VERSION = "0.18.0";
5035
+ var VERCEL_RUNTIME_VERSION = "0.19.0";
5036
5036
  var VERCEL_WORKERS_VERSION = "0.0.25";
5037
5037
 
5038
5038
  // src/conditional-vendoring.ts
5039
5039
  var import_python_analysis = require("@vercel/python-analysis");
5040
5040
  var UPSTREAM_DEPENDENCY_ADAPTERS = /* @__PURE__ */ new Map([
5041
+ [
5042
+ "apscheduler",
5043
+ {
5044
+ bundled: "vercel-apscheduler-bundle",
5045
+ unbundled: "vercel-apscheduler",
5046
+ envOverride: "VERCEL_PYTHON_APSCHEDULER_DEPENDENCY",
5047
+ preferUnbundledWhenPresent: ["vercel-queue"],
5048
+ integration: {
5049
+ module: "vercel.integrations.apscheduler",
5050
+ installer: "install_vercel_apscheduler_integration",
5051
+ // APScheduler jobs are declared while the subscriber module imports.
5052
+ // Install first so the adapter can capture those definitions.
5053
+ installBeforeImport: true,
5054
+ subscriberProbe: "is_scheduler_subscriber"
5055
+ }
5056
+ }
5057
+ ],
5041
5058
  [
5042
5059
  "celery",
5043
5060
  {
@@ -5069,31 +5086,26 @@ var UPSTREAM_DEPENDENCY_ADAPTERS = /* @__PURE__ */ new Map([
5069
5086
  }
5070
5087
  ]
5071
5088
  ]);
5072
- async function getQueueIntegrations({
5073
- pythonPackage
5089
+ async function getQueueAdapterBootstrap({
5090
+ pythonPackage,
5091
+ env,
5092
+ legacyWorkersProject,
5093
+ hasDeclaredSubscribers
5074
5094
  }) {
5075
- const dependencies = await getDirectDependencyNames(pythonPackage);
5076
- if (!dependencies)
5077
- return [];
5078
5095
  const integrations = [];
5079
- for (const [upstream, adapter] of UPSTREAM_DEPENDENCY_ADAPTERS) {
5080
- if (dependencies.has(upstream)) {
5081
- integrations.push(adapter.integration);
5082
- }
5096
+ const injectedPackages = [];
5097
+ const bootstrap = { integrations, injectedPackages };
5098
+ if (legacyWorkersProject || !hasDeclaredSubscribers) {
5099
+ return bootstrap;
5083
5100
  }
5084
- return integrations;
5085
- }
5086
- async function getConditionalInjectedPackages({
5087
- pythonPackage,
5088
- env
5089
- }) {
5090
5101
  const dependencies = await getDirectDependencyNames(pythonPackage);
5091
- if (!dependencies)
5092
- return [];
5093
- const injectedPackages = [];
5102
+ if (!dependencies) {
5103
+ return bootstrap;
5104
+ }
5094
5105
  for (const [upstream, adapter] of UPSTREAM_DEPENDENCY_ADAPTERS) {
5095
5106
  if (!dependencies.has(upstream))
5096
5107
  continue;
5108
+ integrations.push(adapter.integration);
5097
5109
  if (dependencies.has(adapter.bundled) || dependencies.has(adapter.unbundled)) {
5098
5110
  continue;
5099
5111
  }
@@ -5107,7 +5119,7 @@ async function getConditionalInjectedPackages({
5107
5119
  allowLocalSource: false
5108
5120
  });
5109
5121
  }
5110
- return injectedPackages;
5122
+ return bootstrap;
5111
5123
  }
5112
5124
  async function getDirectDependencyNames(pythonPackage) {
5113
5125
  const dependencies = pythonPackage?.manifest?.data?.project?.dependencies;
@@ -7962,23 +7974,24 @@ function moduleColonFuncToCronPath(serviceName, moduleFunction) {
7962
7974
 
7963
7975
  // src/start-dev-server.ts
7964
7976
  var import_child_process2 = require("child_process");
7965
- var import_fs12 = require("fs");
7966
- var import_path12 = require("path");
7967
- var import_build_utils14 = require("@vercel/build-utils");
7977
+ var import_fs13 = require("fs");
7978
+ var import_path13 = require("path");
7979
+ var import_build_utils15 = require("@vercel/build-utils");
7968
7980
  var import_get_port = __toESM(require_get_port());
7969
7981
  var import_is_port_reachable = __toESM(require_is_port_reachable());
7970
7982
  var import_python_analysis8 = require("@vercel/python-analysis");
7971
7983
 
7972
7984
  // src/subscribers.ts
7973
- var import_path11 = require("path");
7974
- var import_fs11 = __toESM(require("fs"));
7985
+ var import_path12 = require("path");
7986
+ var import_fs12 = __toESM(require("fs"));
7975
7987
  var import_execa6 = __toESM(require_execa());
7976
- var import_build_utils13 = require("@vercel/build-utils");
7988
+ var import_build_utils14 = require("@vercel/build-utils");
7977
7989
 
7978
7990
  // src/module-entrypoint.ts
7979
7991
  var import_path10 = require("path");
7980
7992
  var import_fs10 = __toESM(require("fs"));
7981
7993
  var MODULE_ATTR_RE = /^([A-Za-z_][\w]*(?:\.[A-Za-z_][\w]*)*):([A-Za-z_][\w]*)$/;
7994
+ var MODULE_RE = /^[A-Za-z_][\w]*(?:\.[A-Za-z_][\w]*)*$/;
7982
7995
  function parseModuleEntrypoint(value) {
7983
7996
  const match = MODULE_ATTR_RE.exec(value);
7984
7997
  if (!match) {
@@ -7990,11 +8003,21 @@ function parseModuleEntrypoint(value) {
7990
8003
  filePath: `${match[1].replace(/\./g, "/")}.py`
7991
8004
  };
7992
8005
  }
8006
+ function parseBareModuleEntrypoint(value) {
8007
+ if (!MODULE_RE.test(value)) {
8008
+ return null;
8009
+ }
8010
+ return {
8011
+ moduleName: value,
8012
+ filePath: `${value.replace(/\./g, "/")}.py`
8013
+ };
8014
+ }
7993
8015
  function getModuleEntrypointName({
7994
8016
  moduleName,
7995
8017
  variableName
7996
8018
  }) {
7997
- return `${moduleName.replace(/\./g, "-")}_${variableName}`;
8019
+ const base = moduleName.replace(/\./g, "-");
8020
+ return variableName === void 0 ? base : `${base}_${variableName}`;
7998
8021
  }
7999
8022
  function safePathSegment(value) {
8000
8023
  return [...value].map((char) => {
@@ -8018,8 +8041,97 @@ async function resolveExistingEntrypoint(workPath, filePath) {
8018
8041
  return null;
8019
8042
  }
8020
8043
 
8044
+ // src/workflows.ts
8045
+ var import_path11 = require("path");
8046
+ var import_fs11 = __toESM(require("fs"));
8047
+ var import_build_utils13 = require("@vercel/build-utils");
8048
+ var WORKFLOW_OUTPUT_DIR = "_py_workflows";
8049
+ var WORKFLOW_TOPIC_PATTERN = "__wkf_*";
8050
+ var WORKFLOW_DEV_TOPIC_PATTERN = "__*wkf_*";
8051
+ var WORKFLOW_QUEUE_TOPIC_RE = /^__(?:[a-z][a-z0-9]*_)?wkf_/;
8052
+ function isWorkflowQueueTopic(topic) {
8053
+ return WORKFLOW_QUEUE_TOPIC_RE.test(topic);
8054
+ }
8055
+ var WORKFLOW_FIELD_NAMES = /* @__PURE__ */ new Set(["entrypoint"]);
8056
+ function getWorkflowOutputPath(workflowName) {
8057
+ return `${WORKFLOW_OUTPUT_DIR}/${safePathSegment(workflowName)}`;
8058
+ }
8059
+ function getWorkflowConsumerName(workflowName) {
8060
+ return (0, import_build_utils13.sanitizeConsumerName)(getWorkflowOutputPath(workflowName));
8061
+ }
8062
+ async function getPyprojectWorkflows(workPath) {
8063
+ const pyprojectPath = (0, import_path11.join)(workPath, "pyproject.toml");
8064
+ if (!import_fs11.default.existsSync(pyprojectPath)) {
8065
+ return [];
8066
+ }
8067
+ const pyproject = await (0, import_build_utils13.readConfigFile)(pyprojectPath);
8068
+ const workflows = pyproject?.tool?.vercel?.workflows;
8069
+ if (!workflows) {
8070
+ return [];
8071
+ }
8072
+ if (!Array.isArray(workflows)) {
8073
+ throw workflowError('"tool.vercel.workflows" must be an array');
8074
+ }
8075
+ const parsedWorkflows = await Promise.all(
8076
+ workflows.map((config, index) => parseWorkflow(workPath, index, config))
8077
+ );
8078
+ const seenNames = /* @__PURE__ */ new Set();
8079
+ for (const workflow of parsedWorkflows) {
8080
+ if (seenNames.has(workflow.name)) {
8081
+ throw workflowError(
8082
+ `workflow "${workflow.name}" is declared more than once`
8083
+ );
8084
+ }
8085
+ seenNames.add(workflow.name);
8086
+ }
8087
+ return parsedWorkflows;
8088
+ }
8089
+ async function parseWorkflow(workPath, index, config) {
8090
+ const label = `workflow #${index + 1}`;
8091
+ if (!config || typeof config !== "object" || Array.isArray(config)) {
8092
+ throw workflowError(`${label} must be an object`);
8093
+ }
8094
+ for (const key of Object.keys(config)) {
8095
+ if (!WORKFLOW_FIELD_NAMES.has(key)) {
8096
+ throw workflowError(`${label} has unrecognized field "${key}"`);
8097
+ }
8098
+ }
8099
+ if (typeof config.entrypoint !== "string") {
8100
+ throw workflowError(`${label} must define string field "entrypoint"`);
8101
+ }
8102
+ const entrypoint = parseModuleEntrypoint(config.entrypoint);
8103
+ if (!entrypoint) {
8104
+ throw workflowError(
8105
+ `${label} has invalid entrypoint "${config.entrypoint}". Use "module:object"`
8106
+ );
8107
+ }
8108
+ const name = getModuleEntrypointName(entrypoint);
8109
+ const existingEntrypoint = await resolveExistingEntrypoint(
8110
+ workPath,
8111
+ entrypoint.filePath
8112
+ );
8113
+ if (!existingEntrypoint) {
8114
+ throw workflowError(
8115
+ `workflow "${name}" has entrypoint "${config.entrypoint}" but file "${entrypoint.filePath}" does not exist`
8116
+ );
8117
+ }
8118
+ return {
8119
+ name,
8120
+ entrypoint: existingEntrypoint,
8121
+ moduleName: entrypoint.moduleName,
8122
+ variableName: entrypoint.variableName
8123
+ };
8124
+ }
8125
+ function workflowError(message) {
8126
+ return new import_build_utils13.NowBuildError({
8127
+ code: "PYTHON_INVALID_WORKFLOW_CONFIG",
8128
+ message
8129
+ });
8130
+ }
8131
+
8021
8132
  // src/subscribers.ts
8022
8133
  var SUBSCRIBER_OUTPUT_DIR = "_py_subscribers";
8134
+ var SUBSCRIBER_ID_ENV = "VERCEL_PYTHON_SUBSCRIBER_ID";
8023
8135
  var TRIGGER_NUMBER_FIELDS = [
8024
8136
  {
8025
8137
  field: "max_attempts",
@@ -8078,11 +8190,18 @@ var LEGACY_SUBSCRIBER_FIELD_NAMES = /* @__PURE__ */ new Set([
8078
8190
  "topics",
8079
8191
  ...LEGACY_TRIGGER_NUMBER_FIELDS.map(({ field }) => field)
8080
8192
  ]);
8193
+ var APSCHEDULER_PREVIEW_FIELD_NAMES = /* @__PURE__ */ new Set(["enabled", "idle_timeout"]);
8194
+ var APSCHEDULER_DURATION_UNITS = {
8195
+ s: 1,
8196
+ m: 60,
8197
+ h: 60 * 60,
8198
+ d: 24 * 60 * 60
8199
+ };
8081
8200
  function getSubscriberOutputPath(subscriberName) {
8082
8201
  return `${SUBSCRIBER_OUTPUT_DIR}/${safePathSegment(subscriberName)}`;
8083
8202
  }
8084
8203
  function getSubscriberConsumerName(subscriberName) {
8085
- return (0, import_build_utils13.sanitizeConsumerName)(getSubscriberOutputPath(subscriberName));
8204
+ return (0, import_build_utils14.sanitizeConsumerName)(getSubscriberOutputPath(subscriberName));
8086
8205
  }
8087
8206
  function getGeneratedQueueHandlerPath(outputPath) {
8088
8207
  return `_vc_queue_handlers/${outputPath.replace(/[^A-Za-z0-9_]+/g, "_")}.py`;
@@ -8090,12 +8209,21 @@ function getGeneratedQueueHandlerPath(outputPath) {
8090
8209
  function generatedPythonPathToModule(filePath) {
8091
8210
  return filePath.replace(/\.py$/, "").split(/[\\/]+/).join(".");
8092
8211
  }
8212
+ async function hasPyprojectSubscribers(workPath) {
8213
+ const pyprojectPath = (0, import_path12.join)(workPath, "pyproject.toml");
8214
+ if (!import_fs12.default.existsSync(pyprojectPath)) {
8215
+ return false;
8216
+ }
8217
+ const pyproject = await (0, import_build_utils14.readConfigFile)(pyprojectPath);
8218
+ const subscribers = pyproject?.tool?.vercel?.subscribers;
8219
+ return Array.isArray(subscribers) && subscribers.length > 0;
8220
+ }
8093
8221
  async function getPyprojectSubscribers(workPath, { legacySchema = false } = {}) {
8094
- const pyprojectPath = (0, import_path11.join)(workPath, "pyproject.toml");
8095
- if (!import_fs11.default.existsSync(pyprojectPath)) {
8222
+ const pyprojectPath = (0, import_path12.join)(workPath, "pyproject.toml");
8223
+ if (!import_fs12.default.existsSync(pyprojectPath)) {
8096
8224
  return [];
8097
8225
  }
8098
- const pyproject = await (0, import_build_utils13.readConfigFile)(pyprojectPath);
8226
+ const pyproject = await (0, import_build_utils14.readConfigFile)(pyprojectPath);
8099
8227
  const subscribers = pyproject?.tool?.vercel?.subscribers;
8100
8228
  if (!subscribers) {
8101
8229
  return [];
@@ -8119,6 +8247,63 @@ async function getPyprojectSubscribers(workPath, { legacySchema = false } = {})
8119
8247
  }
8120
8248
  return parsedSubscribers;
8121
8249
  }
8250
+ async function getApschedulerPreviewConfig(workPath) {
8251
+ const pyprojectPath = (0, import_path12.join)(workPath, "pyproject.toml");
8252
+ if (!import_fs12.default.existsSync(pyprojectPath)) {
8253
+ return void 0;
8254
+ }
8255
+ const pyproject = await (0, import_build_utils14.readConfigFile)(pyprojectPath);
8256
+ const apscheduler = pyproject?.tool?.vercel?.apscheduler;
8257
+ if (apscheduler === void 0) {
8258
+ return void 0;
8259
+ }
8260
+ if (!apscheduler || typeof apscheduler !== "object" || Array.isArray(apscheduler)) {
8261
+ throw apschedulerError('"tool.vercel.apscheduler" must be a table');
8262
+ }
8263
+ const previews = apscheduler.previews;
8264
+ if (previews === void 0) {
8265
+ return void 0;
8266
+ }
8267
+ if (!previews || typeof previews !== "object" || Array.isArray(previews)) {
8268
+ throw apschedulerError(
8269
+ '"tool.vercel.apscheduler.previews" must be a table'
8270
+ );
8271
+ }
8272
+ const rawPreviews = previews;
8273
+ for (const key of Object.keys(rawPreviews)) {
8274
+ if (!APSCHEDULER_PREVIEW_FIELD_NAMES.has(key)) {
8275
+ throw apschedulerError(
8276
+ `"tool.vercel.apscheduler.previews" has unrecognized field "${key}"`
8277
+ );
8278
+ }
8279
+ }
8280
+ if (rawPreviews.enabled !== void 0 && typeof rawPreviews.enabled !== "boolean") {
8281
+ throw apschedulerError(
8282
+ '"tool.vercel.apscheduler.previews.enabled" must be a boolean'
8283
+ );
8284
+ }
8285
+ if (rawPreviews.enabled !== true) {
8286
+ return void 0;
8287
+ }
8288
+ if (typeof rawPreviews.idle_timeout !== "string") {
8289
+ throw apschedulerError(
8290
+ '"tool.vercel.apscheduler.previews.idle_timeout" must be a duration such as "30m"'
8291
+ );
8292
+ }
8293
+ const match = /^([1-9]\d*)([smhd])$/.exec(rawPreviews.idle_timeout);
8294
+ if (!match) {
8295
+ throw apschedulerError(
8296
+ '"tool.vercel.apscheduler.previews.idle_timeout" must be a positive duration using s, m, h, or d (for example "30m")'
8297
+ );
8298
+ }
8299
+ const idleTimeoutSeconds = Number(match[1]) * APSCHEDULER_DURATION_UNITS[match[2]];
8300
+ if (!Number.isSafeInteger(idleTimeoutSeconds)) {
8301
+ throw apschedulerError(
8302
+ '"tool.vercel.apscheduler.previews.idle_timeout" is too large'
8303
+ );
8304
+ }
8305
+ return { idleTimeoutSeconds };
8306
+ }
8122
8307
  async function resolveQueueSubscribers({
8123
8308
  declarations,
8124
8309
  uv,
@@ -8140,10 +8325,12 @@ async function resolveQueueSubscribers({
8140
8325
  const hint = kind === "workflow" ? "; ensure the entrypoint instantiates vercel.workflow.Workflows" : "";
8141
8326
  const unmatchedTopicPatterns = getUnmatchedQueueTopicPatterns(
8142
8327
  declaration,
8143
- introspected
8328
+ introspected.subscriptions
8144
8329
  );
8145
8330
  if (unmatchedTopicPatterns.length > 0) {
8146
- const introspectedTopics = introspected.map(({ topic }) => topic);
8331
+ const introspectedTopics = introspected.subscriptions.map(
8332
+ ({ topic }) => topic
8333
+ );
8147
8334
  throw subscriberError(
8148
8335
  `${kind} "${declaration.name}" declared topics [${unmatchedTopicPatterns.join(
8149
8336
  ", "
@@ -8152,14 +8339,21 @@ async function resolveQueueSubscribers({
8152
8339
  )}]${hint}`
8153
8340
  );
8154
8341
  }
8155
- const subscriptions = filterQueueSubscriptions(declaration, introspected);
8342
+ const subscriptions = kind === "workflow" ? introspected.subscriptions.filter(
8343
+ (subscription) => isWorkflowQueueTopic(subscription.topic)
8344
+ ) : filterQueueSubscriptions(declaration, introspected.subscriptions);
8156
8345
  if (subscriptions.length === 0) {
8346
+ if (kind === "workflow") {
8347
+ throw subscriberError(
8348
+ `workflow "${declaration.name}" registered no workflow queue subscriptions${hint}`
8349
+ );
8350
+ }
8157
8351
  const declared = declaration.topicPatterns?.join(", ") ?? "*";
8158
8352
  throw subscriberError(
8159
8353
  `${kind} "${declaration.name}" declared topics [${declared}] but no introspected queue subscriptions matched${hint}`
8160
8354
  );
8161
8355
  }
8162
- result.push({ ...declaration, subscriptions });
8356
+ result.push({ ...declaration, subscriptions, owners: introspected.owners });
8163
8357
  }
8164
8358
  return result;
8165
8359
  }
@@ -8212,8 +8406,10 @@ function createIntegrationInstallLines(integrations, { serving, beforeImport })
8212
8406
  function createQueueHandlerModule(declaration, integrations) {
8213
8407
  return [
8214
8408
  "import importlib",
8409
+ "import os",
8215
8410
  "import vercel.queue",
8216
8411
  "",
8412
+ `os.environ[${JSON.stringify(SUBSCRIBER_ID_ENV)}] = ${JSON.stringify(declaration.name)}`,
8217
8413
  ...createIntegrationInstallLines(integrations, {
8218
8414
  serving: true,
8219
8415
  beforeImport: true
@@ -8227,14 +8423,22 @@ function createQueueHandlerModule(declaration, integrations) {
8227
8423
  ""
8228
8424
  ].join("\n");
8229
8425
  }
8230
- async function parseSubscriberEntrypoint(workPath, label, entrypointValue) {
8426
+ async function parseSubscriberEntrypoint(workPath, label, entrypointValue, { requireVariable }) {
8231
8427
  if (typeof entrypointValue !== "string") {
8232
8428
  throw subscriberError(`${label} must define string field "entrypoint"`);
8233
8429
  }
8234
- const entrypoint = parseModuleEntrypoint(entrypointValue);
8430
+ if (!requireVariable && /\.py$/i.test(entrypointValue)) {
8431
+ const suggestion = parseBareModuleEntrypoint(
8432
+ entrypointValue.slice(0, -3).replace(/[\\/]+/g, ".").replace(/(^|\.)__init__$/, "")
8433
+ );
8434
+ throw subscriberError(
8435
+ `${label} has invalid entrypoint "${entrypointValue}". Use an import path, not a file path${suggestion ? `: "${suggestion.moduleName}"` : ""}`
8436
+ );
8437
+ }
8438
+ const entrypoint = parseModuleEntrypoint(entrypointValue) ?? (requireVariable ? null : parseBareModuleEntrypoint(entrypointValue));
8235
8439
  if (!entrypoint) {
8236
8440
  throw subscriberError(
8237
- `${label} has invalid entrypoint "${entrypointValue}". Use "module:object"`
8441
+ `${label} has invalid entrypoint "${entrypointValue}". Use ${requireVariable ? '"module:object"' : '"module:object" or a module path like "pkg.module"'}`
8238
8442
  );
8239
8443
  }
8240
8444
  const name = getModuleEntrypointName(entrypoint);
@@ -8247,11 +8451,12 @@ async function parseSubscriberEntrypoint(workPath, label, entrypointValue) {
8247
8451
  `subscriber "${name}" has entrypoint "${entrypointValue}" but file "${entrypoint.filePath}" does not exist`
8248
8452
  );
8249
8453
  }
8454
+ const { variableName } = entrypoint;
8250
8455
  return {
8251
8456
  name,
8252
8457
  entrypoint: existingEntrypoint,
8253
8458
  moduleName: entrypoint.moduleName,
8254
- variableName: entrypoint.variableName
8459
+ ...variableName === void 0 ? {} : { variableName }
8255
8460
  };
8256
8461
  }
8257
8462
  async function parseSubscriber(workPath, index, config) {
@@ -8267,7 +8472,8 @@ async function parseSubscriber(workPath, index, config) {
8267
8472
  const base = await parseSubscriberEntrypoint(
8268
8473
  workPath,
8269
8474
  label,
8270
- config.entrypoint
8475
+ config.entrypoint,
8476
+ { requireVariable: false }
8271
8477
  );
8272
8478
  return {
8273
8479
  ...base,
@@ -8287,7 +8493,8 @@ async function parseLegacySubscriber(workPath, index, config) {
8287
8493
  const base = await parseSubscriberEntrypoint(
8288
8494
  workPath,
8289
8495
  label,
8290
- config.entrypoint
8496
+ config.entrypoint,
8497
+ { requireVariable: true }
8291
8498
  );
8292
8499
  return {
8293
8500
  ...base,
@@ -8351,14 +8558,26 @@ function parseTopicPatterns(name, value) {
8351
8558
  }
8352
8559
  return value;
8353
8560
  }
8354
- function createQueueIntrospectionScript(moduleName, integrations) {
8561
+ function createQueueIntrospectionScript(declaration, integrations) {
8562
+ const { variableName } = declaration;
8563
+ const probeLines = variableName === void 0 ? [] : integrations.filter((integration) => integration.subscriberProbe).flatMap(({ module: module2, subscriberProbe }) => [
8564
+ "try:",
8565
+ ` from ${module2} import ${subscriberProbe}`,
8566
+ "except ImportError:",
8567
+ " pass",
8568
+ "else:",
8569
+ ` if ${subscriberProbe}(${JSON.stringify(declaration.moduleName)}, ${JSON.stringify(variableName)}):`,
8570
+ ` owners.append(${JSON.stringify(module2)})`
8571
+ ]);
8355
8572
  return [
8356
- "import importlib, json, sys",
8573
+ "import importlib, json, os, sys",
8574
+ `os.environ[${JSON.stringify(SUBSCRIBER_ID_ENV)}] = ${JSON.stringify(declaration.name)}`,
8575
+ 'os.environ["VERCEL_APSCHEDULER_DISCOVERY"] = "1"',
8357
8576
  ...createIntegrationInstallLines(integrations, {
8358
8577
  serving: false,
8359
8578
  beforeImport: true
8360
8579
  }),
8361
- `importlib.import_module(${JSON.stringify(moduleName)})`,
8580
+ `importlib.import_module(${JSON.stringify(declaration.moduleName)})`,
8362
8581
  ...createIntegrationInstallLines(integrations, {
8363
8582
  serving: false,
8364
8583
  beforeImport: false
@@ -8375,7 +8594,9 @@ function createQueueIntrospectionScript(moduleName, integrations) {
8375
8594
  " }.items() if v is not None}",
8376
8595
  " for s in get_subscriptions()",
8377
8596
  "]",
8378
- "json.dump(subs, sys.stdout)"
8597
+ "owners = []",
8598
+ ...probeLines,
8599
+ "json.dump({'subscriptions': subs, 'owners': owners}, sys.stdout)"
8379
8600
  ].join("\n");
8380
8601
  }
8381
8602
  async function introspectQueueSubscriptions({
@@ -8386,10 +8607,7 @@ async function introspectQueueSubscriptions({
8386
8607
  kind,
8387
8608
  integrations
8388
8609
  }) {
8389
- const script3 = createQueueIntrospectionScript(
8390
- declaration.moduleName,
8391
- integrations
8392
- );
8610
+ const script3 = createQueueIntrospectionScript(declaration, integrations);
8393
8611
  try {
8394
8612
  const { stdout } = await uv.run({
8395
8613
  venvPath,
@@ -8410,7 +8628,7 @@ async function introspectQueueSubscriptions({
8410
8628
  });
8411
8629
  return parseIntrospectedSubscriptions(kind, declaration.name, stdout);
8412
8630
  } catch (err) {
8413
- if (err instanceof import_build_utils13.NowBuildError) {
8631
+ if (err instanceof import_build_utils14.NowBuildError) {
8414
8632
  throw err;
8415
8633
  }
8416
8634
  const message = err instanceof Error ? err.message : String(err);
@@ -8421,6 +8639,8 @@ async function introspectQueueSubscriptions({
8421
8639
  }
8422
8640
  async function introspectDevQueueSubscriptions({
8423
8641
  moduleName,
8642
+ subscriberName,
8643
+ variableName,
8424
8644
  pythonBin,
8425
8645
  cwd,
8426
8646
  env,
@@ -8429,7 +8649,13 @@ async function introspectDevQueueSubscriptions({
8429
8649
  try {
8430
8650
  const { stdout } = await (0, import_execa6.default)(
8431
8651
  pythonBin,
8432
- ["-c", createQueueIntrospectionScript(moduleName, integrations)],
8652
+ [
8653
+ "-c",
8654
+ createQueueIntrospectionScript(
8655
+ { moduleName, name: subscriberName, variableName },
8656
+ integrations
8657
+ )
8658
+ ],
8433
8659
  // Match the deployed-function environment (see
8434
8660
  // introspectQueueSubscriptions): SDKs may need VERCEL=1,
8435
8661
  // VERCEL_REGION, and VERCEL_DEPLOYMENT_ID to register subscriptions.
@@ -8443,12 +8669,12 @@ async function introspectDevQueueSubscriptions({
8443
8669
  }
8444
8670
  }
8445
8671
  );
8446
- const subscriptions = parseIntrospectedSubscriptions(
8672
+ const introspected = parseIntrospectedSubscriptions(
8447
8673
  "subscriber",
8448
8674
  moduleName,
8449
8675
  stdout
8450
8676
  );
8451
- return subscriptions.map((subscription) => {
8677
+ const subscriptions = introspected.subscriptions.map((subscription) => {
8452
8678
  const { retryAfterSeconds, initialDelaySeconds, maxDeliveries } = subscription.triggerDefaults;
8453
8679
  return {
8454
8680
  topic: subscription.topic,
@@ -8458,8 +8684,9 @@ async function introspectDevQueueSubscriptions({
8458
8684
  ...maxDeliveries === void 0 ? {} : { maxDeliveries }
8459
8685
  };
8460
8686
  });
8687
+ return { subscriptions, owners: introspected.owners };
8461
8688
  } catch (err) {
8462
- (0, import_build_utils13.debug)(
8689
+ (0, import_build_utils14.debug)(
8463
8690
  `Failed to introspect dev queue subscriptions for module "${moduleName}": ${err instanceof Error ? err.message : String(err)}`
8464
8691
  );
8465
8692
  return void 0;
@@ -8474,14 +8701,28 @@ function parseIntrospectedSubscriptions(kind, subscriberName, stdout) {
8474
8701
  `${kind} "${subscriberName}" queue introspection did not return valid JSON`
8475
8702
  );
8476
8703
  }
8477
- if (!Array.isArray(parsed)) {
8704
+ if (!parsed || typeof parsed !== "object" || Array.isArray(parsed)) {
8478
8705
  throw subscriberError(
8479
- `${kind} "${subscriberName}" queue introspection must return an array`
8706
+ `${kind} "${subscriberName}" queue introspection must return an object`
8480
8707
  );
8481
8708
  }
8482
- return parsed.map(
8483
- (subscription, index) => parseIntrospectedSubscription(kind, subscriberName, index, subscription)
8484
- );
8709
+ const { subscriptions, owners = [] } = parsed;
8710
+ if (!Array.isArray(subscriptions)) {
8711
+ throw subscriberError(
8712
+ `${kind} "${subscriberName}" queue introspection must return a "subscriptions" array`
8713
+ );
8714
+ }
8715
+ if (!Array.isArray(owners) || owners.some((o) => typeof o !== "string")) {
8716
+ throw subscriberError(
8717
+ `${kind} "${subscriberName}" queue introspection "owners" must be an array of strings`
8718
+ );
8719
+ }
8720
+ return {
8721
+ subscriptions: subscriptions.map(
8722
+ (subscription, index) => parseIntrospectedSubscription(kind, subscriberName, index, subscription)
8723
+ ),
8724
+ owners
8725
+ };
8485
8726
  }
8486
8727
  function parseIntrospectedSubscription(kind, subscriberName, index, value) {
8487
8728
  const label = `${kind} "${subscriberName}" introspected subscription #${index + 1}`;
@@ -8525,12 +8766,27 @@ function getQueueWildcardPrefix(pattern) {
8525
8766
  }
8526
8767
  return void 0;
8527
8768
  }
8769
+ var APSCHEDULER_INTEGRATION_MODULE = "vercel.integrations.apscheduler";
8770
+ function apschedulerSubscriberIdentities(subscribers) {
8771
+ return subscribers.filter(
8772
+ (subscriber) => subscriber.owners.includes(APSCHEDULER_INTEGRATION_MODULE)
8773
+ ).map((subscriber) => ({
8774
+ id: subscriber.name,
8775
+ entrypoint: `${subscriber.moduleName}:${subscriber.variableName}`
8776
+ }));
8777
+ }
8528
8778
  function subscriberError(message) {
8529
- return new import_build_utils13.NowBuildError({
8779
+ return new import_build_utils14.NowBuildError({
8530
8780
  code: "PYTHON_INVALID_SUBSCRIBER_CONFIG",
8531
8781
  message
8532
8782
  });
8533
8783
  }
8784
+ function apschedulerError(message) {
8785
+ return new import_build_utils14.NowBuildError({
8786
+ code: "PYTHON_INVALID_APSCHEDULER_CONFIG",
8787
+ message
8788
+ });
8789
+ }
8534
8790
 
8535
8791
  // src/start-dev-server.ts
8536
8792
  var DEV_SERVER_STARTUP_TIMEOUT = 5 * 6e4;
@@ -8631,17 +8887,17 @@ async function syncDependencies({
8631
8887
  let { manifestPath } = installInfo;
8632
8888
  const manifest = pythonPackage.manifest;
8633
8889
  if (!manifestType || !manifestPath) {
8634
- (0, import_build_utils14.debug)("No Python project manifest found, skipping dependency sync");
8890
+ (0, import_build_utils15.debug)("No Python project manifest found, skipping dependency sync");
8635
8891
  return;
8636
8892
  }
8637
8893
  if (manifest?.origin && manifestType === "pyproject.toml") {
8638
- const syncDir = (0, import_path12.join)(workPath, ".vercel", "python", "sync");
8639
- (0, import_fs12.mkdirSync)(syncDir, { recursive: true });
8640
- const tempPyproject = (0, import_path12.join)(syncDir, "pyproject.toml");
8894
+ const syncDir = (0, import_path13.join)(workPath, ".vercel", "python", "sync");
8895
+ (0, import_fs13.mkdirSync)(syncDir, { recursive: true });
8896
+ const tempPyproject = (0, import_path13.join)(syncDir, "pyproject.toml");
8641
8897
  const content = (0, import_python_analysis8.stringifyManifest)(manifest.data);
8642
- (0, import_fs12.writeFileSync)(tempPyproject, content, "utf8");
8898
+ (0, import_fs13.writeFileSync)(tempPyproject, content, "utf8");
8643
8899
  manifestPath = tempPyproject;
8644
- (0, import_build_utils14.debug)(
8900
+ (0, import_build_utils15.debug)(
8645
8901
  `Wrote converted ${manifest.origin.kind} manifest to ${tempPyproject}`
8646
8902
  );
8647
8903
  }
@@ -8674,7 +8930,7 @@ async function syncDependencies({
8674
8930
  for (const [channel, chunk] of captured) {
8675
8931
  (channel === "stdout" ? writeOut : writeErr)(chunk.toString());
8676
8932
  }
8677
- throw new import_build_utils14.NowBuildError({
8933
+ throw new import_build_utils15.NowBuildError({
8678
8934
  code: "PYTHON_DEPENDENCY_SYNC_FAILED",
8679
8935
  message: `Failed to install Python dependencies from ${manifestType}: ${err instanceof Error ? err.message : String(err)}`
8680
8936
  });
@@ -8689,14 +8945,14 @@ async function runSync({
8689
8945
  onStdout,
8690
8946
  onStderr
8691
8947
  }) {
8692
- const projectDir = (0, import_path12.dirname)(manifestPath);
8948
+ const projectDir = (0, import_path13.dirname)(manifestPath);
8693
8949
  const pip = uvPath ? { cmd: uvPath, prefix: ["pip", "install"] } : { cmd: pythonBin, prefix: ["-m", "pip", "install"] };
8694
8950
  let spawnCmd;
8695
8951
  let spawnArgs;
8696
8952
  switch (manifestType) {
8697
8953
  case "uv.lock": {
8698
8954
  if (!uvPath) {
8699
- throw new import_build_utils14.NowBuildError({
8955
+ throw new import_build_utils15.NowBuildError({
8700
8956
  code: "PYTHON_DEPENDENCY_SYNC_FAILED",
8701
8957
  message: "uv is required to install dependencies from uv.lock.",
8702
8958
  link: "https://docs.astral.sh/uv/getting-started/installation/",
@@ -8718,11 +8974,11 @@ async function runSync({
8718
8974
  break;
8719
8975
  }
8720
8976
  default:
8721
- (0, import_build_utils14.debug)(`Unknown manifest type: ${manifestType}`);
8977
+ (0, import_build_utils15.debug)(`Unknown manifest type: ${manifestType}`);
8722
8978
  return;
8723
8979
  }
8724
8980
  await new Promise((resolve4, reject) => {
8725
- (0, import_build_utils14.debug)(`Running "${spawnCmd} ${spawnArgs.join(" ")}" in ${projectDir}...`);
8981
+ (0, import_build_utils15.debug)(`Running "${spawnCmd} ${spawnArgs.join(" ")}" in ${projectDir}...`);
8726
8982
  const child = (0, import_child_process2.spawn)(spawnCmd, spawnArgs, {
8727
8983
  cwd: projectDir,
8728
8984
  env: getProtectedUvEnv(env),
@@ -8761,7 +9017,7 @@ var COMPLETED_INSTALLS = /* @__PURE__ */ new Set();
8761
9017
  function hasInstalledDistribution(targetDir, packageName) {
8762
9018
  const prefix = `${packageName.replace("-", "_")}-`;
8763
9019
  try {
8764
- return (0, import_fs12.readdirSync)(targetDir).some(
9020
+ return (0, import_fs13.readdirSync)(targetDir).some(
8765
9021
  (entry) => entry.startsWith(prefix) && entry.endsWith(".dist-info")
8766
9022
  );
8767
9023
  } catch {
@@ -8769,7 +9025,7 @@ function hasInstalledDistribution(targetDir, packageName) {
8769
9025
  }
8770
9026
  }
8771
9027
  async function installInjectedDevPackage(pkg, opts) {
8772
- const targetDir = (0, import_path12.join)(opts.workPath, ".vercel", "python");
9028
+ const targetDir = (0, import_path13.join)(opts.workPath, ".vercel", "python");
8773
9029
  const source = pkg.envOverride || pkg.pinnedVersion || pkg.requirement;
8774
9030
  const key = `${targetDir}:${pkg.name}:${source}`;
8775
9031
  if (COMPLETED_INSTALLS.has(key) && hasInstalledDistribution(targetDir, pkg.name)) {
@@ -8783,23 +9039,23 @@ async function installInjectedDevPackage(pkg, opts) {
8783
9039
  }
8784
9040
  async function doInstallInjectedDevPackage(pkg, opts) {
8785
9041
  const { targetDir, workPath, uvPath, pythonBin, env, onStdout, onStderr } = opts;
8786
- (0, import_fs12.mkdirSync)(targetDir, { recursive: true });
8787
- const localDir = (0, import_path12.join)(__dirname, "..", "..", "..", "python", pkg.name);
8788
- const isLocalDev = (0, import_fs12.existsSync)((0, import_path12.join)(localDir, "pyproject.toml"));
9042
+ (0, import_fs13.mkdirSync)(targetDir, { recursive: true });
9043
+ const localDir = (0, import_path13.join)(__dirname, "..", "..", "..", "python", pkg.name);
9044
+ const isLocalDev = (0, import_fs13.existsSync)((0, import_path13.join)(localDir, "pyproject.toml"));
8789
9045
  const requirement = pkg.pinnedVersion ? `${pkg.name}==${pkg.pinnedVersion}` : pkg.requirement ?? pkg.name;
8790
9046
  const dep = pkg.envOverride || (isLocalDev ? localDir : requirement);
8791
9047
  if (!isLocalDev && !pkg.envOverride && pkg.pinnedVersion) {
8792
9048
  const distInfoName = pkg.name.replace("-", "_");
8793
- const distInfo = (0, import_path12.join)(
9049
+ const distInfo = (0, import_path13.join)(
8794
9050
  targetDir,
8795
9051
  `${distInfoName}-${pkg.pinnedVersion}.dist-info`
8796
9052
  );
8797
- if ((0, import_fs12.existsSync)(distInfo)) {
8798
- (0, import_build_utils14.debug)(`${pkg.name} ${pkg.pinnedVersion} already installed, skipping`);
9053
+ if ((0, import_fs13.existsSync)(distInfo)) {
9054
+ (0, import_build_utils15.debug)(`${pkg.name} ${pkg.pinnedVersion} already installed, skipping`);
8799
9055
  return;
8800
9056
  }
8801
9057
  }
8802
- (0, import_build_utils14.debug)(
9058
+ (0, import_build_utils15.debug)(
8803
9059
  `Installing ${pkg.name} into ${targetDir} (type: ${isLocalDev ? "local" : "pypi"}, source: ${dep})`
8804
9060
  );
8805
9061
  const pip = uvPath ? { cmd: uvPath, prefix: ["pip", "install"] } : { cmd: pythonBin, prefix: ["-m", "pip", "install"] };
@@ -8821,14 +9077,14 @@ async function doInstallInjectedDevPackage(pkg, opts) {
8821
9077
  if (onStdout) {
8822
9078
  onStdout(data);
8823
9079
  } else {
8824
- (0, import_build_utils14.debug)(data.toString());
9080
+ (0, import_build_utils15.debug)(data.toString());
8825
9081
  }
8826
9082
  });
8827
9083
  child.stderr?.on("data", (data) => {
8828
9084
  if (onStderr) {
8829
9085
  onStderr(data);
8830
9086
  } else {
8831
- (0, import_build_utils14.debug)(data.toString());
9087
+ (0, import_build_utils15.debug)(data.toString());
8832
9088
  }
8833
9089
  });
8834
9090
  child.on("error", reject);
@@ -8858,12 +9114,12 @@ function installGlobalCleanupHandlers() {
8858
9114
  try {
8859
9115
  process.kill(info.pid, "SIGTERM");
8860
9116
  } catch (err) {
8861
- (0, import_build_utils14.debug)(`Error sending SIGTERM to ${info.pid}: ${err}`);
9117
+ (0, import_build_utils15.debug)(`Error sending SIGTERM to ${info.pid}: ${err}`);
8862
9118
  }
8863
9119
  try {
8864
9120
  process.kill(info.pid, "SIGKILL");
8865
9121
  } catch (err) {
8866
- (0, import_build_utils14.debug)(`Error sending SIGKILL to ${info.pid}: ${err}`);
9122
+ (0, import_build_utils15.debug)(`Error sending SIGKILL to ${info.pid}: ${err}`);
8867
9123
  }
8868
9124
  PERSISTENT_SERVERS.delete(key);
8869
9125
  }
@@ -8871,7 +9127,7 @@ function installGlobalCleanupHandlers() {
8871
9127
  try {
8872
9128
  restoreWarnings();
8873
9129
  } catch (err) {
8874
- (0, import_build_utils14.debug)(`Error restoring warnings: ${err}`);
9130
+ (0, import_build_utils15.debug)(`Error restoring warnings: ${err}`);
8875
9131
  }
8876
9132
  restoreWarnings = null;
8877
9133
  }
@@ -8888,46 +9144,46 @@ function installGlobalCleanupHandlers() {
8888
9144
  }
8889
9145
  function createDevShim(workPath, entry, modulePath, serviceName, framework, variableName) {
8890
9146
  try {
8891
- const vercelPythonDir = serviceName ? (0, import_path12.join)(workPath, ".vercel", "python", "services", serviceName) : (0, import_path12.join)(workPath, ".vercel", "python");
8892
- (0, import_fs12.mkdirSync)(vercelPythonDir, { recursive: true });
9147
+ const vercelPythonDir = serviceName ? (0, import_path13.join)(workPath, ".vercel", "python", "services", serviceName) : (0, import_path13.join)(workPath, ".vercel", "python");
9148
+ (0, import_fs13.mkdirSync)(vercelPythonDir, { recursive: true });
8893
9149
  let qualifiedModule = modulePath;
8894
9150
  let extraPythonPath;
8895
- if ((0, import_fs12.existsSync)((0, import_path12.join)(workPath, "__init__.py"))) {
8896
- const pkgName = (0, import_path12.basename)(workPath);
9151
+ if ((0, import_fs13.existsSync)((0, import_path13.join)(workPath, "__init__.py"))) {
9152
+ const pkgName = (0, import_path13.basename)(workPath);
8897
9153
  qualifiedModule = `${pkgName}.${modulePath}`;
8898
- extraPythonPath = (0, import_path12.dirname)(workPath);
9154
+ extraPythonPath = (0, import_path13.dirname)(workPath);
8899
9155
  }
8900
- const entryAbs = (0, import_path12.join)(workPath, entry);
8901
- const shimPath = (0, import_path12.join)(vercelPythonDir, `${DEV_SHIM_MODULE}.py`);
8902
- const templatePath = (0, import_path12.join)(
9156
+ const entryAbs = (0, import_path13.join)(workPath, entry);
9157
+ const shimPath = (0, import_path13.join)(vercelPythonDir, `${DEV_SHIM_MODULE}.py`);
9158
+ const templatePath = (0, import_path13.join)(
8903
9159
  __dirname,
8904
9160
  "..",
8905
9161
  "templates",
8906
9162
  `${DEV_SHIM_MODULE}.py`
8907
9163
  );
8908
- const template = (0, import_fs12.readFileSync)(templatePath, "utf8");
9164
+ const template = (0, import_fs13.readFileSync)(templatePath, "utf8");
8909
9165
  const shimSource = template.replace(/__VC_DEV_MODULE_NAME__/g, qualifiedModule).replace(/__VC_DEV_ENTRY_ABS__/g, entryAbs).replace(/__VC_DEV_FRAMEWORK__/g, framework).replace(/__VC_DEV_VARIABLE_NAME__/g, variableName);
8910
- (0, import_fs12.writeFileSync)(shimPath, shimSource, "utf8");
8911
- (0, import_build_utils14.debug)(`Prepared Python dev shim at ${shimPath}`);
9166
+ (0, import_fs13.writeFileSync)(shimPath, shimSource, "utf8");
9167
+ (0, import_build_utils15.debug)(`Prepared Python dev shim at ${shimPath}`);
8912
9168
  return {
8913
9169
  module: DEV_SHIM_MODULE,
8914
9170
  extraPythonPath,
8915
9171
  shimDir: vercelPythonDir
8916
9172
  };
8917
9173
  } catch (err) {
8918
- (0, import_build_utils14.debug)(`Failed to prepare dev shim: ${err?.message || err}`);
9174
+ (0, import_build_utils15.debug)(`Failed to prepare dev shim: ${err?.message || err}`);
8919
9175
  return null;
8920
9176
  }
8921
9177
  }
8922
9178
  async function getMultiServicePythonRunner(workPath, env, systemPython, uvPath) {
8923
- const venvPath = (0, import_path12.join)(workPath, ".venv");
9179
+ const venvPath = (0, import_path13.join)(workPath, ".venv");
8924
9180
  const pendingCreation = PENDING_MANAGED_VENV_CREATIONS.get(venvPath);
8925
9181
  if (pendingCreation) {
8926
9182
  await pendingCreation;
8927
9183
  }
8928
9184
  const { pythonCmd, venvRoot } = useVirtualEnv(workPath, env, systemPython);
8929
9185
  if (venvRoot) {
8930
- (0, import_build_utils14.debug)(`Using existing virtualenv at ${venvRoot} for multi-service dev`);
9186
+ (0, import_build_utils15.debug)(`Using existing virtualenv at ${venvRoot} for multi-service dev`);
8931
9187
  return { command: pythonCmd, args: [] };
8932
9188
  }
8933
9189
  await dedupePendingOperation(
@@ -8940,11 +9196,11 @@ async function getMultiServicePythonRunner(workPath, env, systemPython, uvPath)
8940
9196
  quiet: true
8941
9197
  })
8942
9198
  );
8943
- (0, import_build_utils14.debug)(`Created virtualenv at ${venvPath} for multi-service dev`);
9199
+ (0, import_build_utils15.debug)(`Created virtualenv at ${venvPath} for multi-service dev`);
8944
9200
  const pythonBin = getVenvPythonBin(venvPath);
8945
9201
  const binDir = getVenvBinDir(venvPath);
8946
9202
  env.VIRTUAL_ENV = venvPath;
8947
- env.PATH = `${binDir}${import_path12.delimiter}${env.PATH || ""}`;
9203
+ env.PATH = `${binDir}${import_path13.delimiter}${env.PATH || ""}`;
8948
9204
  return { command: pythonBin, args: [] };
8949
9205
  }
8950
9206
  var startDevServer = async (opts) => {
@@ -8992,6 +9248,7 @@ var startDevServer = async (opts) => {
8992
9248
  const isPyprojectEntrypoint = entrypoint === "pyproject.toml";
8993
9249
  let resolved;
8994
9250
  const handlerFunction = typeof config?.handlerFunction === "string" ? config.handlerFunction : void 0;
9251
+ const isPyQueueSidecar = config?.pythonQueueSidecar === "subscriber" || config?.pythonQueueSidecar === "workflow";
8995
9252
  let detected;
8996
9253
  if (isPyprojectEntrypoint) {
8997
9254
  const declaredEntrypoint = await getVercelToolsEntrypoint(
@@ -9007,7 +9264,7 @@ var startDevServer = async (opts) => {
9007
9264
  filePath: entrypoint,
9008
9265
  // Schedule-triggered services create their own "app" wrapper dynamically.
9009
9266
  // Other services use handlerFunction as the entrypoint variable name.
9010
- varName: service && (0, import_build_utils14.isScheduleTriggeredService)(service) ? void 0 : handlerFunction
9267
+ varName: service && (0, import_build_utils15.isScheduleTriggeredService)(service) ? void 0 : handlerFunction ?? (isPyQueueSidecar ? "app" : void 0)
9011
9268
  } : void 0,
9012
9269
  service,
9013
9270
  opts.repoRootPath
@@ -9029,7 +9286,7 @@ var startDevServer = async (opts) => {
9029
9286
  if (detected?.error) {
9030
9287
  throw detected.error;
9031
9288
  }
9032
- throw new import_build_utils14.NowBuildError({
9289
+ throw new import_build_utils15.NowBuildError({
9033
9290
  code: isPyprojectEntrypoint ? "PYTHON_PYPROJECT_NOTHING_TO_BUILD" : "PYTHON_ENTRYPOINT_NOT_FOUND",
9034
9291
  message: isPyprojectEntrypoint ? 'Entrypoint "pyproject.toml" does not declare a web app. Set "tool.vercel.entrypoint" in pyproject.toml.' : "No Python entrypoint could be detected. Please specify an entrypoint file."
9035
9292
  });
@@ -9061,7 +9318,7 @@ var startDevServer = async (opts) => {
9061
9318
  const yellow = "\x1B[33m";
9062
9319
  const white = "\x1B[1m";
9063
9320
  const reset = "\x1B[0m";
9064
- throw new import_build_utils14.NowBuildError({
9321
+ throw new import_build_utils15.NowBuildError({
9065
9322
  code: "PYTHON_EXTERNAL_VENV_DETECTED",
9066
9323
  message: `Detected activated venv at ${yellow}${venv}${reset}, ${white}vercel dev${reset} manages virtual environments automatically.
9067
9324
  Run ${white}deactivate${reset} and try again.`
@@ -9078,11 +9335,11 @@ Run ${white}deactivate${reset} and try again.`
9078
9335
  );
9079
9336
  spawnCommand = runner.command;
9080
9337
  spawnArgsPrefix = runner.args;
9081
- (0, import_build_utils14.debug)(
9338
+ (0, import_build_utils15.debug)(
9082
9339
  `Multi-service Python runner: ${spawnCommand} ${spawnArgsPrefix.join(" ")}`
9083
9340
  );
9084
9341
  } else if (venv) {
9085
- (0, import_build_utils14.debug)(`Running in virtualenv at ${venv}`);
9342
+ (0, import_build_utils15.debug)(`Running in virtualenv at ${venv}`);
9086
9343
  } else {
9087
9344
  const { pythonCmd: venvPythonCmd, venvRoot } = useVirtualEnv(
9088
9345
  workPath,
@@ -9091,9 +9348,9 @@ Run ${white}deactivate${reset} and try again.`
9091
9348
  );
9092
9349
  spawnCommand = venvPythonCmd;
9093
9350
  if (venvRoot) {
9094
- (0, import_build_utils14.debug)(`Using virtualenv at ${venvRoot}`);
9351
+ (0, import_build_utils15.debug)(`Using virtualenv at ${venvRoot}`);
9095
9352
  } else {
9096
- (0, import_build_utils14.debug)("No virtualenv found");
9353
+ (0, import_build_utils15.debug)("No virtualenv found");
9097
9354
  try {
9098
9355
  const yellow = "\x1B[33m";
9099
9356
  const reset = "\x1B[0m";
@@ -9146,7 +9403,13 @@ If you are using a virtual environment, activate it before running "vercel dev",
9146
9403
  entrypointDir: workPath,
9147
9404
  rootDir: workPath
9148
9405
  });
9149
- queueIntegrations = legacyProject ? [] : await getQueueIntegrations({ pythonPackage });
9406
+ const queueAdapterBootstrap = await getQueueAdapterBootstrap({
9407
+ pythonPackage,
9408
+ env,
9409
+ legacyWorkersProject: legacyProject,
9410
+ hasDeclaredSubscribers: await hasPyprojectSubscribers(workPath)
9411
+ });
9412
+ queueIntegrations = queueAdapterBootstrap.integrations;
9150
9413
  if (queueIntegrations.length > 0) {
9151
9414
  env.VERCEL_QUEUE_INTEGRATIONS = queueIntegrations.map(
9152
9415
  ({ module: module2, installer, servingActivator }) => `${module2}:${installer}` + (servingActivator ? `:${servingActivator}` : "")
@@ -9154,11 +9417,7 @@ If you are using a virtual environment, activate it before running "vercel dev",
9154
9417
  } else {
9155
9418
  delete env.VERCEL_QUEUE_INTEGRATIONS;
9156
9419
  }
9157
- const conditionalInjectedPackages = legacyProject ? [] : await getConditionalInjectedPackages({
9158
- pythonPackage,
9159
- env
9160
- });
9161
- for (const injectedPackage of conditionalInjectedPackages) {
9420
+ for (const injectedPackage of queueAdapterBootstrap.injectedPackages) {
9162
9421
  await installInjectedDevPackage(
9163
9422
  {
9164
9423
  name: injectedPackage.name,
@@ -9169,10 +9428,52 @@ If you are using a virtual environment, activate it before running "vercel dev",
9169
9428
  );
9170
9429
  }
9171
9430
  } catch (err) {
9172
- (0, import_build_utils14.debug)(
9431
+ (0, import_build_utils15.debug)(
9173
9432
  `Skipping conditional dev package injection: ${err instanceof Error ? err.message : String(err)}`
9174
9433
  );
9175
9434
  }
9435
+ const apschedulerSubscribers = [];
9436
+ if (!legacyProject) {
9437
+ const runtimeDir = (0, import_path13.join)(workPath, ".vercel", "python");
9438
+ const declaredSubscribers = await getPyprojectSubscribers(workPath);
9439
+ const introspectionEnv = {
9440
+ ...env,
9441
+ PYTHONPATH: [runtimeDir, env.PYTHONPATH].filter(Boolean).join(import_path13.delimiter)
9442
+ };
9443
+ delete introspectionEnv.VERCEL_APSCHEDULER_SUBSCRIBERS;
9444
+ for (const declaration of declaredSubscribers) {
9445
+ const introspected = await introspectDevQueueSubscriptions({
9446
+ moduleName: declaration.moduleName,
9447
+ subscriberName: declaration.name,
9448
+ variableName: declaration.variableName || "app",
9449
+ pythonBin: spawnCommand,
9450
+ cwd: workPath,
9451
+ env: introspectionEnv,
9452
+ integrations: queueIntegrations
9453
+ });
9454
+ apschedulerSubscribers.push(
9455
+ ...apschedulerSubscriberIdentities([
9456
+ { ...declaration, owners: introspected?.owners ?? [] }
9457
+ ])
9458
+ );
9459
+ }
9460
+ }
9461
+ if (apschedulerSubscribers.length > 0) {
9462
+ env.VERCEL_APSCHEDULER_SUBSCRIBERS = JSON.stringify(
9463
+ apschedulerSubscribers
9464
+ );
9465
+ const previewConfig = await getApschedulerPreviewConfig(workPath);
9466
+ if (previewConfig) {
9467
+ env.VERCEL_APSCHEDULER_PREVIEW_IDLE_TIMEOUT_SECONDS = String(
9468
+ previewConfig.idleTimeoutSeconds
9469
+ );
9470
+ } else {
9471
+ delete env.VERCEL_APSCHEDULER_PREVIEW_IDLE_TIMEOUT_SECONDS;
9472
+ }
9473
+ } else {
9474
+ delete env.VERCEL_APSCHEDULER_SUBSCRIBERS;
9475
+ delete env.VERCEL_APSCHEDULER_PREVIEW_IDLE_TIMEOUT_SECONDS;
9476
+ }
9176
9477
  if (legacyProject) {
9177
9478
  await installInjectedDevPackage(
9178
9479
  {
@@ -9183,7 +9484,7 @@ If you are using a virtual environment, activate it before running "vercel dev",
9183
9484
  devOpts
9184
9485
  );
9185
9486
  }
9186
- const queueSidecarKind = config?.pythonQueueSidecar === "subscriber" || config?.pythonQueueSidecar === "workflow" ? config.pythonQueueSidecar : service && (0, import_build_utils14.isQueueBackedService)(service) ? (0, import_build_utils14.isWorkflowTriggeredService)(service) ? "workflow" : "subscriber" : void 0;
9487
+ const queueSidecarKind = config?.pythonQueueSidecar === "subscriber" || config?.pythonQueueSidecar === "workflow" ? config.pythonQueueSidecar : service && (0, import_build_utils15.isQueueBackedService)(service) ? (0, import_build_utils15.isWorkflowTriggeredService)(service) ? "workflow" : "subscriber" : void 0;
9187
9488
  let queueSubscriptions;
9188
9489
  if (queueSidecarKind) {
9189
9490
  let useQueueServing = !legacyProject;
@@ -9197,19 +9498,29 @@ If you are using a virtual environment, activate it before running "vercel dev",
9197
9498
  }
9198
9499
  if (useQueueServing) {
9199
9500
  env.VERCEL_DEV_QUEUE_SERVING = "1";
9200
- const runtimeDir = (0, import_path12.join)(workPath, ".vercel", "python");
9201
- queueSubscriptions = await introspectDevQueueSubscriptions({
9501
+ const subscriberName = getModuleEntrypointName({
9202
9502
  moduleName: modulePath,
9503
+ variableName: variableName || "app"
9504
+ });
9505
+ env.VERCEL_PYTHON_SUBSCRIBER_ID = subscriberName;
9506
+ const runtimeDir = (0, import_path13.join)(workPath, ".vercel", "python");
9507
+ const introspectionEnv = {
9508
+ ...env,
9509
+ PYTHONPATH: [runtimeDir, env.PYTHONPATH].filter(Boolean).join(import_path13.delimiter)
9510
+ };
9511
+ delete introspectionEnv.VERCEL_APSCHEDULER_SUBSCRIBERS;
9512
+ queueSubscriptions = (await introspectDevQueueSubscriptions({
9513
+ moduleName: modulePath,
9514
+ subscriberName,
9515
+ variableName: variableName || "app",
9203
9516
  pythonBin: spawnCommand,
9204
9517
  cwd: workPath,
9205
- env: {
9206
- ...env,
9207
- PYTHONPATH: [runtimeDir, env.PYTHONPATH].filter(Boolean).join(import_path12.delimiter)
9208
- },
9518
+ env: introspectionEnv,
9209
9519
  integrations: queueIntegrations
9210
- });
9520
+ }))?.subscriptions;
9211
9521
  } else {
9212
9522
  delete env.VERCEL_DEV_QUEUE_SERVING;
9523
+ delete env.VERCEL_PYTHON_SUBSCRIBER_ID;
9213
9524
  await installInjectedDevPackage(
9214
9525
  {
9215
9526
  name: "vercel-workers",
@@ -9235,7 +9546,7 @@ If you are using a virtual environment, activate it before running "vercel dev",
9235
9546
  const port = typeof meta.port === "number" ? meta.port : await (0, import_get_port.default)();
9236
9547
  env.PORT = `${port}`;
9237
9548
  if (entry) {
9238
- env.__VC_HANDLER_ENTRYPOINT_ABS = (0, import_path12.join)(workPath, entry);
9549
+ env.__VC_HANDLER_ENTRYPOINT_ABS = (0, import_path13.join)(workPath, entry);
9239
9550
  }
9240
9551
  const devShim = createDevShim(
9241
9552
  workPath,
@@ -9246,8 +9557,8 @@ If you are using a virtual environment, activate it before running "vercel dev",
9246
9557
  variableName ?? ""
9247
9558
  );
9248
9559
  if (devShim) {
9249
- const shimDir = devShim.shimDir || (0, import_path12.join)(workPath, ".vercel", "python");
9250
- const runtimeDir = (0, import_path12.join)(workPath, ".vercel", "python");
9560
+ const shimDir = devShim.shimDir || (0, import_path13.join)(workPath, ".vercel", "python");
9561
+ const runtimeDir = (0, import_path13.join)(workPath, ".vercel", "python");
9251
9562
  const pathParts = shimDir !== runtimeDir ? [shimDir, runtimeDir] : [shimDir];
9252
9563
  if (devShim.extraPythonPath) {
9253
9564
  pathParts.push(devShim.extraPythonPath);
@@ -9259,12 +9570,12 @@ If you are using a virtual environment, activate it before running "vercel dev",
9259
9570
  if (existingPythonPath) {
9260
9571
  pathParts.push(existingPythonPath);
9261
9572
  }
9262
- env.PYTHONPATH = pathParts.join(import_path12.delimiter);
9573
+ env.PYTHONPATH = pathParts.join(import_path13.delimiter);
9263
9574
  }
9264
9575
  const moduleToRun = devShim?.module || modulePath;
9265
9576
  const pythonArgs = ["-u", "-m", moduleToRun];
9266
9577
  const argv = [...spawnArgsPrefix, ...pythonArgs];
9267
- (0, import_build_utils14.debug)(
9578
+ (0, import_build_utils15.debug)(
9268
9579
  `Starting Python dev server (${framework}): ${spawnCommand} ${argv.join(" ")} [PORT=${port}]`
9269
9580
  );
9270
9581
  if (process.stdout.columns) {
@@ -9318,7 +9629,7 @@ If you are using a virtual environment, activate it before running "vercel dev",
9318
9629
  };
9319
9630
 
9320
9631
  // src/quirks/index.ts
9321
- var import_build_utils17 = require("@vercel/build-utils");
9632
+ var import_build_utils18 = require("@vercel/build-utils");
9322
9633
  var import_python_analysis10 = require("@vercel/python-analysis");
9323
9634
 
9324
9635
  // src/quirks/matplotlib.ts
@@ -9332,9 +9643,9 @@ var matplotlibQuirk = {
9332
9643
  };
9333
9644
 
9334
9645
  // src/quirks/litellm.ts
9335
- var import_fs13 = __toESM(require("fs"));
9336
- var import_path13 = require("path");
9337
- var import_build_utils15 = require("@vercel/build-utils");
9646
+ var import_fs14 = __toESM(require("fs"));
9647
+ var import_path14 = require("path");
9648
+ var import_build_utils16 = require("@vercel/build-utils");
9338
9649
  var LAMBDA_ROOT = "/var/task";
9339
9650
  var CONFIG_CANDIDATES = [
9340
9651
  "litellm_config.yaml",
@@ -9344,9 +9655,9 @@ var CONFIG_CANDIDATES = [
9344
9655
  ];
9345
9656
  async function findConfigFile(workPath) {
9346
9657
  for (const name of CONFIG_CANDIDATES) {
9347
- const candidate = (0, import_path13.join)(workPath, name);
9658
+ const candidate = (0, import_path14.join)(workPath, name);
9348
9659
  try {
9349
- await import_fs13.default.promises.access(candidate);
9660
+ await import_fs14.default.promises.access(candidate);
9350
9661
  return name;
9351
9662
  } catch {
9352
9663
  }
@@ -9361,32 +9672,32 @@ var litellmQuirk = {
9361
9672
  const env = {};
9362
9673
  const sitePackagesDirs = await getVenvSitePackagesDirs(ctx.venvPath);
9363
9674
  for (const sitePackages of sitePackagesDirs) {
9364
- const schemaPath = (0, import_path13.join)(
9675
+ const schemaPath = (0, import_path14.join)(
9365
9676
  sitePackages,
9366
9677
  "litellm",
9367
9678
  "proxy",
9368
9679
  "schema.prisma"
9369
9680
  );
9370
9681
  try {
9371
- await import_fs13.default.promises.access(schemaPath);
9372
- (0, import_build_utils15.debug)(`LiteLLM quirk: found schema at ${schemaPath}`);
9682
+ await import_fs14.default.promises.access(schemaPath);
9683
+ (0, import_build_utils16.debug)(`LiteLLM quirk: found schema at ${schemaPath}`);
9373
9684
  buildEnv.PRISMA_SCHEMA_PATH = schemaPath;
9374
9685
  break;
9375
9686
  } catch {
9376
9687
  }
9377
9688
  }
9378
9689
  if (!buildEnv.PRISMA_SCHEMA_PATH) {
9379
- (0, import_build_utils15.debug)("LiteLLM quirk: schema.prisma not found in any site-packages");
9690
+ (0, import_build_utils16.debug)("LiteLLM quirk: schema.prisma not found in any site-packages");
9380
9691
  }
9381
9692
  if (!process.env.CONFIG_FILE_PATH) {
9382
9693
  const configName = await findConfigFile(ctx.workPath);
9383
9694
  if (configName) {
9384
- (0, import_build_utils15.debug)(`LiteLLM quirk: found config at ${configName}`);
9385
- buildEnv.CONFIG_FILE_PATH = (0, import_path13.join)(ctx.workPath, configName);
9386
- env.CONFIG_FILE_PATH = (0, import_path13.join)(LAMBDA_ROOT, configName);
9695
+ (0, import_build_utils16.debug)(`LiteLLM quirk: found config at ${configName}`);
9696
+ buildEnv.CONFIG_FILE_PATH = (0, import_path14.join)(ctx.workPath, configName);
9697
+ env.CONFIG_FILE_PATH = (0, import_path14.join)(LAMBDA_ROOT, configName);
9387
9698
  }
9388
9699
  } else {
9389
- (0, import_build_utils15.debug)(
9700
+ (0, import_build_utils16.debug)(
9390
9701
  `LiteLLM quirk: CONFIG_FILE_PATH already set to ${process.env.CONFIG_FILE_PATH}`
9391
9702
  );
9392
9703
  }
@@ -9395,10 +9706,10 @@ var litellmQuirk = {
9395
9706
  };
9396
9707
 
9397
9708
  // src/quirks/prisma.ts
9398
- var import_fs14 = __toESM(require("fs"));
9399
- var import_path14 = require("path");
9709
+ var import_fs15 = __toESM(require("fs"));
9710
+ var import_path15 = require("path");
9400
9711
  var import_execa7 = __toESM(require_execa());
9401
- var import_build_utils16 = require("@vercel/build-utils");
9712
+ var import_build_utils17 = require("@vercel/build-utils");
9402
9713
  var import_python_analysis9 = require("@vercel/python-analysis");
9403
9714
  function execErrorMessage(err) {
9404
9715
  if (err != null && typeof err === "object" && "stderr" in err) {
@@ -9436,22 +9747,22 @@ model DummyModel {
9436
9747
  async function findUserSchema(workPath) {
9437
9748
  const envPath = process.env.PRISMA_SCHEMA_PATH;
9438
9749
  if (envPath) {
9439
- const resolved = (0, import_path14.isAbsolute)(envPath) ? envPath : (0, import_path14.join)(workPath, envPath);
9750
+ const resolved = (0, import_path15.isAbsolute)(envPath) ? envPath : (0, import_path15.join)(workPath, envPath);
9440
9751
  try {
9441
- await import_fs14.default.promises.access(resolved);
9752
+ await import_fs15.default.promises.access(resolved);
9442
9753
  return resolved;
9443
9754
  } catch {
9444
- (0, import_build_utils16.debug)(`PRISMA_SCHEMA_PATH=${envPath} not found at ${resolved}`);
9755
+ (0, import_build_utils17.debug)(`PRISMA_SCHEMA_PATH=${envPath} not found at ${resolved}`);
9445
9756
  return null;
9446
9757
  }
9447
9758
  }
9448
9759
  const candidates = [
9449
- (0, import_path14.join)(workPath, "schema.prisma"),
9450
- (0, import_path14.join)(workPath, "prisma", "schema.prisma")
9760
+ (0, import_path15.join)(workPath, "schema.prisma"),
9761
+ (0, import_path15.join)(workPath, "prisma", "schema.prisma")
9451
9762
  ];
9452
9763
  for (const candidate of candidates) {
9453
9764
  try {
9454
- await import_fs14.default.promises.access(candidate);
9765
+ await import_fs15.default.promises.access(candidate);
9455
9766
  return candidate;
9456
9767
  } catch {
9457
9768
  }
@@ -9462,32 +9773,32 @@ async function collectFiles(dir, base) {
9462
9773
  const result = [];
9463
9774
  let entries;
9464
9775
  try {
9465
- entries = await import_fs14.default.promises.readdir(dir, { withFileTypes: true });
9776
+ entries = await import_fs15.default.promises.readdir(dir, { withFileTypes: true });
9466
9777
  } catch {
9467
9778
  return result;
9468
9779
  }
9469
9780
  for (const entry of entries) {
9470
9781
  if (entry.name === "__pycache__")
9471
9782
  continue;
9472
- const full = (0, import_path14.join)(dir, entry.name);
9783
+ const full = (0, import_path15.join)(dir, entry.name);
9473
9784
  if (entry.isDirectory()) {
9474
9785
  result.push(...await collectFiles(full, base));
9475
9786
  } else {
9476
- result.push((0, import_path14.relative)(base, full));
9787
+ result.push((0, import_path15.relative)(base, full));
9477
9788
  }
9478
9789
  }
9479
9790
  return result;
9480
9791
  }
9481
9792
  async function cleanCacheArtifacts(cacheDir, extras = []) {
9482
9793
  const paths = [
9483
- (0, import_path14.join)(cacheDir, "node_modules"),
9484
- (0, import_path14.join)(cacheDir, "package.json"),
9485
- (0, import_path14.join)(cacheDir, "package-lock.json"),
9794
+ (0, import_path15.join)(cacheDir, "node_modules"),
9795
+ (0, import_path15.join)(cacheDir, "package.json"),
9796
+ (0, import_path15.join)(cacheDir, "package-lock.json"),
9486
9797
  ...extras
9487
9798
  ];
9488
9799
  for (const p of paths) {
9489
9800
  try {
9490
- await import_fs14.default.promises.rm(p, { recursive: true, force: true });
9801
+ await import_fs15.default.promises.rm(p, { recursive: true, force: true });
9491
9802
  } catch (err) {
9492
9803
  console.warn(
9493
9804
  `could not clean up ${p}: ${err instanceof Error ? err.message : String(err)}`
@@ -9511,7 +9822,7 @@ var prismaQuirk = {
9511
9822
  async run(ctx) {
9512
9823
  const { venvPath, pythonEnv, workPath } = ctx;
9513
9824
  const pythonPath = getVenvPythonBin(venvPath);
9514
- const runtimeCacheDir = (0, import_path14.join)(
9825
+ const runtimeCacheDir = (0, import_path15.join)(
9515
9826
  LAMBDA_ROOT2,
9516
9827
  resolveVendorDir(),
9517
9828
  "prisma",
@@ -9521,7 +9832,7 @@ var prismaQuirk = {
9521
9832
  let sitePackages;
9522
9833
  for (const dir of sitePackagesDirs) {
9523
9834
  try {
9524
- await import_fs14.default.promises.access((0, import_path14.join)(dir, "prisma"));
9835
+ await import_fs15.default.promises.access((0, import_path15.join)(dir, "prisma"));
9525
9836
  sitePackages = dir;
9526
9837
  break;
9527
9838
  } catch {
@@ -9533,19 +9844,19 @@ var prismaQuirk = {
9533
9844
  );
9534
9845
  return {};
9535
9846
  }
9536
- const cacheDir = (0, import_path14.join)(sitePackages, "prisma", "__bincache__");
9537
- await import_fs14.default.promises.mkdir(cacheDir, { recursive: true });
9847
+ const cacheDir = (0, import_path15.join)(sitePackages, "prisma", "__bincache__");
9848
+ await import_fs15.default.promises.mkdir(cacheDir, { recursive: true });
9538
9849
  const generateEnv = {
9539
9850
  ...pythonEnv,
9540
9851
  PRISMA_BINARY_CACHE_DIR: cacheDir
9541
9852
  };
9542
- const generatedDir = (0, import_path14.join)(workPath, "_prisma_generated");
9543
- const dummySchemaPath = (0, import_path14.join)(workPath, DUMMY_SCHEMA_NAME);
9544
- await import_fs14.default.promises.writeFile(
9853
+ const generatedDir = (0, import_path15.join)(workPath, "_prisma_generated");
9854
+ const dummySchemaPath = (0, import_path15.join)(workPath, DUMMY_SCHEMA_NAME);
9855
+ await import_fs15.default.promises.writeFile(
9545
9856
  dummySchemaPath,
9546
9857
  buildDummySchema(generatedDir)
9547
9858
  );
9548
- (0, import_build_utils16.debug)(`Running prisma generate (dummy) with cache dir: ${cacheDir}`);
9859
+ (0, import_build_utils17.debug)(`Running prisma generate (dummy) with cache dir: ${cacheDir}`);
9549
9860
  try {
9550
9861
  const dummyResult = await (0, import_execa7.default)(
9551
9862
  pythonPath,
@@ -9557,11 +9868,11 @@ var prismaQuirk = {
9557
9868
  }
9558
9869
  );
9559
9870
  if (dummyResult.stdout)
9560
- (0, import_build_utils16.debug)(`prisma generate (dummy) stdout: ${dummyResult.stdout}`);
9871
+ (0, import_build_utils17.debug)(`prisma generate (dummy) stdout: ${dummyResult.stdout}`);
9561
9872
  if (dummyResult.stderr)
9562
- (0, import_build_utils16.debug)(`prisma generate (dummy) stderr: ${dummyResult.stderr}`);
9873
+ (0, import_build_utils17.debug)(`prisma generate (dummy) stderr: ${dummyResult.stderr}`);
9563
9874
  } catch (err) {
9564
- throw new import_build_utils16.NowBuildError({
9875
+ throw new import_build_utils17.NowBuildError({
9565
9876
  code: "PRISMA_GENERATE_FAILED",
9566
9877
  message: `Prisma engine download failed during \`prisma generate\`. Check that your prisma version is compatible with this Python version.
9567
9878
  ` + execErrorMessage(err)
@@ -9569,47 +9880,47 @@ var prismaQuirk = {
9569
9880
  }
9570
9881
  const srcBinaryPrefix = `query-engine-${getLambdaBinaryTarget()}`;
9571
9882
  const runtimeName = `prisma-query-engine-rhel-openssl-${RUNTIME_OPENSSL_VERSION}.x`;
9572
- const nodeModulesDir = (0, import_path14.join)(cacheDir, "node_modules", "prisma");
9883
+ const nodeModulesDir = (0, import_path15.join)(cacheDir, "node_modules", "prisma");
9573
9884
  let engineCopied = false;
9574
9885
  try {
9575
- const entries = await import_fs14.default.promises.readdir(nodeModulesDir);
9886
+ const entries = await import_fs15.default.promises.readdir(nodeModulesDir);
9576
9887
  for (const entry of entries) {
9577
9888
  if (!entry.startsWith(srcBinaryPrefix))
9578
9889
  continue;
9579
- const srcPath = (0, import_path14.join)(nodeModulesDir, entry);
9580
- const destPath = (0, import_path14.join)(cacheDir, runtimeName);
9890
+ const srcPath = (0, import_path15.join)(nodeModulesDir, entry);
9891
+ const destPath = (0, import_path15.join)(cacheDir, runtimeName);
9581
9892
  try {
9582
- await import_fs14.default.promises.access(destPath);
9583
- (0, import_build_utils16.debug)(`Engine binary: ${runtimeName} already exists, skipping`);
9893
+ await import_fs15.default.promises.access(destPath);
9894
+ (0, import_build_utils17.debug)(`Engine binary: ${runtimeName} already exists, skipping`);
9584
9895
  } catch {
9585
- (0, import_build_utils16.debug)(`Engine binary: copying ${entry} -> ${runtimeName}`);
9586
- await import_fs14.default.promises.copyFile(srcPath, destPath);
9896
+ (0, import_build_utils17.debug)(`Engine binary: copying ${entry} -> ${runtimeName}`);
9897
+ await import_fs15.default.promises.copyFile(srcPath, destPath);
9587
9898
  }
9588
9899
  engineCopied = true;
9589
9900
  }
9590
9901
  } catch (err) {
9591
- throw new import_build_utils16.NowBuildError({
9902
+ throw new import_build_utils17.NowBuildError({
9592
9903
  code: "PRISMA_ENGINE_NOT_FOUND",
9593
9904
  message: `could not read Prisma engine directory "${nodeModulesDir}". This may indicate an incompatible prisma version.
9594
9905
  ` + (err instanceof Error ? err.message : String(err))
9595
9906
  });
9596
9907
  }
9597
9908
  if (!engineCopied) {
9598
- throw new import_build_utils16.NowBuildError({
9909
+ throw new import_build_utils17.NowBuildError({
9599
9910
  code: "PRISMA_ENGINE_NOT_FOUND",
9600
9911
  message: `could not find engine binary matching "${srcBinaryPrefix}*" in "${nodeModulesDir}". This may indicate an incompatible prisma version or an unsupported platform (${process.arch}).`
9601
9912
  });
9602
9913
  }
9603
- const shimPath = (0, import_path14.join)(cacheDir, "openssl");
9604
- await import_fs14.default.promises.writeFile(
9914
+ const shimPath = (0, import_path15.join)(cacheDir, "openssl");
9915
+ await import_fs15.default.promises.writeFile(
9605
9916
  shimPath,
9606
9917
  `#!/bin/sh
9607
9918
  echo "OpenSSL ${RUNTIME_OPENSSL_VERSION}.0 1 Jan 2024 (Library: OpenSSL ${RUNTIME_OPENSSL_VERSION}.0)"
9608
9919
  `
9609
9920
  );
9610
- await import_fs14.default.promises.chmod(shimPath, 493);
9921
+ await import_fs15.default.promises.chmod(shimPath, 493);
9611
9922
  for (const p of [generatedDir, dummySchemaPath]) {
9612
- await import_fs14.default.promises.rm(p, { recursive: true, force: true });
9923
+ await import_fs15.default.promises.rm(p, { recursive: true, force: true });
9613
9924
  }
9614
9925
  await cleanCacheArtifacts(cacheDir);
9615
9926
  const generateMode = (process.env.VERCEL_PRISMA_GENERATE_CLIENT ?? "auto").toLowerCase();
@@ -9622,14 +9933,14 @@ echo "OpenSSL ${RUNTIME_OPENSSL_VERSION}.0 1 Jan 2024 (Library: OpenSSL ${RUNTIM
9622
9933
  pythonEnv
9623
9934
  );
9624
9935
  if (clientAlreadyGenerated) {
9625
- (0, import_build_utils16.debug)(
9936
+ (0, import_build_utils17.debug)(
9626
9937
  "Prisma quirk: client already generated, skipping user schema generate"
9627
9938
  );
9628
9939
  shouldGenerate = false;
9629
9940
  }
9630
9941
  }
9631
9942
  if (shouldGenerate) {
9632
- (0, import_build_utils16.debug)(`Running prisma generate with user schema: ${userSchema}`);
9943
+ (0, import_build_utils17.debug)(`Running prisma generate with user schema: ${userSchema}`);
9633
9944
  try {
9634
9945
  const userResult = await (0, import_execa7.default)(
9635
9946
  pythonPath,
@@ -9641,11 +9952,11 @@ echo "OpenSSL ${RUNTIME_OPENSSL_VERSION}.0 1 Jan 2024 (Library: OpenSSL ${RUNTIM
9641
9952
  }
9642
9953
  );
9643
9954
  if (userResult.stdout)
9644
- (0, import_build_utils16.debug)(`prisma generate stdout: ${userResult.stdout}`);
9955
+ (0, import_build_utils17.debug)(`prisma generate stdout: ${userResult.stdout}`);
9645
9956
  if (userResult.stderr)
9646
- (0, import_build_utils16.debug)(`prisma generate stderr: ${userResult.stderr}`);
9957
+ (0, import_build_utils17.debug)(`prisma generate stderr: ${userResult.stderr}`);
9647
9958
  } catch (err) {
9648
- throw new import_build_utils16.NowBuildError({
9959
+ throw new import_build_utils17.NowBuildError({
9649
9960
  code: "PRISMA_GENERATE_FAILED",
9650
9961
  message: `\`prisma generate\` failed for schema "${userSchema}".
9651
9962
  ` + execErrorMessage(err)
@@ -9656,12 +9967,12 @@ echo "OpenSSL ${RUNTIME_OPENSSL_VERSION}.0 1 Jan 2024 (Library: OpenSSL ${RUNTIM
9656
9967
  }
9657
9968
  try {
9658
9969
  const allFiles = await collectFiles(
9659
- (0, import_path14.join)(sitePackages, "prisma"),
9970
+ (0, import_path15.join)(sitePackages, "prisma"),
9660
9971
  sitePackages
9661
9972
  );
9662
9973
  const count = await (0, import_python_analysis9.extendDistRecord)(sitePackages, "prisma", allFiles);
9663
9974
  if (count > 0) {
9664
- (0, import_build_utils16.debug)(`Appended ${count} entries to prisma RECORD`);
9975
+ (0, import_build_utils17.debug)(`Appended ${count} entries to prisma RECORD`);
9665
9976
  }
9666
9977
  } catch (err) {
9667
9978
  console.warn(
@@ -9755,13 +10066,13 @@ async function runQuirks(ctx) {
9755
10066
  (0, import_python_analysis10.normalizePackageName)(quirk.dependency)
9756
10067
  );
9757
10068
  if (!installed) {
9758
- (0, import_build_utils17.debug)(`Quirk "${quirk.dependency}": not installed, skipping`);
10069
+ (0, import_build_utils18.debug)(`Quirk "${quirk.dependency}": not installed, skipping`);
9759
10070
  }
9760
10071
  return installed;
9761
10072
  });
9762
10073
  const sorted = toposortQuirks(activated);
9763
10074
  for (const quirk of sorted) {
9764
- (0, import_build_utils17.debug)(`Quirk "${quirk.dependency}": detected, running fix-up`);
10075
+ (0, import_build_utils18.debug)(`Quirk "${quirk.dependency}": detected, running fix-up`);
9765
10076
  const result = await quirk.run(ctx);
9766
10077
  if (result.env) {
9767
10078
  Object.assign(mergedEnv, result.env);
@@ -9782,12 +10093,12 @@ async function runQuirks(ctx) {
9782
10093
  }
9783
10094
 
9784
10095
  // src/django.ts
9785
- var import_fs15 = __toESM(require("fs"));
9786
- var import_path15 = require("path");
10096
+ var import_fs16 = __toESM(require("fs"));
10097
+ var import_path16 = require("path");
9787
10098
  var import_execa8 = __toESM(require_execa());
9788
- var import_build_utils18 = require("@vercel/build-utils");
9789
- var scriptPath2 = (0, import_path15.join)(__dirname, "..", "templates", "vc_django_settings.py");
9790
- var script2 = import_fs15.default.readFileSync(scriptPath2, "utf-8");
10099
+ var import_build_utils19 = require("@vercel/build-utils");
10100
+ var scriptPath2 = (0, import_path16.join)(__dirname, "..", "templates", "vc_django_settings.py");
10101
+ var script2 = import_fs16.default.readFileSync(scriptPath2, "utf-8");
9791
10102
  async function getDjangoSettings(projectDir, env) {
9792
10103
  const { stdout } = await (0, import_execa8.default)("python", ["-c", script2], {
9793
10104
  env,
@@ -9815,10 +10126,10 @@ async function runDjangoCollectStatic(venvPath, workPath, djangoPath, env, outpu
9815
10126
  const installedApps = djangoSettings["INSTALLED_APPS"] ?? [];
9816
10127
  const staticfilesDirs = djangoSettings["STATICFILES_DIRS"] ?? [];
9817
10128
  const staticSourceDirs = [
9818
- ...installedApps.map((app) => (0, import_path15.join)(djangoPath, ...app.split("."), "static")),
10129
+ ...installedApps.map((app) => (0, import_path16.join)(djangoPath, ...app.split("."), "static")),
9819
10130
  // TODO: Deal with optional prefixes in STATICFILES_DIRS.
9820
10131
  ...staticfilesDirs.map((d) => Array.isArray(d) ? d[1] : d)
9821
- ].filter((d) => import_fs15.default.existsSync(d));
10132
+ ].filter((d) => import_fs16.default.existsSync(d));
9822
10133
  if (storageBackend.startsWith("storages.backends.")) {
9823
10134
  console.log(
9824
10135
  "django-storages detected \u2014 running collectstatic with original settings"
@@ -9829,7 +10140,7 @@ async function runDjangoCollectStatic(venvPath, workPath, djangoPath, env, outpu
9829
10140
  });
9830
10141
  return {
9831
10142
  staticSourceDirs,
9832
- staticRoot: staticRoot ? (0, import_path15.resolve)(djangoPath, staticRoot) : null,
10143
+ staticRoot: staticRoot ? (0, import_path16.resolve)(djangoPath, staticRoot) : null,
9833
10144
  cdnOutputDir: null,
9834
10145
  manifestRelPath: null
9835
10146
  };
@@ -9841,9 +10152,9 @@ async function runDjangoCollectStatic(venvPath, workPath, djangoPath, env, outpu
9841
10152
  return null;
9842
10153
  }
9843
10154
  const staticUrlPath = staticUrl.replace(/^\/|\/$/g, "") || "static";
9844
- const staticOutputDir = (0, import_path15.join)(outputStaticDir, staticUrlPath);
9845
- await import_fs15.default.promises.mkdir(staticOutputDir, { recursive: true });
9846
- const shimPath = (0, import_path15.join)(djangoPath, "_vercel_collectstatic_settings.py");
10155
+ const staticOutputDir = (0, import_path16.join)(outputStaticDir, staticUrlPath);
10156
+ await import_fs16.default.promises.mkdir(staticOutputDir, { recursive: true });
10157
+ const shimPath = (0, import_path16.join)(djangoPath, "_vercel_collectstatic_settings.py");
9847
10158
  const shimLines = [
9848
10159
  `from ${settingsModule} import *`,
9849
10160
  `STATIC_ROOT = ${JSON.stringify(staticOutputDir)}`
@@ -9851,7 +10162,7 @@ async function runDjangoCollectStatic(venvPath, workPath, djangoPath, env, outpu
9851
10162
  if (whitenoiseUseFinders) {
9852
10163
  shimLines.push(`WHITENOISE_USE_FINDERS = False`);
9853
10164
  }
9854
- await import_fs15.default.promises.writeFile(shimPath, shimLines.join("\n") + "\n");
10165
+ await import_fs16.default.promises.writeFile(shimPath, shimLines.join("\n") + "\n");
9855
10166
  try {
9856
10167
  console.log("Running collectstatic...");
9857
10168
  await (0, import_execa8.default)(pythonPath, ["manage.py", "collectstatic", "--noinput"], {
@@ -9862,7 +10173,7 @@ async function runDjangoCollectStatic(venvPath, workPath, djangoPath, env, outpu
9862
10173
  cwd: djangoPath
9863
10174
  });
9864
10175
  } finally {
9865
- await import_fs15.default.promises.unlink(shimPath).catch(() => {
10176
+ await import_fs16.default.promises.unlink(shimPath).catch(() => {
9866
10177
  });
9867
10178
  }
9868
10179
  const MANIFEST_STORAGE_BACKENDS = [
@@ -9871,38 +10182,38 @@ async function runDjangoCollectStatic(venvPath, workPath, djangoPath, env, outpu
9871
10182
  ];
9872
10183
  let manifestRelPath = null;
9873
10184
  if (MANIFEST_STORAGE_BACKENDS.includes(storageBackend) && staticRoot) {
9874
- const manifestSrc = (0, import_path15.join)(staticOutputDir, "staticfiles.json");
9875
- const resolvedStaticRoot = (0, import_path15.resolve)(djangoPath, staticRoot);
9876
- const manifestDest = (0, import_path15.join)(resolvedStaticRoot, "staticfiles.json");
9877
- await import_fs15.default.promises.mkdir(resolvedStaticRoot, { recursive: true });
9878
- await import_fs15.default.promises.copyFile(manifestSrc, manifestDest);
9879
- manifestRelPath = (0, import_path15.relative)(workPath, manifestDest);
9880
- (0, import_build_utils18.debug)(`Copied staticfiles.json to ${manifestDest} for Lambda bundle`);
10185
+ const manifestSrc = (0, import_path16.join)(staticOutputDir, "staticfiles.json");
10186
+ const resolvedStaticRoot = (0, import_path16.resolve)(djangoPath, staticRoot);
10187
+ const manifestDest = (0, import_path16.join)(resolvedStaticRoot, "staticfiles.json");
10188
+ await import_fs16.default.promises.mkdir(resolvedStaticRoot, { recursive: true });
10189
+ await import_fs16.default.promises.copyFile(manifestSrc, manifestDest);
10190
+ manifestRelPath = (0, import_path16.relative)(workPath, manifestDest);
10191
+ (0, import_build_utils19.debug)(`Copied staticfiles.json to ${manifestDest} for Lambda bundle`);
9881
10192
  }
9882
10193
  return {
9883
10194
  staticSourceDirs,
9884
- staticRoot: staticRoot ? (0, import_path15.resolve)(djangoPath, staticRoot) : null,
10195
+ staticRoot: staticRoot ? (0, import_path16.resolve)(djangoPath, staticRoot) : null,
9885
10196
  cdnOutputDir: outputStaticDir,
9886
10197
  manifestRelPath
9887
10198
  };
9888
10199
  }
9889
10200
 
9890
10201
  // src/fastapi.ts
9891
- var import_fs16 = __toESM(require("fs"));
9892
- var import_path16 = require("path");
10202
+ var import_fs17 = __toESM(require("fs"));
10203
+ var import_path17 = require("path");
9893
10204
  var import_execa9 = __toESM(require_execa());
9894
- var import_build_utils19 = require("@vercel/build-utils");
9895
- var scriptPath3 = (0, import_path16.join)(__dirname, "..", "templates", "vc_fastapi_static.py");
10205
+ var import_build_utils20 = require("@vercel/build-utils");
10206
+ var scriptPath3 = (0, import_path17.join)(__dirname, "..", "templates", "vc_fastapi_static.py");
9896
10207
  var _STATIC_FILE_COLLECTION_ERROR_MESSAGE = "Warning: FastAPI static file collection failed. Static files will not be served from the CDN.";
9897
10208
  async function getFastAPIStaticMounts(venvPath, entrypointAbs, variableName, env, workPath) {
9898
10209
  const pythonPath = getVenvPythonBin(venvPath);
9899
- const outputPath = (0, import_path16.join)(
10210
+ const outputPath = (0, import_path17.join)(
9900
10211
  workPath,
9901
10212
  ".vercel",
9902
10213
  "python",
9903
10214
  "vc_fastapi_static_output.json"
9904
10215
  );
9905
- await import_fs16.default.promises.mkdir((0, import_path16.join)(workPath, ".vercel", "python"), {
10216
+ await import_fs17.default.promises.mkdir((0, import_path17.join)(workPath, ".vercel", "python"), {
9906
10217
  recursive: true
9907
10218
  });
9908
10219
  try {
@@ -9912,27 +10223,27 @@ async function getFastAPIStaticMounts(venvPath, entrypointAbs, variableName, env
9912
10223
  { env, cwd: workPath }
9913
10224
  );
9914
10225
  if (stderr) {
9915
- (0, import_build_utils19.debug)(`FastAPI shim stderr:
10226
+ (0, import_build_utils20.debug)(`FastAPI shim stderr:
9916
10227
  ${stderr}`);
9917
10228
  }
9918
10229
  } catch (err) {
9919
10230
  console.error(_STATIC_FILE_COLLECTION_ERROR_MESSAGE);
9920
- (0, import_build_utils19.debug)(
10231
+ (0, import_build_utils20.debug)(
9921
10232
  `FastAPI: could not discover static mounts: ${err?.stderr ?? err?.message ?? err}`
9922
10233
  );
9923
10234
  return [];
9924
10235
  }
9925
10236
  try {
9926
- const raw = await import_fs16.default.promises.readFile(outputPath, "utf8");
10237
+ const raw = await import_fs17.default.promises.readFile(outputPath, "utf8");
9927
10238
  const parsed = JSON.parse(raw);
9928
- (0, import_build_utils19.debug)(`FastAPI: discovered mounts: ${JSON.stringify(parsed)}`);
10239
+ (0, import_build_utils20.debug)(`FastAPI: discovered mounts: ${JSON.stringify(parsed)}`);
9929
10240
  return parsed;
9930
10241
  } catch {
9931
10242
  console.error(_STATIC_FILE_COLLECTION_ERROR_MESSAGE);
9932
- (0, import_build_utils19.debug)(`FastAPI: could not read shim output file: ${outputPath}`);
10243
+ (0, import_build_utils20.debug)(`FastAPI: could not read shim output file: ${outputPath}`);
9933
10244
  return [];
9934
10245
  } finally {
9935
- await import_fs16.default.promises.rm(outputPath, { force: true });
10246
+ await import_fs17.default.promises.rm(outputPath, { force: true });
9936
10247
  }
9937
10248
  }
9938
10249
  async function runFastAPICollectStatic(venvPath, workPath, env, outputStaticDir, entrypointAbs, variableName) {
@@ -9944,18 +10255,18 @@ async function runFastAPICollectStatic(venvPath, workPath, env, outputStaticDir,
9944
10255
  workPath
9945
10256
  );
9946
10257
  if (mounts.length === 0) {
9947
- (0, import_build_utils19.debug)("FastAPI: no StaticFiles mounts found, skipping");
10258
+ (0, import_build_utils20.debug)("FastAPI: no StaticFiles mounts found, skipping");
9948
10259
  return null;
9949
10260
  }
9950
- (0, import_build_utils19.debug)(
10261
+ (0, import_build_utils20.debug)(
9951
10262
  `Found ${mounts.length} FastAPI static mount(s): ${mounts.map((m) => m.urlPath).join(", ")}`
9952
10263
  );
9953
10264
  for (const mount of mounts) {
9954
10265
  const urlSubPath = mount.urlPath.replace(/^\/|\/$/g, "");
9955
- const dest = (0, import_path16.join)(outputStaticDir, urlSubPath);
9956
- await import_fs16.default.promises.mkdir(dest, { recursive: true });
9957
- await import_fs16.default.promises.cp(mount.directory, dest, { recursive: true });
9958
- (0, import_build_utils19.debug)(`copied ${mount.directory} -> ${dest}`);
10266
+ const dest = (0, import_path17.join)(outputStaticDir, urlSubPath);
10267
+ await import_fs17.default.promises.mkdir(dest, { recursive: true });
10268
+ await import_fs17.default.promises.cp(mount.directory, dest, { recursive: true });
10269
+ (0, import_build_utils20.debug)(`copied ${mount.directory} -> ${dest}`);
9959
10270
  }
9960
10271
  return {
9961
10272
  collectedMounts: mounts.map((m) => m.urlPath),
@@ -10011,10 +10322,10 @@ function fillBytecodeWithinCapacity(files, rankedItems, capacity) {
10011
10322
 
10012
10323
  // src/compileall.ts
10013
10324
  var import_execa10 = __toESM(require_execa());
10014
- var import_build_utils20 = require("@vercel/build-utils");
10015
- var import_fs17 = __toESM(require("fs"));
10325
+ var import_build_utils21 = require("@vercel/build-utils");
10326
+ var import_fs18 = __toESM(require("fs"));
10016
10327
  var import_os3 = require("os");
10017
- var import_path17 = require("path");
10328
+ var import_path18 = require("path");
10018
10329
  var COMPILEALL_TIMEOUT_MS = 5 * 60 * 1e3;
10019
10330
  var PYCACHE_PREFIX_DIR = "_vc_pycache";
10020
10331
  var RUNTIME_PYCACHE_PREFIX = `/var/task/${PYCACHE_PREFIX_DIR}`;
@@ -10050,13 +10361,13 @@ async function runCompileAll({
10050
10361
  }
10051
10362
  let tempDir;
10052
10363
  try {
10053
- tempDir = await import_fs17.default.promises.mkdtemp(
10054
- (0, import_path17.join)((0, import_os3.tmpdir)(), "vercel-python-compileall-")
10364
+ tempDir = await import_fs18.default.promises.mkdtemp(
10365
+ (0, import_path18.join)((0, import_os3.tmpdir)(), "vercel-python-compileall-")
10055
10366
  );
10056
- const listPath = (0, import_path17.join)(tempDir, "pysources.json");
10057
- await import_fs17.default.promises.writeFile(listPath, JSON.stringify(uniqueSourceFiles));
10058
- const timingsPath = (0, import_path17.join)(tempDir, "timings.json");
10059
- const scriptPath4 = (0, import_path17.join)(__dirname, "..", "templates", "vc_compileall.py");
10367
+ const listPath = (0, import_path18.join)(tempDir, "pysources.json");
10368
+ await import_fs18.default.promises.writeFile(listPath, JSON.stringify(uniqueSourceFiles));
10369
+ const timingsPath = (0, import_path18.join)(tempDir, "timings.json");
10370
+ const scriptPath4 = (0, import_path18.join)(__dirname, "..", "templates", "vc_compileall.py");
10060
10371
  const baseEnv = env || process.env;
10061
10372
  const subprocessEnv = pycachePrefix ? { ...baseEnv, PYTHONPYCACHEPREFIX: pycachePrefix } : baseEnv;
10062
10373
  await (0, import_execa10.default)(pythonBin, [scriptPath4, listPath, timingsPath], {
@@ -10065,21 +10376,21 @@ async function runCompileAll({
10065
10376
  });
10066
10377
  let timings;
10067
10378
  try {
10068
- const raw = await import_fs17.default.promises.readFile(timingsPath, "utf8");
10379
+ const raw = await import_fs18.default.promises.readFile(timingsPath, "utf8");
10069
10380
  timings = new Map(Object.entries(JSON.parse(raw)));
10070
10381
  } catch (err) {
10071
- (0, import_build_utils20.debug)(`compileall timings unavailable: ${String(err)}`);
10382
+ (0, import_build_utils21.debug)(`compileall timings unavailable: ${String(err)}`);
10072
10383
  }
10073
10384
  return { success: true, timings };
10074
10385
  } catch (err) {
10075
- (0, import_build_utils20.debug)(`compileall error details: ${JSON.stringify(err)}`);
10386
+ (0, import_build_utils21.debug)(`compileall error details: ${JSON.stringify(err)}`);
10076
10387
  return { success: false };
10077
10388
  } finally {
10078
10389
  if (tempDir) {
10079
10390
  try {
10080
- await import_fs17.default.promises.rm(tempDir, { recursive: true, force: true });
10391
+ await import_fs18.default.promises.rm(tempDir, { recursive: true, force: true });
10081
10392
  } catch (err) {
10082
- (0, import_build_utils20.debug)(`compileall temporary file cleanup error: ${String(err)}`);
10393
+ (0, import_build_utils21.debug)(`compileall temporary file cleanup error: ${String(err)}`);
10083
10394
  }
10084
10395
  }
10085
10396
  }
@@ -10116,7 +10427,7 @@ function deriveStagedPycFsPath(stagingDir, srcAbsPath, pythonMajor, pythonMinor)
10116
10427
  );
10117
10428
  if (!rel)
10118
10429
  return null;
10119
- return (0, import_path17.join)(stagingDir, rel.replaceAll("/", import_path17.sep));
10430
+ return (0, import_path18.join)(stagingDir, rel.replaceAll("/", import_path18.sep));
10120
10431
  }
10121
10432
  function derivePrefixPycBundlePath(runtimeAbsPath, pythonMajor, pythonMinor) {
10122
10433
  const rel = derivePrefixPycRelPath(
@@ -10140,7 +10451,7 @@ async function collectAppPrefixBytecodeFiles({
10140
10451
  for (const bundlePath of Object.keys(appFiles)) {
10141
10452
  if (!bundlePath.endsWith(".py"))
10142
10453
  continue;
10143
- const sourceAbsPath = (0, import_path17.join)(workPath, bundlePath.replaceAll("/", import_path17.sep));
10454
+ const sourceAbsPath = (0, import_path18.join)(workPath, bundlePath.replaceAll("/", import_path18.sep));
10144
10455
  const stagedFsPath = deriveStagedPycFsPath(
10145
10456
  stagingDir,
10146
10457
  sourceAbsPath,
@@ -10164,7 +10475,7 @@ async function collectAppPrefixBytecodeFiles({
10164
10475
  const results = await Promise.all(
10165
10476
  pending.map(async ({ bundlePath, srcFsPath, moduleKey, sourceAbsPath }) => {
10166
10477
  try {
10167
- const stats = await import_fs17.default.promises.stat(srcFsPath);
10478
+ const stats = await import_fs18.default.promises.stat(srcFsPath);
10168
10479
  return {
10169
10480
  bundlePath,
10170
10481
  srcFsPath,
@@ -10184,7 +10495,7 @@ async function collectAppPrefixBytecodeFiles({
10184
10495
  for (const result of results) {
10185
10496
  if (!result)
10186
10497
  continue;
10187
- const file = new import_build_utils20.FileFsRef({
10498
+ const file = new import_build_utils21.FileFsRef({
10188
10499
  fsPath: result.srcFsPath,
10189
10500
  size: result.size
10190
10501
  });
@@ -10214,15 +10525,15 @@ async function collectAppBytecodeFiles({
10214
10525
  continue;
10215
10526
  pending.push({
10216
10527
  bundlePath: pycRel,
10217
- srcFsPath: (0, import_path17.join)(workPath, pycRel.replaceAll("/", import_path17.sep)),
10528
+ srcFsPath: (0, import_path18.join)(workPath, pycRel.replaceAll("/", import_path18.sep)),
10218
10529
  moduleKey: bundlePath,
10219
- sourceAbsPath: (0, import_path17.join)(workPath, bundlePath.replaceAll("/", import_path17.sep))
10530
+ sourceAbsPath: (0, import_path18.join)(workPath, bundlePath.replaceAll("/", import_path18.sep))
10220
10531
  });
10221
10532
  }
10222
10533
  const results = await Promise.all(
10223
10534
  pending.map(async ({ bundlePath, srcFsPath, moduleKey, sourceAbsPath }) => {
10224
10535
  try {
10225
- const stats = await import_fs17.default.promises.stat(srcFsPath);
10536
+ const stats = await import_fs18.default.promises.stat(srcFsPath);
10226
10537
  return {
10227
10538
  bundlePath,
10228
10539
  srcFsPath,
@@ -10242,7 +10553,7 @@ async function collectAppBytecodeFiles({
10242
10553
  for (const result of results) {
10243
10554
  if (!result)
10244
10555
  continue;
10245
- const file = new import_build_utils20.FileFsRef({
10556
+ const file = new import_build_utils21.FileFsRef({
10246
10557
  fsPath: result.srcFsPath,
10247
10558
  size: result.size
10248
10559
  });
@@ -10261,9 +10572,9 @@ async function collectAppBytecodeFiles({
10261
10572
  }
10262
10573
 
10263
10574
  // src/installed-distributions.ts
10264
- var import_fs18 = __toESM(require("fs"));
10265
- var import_path18 = require("path");
10266
- var import_build_utils21 = require("@vercel/build-utils");
10575
+ var import_fs19 = __toESM(require("fs"));
10576
+ var import_path19 = require("path");
10577
+ var import_build_utils22 = require("@vercel/build-utils");
10267
10578
  var import_python_analysis11 = require("@vercel/python-analysis");
10268
10579
  var STRIP_BASENAMES = /* @__PURE__ */ new Set([
10269
10580
  "py.typed",
@@ -10272,7 +10583,7 @@ var STRIP_BASENAMES = /* @__PURE__ */ new Set([
10272
10583
  "direct_url.json"
10273
10584
  ]);
10274
10585
  function shouldStripVendorFile(filePath) {
10275
- const segments = filePath.split(import_path18.sep);
10586
+ const segments = filePath.split(import_path19.sep);
10276
10587
  if (segments.includes("__pycache__"))
10277
10588
  return true;
10278
10589
  const name = segments[segments.length - 1] ?? "";
@@ -10296,19 +10607,19 @@ function getDistributionFileGroups({
10296
10607
  const dirDistributions = distributions.get(dir);
10297
10608
  if (!dirDistributions)
10298
10609
  continue;
10299
- const sitePackagesDir = (0, import_path18.resolve)(dir);
10610
+ const sitePackagesDir = (0, import_path19.resolve)(dir);
10300
10611
  for (const [name, distribution] of dirDistributions) {
10301
10612
  const packageName = (0, import_python_analysis11.normalizePackageName)(name);
10302
10613
  if (includeSet && !includeSet.has(packageName))
10303
10614
  continue;
10304
10615
  const files = [];
10305
10616
  for (const record of distribution.files) {
10306
- const absolutePath = (0, import_path18.resolve)(
10617
+ const absolutePath = (0, import_path19.resolve)(
10307
10618
  sitePackagesDir,
10308
- record.path.replaceAll("/", import_path18.sep)
10619
+ record.path.replaceAll("/", import_path19.sep)
10309
10620
  );
10310
- const relativePath = (0, import_path18.relative)(sitePackagesDir, absolutePath);
10311
- if (relativePath === "" || relativePath === ".." || relativePath.startsWith(`..${import_path18.sep}`) || (0, import_path18.isAbsolute)(relativePath)) {
10621
+ const relativePath = (0, import_path19.relative)(sitePackagesDir, absolutePath);
10622
+ if (relativePath === "" || relativePath === ".." || relativePath.startsWith(`..${import_path19.sep}`) || (0, import_path19.isAbsolute)(relativePath)) {
10312
10623
  continue;
10313
10624
  }
10314
10625
  files.push({ absolutePath, relativePath, record });
@@ -10328,7 +10639,7 @@ var InstalledPythonDistributions = class _InstalledPythonDistributions {
10328
10639
  const distributions = /* @__PURE__ */ new Map();
10329
10640
  for (const dir of sitePackageDirs) {
10330
10641
  try {
10331
- await import_fs18.default.promises.access(dir);
10642
+ await import_fs19.default.promises.access(dir);
10332
10643
  } catch {
10333
10644
  continue;
10334
10645
  }
@@ -10369,7 +10680,7 @@ var InstalledPythonDistributions = class _InstalledPythonDistributions {
10369
10680
  if (shouldStripVendorFile(relativePath))
10370
10681
  continue;
10371
10682
  pending.push({
10372
- bundlePath: (0, import_path18.join)(vendorDirName, relativePath).replace(/\\/g, "/"),
10683
+ bundlePath: (0, import_path19.join)(vendorDirName, relativePath).replace(/\\/g, "/"),
10373
10684
  srcFsPath: absolutePath,
10374
10685
  recordSize: record.size != null ? Number(record.size) : void 0
10375
10686
  });
@@ -10379,10 +10690,10 @@ var InstalledPythonDistributions = class _InstalledPythonDistributions {
10379
10690
  pending.map(async ({ bundlePath, srcFsPath, recordSize }) => {
10380
10691
  try {
10381
10692
  if (recordSize === void 0) {
10382
- const stats = await import_fs18.default.promises.stat(srcFsPath);
10693
+ const stats = await import_fs19.default.promises.stat(srcFsPath);
10383
10694
  return { bundlePath, srcFsPath, size: stats.size };
10384
10695
  }
10385
- await import_fs18.default.promises.access(srcFsPath);
10696
+ await import_fs19.default.promises.access(srcFsPath);
10386
10697
  return { bundlePath, srcFsPath, size: recordSize };
10387
10698
  } catch {
10388
10699
  return null;
@@ -10393,12 +10704,12 @@ var InstalledPythonDistributions = class _InstalledPythonDistributions {
10393
10704
  for (const result of results) {
10394
10705
  if (!result)
10395
10706
  continue;
10396
- vendorFiles[result.bundlePath] = new import_build_utils21.FileFsRef({
10707
+ vendorFiles[result.bundlePath] = new import_build_utils22.FileFsRef({
10397
10708
  fsPath: result.srcFsPath,
10398
10709
  size: result.size
10399
10710
  });
10400
10711
  }
10401
- (0, import_build_utils21.debug)(
10712
+ (0, import_build_utils22.debug)(
10402
10713
  `Mirrored ${Object.keys(vendorFiles).length} files` + (includePackages ? ` from ${includePackages.length} packages` : "")
10403
10714
  );
10404
10715
  return vendorFiles;
@@ -10419,7 +10730,7 @@ var InstalledPythonDistributions = class _InstalledPythonDistributions {
10419
10730
  knownSize += Number(record.size);
10420
10731
  } else {
10421
10732
  statPromises.push(
10422
- import_fs18.default.promises.stat(absolutePath).then((stats) => stats.size).catch(() => 0)
10733
+ import_fs19.default.promises.stat(absolutePath).then((stats) => stats.size).catch(() => 0)
10423
10734
  );
10424
10735
  }
10425
10736
  }
@@ -10462,7 +10773,7 @@ var InstalledPythonDistributions = class _InstalledPythonDistributions {
10462
10773
  });
10463
10774
  for (const { packageName, sitePackagesDir, files } of distributionGroups) {
10464
10775
  for (const { relativePath } of files) {
10465
- const moduleKey = relativePath.replaceAll(import_path18.sep, "/");
10776
+ const moduleKey = relativePath.replaceAll(import_path19.sep, "/");
10466
10777
  const pycRelativePath = derivePycPath(
10467
10778
  moduleKey,
10468
10779
  this.pythonMajor,
@@ -10470,18 +10781,18 @@ var InstalledPythonDistributions = class _InstalledPythonDistributions {
10470
10781
  );
10471
10782
  if (!pycRelativePath)
10472
10783
  continue;
10473
- const pycFilePath = pycRelativePath.replaceAll("/", import_path18.sep);
10784
+ const pycFilePath = pycRelativePath.replaceAll("/", import_path19.sep);
10474
10785
  pending.push({
10475
- bundlePath: (0, import_path18.join)(vendorDirName, pycFilePath).replace(/\\/g, "/"),
10476
- srcFsPath: (0, import_path18.join)(sitePackagesDir, pycFilePath),
10786
+ bundlePath: (0, import_path19.join)(vendorDirName, pycFilePath).replace(/\\/g, "/"),
10787
+ srcFsPath: (0, import_path19.join)(sitePackagesDir, pycFilePath),
10477
10788
  packageName,
10478
10789
  moduleKey,
10479
- sourceAbsPath: (0, import_path18.join)(sitePackagesDir, relativePath)
10790
+ sourceAbsPath: (0, import_path19.join)(sitePackagesDir, relativePath)
10480
10791
  });
10481
10792
  }
10482
10793
  }
10483
10794
  const result = await this.collectExistingBytecode(pending);
10484
- (0, import_build_utils21.debug)(
10795
+ (0, import_build_utils22.debug)(
10485
10796
  `Collected ${Object.keys(result.files).length} bytecode files (${(result.totalSize / (1024 * 1024)).toFixed(2)} MB)` + (includePackages ? ` from ${includePackages.length} packages` : "")
10486
10797
  );
10487
10798
  return result;
@@ -10504,7 +10815,7 @@ var InstalledPythonDistributions = class _InstalledPythonDistributions {
10504
10815
  for (const { absolutePath, relativePath } of files) {
10505
10816
  if (!relativePath.endsWith(".py"))
10506
10817
  continue;
10507
- const recordPath = relativePath.replaceAll(import_path18.sep, "/");
10818
+ const recordPath = relativePath.replaceAll(import_path19.sep, "/");
10508
10819
  const srcFsPath = deriveStagedPycFsPath(
10509
10820
  stagingDir,
10510
10821
  absolutePath,
@@ -10528,7 +10839,7 @@ var InstalledPythonDistributions = class _InstalledPythonDistributions {
10528
10839
  }
10529
10840
  }
10530
10841
  const result = await this.collectExistingBytecode(pending);
10531
- (0, import_build_utils21.debug)(
10842
+ (0, import_build_utils22.debug)(
10532
10843
  `Collected ${Object.keys(result.files).length} prefix bytecode files (${(result.totalSize / (1024 * 1024)).toFixed(2)} MB) for runtime root ${runtimeRoot}` + (includePackages ? ` from ${includePackages.length} packages` : "")
10533
10844
  );
10534
10845
  return result;
@@ -10544,7 +10855,7 @@ var InstalledPythonDistributions = class _InstalledPythonDistributions {
10544
10855
  sourceAbsPath
10545
10856
  }) => {
10546
10857
  try {
10547
- const stats = await import_fs18.default.promises.stat(srcFsPath);
10858
+ const stats = await import_fs19.default.promises.stat(srcFsPath);
10548
10859
  return {
10549
10860
  bundlePath,
10550
10861
  srcFsPath,
@@ -10566,7 +10877,7 @@ var InstalledPythonDistributions = class _InstalledPythonDistributions {
10566
10877
  for (const result of results) {
10567
10878
  if (!result)
10568
10879
  continue;
10569
- const file = new import_build_utils21.FileFsRef({
10880
+ const file = new import_build_utils22.FileFsRef({
10570
10881
  fsPath: result.srcFsPath,
10571
10882
  size: result.size
10572
10883
  });
@@ -10588,84 +10899,6 @@ var InstalledPythonDistributions = class _InstalledPythonDistributions {
10588
10899
  }
10589
10900
  };
10590
10901
 
10591
- // src/workflows.ts
10592
- var import_path19 = require("path");
10593
- var import_fs19 = __toESM(require("fs"));
10594
- var import_build_utils22 = require("@vercel/build-utils");
10595
- var WORKFLOW_OUTPUT_DIR = "_py_workflows";
10596
- var WORKFLOW_TOPIC_PATTERN = "__wkf_*";
10597
- var WORKFLOW_FIELD_NAMES = /* @__PURE__ */ new Set(["entrypoint"]);
10598
- function getWorkflowOutputPath(workflowName) {
10599
- return `${WORKFLOW_OUTPUT_DIR}/${safePathSegment(workflowName)}`;
10600
- }
10601
- function getWorkflowConsumerName(workflowName) {
10602
- return (0, import_build_utils22.sanitizeConsumerName)(getWorkflowOutputPath(workflowName));
10603
- }
10604
- async function getPyprojectWorkflows(workPath) {
10605
- const pyprojectPath = (0, import_path19.join)(workPath, "pyproject.toml");
10606
- if (!import_fs19.default.existsSync(pyprojectPath)) {
10607
- return [];
10608
- }
10609
- const pyproject = await (0, import_build_utils22.readConfigFile)(pyprojectPath);
10610
- const workflows = pyproject?.tool?.vercel?.workflows;
10611
- if (!workflows) {
10612
- return [];
10613
- }
10614
- if (!Array.isArray(workflows)) {
10615
- throw workflowError('"tool.vercel.workflows" must be an array');
10616
- }
10617
- if (workflows.length > 1) {
10618
- throw workflowError(
10619
- '"tool.vercel.workflows" must declare a single entrypoint that registers every workflow'
10620
- );
10621
- }
10622
- return Promise.all(
10623
- workflows.map((config, index) => parseWorkflow(workPath, index, config))
10624
- );
10625
- }
10626
- async function parseWorkflow(workPath, index, config) {
10627
- const label = `workflow #${index + 1}`;
10628
- if (!config || typeof config !== "object" || Array.isArray(config)) {
10629
- throw workflowError(`${label} must be an object`);
10630
- }
10631
- for (const key of Object.keys(config)) {
10632
- if (!WORKFLOW_FIELD_NAMES.has(key)) {
10633
- throw workflowError(`${label} has unrecognized field "${key}"`);
10634
- }
10635
- }
10636
- if (typeof config.entrypoint !== "string") {
10637
- throw workflowError(`${label} must define string field "entrypoint"`);
10638
- }
10639
- const entrypoint = parseModuleEntrypoint(config.entrypoint);
10640
- if (!entrypoint) {
10641
- throw workflowError(
10642
- `${label} has invalid entrypoint "${config.entrypoint}". Use "module:object"`
10643
- );
10644
- }
10645
- const name = getModuleEntrypointName(entrypoint);
10646
- const existingEntrypoint = await resolveExistingEntrypoint(
10647
- workPath,
10648
- entrypoint.filePath
10649
- );
10650
- if (!existingEntrypoint) {
10651
- throw workflowError(
10652
- `workflow "${name}" has entrypoint "${config.entrypoint}" but file "${entrypoint.filePath}" does not exist`
10653
- );
10654
- }
10655
- return {
10656
- name,
10657
- entrypoint: existingEntrypoint,
10658
- moduleName: entrypoint.moduleName,
10659
- variableName: entrypoint.variableName
10660
- };
10661
- }
10662
- function workflowError(message) {
10663
- return new import_build_utils22.NowBuildError({
10664
- code: "PYTHON_INVALID_WORKFLOW_CONFIG",
10665
- message
10666
- });
10667
- }
10668
-
10669
10902
  // src/import-closure.ts
10670
10903
  var import_path20 = require("path");
10671
10904
  var import_build_utils23 = require("@vercel/build-utils");
@@ -10776,7 +11009,7 @@ async function getDevSidecars({
10776
11009
  use: build2.use,
10777
11010
  src: subscriber.entrypoint,
10778
11011
  config: {
10779
- handlerFunction: subscriber.variableName,
11012
+ ...subscriber.variableName === void 0 ? {} : { handlerFunction: subscriber.variableName },
10780
11013
  pythonQueueSidecar: "subscriber"
10781
11014
  }
10782
11015
  },
@@ -10799,7 +11032,7 @@ async function getDevSidecars({
10799
11032
  pythonQueueSidecar: "workflow"
10800
11033
  }
10801
11034
  },
10802
- topics: [{ topic: WORKFLOW_TOPIC_PATTERN }]
11035
+ topics: [{ topic: WORKFLOW_DEV_TOPIC_PATTERN }]
10803
11036
  })
10804
11037
  )
10805
11038
  ];
@@ -11403,11 +11636,14 @@ var build = async ({
11403
11636
  projectDir: (0, import_path21.join)(workPath, entryDirectory),
11404
11637
  pipPlatformArgs
11405
11638
  });
11406
- const conditionalInjectedPackages = usedUvManagedInstall && !legacyWorkersProject ? await getConditionalInjectedPackages({
11639
+ const queueAdapterBootstrap = await getQueueAdapterBootstrap({
11407
11640
  pythonPackage,
11408
- env: baseEnv
11409
- }) : [];
11410
- for (const injectedPackage of conditionalInjectedPackages) {
11641
+ env: baseEnv,
11642
+ legacyWorkersProject,
11643
+ hasDeclaredSubscribers: await hasPyprojectSubscribers(workPath)
11644
+ });
11645
+ const queueAdapterInjectedPackages = usedUvManagedInstall ? queueAdapterBootstrap.injectedPackages : [];
11646
+ for (const injectedPackage of queueAdapterInjectedPackages) {
11411
11647
  await installInjectedPackage({
11412
11648
  ...injectedPackage,
11413
11649
  uv,
@@ -11424,6 +11660,12 @@ var build = async ({
11424
11660
  projectDir: (0, import_path21.join)(workPath, entryDirectory),
11425
11661
  uvLockPath
11426
11662
  });
11663
+ if (workflowMode === "workers" && workflows.length > 1) {
11664
+ throw new import_build_utils24.NowBuildError({
11665
+ code: "PYTHON_INVALID_WORKFLOW_CONFIG",
11666
+ message: `"tool.vercel.workflows" declares multiple entrypoints, which requires vercel>=${MIN_QUEUE_WORKFLOW_SDK_VERSION} with a distinct namespace per Workflows registry; the installed SDK serves every workflow on the shared __wkf_* topic`
11667
+ });
11668
+ }
11427
11669
  }
11428
11670
  const shouldInstallVercelWorkers = legacyWorkersProject || workflows.length > 0 && workflowMode === "workers";
11429
11671
  if (shouldInstallVercelWorkers) {
@@ -11442,7 +11684,7 @@ var build = async ({
11442
11684
  if (quirksResult.buildEnv) {
11443
11685
  Object.assign(pythonEnv, quirksResult.buildEnv);
11444
11686
  }
11445
- const queueIntegrations = legacyWorkersProject ? [] : await getQueueIntegrations({ pythonPackage });
11687
+ const queueIntegrations = queueAdapterBootstrap.integrations;
11446
11688
  const writeGeneratedQueueHandler = async (outputPath, declaration) => {
11447
11689
  const generatedPath = getGeneratedQueueHandlerPath(outputPath);
11448
11690
  await import_fs20.default.promises.mkdir((0, import_path21.dirname)((0, import_path21.join)(workPath, generatedPath)), {
@@ -11465,7 +11707,7 @@ var build = async ({
11465
11707
  for (const subscriber of subscribers) {
11466
11708
  if (!subscriber.topicPatterns) {
11467
11709
  subscriber.subscriptions = subscriber.subscriptions.filter(
11468
- (subscription) => !subscription.topic.startsWith("__wkf_")
11710
+ (subscription) => !isWorkflowQueueTopic(subscription.topic)
11469
11711
  );
11470
11712
  }
11471
11713
  }
@@ -11484,8 +11726,7 @@ var build = async ({
11484
11726
  name: workflow.name,
11485
11727
  entrypoint: workflow.entrypoint,
11486
11728
  moduleName: workflow.moduleName,
11487
- variableName: workflow.variableName,
11488
- topicPatterns: [WORKFLOW_TOPIC_PATTERN]
11729
+ variableName: workflow.variableName
11489
11730
  })),
11490
11731
  uv,
11491
11732
  venvPath,
@@ -11493,6 +11734,21 @@ var build = async ({
11493
11734
  kind: "workflow",
11494
11735
  integrations: queueIntegrations
11495
11736
  });
11737
+ for (let i = 0; i < resolved2.length; i++) {
11738
+ for (let j = i + 1; j < resolved2.length; j++) {
11739
+ const overlaps = resolved2[i].subscriptions.some(
11740
+ (left) => resolved2[j].subscriptions.some(
11741
+ (right) => queueTopicPatternsOverlap(left.topic, right.topic)
11742
+ )
11743
+ );
11744
+ if (overlaps) {
11745
+ throw new import_build_utils24.NowBuildError({
11746
+ code: "PYTHON_INVALID_WORKFLOW_CONFIG",
11747
+ message: `workflow entrypoints "${resolved2[i].moduleName}:${resolved2[i].variableName}" and "${resolved2[j].moduleName}:${resolved2[j].variableName}" subscribe to overlapping queue topics; construct each vercel.workflow.Workflows registry with a distinct namespace`
11748
+ });
11749
+ }
11750
+ }
11751
+ }
11496
11752
  for (const workflow of resolved2) {
11497
11753
  workflowQueueSubscriptions.set(workflow.name, workflow.subscriptions);
11498
11754
  await writeGeneratedQueueHandler(
@@ -11598,6 +11854,18 @@ var build = async ({
11598
11854
  ({ module: module2, installer, servingActivator }) => `${module2}:${installer}` + (servingActivator ? `:${servingActivator}` : "")
11599
11855
  ).join(",");
11600
11856
  }
11857
+ const apschedulerSubscribers = apschedulerSubscriberIdentities(subscribers);
11858
+ if (apschedulerSubscribers.length > 0) {
11859
+ lambdaEnv.VERCEL_APSCHEDULER_SUBSCRIBERS = JSON.stringify(
11860
+ apschedulerSubscribers
11861
+ );
11862
+ const previewConfig = await getApschedulerPreviewConfig(workPath);
11863
+ if (previewConfig) {
11864
+ lambdaEnv.VERCEL_APSCHEDULER_PREVIEW_IDLE_TIMEOUT_SECONDS = String(
11865
+ previewConfig.idleTimeoutSeconds
11866
+ );
11867
+ }
11868
+ }
11601
11869
  const globOptions = {
11602
11870
  cwd: workPath,
11603
11871
  ignore: config && typeof config.excludeFiles === "string" ? [...predefinedExcludes, config.excludeFiles] : predefinedExcludes
@@ -11934,7 +12202,9 @@ var build = async ({
11934
12202
  runtime: pythonVersion.runtime,
11935
12203
  ...lambdaOptions,
11936
12204
  architecture: target.architecture,
11937
- environment: lambdaEnv,
12205
+ environment: {
12206
+ ...lambdaEnv
12207
+ },
11938
12208
  supportsResponseStreaming: true
11939
12209
  });
11940
12210
  }
@@ -11972,7 +12242,12 @@ var build = async ({
11972
12242
  handler: `${handlerPyFilename}.vc_handler`,
11973
12243
  runtime: pythonVersion.runtime,
11974
12244
  architecture: target.architecture,
11975
- environment: lambdaEnv,
12245
+ environment: {
12246
+ ...lambdaEnv,
12247
+ // The runtime activates publish-side integrations before importing the
12248
+ // generated subscriber module, so the identity must already be present.
12249
+ VERCEL_PYTHON_SUBSCRIBER_ID: subscriber.name
12250
+ },
11976
12251
  experimentalTriggers,
11977
12252
  supportsResponseStreaming: true
11978
12253
  });
@@ -11984,6 +12259,11 @@ var build = async ({
11984
12259
  const consumer = getSubscriberConsumerName(declaration.name);
11985
12260
  const legacy = declaration.legacy;
11986
12261
  (0, import_assert.default)(legacy, "legacy subscriber declarations must carry legacy config");
12262
+ const { variableName } = declaration;
12263
+ (0, import_assert.default)(
12264
+ variableName,
12265
+ "legacy subscriber declarations must name an entrypoint object"
12266
+ );
11987
12267
  const experimentalTriggers = legacy.topics.map((topic) => ({
11988
12268
  type: "queue/v2beta",
11989
12269
  topic,
@@ -11998,7 +12278,7 @@ var build = async ({
11998
12278
  moduleName: declaration.moduleName,
11999
12279
  entrypoint: declaration.entrypoint,
12000
12280
  vendorDir,
12001
- variableName: declaration.variableName
12281
+ variableName
12002
12282
  })
12003
12283
  })
12004
12284
  },