@workflow/world-testing 4.1.0-beta.58 → 4.1.0-beta.59

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.
@@ -200,12 +200,12 @@ var require_headers = __commonJS({
200
200
  var POSTAL_CODE_HEADER_NAME = "x-vercel-ip-postal-code";
201
201
  var REQUEST_ID_HEADER_NAME = "x-vercel-id";
202
202
  var EMOJI_FLAG_UNICODE_STARTING_POSITION = 127397;
203
- function getHeader(headers, key) {
203
+ function getHeader2(headers, key) {
204
204
  return headers.get(key) ?? void 0;
205
205
  }
206
- __name(getHeader, "getHeader");
206
+ __name(getHeader2, "getHeader");
207
207
  function getHeaderWithDecode(request, key) {
208
- const header = getHeader(request.headers, key);
208
+ const header = getHeader2(request.headers, key);
209
209
  return header ? decodeURIComponent(header) : void 0;
210
210
  }
211
211
  __name(getHeaderWithDecode, "getHeaderWithDecode");
@@ -218,7 +218,7 @@ var require_headers = __commonJS({
218
218
  __name(getFlag, "getFlag");
219
219
  function ipAddress2(input) {
220
220
  const headers = "headers" in input ? input.headers : input;
221
- return getHeader(headers, IP_HEADER_NAME);
221
+ return getHeader2(headers, IP_HEADER_NAME);
222
222
  }
223
223
  __name(ipAddress2, "ipAddress");
224
224
  function getRegionFromRequestId(requestId) {
@@ -232,13 +232,13 @@ var require_headers = __commonJS({
232
232
  return {
233
233
  // city name may be encoded to support multi-byte characters
234
234
  city: getHeaderWithDecode(request, CITY_HEADER_NAME),
235
- country: getHeader(request.headers, COUNTRY_HEADER_NAME),
236
- flag: getFlag(getHeader(request.headers, COUNTRY_HEADER_NAME)),
237
- countryRegion: getHeader(request.headers, REGION_HEADER_NAME),
238
- region: getRegionFromRequestId(getHeader(request.headers, REQUEST_ID_HEADER_NAME)),
239
- latitude: getHeader(request.headers, LATITUDE_HEADER_NAME),
240
- longitude: getHeader(request.headers, LONGITUDE_HEADER_NAME),
241
- postalCode: getHeader(request.headers, POSTAL_CODE_HEADER_NAME)
235
+ country: getHeader2(request.headers, COUNTRY_HEADER_NAME),
236
+ flag: getFlag(getHeader2(request.headers, COUNTRY_HEADER_NAME)),
237
+ countryRegion: getHeader2(request.headers, REGION_HEADER_NAME),
238
+ region: getRegionFromRequestId(getHeader2(request.headers, REQUEST_ID_HEADER_NAME)),
239
+ latitude: getHeader2(request.headers, LATITUDE_HEADER_NAME),
240
+ longitude: getHeader2(request.headers, LONGITUDE_HEADER_NAME),
241
+ postalCode: getHeader2(request.headers, POSTAL_CODE_HEADER_NAME)
242
242
  };
243
243
  }
244
244
  __name(geolocation2, "geolocation");
@@ -4182,7 +4182,7 @@ var require_token_util = __commonJS({
4182
4182
  getTokenPayload: /* @__PURE__ */ __name(() => getTokenPayload, "getTokenPayload"),
4183
4183
  getVercelCliToken: /* @__PURE__ */ __name(() => getVercelCliToken, "getVercelCliToken"),
4184
4184
  getVercelDataDir: /* @__PURE__ */ __name(() => getVercelDataDir, "getVercelDataDir"),
4185
- getVercelOidcToken: /* @__PURE__ */ __name(() => getVercelOidcToken4, "getVercelOidcToken"),
4185
+ getVercelOidcToken: /* @__PURE__ */ __name(() => getVercelOidcToken5, "getVercelOidcToken"),
4186
4186
  isExpired: /* @__PURE__ */ __name(() => isExpired, "isExpired"),
4187
4187
  loadToken: /* @__PURE__ */ __name(() => loadToken, "loadToken"),
4188
4188
  saveToken: /* @__PURE__ */ __name(() => saveToken, "saveToken")
@@ -4217,7 +4217,7 @@ var require_token_util = __commonJS({
4217
4217
  return JSON.parse(token).token;
4218
4218
  }
4219
4219
  __name(getVercelCliToken, "getVercelCliToken");
4220
- async function getVercelOidcToken4(authToken, projectId, teamId) {
4220
+ async function getVercelOidcToken5(authToken, projectId, teamId) {
4221
4221
  try {
4222
4222
  const url2 = `https://api.vercel.com/v1/projects/${projectId}/token?source=vercel-oidc-refresh${teamId ? `&teamId=${teamId}` : ""}`;
4223
4223
  const res = await fetch(url2, {
@@ -4237,7 +4237,7 @@ var require_token_util = __commonJS({
4237
4237
  throw new import_token_error.VercelOidcTokenError(`Failed to refresh OIDC token`, e);
4238
4238
  }
4239
4239
  }
4240
- __name(getVercelOidcToken4, "getVercelOidcToken");
4240
+ __name(getVercelOidcToken5, "getVercelOidcToken");
4241
4241
  function assertVercelOidcTokenResponse(res) {
4242
4242
  if (!res || typeof res !== "object") {
4243
4243
  throw new TypeError("Expected an object");
@@ -4417,13 +4417,13 @@ var require_get_vercel_oidc_token = __commonJS({
4417
4417
  }), mod), "__toCommonJS");
4418
4418
  var get_vercel_oidc_token_exports = {};
4419
4419
  __export2(get_vercel_oidc_token_exports, {
4420
- getVercelOidcToken: /* @__PURE__ */ __name(() => getVercelOidcToken4, "getVercelOidcToken"),
4420
+ getVercelOidcToken: /* @__PURE__ */ __name(() => getVercelOidcToken5, "getVercelOidcToken"),
4421
4421
  getVercelOidcTokenSync: /* @__PURE__ */ __name(() => getVercelOidcTokenSync2, "getVercelOidcTokenSync")
4422
4422
  });
4423
4423
  module2.exports = __toCommonJS2(get_vercel_oidc_token_exports);
4424
4424
  var import_get_context = require_get_context2();
4425
4425
  var import_token_error = require_token_error();
4426
- async function getVercelOidcToken4() {
4426
+ async function getVercelOidcToken5() {
4427
4427
  let token = "";
4428
4428
  let err;
4429
4429
  try {
@@ -4451,7 +4451,7 @@ ${error45.message}`;
4451
4451
  }
4452
4452
  return token;
4453
4453
  }
4454
- __name(getVercelOidcToken4, "getVercelOidcToken");
4454
+ __name(getVercelOidcToken5, "getVercelOidcToken");
4455
4455
  function getVercelOidcTokenSync2() {
4456
4456
  const token = (0, import_get_context.getContext)().headers?.["x-vercel-oidc-token"] ?? process.env.VERCEL_OIDC_TOKEN;
4457
4457
  if (!token) {
@@ -12180,7 +12180,7 @@ var require_client = __commonJS({
12180
12180
  return client[kPipelining] ?? client[kHTTPContext]?.defaultPipelining ?? 1;
12181
12181
  }
12182
12182
  __name(getPipelining, "getPipelining");
12183
- var Client2 = class extends DispatcherBase {
12183
+ var Client = class extends DispatcherBase {
12184
12184
  static {
12185
12185
  __name(this, "Client");
12186
12186
  }
@@ -12612,7 +12612,7 @@ var require_client = __commonJS({
12612
12612
  }
12613
12613
  }
12614
12614
  __name(_resume, "_resume");
12615
- module2.exports = Client2;
12615
+ module2.exports = Client;
12616
12616
  }
12617
12617
  });
12618
12618
  // ../../node_modules/.pnpm/undici@6.22.0/node_modules/undici/lib/dispatcher/fixed-queue.js
@@ -12894,7 +12894,7 @@ var require_pool = __commonJS({
12894
12894
  "../../node_modules/.pnpm/undici@6.22.0/node_modules/undici/lib/dispatcher/pool.js"(exports2, module2) {
12895
12895
  "use strict";
12896
12896
  var { PoolBase, kClients, kNeedDrain, kAddClient, kGetDispatcher } = require_pool_base();
12897
- var Client2 = require_client();
12897
+ var Client = require_client();
12898
12898
  var { InvalidArgumentError } = require_errors();
12899
12899
  var util = require_util();
12900
12900
  var { kUrl, kInterceptors } = require_symbols();
@@ -12903,7 +12903,7 @@ var require_pool = __commonJS({
12903
12903
  var kConnections = Symbol("connections");
12904
12904
  var kFactory = Symbol("factory");
12905
12905
  function defaultFactory(origin, opts) {
12906
- return new Client2(origin, opts);
12906
+ return new Client(origin, opts);
12907
12907
  }
12908
12908
  __name(defaultFactory, "defaultFactory");
12909
12909
  var Pool = class extends PoolBase {
@@ -13121,7 +13121,7 @@ var require_agent = __commonJS({
13121
13121
  var { kClients, kRunning, kClose, kDestroy, kDispatch, kInterceptors } = require_symbols();
13122
13122
  var DispatcherBase = require_dispatcher_base();
13123
13123
  var Pool = require_pool();
13124
- var Client2 = require_client();
13124
+ var Client = require_client();
13125
13125
  var util = require_util();
13126
13126
  var createRedirectInterceptor = require_redirect_interceptor();
13127
13127
  var kOnConnect = Symbol("onConnect");
@@ -13132,7 +13132,7 @@ var require_agent = __commonJS({
13132
13132
  var kFactory = Symbol("factory");
13133
13133
  var kOptions = Symbol("options");
13134
13134
  function defaultFactory(origin, opts) {
13135
- return opts && opts.connections === 1 ? new Client2(origin, opts) : new Pool(origin, opts);
13135
+ return opts && opts.connections === 1 ? new Client(origin, opts) : new Pool(origin, opts);
13136
13136
  }
13137
13137
  __name(defaultFactory, "defaultFactory");
13138
13138
  var Agent2 = class extends DispatcherBase {
@@ -13248,7 +13248,7 @@ var require_proxy_agent = __commonJS({
13248
13248
  var DispatcherBase = require_dispatcher_base();
13249
13249
  var { InvalidArgumentError, RequestAbortedError, SecureProxyConnectionError } = require_errors();
13250
13250
  var buildConnector = require_connect();
13251
- var Client2 = require_client();
13251
+ var Client = require_client();
13252
13252
  var kAgent = Symbol("proxy agent");
13253
13253
  var kClient = Symbol("proxy client");
13254
13254
  var kProxyHeaders = Symbol("proxy headers");
@@ -13268,7 +13268,7 @@ var require_proxy_agent = __commonJS({
13268
13268
  }, "noop");
13269
13269
  function defaultAgentFactory(origin, opts) {
13270
13270
  if (opts.connections === 1) {
13271
- return new Client2(origin, opts);
13271
+ return new Client(origin, opts);
13272
13272
  }
13273
13273
  return new Pool(origin, opts);
13274
13274
  }
@@ -13290,7 +13290,7 @@ var require_proxy_agent = __commonJS({
13290
13290
  });
13291
13291
  }
13292
13292
  else {
13293
- this.#client = new Client2(proxyUrl, {
13293
+ this.#client = new Client(proxyUrl, {
13294
13294
  connect
13295
13295
  });
13296
13296
  }
@@ -15810,13 +15810,13 @@ var require_mock_client = __commonJS({
15810
15810
  "../../node_modules/.pnpm/undici@6.22.0/node_modules/undici/lib/mock/mock-client.js"(exports2, module2) {
15811
15811
  "use strict";
15812
15812
  var { promisify: promisify2 } = require("node:util");
15813
- var Client2 = require_client();
15813
+ var Client = require_client();
15814
15814
  var { buildMockDispatch } = require_mock_utils();
15815
15815
  var { kDispatches, kMockAgent, kClose, kOriginalClose, kOrigin, kOriginalDispatch, kConnected } = require_mock_symbols();
15816
15816
  var { MockInterceptor } = require_mock_interceptor();
15817
15817
  var Symbols = require_symbols();
15818
15818
  var { InvalidArgumentError } = require_errors();
15819
- var MockClient = class extends Client2 {
15819
+ var MockClient = class extends Client {
15820
15820
  static {
15821
15821
  __name(this, "MockClient");
15822
15822
  }
@@ -23618,7 +23618,7 @@ var require_eventsource = __commonJS({
23618
23618
  var require_undici = __commonJS({
23619
23619
  "../../node_modules/.pnpm/undici@6.22.0/node_modules/undici/index.js"(exports2, module2) {
23620
23620
  "use strict";
23621
- var Client2 = require_client();
23621
+ var Client = require_client();
23622
23622
  var Dispatcher = require_dispatcher();
23623
23623
  var Pool = require_pool();
23624
23624
  var BalancedPool = require_balanced_pool();
@@ -23642,7 +23642,7 @@ var require_undici = __commonJS({
23642
23642
  var createRedirectInterceptor = require_redirect_interceptor();
23643
23643
  Object.assign(Dispatcher.prototype, api);
23644
23644
  module2.exports.Dispatcher = Dispatcher;
23645
- module2.exports.Client = Client2;
23645
+ module2.exports.Client = Client;
23646
23646
  module2.exports.Pool = Pool;
23647
23647
  module2.exports.BalancedPool = BalancedPool;
23648
23648
  module2.exports.Agent = Agent2;
@@ -25191,7 +25191,7 @@ async function fetch2(...args) {
25191
25191
  return globalThis.fetch(...args);
25192
25192
  }
25193
25193
  __name(fetch2, "fetch");
25194
- registerStepFunction("step//workflow@4.1.0-beta.57//fetch", fetch2);
25194
+ registerStepFunction("step//workflow@4.1.0-beta.58//fetch", fetch2);
25195
25195
  // workflows/addition.ts
25196
25196
  async function add(num, num2) {
25197
25197
  return num + num2;
@@ -39585,6 +39585,21 @@ var StepSchema = external_exports.object({
39585
39585
  // Optional in database for backwards compatibility, defaults to 1 (legacy) when reading
39586
39586
  specVersion: external_exports.number().optional()
39587
39587
  });
39588
+ // ../world/dist/waits.js
39589
+ var WaitStatusSchema = external_exports.enum([
39590
+ "waiting",
39591
+ "completed"
39592
+ ]);
39593
+ var WaitSchema = external_exports.object({
39594
+ waitId: external_exports.string(),
39595
+ runId: external_exports.string(),
39596
+ status: WaitStatusSchema,
39597
+ resumeAt: external_exports.coerce.date().optional(),
39598
+ completedAt: external_exports.coerce.date().optional(),
39599
+ createdAt: external_exports.coerce.date(),
39600
+ updatedAt: external_exports.coerce.date(),
39601
+ specVersion: external_exports.number().optional()
39602
+ });
39588
39603
  // ../serde/dist/index.js
39589
39604
  var WORKFLOW_SERIALIZE = Symbol.for("workflow-serialize");
39590
39605
  var WORKFLOW_DESERIALIZE = Symbol.for("workflow-deserialize");
@@ -41675,9 +41690,7 @@ var StreamingMultipartParser = class {
41675
41690
  }
41676
41691
  }
41677
41692
  };
41678
- // ../../node_modules/.pnpm/@vercel+queue@0.0.0-alpha.36/node_modules/@vercel/queue/dist/index.mjs
41679
- var fs = __toESM(require("fs"), 1);
41680
- var path2 = __toESM(require("path"), 1);
41693
+ // ../../node_modules/.pnpm/@vercel+queue@0.0.0-alpha.38/node_modules/@vercel/queue/dist/index.mjs
41681
41694
  var import_oidc = __toESM(require_dist(), 1);
41682
41695
  async function streamToBuffer(stream) {
41683
41696
  let totalLength = 0;
@@ -41750,15 +41763,6 @@ var MessageCorruptedError = class extends Error {
41750
41763
  this.name = "MessageCorruptedError";
41751
41764
  }
41752
41765
  };
41753
- var QueueEmptyError = class extends Error {
41754
- static {
41755
- __name(this, "QueueEmptyError");
41756
- }
41757
- constructor(queueName, consumerGroup) {
41758
- super(`No messages available in queue "${queueName}" for consumer group "${consumerGroup}"`);
41759
- this.name = "QueueEmptyError";
41760
- }
41761
- };
41762
41766
  var UnauthorizedError = class extends Error {
41763
41767
  static {
41764
41768
  __name(this, "UnauthorizedError");
@@ -41813,21 +41817,6 @@ var MessageAlreadyProcessedError = class extends Error {
41813
41817
  this.name = "MessageAlreadyProcessedError";
41814
41818
  }
41815
41819
  };
41816
- var ConcurrencyLimitError = class extends Error {
41817
- static {
41818
- __name(this, "ConcurrencyLimitError");
41819
- }
41820
- /** Current number of in-flight messages for this consumer group. */
41821
- currentInflight;
41822
- /** Maximum allowed concurrent messages (as configured). */
41823
- maxConcurrency;
41824
- constructor(message = "Concurrency limit exceeded", currentInflight, maxConcurrency) {
41825
- super(message);
41826
- this.name = "ConcurrencyLimitError";
41827
- this.currentInflight = currentInflight;
41828
- this.maxConcurrency = maxConcurrency;
41829
- }
41830
- };
41831
41820
  var DuplicateMessageError = class extends Error {
41832
41821
  static {
41833
41822
  __name(this, "DuplicateMessageError");
@@ -41860,185 +41849,10 @@ var ConsumerRegistryNotConfiguredError = class extends Error {
41860
41849
  }
41861
41850
  };
41862
41851
  var ROUTE_MAPPINGS_KEY = Symbol.for("@vercel/queue.devRouteMappings");
41863
- function filePathToUrlPath(filePath) {
41864
- let urlPath = filePath.replace(/^app\//, "/").replace(/^pages\//, "/").replace(/\/route\.(ts|js|tsx|jsx)$/, "").replace(/\.(ts|js|tsx|jsx)$/, "");
41865
- if (!urlPath.startsWith("/")) {
41866
- urlPath = "/" + urlPath;
41867
- }
41868
- return urlPath;
41869
- }
41870
- __name(filePathToUrlPath, "filePathToUrlPath");
41871
- function getDevRouteMappings() {
41872
- const g = globalThis;
41873
- if (ROUTE_MAPPINGS_KEY in g) {
41874
- return g[ROUTE_MAPPINGS_KEY] ?? null;
41875
- }
41876
- try {
41877
- const vercelJsonPath = path2.join(process.cwd(), "vercel.json");
41878
- if (!fs.existsSync(vercelJsonPath)) {
41879
- g[ROUTE_MAPPINGS_KEY] = null;
41880
- return null;
41881
- }
41882
- const vercelJson = JSON.parse(fs.readFileSync(vercelJsonPath, "utf-8"));
41883
- if (!vercelJson.functions) {
41884
- g[ROUTE_MAPPINGS_KEY] = null;
41885
- return null;
41886
- }
41887
- const mappings = [];
41888
- for (const [filePath, config3] of Object.entries(vercelJson.functions)) {
41889
- if (!config3.experimentalTriggers)
41890
- continue;
41891
- for (const trigger of config3.experimentalTriggers) {
41892
- if (trigger.type?.startsWith("queue/") && trigger.topic && trigger.consumer) {
41893
- mappings.push({
41894
- urlPath: filePathToUrlPath(filePath),
41895
- topic: trigger.topic,
41896
- consumer: trigger.consumer
41897
- });
41898
- }
41899
- }
41900
- }
41901
- g[ROUTE_MAPPINGS_KEY] = mappings.length > 0 ? mappings : null;
41902
- return g[ROUTE_MAPPINGS_KEY];
41903
- }
41904
- catch (error45) {
41905
- console.warn("[Dev Mode] Failed to read vercel.json:", error45);
41906
- g[ROUTE_MAPPINGS_KEY] = null;
41907
- return null;
41908
- }
41909
- }
41910
- __name(getDevRouteMappings, "getDevRouteMappings");
41911
- function findMatchingRoutes(topicName) {
41912
- const mappings = getDevRouteMappings();
41913
- if (!mappings) {
41914
- return [];
41915
- }
41916
- return mappings.filter((mapping) => {
41917
- if (mapping.topic.includes("*")) {
41918
- return matchesWildcardPattern(topicName, mapping.topic);
41919
- }
41920
- return mapping.topic === topicName;
41921
- });
41922
- }
41923
- __name(findMatchingRoutes, "findMatchingRoutes");
41924
41852
  function isDevMode() {
41925
41853
  return process.env.NODE_ENV === "development";
41926
41854
  }
41927
41855
  __name(isDevMode, "isDevMode");
41928
- var DEV_VISIBILITY_POLL_INTERVAL = 50;
41929
- var DEV_VISIBILITY_MAX_WAIT = 5e3;
41930
- var DEV_VISIBILITY_BACKOFF_MULTIPLIER = 2;
41931
- async function waitForMessageVisibility(topicName, consumerGroup, messageId) {
41932
- const client = new QueueClient();
41933
- const transport = new JsonTransport();
41934
- let elapsed = 0;
41935
- let interval = DEV_VISIBILITY_POLL_INTERVAL;
41936
- while (elapsed < DEV_VISIBILITY_MAX_WAIT) {
41937
- try {
41938
- await client.receiveMessageById({
41939
- queueName: topicName,
41940
- consumerGroup,
41941
- messageId,
41942
- visibilityTimeoutSeconds: 0
41943
- }, transport);
41944
- return true;
41945
- }
41946
- catch (error45) {
41947
- if (error45 instanceof MessageNotFoundError) {
41948
- await new Promise((resolve2) => setTimeout(resolve2, interval));
41949
- elapsed += interval;
41950
- interval = Math.min(interval * DEV_VISIBILITY_BACKOFF_MULTIPLIER, DEV_VISIBILITY_MAX_WAIT - elapsed);
41951
- continue;
41952
- }
41953
- if (error45 instanceof MessageAlreadyProcessedError) {
41954
- console.log(`[Dev Mode] Message already processed: topic="${topicName}" messageId="${messageId}"`);
41955
- return false;
41956
- }
41957
- console.error(`[Dev Mode] Error polling for message visibility: topic="${topicName}" messageId="${messageId}"`, error45);
41958
- return false;
41959
- }
41960
- }
41961
- console.warn(`[Dev Mode] Message visibility timeout after ${DEV_VISIBILITY_MAX_WAIT}ms: topic="${topicName}" messageId="${messageId}"`);
41962
- return false;
41963
- }
41964
- __name(waitForMessageVisibility, "waitForMessageVisibility");
41965
- function triggerDevCallbacks(topicName, messageId, delaySeconds) {
41966
- if (delaySeconds && delaySeconds > 0) {
41967
- console.log(`[Dev Mode] Message sent with delay: topic="${topicName}" messageId="${messageId}" delay=${delaySeconds}s`);
41968
- setTimeout(() => {
41969
- triggerDevCallbacks(topicName, messageId);
41970
- }, delaySeconds * 1e3);
41971
- return;
41972
- }
41973
- console.log(`[Dev Mode] Message sent: topic="${topicName}" messageId="${messageId}"`);
41974
- const matchingRoutes = findMatchingRoutes(topicName);
41975
- if (matchingRoutes.length === 0) {
41976
- console.log(`[Dev Mode] No matching routes in vercel.json for topic "${topicName}"`);
41977
- return;
41978
- }
41979
- const consumerGroups = matchingRoutes.map((r) => r.consumer);
41980
- console.log(`[Dev Mode] Scheduling callbacks for topic="${topicName}" messageId="${messageId}" \u2192 consumers: [${consumerGroups.join(", ")}]`);
41981
- (async () => {
41982
- const firstRoute = matchingRoutes[0];
41983
- const isVisible = await waitForMessageVisibility(topicName, firstRoute.consumer, messageId);
41984
- if (!isVisible) {
41985
- console.warn(`[Dev Mode] Skipping callbacks - message not visible: topic="${topicName}" messageId="${messageId}"`);
41986
- return;
41987
- }
41988
- const port = process.env.PORT || 3e3;
41989
- const baseUrl = `http://localhost:${port}`;
41990
- for (const route of matchingRoutes) {
41991
- const url2 = `${baseUrl}${route.urlPath}`;
41992
- console.log(`[Dev Mode] Invoking handler: topic="${topicName}" consumer="${route.consumer}" messageId="${messageId}" url="${url2}"`);
41993
- const cloudEvent = {
41994
- type: "com.vercel.queue.v1beta",
41995
- source: `/topic/${topicName}/consumer/${route.consumer}`,
41996
- id: messageId,
41997
- datacontenttype: "application/json",
41998
- data: {
41999
- messageId,
42000
- queueName: topicName,
42001
- consumerGroup: route.consumer
42002
- },
42003
- time: /* @__PURE__ */ ( /* @__PURE__ */new Date()).toISOString(),
42004
- specversion: "1.0"
42005
- };
42006
- try {
42007
- const response = await fetch(url2, {
42008
- method: "POST",
42009
- headers: {
42010
- "Content-Type": "application/cloudevents+json"
42011
- },
42012
- body: JSON.stringify(cloudEvent)
42013
- });
42014
- if (response.ok) {
42015
- try {
42016
- const responseData = await response.json();
42017
- if (responseData.status === "success") {
42018
- console.log(`[Dev Mode] \u2713 Message processed successfully: topic="${topicName}" consumer="${route.consumer}" messageId="${messageId}"`);
42019
- }
42020
- }
42021
- catch {
42022
- console.warn(`[Dev Mode] Handler returned OK but response was not JSON: topic="${topicName}" consumer="${route.consumer}"`);
42023
- }
42024
- }
42025
- else {
42026
- try {
42027
- const errorData = await response.json();
42028
- console.error(`[Dev Mode] \u2717 Handler failed: topic="${topicName}" consumer="${route.consumer}" messageId="${messageId}" error="${errorData.error || response.statusText}"`);
42029
- }
42030
- catch {
42031
- console.error(`[Dev Mode] \u2717 Handler failed: topic="${topicName}" consumer="${route.consumer}" messageId="${messageId}" status=${response.status}`);
42032
- }
42033
- }
42034
- }
42035
- catch (error45) {
42036
- console.error(`[Dev Mode] \u2717 HTTP request failed: topic="${topicName}" consumer="${route.consumer}" messageId="${messageId}" url="${url2}"`, error45);
42037
- }
42038
- }
42039
- })();
42040
- }
42041
- __name(triggerDevCallbacks, "triggerDevCallbacks");
42042
41856
  function clearDevRouteMappings() {
42043
41857
  const g = globalThis;
42044
41858
  delete g[ROUTE_MAPPINGS_KEY];
@@ -42113,6 +41927,7 @@ var QueueClient = class {
42113
41927
  providedToken;
42114
41928
  defaultDeploymentId;
42115
41929
  pinToDeployment;
41930
+ transport;
42116
41931
  constructor(options = {}) {
42117
41932
  this.baseUrl = options.baseUrl || process.env.VERCEL_QUEUE_BASE_URL || "https://vercel-queue.com";
42118
41933
  this.basePath = options.basePath || process.env.VERCEL_QUEUE_BASE_PATH || "/api/v3/topic";
@@ -42120,6 +41935,10 @@ var QueueClient = class {
42120
41935
  this.providedToken = options.token;
42121
41936
  this.defaultDeploymentId = options.deploymentId || process.env.VERCEL_DEPLOYMENT_ID;
42122
41937
  this.pinToDeployment = options.pinToDeployment ?? true;
41938
+ this.transport = options.transport || new JsonTransport();
41939
+ }
41940
+ getTransport() {
41941
+ return this.transport;
42123
41942
  }
42124
41943
  getSendDeploymentId() {
42125
41944
  if (isDevMode()) {
@@ -42177,6 +41996,8 @@ var QueueClient = class {
42177
41996
  }
42178
41997
  console.debug("[VQS Debug] Request:", JSON.stringify(logData, null, 2));
42179
41998
  }
41999
+ init.headers.set("User-Agent", `@vercel/queue/${"0.0.0-alpha.38"}`);
42000
+ init.headers.set("Vqs-Client-Ts", /* @__PURE__ */ ( /* @__PURE__ */new Date()).toISOString());
42180
42001
  const response = await fetch(url2, init);
42181
42002
  if (isDebugEnabled()) {
42182
42003
  const logData = {
@@ -42199,7 +42020,6 @@ var QueueClient = class {
42199
42020
  * @param options.idempotencyKey - Optional deduplication key (dedup window: min(retention, 24h))
42200
42021
  * @param options.retentionSeconds - Message TTL (default: 86400, min: 60, max: 86400)
42201
42022
  * @param options.delaySeconds - Delivery delay (default: 0, max: retentionSeconds)
42202
- * @param transport - Serializer for the payload
42203
42023
  * @returns Promise with the generated messageId
42204
42024
  * @throws {DuplicateMessageError} When idempotency key was already used
42205
42025
  * @throws {ConsumerDiscoveryError} When consumer discovery fails
@@ -42209,7 +42029,8 @@ var QueueClient = class {
42209
42029
  * @throws {ForbiddenError} When access is denied
42210
42030
  * @throws {InternalServerError} When server encounters an error
42211
42031
  */
42212
- async sendMessage(options, transport) {
42032
+ async sendMessage(options) {
42033
+ const transport = this.transport;
42213
42034
  const { queueName, payload, idempotencyKey, retentionSeconds, delaySeconds, headers: optionHeaders } = options;
42214
42035
  const headers = new Headers();
42215
42036
  if (this.customHeaders) {
@@ -42275,24 +42096,25 @@ var QueueClient = class {
42275
42096
  /**
42276
42097
  * Receive messages from a topic as an async generator.
42277
42098
  *
42099
+ * When the queue is empty, the generator completes without yielding any
42100
+ * messages. Callers should handle the case where no messages are yielded.
42101
+ *
42278
42102
  * @param options - Receive options
42279
42103
  * @param options.queueName - Topic name (pattern: `[A-Za-z0-9_-]+`)
42280
42104
  * @param options.consumerGroup - Consumer group name (pattern: `[A-Za-z0-9_-]+`)
42281
42105
  * @param options.visibilityTimeoutSeconds - Lock duration (default: 30, min: 0, max: 3600)
42282
42106
  * @param options.limit - Max messages to retrieve (default: 1, min: 1, max: 10)
42283
- * @param options.maxConcurrency - Max in-flight messages (default: unlimited, min: 1)
42284
- * @param transport - Deserializer for message payloads
42285
42107
  * @yields Message objects with payload, messageId, receiptHandle, etc.
42286
- * @throws {QueueEmptyError} When no messages available
42108
+ * Yields nothing if queue is empty.
42287
42109
  * @throws {InvalidLimitError} When limit is outside 1-10 range
42288
- * @throws {ConcurrencyLimitError} When maxConcurrency exceeded
42289
42110
  * @throws {BadRequestError} When parameters are invalid
42290
42111
  * @throws {UnauthorizedError} When authentication fails
42291
42112
  * @throws {ForbiddenError} When access is denied
42292
42113
  * @throws {InternalServerError} When server encounters an error
42293
42114
  */
42294
- async *receiveMessages(options, transport) {
42295
- const { queueName, consumerGroup, visibilityTimeoutSeconds, limit, maxConcurrency } = options;
42115
+ async *receiveMessages(options) {
42116
+ const transport = this.transport;
42117
+ const { queueName, consumerGroup, visibilityTimeoutSeconds, limit } = options;
42296
42118
  if (limit !== void 0 && (limit < 1 || limit > 10)) {
42297
42119
  throw new InvalidLimitError(limit);
42298
42120
  }
@@ -42307,9 +42129,6 @@ var QueueClient = class {
42307
42129
  if (limit !== void 0) {
42308
42130
  headers.set("Vqs-Max-Messages", limit.toString());
42309
42131
  }
42310
- if (maxConcurrency !== void 0) {
42311
- headers.set("Vqs-Max-Concurrency", maxConcurrency.toString());
42312
- }
42313
42132
  const effectiveDeploymentId = this.getConsumeDeploymentId();
42314
42133
  if (effectiveDeploymentId) {
42315
42134
  headers.set("Vqs-Deployment-Id", effectiveDeploymentId);
@@ -42319,19 +42138,10 @@ var QueueClient = class {
42319
42138
  headers
42320
42139
  });
42321
42140
  if (response.status === 204) {
42322
- throw new QueueEmptyError(queueName, consumerGroup);
42141
+ return;
42323
42142
  }
42324
42143
  if (!response.ok) {
42325
42144
  const errorText = await response.text();
42326
- if (response.status === 429) {
42327
- let errorData = {};
42328
- try {
42329
- errorData = JSON.parse(errorText);
42330
- }
42331
- catch {
42332
- }
42333
- throw new ConcurrencyLimitError(errorData.error || "Concurrency limit exceeded or throttled", errorData.currentInflight, errorData.maxConcurrency);
42334
- }
42335
42145
  throwCommonHttpError(response.status, response.statusText, errorText, "receive messages");
42336
42146
  }
42337
42147
  for await (const multipartMessage of parseMultipartStream(response)) {
@@ -42363,20 +42173,18 @@ var QueueClient = class {
42363
42173
  * @param options.consumerGroup - Consumer group name (pattern: `[A-Za-z0-9_-]+`)
42364
42174
  * @param options.messageId - Message ID to retrieve
42365
42175
  * @param options.visibilityTimeoutSeconds - Lock duration (default: 30, min: 0, max: 3600)
42366
- * @param options.maxConcurrency - Max in-flight messages (default: unlimited, min: 1)
42367
- * @param transport - Deserializer for the message payload
42368
42176
  * @returns Promise with the message
42369
42177
  * @throws {MessageNotFoundError} When message doesn't exist
42370
42178
  * @throws {MessageNotAvailableError} When message is in wrong state or was a duplicate
42371
42179
  * @throws {MessageAlreadyProcessedError} When message was already processed
42372
- * @throws {ConcurrencyLimitError} When maxConcurrency exceeded
42373
42180
  * @throws {BadRequestError} When parameters are invalid
42374
42181
  * @throws {UnauthorizedError} When authentication fails
42375
42182
  * @throws {ForbiddenError} When access is denied
42376
42183
  * @throws {InternalServerError} When server encounters an error
42377
42184
  */
42378
- async receiveMessageById(options, transport) {
42379
- const { queueName, consumerGroup, messageId, visibilityTimeoutSeconds, maxConcurrency } = options;
42185
+ async receiveMessageById(options) {
42186
+ const transport = this.transport;
42187
+ const { queueName, consumerGroup, messageId, visibilityTimeoutSeconds } = options;
42380
42188
  const headers = new Headers({
42381
42189
  Authorization: `Bearer ${await this.getToken()}`,
42382
42190
  Accept: "multipart/mixed",
@@ -42385,9 +42193,6 @@ var QueueClient = class {
42385
42193
  if (visibilityTimeoutSeconds !== void 0) {
42386
42194
  headers.set("Vqs-Visibility-Timeout-Seconds", visibilityTimeoutSeconds.toString());
42387
42195
  }
42388
- if (maxConcurrency !== void 0) {
42389
- headers.set("Vqs-Max-Concurrency", maxConcurrency.toString());
42390
- }
42391
42196
  const effectiveDeploymentId = this.getConsumeDeploymentId();
42392
42197
  if (effectiveDeploymentId) {
42393
42198
  headers.set("Vqs-Deployment-Id", effectiveDeploymentId);
@@ -42416,15 +42221,6 @@ var QueueClient = class {
42416
42221
  if (response.status === 410) {
42417
42222
  throw new MessageAlreadyProcessedError(messageId);
42418
42223
  }
42419
- if (response.status === 429) {
42420
- let errorData = {};
42421
- try {
42422
- errorData = JSON.parse(errorText);
42423
- }
42424
- catch {
42425
- }
42426
- throw new ConcurrencyLimitError(errorData.error || "Concurrency limit exceeded or throttled", errorData.currentInflight, errorData.maxConcurrency);
42427
- }
42428
42224
  throwCommonHttpError(response.status, response.statusText, errorText, "receive message by ID");
42429
42225
  }
42430
42226
  for await (const multipartMessage of parseMultipartStream(response)) {
@@ -42577,449 +42373,6 @@ var QueueClient = class {
42577
42373
  };
42578
42374
  }
42579
42375
  };
42580
- var ConsumerGroup = class {
42581
- static {
42582
- __name(this, "ConsumerGroup");
42583
- }
42584
- client;
42585
- topicName;
42586
- consumerGroupName;
42587
- visibilityTimeout;
42588
- refreshInterval;
42589
- transport;
42590
- /**
42591
- * Create a new ConsumerGroup instance.
42592
- *
42593
- * @param client - QueueClient instance to use for API calls
42594
- * @param topicName - Name of the topic to consume from (pattern: `[A-Za-z0-9_-]+`)
42595
- * @param consumerGroupName - Name of the consumer group (pattern: `[A-Za-z0-9_-]+`)
42596
- * @param options - Optional configuration
42597
- * @param options.transport - Payload serializer (default: JsonTransport)
42598
- * @param options.visibilityTimeoutSeconds - Message lock duration (default: 30, max: 3600)
42599
- * @param options.visibilityRefreshInterval - Lock refresh interval in seconds (default: visibilityTimeout / 3)
42600
- */
42601
- constructor(client, topicName, consumerGroupName, options = {}) {
42602
- this.client = client;
42603
- this.topicName = topicName;
42604
- this.consumerGroupName = consumerGroupName;
42605
- this.visibilityTimeout = options.visibilityTimeoutSeconds ?? 30;
42606
- this.refreshInterval = options.visibilityRefreshInterval ?? Math.floor(this.visibilityTimeout / 3);
42607
- this.transport = options.transport || new JsonTransport();
42608
- }
42609
- /**
42610
- * Starts a background loop that periodically extends the visibility timeout for a message.
42611
- */
42612
- startVisibilityExtension(receiptHandle) {
42613
- let isRunning = true;
42614
- let isResolved = false;
42615
- let resolveLifecycle;
42616
- let timeoutId = null;
42617
- const lifecyclePromise = new Promise((resolve2) => {
42618
- resolveLifecycle = resolve2;
42619
- });
42620
- const safeResolve = /* @__PURE__ */ __name(() => {
42621
- if (!isResolved) {
42622
- isResolved = true;
42623
- resolveLifecycle();
42624
- }
42625
- }, "safeResolve");
42626
- const extend2 = /* @__PURE__ */ __name(async () => {
42627
- if (!isRunning) {
42628
- safeResolve();
42629
- return;
42630
- }
42631
- try {
42632
- await this.client.changeVisibility({
42633
- queueName: this.topicName,
42634
- consumerGroup: this.consumerGroupName,
42635
- receiptHandle,
42636
- visibilityTimeoutSeconds: this.visibilityTimeout
42637
- });
42638
- if (isRunning) {
42639
- timeoutId = setTimeout(() => extend2(), this.refreshInterval * 1e3);
42640
- }
42641
- else {
42642
- safeResolve();
42643
- }
42644
- }
42645
- catch (error45) {
42646
- console.error(`Failed to extend visibility for receipt handle ${receiptHandle}:`, error45);
42647
- safeResolve();
42648
- }
42649
- }, "extend");
42650
- timeoutId = setTimeout(() => extend2(), this.refreshInterval * 1e3);
42651
- return async (waitForCompletion = false) => {
42652
- isRunning = false;
42653
- if (timeoutId) {
42654
- clearTimeout(timeoutId);
42655
- timeoutId = null;
42656
- }
42657
- if (waitForCompletion) {
42658
- await lifecyclePromise;
42659
- }
42660
- else {
42661
- safeResolve();
42662
- }
42663
- };
42664
- }
42665
- async processMessage(message, handler) {
42666
- const stopExtension = this.startVisibilityExtension(message.receiptHandle);
42667
- try {
42668
- await handler(message.payload, {
42669
- messageId: message.messageId,
42670
- deliveryCount: message.deliveryCount,
42671
- createdAt: message.createdAt,
42672
- topicName: this.topicName,
42673
- consumerGroup: this.consumerGroupName
42674
- });
42675
- await stopExtension();
42676
- await this.client.deleteMessage({
42677
- queueName: this.topicName,
42678
- consumerGroup: this.consumerGroupName,
42679
- receiptHandle: message.receiptHandle
42680
- });
42681
- }
42682
- catch (error45) {
42683
- await stopExtension();
42684
- if (this.transport.finalize && message.payload !== void 0 && message.payload !== null) {
42685
- try {
42686
- await this.transport.finalize(message.payload);
42687
- }
42688
- catch (finalizeError) {
42689
- console.warn("Failed to finalize message payload:", finalizeError);
42690
- }
42691
- }
42692
- throw error45;
42693
- }
42694
- }
42695
- async consume(handler, options) {
42696
- if (options?.messageId) {
42697
- const response = await this.client.receiveMessageById({
42698
- queueName: this.topicName,
42699
- consumerGroup: this.consumerGroupName,
42700
- messageId: options.messageId,
42701
- visibilityTimeoutSeconds: this.visibilityTimeout
42702
- }, this.transport);
42703
- await this.processMessage(response.message, handler);
42704
- }
42705
- else {
42706
- let messageFound = false;
42707
- for await (const message of this.client.receiveMessages({
42708
- queueName: this.topicName,
42709
- consumerGroup: this.consumerGroupName,
42710
- visibilityTimeoutSeconds: this.visibilityTimeout,
42711
- limit: 1
42712
- }, this.transport)) {
42713
- messageFound = true;
42714
- await this.processMessage(message, handler);
42715
- break;
42716
- }
42717
- if (!messageFound) {
42718
- throw new Error("No messages available");
42719
- }
42720
- }
42721
- }
42722
- /**
42723
- * Get the consumer group name
42724
- */
42725
- get name() {
42726
- return this.consumerGroupName;
42727
- }
42728
- /**
42729
- * Get the topic name this consumer group is subscribed to
42730
- */
42731
- get topic() {
42732
- return this.topicName;
42733
- }
42734
- };
42735
- var Topic = class {
42736
- static {
42737
- __name(this, "Topic");
42738
- }
42739
- client;
42740
- topicName;
42741
- transport;
42742
- /**
42743
- * Create a new Topic instance
42744
- * @param client QueueClient instance to use for API calls
42745
- * @param topicName Name of the topic to work with
42746
- * @param transport Optional serializer/deserializer for the payload (defaults to JSON)
42747
- */
42748
- constructor(client, topicName, transport) {
42749
- this.client = client;
42750
- this.topicName = topicName;
42751
- this.transport = transport || new JsonTransport();
42752
- }
42753
- /**
42754
- * Publish a message to the topic
42755
- * @param payload The data to publish
42756
- * @param options Optional publish options
42757
- * @returns An object containing the message ID
42758
- * @throws {BadRequestError} When request parameters are invalid
42759
- * @throws {UnauthorizedError} When authentication fails
42760
- * @throws {ForbiddenError} When access is denied (environment mismatch)
42761
- * @throws {InternalServerError} When server encounters an error
42762
- */
42763
- async publish(payload, options) {
42764
- const result = await this.client.sendMessage({
42765
- queueName: this.topicName,
42766
- payload,
42767
- idempotencyKey: options?.idempotencyKey,
42768
- retentionSeconds: options?.retentionSeconds,
42769
- delaySeconds: options?.delaySeconds,
42770
- headers: options?.headers
42771
- }, this.transport);
42772
- if (isDevMode()) {
42773
- triggerDevCallbacks(this.topicName, result.messageId);
42774
- }
42775
- return {
42776
- messageId: result.messageId
42777
- };
42778
- }
42779
- /**
42780
- * Create a consumer group for this topic
42781
- * @param consumerGroupName Name of the consumer group
42782
- * @param options Optional configuration for the consumer group
42783
- * @returns A ConsumerGroup instance
42784
- */
42785
- consumerGroup(consumerGroupName, options) {
42786
- const consumerOptions = {
42787
- ...options,
42788
- transport: options?.transport || this.transport
42789
- };
42790
- return new ConsumerGroup(this.client, this.topicName, consumerGroupName, consumerOptions);
42791
- }
42792
- /**
42793
- * Get the topic name
42794
- */
42795
- get name() {
42796
- return this.topicName;
42797
- }
42798
- /**
42799
- * Get the transport used by this topic
42800
- */
42801
- get serializer() {
42802
- return this.transport;
42803
- }
42804
- };
42805
- function validateWildcardPattern(pattern) {
42806
- const firstIndex = pattern.indexOf("*");
42807
- const lastIndex = pattern.lastIndexOf("*");
42808
- if (firstIndex !== lastIndex) {
42809
- return false;
42810
- }
42811
- if (firstIndex === -1) {
42812
- return false;
42813
- }
42814
- if (firstIndex !== pattern.length - 1) {
42815
- return false;
42816
- }
42817
- return true;
42818
- }
42819
- __name(validateWildcardPattern, "validateWildcardPattern");
42820
- function matchesWildcardPattern(topicName, pattern) {
42821
- const prefix = pattern.slice(0, -1);
42822
- return topicName.startsWith(prefix);
42823
- }
42824
- __name(matchesWildcardPattern, "matchesWildcardPattern");
42825
- function findTopicHandler(queueName, handlers) {
42826
- const exactHandler = handlers[queueName];
42827
- if (exactHandler) {
42828
- return exactHandler;
42829
- }
42830
- for (const pattern in handlers) {
42831
- if (pattern.includes("*") && matchesWildcardPattern(queueName, pattern)) {
42832
- return handlers[pattern];
42833
- }
42834
- }
42835
- return null;
42836
- }
42837
- __name(findTopicHandler, "findTopicHandler");
42838
- async function parseCallback(request) {
42839
- const contentType = request.headers.get("content-type");
42840
- if (!contentType || !contentType.includes("application/cloudevents+json")) {
42841
- throw new Error("Invalid content type: expected 'application/cloudevents+json'");
42842
- }
42843
- let cloudEvent;
42844
- try {
42845
- cloudEvent = await request.json();
42846
- }
42847
- catch (error45) {
42848
- throw new Error("Failed to parse CloudEvent from request body");
42849
- }
42850
- if (!cloudEvent.type || !cloudEvent.source || !cloudEvent.id || typeof cloudEvent.data !== "object" || cloudEvent.data == null) {
42851
- throw new Error("Invalid CloudEvent: missing required fields");
42852
- }
42853
- if (cloudEvent.type !== "com.vercel.queue.v1beta") {
42854
- throw new Error(`Invalid CloudEvent type: expected 'com.vercel.queue.v1beta', got '${cloudEvent.type}'`);
42855
- }
42856
- const missingFields = [];
42857
- if (!("queueName" in cloudEvent.data))
42858
- missingFields.push("queueName");
42859
- if (!("consumerGroup" in cloudEvent.data))
42860
- missingFields.push("consumerGroup");
42861
- if (!("messageId" in cloudEvent.data))
42862
- missingFields.push("messageId");
42863
- if (missingFields.length > 0) {
42864
- throw new Error(`Missing required CloudEvent data fields: ${missingFields.join(", ")}`);
42865
- }
42866
- const { messageId, queueName, consumerGroup } = cloudEvent.data;
42867
- return {
42868
- queueName,
42869
- consumerGroup,
42870
- messageId
42871
- };
42872
- }
42873
- __name(parseCallback, "parseCallback");
42874
- function createCallbackHandler(handlers, client, visibilityTimeoutSeconds) {
42875
- for (const topicPattern in handlers) {
42876
- if (topicPattern.includes("*")) {
42877
- if (!validateWildcardPattern(topicPattern)) {
42878
- throw new Error(`Invalid wildcard pattern "${topicPattern}": * may only appear once and must be at the end of the topic name`);
42879
- }
42880
- }
42881
- }
42882
- const routeHandler = /* @__PURE__ */ __name(async (request) => {
42883
- try {
42884
- const { queueName, consumerGroup, messageId } = await parseCallback(request);
42885
- const topicHandler = findTopicHandler(queueName, handlers);
42886
- if (!topicHandler) {
42887
- const availableTopics = Object.keys(handlers).join(", ");
42888
- return Response.json({
42889
- error: `No handler found for topic: ${queueName}`,
42890
- availableTopics
42891
- }, {
42892
- status: 404
42893
- });
42894
- }
42895
- const consumerGroupHandler = topicHandler[consumerGroup];
42896
- if (!consumerGroupHandler) {
42897
- const availableGroups = Object.keys(topicHandler).join(", ");
42898
- return Response.json({
42899
- error: `No handler found for consumer group "${consumerGroup}" in topic "${queueName}".`,
42900
- availableGroups
42901
- }, {
42902
- status: 404
42903
- });
42904
- }
42905
- const topic = new Topic(client, queueName);
42906
- const cg = topic.consumerGroup(consumerGroup, visibilityTimeoutSeconds !== void 0 ? {
42907
- visibilityTimeoutSeconds
42908
- } : void 0);
42909
- await cg.consume(consumerGroupHandler, {
42910
- messageId
42911
- });
42912
- return Response.json({
42913
- status: "success"
42914
- });
42915
- }
42916
- catch (error45) {
42917
- console.error("Queue callback error:", error45);
42918
- if (error45 instanceof Error && (error45.message.includes("Missing required CloudEvent data fields") || error45.message.includes("Invalid CloudEvent") || error45.message.includes("Invalid CloudEvent type") || error45.message.includes("Invalid content type") || error45.message.includes("Failed to parse CloudEvent"))) {
42919
- return Response.json({
42920
- error: error45.message
42921
- }, {
42922
- status: 400
42923
- });
42924
- }
42925
- return Response.json({
42926
- error: "Failed to process queue message"
42927
- }, {
42928
- status: 500
42929
- });
42930
- }
42931
- }, "routeHandler");
42932
- return routeHandler;
42933
- }
42934
- __name(createCallbackHandler, "createCallbackHandler");
42935
- function handleCallback(handlers, options) {
42936
- return createCallbackHandler(handlers, options?.client || new QueueClient(), options?.visibilityTimeoutSeconds);
42937
- }
42938
- __name(handleCallback, "handleCallback");
42939
- async function send(topicName, payload, options) {
42940
- const transport = options?.transport || new JsonTransport();
42941
- const client = options?.client || new QueueClient();
42942
- const result = await client.sendMessage({
42943
- queueName: topicName,
42944
- payload,
42945
- idempotencyKey: options?.idempotencyKey,
42946
- retentionSeconds: options?.retentionSeconds,
42947
- delaySeconds: options?.delaySeconds,
42948
- headers: options?.headers
42949
- }, transport);
42950
- if (isDevMode()) {
42951
- triggerDevCallbacks(topicName, result.messageId, options?.delaySeconds);
42952
- }
42953
- return {
42954
- messageId: result.messageId
42955
- };
42956
- }
42957
- __name(send, "send");
42958
- var Client = class {
42959
- static {
42960
- __name(this, "Client");
42961
- }
42962
- client;
42963
- /**
42964
- * Create a new Client
42965
- * @param options QueueClient configuration options
42966
- */
42967
- constructor(options = {}) {
42968
- this.client = new QueueClient(options);
42969
- }
42970
- /**
42971
- * Send a message to a topic
42972
- * @param topicName Name of the topic to send to
42973
- * @param payload The data to send
42974
- * @param options Optional publish options and transport
42975
- * @returns Promise with the message ID
42976
- * @throws {BadRequestError} When request parameters are invalid
42977
- * @throws {UnauthorizedError} When authentication fails
42978
- * @throws {ForbiddenError} When access is denied (environment mismatch)
42979
- * @throws {InternalServerError} When server encounters an error
42980
- */
42981
- async send(topicName, payload, options) {
42982
- return send(topicName, payload, {
42983
- ...options,
42984
- client: this.client
42985
- });
42986
- }
42987
- /**
42988
- * Create a callback handler for processing queue messages.
42989
- * Returns a Next.js route handler function that routes messages to appropriate handlers.
42990
- *
42991
- * @param handlers - Object with topic-specific handlers organized by consumer groups
42992
- * @param options - Optional configuration
42993
- * @param options.visibilityTimeoutSeconds - Message lock duration (default: 30, max: 3600)
42994
- * @returns A Next.js route handler function
42995
- *
42996
- * @example
42997
- * ```typescript
42998
- * // Basic usage
42999
- * export const POST = client.handleCallback({
43000
- * "user-events": {
43001
- * "welcome": (user, metadata) => console.log("Welcoming user", user),
43002
- * "analytics": (user, metadata) => console.log("Tracking user", user),
43003
- * },
43004
- * });
43005
- *
43006
- * // With custom visibility timeout
43007
- * export const POST = client.handleCallback({
43008
- * "video-processing": {
43009
- * "transcode": async (video) => await transcodeVideo(video),
43010
- * },
43011
- * }, {
43012
- * visibilityTimeoutSeconds: 300, // 5 minutes for long operations
43013
- * });
43014
- * ```
43015
- */
43016
- handleCallback(handlers, options) {
43017
- return handleCallback(handlers, {
43018
- ...options,
43019
- client: this.client
43020
- });
43021
- }
43022
- };
43023
42376
  // ../world-local/dist/queue.js
43024
42377
  var import_async_sema = __toESM(require_lib(), 1);
43025
42378
  var import_undici = __toESM(require_undici(), 1);
@@ -43027,12 +42380,12 @@ var LOCAL_QUEUE_MAX_VISIBILITY = parseInt(process.env.WORKFLOW_LOCAL_QUEUE_MAX_V
43027
42380
  var MAX_SAFE_TIMEOUT_MS = 2147483647;
43028
42381
  var DEFAULT_CONCURRENCY_LIMIT = 1e3;
43029
42382
  var WORKFLOW_LOCAL_QUEUE_CONCURRENCY = parseInt(process.env.WORKFLOW_LOCAL_QUEUE_CONCURRENCY ?? "0", 10) || DEFAULT_CONCURRENCY_LIMIT;
43030
- var httpAgent = new import_undici.Agent({
43031
- headersTimeout: 0,
43032
- connections: 1e3,
43033
- keepAliveTimeout: 3e4
43034
- });
43035
42383
  function createQueue(config3) {
42384
+ const httpAgent = new import_undici.Agent({
42385
+ headersTimeout: 0,
42386
+ connections: 1e3,
42387
+ keepAliveTimeout: 3e4
42388
+ });
43036
42389
  const transport = new JsonTransport();
43037
42390
  const generateId2 = monotonicFactory();
43038
42391
  const semaphore = new import_async_sema.Sema(WORKFLOW_LOCAL_QUEUE_CONCURRENCY);
@@ -43193,7 +42546,10 @@ function createQueue(config3) {
43193
42546
  return {
43194
42547
  queue,
43195
42548
  createQueueHandler,
43196
- getDeploymentId
42549
+ getDeploymentId,
42550
+ async close() {
42551
+ await httpAgent.close();
42552
+ }
43197
42553
  };
43198
42554
  }
43199
42555
  __name(createQueue, "createQueue");
@@ -43764,6 +43120,17 @@ async function handleLegacyEvent(basedir, runId, data, currentRun, params) {
43764
43120
  }
43765
43121
  __name(handleLegacyEvent, "handleLegacyEvent");
43766
43122
  // ../world-local/dist/storage/events-storage.js
43123
+ async function deleteAllWaitsForRun(basedir, runId) {
43124
+ const waitsDir = import_node_path5.default.join(basedir, "waits");
43125
+ const files = await listJSONFiles(waitsDir);
43126
+ for (const file2 of files) {
43127
+ if (file2.startsWith(`${runId}-`)) {
43128
+ const waitPath = import_node_path5.default.join(waitsDir, `${file2}.json`);
43129
+ await deleteJSON(waitPath);
43130
+ }
43131
+ }
43132
+ }
43133
+ __name(deleteAllWaitsForRun, "deleteAllWaitsForRun");
43767
43134
  function createEventsStorage(basedir) {
43768
43135
  return {
43769
43136
  async create(runId, data, params) {
@@ -43834,7 +43201,7 @@ function createEventsStorage(basedir) {
43834
43201
  status: 409
43835
43202
  });
43836
43203
  }
43837
- if (data.eventType === "step_created" || data.eventType === "hook_created") {
43204
+ if (data.eventType === "step_created" || data.eventType === "hook_created" || data.eventType === "wait_created") {
43838
43205
  throw new WorkflowAPIError(`Cannot create new entities on run in terminal state "${currentRun.status}"`, {
43839
43206
  status: 409
43840
43207
  });
@@ -43892,6 +43259,7 @@ function createEventsStorage(basedir) {
43892
43259
  let run;
43893
43260
  let step;
43894
43261
  let hook;
43262
+ let wait;
43895
43263
  if (data.eventType === "run_created" && "eventData" in data) {
43896
43264
  const runData = data.eventData;
43897
43265
  run = {
@@ -43960,7 +43328,10 @@ function createEventsStorage(basedir) {
43960
43328
  await writeJSON(runPath, run, {
43961
43329
  overwrite: true
43962
43330
  });
43963
- await deleteAllHooksForRun(basedir, effectiveRunId);
43331
+ await Promise.all([
43332
+ deleteAllHooksForRun(basedir, effectiveRunId),
43333
+ deleteAllWaitsForRun(basedir, effectiveRunId)
43334
+ ]);
43964
43335
  }
43965
43336
  }
43966
43337
  else if (data.eventType === "run_failed" && "eventData" in data) {
@@ -43990,7 +43361,10 @@ function createEventsStorage(basedir) {
43990
43361
  await writeJSON(runPath, run, {
43991
43362
  overwrite: true
43992
43363
  });
43993
- await deleteAllHooksForRun(basedir, effectiveRunId);
43364
+ await Promise.all([
43365
+ deleteAllHooksForRun(basedir, effectiveRunId),
43366
+ deleteAllWaitsForRun(basedir, effectiveRunId)
43367
+ ]);
43994
43368
  }
43995
43369
  }
43996
43370
  else if (data.eventType === "run_cancelled") {
@@ -44015,7 +43389,10 @@ function createEventsStorage(basedir) {
44015
43389
  await writeJSON(runPath, run, {
44016
43390
  overwrite: true
44017
43391
  });
44018
- await deleteAllHooksForRun(basedir, effectiveRunId);
43392
+ await Promise.all([
43393
+ deleteAllHooksForRun(basedir, effectiveRunId),
43394
+ deleteAllWaitsForRun(basedir, effectiveRunId)
43395
+ ]);
44019
43396
  }
44020
43397
  }
44021
43398
  else if (
@@ -44188,6 +43565,52 @@ function createEventsStorage(basedir) {
44188
43565
  const hookPath = import_node_path5.default.join(basedir, "hooks", `${data.correlationId}.json`);
44189
43566
  await deleteJSON(hookPath);
44190
43567
  }
43568
+ else if (data.eventType === "wait_created" && "eventData" in data) {
43569
+ const waitData = data.eventData;
43570
+ const waitCompositeKey = `${effectiveRunId}-${data.correlationId}`;
43571
+ const waitPath = import_node_path5.default.join(basedir, "waits", `${waitCompositeKey}.json`);
43572
+ const existingWait = await readJSON(waitPath, WaitSchema);
43573
+ if (existingWait) {
43574
+ throw new WorkflowAPIError(`Wait "${data.correlationId}" already exists`, {
43575
+ status: 409
43576
+ });
43577
+ }
43578
+ wait = {
43579
+ waitId: waitCompositeKey,
43580
+ runId: effectiveRunId,
43581
+ status: "waiting",
43582
+ resumeAt: waitData.resumeAt,
43583
+ completedAt: void 0,
43584
+ createdAt: now,
43585
+ updatedAt: now,
43586
+ specVersion: effectiveSpecVersion
43587
+ };
43588
+ await writeJSON(waitPath, wait);
43589
+ }
43590
+ else if (data.eventType === "wait_completed") {
43591
+ const waitCompositeKey = `${effectiveRunId}-${data.correlationId}`;
43592
+ const waitPath = import_node_path5.default.join(basedir, "waits", `${waitCompositeKey}.json`);
43593
+ const existingWait = await readJSON(waitPath, WaitSchema);
43594
+ if (!existingWait) {
43595
+ throw new WorkflowAPIError(`Wait "${data.correlationId}" not found`, {
43596
+ status: 404
43597
+ });
43598
+ }
43599
+ if (existingWait.status === "completed") {
43600
+ throw new WorkflowAPIError(`Wait "${data.correlationId}" already completed`, {
43601
+ status: 409
43602
+ });
43603
+ }
43604
+ wait = {
43605
+ ...existingWait,
43606
+ status: "completed",
43607
+ completedAt: now,
43608
+ updatedAt: now
43609
+ };
43610
+ await writeJSON(waitPath, wait, {
43611
+ overwrite: true
43612
+ });
43613
+ }
44191
43614
  const compositeKey = `${effectiveRunId}-${eventId}`;
44192
43615
  const eventPath = import_node_path5.default.join(basedir, "events", `${compositeKey}.json`);
44193
43616
  await writeJSON(eventPath, event);
@@ -44197,7 +43620,8 @@ function createEventsStorage(basedir) {
44197
43620
  event: filteredEvent,
44198
43621
  run,
44199
43622
  step,
44200
- hook
43623
+ hook,
43624
+ wait
44201
43625
  };
44202
43626
  },
44203
43627
  async list(params) {
@@ -44315,309 +43739,1654 @@ function createStepsStorage(basedir) {
44315
43739
  if (!fileId) {
44316
43740
  throw new Error(`Step ${stepId} not found`);
44317
43741
  }
44318
- runId = fileId.split("-")[0];
43742
+ runId = fileId.split("-")[0];
43743
+ }
43744
+ const compositeKey = `${runId}-${stepId}`;
43745
+ const stepPath = import_node_path7.default.join(basedir, "steps", `${compositeKey}.json`);
43746
+ const step = await readJSON(stepPath, StepSchema);
43747
+ if (!step) {
43748
+ throw new Error(`Step ${stepId} in run ${runId} not found`);
43749
+ }
43750
+ const resolveData = params?.resolveData ?? DEFAULT_RESOLVE_DATA_OPTION;
43751
+ return filterStepData(step, resolveData);
43752
+ }, "get"),
43753
+ list: /* @__PURE__ */ __name(async (params) => {
43754
+ const resolveData = params.resolveData ?? DEFAULT_RESOLVE_DATA_OPTION;
43755
+ const result = await paginatedFileSystemQuery({
43756
+ directory: import_node_path7.default.join(basedir, "steps"),
43757
+ schema: StepSchema,
43758
+ filePrefix: `${params.runId}-`,
43759
+ sortOrder: params.pagination?.sortOrder ?? "desc",
43760
+ limit: params.pagination?.limit,
43761
+ cursor: params.pagination?.cursor,
43762
+ getCreatedAt: getObjectCreatedAt("step"),
43763
+ getId: /* @__PURE__ */ __name((step) => step.stepId, "getId")
43764
+ });
43765
+ if (resolveData === "none") {
43766
+ return {
43767
+ ...result,
43768
+ data: result.data.map((step) => ({
43769
+ ...step,
43770
+ input: void 0,
43771
+ output: void 0
43772
+ }))
43773
+ };
43774
+ }
43775
+ return result;
43776
+ }, "list")
43777
+ };
43778
+ }
43779
+ __name(createStepsStorage, "createStepsStorage");
43780
+ // ../world-local/dist/storage/index.js
43781
+ function createStorage(basedir) {
43782
+ const storage = {
43783
+ runs: createRunsStorage(basedir),
43784
+ steps: createStepsStorage(basedir),
43785
+ events: createEventsStorage(basedir),
43786
+ hooks: createHooksStorage(basedir)
43787
+ };
43788
+ return {
43789
+ runs: instrumentObject("world.runs", storage.runs),
43790
+ steps: instrumentObject("world.steps", storage.steps),
43791
+ events: instrumentObject("world.events", storage.events),
43792
+ hooks: instrumentObject("world.hooks", storage.hooks)
43793
+ };
43794
+ }
43795
+ __name(createStorage, "createStorage");
43796
+ // ../world-local/dist/streamer.js
43797
+ var import_node_events = require("node:events");
43798
+ var import_node_path8 = __toESM(require("node:path"), 1);
43799
+ var monotonicUlid2 = monotonicFactory(() => Math.random());
43800
+ var RunStreamsSchema = external_exports.object({
43801
+ streams: external_exports.array(external_exports.string())
43802
+ });
43803
+ function serializeChunk(chunk) {
43804
+ const eofByte = Buffer.from([
43805
+ chunk.eof ? 1 : 0
43806
+ ]);
43807
+ return Buffer.concat([
43808
+ eofByte,
43809
+ chunk.chunk
43810
+ ]);
43811
+ }
43812
+ __name(serializeChunk, "serializeChunk");
43813
+ function deserializeChunk(serialized) {
43814
+ const eof = serialized[0] === 1;
43815
+ const chunk = Buffer.from(serialized.subarray(1));
43816
+ return {
43817
+ eof,
43818
+ chunk
43819
+ };
43820
+ }
43821
+ __name(deserializeChunk, "deserializeChunk");
43822
+ function createStreamer(basedir) {
43823
+ const streamEmitter = new import_node_events.EventEmitter();
43824
+ const registeredStreams = /* @__PURE__ */ new Set();
43825
+ async function registerStreamForRun(runId, streamName) {
43826
+ const cacheKey = `${runId}:${streamName}`;
43827
+ if (registeredStreams.has(cacheKey)) {
43828
+ return;
43829
+ }
43830
+ const runStreamsPath = import_node_path8.default.join(basedir, "streams", "runs", `${runId}.json`);
43831
+ const existing = await readJSON(runStreamsPath, RunStreamsSchema);
43832
+ const streams = existing?.streams ?? [];
43833
+ if (!streams.includes(streamName)) {
43834
+ streams.push(streamName);
43835
+ await writeJSON(runStreamsPath, {
43836
+ streams
43837
+ }, {
43838
+ overwrite: true
43839
+ });
43840
+ }
43841
+ registeredStreams.add(cacheKey);
43842
+ }
43843
+ __name(registerStreamForRun, "registerStreamForRun");
43844
+ function toBuffer(chunk) {
43845
+ if (typeof chunk === "string") {
43846
+ return Buffer.from(new TextEncoder().encode(chunk));
43847
+ }
43848
+ else if (chunk instanceof Buffer) {
43849
+ return chunk;
43850
+ }
43851
+ else {
43852
+ return Buffer.from(chunk);
43853
+ }
43854
+ }
43855
+ __name(toBuffer, "toBuffer");
43856
+ return {
43857
+ async writeToStream(name, _runId, chunk) {
43858
+ const chunkId = `chnk_${monotonicUlid2()}`;
43859
+ const runId = await _runId;
43860
+ await registerStreamForRun(runId, name);
43861
+ const chunkBuffer = toBuffer(chunk);
43862
+ const serialized = serializeChunk({
43863
+ chunk: chunkBuffer,
43864
+ eof: false
43865
+ });
43866
+ const chunkPath = import_node_path8.default.join(basedir, "streams", "chunks", `${name}-${chunkId}.bin`);
43867
+ await write(chunkPath, serialized);
43868
+ const chunkData = Uint8Array.from(chunkBuffer);
43869
+ streamEmitter.emit(`chunk:${name}`, {
43870
+ streamName: name,
43871
+ chunkData,
43872
+ chunkId
43873
+ });
43874
+ },
43875
+ async writeToStreamMulti(name, _runId, chunks) {
43876
+ if (chunks.length === 0)
43877
+ return;
43878
+ const chunkIds = chunks.map(() => `chnk_${monotonicUlid2()}`);
43879
+ const runId = await _runId;
43880
+ await registerStreamForRun(runId, name);
43881
+ const chunkBuffers = chunks.map((chunk) => toBuffer(chunk));
43882
+ const writePromises = chunkBuffers.map(async (chunkBuffer, i) => {
43883
+ const chunkId = chunkIds[i];
43884
+ const serialized = serializeChunk({
43885
+ chunk: chunkBuffer,
43886
+ eof: false
43887
+ });
43888
+ const chunkPath = import_node_path8.default.join(basedir, "streams", "chunks", `${name}-${chunkId}.bin`);
43889
+ await write(chunkPath, serialized);
43890
+ return {
43891
+ chunkId,
43892
+ chunkData: Uint8Array.from(chunkBuffer)
43893
+ };
43894
+ });
43895
+ for (const writePromise of writePromises) {
43896
+ const { chunkId, chunkData } = await writePromise;
43897
+ streamEmitter.emit(`chunk:${name}`, {
43898
+ streamName: name,
43899
+ chunkData,
43900
+ chunkId
43901
+ });
43902
+ }
43903
+ },
43904
+ async closeStream(name, _runId) {
43905
+ const chunkId = `chnk_${monotonicUlid2()}`;
43906
+ const runId = await _runId;
43907
+ await registerStreamForRun(runId, name);
43908
+ const chunkPath = import_node_path8.default.join(basedir, "streams", "chunks", `${name}-${chunkId}.bin`);
43909
+ await write(chunkPath, serializeChunk({
43910
+ chunk: Buffer.from([]),
43911
+ eof: true
43912
+ }));
43913
+ streamEmitter.emit(`close:${name}`, {
43914
+ streamName: name
43915
+ });
43916
+ },
43917
+ async listStreamsByRunId(runId) {
43918
+ const runStreamsPath = import_node_path8.default.join(basedir, "streams", "runs", `${runId}.json`);
43919
+ const data = await readJSON(runStreamsPath, RunStreamsSchema);
43920
+ return data?.streams ?? [];
43921
+ },
43922
+ async readFromStream(name, startIndex = 0) {
43923
+ const chunksDir = import_node_path8.default.join(basedir, "streams", "chunks");
43924
+ let removeListeners = /* @__PURE__ */ __name(() => {
43925
+ }, "removeListeners");
43926
+ return new ReadableStream({
43927
+ async start(controller) {
43928
+ const deliveredChunkIds = /* @__PURE__ */ new Set();
43929
+ const bufferedEventChunks = [];
43930
+ let isReadingFromDisk = true;
43931
+ let pendingClose = false;
43932
+ const chunkListener = /* @__PURE__ */ __name((event) => {
43933
+ deliveredChunkIds.add(event.chunkId);
43934
+ if (event.chunkData.byteLength === 0) {
43935
+ return;
43936
+ }
43937
+ if (isReadingFromDisk) {
43938
+ bufferedEventChunks.push({
43939
+ chunkId: event.chunkId,
43940
+ chunkData: Uint8Array.from(event.chunkData)
43941
+ });
43942
+ }
43943
+ else {
43944
+ controller.enqueue(Uint8Array.from(event.chunkData));
43945
+ }
43946
+ }, "chunkListener");
43947
+ const closeListener = /* @__PURE__ */ __name(() => {
43948
+ if (isReadingFromDisk) {
43949
+ pendingClose = true;
43950
+ return;
43951
+ }
43952
+ streamEmitter.off(`chunk:${name}`, chunkListener);
43953
+ streamEmitter.off(`close:${name}`, closeListener);
43954
+ try {
43955
+ controller.close();
43956
+ }
43957
+ catch {
43958
+ }
43959
+ }, "closeListener");
43960
+ removeListeners = closeListener;
43961
+ streamEmitter.on(`chunk:${name}`, chunkListener);
43962
+ streamEmitter.on(`close:${name}`, closeListener);
43963
+ const [binFiles, jsonFiles] = await Promise.all([
43964
+ listFilesByExtension(chunksDir, ".bin"),
43965
+ listFilesByExtension(chunksDir, ".json")
43966
+ ]);
43967
+ const fileExtMap = /* @__PURE__ */ new Map();
43968
+ for (const f of jsonFiles)
43969
+ fileExtMap.set(f, ".json");
43970
+ for (const f of binFiles)
43971
+ fileExtMap.set(f, ".bin");
43972
+ const chunkFiles = [
43973
+ ...fileExtMap.keys()
43974
+ ].filter((file2) => file2.startsWith(`${name}-`)).sort();
43975
+ let isComplete = false;
43976
+ for (let i = startIndex; i < chunkFiles.length; i++) {
43977
+ const file2 = chunkFiles[i];
43978
+ const chunkId = file2.substring(name.length + 1);
43979
+ if (deliveredChunkIds.has(chunkId)) {
43980
+ continue;
43981
+ }
43982
+ const ext = fileExtMap.get(file2) ?? ".bin";
43983
+ const chunk = deserializeChunk(await readBuffer(import_node_path8.default.join(chunksDir, `${file2}${ext}`)));
43984
+ if (chunk?.eof === true) {
43985
+ isComplete = true;
43986
+ break;
43987
+ }
43988
+ if (chunk.chunk.byteLength) {
43989
+ controller.enqueue(Uint8Array.from(chunk.chunk));
43990
+ }
43991
+ }
43992
+ isReadingFromDisk = false;
43993
+ bufferedEventChunks.sort((a, b) => a.chunkId.localeCompare(b.chunkId));
43994
+ for (const buffered of bufferedEventChunks) {
43995
+ controller.enqueue(Uint8Array.from(buffered.chunkData));
43996
+ }
43997
+ if (isComplete) {
43998
+ removeListeners();
43999
+ try {
44000
+ controller.close();
44001
+ }
44002
+ catch {
44003
+ }
44004
+ return;
44005
+ }
44006
+ if (pendingClose) {
44007
+ streamEmitter.off(`chunk:${name}`, chunkListener);
44008
+ streamEmitter.off(`close:${name}`, closeListener);
44009
+ try {
44010
+ controller.close();
44011
+ }
44012
+ catch {
44013
+ }
44014
+ }
44015
+ },
44016
+ cancel() {
44017
+ removeListeners();
44018
+ }
44019
+ });
44020
+ }
44021
+ };
44022
+ }
44023
+ __name(createStreamer, "createStreamer");
44024
+ // ../world-local/dist/index.js
44025
+ function createLocalWorld(args) {
44026
+ const definedArgs = args ? Object.fromEntries(Object.entries(args).filter(([, value]) => value !== void 0)) : {};
44027
+ const mergedConfig = {
44028
+ ...config2.value,
44029
+ ...definedArgs
44030
+ };
44031
+ const queue = createQueue(mergedConfig);
44032
+ return {
44033
+ ...queue,
44034
+ ...createStorage(mergedConfig.dataDir),
44035
+ ...createStreamer(mergedConfig.dataDir),
44036
+ async start() {
44037
+ await initDataDir(mergedConfig.dataDir);
44038
+ },
44039
+ async close() {
44040
+ await queue.close();
44041
+ }
44042
+ };
44043
+ }
44044
+ __name(createLocalWorld, "createLocalWorld");
44045
+ // ../../node_modules/.pnpm/@vercel+queue@0.0.0-alpha.38/node_modules/@vercel/queue/dist/web.mjs
44046
+ var fs2 = __toESM(require("fs"), 1);
44047
+ var path9 = __toESM(require("path"), 1);
44048
+ var import_oidc2 = __toESM(require_dist(), 1);
44049
+ var MessageNotFoundError2 = class extends Error {
44050
+ static {
44051
+ __name(this, "MessageNotFoundError");
44052
+ }
44053
+ constructor(messageId) {
44054
+ super(`Message ${messageId} not found`);
44055
+ this.name = "MessageNotFoundError";
44056
+ }
44057
+ };
44058
+ var MessageNotAvailableError2 = class extends Error {
44059
+ static {
44060
+ __name(this, "MessageNotAvailableError");
44061
+ }
44062
+ constructor(messageId, reason) {
44063
+ super(`Message ${messageId} not available for processing${reason ? `: ${reason}` : ""}`);
44064
+ this.name = "MessageNotAvailableError";
44065
+ }
44066
+ };
44067
+ var MessageCorruptedError2 = class extends Error {
44068
+ static {
44069
+ __name(this, "MessageCorruptedError");
44070
+ }
44071
+ constructor(messageId, reason) {
44072
+ super(`Message ${messageId} is corrupted: ${reason}`);
44073
+ this.name = "MessageCorruptedError";
44074
+ }
44075
+ };
44076
+ var UnauthorizedError2 = class extends Error {
44077
+ static {
44078
+ __name(this, "UnauthorizedError");
44079
+ }
44080
+ constructor(message = "Missing or invalid authentication token") {
44081
+ super(message);
44082
+ this.name = "UnauthorizedError";
44083
+ }
44084
+ };
44085
+ var ForbiddenError2 = class extends Error {
44086
+ static {
44087
+ __name(this, "ForbiddenError");
44088
+ }
44089
+ constructor(message = "Queue environment doesn't match token environment") {
44090
+ super(message);
44091
+ this.name = "ForbiddenError";
44092
+ }
44093
+ };
44094
+ var BadRequestError2 = class extends Error {
44095
+ static {
44096
+ __name(this, "BadRequestError");
44097
+ }
44098
+ constructor(message) {
44099
+ super(message);
44100
+ this.name = "BadRequestError";
44101
+ }
44102
+ };
44103
+ var InternalServerError2 = class extends Error {
44104
+ static {
44105
+ __name(this, "InternalServerError");
44106
+ }
44107
+ constructor(message = "Unexpected server error") {
44108
+ super(message);
44109
+ this.name = "InternalServerError";
44110
+ }
44111
+ };
44112
+ var InvalidLimitError2 = class extends Error {
44113
+ static {
44114
+ __name(this, "InvalidLimitError");
44115
+ }
44116
+ constructor(limit, min = 1, max = 10) {
44117
+ super(`Invalid limit: ${limit}. Limit must be between ${min} and ${max}.`);
44118
+ this.name = "InvalidLimitError";
44119
+ }
44120
+ };
44121
+ var MessageAlreadyProcessedError2 = class extends Error {
44122
+ static {
44123
+ __name(this, "MessageAlreadyProcessedError");
44124
+ }
44125
+ constructor(messageId) {
44126
+ super(`Message ${messageId} has already been processed`);
44127
+ this.name = "MessageAlreadyProcessedError";
44128
+ }
44129
+ };
44130
+ var DuplicateMessageError2 = class extends Error {
44131
+ static {
44132
+ __name(this, "DuplicateMessageError");
44133
+ }
44134
+ idempotencyKey;
44135
+ constructor(message, idempotencyKey) {
44136
+ super(message);
44137
+ this.name = "DuplicateMessageError";
44138
+ this.idempotencyKey = idempotencyKey;
44139
+ }
44140
+ };
44141
+ var ConsumerDiscoveryError2 = class extends Error {
44142
+ static {
44143
+ __name(this, "ConsumerDiscoveryError");
44144
+ }
44145
+ deploymentId;
44146
+ constructor(message, deploymentId) {
44147
+ super(message);
44148
+ this.name = "ConsumerDiscoveryError";
44149
+ this.deploymentId = deploymentId;
44150
+ }
44151
+ };
44152
+ var ConsumerRegistryNotConfiguredError2 = class extends Error {
44153
+ static {
44154
+ __name(this, "ConsumerRegistryNotConfiguredError");
44155
+ }
44156
+ constructor(message = "Consumer registry not configured") {
44157
+ super(message);
44158
+ this.name = "ConsumerRegistryNotConfiguredError";
44159
+ }
44160
+ };
44161
+ var ROUTE_MAPPINGS_KEY2 = Symbol.for("@vercel/queue.devRouteMappings");
44162
+ function filePathToUrlPath(filePath) {
44163
+ let urlPath = filePath.replace(/^app\//, "/").replace(/^pages\//, "/").replace(/\/route\.(ts|mts|js|mjs|tsx|jsx)$/, "").replace(/\.(ts|mts|js|mjs|tsx|jsx)$/, "");
44164
+ if (!urlPath.startsWith("/")) {
44165
+ urlPath = "/" + urlPath;
44166
+ }
44167
+ return urlPath;
44168
+ }
44169
+ __name(filePathToUrlPath, "filePathToUrlPath");
44170
+ function filePathToConsumerGroup(filePath) {
44171
+ return filePath.replace(/_/g, "__").replace(/\//g, "_S").replace(/\./g, "_D");
44172
+ }
44173
+ __name(filePathToConsumerGroup, "filePathToConsumerGroup");
44174
+ function getDevRouteMappings() {
44175
+ const g = globalThis;
44176
+ if (ROUTE_MAPPINGS_KEY2 in g) {
44177
+ return g[ROUTE_MAPPINGS_KEY2] ?? null;
44178
+ }
44179
+ try {
44180
+ const vercelJsonPath = path9.join(process.cwd(), "vercel.json");
44181
+ if (!fs2.existsSync(vercelJsonPath)) {
44182
+ g[ROUTE_MAPPINGS_KEY2] = null;
44183
+ return null;
44184
+ }
44185
+ const vercelJson = JSON.parse(fs2.readFileSync(vercelJsonPath, "utf-8"));
44186
+ if (!vercelJson.functions) {
44187
+ g[ROUTE_MAPPINGS_KEY2] = null;
44188
+ return null;
44189
+ }
44190
+ const mappings = [];
44191
+ for (const [filePath, config3] of Object.entries(vercelJson.functions)) {
44192
+ if (!config3.experimentalTriggers)
44193
+ continue;
44194
+ for (const trigger of config3.experimentalTriggers) {
44195
+ if (trigger.type?.startsWith("queue/") && trigger.topic) {
44196
+ mappings.push({
44197
+ urlPath: filePathToUrlPath(filePath),
44198
+ topic: trigger.topic,
44199
+ consumer: filePathToConsumerGroup(filePath)
44200
+ });
44201
+ }
44202
+ }
44203
+ }
44204
+ g[ROUTE_MAPPINGS_KEY2] = mappings.length > 0 ? mappings : null;
44205
+ return g[ROUTE_MAPPINGS_KEY2];
44206
+ }
44207
+ catch (error45) {
44208
+ console.warn("[Dev Mode] Failed to read vercel.json:", error45);
44209
+ g[ROUTE_MAPPINGS_KEY2] = null;
44210
+ return null;
44211
+ }
44212
+ }
44213
+ __name(getDevRouteMappings, "getDevRouteMappings");
44214
+ function findMatchingRoutes(topicName) {
44215
+ const mappings = getDevRouteMappings();
44216
+ if (!mappings) {
44217
+ return [];
44218
+ }
44219
+ return mappings.filter((mapping) => {
44220
+ if (mapping.topic.includes("*")) {
44221
+ return matchesWildcardPattern(topicName, mapping.topic);
44222
+ }
44223
+ return mapping.topic === topicName;
44224
+ });
44225
+ }
44226
+ __name(findMatchingRoutes, "findMatchingRoutes");
44227
+ function isDevMode2() {
44228
+ return process.env.NODE_ENV === "development";
44229
+ }
44230
+ __name(isDevMode2, "isDevMode");
44231
+ var DEV_VISIBILITY_POLL_INTERVAL = 50;
44232
+ var DEV_VISIBILITY_MAX_WAIT = 5e3;
44233
+ var DEV_VISIBILITY_BACKOFF_MULTIPLIER = 2;
44234
+ async function waitForMessageVisibility(topicName, consumerGroup, messageId) {
44235
+ const client = new QueueClient2();
44236
+ let elapsed = 0;
44237
+ let interval = DEV_VISIBILITY_POLL_INTERVAL;
44238
+ while (elapsed < DEV_VISIBILITY_MAX_WAIT) {
44239
+ try {
44240
+ await client.receiveMessageById({
44241
+ queueName: topicName,
44242
+ consumerGroup,
44243
+ messageId,
44244
+ visibilityTimeoutSeconds: 0
44245
+ });
44246
+ return true;
44247
+ }
44248
+ catch (error45) {
44249
+ if (error45 instanceof MessageNotFoundError2) {
44250
+ await new Promise((resolve2) => setTimeout(resolve2, interval));
44251
+ elapsed += interval;
44252
+ interval = Math.min(interval * DEV_VISIBILITY_BACKOFF_MULTIPLIER, DEV_VISIBILITY_MAX_WAIT - elapsed);
44253
+ continue;
44254
+ }
44255
+ if (error45 instanceof MessageAlreadyProcessedError2) {
44256
+ console.log(`[Dev Mode] Message already processed: topic="${topicName}" messageId="${messageId}"`);
44257
+ return false;
44258
+ }
44259
+ console.error(`[Dev Mode] Error polling for message visibility: topic="${topicName}" messageId="${messageId}"`, error45);
44260
+ return false;
44261
+ }
44262
+ }
44263
+ console.warn(`[Dev Mode] Message visibility timeout after ${DEV_VISIBILITY_MAX_WAIT}ms: topic="${topicName}" messageId="${messageId}"`);
44264
+ return false;
44265
+ }
44266
+ __name(waitForMessageVisibility, "waitForMessageVisibility");
44267
+ function triggerDevCallbacks(topicName, messageId, delaySeconds) {
44268
+ if (delaySeconds && delaySeconds > 0) {
44269
+ console.log(`[Dev Mode] Message sent with delay: topic="${topicName}" messageId="${messageId}" delay=${delaySeconds}s`);
44270
+ setTimeout(() => {
44271
+ triggerDevCallbacks(topicName, messageId);
44272
+ }, delaySeconds * 1e3);
44273
+ return;
44274
+ }
44275
+ console.log(`[Dev Mode] Message sent: topic="${topicName}" messageId="${messageId}"`);
44276
+ const matchingRoutes = findMatchingRoutes(topicName);
44277
+ if (matchingRoutes.length === 0) {
44278
+ console.log(`[Dev Mode] No matching routes in vercel.json for topic "${topicName}"`);
44279
+ return;
44280
+ }
44281
+ const consumerGroups = matchingRoutes.map((r) => r.consumer);
44282
+ console.log(`[Dev Mode] Scheduling callbacks for topic="${topicName}" messageId="${messageId}" \u2192 consumers: [${consumerGroups.join(", ")}]`);
44283
+ (async () => {
44284
+ const firstRoute = matchingRoutes[0];
44285
+ const isVisible = await waitForMessageVisibility(topicName, firstRoute.consumer, messageId);
44286
+ if (!isVisible) {
44287
+ console.warn(`[Dev Mode] Skipping callbacks - message not visible: topic="${topicName}" messageId="${messageId}"`);
44288
+ return;
44289
+ }
44290
+ const port = process.env.PORT || 3e3;
44291
+ const baseUrl = `http://localhost:${port}`;
44292
+ for (const route of matchingRoutes) {
44293
+ const url2 = `${baseUrl}${route.urlPath}`;
44294
+ console.log(`[Dev Mode] Invoking handler: topic="${topicName}" consumer="${route.consumer}" messageId="${messageId}" url="${url2}"`);
44295
+ try {
44296
+ const response = await fetch(url2, {
44297
+ method: "POST",
44298
+ headers: {
44299
+ "ce-type": CLOUD_EVENT_TYPE_V2BETA,
44300
+ "ce-vqsqueuename": topicName,
44301
+ "ce-vqsconsumergroup": route.consumer,
44302
+ "ce-vqsmessageid": messageId
44303
+ }
44304
+ });
44305
+ if (response.ok) {
44306
+ try {
44307
+ const responseData = await response.json();
44308
+ if (responseData.status === "success") {
44309
+ console.log(`[Dev Mode] \u2713 Message processed successfully: topic="${topicName}" consumer="${route.consumer}" messageId="${messageId}"`);
44310
+ }
44311
+ }
44312
+ catch {
44313
+ console.warn(`[Dev Mode] Handler returned OK but response was not JSON: topic="${topicName}" consumer="${route.consumer}"`);
44314
+ }
44315
+ }
44316
+ else {
44317
+ try {
44318
+ const errorData = await response.json();
44319
+ console.error(`[Dev Mode] \u2717 Handler failed: topic="${topicName}" consumer="${route.consumer}" messageId="${messageId}" error="${errorData.error || response.statusText}"`);
44320
+ }
44321
+ catch {
44322
+ console.error(`[Dev Mode] \u2717 Handler failed: topic="${topicName}" consumer="${route.consumer}" messageId="${messageId}" status=${response.status}`);
44323
+ }
44324
+ }
44325
+ }
44326
+ catch (error45) {
44327
+ console.error(`[Dev Mode] \u2717 HTTP request failed: topic="${topicName}" consumer="${route.consumer}" messageId="${messageId}" url="${url2}"`, error45);
44328
+ }
44329
+ }
44330
+ })();
44331
+ }
44332
+ __name(triggerDevCallbacks, "triggerDevCallbacks");
44333
+ function clearDevRouteMappings2() {
44334
+ const g = globalThis;
44335
+ delete g[ROUTE_MAPPINGS_KEY2];
44336
+ }
44337
+ __name(clearDevRouteMappings2, "clearDevRouteMappings");
44338
+ if (process.env.NODE_ENV === "test" || process.env.VITEST) {
44339
+ globalThis.__clearDevRouteMappings = clearDevRouteMappings2;
44340
+ }
44341
+ async function streamToBuffer2(stream) {
44342
+ let totalLength = 0;
44343
+ const reader = stream.getReader();
44344
+ const chunks = [];
44345
+ try {
44346
+ while (true) {
44347
+ const { done, value } = await reader.read();
44348
+ if (done)
44349
+ break;
44350
+ chunks.push(value);
44351
+ totalLength += value.length;
44352
+ }
44353
+ }
44354
+ finally {
44355
+ reader.releaseLock();
44356
+ }
44357
+ return Buffer.concat(chunks, totalLength);
44358
+ }
44359
+ __name(streamToBuffer2, "streamToBuffer");
44360
+ var JsonTransport2 = class {
44361
+ static {
44362
+ __name(this, "JsonTransport");
44363
+ }
44364
+ contentType = "application/json";
44365
+ replacer;
44366
+ reviver;
44367
+ /**
44368
+ * Create a new JsonTransport.
44369
+ * @param options - Optional JSON serialization options
44370
+ * @param options.replacer - Custom replacer for JSON.stringify
44371
+ * @param options.reviver - Custom reviver for JSON.parse
44372
+ */
44373
+ constructor(options = {}) {
44374
+ this.replacer = options.replacer;
44375
+ this.reviver = options.reviver;
44376
+ }
44377
+ serialize(value) {
44378
+ return Buffer.from(JSON.stringify(value, this.replacer), "utf8");
44379
+ }
44380
+ async deserialize(stream) {
44381
+ const buffer = await streamToBuffer2(stream);
44382
+ return JSON.parse(buffer.toString("utf8"), this.reviver);
44383
+ }
44384
+ };
44385
+ function isDebugEnabled2() {
44386
+ return process.env.VERCEL_QUEUE_DEBUG === "1" || process.env.VERCEL_QUEUE_DEBUG === "true";
44387
+ }
44388
+ __name(isDebugEnabled2, "isDebugEnabled");
44389
+ async function consumeStream2(stream) {
44390
+ const reader = stream.getReader();
44391
+ try {
44392
+ while (true) {
44393
+ const { done } = await reader.read();
44394
+ if (done)
44395
+ break;
44396
+ }
44397
+ }
44398
+ finally {
44399
+ reader.releaseLock();
44400
+ }
44401
+ }
44402
+ __name(consumeStream2, "consumeStream");
44403
+ function throwCommonHttpError2(status, statusText, errorText, operation, badRequestDefault = "Invalid parameters") {
44404
+ if (status === 400) {
44405
+ throw new BadRequestError2(errorText || badRequestDefault);
44406
+ }
44407
+ if (status === 401) {
44408
+ throw new UnauthorizedError2(errorText || void 0);
44409
+ }
44410
+ if (status === 403) {
44411
+ throw new ForbiddenError2(errorText || void 0);
44412
+ }
44413
+ if (status >= 500) {
44414
+ throw new InternalServerError2(errorText || `Server error: ${status} ${statusText}`);
44415
+ }
44416
+ throw new Error(`Failed to ${operation}: ${status} ${statusText}`);
44417
+ }
44418
+ __name(throwCommonHttpError2, "throwCommonHttpError");
44419
+ function parseQueueHeaders2(headers) {
44420
+ const messageId = headers.get("Vqs-Message-Id");
44421
+ const deliveryCountStr = headers.get("Vqs-Delivery-Count") || "0";
44422
+ const timestamp = headers.get("Vqs-Timestamp");
44423
+ const contentType = headers.get("Content-Type") || "application/octet-stream";
44424
+ const receiptHandle = headers.get("Vqs-Receipt-Handle");
44425
+ if (!messageId || !timestamp || !receiptHandle) {
44426
+ return null;
44427
+ }
44428
+ const deliveryCount = parseInt(deliveryCountStr, 10);
44429
+ if (Number.isNaN(deliveryCount)) {
44430
+ return null;
44431
+ }
44432
+ return {
44433
+ messageId,
44434
+ deliveryCount,
44435
+ createdAt: new Date(timestamp),
44436
+ contentType,
44437
+ receiptHandle
44438
+ };
44439
+ }
44440
+ __name(parseQueueHeaders2, "parseQueueHeaders");
44441
+ var QueueClient2 = class {
44442
+ static {
44443
+ __name(this, "QueueClient");
44444
+ }
44445
+ baseUrl;
44446
+ basePath;
44447
+ customHeaders;
44448
+ providedToken;
44449
+ defaultDeploymentId;
44450
+ pinToDeployment;
44451
+ transport;
44452
+ constructor(options = {}) {
44453
+ this.baseUrl = options.baseUrl || process.env.VERCEL_QUEUE_BASE_URL || "https://vercel-queue.com";
44454
+ this.basePath = options.basePath || process.env.VERCEL_QUEUE_BASE_PATH || "/api/v3/topic";
44455
+ this.customHeaders = options.headers || {};
44456
+ this.providedToken = options.token;
44457
+ this.defaultDeploymentId = options.deploymentId || process.env.VERCEL_DEPLOYMENT_ID;
44458
+ this.pinToDeployment = options.pinToDeployment ?? true;
44459
+ this.transport = options.transport || new JsonTransport2();
44460
+ }
44461
+ getTransport() {
44462
+ return this.transport;
44463
+ }
44464
+ getSendDeploymentId() {
44465
+ if (isDevMode2()) {
44466
+ return void 0;
44467
+ }
44468
+ if (this.pinToDeployment) {
44469
+ return this.defaultDeploymentId;
44470
+ }
44471
+ return void 0;
44472
+ }
44473
+ getConsumeDeploymentId() {
44474
+ if (isDevMode2()) {
44475
+ return void 0;
44476
+ }
44477
+ return this.defaultDeploymentId;
44478
+ }
44479
+ async getToken() {
44480
+ if (this.providedToken) {
44481
+ return this.providedToken;
44482
+ }
44483
+ const token = await (0, import_oidc2.getVercelOidcToken)();
44484
+ if (!token) {
44485
+ throw new Error("Failed to get OIDC token from Vercel Functions. Make sure you are running in a Vercel Function environment, or provide a token explicitly.\n\nTo set up your environment:\n1. Link your project: 'vercel link'\n2. Pull environment variables: 'vercel env pull'\n3. Run with environment: 'dotenv -e .env.local -- your-command'");
44486
+ }
44487
+ return token;
44488
+ }
44489
+ buildUrl(queueName, ...pathSegments) {
44490
+ const encodedQueue = encodeURIComponent(queueName);
44491
+ const segments = pathSegments.map((s) => encodeURIComponent(s));
44492
+ const path22 = segments.length > 0 ? "/" + segments.join("/") : "";
44493
+ return `${this.baseUrl}${this.basePath}/${encodedQueue}${path22}`;
44494
+ }
44495
+ async fetch(url2, init) {
44496
+ const method = init.method || "GET";
44497
+ if (isDebugEnabled2()) {
44498
+ const logData = {
44499
+ method,
44500
+ url: url2,
44501
+ headers: init.headers
44502
+ };
44503
+ const body = init.body;
44504
+ if (body !== void 0 && body !== null) {
44505
+ if (body instanceof ArrayBuffer) {
44506
+ logData.bodySize = body.byteLength;
44507
+ }
44508
+ else if (body instanceof Uint8Array) {
44509
+ logData.bodySize = body.byteLength;
44510
+ }
44511
+ else if (typeof body === "string") {
44512
+ logData.bodySize = body.length;
44513
+ }
44514
+ else {
44515
+ logData.bodyType = typeof body;
44516
+ }
44517
+ }
44518
+ console.debug("[VQS Debug] Request:", JSON.stringify(logData, null, 2));
44519
+ }
44520
+ init.headers.set("User-Agent", `@vercel/queue/${"0.0.0-alpha.38"}`);
44521
+ init.headers.set("Vqs-Client-Ts", /* @__PURE__ */ ( /* @__PURE__ */new Date()).toISOString());
44522
+ const response = await fetch(url2, init);
44523
+ if (isDebugEnabled2()) {
44524
+ const logData = {
44525
+ method,
44526
+ url: url2,
44527
+ status: response.status,
44528
+ statusText: response.statusText,
44529
+ headers: response.headers
44530
+ };
44531
+ console.debug("[VQS Debug] Response:", JSON.stringify(logData, null, 2));
44532
+ }
44533
+ return response;
44534
+ }
44535
+ /**
44536
+ * Send a message to a topic.
44537
+ *
44538
+ * @param options - Message options including queue name, payload, and optional settings
44539
+ * @param options.queueName - Topic name (pattern: `[A-Za-z0-9_-]+`)
44540
+ * @param options.payload - Message payload
44541
+ * @param options.idempotencyKey - Optional deduplication key (dedup window: min(retention, 24h))
44542
+ * @param options.retentionSeconds - Message TTL (default: 86400, min: 60, max: 86400)
44543
+ * @param options.delaySeconds - Delivery delay (default: 0, max: retentionSeconds)
44544
+ * @returns Promise with the generated messageId
44545
+ * @throws {DuplicateMessageError} When idempotency key was already used
44546
+ * @throws {ConsumerDiscoveryError} When consumer discovery fails
44547
+ * @throws {ConsumerRegistryNotConfiguredError} When registry not configured
44548
+ * @throws {BadRequestError} When parameters are invalid
44549
+ * @throws {UnauthorizedError} When authentication fails
44550
+ * @throws {ForbiddenError} When access is denied
44551
+ * @throws {InternalServerError} When server encounters an error
44552
+ */
44553
+ async sendMessage(options) {
44554
+ const transport = this.transport;
44555
+ const { queueName, payload, idempotencyKey, retentionSeconds, delaySeconds, headers: optionHeaders } = options;
44556
+ const headers = new Headers();
44557
+ if (this.customHeaders) {
44558
+ for (const [name, value] of Object.entries(this.customHeaders)) {
44559
+ headers.append(name, value);
44560
+ }
44561
+ }
44562
+ if (optionHeaders) {
44563
+ const protectedHeaderNames = /* @__PURE__ */ new Set([
44564
+ "authorization",
44565
+ "content-type"
44566
+ ]);
44567
+ const isProtectedHeader = /* @__PURE__ */ __name((name) => {
44568
+ const lower = name.toLowerCase();
44569
+ if (protectedHeaderNames.has(lower))
44570
+ return true;
44571
+ return lower.startsWith("vqs-");
44572
+ }, "isProtectedHeader");
44573
+ for (const [name, value] of Object.entries(optionHeaders)) {
44574
+ if (!isProtectedHeader(name) && value !== void 0) {
44575
+ headers.append(name, value);
44576
+ }
44577
+ }
44578
+ }
44579
+ headers.set("Authorization", `Bearer ${await this.getToken()}`);
44580
+ headers.set("Content-Type", transport.contentType);
44581
+ const deploymentId = this.getSendDeploymentId();
44582
+ if (deploymentId) {
44583
+ headers.set("Vqs-Deployment-Id", deploymentId);
44584
+ }
44585
+ if (idempotencyKey) {
44586
+ headers.set("Vqs-Idempotency-Key", idempotencyKey);
44587
+ }
44588
+ if (retentionSeconds !== void 0) {
44589
+ headers.set("Vqs-Retention-Seconds", retentionSeconds.toString());
44590
+ }
44591
+ if (delaySeconds !== void 0) {
44592
+ headers.set("Vqs-Delay-Seconds", delaySeconds.toString());
44593
+ }
44594
+ const serialized = transport.serialize(payload);
44595
+ const body = Buffer.isBuffer(serialized) ? new Uint8Array(serialized) : serialized;
44596
+ const response = await this.fetch(this.buildUrl(queueName), {
44597
+ method: "POST",
44598
+ body,
44599
+ headers
44600
+ });
44601
+ if (!response.ok) {
44602
+ const errorText = await response.text();
44603
+ if (response.status === 409) {
44604
+ throw new DuplicateMessageError2(errorText || "Duplicate idempotency key detected", idempotencyKey);
44605
+ }
44606
+ if (response.status === 502) {
44607
+ throw new ConsumerDiscoveryError2(errorText || "Consumer discovery failed", deploymentId);
44608
+ }
44609
+ if (response.status === 503) {
44610
+ throw new ConsumerRegistryNotConfiguredError2(errorText || "Consumer registry not configured");
44611
+ }
44612
+ throwCommonHttpError2(response.status, response.statusText, errorText, "send message");
44613
+ }
44614
+ const responseData = await response.json();
44615
+ return responseData;
44616
+ }
44617
+ /**
44618
+ * Receive messages from a topic as an async generator.
44619
+ *
44620
+ * When the queue is empty, the generator completes without yielding any
44621
+ * messages. Callers should handle the case where no messages are yielded.
44622
+ *
44623
+ * @param options - Receive options
44624
+ * @param options.queueName - Topic name (pattern: `[A-Za-z0-9_-]+`)
44625
+ * @param options.consumerGroup - Consumer group name (pattern: `[A-Za-z0-9_-]+`)
44626
+ * @param options.visibilityTimeoutSeconds - Lock duration (default: 30, min: 0, max: 3600)
44627
+ * @param options.limit - Max messages to retrieve (default: 1, min: 1, max: 10)
44628
+ * @yields Message objects with payload, messageId, receiptHandle, etc.
44629
+ * Yields nothing if queue is empty.
44630
+ * @throws {InvalidLimitError} When limit is outside 1-10 range
44631
+ * @throws {BadRequestError} When parameters are invalid
44632
+ * @throws {UnauthorizedError} When authentication fails
44633
+ * @throws {ForbiddenError} When access is denied
44634
+ * @throws {InternalServerError} When server encounters an error
44635
+ */
44636
+ async *receiveMessages(options) {
44637
+ const transport = this.transport;
44638
+ const { queueName, consumerGroup, visibilityTimeoutSeconds, limit } = options;
44639
+ if (limit !== void 0 && (limit < 1 || limit > 10)) {
44640
+ throw new InvalidLimitError2(limit);
44641
+ }
44642
+ const headers = new Headers({
44643
+ Authorization: `Bearer ${await this.getToken()}`,
44644
+ Accept: "multipart/mixed",
44645
+ ...this.customHeaders
44646
+ });
44647
+ if (visibilityTimeoutSeconds !== void 0) {
44648
+ headers.set("Vqs-Visibility-Timeout-Seconds", visibilityTimeoutSeconds.toString());
44649
+ }
44650
+ if (limit !== void 0) {
44651
+ headers.set("Vqs-Max-Messages", limit.toString());
44652
+ }
44653
+ const effectiveDeploymentId = this.getConsumeDeploymentId();
44654
+ if (effectiveDeploymentId) {
44655
+ headers.set("Vqs-Deployment-Id", effectiveDeploymentId);
44656
+ }
44657
+ const response = await this.fetch(this.buildUrl(queueName, "consumer", consumerGroup), {
44658
+ method: "POST",
44659
+ headers
44660
+ });
44661
+ if (response.status === 204) {
44662
+ return;
44663
+ }
44664
+ if (!response.ok) {
44665
+ const errorText = await response.text();
44666
+ throwCommonHttpError2(response.status, response.statusText, errorText, "receive messages");
44667
+ }
44668
+ for await (const multipartMessage of parseMultipartStream(response)) {
44669
+ try {
44670
+ const parsedHeaders = parseQueueHeaders2(multipartMessage.headers);
44671
+ if (!parsedHeaders) {
44672
+ console.warn("Missing required queue headers in multipart part");
44673
+ await consumeStream2(multipartMessage.payload);
44674
+ continue;
44675
+ }
44676
+ const deserializedPayload = await transport.deserialize(multipartMessage.payload);
44677
+ const message = {
44678
+ ...parsedHeaders,
44679
+ payload: deserializedPayload
44680
+ };
44681
+ yield message;
44682
+ }
44683
+ catch (error45) {
44684
+ console.warn("Failed to process multipart message:", error45);
44685
+ await consumeStream2(multipartMessage.payload);
44686
+ }
44687
+ }
44688
+ }
44689
+ /**
44690
+ * Receive a specific message by its ID.
44691
+ *
44692
+ * @param options - Receive options
44693
+ * @param options.queueName - Topic name (pattern: `[A-Za-z0-9_-]+`)
44694
+ * @param options.consumerGroup - Consumer group name (pattern: `[A-Za-z0-9_-]+`)
44695
+ * @param options.messageId - Message ID to retrieve
44696
+ * @param options.visibilityTimeoutSeconds - Lock duration (default: 30, min: 0, max: 3600)
44697
+ * @returns Promise with the message
44698
+ * @throws {MessageNotFoundError} When message doesn't exist
44699
+ * @throws {MessageNotAvailableError} When message is in wrong state or was a duplicate
44700
+ * @throws {MessageAlreadyProcessedError} When message was already processed
44701
+ * @throws {BadRequestError} When parameters are invalid
44702
+ * @throws {UnauthorizedError} When authentication fails
44703
+ * @throws {ForbiddenError} When access is denied
44704
+ * @throws {InternalServerError} When server encounters an error
44705
+ */
44706
+ async receiveMessageById(options) {
44707
+ const transport = this.transport;
44708
+ const { queueName, consumerGroup, messageId, visibilityTimeoutSeconds } = options;
44709
+ const headers = new Headers({
44710
+ Authorization: `Bearer ${await this.getToken()}`,
44711
+ Accept: "multipart/mixed",
44712
+ ...this.customHeaders
44713
+ });
44714
+ if (visibilityTimeoutSeconds !== void 0) {
44715
+ headers.set("Vqs-Visibility-Timeout-Seconds", visibilityTimeoutSeconds.toString());
44716
+ }
44717
+ const effectiveDeploymentId = this.getConsumeDeploymentId();
44718
+ if (effectiveDeploymentId) {
44719
+ headers.set("Vqs-Deployment-Id", effectiveDeploymentId);
44720
+ }
44721
+ const response = await this.fetch(this.buildUrl(queueName, "consumer", consumerGroup, "id", messageId), {
44722
+ method: "POST",
44723
+ headers
44724
+ });
44725
+ if (!response.ok) {
44726
+ const errorText = await response.text();
44727
+ if (response.status === 404) {
44728
+ throw new MessageNotFoundError2(messageId);
44729
+ }
44730
+ if (response.status === 409) {
44731
+ let errorData = {};
44732
+ try {
44733
+ errorData = JSON.parse(errorText);
44734
+ }
44735
+ catch {
44736
+ }
44737
+ if (errorData.originalMessageId) {
44738
+ throw new MessageNotAvailableError2(messageId, `This message was a duplicate - use originalMessageId: ${errorData.originalMessageId}`);
44739
+ }
44740
+ throw new MessageNotAvailableError2(messageId);
44741
+ }
44742
+ if (response.status === 410) {
44743
+ throw new MessageAlreadyProcessedError2(messageId);
44744
+ }
44745
+ throwCommonHttpError2(response.status, response.statusText, errorText, "receive message by ID");
44746
+ }
44747
+ for await (const multipartMessage of parseMultipartStream(response)) {
44748
+ const parsedHeaders = parseQueueHeaders2(multipartMessage.headers);
44749
+ if (!parsedHeaders) {
44750
+ await consumeStream2(multipartMessage.payload);
44751
+ throw new MessageCorruptedError2(messageId, "Missing required queue headers in response");
44752
+ }
44753
+ const deserializedPayload = await transport.deserialize(multipartMessage.payload);
44754
+ const message = {
44755
+ ...parsedHeaders,
44756
+ payload: deserializedPayload
44757
+ };
44758
+ return {
44759
+ message
44760
+ };
44761
+ }
44762
+ throw new MessageNotFoundError2(messageId);
44763
+ }
44764
+ /**
44765
+ * Delete (acknowledge) a message after successful processing.
44766
+ *
44767
+ * @param options - Delete options
44768
+ * @param options.queueName - Topic name
44769
+ * @param options.consumerGroup - Consumer group name
44770
+ * @param options.receiptHandle - Receipt handle from the received message (must use same deployment ID as receive)
44771
+ * @returns Promise indicating deletion success
44772
+ * @throws {MessageNotFoundError} When receipt handle not found
44773
+ * @throws {MessageNotAvailableError} When receipt handle invalid or message already processed
44774
+ * @throws {BadRequestError} When parameters are invalid
44775
+ * @throws {UnauthorizedError} When authentication fails
44776
+ * @throws {ForbiddenError} When access is denied
44777
+ * @throws {InternalServerError} When server encounters an error
44778
+ */
44779
+ async deleteMessage(options) {
44780
+ const { queueName, consumerGroup, receiptHandle } = options;
44781
+ const headers = new Headers({
44782
+ Authorization: `Bearer ${await this.getToken()}`,
44783
+ ...this.customHeaders
44784
+ });
44785
+ const effectiveDeploymentId = this.getConsumeDeploymentId();
44786
+ if (effectiveDeploymentId) {
44787
+ headers.set("Vqs-Deployment-Id", effectiveDeploymentId);
44788
+ }
44789
+ const response = await this.fetch(this.buildUrl(queueName, "consumer", consumerGroup, "lease", receiptHandle), {
44790
+ method: "DELETE",
44791
+ headers
44792
+ });
44793
+ if (!response.ok) {
44794
+ const errorText = await response.text();
44795
+ if (response.status === 404) {
44796
+ throw new MessageNotFoundError2(receiptHandle);
44797
+ }
44798
+ if (response.status === 409) {
44799
+ throw new MessageNotAvailableError2(receiptHandle, errorText || "Invalid receipt handle, message not in correct state, or already processed");
44800
+ }
44801
+ throwCommonHttpError2(response.status, response.statusText, errorText, "delete message", "Missing or invalid receipt handle");
44802
+ }
44803
+ return {
44804
+ deleted: true
44805
+ };
44806
+ }
44807
+ /**
44808
+ * Extend or change the visibility timeout of a message.
44809
+ * Used to prevent message redelivery while still processing.
44810
+ *
44811
+ * @param options - Visibility options
44812
+ * @param options.queueName - Topic name
44813
+ * @param options.consumerGroup - Consumer group name
44814
+ * @param options.receiptHandle - Receipt handle from the received message (must use same deployment ID as receive)
44815
+ * @param options.visibilityTimeoutSeconds - New timeout (min: 0, max: 3600, cannot exceed message expiration)
44816
+ * @returns Promise indicating success
44817
+ * @throws {MessageNotFoundError} When receipt handle not found
44818
+ * @throws {MessageNotAvailableError} When receipt handle invalid or message already processed
44819
+ * @throws {BadRequestError} When parameters are invalid
44820
+ * @throws {UnauthorizedError} When authentication fails
44821
+ * @throws {ForbiddenError} When access is denied
44822
+ * @throws {InternalServerError} When server encounters an error
44823
+ */
44824
+ async changeVisibility(options) {
44825
+ const { queueName, consumerGroup, receiptHandle, visibilityTimeoutSeconds } = options;
44826
+ const headers = new Headers({
44827
+ Authorization: `Bearer ${await this.getToken()}`,
44828
+ "Content-Type": "application/json",
44829
+ ...this.customHeaders
44830
+ });
44831
+ const effectiveDeploymentId = this.getConsumeDeploymentId();
44832
+ if (effectiveDeploymentId) {
44833
+ headers.set("Vqs-Deployment-Id", effectiveDeploymentId);
44834
+ }
44835
+ const response = await this.fetch(this.buildUrl(queueName, "consumer", consumerGroup, "lease", receiptHandle), {
44836
+ method: "PATCH",
44837
+ headers,
44838
+ body: JSON.stringify({
44839
+ visibilityTimeoutSeconds
44840
+ })
44841
+ });
44842
+ if (!response.ok) {
44843
+ const errorText = await response.text();
44844
+ if (response.status === 404) {
44845
+ throw new MessageNotFoundError2(receiptHandle);
44846
+ }
44847
+ if (response.status === 409) {
44848
+ throw new MessageNotAvailableError2(receiptHandle, errorText || "Invalid receipt handle, message not in correct state, or already processed");
44849
+ }
44850
+ throwCommonHttpError2(response.status, response.statusText, errorText, "change visibility", "Missing receipt handle or invalid visibility timeout");
44851
+ }
44852
+ return {
44853
+ success: true
44854
+ };
44855
+ }
44856
+ /**
44857
+ * Alternative endpoint for changing message visibility timeout.
44858
+ * Uses the /visibility path suffix and expects visibilityTimeoutSeconds in the body.
44859
+ * Functionally equivalent to changeVisibility but follows an alternative API pattern.
44860
+ *
44861
+ * @param options - Options for changing visibility
44862
+ * @returns Promise resolving to change visibility response
44863
+ */
44864
+ async changeVisibilityAlt(options) {
44865
+ const { queueName, consumerGroup, receiptHandle, visibilityTimeoutSeconds } = options;
44866
+ const headers = new Headers({
44867
+ Authorization: `Bearer ${await this.getToken()}`,
44868
+ "Content-Type": "application/json",
44869
+ ...this.customHeaders
44870
+ });
44871
+ const effectiveDeploymentId = this.getConsumeDeploymentId();
44872
+ if (effectiveDeploymentId) {
44873
+ headers.set("Vqs-Deployment-Id", effectiveDeploymentId);
44874
+ }
44875
+ const response = await this.fetch(this.buildUrl(queueName, "consumer", consumerGroup, "lease", receiptHandle, "visibility"), {
44876
+ method: "PATCH",
44877
+ headers,
44878
+ body: JSON.stringify({
44879
+ visibilityTimeoutSeconds
44880
+ })
44881
+ });
44882
+ if (!response.ok) {
44883
+ const errorText = await response.text();
44884
+ if (response.status === 404) {
44885
+ throw new MessageNotFoundError2(receiptHandle);
44886
+ }
44887
+ if (response.status === 409) {
44888
+ throw new MessageNotAvailableError2(receiptHandle, errorText || "Invalid receipt handle, message not in correct state, or already processed");
44889
+ }
44890
+ throwCommonHttpError2(response.status, response.statusText, errorText, "change visibility (alt)", "Missing receipt handle or invalid visibility timeout");
44891
+ }
44892
+ return {
44893
+ success: true
44894
+ };
44895
+ }
44896
+ };
44897
+ var DEFAULT_VISIBILITY_TIMEOUT_SECONDS = 300;
44898
+ var MIN_VISIBILITY_TIMEOUT_SECONDS = 30;
44899
+ var MAX_RENEWAL_INTERVAL_SECONDS = 60;
44900
+ var MIN_RENEWAL_INTERVAL_SECONDS = 10;
44901
+ var RETRY_INTERVAL_MS = 3e3;
44902
+ function calculateRenewalInterval(visibilityTimeoutSeconds) {
44903
+ return Math.min(MAX_RENEWAL_INTERVAL_SECONDS, Math.max(MIN_RENEWAL_INTERVAL_SECONDS, visibilityTimeoutSeconds / 5));
44904
+ }
44905
+ __name(calculateRenewalInterval, "calculateRenewalInterval");
44906
+ var ConsumerGroup = class {
44907
+ static {
44908
+ __name(this, "ConsumerGroup");
44909
+ }
44910
+ client;
44911
+ topicName;
44912
+ consumerGroupName;
44913
+ visibilityTimeout;
44914
+ /**
44915
+ * Create a new ConsumerGroup instance.
44916
+ *
44917
+ * @param client - QueueClient instance to use for API calls (transport is configured on the client)
44918
+ * @param topicName - Name of the topic to consume from (pattern: `[A-Za-z0-9_-]+`)
44919
+ * @param consumerGroupName - Name of the consumer group (pattern: `[A-Za-z0-9_-]+`)
44920
+ * @param options - Optional configuration
44921
+ * @param options.visibilityTimeoutSeconds - Message lock duration (default: 300, max: 3600)
44922
+ */
44923
+ constructor(client, topicName, consumerGroupName, options = {}) {
44924
+ this.client = client;
44925
+ this.topicName = topicName;
44926
+ this.consumerGroupName = consumerGroupName;
44927
+ this.visibilityTimeout = Math.max(MIN_VISIBILITY_TIMEOUT_SECONDS, options.visibilityTimeoutSeconds ?? DEFAULT_VISIBILITY_TIMEOUT_SECONDS);
44928
+ }
44929
+ /**
44930
+ * Check if an error is a 4xx client error that should stop retries.
44931
+ * 4xx errors indicate the request is fundamentally invalid and retrying won't help.
44932
+ * - 409: Ticket mismatch (lost ownership to another consumer)
44933
+ * - 404: Message/receipt handle not found
44934
+ * - 400, 401, 403: Other client errors
44935
+ */
44936
+ isClientError(error45) {
44937
+ return error45 instanceof MessageNotAvailableError2 || // 409 - ticket mismatch, lost ownership
44938
+ error45 instanceof MessageNotFoundError2 || // 404 - receipt handle not found
44939
+ error45 instanceof BadRequestError2 || // 400 - invalid parameters
44940
+ error45 instanceof UnauthorizedError2 || // 401 - auth failed
44941
+ error45 instanceof ForbiddenError2;
44942
+ }
44943
+ /**
44944
+ * Starts a background loop that periodically extends the visibility timeout for a message.
44945
+ *
44946
+ * Timing strategy:
44947
+ * - Renewal interval: min(60s, max(10s, visibilityTimeout/5))
44948
+ * - Extensions request the same duration as the initial visibility timeout
44949
+ * - When `visibilityDeadline` is provided (binary mode small body), the first
44950
+ * extension delay is calculated from the time remaining until the deadline
44951
+ * using the same renewal formula, ensuring the first extension fires before
44952
+ * the server-assigned lease expires. Subsequent renewals use the standard interval.
44953
+ *
44954
+ * Retry strategy:
44955
+ * - On transient failures (5xx, network errors): retry every 3 seconds
44956
+ * - On 4xx client errors: stop retrying (the lease is lost or invalid)
44957
+ *
44958
+ * @param receiptHandle - The receipt handle to extend visibility for
44959
+ * @param options - Optional configuration
44960
+ * @param options.visibilityDeadline - Absolute deadline (from server's `ce-vqsvisibilitydeadline`)
44961
+ * when the current visibility timeout expires. Used to calculate the first extension delay.
44962
+ */
44963
+ startVisibilityExtension(receiptHandle, options) {
44964
+ let isRunning = true;
44965
+ let isResolved = false;
44966
+ let resolveLifecycle;
44967
+ let timeoutId = null;
44968
+ const renewalIntervalMs = calculateRenewalInterval(this.visibilityTimeout) * 1e3;
44969
+ let firstDelayMs = renewalIntervalMs;
44970
+ if (options?.visibilityDeadline) {
44971
+ const timeRemainingMs = options.visibilityDeadline.getTime() - Date.now();
44972
+ if (timeRemainingMs > 0) {
44973
+ const timeRemainingSeconds = timeRemainingMs / 1e3;
44974
+ firstDelayMs = calculateRenewalInterval(timeRemainingSeconds) * 1e3;
44975
+ }
44976
+ else {
44977
+ firstDelayMs = 0;
44978
+ }
44979
+ }
44980
+ const lifecyclePromise = new Promise((resolve2) => {
44981
+ resolveLifecycle = resolve2;
44982
+ });
44983
+ const safeResolve = /* @__PURE__ */ __name(() => {
44984
+ if (!isResolved) {
44985
+ isResolved = true;
44986
+ resolveLifecycle();
44987
+ }
44988
+ }, "safeResolve");
44989
+ const extend2 = /* @__PURE__ */ __name(async () => {
44990
+ if (!isRunning) {
44991
+ safeResolve();
44992
+ return;
44993
+ }
44994
+ try {
44995
+ await this.client.changeVisibility({
44996
+ queueName: this.topicName,
44997
+ consumerGroup: this.consumerGroupName,
44998
+ receiptHandle,
44999
+ visibilityTimeoutSeconds: this.visibilityTimeout
45000
+ });
45001
+ if (isRunning) {
45002
+ timeoutId = setTimeout(() => extend2(), renewalIntervalMs);
45003
+ }
45004
+ else {
45005
+ safeResolve();
45006
+ }
45007
+ }
45008
+ catch (error45) {
45009
+ if (this.isClientError(error45)) {
45010
+ console.error(`Visibility extension failed with client error for receipt handle ${receiptHandle} (stopping retries):`, error45);
45011
+ safeResolve();
45012
+ return;
45013
+ }
45014
+ console.error(`Failed to extend visibility for receipt handle ${receiptHandle} (will retry in ${RETRY_INTERVAL_MS / 1e3}s):`, error45);
45015
+ if (isRunning) {
45016
+ timeoutId = setTimeout(() => extend2(), RETRY_INTERVAL_MS);
45017
+ }
45018
+ else {
45019
+ safeResolve();
45020
+ }
44319
45021
  }
44320
- const compositeKey = `${runId}-${stepId}`;
44321
- const stepPath = import_node_path7.default.join(basedir, "steps", `${compositeKey}.json`);
44322
- const step = await readJSON(stepPath, StepSchema);
44323
- if (!step) {
44324
- throw new Error(`Step ${stepId} in run ${runId} not found`);
45022
+ }, "extend");
45023
+ timeoutId = setTimeout(() => extend2(), firstDelayMs);
45024
+ return async (waitForCompletion = false) => {
45025
+ isRunning = false;
45026
+ if (timeoutId) {
45027
+ clearTimeout(timeoutId);
45028
+ timeoutId = null;
44325
45029
  }
44326
- const resolveData = params?.resolveData ?? DEFAULT_RESOLVE_DATA_OPTION;
44327
- return filterStepData(step, resolveData);
44328
- }, "get"),
44329
- list: /* @__PURE__ */ __name(async (params) => {
44330
- const resolveData = params.resolveData ?? DEFAULT_RESOLVE_DATA_OPTION;
44331
- const result = await paginatedFileSystemQuery({
44332
- directory: import_node_path7.default.join(basedir, "steps"),
44333
- schema: StepSchema,
44334
- filePrefix: `${params.runId}-`,
44335
- sortOrder: params.pagination?.sortOrder ?? "desc",
44336
- limit: params.pagination?.limit,
44337
- cursor: params.pagination?.cursor,
44338
- getCreatedAt: getObjectCreatedAt("step"),
44339
- getId: /* @__PURE__ */ __name((step) => step.stepId, "getId")
45030
+ if (waitForCompletion) {
45031
+ await lifecyclePromise;
45032
+ }
45033
+ else {
45034
+ safeResolve();
45035
+ }
45036
+ };
45037
+ }
45038
+ async processMessage(message, handler, options) {
45039
+ const stopExtension = this.startVisibilityExtension(message.receiptHandle, options);
45040
+ try {
45041
+ await handler(message.payload, {
45042
+ messageId: message.messageId,
45043
+ deliveryCount: message.deliveryCount,
45044
+ createdAt: message.createdAt,
45045
+ topicName: this.topicName,
45046
+ consumerGroup: this.consumerGroupName
44340
45047
  });
44341
- if (resolveData === "none") {
44342
- return {
44343
- ...result,
44344
- data: result.data.map((step) => ({
44345
- ...step,
44346
- input: void 0,
44347
- output: void 0
44348
- }))
44349
- };
45048
+ await stopExtension();
45049
+ await this.client.deleteMessage({
45050
+ queueName: this.topicName,
45051
+ consumerGroup: this.consumerGroupName,
45052
+ receiptHandle: message.receiptHandle
45053
+ });
45054
+ }
45055
+ catch (error45) {
45056
+ await stopExtension();
45057
+ const transport = this.client.getTransport();
45058
+ if (transport.finalize && message.payload !== void 0 && message.payload !== null) {
45059
+ try {
45060
+ await transport.finalize(message.payload);
45061
+ }
45062
+ catch (finalizeError) {
45063
+ console.warn("Failed to finalize message payload:", finalizeError);
45064
+ }
44350
45065
  }
44351
- return result;
44352
- }, "list")
44353
- };
44354
- }
44355
- __name(createStepsStorage, "createStepsStorage");
44356
- // ../world-local/dist/storage/index.js
44357
- function createStorage(basedir) {
44358
- const storage = {
44359
- runs: createRunsStorage(basedir),
44360
- steps: createStepsStorage(basedir),
44361
- events: createEventsStorage(basedir),
44362
- hooks: createHooksStorage(basedir)
44363
- };
44364
- return {
44365
- runs: instrumentObject("world.runs", storage.runs),
44366
- steps: instrumentObject("world.steps", storage.steps),
44367
- events: instrumentObject("world.events", storage.events),
44368
- hooks: instrumentObject("world.hooks", storage.hooks)
44369
- };
45066
+ throw error45;
45067
+ }
45068
+ }
45069
+ /**
45070
+ * Process a pre-fetched message directly, without calling `receiveMessageById`.
45071
+ *
45072
+ * Used by the binary mode (v2beta) small body fast path, where the server
45073
+ * pushes the full message payload in the callback request. The message is
45074
+ * processed with the same lifecycle guarantees as `consume()`:
45075
+ * - Visibility timeout is extended periodically during processing
45076
+ * - Message is deleted on successful handler completion
45077
+ * - Payload is finalized on error if the transport supports it
45078
+ *
45079
+ * @param handler - Function to process the message payload and metadata
45080
+ * @param message - The complete message including payload and receipt handle
45081
+ * @param options - Optional configuration
45082
+ * @param options.visibilityDeadline - Absolute deadline when the server-assigned
45083
+ * visibility timeout expires (from `ce-vqsvisibilitydeadline`). Used to
45084
+ * schedule the first visibility extension before the lease expires.
45085
+ */
45086
+ async consumeMessage(handler, message, options) {
45087
+ await this.processMessage(message, handler, options);
45088
+ }
45089
+ async consume(handler, options) {
45090
+ if (options && "messageId" in options) {
45091
+ const response = await this.client.receiveMessageById({
45092
+ queueName: this.topicName,
45093
+ consumerGroup: this.consumerGroupName,
45094
+ messageId: options.messageId,
45095
+ visibilityTimeoutSeconds: this.visibilityTimeout
45096
+ });
45097
+ await this.processMessage(response.message, handler);
45098
+ }
45099
+ else {
45100
+ const limit = options && "limit" in options ? options.limit : 1;
45101
+ let messageFound = false;
45102
+ for await (const message of this.client.receiveMessages({
45103
+ queueName: this.topicName,
45104
+ consumerGroup: this.consumerGroupName,
45105
+ visibilityTimeoutSeconds: this.visibilityTimeout,
45106
+ limit
45107
+ })) {
45108
+ messageFound = true;
45109
+ await this.processMessage(message, handler);
45110
+ }
45111
+ if (!messageFound) {
45112
+ await handler(null, null);
45113
+ }
45114
+ }
45115
+ }
45116
+ /**
45117
+ * Get the consumer group name
45118
+ */
45119
+ get name() {
45120
+ return this.consumerGroupName;
45121
+ }
45122
+ /**
45123
+ * Get the topic name this consumer group is subscribed to
45124
+ */
45125
+ get topic() {
45126
+ return this.topicName;
45127
+ }
45128
+ };
45129
+ var Topic = class {
45130
+ static {
45131
+ __name(this, "Topic");
45132
+ }
45133
+ client;
45134
+ topicName;
45135
+ /**
45136
+ * Create a new Topic instance
45137
+ * @param client QueueClient instance to use for API calls (transport is configured on the client)
45138
+ * @param topicName Name of the topic to work with
45139
+ */
45140
+ constructor(client, topicName) {
45141
+ this.client = client;
45142
+ this.topicName = topicName;
45143
+ }
45144
+ /**
45145
+ * Publish a message to the topic
45146
+ * @param payload The data to publish
45147
+ * @param options Optional publish options
45148
+ * @returns An object containing the message ID
45149
+ * @throws {BadRequestError} When request parameters are invalid
45150
+ * @throws {UnauthorizedError} When authentication fails
45151
+ * @throws {ForbiddenError} When access is denied (environment mismatch)
45152
+ * @throws {InternalServerError} When server encounters an error
45153
+ */
45154
+ async publish(payload, options) {
45155
+ const result = await this.client.sendMessage({
45156
+ queueName: this.topicName,
45157
+ payload,
45158
+ idempotencyKey: options?.idempotencyKey,
45159
+ retentionSeconds: options?.retentionSeconds,
45160
+ delaySeconds: options?.delaySeconds,
45161
+ headers: options?.headers
45162
+ });
45163
+ if (isDevMode2()) {
45164
+ triggerDevCallbacks(this.topicName, result.messageId);
45165
+ }
45166
+ return {
45167
+ messageId: result.messageId
45168
+ };
45169
+ }
45170
+ /**
45171
+ * Create a consumer group for this topic
45172
+ * @param consumerGroupName Name of the consumer group
45173
+ * @param options Optional configuration for the consumer group
45174
+ * @returns A ConsumerGroup instance
45175
+ */
45176
+ consumerGroup(consumerGroupName, options) {
45177
+ return new ConsumerGroup(this.client, this.topicName, consumerGroupName, options);
45178
+ }
45179
+ /**
45180
+ * Get the topic name
45181
+ */
45182
+ get name() {
45183
+ return this.topicName;
45184
+ }
45185
+ };
45186
+ var CLOUD_EVENT_TYPE_V1BETA = "com.vercel.queue.v1beta";
45187
+ var CLOUD_EVENT_TYPE_V2BETA = "com.vercel.queue.v2beta";
45188
+ function matchesWildcardPattern(topicName, pattern) {
45189
+ const prefix = pattern.slice(0, -1);
45190
+ return topicName.startsWith(prefix);
44370
45191
  }
44371
- __name(createStorage, "createStorage");
44372
- // ../world-local/dist/streamer.js
44373
- var import_node_events = require("node:events");
44374
- var import_node_path8 = __toESM(require("node:path"), 1);
44375
- var monotonicUlid2 = monotonicFactory(() => Math.random());
44376
- var RunStreamsSchema = external_exports.object({
44377
- streams: external_exports.array(external_exports.string())
44378
- });
44379
- function serializeChunk(chunk) {
44380
- const eofByte = Buffer.from([
44381
- chunk.eof ? 1 : 0
44382
- ]);
44383
- return Buffer.concat([
44384
- eofByte,
44385
- chunk.chunk
44386
- ]);
45192
+ __name(matchesWildcardPattern, "matchesWildcardPattern");
45193
+ function isRecord(value) {
45194
+ return typeof value === "object" && value !== null;
44387
45195
  }
44388
- __name(serializeChunk, "serializeChunk");
44389
- function deserializeChunk(serialized) {
44390
- const eof = serialized[0] === 1;
44391
- const chunk = Buffer.from(serialized.subarray(1));
45196
+ __name(isRecord, "isRecord");
45197
+ function parseV1StructuredBody(body, contentType) {
45198
+ if (!contentType || !contentType.includes("application/cloudevents+json")) {
45199
+ throw new Error("Invalid content type: expected 'application/cloudevents+json'");
45200
+ }
45201
+ if (!isRecord(body) || !body.type || !body.source || !body.id || !isRecord(body.data)) {
45202
+ throw new Error("Invalid CloudEvent: missing required fields");
45203
+ }
45204
+ if (body.type !== CLOUD_EVENT_TYPE_V1BETA) {
45205
+ throw new Error(`Invalid CloudEvent type: expected '${CLOUD_EVENT_TYPE_V1BETA}', got '${String(body.type)}'`);
45206
+ }
45207
+ const { data } = body;
45208
+ const missingFields = [];
45209
+ if (!("queueName" in data))
45210
+ missingFields.push("queueName");
45211
+ if (!("consumerGroup" in data))
45212
+ missingFields.push("consumerGroup");
45213
+ if (!("messageId" in data))
45214
+ missingFields.push("messageId");
45215
+ if (missingFields.length > 0) {
45216
+ throw new Error(`Missing required CloudEvent data fields: ${missingFields.join(", ")}`);
45217
+ }
44392
45218
  return {
44393
- eof,
44394
- chunk
45219
+ queueName: String(data.queueName),
45220
+ consumerGroup: String(data.consumerGroup),
45221
+ messageId: String(data.messageId)
45222
+ };
45223
+ }
45224
+ __name(parseV1StructuredBody, "parseV1StructuredBody");
45225
+ function getHeader(headers, name) {
45226
+ if (headers instanceof Headers) {
45227
+ return headers.get(name);
45228
+ }
45229
+ const value = headers[name];
45230
+ if (Array.isArray(value))
45231
+ return value[0] ?? null;
45232
+ return value ?? null;
45233
+ }
45234
+ __name(getHeader, "getHeader");
45235
+ function parseBinaryHeaders(headers) {
45236
+ const ceType = getHeader(headers, "ce-type");
45237
+ if (ceType !== CLOUD_EVENT_TYPE_V2BETA) {
45238
+ throw new Error(`Invalid CloudEvent type: expected '${CLOUD_EVENT_TYPE_V2BETA}', got '${ceType}'`);
45239
+ }
45240
+ const queueName = getHeader(headers, "ce-vqsqueuename");
45241
+ const consumerGroup = getHeader(headers, "ce-vqsconsumergroup");
45242
+ const messageId = getHeader(headers, "ce-vqsmessageid");
45243
+ const missingFields = [];
45244
+ if (!queueName)
45245
+ missingFields.push("ce-vqsqueuename");
45246
+ if (!consumerGroup)
45247
+ missingFields.push("ce-vqsconsumergroup");
45248
+ if (!messageId)
45249
+ missingFields.push("ce-vqsmessageid");
45250
+ if (missingFields.length > 0) {
45251
+ throw new Error(`Missing required CloudEvent headers: ${missingFields.join(", ")}`);
45252
+ }
45253
+ const base = {
45254
+ queueName,
45255
+ consumerGroup,
45256
+ messageId
45257
+ };
45258
+ const receiptHandle = getHeader(headers, "ce-vqsreceipthandle");
45259
+ if (!receiptHandle) {
45260
+ return base;
45261
+ }
45262
+ const result = {
45263
+ ...base,
45264
+ receiptHandle
44395
45265
  };
45266
+ const deliveryCount = getHeader(headers, "ce-vqsdeliverycount");
45267
+ if (deliveryCount) {
45268
+ result.deliveryCount = parseInt(deliveryCount, 10);
45269
+ }
45270
+ const createdAt = getHeader(headers, "ce-vqscreatedat");
45271
+ if (createdAt) {
45272
+ result.createdAt = createdAt;
45273
+ }
45274
+ const contentType = getHeader(headers, "content-type");
45275
+ if (contentType) {
45276
+ result.contentType = contentType;
45277
+ }
45278
+ const visibilityDeadline = getHeader(headers, "ce-vqsvisibilitydeadline");
45279
+ if (visibilityDeadline) {
45280
+ result.visibilityDeadline = visibilityDeadline;
45281
+ }
45282
+ return result;
44396
45283
  }
44397
- __name(deserializeChunk, "deserializeChunk");
44398
- function createStreamer(basedir) {
44399
- const streamEmitter = new import_node_events.EventEmitter();
44400
- const registeredStreams = /* @__PURE__ */ new Set();
44401
- async function registerStreamForRun(runId, streamName) {
44402
- const cacheKey = `${runId}:${streamName}`;
44403
- if (registeredStreams.has(cacheKey)) {
44404
- return;
44405
- }
44406
- const runStreamsPath = import_node_path8.default.join(basedir, "streams", "runs", `${runId}.json`);
44407
- const existing = await readJSON(runStreamsPath, RunStreamsSchema);
44408
- const streams = existing?.streams ?? [];
44409
- if (!streams.includes(streamName)) {
44410
- streams.push(streamName);
44411
- await writeJSON(runStreamsPath, {
44412
- streams
44413
- }, {
44414
- overwrite: true
44415
- });
45284
+ __name(parseBinaryHeaders, "parseBinaryHeaders");
45285
+ function parseRawCallback(body, headers) {
45286
+ const ceType = getHeader(headers, "ce-type");
45287
+ if (ceType === CLOUD_EVENT_TYPE_V2BETA) {
45288
+ const result = parseBinaryHeaders(headers);
45289
+ if ("receiptHandle" in result) {
45290
+ result.parsedPayload = body;
44416
45291
  }
44417
- registeredStreams.add(cacheKey);
45292
+ return result;
44418
45293
  }
44419
- __name(registerStreamForRun, "registerStreamForRun");
44420
- function toBuffer(chunk) {
44421
- if (typeof chunk === "string") {
44422
- return Buffer.from(new TextEncoder().encode(chunk));
45294
+ return parseV1StructuredBody(body, getHeader(headers, "content-type"));
45295
+ }
45296
+ __name(parseRawCallback, "parseRawCallback");
45297
+ async function parseCallback(request) {
45298
+ const ceType = request.headers.get("ce-type");
45299
+ if (ceType === CLOUD_EVENT_TYPE_V2BETA) {
45300
+ const result = parseBinaryHeaders(request.headers);
45301
+ if ("receiptHandle" in result && request.body) {
45302
+ result.rawBody = request.body;
44423
45303
  }
44424
- else if (chunk instanceof Buffer) {
44425
- return chunk;
45304
+ return result;
45305
+ }
45306
+ let body;
45307
+ try {
45308
+ body = await request.json();
45309
+ }
45310
+ catch {
45311
+ throw new Error("Failed to parse CloudEvent from request body");
45312
+ }
45313
+ const headers = {};
45314
+ request.headers.forEach((value, key) => {
45315
+ headers[key] = value;
45316
+ });
45317
+ return parseRawCallback(body, headers);
45318
+ }
45319
+ __name(parseCallback, "parseCallback");
45320
+ async function handleCallback(handler, request, options) {
45321
+ const { queueName, consumerGroup, messageId } = request;
45322
+ const client = options?.client || new QueueClient2();
45323
+ const topic = new Topic(client, queueName);
45324
+ const cg = topic.consumerGroup(consumerGroup, options?.visibilityTimeoutSeconds !== void 0 ? {
45325
+ visibilityTimeoutSeconds: options.visibilityTimeoutSeconds
45326
+ } : void 0);
45327
+ if ("receiptHandle" in request) {
45328
+ const transport = client.getTransport();
45329
+ let payload;
45330
+ if (request.rawBody) {
45331
+ payload = await transport.deserialize(request.rawBody);
45332
+ }
45333
+ else if (request.parsedPayload !== void 0) {
45334
+ payload = request.parsedPayload;
44426
45335
  }
44427
45336
  else {
44428
- return Buffer.from(chunk);
45337
+ throw new Error("Binary mode callback with receipt handle is missing payload");
44429
45338
  }
45339
+ const message = {
45340
+ messageId,
45341
+ payload,
45342
+ deliveryCount: request.deliveryCount ?? 1,
45343
+ createdAt: request.createdAt ? new Date(request.createdAt) : /* @__PURE__ */ new Date(),
45344
+ contentType: request.contentType ?? transport.contentType,
45345
+ receiptHandle: request.receiptHandle
45346
+ };
45347
+ const visibilityDeadline = request.visibilityDeadline ? new Date(request.visibilityDeadline) : void 0;
45348
+ await cg.consumeMessage(handler, message, {
45349
+ visibilityDeadline
45350
+ });
44430
45351
  }
44431
- __name(toBuffer, "toBuffer");
44432
- return {
44433
- async writeToStream(name, _runId, chunk) {
44434
- const chunkId = `chnk_${monotonicUlid2()}`;
44435
- const runId = await _runId;
44436
- await registerStreamForRun(runId, name);
44437
- const chunkBuffer = toBuffer(chunk);
44438
- const serialized = serializeChunk({
44439
- chunk: chunkBuffer,
44440
- eof: false
44441
- });
44442
- const chunkPath = import_node_path8.default.join(basedir, "streams", "chunks", `${name}-${chunkId}.bin`);
44443
- await write(chunkPath, serialized);
44444
- const chunkData = Uint8Array.from(chunkBuffer);
44445
- streamEmitter.emit(`chunk:${name}`, {
44446
- streamName: name,
44447
- chunkData,
44448
- chunkId
44449
- });
44450
- },
44451
- async writeToStreamMulti(name, _runId, chunks) {
44452
- if (chunks.length === 0)
44453
- return;
44454
- const chunkIds = chunks.map(() => `chnk_${monotonicUlid2()}`);
44455
- const runId = await _runId;
44456
- await registerStreamForRun(runId, name);
44457
- const chunkBuffers = chunks.map((chunk) => toBuffer(chunk));
44458
- const writePromises = chunkBuffers.map(async (chunkBuffer, i) => {
44459
- const chunkId = chunkIds[i];
44460
- const serialized = serializeChunk({
44461
- chunk: chunkBuffer,
44462
- eof: false
44463
- });
44464
- const chunkPath = import_node_path8.default.join(basedir, "streams", "chunks", `${name}-${chunkId}.bin`);
44465
- await write(chunkPath, serialized);
44466
- return {
44467
- chunkId,
44468
- chunkData: Uint8Array.from(chunkBuffer)
44469
- };
45352
+ else {
45353
+ await cg.consume(handler, {
45354
+ messageId
45355
+ });
45356
+ }
45357
+ }
45358
+ __name(handleCallback, "handleCallback");
45359
+ function handleCallback2(handler, options) {
45360
+ return async (request) => {
45361
+ try {
45362
+ const parsed = await parseCallback(request);
45363
+ await handleCallback(handler, parsed, options);
45364
+ return Response.json({
45365
+ status: "success"
44470
45366
  });
44471
- for (const writePromise of writePromises) {
44472
- const { chunkId, chunkData } = await writePromise;
44473
- streamEmitter.emit(`chunk:${name}`, {
44474
- streamName: name,
44475
- chunkData,
44476
- chunkId
45367
+ }
45368
+ catch (error45) {
45369
+ console.error("Queue callback error:", error45);
45370
+ if (error45 instanceof Error && (error45.message.includes("Invalid content type") || error45.message.includes("Invalid CloudEvent") || error45.message.includes("Missing required CloudEvent") || error45.message.includes("Failed to parse CloudEvent") || error45.message.includes("Binary mode callback"))) {
45371
+ return Response.json({
45372
+ error: error45.message
45373
+ }, {
45374
+ status: 400
44477
45375
  });
44478
45376
  }
44479
- },
44480
- async closeStream(name, _runId) {
44481
- const chunkId = `chnk_${monotonicUlid2()}`;
44482
- const runId = await _runId;
44483
- await registerStreamForRun(runId, name);
44484
- const chunkPath = import_node_path8.default.join(basedir, "streams", "chunks", `${name}-${chunkId}.bin`);
44485
- await write(chunkPath, serializeChunk({
44486
- chunk: Buffer.from([]),
44487
- eof: true
44488
- }));
44489
- streamEmitter.emit(`close:${name}`, {
44490
- streamName: name
44491
- });
44492
- },
44493
- async listStreamsByRunId(runId) {
44494
- const runStreamsPath = import_node_path8.default.join(basedir, "streams", "runs", `${runId}.json`);
44495
- const data = await readJSON(runStreamsPath, RunStreamsSchema);
44496
- return data?.streams ?? [];
44497
- },
44498
- async readFromStream(name, startIndex = 0) {
44499
- const chunksDir = import_node_path8.default.join(basedir, "streams", "chunks");
44500
- let removeListeners = /* @__PURE__ */ __name(() => {
44501
- }, "removeListeners");
44502
- return new ReadableStream({
44503
- async start(controller) {
44504
- const deliveredChunkIds = /* @__PURE__ */ new Set();
44505
- const bufferedEventChunks = [];
44506
- let isReadingFromDisk = true;
44507
- let pendingClose = false;
44508
- const chunkListener = /* @__PURE__ */ __name((event) => {
44509
- deliveredChunkIds.add(event.chunkId);
44510
- if (event.chunkData.byteLength === 0) {
44511
- return;
44512
- }
44513
- if (isReadingFromDisk) {
44514
- bufferedEventChunks.push({
44515
- chunkId: event.chunkId,
44516
- chunkData: Uint8Array.from(event.chunkData)
44517
- });
44518
- }
44519
- else {
44520
- controller.enqueue(Uint8Array.from(event.chunkData));
44521
- }
44522
- }, "chunkListener");
44523
- const closeListener = /* @__PURE__ */ __name(() => {
44524
- if (isReadingFromDisk) {
44525
- pendingClose = true;
44526
- return;
44527
- }
44528
- streamEmitter.off(`chunk:${name}`, chunkListener);
44529
- streamEmitter.off(`close:${name}`, closeListener);
44530
- try {
44531
- controller.close();
44532
- }
44533
- catch {
44534
- }
44535
- }, "closeListener");
44536
- removeListeners = closeListener;
44537
- streamEmitter.on(`chunk:${name}`, chunkListener);
44538
- streamEmitter.on(`close:${name}`, closeListener);
44539
- const [binFiles, jsonFiles] = await Promise.all([
44540
- listFilesByExtension(chunksDir, ".bin"),
44541
- listFilesByExtension(chunksDir, ".json")
44542
- ]);
44543
- const fileExtMap = /* @__PURE__ */ new Map();
44544
- for (const f of jsonFiles)
44545
- fileExtMap.set(f, ".json");
44546
- for (const f of binFiles)
44547
- fileExtMap.set(f, ".bin");
44548
- const chunkFiles = [
44549
- ...fileExtMap.keys()
44550
- ].filter((file2) => file2.startsWith(`${name}-`)).sort();
44551
- let isComplete = false;
44552
- for (let i = startIndex; i < chunkFiles.length; i++) {
44553
- const file2 = chunkFiles[i];
44554
- const chunkId = file2.substring(name.length + 1);
44555
- if (deliveredChunkIds.has(chunkId)) {
44556
- continue;
44557
- }
44558
- const ext = fileExtMap.get(file2) ?? ".bin";
44559
- const chunk = deserializeChunk(await readBuffer(import_node_path8.default.join(chunksDir, `${file2}${ext}`)));
44560
- if (chunk?.eof === true) {
44561
- isComplete = true;
44562
- break;
44563
- }
44564
- if (chunk.chunk.byteLength) {
44565
- controller.enqueue(Uint8Array.from(chunk.chunk));
44566
- }
44567
- }
44568
- isReadingFromDisk = false;
44569
- bufferedEventChunks.sort((a, b) => a.chunkId.localeCompare(b.chunkId));
44570
- for (const buffered of bufferedEventChunks) {
44571
- controller.enqueue(Uint8Array.from(buffered.chunkData));
44572
- }
44573
- if (isComplete) {
44574
- removeListeners();
44575
- try {
44576
- controller.close();
44577
- }
44578
- catch {
44579
- }
44580
- return;
44581
- }
44582
- if (pendingClose) {
44583
- streamEmitter.off(`chunk:${name}`, chunkListener);
44584
- streamEmitter.off(`close:${name}`, closeListener);
44585
- try {
44586
- controller.close();
44587
- }
44588
- catch {
44589
- }
44590
- }
44591
- },
44592
- cancel() {
44593
- removeListeners();
44594
- }
45377
+ return Response.json({
45378
+ error: "Failed to process queue message"
45379
+ }, {
45380
+ status: 500
44595
45381
  });
44596
45382
  }
44597
45383
  };
44598
45384
  }
44599
- __name(createStreamer, "createStreamer");
44600
- // ../world-local/dist/index.js
44601
- function createLocalWorld(args) {
44602
- const definedArgs = args ? Object.fromEntries(Object.entries(args).filter(([, value]) => value !== void 0)) : {};
44603
- const mergedConfig = {
44604
- ...config2.value,
44605
- ...definedArgs
44606
- };
44607
- return {
44608
- ...createQueue(mergedConfig),
44609
- ...createStorage(mergedConfig.dataDir),
44610
- ...createStreamer(mergedConfig.dataDir),
44611
- async start() {
44612
- await initDataDir(mergedConfig.dataDir);
44613
- }
44614
- };
44615
- }
44616
- __name(createLocalWorld, "createLocalWorld");
45385
+ __name(handleCallback2, "handleCallback2");
44617
45386
  // ../world-vercel/dist/utils.js
44618
45387
  var import_node_os = __toESM(require("node:os"), 1);
44619
45388
  var import_node_util2 = require("node:util");
44620
- var import_oidc2 = __toESM(require_dist(), 1);
45389
+ var import_oidc3 = __toESM(require_dist(), 1);
44621
45390
  // ../../node_modules/.pnpm/cbor-x@1.6.0/node_modules/cbor-x/decode.js
44622
45391
  var decoder;
44623
45392
  try {
@@ -47236,7 +48005,7 @@ var RpcSystem3 = SemanticConvention3("rpc.system");
47236
48005
  var RpcService3 = SemanticConvention3("rpc.service");
47237
48006
  var RpcMethod3 = SemanticConvention3("rpc.method");
47238
48007
  // ../world-vercel/dist/version.js
47239
- var version2 = "4.1.0-beta.32";
48008
+ var version2 = "4.1.0-beta.33";
47240
48009
  // ../world-vercel/dist/utils.js
47241
48010
  var WORKFLOW_SERVER_URL_OVERRIDE = "";
47242
48011
  var DEFAULT_RESOLVE_DATA_OPTION2 = "all";
@@ -47324,7 +48093,7 @@ async function getHttpConfig(config3) {
47324
48093
  const headers = getHeaders(config3, {
47325
48094
  usingProxy
47326
48095
  });
47327
- const token = config3?.token ?? await (0, import_oidc2.getVercelOidcToken)();
48096
+ const token = config3?.token ?? await (0, import_oidc3.getVercelOidcToken)();
47328
48097
  if (token) {
47329
48098
  headers.set("Authorization", `Bearer ${token}`);
47330
48099
  }
@@ -47486,12 +48255,26 @@ var MessageWrapper = object({
47486
48255
  var MAX_DELAY_SECONDS = Number(process.env.VERCEL_QUEUE_MAX_DELAY_SECONDS || 82800
47487
48256
  // 23 hours - leave 1h buffer before 24h retention limit
47488
48257
  );
48258
+ function getHeadersFromPayload(payload) {
48259
+ const headers = {};
48260
+ if ("runId" in payload && typeof payload.runId === "string") {
48261
+ headers["x-workflow-run-id"] = payload.runId;
48262
+ }
48263
+ if ("workflowRunId" in payload && typeof payload.workflowRunId === "string") {
48264
+ headers["x-workflow-run-id"] = payload.workflowRunId;
48265
+ }
48266
+ if ("stepId" in payload && typeof payload.stepId === "string") {
48267
+ headers["x-workflow-step-id"] = payload.stepId;
48268
+ }
48269
+ return Object.keys(headers).length > 0 ? headers : void 0;
48270
+ }
48271
+ __name(getHeadersFromPayload, "getHeadersFromPayload");
47489
48272
  function createQueue2(config3) {
47490
48273
  const { baseUrl, usingProxy } = getHttpUrl(config3);
47491
48274
  const headers = getHeaders(config3, {
47492
48275
  usingProxy
47493
48276
  });
47494
- const baseClientOptions = {
48277
+ const clientOptions = {
47495
48278
  baseUrl: usingProxy ? baseUrl : void 0,
47496
48279
  // The proxy will strip `/queues` from the path, and add `/api` in front,
47497
48280
  // so this ends up being `/api/v3/topic` when arriving at the queue server,
@@ -47505,8 +48288,8 @@ function createQueue2(config3) {
47505
48288
  if (!deploymentId) {
47506
48289
  throw new Error("No deploymentId provided and VERCEL_DEPLOYMENT_ID environment variable is not set. Queue messages require a deployment ID to route correctly. Either set VERCEL_DEPLOYMENT_ID or provide deploymentId in options.");
47507
48290
  }
47508
- const sendMessageClient = new Client({
47509
- ...baseClientOptions,
48291
+ const client = new QueueClient({
48292
+ ...clientOptions,
47510
48293
  deploymentId
47511
48294
  });
47512
48295
  const hasEncoder = typeof MessageWrapper.encode === "function";
@@ -47522,10 +48305,15 @@ function createQueue2(config3) {
47522
48305
  });
47523
48306
  const sanitizedQueueName = queueName.replace(/[^A-Za-z0-9-_]/g, "-");
47524
48307
  try {
47525
- const { messageId } = await sendMessageClient.send(sanitizedQueueName, encoded, {
48308
+ const { messageId } = await client.sendMessage({
48309
+ queueName: sanitizedQueueName,
48310
+ payload: encoded,
47526
48311
  idempotencyKey: opts?.idempotencyKey,
47527
48312
  delaySeconds: opts?.delaySeconds,
47528
- headers: opts?.headers
48313
+ headers: {
48314
+ ...getHeadersFromPayload(payload),
48315
+ ...opts?.headers
48316
+ }
47529
48317
  });
47530
48318
  return {
47531
48319
  messageId: MessageId.parse(messageId)
@@ -47540,30 +48328,26 @@ function createQueue2(config3) {
47540
48328
  throw error45;
47541
48329
  }
47542
48330
  }, "queue");
47543
- const handleCallbackClient = new Client({
47544
- ...baseClientOptions
47545
- });
47546
- const createQueueHandler = /* @__PURE__ */ __name((prefix, handler) => {
47547
- return handleCallbackClient.handleCallback({
47548
- [`${prefix}*`]: {
47549
- default: /* @__PURE__ */ __name(async (body, meta) => {
47550
- const { payload, queueName, deploymentId } = MessageWrapper.parse(body);
47551
- const result = await handler(payload, {
47552
- queueName,
47553
- messageId: MessageId.parse(meta.messageId),
47554
- attempt: meta.deliveryCount
47555
- });
47556
- if (typeof result?.timeoutSeconds === "number") {
47557
- const delaySeconds = Math.min(result.timeoutSeconds, MAX_DELAY_SECONDS);
47558
- await queue(queueName, payload, {
47559
- deploymentId,
47560
- delaySeconds
47561
- });
47562
- return void 0;
47563
- }
47564
- return void 0;
47565
- }, "default")
48331
+ const createQueueHandler = /* @__PURE__ */ __name((_prefix, handler) => {
48332
+ return handleCallback2(async (message, metadata) => {
48333
+ if (!message || !metadata) {
48334
+ return;
48335
+ }
48336
+ const { payload, queueName, deploymentId } = MessageWrapper.parse(message);
48337
+ const result = await handler(payload, {
48338
+ queueName,
48339
+ messageId: MessageId.parse(metadata.messageId),
48340
+ attempt: metadata.deliveryCount
48341
+ });
48342
+ if (typeof result?.timeoutSeconds === "number") {
48343
+ const delaySeconds = Math.min(result.timeoutSeconds, MAX_DELAY_SECONDS);
48344
+ await queue(queueName, payload, {
48345
+ deploymentId,
48346
+ delaySeconds
48347
+ });
47566
48348
  }
48349
+ }, {
48350
+ client: new QueueClient(clientOptions)
47567
48351
  });
47568
48352
  }, "createQueueHandler");
47569
48353
  const getDeploymentId = /* @__PURE__ */ __name(async () => {
@@ -48234,6 +49018,7 @@ var createWorld = /* @__PURE__ */ __name(() => {
48234
49018
  projectConfig: {
48235
49019
  environment: process.env.WORKFLOW_VERCEL_ENV,
48236
49020
  projectId: process.env.WORKFLOW_VERCEL_PROJECT,
49021
+ projectName: process.env.WORKFLOW_VERCEL_PROJECT_NAME,
48237
49022
  teamId: process.env.WORKFLOW_VERCEL_TEAM
48238
49023
  }
48239
49024
  });
@@ -48921,7 +49706,7 @@ function getStepRevivers(global2 = globalThis, ops, runId) {
48921
49706
  };
48922
49707
  }
48923
49708
  __name(getStepRevivers, "getStepRevivers");
48924
- function hydrateStepArguments(value, ops, runId, global2 = globalThis, extraRevivers = {}) {
49709
+ async function hydrateStepArguments(value, runId, _key, ops = [], global2 = globalThis, extraRevivers = {}) {
48925
49710
  if (!(value instanceof Uint8Array)) {
48926
49711
  return unflatten(value, {
48927
49712
  ...getStepRevivers(global2, ops, runId),
@@ -48940,7 +49725,7 @@ function hydrateStepArguments(value, ops, runId, global2 = globalThis, extraRevi
48940
49725
  throw new Error(`Unsupported serialization format: ${format}`);
48941
49726
  }
48942
49727
  __name(hydrateStepArguments, "hydrateStepArguments");
48943
- function dehydrateStepReturnValue(value, ops, runId, global2 = globalThis, v1Compat = false) {
49728
+ async function dehydrateStepReturnValue(value, runId, _key, ops = [], global2 = globalThis, v1Compat = false) {
48944
49729
  try {
48945
49730
  const str = stringify(value, getStepReducers(global2, ops, runId));
48946
49731
  if (v1Compat) {
@@ -49095,21 +49880,35 @@ async function withServerErrorRetry(fn) {
49095
49880
  }
49096
49881
  __name(withServerErrorRetry, "withServerErrorRetry");
49097
49882
  // ../core/dist/runtime/resume-hook.js
49098
- async function getHookByToken2(token) {
49883
+ async function getHookByTokenWithKey(token) {
49099
49884
  const world = getWorld();
49100
49885
  const hook = await world.hooks.getByToken(token);
49886
+ const encryptionKey = await world.getEncryptionKeyForRun?.(hook.runId);
49101
49887
  if (typeof hook.metadata !== "undefined") {
49102
- hook.metadata = hydrateStepArguments(hook.metadata, [], hook.runId);
49888
+ hook.metadata = await hydrateStepArguments(hook.metadata, hook.runId, encryptionKey);
49103
49889
  }
49104
- return hook;
49890
+ return {
49891
+ hook,
49892
+ encryptionKey
49893
+ };
49105
49894
  }
49106
- __name(getHookByToken2, "getHookByToken");
49107
- async function resumeHook(tokenOrHook, payload) {
49895
+ __name(getHookByTokenWithKey, "getHookByTokenWithKey");
49896
+ async function resumeHook(tokenOrHook, payload, encryptionKeyOverride) {
49108
49897
  return await waitedUntil(() => {
49109
49898
  return trace("hook.resume", async (span) => {
49110
49899
  const world = getWorld();
49111
49900
  try {
49112
- const hook = typeof tokenOrHook === "string" ? await getHookByToken2(tokenOrHook) : tokenOrHook;
49901
+ let hook;
49902
+ let encryptionKey;
49903
+ if (typeof tokenOrHook === "string") {
49904
+ const result = await getHookByTokenWithKey(tokenOrHook);
49905
+ hook = result.hook;
49906
+ encryptionKey = encryptionKeyOverride ?? result.encryptionKey;
49907
+ }
49908
+ else {
49909
+ hook = tokenOrHook;
49910
+ encryptionKey = encryptionKeyOverride ?? await world.getEncryptionKeyForRun?.(hook.runId);
49911
+ }
49113
49912
  span?.setAttributes({
49114
49913
  ...HookToken(hook.token),
49115
49914
  ...HookId(hook.hookId),
@@ -49117,7 +49916,7 @@ async function resumeHook(tokenOrHook, payload) {
49117
49916
  });
49118
49917
  const ops = [];
49119
49918
  const v1Compat = isLegacySpecVersion(hook.specVersion);
49120
- const dehydratedPayload = dehydrateStepReturnValue(payload, ops, hook.runId, globalThis, v1Compat);
49919
+ const dehydratedPayload = await dehydrateStepReturnValue(payload, hook.runId, encryptionKey, ops, globalThis, v1Compat);
49121
49920
  (0, import_functions2.waitUntil)(Promise.all(ops).catch((err) => {
49122
49921
  if (err !== void 0)
49123
49922
  throw err;
@@ -49529,10 +50328,6 @@ var stepHandler = getWorldHandlers().createQueueHandler("__wkf_step_", async (me
49529
50328
  runId: workflowRunId,
49530
50329
  traceCarrier: await serializeTraceCarrier(),
49531
50330
  requestedAt: /* @__PURE__ */ new Date()
49532
- }, {
49533
- headers: {
49534
- "x-workflow-run-id": workflowRunId
49535
- }
49536
50331
  });
49537
50332
  return;
49538
50333
  }
@@ -49543,9 +50338,10 @@ var stepHandler = getWorldHandlers().createQueueHandler("__wkf_step_", async (me
49543
50338
  }
49544
50339
  const stepStartedAt = step.startedAt;
49545
50340
  const ops = [];
50341
+ const encryptionKey = await world.getEncryptionKeyForRun?.(workflowRunId);
49546
50342
  const hydratedInput = await trace("step.hydrate", {}, async (hydrateSpan) => {
49547
50343
  const startTime = Date.now();
49548
- const result2 = hydrateStepArguments(step.input, ops, workflowRunId);
50344
+ const result2 = await hydrateStepArguments(step.input, workflowRunId, encryptionKey, ops);
49549
50345
  const durationMs = Date.now() - startTime;
49550
50346
  hydrateSpan?.setAttributes({
49551
50347
  ...StepArgumentsCount(result2.args.length),
@@ -49580,7 +50376,7 @@ var stepHandler = getWorldHandlers().createQueueHandler("__wkf_step_", async (me
49580
50376
  });
49581
50377
  result = await trace("step.dehydrate", {}, async (dehydrateSpan) => {
49582
50378
  const startTime = Date.now();
49583
- const dehydrated = dehydrateStepReturnValue(result, ops, workflowRunId);
50379
+ const dehydrated = await dehydrateStepReturnValue(result, workflowRunId, encryptionKey, ops);
49584
50380
  const durationMs = Date.now() - startTime;
49585
50381
  dehydrateSpan?.setAttributes({
49586
50382
  ...QueueSerializeTimeMs(durationMs),
@@ -49751,10 +50547,6 @@ var stepHandler = getWorldHandlers().createQueueHandler("__wkf_step_", async (me
49751
50547
  runId: workflowRunId,
49752
50548
  traceCarrier: await serializeTraceCarrier(),
49753
50549
  requestedAt: /* @__PURE__ */ new Date()
49754
- }, {
49755
- headers: {
49756
- "x-workflow-run-id": workflowRunId
49757
- }
49758
50550
  });
49759
50551
  });
49760
50552
  });