@upstash/qstash 2.10.1 → 2.11.1
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.
- package/README.md +20 -0
- package/{chunk-Z37KJCW7.mjs → chunk-ATX5KA4T.mjs} +1 -1
- package/{chunk-PIBVA43B.mjs → chunk-KGYBZXTJ.mjs} +1 -1
- package/{chunk-35B33QW3.mjs → chunk-T3Z5YUS4.mjs} +492 -12
- package/{client-CsM1dTnz.d.ts → client-BHOXiX0H.d.mts} +52 -2
- package/{client-CsM1dTnz.d.mts → client-BHOXiX0H.d.ts} +52 -2
- package/cloudflare.d.mts +1 -1
- package/cloudflare.d.ts +1 -1
- package/cloudflare.js +490 -12
- package/cloudflare.mjs +1 -1
- package/h3.d.mts +1 -1
- package/h3.d.ts +1 -1
- package/h3.js +490 -12
- package/h3.mjs +3 -3
- package/hono.d.mts +1 -1
- package/hono.d.ts +1 -1
- package/hono.js +490 -12
- package/hono.mjs +1 -1
- package/index.d.mts +2 -2
- package/index.d.ts +2 -2
- package/index.js +490 -12
- package/index.mjs +2 -2
- package/nextjs.d.mts +33 -2
- package/nextjs.d.ts +33 -2
- package/nextjs.js +511 -18
- package/nextjs.mjs +24 -8
- package/nuxt.js +70 -3
- package/nuxt.mjs +3 -3
- package/package.json +1 -1
- package/solidjs.d.mts +1 -1
- package/solidjs.d.ts +1 -1
- package/solidjs.js +490 -12
- package/solidjs.mjs +2 -2
- package/svelte.d.mts +1 -1
- package/svelte.d.ts +1 -1
- package/svelte.js +490 -12
- package/svelte.mjs +2 -2
- package/workflow.d.mts +1 -1
- package/workflow.d.ts +1 -1
- package/workflow.js +490 -12
- package/workflow.mjs +1 -1
package/README.md
CHANGED
|
@@ -127,6 +127,26 @@ const result = await client.publishJSON({
|
|
|
127
127
|
});
|
|
128
128
|
```
|
|
129
129
|
|
|
130
|
+
## Local Development
|
|
131
|
+
|
|
132
|
+
Set `QSTASH_DEV=true` in your environment variables, and the SDK will download and connect to a local QStash dev server automatically. No tokens or signing keys required: the SDK injects deterministic dev credentials.
|
|
133
|
+
|
|
134
|
+
```bash .env
|
|
135
|
+
QSTASH_DEV=true
|
|
136
|
+
```
|
|
137
|
+
|
|
138
|
+
Alternatively, pass `devMode: true` to explicitly enable dev mode:
|
|
139
|
+
|
|
140
|
+
```ts
|
|
141
|
+
import { Client } from "@upstash/qstash";
|
|
142
|
+
|
|
143
|
+
const client = new Client({ devMode: true });
|
|
144
|
+
```
|
|
145
|
+
|
|
146
|
+
The same flag works on the receiving side: pass `devMode: true` to `Receiver` or `verifySignature*` to verify signatures with the dev server's keys. Dev mode is automatically a no-op when `NODE_ENV=production` and in browser/edge runtimes.
|
|
147
|
+
|
|
148
|
+
See [Local Development](https://docs.upstash.com/qstash/howto/local-development) for the full walkthrough, including the `registerQStashDev()` helper for Next.js edge routes.
|
|
149
|
+
|
|
130
150
|
## Docs
|
|
131
151
|
|
|
132
152
|
See [the documentation](https://docs.upstash.com/qstash) for details.
|
|
@@ -256,6 +256,9 @@ var formatWorkflowError = (error) => {
|
|
|
256
256
|
|
|
257
257
|
// src/client/utils.ts
|
|
258
258
|
var DEFAULT_BULK_COUNT = 100;
|
|
259
|
+
function serializeLabel(label) {
|
|
260
|
+
return Array.isArray(label) ? label.join(",") : label;
|
|
261
|
+
}
|
|
259
262
|
var isIgnoredHeader = (header) => {
|
|
260
263
|
const lowerCaseHeader = header.toLowerCase();
|
|
261
264
|
return lowerCaseHeader.startsWith("content-type") || lowerCaseHeader.startsWith("upstash-");
|
|
@@ -340,7 +343,7 @@ function processHeaders(request) {
|
|
|
340
343
|
headers.set("Upstash-Flow-Control-Value", controlValue.join(", "));
|
|
341
344
|
}
|
|
342
345
|
if (request.label !== void 0) {
|
|
343
|
-
headers.set("Upstash-Label", request.label);
|
|
346
|
+
headers.set("Upstash-Label", serializeLabel(request.label));
|
|
344
347
|
}
|
|
345
348
|
if (request.redact !== void 0) {
|
|
346
349
|
const redactParts = [];
|
|
@@ -437,17 +440,23 @@ function normalizeCursor(response) {
|
|
|
437
440
|
const cursor = response.cursor;
|
|
438
441
|
return { ...response, cursor: cursor || void 0 };
|
|
439
442
|
}
|
|
443
|
+
function _processGlobal() {
|
|
444
|
+
const proc = globalThis["process"];
|
|
445
|
+
return proc;
|
|
446
|
+
}
|
|
440
447
|
function getRuntime() {
|
|
441
|
-
|
|
442
|
-
|
|
448
|
+
const proc = _processGlobal();
|
|
449
|
+
if (proc?.versions?.bun)
|
|
450
|
+
return `bun@${proc.versions.bun}`;
|
|
443
451
|
if (typeof EdgeRuntime === "string")
|
|
444
452
|
return "edge-light";
|
|
445
|
-
|
|
446
|
-
return `node@${
|
|
453
|
+
if (typeof proc?.version === "string")
|
|
454
|
+
return `node@${proc.version}`;
|
|
447
455
|
return "";
|
|
448
456
|
}
|
|
449
457
|
function getSafeEnvironment() {
|
|
450
|
-
|
|
458
|
+
const proc = _processGlobal();
|
|
459
|
+
return proc?.env ?? {};
|
|
451
460
|
}
|
|
452
461
|
|
|
453
462
|
// src/client/multi-region/utils.ts
|
|
@@ -491,12 +500,453 @@ function normalizeRegionHeader(region) {
|
|
|
491
500
|
return void 0;
|
|
492
501
|
}
|
|
493
502
|
|
|
503
|
+
// src/dev-server/constants.ts
|
|
504
|
+
var DEFAULT_DEV_PORT = 8080;
|
|
505
|
+
var DEV_CREDENTIALS = {
|
|
506
|
+
token: "eyJVc2VySUQiOiJkZWZhdWx0VXNlciIsIlBhc3N3b3JkIjoiZGVmYXVsdFBhc3N3b3JkIn0=",
|
|
507
|
+
currentSigningKey: "sig_7kYjw48mhY7kAjqNGcy6cr29RJ6r",
|
|
508
|
+
nextSigningKey: "sig_5ZB6DVzB1wjE8S6rZ7eenA8Pdnhs"
|
|
509
|
+
};
|
|
510
|
+
var GITHUB_RELEASES_URL = "https://api.github.com/repos/upstash/qstash-cli/releases/latest";
|
|
511
|
+
var BINARY_URL_BASE = "https://artifacts.upstash.com/qstash/versions";
|
|
512
|
+
var CONSOLE_URL = "https://console.upstash.com/qstash/local-mode-user";
|
|
513
|
+
var DEV_PREFIX = "\x1B[2m[QStash Dev]\x1B[0m";
|
|
514
|
+
var CLI_PREFIX = "\x1B[2m[QStash CLI]\x1B[0m";
|
|
515
|
+
var _n = (m) => `node:${m}`;
|
|
516
|
+
var importHttp = () => import(
|
|
517
|
+
/* webpackIgnore: true */
|
|
518
|
+
_n("http")
|
|
519
|
+
);
|
|
520
|
+
var importHttps = () => import(
|
|
521
|
+
/* webpackIgnore: true */
|
|
522
|
+
_n("https")
|
|
523
|
+
);
|
|
524
|
+
var importFs = () => import(
|
|
525
|
+
/* webpackIgnore: true */
|
|
526
|
+
_n("fs")
|
|
527
|
+
);
|
|
528
|
+
var importChildProcess = () => import(
|
|
529
|
+
/* webpackIgnore: true */
|
|
530
|
+
_n("child_process")
|
|
531
|
+
);
|
|
532
|
+
var importOs = () => import(
|
|
533
|
+
/* webpackIgnore: true */
|
|
534
|
+
_n("os")
|
|
535
|
+
);
|
|
536
|
+
|
|
537
|
+
// src/dev-server/http.ts
|
|
538
|
+
var HTTP_OK = 200;
|
|
539
|
+
var HTTP_MULTI_CHOICE = 300;
|
|
540
|
+
var nativeGet = async (url, headers, timeoutMs) => {
|
|
541
|
+
const parsedUrl = new URL(url);
|
|
542
|
+
const httpModule = parsedUrl.protocol === "https:" ? await importHttps() : await importHttp();
|
|
543
|
+
return new Promise((resolve, reject) => {
|
|
544
|
+
const request = httpModule.get(url, { headers }, (response) => {
|
|
545
|
+
const chunks = [];
|
|
546
|
+
response.on("data", (chunk) => chunks.push(chunk));
|
|
547
|
+
response.on("end", () => {
|
|
548
|
+
const statusCode = response.statusCode ?? 0;
|
|
549
|
+
resolve({
|
|
550
|
+
ok: statusCode >= HTTP_OK && statusCode < HTTP_MULTI_CHOICE,
|
|
551
|
+
statusCode,
|
|
552
|
+
body: Buffer.concat(chunks)
|
|
553
|
+
});
|
|
554
|
+
});
|
|
555
|
+
response.on("error", reject);
|
|
556
|
+
});
|
|
557
|
+
if (timeoutMs) {
|
|
558
|
+
request.setTimeout(timeoutMs, () => {
|
|
559
|
+
request.destroy(new Error("Request timed out"));
|
|
560
|
+
});
|
|
561
|
+
}
|
|
562
|
+
request.on("error", reject);
|
|
563
|
+
});
|
|
564
|
+
};
|
|
565
|
+
|
|
566
|
+
// src/dev-server/health.ts
|
|
567
|
+
var HEALTH_CHECK_TIMEOUT_MS = 2e3;
|
|
568
|
+
var isDevServerRunning = async (baseUrl) => {
|
|
569
|
+
try {
|
|
570
|
+
const { ok: ok4, body } = await nativeGet(
|
|
571
|
+
`${baseUrl}/v2/keys`,
|
|
572
|
+
{ Authorization: `Bearer ${DEV_CREDENTIALS.token}` },
|
|
573
|
+
HEALTH_CHECK_TIMEOUT_MS
|
|
574
|
+
);
|
|
575
|
+
if (!ok4)
|
|
576
|
+
return false;
|
|
577
|
+
const data = JSON.parse(body.toString());
|
|
578
|
+
return data.current === DEV_CREDENTIALS.currentSigningKey && data.next === DEV_CREDENTIALS.nextSigningKey;
|
|
579
|
+
} catch {
|
|
580
|
+
return false;
|
|
581
|
+
}
|
|
582
|
+
};
|
|
583
|
+
var _didLogUnreachable = false;
|
|
584
|
+
var checkDevServerReachable = async (baseUrl, runtime) => {
|
|
585
|
+
if (await pingEdge(baseUrl))
|
|
586
|
+
return;
|
|
587
|
+
if (!_didLogUnreachable) {
|
|
588
|
+
console.error(unreachableMessage(baseUrl, runtime));
|
|
589
|
+
_didLogUnreachable = true;
|
|
590
|
+
}
|
|
591
|
+
throw new Error(`${DEV_PREFIX} dev server unreachable at ${baseUrl}`);
|
|
592
|
+
};
|
|
593
|
+
var pingEdge = async (baseUrl) => {
|
|
594
|
+
try {
|
|
595
|
+
const controller = new AbortController();
|
|
596
|
+
const timeout = setTimeout(() => {
|
|
597
|
+
controller.abort();
|
|
598
|
+
}, HEALTH_CHECK_TIMEOUT_MS);
|
|
599
|
+
const response = await fetch(`${baseUrl}/v2/keys`, {
|
|
600
|
+
headers: { Authorization: `Bearer ${DEV_CREDENTIALS.token}` },
|
|
601
|
+
signal: controller.signal
|
|
602
|
+
});
|
|
603
|
+
clearTimeout(timeout);
|
|
604
|
+
return response.ok;
|
|
605
|
+
} catch {
|
|
606
|
+
return false;
|
|
607
|
+
}
|
|
608
|
+
};
|
|
609
|
+
var unreachableMessage = (baseUrl, runtime) => {
|
|
610
|
+
const port = new URL(baseUrl).port;
|
|
611
|
+
const manualStartCmd = `npx @upstash/qstash-cli dev --port ${port}`;
|
|
612
|
+
const header = `
|
|
613
|
+
${DEV_PREFIX} The dev server is not running at ${baseUrl}.
|
|
614
|
+
|
|
615
|
+
`;
|
|
616
|
+
if (runtime === "cloudflare-workers") {
|
|
617
|
+
return header + `Cloudflare Workers cannot start the dev server automatically.
|
|
618
|
+
Start it manually before running wrangler dev:
|
|
619
|
+
|
|
620
|
+
${manualStartCmd}
|
|
621
|
+
`;
|
|
622
|
+
}
|
|
623
|
+
return header + `Edge runtimes cannot start the dev server automatically.
|
|
624
|
+
Either:
|
|
625
|
+
1. Add the instrumentation hook to start it with your app:
|
|
626
|
+
|
|
627
|
+
// instrumentation.ts
|
|
628
|
+
import { registerQStashDev } from "@upstash/qstash/nextjs";
|
|
629
|
+
export async function register() { await registerQStashDev(); }
|
|
630
|
+
|
|
631
|
+
2. Or start it manually:
|
|
632
|
+
|
|
633
|
+
${manualStartCmd}
|
|
634
|
+
`;
|
|
635
|
+
};
|
|
636
|
+
|
|
637
|
+
// src/dev-server/binary.ts
|
|
638
|
+
var ensureBinary = async () => {
|
|
639
|
+
const fs = await importFs();
|
|
640
|
+
const os = await importOs();
|
|
641
|
+
const cacheDirectory = await findCacheDirectory();
|
|
642
|
+
const isWindows = os.platform() === "win32";
|
|
643
|
+
const binaryName = isWindows ? "qstash.exe" : "qstash";
|
|
644
|
+
const binaryPath = `${cacheDirectory}/${binaryName}`;
|
|
645
|
+
const versionFile = `${cacheDirectory}/.version`;
|
|
646
|
+
let version;
|
|
647
|
+
try {
|
|
648
|
+
version = await fetchLatestVersion();
|
|
649
|
+
} catch (error) {
|
|
650
|
+
if (fs.existsSync(binaryPath)) {
|
|
651
|
+
const cachedVersion = fs.existsSync(versionFile) ? fs.readFileSync(versionFile, "utf8").trim() : "unknown";
|
|
652
|
+
console.log(`${DEV_PREFIX} Offline, using local v${cachedVersion}`);
|
|
653
|
+
return binaryPath;
|
|
654
|
+
}
|
|
655
|
+
throw error;
|
|
656
|
+
}
|
|
657
|
+
return downloadBinary(version, cacheDirectory);
|
|
658
|
+
};
|
|
659
|
+
var fetchLatestVersion = async () => {
|
|
660
|
+
const { ok: ok4, statusCode, body } = await nativeGet(GITHUB_RELEASES_URL, {
|
|
661
|
+
Accept: "application/vnd.github.v3+json",
|
|
662
|
+
"User-Agent": "upstash-qstash-js"
|
|
663
|
+
});
|
|
664
|
+
if (!ok4) {
|
|
665
|
+
throw new Error(`[QStash Dev] Failed to fetch latest version: HTTP ${statusCode}`);
|
|
666
|
+
}
|
|
667
|
+
const data = JSON.parse(body.toString());
|
|
668
|
+
return data.tag_name.replace(/^v/, "");
|
|
669
|
+
};
|
|
670
|
+
var findCacheDirectory = async () => {
|
|
671
|
+
const fs = await importFs();
|
|
672
|
+
const os = await importOs();
|
|
673
|
+
const home = os.homedir();
|
|
674
|
+
const platform = os.platform();
|
|
675
|
+
let base;
|
|
676
|
+
if (platform === "darwin") {
|
|
677
|
+
base = `${home}/Library/Caches/upstash`;
|
|
678
|
+
} else if (platform === "win32") {
|
|
679
|
+
base = `${process.env.LOCALAPPDATA ?? `${home}/AppData/Local`}/upstash`;
|
|
680
|
+
} else {
|
|
681
|
+
base = `${home}/.cache/upstash`;
|
|
682
|
+
}
|
|
683
|
+
const cacheDirectory = `${base}/qstash-dev`;
|
|
684
|
+
await fs.promises.mkdir(cacheDirectory, { recursive: true });
|
|
685
|
+
return cacheDirectory;
|
|
686
|
+
};
|
|
687
|
+
var downloadBinary = async (version, cacheDirectory) => {
|
|
688
|
+
const fs = await importFs();
|
|
689
|
+
const childProcess = await importChildProcess();
|
|
690
|
+
const os = await importOs();
|
|
691
|
+
const osPlatform = os.platform();
|
|
692
|
+
const isWindows = osPlatform === "win32";
|
|
693
|
+
const platform = isWindows ? "windows" : osPlatform === "darwin" ? "darwin" : "linux";
|
|
694
|
+
const arch = os.arch() === "arm64" ? "arm64" : "amd64";
|
|
695
|
+
const archiveName = `qstash-server_${version}_${platform}_${arch}`;
|
|
696
|
+
const binaryName = isWindows ? "qstash.exe" : "qstash";
|
|
697
|
+
const binaryPath = `${cacheDirectory}/${binaryName}`;
|
|
698
|
+
const versionFile = `${cacheDirectory}/.version`;
|
|
699
|
+
if (fs.existsSync(binaryPath) && fs.existsSync(versionFile)) {
|
|
700
|
+
const cachedVersion = fs.readFileSync(versionFile, "utf8").trim();
|
|
701
|
+
if (cachedVersion === version) {
|
|
702
|
+
return binaryPath;
|
|
703
|
+
}
|
|
704
|
+
}
|
|
705
|
+
await fs.promises.rm(cacheDirectory, { recursive: true, force: true });
|
|
706
|
+
await fs.promises.mkdir(cacheDirectory, { recursive: true });
|
|
707
|
+
const extension = isWindows ? "zip" : "tar.gz";
|
|
708
|
+
const archiveUrl = `${BINARY_URL_BASE}/${version}/${archiveName}.${extension}`;
|
|
709
|
+
console.log(`${DEV_PREFIX} Downloading dev server v${version}...`);
|
|
710
|
+
const { ok: ok4, statusCode, body } = await nativeGet(archiveUrl);
|
|
711
|
+
if (!ok4) {
|
|
712
|
+
throw new Error(`[QStash Dev] Failed to download binary: HTTP ${statusCode}`);
|
|
713
|
+
}
|
|
714
|
+
const archivePath = `${cacheDirectory}/${archiveName}.${extension}`;
|
|
715
|
+
await fs.promises.writeFile(archivePath, new Uint8Array(body));
|
|
716
|
+
childProcess.execFileSync("tar", ["-xf", archivePath, "-C", cacheDirectory], {
|
|
717
|
+
stdio: "pipe"
|
|
718
|
+
});
|
|
719
|
+
if (!isWindows) {
|
|
720
|
+
const EXECUTABLE_PERMISSION = 493;
|
|
721
|
+
await fs.promises.chmod(binaryPath, EXECUTABLE_PERMISSION);
|
|
722
|
+
}
|
|
723
|
+
await fs.promises.writeFile(versionFile, version);
|
|
724
|
+
await fs.promises.unlink(archivePath).catch(() => {
|
|
725
|
+
});
|
|
726
|
+
return binaryPath;
|
|
727
|
+
};
|
|
728
|
+
|
|
729
|
+
// src/dev-server/process.ts
|
|
730
|
+
var STARTUP_TIMEOUT_MS = 3e4;
|
|
731
|
+
var _proc = () => {
|
|
732
|
+
return globalThis["process"] ?? {};
|
|
733
|
+
};
|
|
734
|
+
var spawnServer = async (binaryPath, port, onUnexpectedExit) => {
|
|
735
|
+
const childProcess = await importChildProcess();
|
|
736
|
+
const child = await new Promise((resolve, reject) => {
|
|
737
|
+
const child2 = childProcess.spawn(binaryPath, ["dev", "--port", String(port)], {
|
|
738
|
+
stdio: ["ignore", "pipe", "pipe"]
|
|
739
|
+
});
|
|
740
|
+
const timeout = setTimeout(() => {
|
|
741
|
+
child2.kill();
|
|
742
|
+
reject(new Error("[QStash Dev] Server failed to start within 30 seconds"));
|
|
743
|
+
}, STARTUP_TIMEOUT_MS);
|
|
744
|
+
let startupOutput = "";
|
|
745
|
+
let started = false;
|
|
746
|
+
const bufferLine = (line) => {
|
|
747
|
+
if (!started)
|
|
748
|
+
startupOutput += `${line}
|
|
749
|
+
`;
|
|
750
|
+
};
|
|
751
|
+
forwardWithPrefix(child2.stdout, _proc().stdout, (line) => {
|
|
752
|
+
bufferLine(line);
|
|
753
|
+
if (!started && /runn+ing( at|\.)/i.test(line)) {
|
|
754
|
+
clearTimeout(timeout);
|
|
755
|
+
started = true;
|
|
756
|
+
resolve(child2);
|
|
757
|
+
}
|
|
758
|
+
});
|
|
759
|
+
forwardWithPrefix(child2.stderr, _proc().stderr, bufferLine);
|
|
760
|
+
child2.on("error", (error) => {
|
|
761
|
+
clearTimeout(timeout);
|
|
762
|
+
reject(new Error(`[QStash Dev] Failed to start server: ${error.message}`));
|
|
763
|
+
});
|
|
764
|
+
child2.on("close", (code, _signal) => {
|
|
765
|
+
if (started) {
|
|
766
|
+
onUnexpectedExit?.();
|
|
767
|
+
return;
|
|
768
|
+
}
|
|
769
|
+
clearTimeout(timeout);
|
|
770
|
+
reject(new Error(formatStartupError(code, startupOutput)));
|
|
771
|
+
});
|
|
772
|
+
});
|
|
773
|
+
registerCleanup(child);
|
|
774
|
+
child.unref?.();
|
|
775
|
+
child.stdout?.unref?.();
|
|
776
|
+
child.stderr?.unref?.();
|
|
777
|
+
};
|
|
778
|
+
var formatStartupError = (code, startupOutput) => {
|
|
779
|
+
const cleaned = startupOutput.replaceAll(/\u001B\[[\d;]*m/g, "").replaceAll(/^\d{1,2}:\d{2}(AM|PM)\s+\w{3}\s+/gm, "").trim();
|
|
780
|
+
if (/address already in use/i.test(cleaned)) {
|
|
781
|
+
const match = /:(\d+)\s*$/.exec(cleaned);
|
|
782
|
+
const portHint = match ? ` on port ${match[1]}` : "";
|
|
783
|
+
return `[QStash Dev] Port already in use${portHint}. Set QSTASH_DEV_PORT to use a different port, or stop the process holding it.`;
|
|
784
|
+
}
|
|
785
|
+
const codeSuffix = code ? ` with code ${code}` : "";
|
|
786
|
+
const detail = cleaned ? `: ${cleaned}` : "";
|
|
787
|
+
return `[QStash Dev] Server exited unexpectedly${codeSuffix}${detail}`;
|
|
788
|
+
};
|
|
789
|
+
var forwardWithPrefix = (source, destination, onLine) => {
|
|
790
|
+
if (!source)
|
|
791
|
+
return;
|
|
792
|
+
let buffer = "";
|
|
793
|
+
const flushLine = (line) => {
|
|
794
|
+
destination?.write(`${CLI_PREFIX} ${line}
|
|
795
|
+
`);
|
|
796
|
+
onLine(line);
|
|
797
|
+
};
|
|
798
|
+
source.on("data", (data) => {
|
|
799
|
+
buffer += data.toString();
|
|
800
|
+
let newlineIndex = buffer.indexOf("\n");
|
|
801
|
+
while (newlineIndex !== -1) {
|
|
802
|
+
flushLine(buffer.slice(0, newlineIndex));
|
|
803
|
+
buffer = buffer.slice(newlineIndex + 1);
|
|
804
|
+
newlineIndex = buffer.indexOf("\n");
|
|
805
|
+
}
|
|
806
|
+
});
|
|
807
|
+
source.on("end", () => {
|
|
808
|
+
if (buffer.length > 0) {
|
|
809
|
+
flushLine(buffer);
|
|
810
|
+
buffer = "";
|
|
811
|
+
}
|
|
812
|
+
});
|
|
813
|
+
source.on("error", () => {
|
|
814
|
+
});
|
|
815
|
+
};
|
|
816
|
+
var currentChild;
|
|
817
|
+
var processHandlersRegistered = false;
|
|
818
|
+
var killCurrentChild = () => {
|
|
819
|
+
if (!currentChild)
|
|
820
|
+
return;
|
|
821
|
+
try {
|
|
822
|
+
currentChild.kill("SIGTERM");
|
|
823
|
+
} catch {
|
|
824
|
+
}
|
|
825
|
+
currentChild = void 0;
|
|
826
|
+
};
|
|
827
|
+
var registerCleanup = (child) => {
|
|
828
|
+
currentChild = child;
|
|
829
|
+
if (!processHandlersRegistered) {
|
|
830
|
+
processHandlersRegistered = true;
|
|
831
|
+
const proc = _proc();
|
|
832
|
+
proc.on?.("exit", killCurrentChild);
|
|
833
|
+
proc.on?.("SIGINT", () => {
|
|
834
|
+
killCurrentChild();
|
|
835
|
+
proc.exit?.(0);
|
|
836
|
+
});
|
|
837
|
+
proc.on?.("SIGTERM", () => {
|
|
838
|
+
killCurrentChild();
|
|
839
|
+
proc.exit?.(0);
|
|
840
|
+
});
|
|
841
|
+
}
|
|
842
|
+
};
|
|
843
|
+
|
|
844
|
+
// src/dev-server/index.ts
|
|
845
|
+
var _processGlobal2 = () => {
|
|
846
|
+
const proc = globalThis["process"];
|
|
847
|
+
return proc;
|
|
848
|
+
};
|
|
849
|
+
var devServerPromise;
|
|
850
|
+
var ensureDevelopmentServer = (env, devMode) => {
|
|
851
|
+
if (!shouldUseDevelopmentMode(devMode, env))
|
|
852
|
+
return Promise.resolve();
|
|
853
|
+
const procEnv = _processGlobal2()?.env;
|
|
854
|
+
if (procEnv?.NEXT_PHASE === "phase-production-build")
|
|
855
|
+
return Promise.resolve();
|
|
856
|
+
if (procEnv?.NODE_ENV === "production")
|
|
857
|
+
return Promise.resolve();
|
|
858
|
+
const runtime = getRuntime2();
|
|
859
|
+
if (runtime !== "nodejs") {
|
|
860
|
+
return checkDevServerReachable(getDevUrl(env), runtime);
|
|
861
|
+
}
|
|
862
|
+
if (!devServerPromise) {
|
|
863
|
+
devServerPromise = startPipeline(env).catch((error) => {
|
|
864
|
+
devServerPromise = void 0;
|
|
865
|
+
throw error;
|
|
866
|
+
});
|
|
867
|
+
}
|
|
868
|
+
return devServerPromise;
|
|
869
|
+
};
|
|
870
|
+
var startPipeline = async (env) => {
|
|
871
|
+
const baseUrl = getDevUrl(env);
|
|
872
|
+
const port = new URL(baseUrl).port;
|
|
873
|
+
const consoleLink = `\x1B[36m${CONSOLE_URL}?port=${port}\x1B[0m`;
|
|
874
|
+
if (await isDevServerRunning(baseUrl)) {
|
|
875
|
+
console.log(
|
|
876
|
+
`${DEV_PREFIX} Server already running at ${baseUrl}
|
|
877
|
+
${DEV_PREFIX} Console: ${consoleLink}`
|
|
878
|
+
);
|
|
879
|
+
return;
|
|
880
|
+
}
|
|
881
|
+
const binaryPath = await ensureBinary();
|
|
882
|
+
await spawnServer(binaryPath, port, () => {
|
|
883
|
+
devServerPromise = void 0;
|
|
884
|
+
});
|
|
885
|
+
};
|
|
886
|
+
var shouldUseDevelopmentMode = (devMode, env) => {
|
|
887
|
+
if (devMode !== void 0)
|
|
888
|
+
return devMode;
|
|
889
|
+
const value = env?.QSTASH_DEV ?? getProcessEnvironment("QSTASH_DEV");
|
|
890
|
+
if (value === void 0 || value === "" || value === "false" || value === "0")
|
|
891
|
+
return false;
|
|
892
|
+
if (value === "true" || value === "1")
|
|
893
|
+
return true;
|
|
894
|
+
throw new Error(`[QStash Dev] Invalid value for QSTASH_DEV in environment: ${value}`);
|
|
895
|
+
};
|
|
896
|
+
var getDevelopmentCredentials = (env) => {
|
|
897
|
+
return {
|
|
898
|
+
...DEV_CREDENTIALS,
|
|
899
|
+
baseUrl: getDevUrl(env)
|
|
900
|
+
};
|
|
901
|
+
};
|
|
902
|
+
var getDevUrl = (env) => {
|
|
903
|
+
const portString = env?.QSTASH_DEV_PORT ?? getProcessEnvironment("QSTASH_DEV_PORT");
|
|
904
|
+
let port = DEFAULT_DEV_PORT;
|
|
905
|
+
if (portString) {
|
|
906
|
+
const parsed = Number.parseInt(portString, 10);
|
|
907
|
+
if (!Number.isNaN(parsed) && parsed > 0) {
|
|
908
|
+
port = parsed;
|
|
909
|
+
}
|
|
910
|
+
}
|
|
911
|
+
return `http://127.0.0.1:${port}`;
|
|
912
|
+
};
|
|
913
|
+
var getRuntime2 = () => {
|
|
914
|
+
if (typeof navigator !== "undefined" && navigator.userAgent === "Cloudflare-Workers") {
|
|
915
|
+
return "cloudflare-workers";
|
|
916
|
+
}
|
|
917
|
+
const proc = _processGlobal2();
|
|
918
|
+
if (!proc) {
|
|
919
|
+
return "browser";
|
|
920
|
+
}
|
|
921
|
+
if (!proc.release?.name) {
|
|
922
|
+
return "edge";
|
|
923
|
+
}
|
|
924
|
+
return "nodejs";
|
|
925
|
+
};
|
|
926
|
+
var getProcessEnvironment = (key) => {
|
|
927
|
+
const proc = _processGlobal2();
|
|
928
|
+
return proc?.env ? proc.env[key] : void 0;
|
|
929
|
+
};
|
|
930
|
+
|
|
494
931
|
// src/client/multi-region/incoming.ts
|
|
495
932
|
var getReceiverSigningKeys = ({
|
|
496
933
|
environment,
|
|
497
934
|
regionFromHeader,
|
|
498
|
-
config
|
|
935
|
+
config,
|
|
936
|
+
devMode
|
|
499
937
|
}) => {
|
|
938
|
+
if (shouldUseDevelopmentMode(devMode, environment)) {
|
|
939
|
+
if (config?.currentSigningKey || config?.nextSigningKey) {
|
|
940
|
+
console.warn(
|
|
941
|
+
`${DEV_PREFIX} Dev mode is active. Ignoring signing keys from config. Set devMode: false to use your own keys.`
|
|
942
|
+
);
|
|
943
|
+
}
|
|
944
|
+
const developmentCreds = getDevelopmentCredentials(environment);
|
|
945
|
+
return {
|
|
946
|
+
currentSigningKey: developmentCreds.currentSigningKey,
|
|
947
|
+
nextSigningKey: developmentCreds.nextSigningKey
|
|
948
|
+
};
|
|
949
|
+
}
|
|
500
950
|
if (config?.currentSigningKey && config.nextSigningKey) {
|
|
501
951
|
return {
|
|
502
952
|
currentSigningKey: config.currentSigningKey,
|
|
@@ -541,8 +991,21 @@ var getClientCredentials = (clientCredentialConfig) => {
|
|
|
541
991
|
};
|
|
542
992
|
var resolveCredentials = ({
|
|
543
993
|
environment,
|
|
544
|
-
config
|
|
994
|
+
config,
|
|
995
|
+
devMode
|
|
545
996
|
}) => {
|
|
997
|
+
if (shouldUseDevelopmentMode(devMode, environment)) {
|
|
998
|
+
if (config?.baseUrl || config?.token) {
|
|
999
|
+
console.warn(
|
|
1000
|
+
`${DEV_PREFIX} Dev mode is active. Ignoring baseUrl/token from config. Set devMode: false to use your own credentials.`
|
|
1001
|
+
);
|
|
1002
|
+
}
|
|
1003
|
+
const developmentCreds = getDevelopmentCredentials(environment);
|
|
1004
|
+
return {
|
|
1005
|
+
baseUrl: developmentCreds.baseUrl,
|
|
1006
|
+
token: developmentCreds.token
|
|
1007
|
+
};
|
|
1008
|
+
}
|
|
546
1009
|
if (config?.baseUrl && config.token) {
|
|
547
1010
|
return {
|
|
548
1011
|
baseUrl: config.baseUrl,
|
|
@@ -595,9 +1058,11 @@ var SignatureError = class extends Error {
|
|
|
595
1058
|
var Receiver = class {
|
|
596
1059
|
currentSigningKey;
|
|
597
1060
|
nextSigningKey;
|
|
1061
|
+
devMode;
|
|
598
1062
|
constructor(config) {
|
|
599
1063
|
this.currentSigningKey = config?.currentSigningKey;
|
|
600
1064
|
this.nextSigningKey = config?.nextSigningKey;
|
|
1065
|
+
this.devMode = config?.devMode;
|
|
601
1066
|
}
|
|
602
1067
|
/**
|
|
603
1068
|
* Verify the signature of a request.
|
|
@@ -616,7 +1081,8 @@ var Receiver = class {
|
|
|
616
1081
|
config: {
|
|
617
1082
|
currentSigningKey: this.currentSigningKey,
|
|
618
1083
|
nextSigningKey: this.nextSigningKey
|
|
619
|
-
}
|
|
1084
|
+
},
|
|
1085
|
+
devMode: this.devMode
|
|
620
1086
|
});
|
|
621
1087
|
if (!signingKeys) {
|
|
622
1088
|
throw new Error(
|
|
@@ -882,12 +1348,14 @@ var HttpClient = class {
|
|
|
882
1348
|
baseUrl;
|
|
883
1349
|
authorization;
|
|
884
1350
|
options;
|
|
1351
|
+
devMode;
|
|
885
1352
|
retry;
|
|
886
1353
|
headers;
|
|
887
1354
|
telemetryHeaders;
|
|
888
1355
|
constructor(config) {
|
|
889
1356
|
this.baseUrl = config.baseUrl.replace(/\/$/, "");
|
|
890
1357
|
this.authorization = config.authorization;
|
|
1358
|
+
this.devMode = config.devMode;
|
|
891
1359
|
this.retry = // eslint-disable-next-line @typescript-eslint/no-unnecessary-condition
|
|
892
1360
|
typeof config.retry === "boolean" && !config.retry ? {
|
|
893
1361
|
attempts: 1,
|
|
@@ -900,6 +1368,7 @@ var HttpClient = class {
|
|
|
900
1368
|
this.telemetryHeaders = config.telemetryHeaders;
|
|
901
1369
|
}
|
|
902
1370
|
async request(request) {
|
|
1371
|
+
await ensureDevelopmentServer(void 0, this.devMode);
|
|
903
1372
|
const { response } = await this.requestWithBackoff(request);
|
|
904
1373
|
if (request.parseResponseAsJson === false) {
|
|
905
1374
|
return void 0;
|
|
@@ -907,6 +1376,7 @@ var HttpClient = class {
|
|
|
907
1376
|
return await response.json();
|
|
908
1377
|
}
|
|
909
1378
|
async *requestStream(request) {
|
|
1379
|
+
await ensureDevelopmentServer(void 0, this.devMode);
|
|
910
1380
|
const { response } = await this.requestWithBackoff(request);
|
|
911
1381
|
if (!response.body) {
|
|
912
1382
|
throw new Error("No response body");
|
|
@@ -1629,7 +2099,7 @@ var UrlGroups = class {
|
|
|
1629
2099
|
};
|
|
1630
2100
|
|
|
1631
2101
|
// version.ts
|
|
1632
|
-
var VERSION = "2.
|
|
2102
|
+
var VERSION = "2.11.1";
|
|
1633
2103
|
|
|
1634
2104
|
// src/client/client.ts
|
|
1635
2105
|
var Client = class {
|
|
@@ -1637,7 +2107,14 @@ var Client = class {
|
|
|
1637
2107
|
token;
|
|
1638
2108
|
constructor(config) {
|
|
1639
2109
|
const environment = getSafeEnvironment();
|
|
1640
|
-
const { baseUrl, token } = getClientCredentials({
|
|
2110
|
+
const { baseUrl, token } = getClientCredentials({
|
|
2111
|
+
environment,
|
|
2112
|
+
config,
|
|
2113
|
+
devMode: config?.devMode
|
|
2114
|
+
});
|
|
2115
|
+
if (shouldUseDevelopmentMode(config?.devMode, environment)) {
|
|
2116
|
+
void ensureDevelopmentServer(environment, config?.devMode);
|
|
2117
|
+
}
|
|
1641
2118
|
const enableTelemetry = environment.UPSTASH_DISABLE_TELEMETRY ? false : config?.enableTelemetry ?? true;
|
|
1642
2119
|
const isCloudflare = typeof caches !== "undefined" && "default" in caches;
|
|
1643
2120
|
const telemetryHeaders = new Headers(
|
|
@@ -1654,7 +2131,8 @@ var Client = class {
|
|
|
1654
2131
|
//@ts-expect-error caused by undici and bunjs type overlap
|
|
1655
2132
|
headers: prefixHeaders(new Headers(config?.headers ?? {})),
|
|
1656
2133
|
//@ts-expect-error caused by undici and bunjs type overlap
|
|
1657
|
-
telemetryHeaders
|
|
2134
|
+
telemetryHeaders,
|
|
2135
|
+
devMode: config?.devMode
|
|
1658
2136
|
});
|
|
1659
2137
|
this.token = token;
|
|
1660
2138
|
}
|
|
@@ -3272,6 +3750,8 @@ export {
|
|
|
3272
3750
|
QStashWorkflowAbort,
|
|
3273
3751
|
formatWorkflowError,
|
|
3274
3752
|
decodeBase64,
|
|
3753
|
+
ensureDevelopmentServer,
|
|
3754
|
+
shouldUseDevelopmentMode,
|
|
3275
3755
|
SignatureError,
|
|
3276
3756
|
Receiver,
|
|
3277
3757
|
FlowControlApi,
|