naro-cli 0.29.0 → 0.30.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +44 -1
- package/dist/{chunk-BAP7PHBF.js → chunk-ITTYPT3A.js} +251 -94
- package/dist/deploy.js +1 -1
- package/dist/functions/deploy.d.ts +7 -0
- package/dist/functions/retry.d.ts +16 -1
- package/dist/index.js +206 -29
- package/dist/{stack-PDV3NPWC.js → stack-DFLT7AVX.js} +41 -22
- package/package.json +8 -9
|
@@ -1749,7 +1749,12 @@ var CAPABILITIES = [
|
|
|
1749
1749
|
id: "function-get",
|
|
1750
1750
|
domain: "functions",
|
|
1751
1751
|
title: "\uD568\uC218 \uC0C1\uC138",
|
|
1752
|
-
|
|
1752
|
+
// `deploy` is a name the rule allows; the batch deploy's static segment
|
|
1753
|
+
// answers that one path for it (functions/deploy/route.ts).
|
|
1754
|
+
routes: [
|
|
1755
|
+
"GET projects/[projectId]/backend/functions/[name]",
|
|
1756
|
+
"GET projects/[projectId]/backend/functions/deploy"
|
|
1757
|
+
],
|
|
1753
1758
|
ui: { kind: "built" },
|
|
1754
1759
|
cli: { kind: "built", commands: ["naro functions versions"] },
|
|
1755
1760
|
mcp: { kind: "built", tools: ["get_function"] }
|
|
@@ -1758,7 +1763,10 @@ var CAPABILITIES = [
|
|
|
1758
1763
|
id: "function-update",
|
|
1759
1764
|
domain: "functions",
|
|
1760
1765
|
title: "\uD568\uC218 verify_jwt \uC124\uC815",
|
|
1761
|
-
routes: [
|
|
1766
|
+
routes: [
|
|
1767
|
+
"PATCH projects/[projectId]/backend/functions/[name]",
|
|
1768
|
+
"PATCH projects/[projectId]/backend/functions/deploy"
|
|
1769
|
+
],
|
|
1762
1770
|
ui: { kind: "built" },
|
|
1763
1771
|
cli: { kind: "built", commands: ["naro functions update"] },
|
|
1764
1772
|
mcp: { kind: "built", tools: ["update_function"] }
|
|
@@ -1767,7 +1775,10 @@ var CAPABILITIES = [
|
|
|
1767
1775
|
id: "function-delete",
|
|
1768
1776
|
domain: "functions",
|
|
1769
1777
|
title: "\uD568\uC218 \uC0AD\uC81C",
|
|
1770
|
-
routes: [
|
|
1778
|
+
routes: [
|
|
1779
|
+
"DELETE projects/[projectId]/backend/functions/[name]",
|
|
1780
|
+
"DELETE projects/[projectId]/backend/functions/deploy"
|
|
1781
|
+
],
|
|
1771
1782
|
ui: { kind: "built" },
|
|
1772
1783
|
cli: { kind: "built", commands: ["naro functions delete"] },
|
|
1773
1784
|
mcp: { kind: "built", tools: ["delete_function"] }
|
|
@@ -1790,10 +1801,14 @@ var CAPABILITIES = [
|
|
|
1790
1801
|
domain: "functions",
|
|
1791
1802
|
title: "\uC800\uC7A5\uB41C \uBC84\uC804 \uBC30\uD3EC",
|
|
1792
1803
|
routes: [
|
|
1793
|
-
"POST projects/[projectId]/backend/functions/[name]/versions/[versionId]/deploy"
|
|
1804
|
+
"POST projects/[projectId]/backend/functions/[name]/versions/[versionId]/deploy",
|
|
1805
|
+
// Many functions' versions in one upload of the project's worker
|
|
1806
|
+
// (design 2026-11-08 G4): naro functions deploy with several names,
|
|
1807
|
+
// deploy_function with `names` (Task 8).
|
|
1808
|
+
"POST projects/[projectId]/backend/functions/deploy"
|
|
1794
1809
|
],
|
|
1795
1810
|
ui: { kind: "built" },
|
|
1796
|
-
// naro functions deploy가 올린 버전을 배포한다(client.functions.deploy).
|
|
1811
|
+
// naro functions deploy가 올린 버전을 배포한다(client.functions.deploy, 여럿이면 deployMany).
|
|
1797
1812
|
cli: { kind: "built" },
|
|
1798
1813
|
// deploy_function이 naro-cli의 deployFunctions로 올린 버전을 배포한다.
|
|
1799
1814
|
mcp: { kind: "built" }
|
|
@@ -2516,7 +2531,7 @@ var DEPLOYMENT_ERROR_CODES = [
|
|
|
2516
2531
|
"USAGE_LIMIT_REACHED",
|
|
2517
2532
|
/** Hobby: another limit (requests, D1, Storage, Functions, Realtime) is reached, so new builds wait (spec 2026-11-07-hobby-any-limit-blocks-build). */
|
|
2518
2533
|
"BUILDS_PAUSED",
|
|
2519
|
-
/** A hobby team has its
|
|
2534
|
+
/** A hobby team has its 20 projects; no project can be added. */
|
|
2520
2535
|
"PROJECT_LIMIT_REACHED",
|
|
2521
2536
|
/** A hobby team has its 1 member; no member or invite can be added. */
|
|
2522
2537
|
"MEMBER_LIMIT_REACHED",
|
|
@@ -2528,6 +2543,8 @@ var DEPLOYMENT_ERROR_CODES = [
|
|
|
2528
2543
|
"PLAN_DOMAINS_NOT_INCLUDED",
|
|
2529
2544
|
/** A hobby project has its 1 custom domain (with its www form); no other can be added. */
|
|
2530
2545
|
"PLAN_DOMAIN_LIMIT_REACHED",
|
|
2546
|
+
/** A hobby team has its 5 projects with a database; no other project can turn its database or backend on. */
|
|
2547
|
+
"BACKEND_LIMIT_REACHED",
|
|
2531
2548
|
/** Named environments (spec 2026-10-18-named-environments §15): the name is not lowercase letters, digits and single hyphens, or is over 20 characters. */
|
|
2532
2549
|
"ENVIRONMENT_NAME_INVALID",
|
|
2533
2550
|
/** `production` and `preview` are reserved names. */
|
|
@@ -20887,7 +20904,7 @@ var LocalBuildExecutor = class {
|
|
|
20887
20904
|
input.rootDirectory
|
|
20888
20905
|
);
|
|
20889
20906
|
await assertAppRootInsideCheckout(checkout, appRoot);
|
|
20890
|
-
const stacks = await import("./stack-
|
|
20907
|
+
const stacks = await import("./stack-DFLT7AVX.js");
|
|
20891
20908
|
const stack = await (this.dependencies.detectStack ?? stacks.detectStack)(
|
|
20892
20909
|
appRoot
|
|
20893
20910
|
).catch(() => null);
|
|
@@ -21332,7 +21349,16 @@ async function errorFromResponse(response, context) {
|
|
|
21332
21349
|
}
|
|
21333
21350
|
|
|
21334
21351
|
// ../../packages/sdk/src/session.ts
|
|
21335
|
-
import {
|
|
21352
|
+
import { randomBytes } from "crypto";
|
|
21353
|
+
import {
|
|
21354
|
+
chmodSync,
|
|
21355
|
+
mkdirSync,
|
|
21356
|
+
readdirSync,
|
|
21357
|
+
readFileSync,
|
|
21358
|
+
renameSync,
|
|
21359
|
+
rmSync,
|
|
21360
|
+
writeFileSync
|
|
21361
|
+
} from "fs";
|
|
21336
21362
|
import { homedir } from "os";
|
|
21337
21363
|
import { join as join18 } from "path";
|
|
21338
21364
|
function credentialsDir(home = homedir()) {
|
|
@@ -21342,10 +21368,18 @@ function credentialsFile(home = homedir()) {
|
|
|
21342
21368
|
return join18(credentialsDir(home), "credentials.json");
|
|
21343
21369
|
}
|
|
21344
21370
|
function saveSession(session, home = homedir()) {
|
|
21345
|
-
|
|
21346
|
-
|
|
21347
|
-
|
|
21348
|
-
|
|
21371
|
+
const dir = credentialsDir(home);
|
|
21372
|
+
const file2 = credentialsFile(home);
|
|
21373
|
+
mkdirSync(dir, { recursive: true, mode: 448 });
|
|
21374
|
+
chmodSync(dir, 448);
|
|
21375
|
+
const tmp = `${file2}.${randomBytes(6).toString("hex")}.tmp`;
|
|
21376
|
+
try {
|
|
21377
|
+
writeFileSync(tmp, JSON.stringify(session, null, 2), { mode: 384 });
|
|
21378
|
+
renameSync(tmp, file2);
|
|
21379
|
+
} catch (error51) {
|
|
21380
|
+
rmSync(tmp, { force: true });
|
|
21381
|
+
throw error51;
|
|
21382
|
+
}
|
|
21349
21383
|
}
|
|
21350
21384
|
function loadStoredSession(home = homedir()) {
|
|
21351
21385
|
try {
|
|
@@ -21357,7 +21391,19 @@ function loadStoredSession(home = homedir()) {
|
|
|
21357
21391
|
}
|
|
21358
21392
|
}
|
|
21359
21393
|
function clearSession(home = homedir()) {
|
|
21394
|
+
const dir = credentialsDir(home);
|
|
21360
21395
|
rmSync(credentialsFile(home), { force: true });
|
|
21396
|
+
let names;
|
|
21397
|
+
try {
|
|
21398
|
+
names = readdirSync(dir);
|
|
21399
|
+
} catch {
|
|
21400
|
+
return;
|
|
21401
|
+
}
|
|
21402
|
+
for (const name of names) {
|
|
21403
|
+
if (/^credentials\.json\.[0-9a-f]+\.tmp$/.test(name)) {
|
|
21404
|
+
rmSync(join18(dir, name), { force: true });
|
|
21405
|
+
}
|
|
21406
|
+
}
|
|
21361
21407
|
}
|
|
21362
21408
|
function isExpired(session, skewSeconds = 60) {
|
|
21363
21409
|
return session.expires_at * 1e3 <= Date.now() + skewSeconds * 1e3;
|
|
@@ -21532,7 +21578,20 @@ async function startCallbackServer() {
|
|
|
21532
21578
|
resolveCode = resolve16;
|
|
21533
21579
|
rejectCode = reject;
|
|
21534
21580
|
});
|
|
21581
|
+
let port = 0;
|
|
21582
|
+
let settled = false;
|
|
21535
21583
|
const server = createServer2((req, res) => {
|
|
21584
|
+
const host = (req.headers.host ?? "").toLowerCase();
|
|
21585
|
+
if (host !== `localhost:${String(port)}` && host !== `127.0.0.1:${String(port)}`) {
|
|
21586
|
+
res.statusCode = 404;
|
|
21587
|
+
res.end("Not found");
|
|
21588
|
+
return;
|
|
21589
|
+
}
|
|
21590
|
+
if (settled) {
|
|
21591
|
+
res.statusCode = 410;
|
|
21592
|
+
res.end("Gone");
|
|
21593
|
+
return;
|
|
21594
|
+
}
|
|
21536
21595
|
const url2 = new URL(req.url ?? "/", "http://localhost");
|
|
21537
21596
|
if (url2.pathname !== "/callback") {
|
|
21538
21597
|
res.statusCode = 404;
|
|
@@ -21543,6 +21602,7 @@ async function startCallbackServer() {
|
|
|
21543
21602
|
const code = url2.searchParams.get("code");
|
|
21544
21603
|
if (error51) {
|
|
21545
21604
|
const description = url2.searchParams.get("error_description");
|
|
21605
|
+
settled = true;
|
|
21546
21606
|
sendPage(res, 200, failurePage(description ?? error51));
|
|
21547
21607
|
rejectCode(new Error(`GitHub authorization failed: ${error51}`));
|
|
21548
21608
|
return;
|
|
@@ -21555,11 +21615,12 @@ async function startCallbackServer() {
|
|
|
21555
21615
|
);
|
|
21556
21616
|
return;
|
|
21557
21617
|
}
|
|
21618
|
+
settled = true;
|
|
21558
21619
|
sendPage(res, 200, successPage());
|
|
21559
21620
|
resolveCode(code);
|
|
21560
21621
|
});
|
|
21561
21622
|
await new Promise((resolve16) => server.listen(0, "127.0.0.1", resolve16));
|
|
21562
|
-
|
|
21623
|
+
port = server.address().port;
|
|
21563
21624
|
return {
|
|
21564
21625
|
port,
|
|
21565
21626
|
waitForCode(timeoutMs) {
|
|
@@ -21765,10 +21826,15 @@ async function resolveAuth(options = {}) {
|
|
|
21765
21826
|
|
|
21766
21827
|
// ../../packages/sdk/src/browser.ts
|
|
21767
21828
|
import { spawn as spawn2 } from "child_process";
|
|
21829
|
+
function browserCommand(url2, platform = process.platform) {
|
|
21830
|
+
if (platform === "darwin") return { command: "open", args: [url2] };
|
|
21831
|
+
if (platform === "win32") {
|
|
21832
|
+
return { command: "rundll32", args: ["url.dll,FileProtocolHandler", url2] };
|
|
21833
|
+
}
|
|
21834
|
+
return { command: "xdg-open", args: [url2] };
|
|
21835
|
+
}
|
|
21768
21836
|
function openBrowser(url2) {
|
|
21769
|
-
const
|
|
21770
|
-
const command = platform === "darwin" ? "open" : platform === "win32" ? "cmd" : "xdg-open";
|
|
21771
|
-
const args = platform === "win32" ? ["/c", "start", "", url2] : [url2];
|
|
21837
|
+
const { command, args } = browserCommand(url2);
|
|
21772
21838
|
const child = spawn2(command, args, { stdio: "ignore", detached: true });
|
|
21773
21839
|
child.on("error", () => {
|
|
21774
21840
|
});
|
|
@@ -24257,6 +24323,28 @@ var FunctionsApi = class {
|
|
|
24257
24323
|
);
|
|
24258
24324
|
return body.function;
|
|
24259
24325
|
}
|
|
24326
|
+
/**
|
|
24327
|
+
* Puts several functions' versions live in one upload of the project's
|
|
24328
|
+
* worker (design 2026-11-08 G4): 1 to 100 `{ name, versionId }`, each
|
|
24329
|
+
* function once. One refusal refuses them all and nothing goes live —
|
|
24330
|
+
* `deploy`'s refusals, `VALIDATION_FAILED` for the list itself (`Send 1 to
|
|
24331
|
+
* 100 versions.`, a name listed twice), and `FUNCTIONS_TOO_LARGE` (413:
|
|
24332
|
+
* the project's live bundles together past 64 MiB). The answer is each
|
|
24333
|
+
* function's new version, in the order asked. Two minutes, or
|
|
24334
|
+
* `options.timeoutMs`; a timeout here does not say whether they went
|
|
24335
|
+
* live — `list` does.
|
|
24336
|
+
*/
|
|
24337
|
+
async deployMany(projectId, versions, options = {}) {
|
|
24338
|
+
return this.client.request(
|
|
24339
|
+
this.path(projectId, "/deploy"),
|
|
24340
|
+
{
|
|
24341
|
+
method: "POST",
|
|
24342
|
+
body: { versions },
|
|
24343
|
+
context: "Deploy functions",
|
|
24344
|
+
timeoutMs: options.timeoutMs ?? PROVISION_TIMEOUT_MS
|
|
24345
|
+
}
|
|
24346
|
+
);
|
|
24347
|
+
}
|
|
24260
24348
|
/**
|
|
24261
24349
|
* Puts a stored version live again: the one numbered `version`, which must
|
|
24262
24350
|
* have been live before (`VERSION_NOT_FOUND` otherwise — put a version that
|
|
@@ -24524,7 +24612,7 @@ function serializeDotenv(vars) {
|
|
|
24524
24612
|
}
|
|
24525
24613
|
|
|
24526
24614
|
// ../../packages/sdk/src/env-scan.ts
|
|
24527
|
-
import { existsSync as existsSync2, readFileSync as readFileSync3, readdirSync, statSync } from "fs";
|
|
24615
|
+
import { existsSync as existsSync2, readFileSync as readFileSync3, readdirSync as readdirSync2, statSync } from "fs";
|
|
24528
24616
|
import { join as join20 } from "path";
|
|
24529
24617
|
var SOURCE_EXTENSIONS3 = /* @__PURE__ */ new Set([
|
|
24530
24618
|
".ts",
|
|
@@ -24573,7 +24661,7 @@ function collect(dir, out) {
|
|
|
24573
24661
|
if (out.length >= MAX_FILES) return;
|
|
24574
24662
|
let entries;
|
|
24575
24663
|
try {
|
|
24576
|
-
entries =
|
|
24664
|
+
entries = readdirSync2(dir, { withFileTypes: true });
|
|
24577
24665
|
} catch {
|
|
24578
24666
|
return;
|
|
24579
24667
|
}
|
|
@@ -33570,12 +33658,32 @@ function generateTypes(tables, options = {}) {
|
|
|
33570
33658
|
// ../../packages/sdk/src/link.ts
|
|
33571
33659
|
import {
|
|
33572
33660
|
existsSync as existsSync4,
|
|
33661
|
+
lstatSync,
|
|
33573
33662
|
mkdirSync as mkdirSync2,
|
|
33574
33663
|
readFileSync as readFileSync5,
|
|
33575
33664
|
rmSync as rmSync2,
|
|
33576
33665
|
writeFileSync as writeFileSync2
|
|
33577
33666
|
} from "fs";
|
|
33578
33667
|
import { join as join22 } from "path";
|
|
33668
|
+
function isSymbolicLink(path) {
|
|
33669
|
+
try {
|
|
33670
|
+
return lstatSync(path).isSymbolicLink();
|
|
33671
|
+
} catch {
|
|
33672
|
+
return false;
|
|
33673
|
+
}
|
|
33674
|
+
}
|
|
33675
|
+
function refuseLink(path, shown, before) {
|
|
33676
|
+
if (isSymbolicLink(path))
|
|
33677
|
+
throw new NaroError(
|
|
33678
|
+
"VALIDATION_FAILED",
|
|
33679
|
+
`${shown} is a symbolic link. Remove it before ${before}.`
|
|
33680
|
+
);
|
|
33681
|
+
}
|
|
33682
|
+
function assertProjectLinkWritable(dir, before = "linking the project") {
|
|
33683
|
+
refuseLink(linkDir(dir), ".naro", before);
|
|
33684
|
+
refuseLink(linkFile(dir), ".naro/project.json", before);
|
|
33685
|
+
refuseLink(join22(linkDir(dir), "README.txt"), ".naro/README.txt", before);
|
|
33686
|
+
}
|
|
33579
33687
|
function linkDir(dir) {
|
|
33580
33688
|
return join22(dir, ".naro");
|
|
33581
33689
|
}
|
|
@@ -33598,6 +33706,7 @@ function readProjectLink(dir) {
|
|
|
33598
33706
|
}
|
|
33599
33707
|
}
|
|
33600
33708
|
function writeProjectLink(dir, link) {
|
|
33709
|
+
assertProjectLinkWritable(dir);
|
|
33601
33710
|
mkdirSync2(linkDir(dir), { recursive: true });
|
|
33602
33711
|
writeFileSync2(linkFile(dir), `${JSON.stringify(link, null, 2)}
|
|
33603
33712
|
`);
|
|
@@ -33613,6 +33722,7 @@ function removeProjectLink(dir) {
|
|
|
33613
33722
|
}
|
|
33614
33723
|
function ensureGitignoreHasNaro(dir) {
|
|
33615
33724
|
const gitignorePath = join22(dir, ".gitignore");
|
|
33725
|
+
if (isSymbolicLink(gitignorePath)) return false;
|
|
33616
33726
|
const hasGitignore = existsSync4(gitignorePath);
|
|
33617
33727
|
if (!hasGitignore && !existsSync4(join22(dir, ".git"))) return false;
|
|
33618
33728
|
const current = hasGitignore ? readFileSync5(gitignorePath, "utf8") : "";
|
|
@@ -33953,7 +34063,7 @@ async function repairLedger(client, projectId, key, status, ledgerIsEmpty) {
|
|
|
33953
34063
|
}
|
|
33954
34064
|
|
|
33955
34065
|
// ../../packages/sdk/src/migrations.ts
|
|
33956
|
-
import { existsSync as existsSync5, readdirSync as
|
|
34066
|
+
import { existsSync as existsSync5, readdirSync as readdirSync3 } from "fs";
|
|
33957
34067
|
import { resolve as resolve9 } from "path";
|
|
33958
34068
|
function resolveMigrationsDir(input) {
|
|
33959
34069
|
if (input.dir) return resolve9(input.baseDir, input.dir);
|
|
@@ -33973,7 +34083,7 @@ function sortMigrationNames(names) {
|
|
|
33973
34083
|
function listMigrationFiles(dir) {
|
|
33974
34084
|
if (!existsSync5(dir)) return [];
|
|
33975
34085
|
return sortMigrationNames(
|
|
33976
|
-
|
|
34086
|
+
readdirSync3(dir, { withFileTypes: true }).filter((entry) => entry.isFile() && entry.name.endsWith(".sql")).map((entry) => entry.name)
|
|
33977
34087
|
);
|
|
33978
34088
|
}
|
|
33979
34089
|
function nextMigrationFileName(existing, name) {
|
|
@@ -35416,8 +35526,6 @@ var BUNDLE_MESSAGES = {
|
|
|
35416
35526
|
wasm: (file2) => `WebAssembly modules are not supported in functions yet: ${file2}.`,
|
|
35417
35527
|
naroJsMissing: 'Cannot find "naro-js/functions". Install naro-js 0.7.0 or later: npm install naro-js@latest.',
|
|
35418
35528
|
tooLarge: (name, size, inputs) => `Function ${name} bundles to ${bytes(size)} bytes; the limit is 67,108,864 (64 MiB). The biggest inputs: ${inputs}.`,
|
|
35419
|
-
// Rounded up: a size over the limit never reads as the limit (10.0 MB).
|
|
35420
|
-
tooLargeCompressed: (name, size) => `Function ${name} is ${(Math.ceil(size / 1048576 * 10) / 10).toFixed(1)} MB after compression; Cloudflare accepts 10 MB.`,
|
|
35421
35529
|
otherBundle: (name, text3, location2) => `Function ${name} did not bundle: ${text3}${location2 ? ` (${location2})` : ""}`,
|
|
35422
35530
|
noHandler: (name) => `Function ${name} did not register a handler. Call Deno.serve(handler) or export default { fetch }.`,
|
|
35423
35531
|
failedToStart: (name, line) => `Function ${name} failed to start: ${line}`,
|
|
@@ -35427,12 +35535,11 @@ var BUNDLE_MESSAGES = {
|
|
|
35427
35535
|
};
|
|
35428
35536
|
|
|
35429
35537
|
// ../../packages/functions-bundler/src/discover.ts
|
|
35430
|
-
import { existsSync as existsSync7, readdirSync as
|
|
35538
|
+
import { existsSync as existsSync7, readdirSync as readdirSync4, readFileSync as readFileSync8, statSync as statSync2 } from "fs";
|
|
35431
35539
|
import { join as join27, relative as relative8, resolve as resolve12, sep as sep6 } from "path";
|
|
35432
35540
|
|
|
35433
35541
|
// ../../packages/functions-bundler/src/limits.ts
|
|
35434
35542
|
var FUNCTION_BUNDLE_MAX_BYTES = 67108864;
|
|
35435
|
-
var FUNCTION_COMPRESSED_BUNDLE_MAX_BYTES = 10485760;
|
|
35436
35543
|
var ENTRY_FILES = [
|
|
35437
35544
|
"index.ts",
|
|
35438
35545
|
"index.js",
|
|
@@ -35459,7 +35566,7 @@ function functionsFolder(options) {
|
|
|
35459
35566
|
function listFunctionNames(folder) {
|
|
35460
35567
|
let entries;
|
|
35461
35568
|
try {
|
|
35462
|
-
entries =
|
|
35569
|
+
entries = readdirSync4(folder.dir, { withFileTypes: true });
|
|
35463
35570
|
} catch {
|
|
35464
35571
|
if (!folder.explicit && existsSync7(join27(folder.root, "supabase", "functions")))
|
|
35465
35572
|
throw new FunctionBundleError(
|
|
@@ -36192,25 +36299,18 @@ function denoImportsPlugin(options) {
|
|
|
36192
36299
|
// ../../packages/functions-bundler/src/bundle.ts
|
|
36193
36300
|
import { createHash as createHash4 } from "crypto";
|
|
36194
36301
|
import { join as join30, relative as relative10, sep as sep9 } from "path";
|
|
36195
|
-
import { gzipSync } from "zlib";
|
|
36196
36302
|
|
|
36197
36303
|
// ../../packages/functions-runtime/dist/index.js
|
|
36198
36304
|
var NARO_SHIM_MODULE = "naro-shim.js";
|
|
36199
36305
|
var NARO_USER_MODULE = "user.js";
|
|
36200
36306
|
var NARO_BOOT_MODULE = "naro-boot.js";
|
|
36201
|
-
var NARO_ENTRY_SOURCE = '// src/naro-entry.ts\nimport "./naro-shim.js";\nimport * as user from "./user.js";\n\n// src/context.ts\nvar CONTEXT_HEADER = "x-naro-context";\nvar MAX_CONTEXT_LENGTH = 4096;\nvar BASE64URL = /^[A-Za-z0-9_-]+$/;\nvar TRACE_ID_RE = /^[A-Za-z0-9-]{1,64}$/;\nvar MAX_HOP = 1e3;\nvar ROLES = /* @__PURE__ */ new Set([\n "anon",\n "authenticated",\n "service"\n]);\nfunction fieldsOf(value) {\n if (typeof value !== "object" || value === null || Array.isArray(value))\n return null;\n return value;\n}\nfunction own(fields, key) {\n return Object.hasOwn(fields, key) ? fields[key] : void 0;\n}\nfunction nonEmptyText(value) {\n return typeof value === "string" && value !== "";\n}\nvar MAX_USER_ID_LENGTH = 256;\nfunction headerSafeId(value) {\n if (!nonEmptyText(value) || value.length > MAX_USER_ID_LENGTH) return false;\n if (value.trim() !== value) return false;\n for (let index = 0; index < value.length; index += 1) {\n const code = value.charCodeAt(index);\n if (code < 32 || code >= 127 && code <= 159) return false;\n if (code >= 55296 && code <= 57343) {\n const next = value.charCodeAt(index + 1);\n if (code >= 56320 || !(next >= 56320 && next <= 57343)) return false;\n index += 1;\n }\n }\n return true;\n}\nfunction userOf(value) {\n const fields = fieldsOf(value);\n if (fields === null) return null;\n const id = own(fields, "id");\n const email = own(fields, "email");\n const emailVerified = own(fields, "emailVerified");\n if (!headerSafeId(id)) return null;\n if (email !== null && typeof email !== "string") return null;\n if (typeof emailVerified !== "boolean") return null;\n return { id, email, emailVerified };\n}\nfunction contextOf(value, projectId, name) {\n const fields = fieldsOf(value);\n if (fields === null) return null;\n if (own(fields, "v") !== 1) return null;\n if (own(fields, "projectId") !== projectId) return null;\n if (own(fields, "function") !== name) return null;\n const traceId = own(fields, "traceId");\n if (typeof traceId !== "string" || !TRACE_ID_RE.test(traceId)) return null;\n const hop = own(fields, "hop");\n if (typeof hop !== "number" || !Number.isInteger(hop) || hop < 0 || hop > MAX_HOP)\n return null;\n const role = own(fields, "role");\n if (role !== null && !ROLES.has(role)) return null;\n const sentUser = own(fields, "user");\n let user2 = null;\n if (role === "authenticated") {\n user2 = userOf(sentUser);\n if (user2 === null) return null;\n } else if (sentUser !== null) return null;\n return {\n v: 1,\n projectId,\n function: name,\n role,\n user: user2,\n traceId,\n hop\n };\n}\nfunction bytesOf(value) {\n if (!BASE64URL.test(value) || value.length % 4 === 1) return null;\n const base64 = value.replace(/-/g, "+").replace(/_/g, "/");\n let binary;\n try {\n binary = atob(base64 + "=".repeat((4 - base64.length % 4) % 4));\n } catch {\n return null;\n }\n const again = btoa(binary).replace(/\\+/g, "-").replace(/\\//g, "_").replace(/=+$/, "");\n if (again !== value) return null;\n return Uint8Array.from(binary, (char) => char.charCodeAt(0));\n}\nfunction decodeContext(value, bindings) {\n const projectId = bindings.NARO_PROJECT_ID;\n const name = bindings.NARO_FUNCTION_NAME;\n if (!nonEmptyText(projectId) || !nonEmptyText(name)) return null;\n if (typeof value !== "string" || value.length > MAX_CONTEXT_LENGTH)\n return null;\n const bytes = bytesOf(value);\n if (bytes === null) return null;\n let parsed;\n try {\n parsed = JSON.parse(\n new TextDecoder("utf-8", { fatal: true, ignoreBOM: true }).decode(bytes)\n );\n } catch {\n return null;\n }\n return contextOf(parsed, projectId, name);\n}\n\n// src/rejections.ts\nfunction loggedRejection(promise, name) {\n return Promise.resolve(promise).then(\n () => void 0,\n (error) => {\n console.error(`naro functions: ${name} waitUntil rejected`, error);\n }\n );\n}\n\n// src/respond.ts\nvar FUNCTION_EXPOSE_HEADERS = [\n "x-relay-error",\n "x-naro-trace-id",\n "retry-after",\n "x-retry-after"\n];\nvar WRAPPER_ERRORS = {\n FUNCTION_ERROR: "The function threw an error. See `naro functions logs {name}`.",\n FUNCTION_NO_HANDLER: "The function has no handler. Call Deno.serve(handler) or export default { fetch }.",\n FUNCTION_MISROUTED: "This function was reached without the Naro gateway."\n};\nfunction appendExposeHeaders(value) {\n const listed = (value ?? "").split(",").map((part) => part.trim()).filter((part) => part !== "");\n const seen = new Set(listed.map((part) => part.toLowerCase()));\n for (const name of FUNCTION_EXPOSE_HEADERS)\n if (!seen.has(name)) listed.push(name);\n return listed.join(", ");\n}\nfunction wrapperError(code, name, traceId) {\n const headers = new Headers({\n "access-control-allow-origin": "*",\n "access-control-expose-headers": appendExposeHeaders(null),\n "cache-control": "no-store"\n });\n if (traceId !== null) headers.set("x-naro-trace-id", traceId);\n return Response.json(\n {\n data: null,\n error: {\n code,\n // A function, not a string: `$&` in a name stays as it is.\n message: WRAPPER_ERRORS[code].replace("{name}", () => name)\n }\n },\n { status: 500, headers }\n );\n}\nfunction withFunctionHeaders(response, traceId) {\n if (response.status === 101) return response;\n const out = new Response(response.body, response);\n const headers = out.headers;\n headers.delete("x-relay-error");\n if (!headers.has("access-control-allow-origin"))\n headers.set("access-control-allow-origin", "*");\n headers.set(\n "access-control-expose-headers",\n appendExposeHeaders(headers.get("access-control-expose-headers"))\n );\n headers.set("x-naro-trace-id", traceId);\n return out;\n}\n\n// src/runtime-state.ts\nvar RUNTIME_KEY = /* @__PURE__ */ Symbol.for("naro.functions.runtime");\nvar CONTEXT_KEY = /* @__PURE__ */ Symbol.for("naro.functions.context");\nvar SHIM_FIRST = "The Naro functions shim must be imported before the wrapper.";\nfunction globals() {\n return globalThis;\n}\nfunction runtimeState() {\n const state2 = globals()[RUNTIME_KEY];\n if (state2 === void 0) throw new Error(SHIM_FIRST);\n return state2;\n}\nfunction callContexts() {\n const contexts2 = globals()[CONTEXT_KEY];\n if (contexts2 === void 0) throw new Error(SHIM_FIRST);\n return contexts2;\n}\n\n// src/naro-entry.ts\nvar state = runtimeState();\nvar contexts = callContexts();\nasync function serveWithInfo(registered, request) {\n let complete;\n const info = {\n remoteAddr: {\n transport: "tcp",\n hostname: request.headers.get("cf-connecting-ip") ?? "0.0.0.0",\n port: 0\n },\n completed: new Promise((resolve) => {\n complete = resolve;\n })\n };\n try {\n return await registered(request, info);\n } finally {\n complete();\n }\n}\nfunction chooseHandler() {\n const registered = state.handler;\n if (registered !== null)\n return {\n handler: async (request) => serveWithInfo(registered, request),\n onError: state.onError\n };\n const exported = user.default;\n if (typeof exported === "object" && exported !== null) {\n const fetchHandler = exported.fetch;\n if (typeof fetchHandler === "function")\n return {\n handler: async (request, env, ctx) => fetchHandler.call(exported, request, env, ctx),\n onError: null\n };\n }\n if (typeof exported === "function") {\n const prototype = exported.prototype;\n if (typeof prototype === "object" && prototype !== null && typeof prototype.fetch === "function")\n return {\n handler: async (request, env, ctx) => new exported(ctx, env).fetch(request),\n onError: null\n };\n return {\n handler: async (request, env, ctx) => exported(request, env, ctx),\n onError: null\n };\n }\n return null;\n}\nfunction callerRequest(request, context) {\n const headers = new Headers();\n for (const [name, value] of request.headers)\n if (!name.startsWith("x-naro-")) headers.append(name, value);\n if (context.role !== null) headers.set("x-naro-role", context.role);\n if (context.user !== null) headers.set("x-naro-user-id", context.user.id);\n headers.set("x-naro-trace-id", context.traceId);\n return new Request(request, { headers });\n}\nfunction logWaitUntilRejections(ctx, name) {\n const waitUntil = ctx.waitUntil.bind(ctx);\n try {\n Object.defineProperty(ctx, "waitUntil", {\n configurable: true,\n writable: true,\n value: (promise) => waitUntil(loggedRejection(promise, name))\n });\n } catch {\n }\n}\nfunction textOf(value) {\n return typeof value === "string" ? value : "";\n}\nfunction responseOf(value, what) {\n if (value instanceof Response) return value;\n throw new TypeError(`${what} did not return a Response.`);\n}\nasync function answerOf(chosen, name, request, env, ctx) {\n try {\n return responseOf(await chosen.handler(request, env, ctx), "The handler");\n } catch (error) {\n if (chosen.onError === null) {\n console.error(`naro functions: ${name} threw`, error);\n return null;\n }\n try {\n return responseOf(await chosen.onError(error), "onError");\n } catch (failed) {\n console.error(`naro functions: ${name} threw`, error, failed);\n return null;\n }\n }\n}\nasync function answerCall(request, env, ctx, seen) {\n const name = textOf(env.NARO_FUNCTION_NAME);\n const context = decodeContext(request.headers.get(CONTEXT_HEADER), env);\n if (context === null) return wrapperError("FUNCTION_MISROUTED", name, null);\n let forwarded;\n try {\n forwarded = callerRequest(request, context);\n } catch (error) {\n console.error(`naro functions: ${name} misrouted`, error);\n return wrapperError("FUNCTION_MISROUTED", name, null);\n }\n seen.traceId = context.traceId;\n const call = {\n role: context.role,\n user: context.user,\n traceId: context.traceId\n };\n contexts.set(forwarded, call);\n const chosen = chooseHandler();\n if (chosen === null)\n return wrapperError("FUNCTION_NO_HANDLER", name, context.traceId);\n logWaitUntilRejections(ctx, name);\n const answer = await state.requests.run(\n { ctx, hop: context.hop, traceId: context.traceId, call },\n () => answerOf(chosen, name, forwarded, env, ctx)\n );\n if (answer === null)\n return wrapperError("FUNCTION_ERROR", name, context.traceId);\n try {\n return withFunctionHeaders(answer, context.traceId);\n } catch (error) {\n console.error(\n `naro functions: ${name} answered with a response that cannot be sent`,\n error\n );\n return wrapperError("FUNCTION_ERROR", name, context.traceId);\n }\n}\nvar naro_entry_default = {\n async fetch(request, env, ctx) {\n const seen = { traceId: null };\n let answer;\n try {\n answer = await answerCall(request, env, ctx, seen);\n } catch (error) {\n return state.lastResort(error, seen.traceId);\n }\n if (state.isResponse(answer)) return answer;\n return state.lastResort(\n new TypeError("The wrapper\'s answer is not a Response."),\n seen.traceId\n );\n }\n};\nexport {\n naro_entry_default as default\n};\n';
|
|
36202
|
-
var NARO_SHIM_SOURCE = '// src/naro-shim.ts\nimport { AsyncLocalStorage } from "node:async_hooks";\nimport { env } from "cloudflare:workers";\n\n// src/hosts.ts\nfunction bareHost(host) {\n return host.toLowerCase().replace(/\\.+$/, "");\n}\nfunction isNaroHost(hostname, rootDomain2, naroUrl2) {\n const host = bareHost(hostname);\n if (host === "") return false;\n const root = rootDomain2.toLowerCase().replace(/^\\.+|\\.+$/g, "");\n if (root !== "" && host.endsWith(`.${root}`)) return true;\n if (naroUrl2 === "") return false;\n try {\n return bareHost(new URL(naroUrl2).hostname) === host;\n } catch {\n return false;\n }\n}\n\n// src/redact.ts\nvar MIN_REDACTED_LENGTH = 8;\nvar REDACTED = "[redacted]";\nfunction isSecretBinding(name) {\n return name === "NARO_SERVICE_KEY" || !name.startsWith("NARO_") && name !== "DB";\n}\nfunction secretValues(bindings2) {\n const values = /* @__PURE__ */ new Set();\n for (const [name, value] of Object.entries(bindings2)) {\n if (typeof value !== "string" || value.length < MIN_REDACTED_LENGTH)\n continue;\n if (!isSecretBinding(name)) continue;\n values.add(value);\n values.add(JSON.stringify(value).slice(1, -1));\n }\n return [...values].toSorted(\n (left, right) => right.length - left.length || (left < right ? -1 : left > right ? 1 : 0)\n );\n}\nfunction redactText(text, secrets2) {\n const spans = [];\n for (const secret of secrets2) {\n if (secret === "") continue;\n let last;\n for (let at = text.indexOf(secret); at !== -1; at = text.indexOf(secret, at + 1)) {\n if (last !== void 0 && at <= last[1]) last[1] = at + secret.length;\n else spans.push(last = [at, at + secret.length]);\n }\n }\n if (spans.length === 0) return text;\n const ordered = spans.toSorted((left, right) => left[0] - right[0]);\n let out = "";\n let kept = 0;\n let [start, end] = ordered[0];\n for (const [nextStart, nextEnd] of ordered) {\n if (nextStart <= end) {\n end = Math.max(end, nextEnd);\n continue;\n }\n out += text.slice(kept, start) + REDACTED;\n kept = end;\n start = nextStart;\n end = nextEnd;\n }\n return out + text.slice(kept, start) + REDACTED + text.slice(end);\n}\nfunction stringOf(value) {\n try {\n return String(value);\n } catch {\n return void 0;\n }\n}\nfunction withHead(stack, head) {\n if (stack === head || stack.startsWith(`${head}\n`)) return stack;\n const frames = stack.indexOf("\\n at ");\n return frames === -1 ? `${head}\n${stack}` : `${head}${stack.slice(frames)}`;\n}\nfunction redactError(error, secrets2) {\n const stack = typeof error.stack === "string" ? error.stack : `${error.name}: ${error.message}`;\n const head = stringOf(error);\n let json;\n try {\n json = JSON.stringify(error);\n } catch {\n json = void 0;\n }\n const cleanStack = redactText(stack, secrets2);\n const cleanHead = head === void 0 ? void 0 : redactText(head, secrets2);\n const cleanJson = json === void 0 ? void 0 : redactText(json, secrets2);\n if (cleanStack === stack && head !== void 0 && cleanHead === head && json !== void 0 && cleanJson === json)\n return error;\n const text = cleanHead === void 0 ? cleanStack : withHead(cleanStack, cleanHead);\n return cleanJson === void 0 || cleanJson === "{}" ? text : `${text}\n${cleanJson}`;\n}\nfunction isPlain(value) {\n if (Array.isArray(value)) return true;\n const prototype = Object.getPrototypeOf(value);\n return prototype === Object.prototype || prototype === null;\n}\nfunction redactArg(arg, secrets2) {\n if (typeof arg === "string") return redactText(arg, secrets2);\n if (arg === null || typeof arg !== "object" && typeof arg !== "function")\n return arg;\n try {\n if (arg instanceof Error) return redactError(arg, secrets2);\n let json;\n try {\n json = JSON.stringify(arg);\n } catch {\n return redactText(String(arg), secrets2);\n }\n if (json !== void 0) {\n const clean2 = redactText(json, secrets2);\n if (clean2 !== json) return clean2;\n }\n if (isPlain(arg)) return arg;\n const text = stringOf(arg);\n if (text === void 0) return arg;\n const clean = redactText(text, secrets2);\n return clean === text ? arg : clean;\n } catch {\n return REDACTED;\n }\n}\nfunction redactArgs(args, secrets2) {\n if (secrets2.length === 0) return [...args];\n return args.map((arg) => redactArg(arg, secrets2));\n}\n\n// src/rejections.ts\nfunction loggedRejection(promise, name) {\n return Promise.resolve(promise).then(\n () => void 0,\n (error) => {\n console.error(`naro functions: ${name} waitUntil rejected`, error);\n }\n );\n}\n\n// src/respond.ts\nvar FUNCTION_EXPOSE_HEADERS = [\n "x-relay-error",\n "x-naro-trace-id",\n "retry-after",\n "x-retry-after"\n];\nvar WRAPPER_ERRORS = {\n FUNCTION_ERROR: "The function threw an error. See `naro functions logs {name}`.",\n FUNCTION_NO_HANDLER: "The function has no handler. Call Deno.serve(handler) or export default { fetch }.",\n FUNCTION_MISROUTED: "This function was reached without the Naro gateway."\n};\nfunction appendExposeHeaders(value) {\n const listed = (value ?? "").split(",").map((part) => part.trim()).filter((part) => part !== "");\n const seen = new Set(listed.map((part) => part.toLowerCase()));\n for (const name of FUNCTION_EXPOSE_HEADERS)\n if (!seen.has(name)) listed.push(name);\n return listed.join(", ");\n}\n\n// src/runtime-state.ts\nvar RUNTIME_KEY = /* @__PURE__ */ Symbol.for("naro.functions.runtime");\nvar CONTEXT_KEY = /* @__PURE__ */ Symbol.for("naro.functions.context");\n\n// src/naro-shim.ts\nvar bindings = env;\nvar globals = globalThis;\nvar functionName = typeof bindings.NARO_FUNCTION_NAME === "string" ? bindings.NARO_FUNCTION_NAME : "";\nvar secrets = secretValues(bindings);\nfor (const level of ["log", "info", "warn", "error", "debug"]) {\n const original = console[level].bind(console);\n console[level] = (...args) => {\n original(...redactArgs(args, secrets));\n };\n}\nvar logError = console.error;\nvar NativeResponse = Response;\nvar bareRecord = Object.create;\nvar failedBody = JSON.stringify({\n data: null,\n error: {\n code: "FUNCTION_ERROR",\n message: WRAPPER_ERRORS.FUNCTION_ERROR.replace(\n "{name}",\n () => functionName\n )\n }\n});\nvar exposedHeaders = appendExposeHeaders(null);\nfunction lastResort(error, traceId) {\n try {\n logError(`naro functions: ${functionName} threw`, error);\n } catch {\n }\n const headers = bareRecord(null);\n headers["content-type"] = "application/json";\n headers["access-control-allow-origin"] = "*";\n headers["access-control-expose-headers"] = exposedHeaders;\n headers["cache-control"] = "no-store";\n if (traceId !== null) headers["x-naro-trace-id"] = traceId;\n const init = bareRecord(null);\n init.status = 500;\n init.headers = headers;\n return new NativeResponse(failedBody, init);\n}\nvar reflectApply = Reflect.apply;\nvar responseStatus = Object.getOwnPropertyDescriptor(\n NativeResponse.prototype,\n "status"\n)?.get;\nfunction isResponse(value) {\n if (typeof value !== "object" || value === null) return false;\n try {\n if (responseStatus === void 0) return value instanceof NativeResponse;\n reflectApply(responseStatus, value, []);\n return true;\n } catch {\n return false;\n }\n}\nvar state = {\n handler: null,\n onError: null,\n requests: new AsyncLocalStorage(),\n lastResort,\n isResponse\n};\nglobals[RUNTIME_KEY] = state;\nglobals[CONTEXT_KEY] = /* @__PURE__ */ new WeakMap();\nvar rootDomain = typeof bindings.NARO_ROOT_DOMAIN === "string" ? bindings.NARO_ROOT_DOMAIN : "";\nvar naroUrl = typeof bindings.NARO_URL === "string" ? bindings.NARO_URL : "";\nvar originalFetch = globalThis.fetch.bind(globalThis);\nasync function naroFetch(input, init) {\n const store = state.requests.getStore();\n if (store === void 0) return originalFetch(input, init);\n let host;\n try {\n host = new URL(input instanceof Request ? input.url : String(input)).hostname;\n } catch {\n return originalFetch(input, init);\n }\n if (!isNaroHost(host, rootDomain, naroUrl)) return originalFetch(input, init);\n const request = new Request(input, init);\n const headers = new Headers(request.headers);\n headers.set("x-naro-fn-hop", String(store.hop + 1));\n headers.set("x-naro-trace-id", store.traceId);\n return originalFetch(new Request(request, { headers }));\n}\nglobalThis.fetch = naroFetch;\nvar addListener = EventTarget.prototype.addEventListener;\nvar removeListener = EventTarget.prototype.removeEventListener;\nvar standIns = /* @__PURE__ */ new WeakMap();\nfunction standInFor(socket, listener, store) {\n let listeners = standIns.get(socket);\n if (listeners === void 0)\n standIns.set(socket, listeners = /* @__PURE__ */ new WeakMap());\n let standIn = listeners.get(listener);\n if (standIn === void 0) {\n standIn = function(event) {\n state.requests.run(\n store,\n () => typeof listener === "function" ? Reflect.apply(listener, this, [event]) : listener.handleEvent(event)\n );\n };\n listeners.set(listener, standIn);\n }\n return standIn;\n}\nObject.defineProperties(WebSocket.prototype, {\n addEventListener: {\n configurable: true,\n writable: true,\n value(type, listener, ...rest) {\n const store = state.requests.getStore();\n const runs = store !== void 0 && listener !== null && (typeof listener === "function" || typeof listener === "object");\n return Reflect.apply(addListener, this, [\n type,\n runs ? standInFor(this, listener, store) : listener,\n ...rest\n ]);\n }\n },\n removeEventListener: {\n configurable: true,\n writable: true,\n value(type, listener, ...rest) {\n const standIn = typeof listener === "function" || typeof listener === "object" && listener !== null ? standIns.get(this)?.get(listener) : void 0;\n return Reflect.apply(removeListener, this, [\n type,\n standIn ?? listener,\n ...rest\n ]);\n }\n }\n});\nvar ON_EVENTS = ["onopen", "onmessage", "onclose", "onerror"];\nvar onHandlers = /* @__PURE__ */ new WeakMap();\nfunction nativeAccessor(target, name) {\n for (let at = target; at !== null; at = Object.getPrototypeOf(at)) {\n const descriptor = Object.getOwnPropertyDescriptor(at, name);\n if (descriptor === void 0) continue;\n return descriptor.get !== void 0 && descriptor.set !== void 0 ? { get: descriptor.get, set: descriptor.set } : void 0;\n }\n return void 0;\n}\nfor (const name of ON_EVENTS) {\n const native = nativeAccessor(WebSocket.prototype, name);\n Object.defineProperty(WebSocket.prototype, name, {\n configurable: true,\n enumerable: true,\n get() {\n const set = onHandlers.get(this)?.get(name);\n if (set === void 0)\n return native === void 0 ? void 0 : Reflect.apply(native.get, this, []);\n return state.requests.getStore() === void 0 ? set.standIn : set.handler;\n },\n set(handler) {\n const store = state.requests.getStore();\n const standIn = store !== void 0 && typeof handler === "function" ? standInFor(this, handler, store) : handler;\n let handlers = onHandlers.get(this);\n if (handlers === void 0) onHandlers.set(this, handlers = /* @__PURE__ */ new Map());\n handlers.set(name, { handler, standIn });\n if (native !== void 0) Reflect.apply(native.set, this, [standIn]);\n }\n });\n}\nfunction serve(first, second) {\n const options = typeof first === "function" ? {} : first ?? {};\n const handler = typeof first === "function" ? first : second ?? options.handler;\n if (typeof handler !== "function")\n throw new TypeError("Deno.serve needs a handler.");\n state.handler = handler;\n state.onError = typeof options.onError === "function" ? options.onError : null;\n return {\n finished: new Promise(() => {\n }),\n shutdown: () => Promise.resolve()\n };\n}\nfunction textBindings() {\n const out = {};\n for (const [name, value] of Object.entries(bindings))\n if (typeof value === "string") out[name] = value;\n return out;\n}\nvar build = Object.freeze({\n os: "linux",\n arch: "x86_64",\n target: "x86_64-unknown-linux-gnu",\n vendor: "unknown",\n env: "gnu"\n});\nvar version = Object.freeze({\n deno: "2.1.4",\n v8: "13.0.245.12",\n typescript: "5.6.2"\n});\nvar DENO_ERROR_NAMES = [\n "NotFound",\n "PermissionDenied",\n "ConnectionRefused",\n "ConnectionReset",\n "ConnectionAborted",\n "NotConnected",\n "AddrInUse",\n "AddrNotAvailable",\n "BrokenPipe",\n "AlreadyExists",\n "InvalidData",\n "TimedOut",\n "Interrupted",\n "WriteZero",\n "WouldBlock",\n "UnexpectedEof",\n "BadResource",\n "Http",\n "Busy",\n "NotSupported",\n "FilesystemLoop",\n "IsADirectory",\n "NetworkUnreachable",\n "NotADirectory",\n "NotCapable"\n];\nfunction denoError(name) {\n const made = { [name]: class extends Error {\n } }[name];\n Object.defineProperty(made.prototype, "name", {\n configurable: true,\n writable: true,\n value: name\n });\n return made;\n}\nvar errors = Object.freeze(\n Object.fromEntries(DENO_ERROR_NAMES.map((name) => [name, denoError(name)]))\n);\nvar deno = {\n serve,\n env: {\n get: (name) => {\n const value = bindings[name];\n return typeof value === "string" ? value : void 0;\n },\n has: (name) => typeof bindings[name] === "string",\n toObject: () => textBindings(),\n set: () => {\n throw new Error("Deno.env.set is not available on Naro Functions.");\n },\n delete: () => {\n throw new Error("Deno.env.delete is not available on Naro Functions.");\n }\n },\n build,\n version,\n errors\n};\nvar PROBES = /* @__PURE__ */ new Set(["then", "toJSON"]);\nglobals.Deno = new Proxy(deno, {\n get(target, property) {\n if (typeof property === "symbol" || PROBES.has(property)) return void 0;\n if (Object.hasOwn(target, property)) return target[property];\n return () => {\n throw new Error(`Deno.${property} is not available on Naro Functions.`);\n };\n }\n});\nglobals.EdgeRuntime = {\n waitUntil(promise) {\n const logged = loggedRejection(promise, functionName);\n state.requests.getStore()?.ctx.waitUntil(logged);\n return promise;\n }\n};\naddEventListener("unhandledrejection", (event) => {\n event.preventDefault();\n console.error(\n `naro functions: ${functionName} unhandled rejection`,\n event.reason\n );\n});\n';
|
|
36203
|
-
var NARO_BOOT_SOURCE = '// src/naro-boot.ts\nimport "./naro-shim.js";\nimport * as user from "./user.js";\n\n// src/runtime-state.ts\nvar RUNTIME_KEY = /* @__PURE__ */ Symbol.for("naro.functions.runtime");\nvar SHIM_FIRST = "The Naro functions shim must be imported before the wrapper.";\nfunction globals() {\n return globalThis;\n}\nfunction runtimeState() {\n const state2 = globals()[RUNTIME_KEY];\n if (state2 === void 0) throw new Error(SHIM_FIRST);\n return state2;\n}\n\n// src/naro-boot.ts\nvar BOOT_PATH = "/__naro/boot";\nvar state = runtimeState();\nfunction hasHandler(exported) {\n if (state.handler !== null) return true;\n if (typeof exported === "function") return true;\n return typeof exported === "object" && exported !== null && typeof exported.fetch === "function";\n}\nvar naro_boot_default = {\n fetch(request) {\n if (new URL(request.url).pathname !== BOOT_PATH)\n return new Response("Not found", { status: 404 });\n return Response.json({ handler: hasHandler(user.default) });\n }\n};\nexport {\n naro_boot_default as default\n};\n';
|
|
36307
|
+
var NARO_SHIM_SOURCE = '// src/naro-shim.ts\nimport { AsyncLocalStorage } from "node:async_hooks";\nimport { env } from "cloudflare:workers";\n\n// src/hosts.ts\nfunction bareHost(host) {\n return host.toLowerCase().replace(/\\.+$/, "");\n}\nfunction isNaroHost(hostname, rootDomain2, naroUrl2) {\n const host = bareHost(hostname);\n if (host === "") return false;\n const root = rootDomain2.toLowerCase().replace(/^\\.+|\\.+$/g, "");\n if (root !== "" && host.endsWith(`.${root}`)) return true;\n if (naroUrl2 === "") return false;\n try {\n return bareHost(new URL(naroUrl2).hostname) === host;\n } catch {\n return false;\n }\n}\n\n// src/redact.ts\nvar MIN_REDACTED_LENGTH = 8;\nvar REDACTED = "[redacted]";\nfunction isSecretBinding(name) {\n return name === "NARO_SERVICE_KEY" || !name.startsWith("NARO_") && name !== "DB";\n}\nfunction secretValues(bindings2) {\n const values = /* @__PURE__ */ new Set();\n for (const [name, value] of Object.entries(bindings2)) {\n if (typeof value !== "string" || value.length < MIN_REDACTED_LENGTH)\n continue;\n if (!isSecretBinding(name)) continue;\n values.add(value);\n values.add(JSON.stringify(value).slice(1, -1));\n }\n return [...values].toSorted(\n (left, right) => right.length - left.length || (left < right ? -1 : left > right ? 1 : 0)\n );\n}\nfunction redactText(text, secrets2) {\n const spans = [];\n for (const secret of secrets2) {\n if (secret === "") continue;\n let last;\n for (let at = text.indexOf(secret); at !== -1; at = text.indexOf(secret, at + 1)) {\n if (last !== void 0 && at <= last[1]) last[1] = at + secret.length;\n else spans.push(last = [at, at + secret.length]);\n }\n }\n if (spans.length === 0) return text;\n const ordered = spans.toSorted((left, right) => left[0] - right[0]);\n let out = "";\n let kept = 0;\n let [start, end] = ordered[0];\n for (const [nextStart, nextEnd] of ordered) {\n if (nextStart <= end) {\n end = Math.max(end, nextEnd);\n continue;\n }\n out += text.slice(kept, start) + REDACTED;\n kept = end;\n start = nextStart;\n end = nextEnd;\n }\n return out + text.slice(kept, start) + REDACTED + text.slice(end);\n}\nfunction stringOf(value) {\n try {\n return String(value);\n } catch {\n return void 0;\n }\n}\nfunction withHead(stack, head) {\n if (stack === head || stack.startsWith(`${head}\n`)) return stack;\n const frames = stack.indexOf("\\n at ");\n return frames === -1 ? `${head}\n${stack}` : `${head}${stack.slice(frames)}`;\n}\nfunction redactError(error, secrets2) {\n const stack = typeof error.stack === "string" ? error.stack : `${error.name}: ${error.message}`;\n const head = stringOf(error);\n let json;\n try {\n json = JSON.stringify(error);\n } catch {\n json = void 0;\n }\n const cleanStack = redactText(stack, secrets2);\n const cleanHead = head === void 0 ? void 0 : redactText(head, secrets2);\n const cleanJson = json === void 0 ? void 0 : redactText(json, secrets2);\n if (cleanStack === stack && head !== void 0 && cleanHead === head && json !== void 0 && cleanJson === json)\n return error;\n const text = cleanHead === void 0 ? cleanStack : withHead(cleanStack, cleanHead);\n return cleanJson === void 0 || cleanJson === "{}" ? text : `${text}\n${cleanJson}`;\n}\nfunction isPlain(value) {\n if (Array.isArray(value)) return true;\n const prototype = Object.getPrototypeOf(value);\n return prototype === Object.prototype || prototype === null;\n}\nfunction redactArg(arg, secrets2) {\n if (typeof arg === "string") return redactText(arg, secrets2);\n if (arg === null || typeof arg !== "object" && typeof arg !== "function")\n return arg;\n try {\n if (arg instanceof Error) return redactError(arg, secrets2);\n let json;\n try {\n json = JSON.stringify(arg);\n } catch {\n return redactText(String(arg), secrets2);\n }\n if (json !== void 0) {\n const clean2 = redactText(json, secrets2);\n if (clean2 !== json) return clean2;\n }\n if (isPlain(arg)) return arg;\n const text = stringOf(arg);\n if (text === void 0) return arg;\n const clean = redactText(text, secrets2);\n return clean === text ? arg : clean;\n } catch {\n return REDACTED;\n }\n}\nfunction redactArgs(args, secrets2) {\n if (secrets2.length === 0) return [...args];\n return args.map((arg) => redactArg(arg, secrets2));\n}\n\n// src/rejections.ts\nfunction loggedRejection(promise, name) {\n return Promise.resolve(promise).then(\n () => void 0,\n (error) => {\n console.error(`naro functions: ${name} waitUntil rejected`, error);\n }\n );\n}\n\n// src/respond.ts\nvar FUNCTION_EXPOSE_HEADERS = [\n "x-relay-error",\n "x-naro-trace-id",\n "retry-after",\n "x-retry-after"\n];\nvar WRAPPER_ERRORS = {\n FUNCTION_ERROR: "The function threw an error. See `naro functions logs {name}`.",\n FUNCTION_NO_HANDLER: "The function has no handler. Call Deno.serve(handler) or export default { fetch }.",\n FUNCTION_MISROUTED: "This function was reached without the Naro gateway.",\n FUNCTION_NOT_FOUND: "Function {name} was not found."\n};\nfunction appendExposeHeaders(value) {\n const listed = (value ?? "").split(",").map((part) => part.trim()).filter((part) => part !== "");\n const seen = new Set(listed.map((part) => part.toLowerCase()));\n for (const name of FUNCTION_EXPOSE_HEADERS)\n if (!seen.has(name)) listed.push(name);\n return listed.join(", ");\n}\n\n// src/runtime-state.ts\nvar RUNTIME_KEY = /* @__PURE__ */ Symbol.for("naro.functions.runtime");\nvar CONTEXT_KEY = /* @__PURE__ */ Symbol.for("naro.functions.context");\n\n// src/naro-shim.ts\nvar bindings = env;\nvar globals = globalThis;\nfunction callName() {\n return state.requests.getStore()?.name ?? "";\n}\nvar secrets = secretValues(bindings);\nfor (const level of ["log", "info", "warn", "error", "debug"]) {\n const original = console[level].bind(console);\n console[level] = (...args) => {\n original(...redactArgs(args, secrets));\n };\n}\nvar logError = console.error;\nvar NativeResponse = Response;\nvar bareRecord = Object.create;\nvar NAME_SLOT = "\\0";\nvar [failedHead = "", failedTail = ""] = JSON.stringify({\n data: null,\n error: {\n code: "FUNCTION_ERROR",\n message: WRAPPER_ERRORS.FUNCTION_ERROR.replace("{name}", () => NAME_SLOT)\n }\n}).split(JSON.stringify(NAME_SLOT).slice(1, -1));\nvar exposedHeaders = appendExposeHeaders(null);\nfunction lastResort(error, traceId, name) {\n try {\n logError(`naro functions: ${name} threw`, error);\n } catch {\n }\n const headers = bareRecord(null);\n headers["content-type"] = "application/json";\n headers["access-control-allow-origin"] = "*";\n headers["access-control-expose-headers"] = exposedHeaders;\n headers["cache-control"] = "no-store";\n if (traceId !== null) headers["x-naro-trace-id"] = traceId;\n const init = bareRecord(null);\n init.status = 500;\n init.headers = headers;\n return new NativeResponse(\n failedHead + name + failedTail,\n init\n );\n}\nvar reflectApply = Reflect.apply;\nvar responseStatus = Object.getOwnPropertyDescriptor(\n NativeResponse.prototype,\n "status"\n)?.get;\nfunction isResponse(value) {\n if (typeof value !== "object" || value === null) return false;\n try {\n if (responseStatus === void 0) return value instanceof NativeResponse;\n reflectApply(responseStatus, value, []);\n return true;\n } catch {\n return false;\n }\n}\nvar state = {\n router: null,\n registered: null,\n requests: new AsyncLocalStorage(),\n lastResort,\n isResponse\n};\nglobals[RUNTIME_KEY] = state;\nglobals[CONTEXT_KEY] = /* @__PURE__ */ new WeakMap();\nvar rootDomain = typeof bindings.NARO_ROOT_DOMAIN === "string" ? bindings.NARO_ROOT_DOMAIN : "";\nvar naroUrl = typeof bindings.NARO_URL === "string" ? bindings.NARO_URL : "";\nvar originalFetch = globalThis.fetch.bind(globalThis);\nasync function naroFetch(input, init) {\n const store = state.requests.getStore();\n if (store === void 0) return originalFetch(input, init);\n let host;\n try {\n host = new URL(input instanceof Request ? input.url : String(input)).hostname;\n } catch {\n return originalFetch(input, init);\n }\n if (!isNaroHost(host, rootDomain, naroUrl)) return originalFetch(input, init);\n const request = new Request(input, init);\n const headers = new Headers(request.headers);\n headers.set("x-naro-fn-hop", String(store.hop + 1));\n headers.set("x-naro-trace-id", store.traceId);\n return originalFetch(new Request(request, { headers }));\n}\nglobalThis.fetch = naroFetch;\nvar addListener = EventTarget.prototype.addEventListener;\nvar removeListener = EventTarget.prototype.removeEventListener;\nvar standIns = /* @__PURE__ */ new WeakMap();\nfunction standInFor(socket, listener, store) {\n let listeners = standIns.get(socket);\n if (listeners === void 0)\n standIns.set(socket, listeners = /* @__PURE__ */ new WeakMap());\n let standIn = listeners.get(listener);\n if (standIn === void 0) {\n standIn = function(event) {\n state.requests.run(\n store,\n () => typeof listener === "function" ? Reflect.apply(listener, this, [event]) : listener.handleEvent(event)\n );\n };\n listeners.set(listener, standIn);\n }\n return standIn;\n}\nObject.defineProperties(WebSocket.prototype, {\n addEventListener: {\n configurable: true,\n writable: true,\n value(type, listener, ...rest) {\n const store = state.requests.getStore();\n const runs = store !== void 0 && listener !== null && (typeof listener === "function" || typeof listener === "object");\n return Reflect.apply(addListener, this, [\n type,\n runs ? standInFor(this, listener, store) : listener,\n ...rest\n ]);\n }\n },\n removeEventListener: {\n configurable: true,\n writable: true,\n value(type, listener, ...rest) {\n const standIn = typeof listener === "function" || typeof listener === "object" && listener !== null ? standIns.get(this)?.get(listener) : void 0;\n return Reflect.apply(removeListener, this, [\n type,\n standIn ?? listener,\n ...rest\n ]);\n }\n }\n});\nvar ON_EVENTS = ["onopen", "onmessage", "onclose", "onerror"];\nvar onHandlers = /* @__PURE__ */ new WeakMap();\nfunction nativeAccessor(target, name) {\n for (let at = target; at !== null; at = Object.getPrototypeOf(at)) {\n const descriptor = Object.getOwnPropertyDescriptor(at, name);\n if (descriptor === void 0) continue;\n return descriptor.get !== void 0 && descriptor.set !== void 0 ? { get: descriptor.get, set: descriptor.set } : void 0;\n }\n return void 0;\n}\nfor (const name of ON_EVENTS) {\n const native = nativeAccessor(WebSocket.prototype, name);\n Object.defineProperty(WebSocket.prototype, name, {\n configurable: true,\n enumerable: true,\n get() {\n const set = onHandlers.get(this)?.get(name);\n if (set === void 0)\n return native === void 0 ? void 0 : Reflect.apply(native.get, this, []);\n return state.requests.getStore() === void 0 ? set.standIn : set.handler;\n },\n set(handler) {\n const store = state.requests.getStore();\n const standIn = store !== void 0 && typeof handler === "function" ? standInFor(this, handler, store) : handler;\n let handlers = onHandlers.get(this);\n if (handlers === void 0) onHandlers.set(this, handlers = /* @__PURE__ */ new Map());\n handlers.set(name, { handler, standIn });\n if (native !== void 0) Reflect.apply(native.set, this, [standIn]);\n }\n });\n}\nfunction serve(first, second) {\n const options = typeof first === "function" ? {} : first ?? {};\n const handler = typeof first === "function" ? first : second ?? options.handler;\n if (typeof handler !== "function")\n throw new TypeError("Deno.serve needs a handler.");\n const onError = typeof options.onError === "function" ? options.onError : null;\n if (state.requests.getStore() === void 0) {\n if (state.router !== null) state.router.register(handler, onError);\n else state.registered = { handler, onError };\n }\n return {\n finished: new Promise(() => {\n }),\n shutdown: () => Promise.resolve()\n };\n}\nfunction textBindings() {\n const out = {};\n for (const [name, value] of Object.entries(bindings))\n if (typeof value === "string") out[name] = value;\n return out;\n}\nvar build = Object.freeze({\n os: "linux",\n arch: "x86_64",\n target: "x86_64-unknown-linux-gnu",\n vendor: "unknown",\n env: "gnu"\n});\nvar version = Object.freeze({\n deno: "2.1.4",\n v8: "13.0.245.12",\n typescript: "5.6.2"\n});\nvar DENO_ERROR_NAMES = [\n "NotFound",\n "PermissionDenied",\n "ConnectionRefused",\n "ConnectionReset",\n "ConnectionAborted",\n "NotConnected",\n "AddrInUse",\n "AddrNotAvailable",\n "BrokenPipe",\n "AlreadyExists",\n "InvalidData",\n "TimedOut",\n "Interrupted",\n "WriteZero",\n "WouldBlock",\n "UnexpectedEof",\n "BadResource",\n "Http",\n "Busy",\n "NotSupported",\n "FilesystemLoop",\n "IsADirectory",\n "NetworkUnreachable",\n "NotADirectory",\n "NotCapable"\n];\nfunction denoError(name) {\n const made = { [name]: class extends Error {\n } }[name];\n Object.defineProperty(made.prototype, "name", {\n configurable: true,\n writable: true,\n value: name\n });\n return made;\n}\nvar errors = Object.freeze(\n Object.fromEntries(DENO_ERROR_NAMES.map((name) => [name, denoError(name)]))\n);\nvar deno = {\n serve,\n env: {\n get: (name) => {\n const value = bindings[name];\n return typeof value === "string" ? value : void 0;\n },\n has: (name) => typeof bindings[name] === "string",\n toObject: () => textBindings(),\n set: () => {\n throw new Error("Deno.env.set is not available on Naro Functions.");\n },\n delete: () => {\n throw new Error("Deno.env.delete is not available on Naro Functions.");\n }\n },\n build,\n version,\n errors\n};\nvar PROBES = /* @__PURE__ */ new Set(["then", "toJSON"]);\nglobals.Deno = new Proxy(deno, {\n get(target, property) {\n if (typeof property === "symbol" || PROBES.has(property)) return void 0;\n if (Object.hasOwn(target, property)) return target[property];\n return () => {\n throw new Error(`Deno.${property} is not available on Naro Functions.`);\n };\n }\n});\nglobals.EdgeRuntime = {\n waitUntil(promise) {\n const logged = loggedRejection(promise, callName());\n state.requests.getStore()?.ctx.waitUntil(logged);\n return promise;\n }\n};\naddEventListener("unhandledrejection", (event) => {\n event.preventDefault();\n console.error(\n `naro functions: ${callName()} unhandled rejection`,\n event.reason\n );\n});\n';
|
|
36308
|
+
var NARO_BOOT_SOURCE = '// src/naro-boot.ts\nimport "./naro-shim.js";\nimport * as user from "./user.js";\n\n// src/choose.ts\nasync function serveWithInfo(registered, request) {\n let complete;\n const info = {\n remoteAddr: {\n transport: "tcp",\n hostname: request.headers.get("cf-connecting-ip") ?? "0.0.0.0",\n port: 0\n },\n completed: new Promise((resolve) => {\n complete = resolve;\n })\n };\n try {\n return await registered(request, info);\n } finally {\n complete();\n }\n}\nfunction chosenOf(registered, module) {\n if (registered !== null) {\n const handler = registered.handler;\n return {\n handler: async (request) => serveWithInfo(handler, request),\n onError: registered.onError\n };\n }\n const exported = module.default;\n if (typeof exported === "object" && exported !== null) {\n const fetchHandler = exported.fetch;\n if (typeof fetchHandler === "function")\n return {\n handler: async (request, env, ctx) => fetchHandler.call(exported, request, env, ctx),\n onError: null\n };\n }\n if (typeof exported === "function") {\n const prototype = exported.prototype;\n if (typeof prototype === "object" && prototype !== null && typeof prototype.fetch === "function")\n return {\n handler: async (request, env, ctx) => new exported(ctx, env).fetch(request),\n onError: null\n };\n return {\n handler: async (request, env, ctx) => exported(request, env, ctx),\n onError: null\n };\n }\n return null;\n}\n\n// src/runtime-state.ts\nvar RUNTIME_KEY = /* @__PURE__ */ Symbol.for("naro.functions.runtime");\nvar SHIM_FIRST = "The Naro functions shim must be imported before the wrapper.";\nfunction globals() {\n return globalThis;\n}\nfunction runtimeState() {\n const state2 = globals()[RUNTIME_KEY];\n if (state2 === void 0) throw new Error(SHIM_FIRST);\n return state2;\n}\n\n// src/naro-boot.ts\nvar BOOT_PATH = "/__naro/boot";\nvar state = runtimeState();\nvar naro_boot_default = {\n fetch(request) {\n if (new URL(request.url).pathname !== BOOT_PATH)\n return new Response("Not found", { status: 404 });\n const module = user;\n return Response.json({\n handler: chosenOf(state.registered, module) !== null\n });\n }\n};\nexport {\n naro_boot_default as default\n};\n';
|
|
36204
36309
|
var FUNCTIONS_COMPATIBILITY_DATE = "2026-08-19";
|
|
36205
36310
|
var FUNCTIONS_COMPATIBILITY_FLAGS = Object.freeze(["nodejs_compat", "global_fetch_strictly_public"]);
|
|
36206
36311
|
|
|
36207
36312
|
// ../../packages/functions-bundler/src/bundle.ts
|
|
36208
36313
|
var NARO_JS_FUNCTIONS = /Could not resolve "naro-js\/functions"/;
|
|
36209
|
-
var runtimeGzip;
|
|
36210
|
-
function runtimeCompressedBytes() {
|
|
36211
|
-
runtimeGzip ??= gzipSync(NARO_ENTRY_SOURCE).byteLength + gzipSync(NARO_SHIM_SOURCE).byteLength;
|
|
36212
|
-
return runtimeGzip;
|
|
36213
|
-
}
|
|
36214
36314
|
function relativeLabel(root, file2) {
|
|
36215
36315
|
return relative10(root, file2).split(sep9).join("/");
|
|
36216
36316
|
}
|
|
@@ -36317,18 +36417,11 @@ async function bundleFunction(source, folder, options = {}) {
|
|
|
36317
36417
|
BUNDLE_MESSAGES.tooLarge(source.name, bytes2, biggest)
|
|
36318
36418
|
);
|
|
36319
36419
|
}
|
|
36320
|
-
const compressedBytes = gzipSync(output.contents).byteLength + runtimeCompressedBytes();
|
|
36321
|
-
if (compressedBytes > (options.maxCompressedBytes ?? FUNCTION_COMPRESSED_BUNDLE_MAX_BYTES))
|
|
36322
|
-
throw new FunctionBundleError(
|
|
36323
|
-
"FUNCTION_BUNDLE_FAILED",
|
|
36324
|
-
BUNDLE_MESSAGES.tooLargeCompressed(source.name, compressedBytes)
|
|
36325
|
-
);
|
|
36326
36420
|
return {
|
|
36327
36421
|
name: source.name,
|
|
36328
36422
|
code: output.text,
|
|
36329
36423
|
contents: output.contents,
|
|
36330
36424
|
bytes: bytes2,
|
|
36331
|
-
compressedBytes,
|
|
36332
36425
|
sha256: createHash4("sha256").update(output.contents).digest("hex"),
|
|
36333
36426
|
warnings: [...state.warnings]
|
|
36334
36427
|
};
|
|
@@ -36452,7 +36545,16 @@ function retryAfterSeconds(error51) {
|
|
|
36452
36545
|
const value = error51.details?.retryAfter;
|
|
36453
36546
|
return typeof value === "number" && Number.isFinite(value) && value > 0 ? Math.min(Math.ceil(value), FUNCTION_RATE_LIMIT_MAX_SECONDS) : FUNCTION_RATE_LIMIT_DEFAULT_SECONDS;
|
|
36454
36547
|
}
|
|
36548
|
+
var functionWords = (name) => ({
|
|
36549
|
+
rateLimited: (seconds, attempt, of) => `\u23F3 Cloudflare is rate limiting function uploads; trying ${name} again in ${String(seconds)} seconds (${String(attempt)}/${String(of)}).`,
|
|
36550
|
+
busy: (attempt, of) => `\u23F3 ${name} is being changed right now; trying again in ${String(FUNCTION_BUSY_WAIT_MS / 1e3)} seconds (${String(attempt)}/${String(of)}).`
|
|
36551
|
+
});
|
|
36552
|
+
var batchRetryWords = (count2) => ({
|
|
36553
|
+
rateLimited: (seconds, attempt, of) => `\u23F3 Cloudflare is rate limiting function uploads; trying the ${String(count2)} functions again in ${String(seconds)} seconds (${String(attempt)}/${String(of)}).`,
|
|
36554
|
+
busy: (attempt, of) => `\u23F3 Functions in this project are being changed right now; trying again in ${String(FUNCTION_BUSY_WAIT_MS / 1e3)} seconds (${String(attempt)}/${String(of)}).`
|
|
36555
|
+
});
|
|
36455
36556
|
async function withFunctionRetries(op, name, io) {
|
|
36557
|
+
const words = typeof name === "string" ? functionWords(name) : name;
|
|
36456
36558
|
const rateRetries = io.rateLimitRetries ?? FUNCTION_RETRIES;
|
|
36457
36559
|
const busyRetries = io.busyRetries ?? FUNCTION_RETRIES;
|
|
36458
36560
|
let rate = 0;
|
|
@@ -36465,17 +36567,13 @@ async function withFunctionRetries(op, name, io) {
|
|
|
36465
36567
|
if (error51.code === "FUNCTIONS_RATE_LIMITED" && rate < rateRetries) {
|
|
36466
36568
|
rate += 1;
|
|
36467
36569
|
const seconds = retryAfterSeconds(error51);
|
|
36468
|
-
io.log(
|
|
36469
|
-
`\u23F3 Cloudflare is rate limiting function uploads; trying ${name} again in ${String(seconds)} seconds (${String(rate)}/${String(rateRetries)}).`
|
|
36470
|
-
);
|
|
36570
|
+
io.log(words.rateLimited(seconds, rate, rateRetries));
|
|
36471
36571
|
await io.sleep(seconds * 1e3);
|
|
36472
36572
|
continue;
|
|
36473
36573
|
}
|
|
36474
36574
|
if (error51.code === "FUNCTION_BUSY" && busy < busyRetries) {
|
|
36475
36575
|
busy += 1;
|
|
36476
|
-
io.log(
|
|
36477
|
-
`\u23F3 ${name} is being changed right now; trying again in ${String(FUNCTION_BUSY_WAIT_MS / 1e3)} seconds (${String(busy)}/${String(busyRetries)}).`
|
|
36478
|
-
);
|
|
36576
|
+
io.log(words.busy(busy, busyRetries));
|
|
36479
36577
|
await io.sleep(FUNCTION_BUSY_WAIT_MS);
|
|
36480
36578
|
continue;
|
|
36481
36579
|
}
|
|
@@ -36494,7 +36592,6 @@ var PER_FUNCTION_CODES = /* @__PURE__ */ new Set([
|
|
|
36494
36592
|
"BUNDLE_MISSING",
|
|
36495
36593
|
"BUNDLE_MISMATCH",
|
|
36496
36594
|
"FUNCTION_LIMIT",
|
|
36497
|
-
"FUNCTION_BUSY",
|
|
36498
36595
|
"FUNCTION_NOT_FOUND",
|
|
36499
36596
|
"VERSION_NOT_FOUND",
|
|
36500
36597
|
"VERSION_NOT_DEPLOYABLE",
|
|
@@ -36524,16 +36621,20 @@ function uploadTimeoutMs(upload, now = Date.now()) {
|
|
|
36524
36621
|
var SECRETS_LIST_TIMEOUT_MS = 45e3;
|
|
36525
36622
|
var FUNCTION_CALL_TIMEOUT_MS = 12e4;
|
|
36526
36623
|
var deadlineReached = (name, deadlineMs) => `Deploying ${name} reached the ${String(deadlineMs / 1e3)}-second limit before it went live; the live version did not change. Try again.`;
|
|
36624
|
+
var batchDeadlineReached = (count2, deadlineMs) => `Deploying ${String(count2)} functions reached the ${String(deadlineMs / 1e3)}-second limit before they went live; the live versions did not change. Try again.`;
|
|
36527
36625
|
function budgetOf(options) {
|
|
36528
36626
|
const { deadlineMs } = options;
|
|
36529
36627
|
if (deadlineMs === void 0) return null;
|
|
36530
36628
|
const now = options.now ?? Date.now;
|
|
36531
36629
|
const end = now() + deadlineMs;
|
|
36532
36630
|
return {
|
|
36533
|
-
left(name, cap) {
|
|
36631
|
+
left(name, cap, message) {
|
|
36534
36632
|
const left = end - now();
|
|
36535
36633
|
if (left <= 0)
|
|
36536
|
-
throw new NaroError(
|
|
36634
|
+
throw new NaroError(
|
|
36635
|
+
"TIMEOUT",
|
|
36636
|
+
message ?? deadlineReached(name, deadlineMs)
|
|
36637
|
+
);
|
|
36537
36638
|
return Math.min(cap, left);
|
|
36538
36639
|
}
|
|
36539
36640
|
};
|
|
@@ -36578,58 +36679,79 @@ async function projectSecretNames(client, projectId, timeoutMs) {
|
|
|
36578
36679
|
return [];
|
|
36579
36680
|
}
|
|
36580
36681
|
}
|
|
36581
|
-
|
|
36682
|
+
function callLimit(budget, name, message) {
|
|
36683
|
+
return budget ? { timeoutMs: budget.left(name, FUNCTION_CALL_TIMEOUT_MS, message) } : null;
|
|
36684
|
+
}
|
|
36685
|
+
async function prepareOne(options, folder, name, importMap, secretNames, io, budget) {
|
|
36582
36686
|
const steps = options.steps ?? { bundle: bundleFunction, boot: bootCheck };
|
|
36583
36687
|
const { client, projectId } = options;
|
|
36584
|
-
const call = () => budget ? { timeoutMs: budget.left(name, FUNCTION_CALL_TIMEOUT_MS) } : null;
|
|
36585
36688
|
io.log(`\u23F3 Deploying ${name}\u2026`);
|
|
36586
|
-
|
|
36587
|
-
|
|
36588
|
-
|
|
36589
|
-
|
|
36590
|
-
|
|
36591
|
-
await steps.boot(
|
|
36592
|
-
name,
|
|
36593
|
-
bundle.code,
|
|
36594
|
-
budget ? {
|
|
36595
|
-
secretNames,
|
|
36596
|
-
timeoutMs: bootSeconds(budget.left(name, BOOT_TIMEOUT_MS))
|
|
36597
|
-
} : { secretNames }
|
|
36598
|
-
);
|
|
36599
|
-
const verifyJwt = options.verifyJwt ?? source.verifyJwt ?? true;
|
|
36600
|
-
const request2 = {
|
|
36601
|
-
size: bundle.bytes,
|
|
36602
|
-
sha256: bundle.sha256,
|
|
36603
|
-
verifyJwt,
|
|
36604
|
-
entrypoint: source.entrypoint,
|
|
36605
|
-
...options.cliVersion ? { cliVersion: options.cliVersion } : {}
|
|
36606
|
-
};
|
|
36607
|
-
const created = await withFunctionRetries(
|
|
36608
|
-
() => {
|
|
36609
|
-
const limit = call();
|
|
36610
|
-
return limit ? client.functions.createVersion(projectId, name, request2, limit) : client.functions.createVersion(projectId, name, request2);
|
|
36611
|
-
},
|
|
36689
|
+
const source = readFunctionSource(folder, name);
|
|
36690
|
+
const bundle = await steps.bundle(source, folder, { importMap });
|
|
36691
|
+
for (const warning of bundle.warnings) io.log(warning);
|
|
36692
|
+
if (!options.skipCheck)
|
|
36693
|
+
await steps.boot(
|
|
36612
36694
|
name,
|
|
36613
|
-
|
|
36614
|
-
|
|
36615
|
-
|
|
36616
|
-
|
|
36617
|
-
|
|
36695
|
+
bundle.code,
|
|
36696
|
+
budget ? {
|
|
36697
|
+
secretNames,
|
|
36698
|
+
timeoutMs: bootSeconds(budget.left(name, BOOT_TIMEOUT_MS))
|
|
36699
|
+
} : { secretNames }
|
|
36700
|
+
);
|
|
36701
|
+
const verifyJwt = options.verifyJwt ?? source.verifyJwt ?? true;
|
|
36702
|
+
const request2 = {
|
|
36703
|
+
size: bundle.bytes,
|
|
36704
|
+
sha256: bundle.sha256,
|
|
36705
|
+
verifyJwt,
|
|
36706
|
+
entrypoint: source.entrypoint,
|
|
36707
|
+
...options.cliVersion ? { cliVersion: options.cliVersion } : {}
|
|
36708
|
+
};
|
|
36709
|
+
const created = await withFunctionRetries(
|
|
36710
|
+
() => {
|
|
36711
|
+
const limit = callLimit(budget, name);
|
|
36712
|
+
return limit ? client.functions.createVersion(projectId, name, request2, limit) : client.functions.createVersion(projectId, name, request2);
|
|
36713
|
+
},
|
|
36714
|
+
name,
|
|
36715
|
+
io
|
|
36716
|
+
);
|
|
36717
|
+
const urlLife = uploadTimeoutMs(created.upload);
|
|
36718
|
+
await putBundle(
|
|
36719
|
+
options.fetch ?? fetch,
|
|
36720
|
+
name,
|
|
36721
|
+
created.upload,
|
|
36722
|
+
bundle.contents,
|
|
36723
|
+
budget ? budget.left(name, urlLife) : urlLife
|
|
36724
|
+
);
|
|
36725
|
+
return {
|
|
36726
|
+
name,
|
|
36727
|
+
versionId: created.version.id,
|
|
36728
|
+
number: created.version.number,
|
|
36729
|
+
url: created.function.url,
|
|
36730
|
+
verifyJwt: created.version.verifyJwt
|
|
36731
|
+
};
|
|
36732
|
+
}
|
|
36733
|
+
async function deployOne(options, folder, name, importMap, secretNames, io, budget) {
|
|
36734
|
+
const { client, projectId } = options;
|
|
36735
|
+
try {
|
|
36736
|
+
const ready = await prepareOne(
|
|
36737
|
+
options,
|
|
36738
|
+
folder,
|
|
36618
36739
|
name,
|
|
36619
|
-
|
|
36620
|
-
|
|
36621
|
-
|
|
36740
|
+
importMap,
|
|
36741
|
+
secretNames,
|
|
36742
|
+
io,
|
|
36743
|
+
budget
|
|
36622
36744
|
);
|
|
36623
36745
|
const live = await withFunctionRetries(
|
|
36624
36746
|
() => {
|
|
36625
|
-
const limit =
|
|
36626
|
-
return limit ? client.functions.deploy(projectId, name,
|
|
36747
|
+
const limit = callLimit(budget, name);
|
|
36748
|
+
return limit ? client.functions.deploy(projectId, name, ready.versionId, limit) : client.functions.deploy(projectId, name, ready.versionId);
|
|
36627
36749
|
},
|
|
36628
36750
|
name,
|
|
36629
36751
|
io
|
|
36630
36752
|
);
|
|
36631
36753
|
io.log(
|
|
36632
|
-
`\u2705 Deployed ${name} (v${String(live.version ??
|
|
36754
|
+
`\u2705 Deployed ${name} (v${String(live.version ?? ready.number)}) \u2014 ${live.url}`
|
|
36633
36755
|
);
|
|
36634
36756
|
return {
|
|
36635
36757
|
name,
|
|
@@ -36641,6 +36763,30 @@ async function deployOne(options, folder, name, importMap, secretNames, io, budg
|
|
|
36641
36763
|
throw asNaroError(error51);
|
|
36642
36764
|
}
|
|
36643
36765
|
}
|
|
36766
|
+
async function deployReady(options, ready, io, budget) {
|
|
36767
|
+
const { client, projectId, deadlineMs } = options;
|
|
36768
|
+
const versions = ready.map(({ name, versionId }) => ({ name, versionId }));
|
|
36769
|
+
const [only] = ready;
|
|
36770
|
+
const one = ready.length === 1 && only !== void 0 ? only.name : null;
|
|
36771
|
+
const late = deadlineMs === void 0 ? void 0 : one === null ? batchDeadlineReached(ready.length, deadlineMs) : deadlineReached(one, deadlineMs);
|
|
36772
|
+
io.log(
|
|
36773
|
+
one === null ? `\u23F3 Putting ${String(ready.length)} functions live in one upload\u2026` : `\u23F3 Putting ${one} live\u2026`
|
|
36774
|
+
);
|
|
36775
|
+
const { functions } = await withFunctionRetries(
|
|
36776
|
+
() => {
|
|
36777
|
+
const limit = callLimit(budget, one ?? "", late);
|
|
36778
|
+
return limit ? client.functions.deployMany(projectId, versions, limit) : client.functions.deployMany(projectId, versions);
|
|
36779
|
+
},
|
|
36780
|
+
one ?? batchRetryWords(ready.length),
|
|
36781
|
+
io
|
|
36782
|
+
);
|
|
36783
|
+
const live = new Map(functions.map((fn) => [fn.name, fn.version]));
|
|
36784
|
+
return ready.map((fn) => {
|
|
36785
|
+
const version3 = live.get(fn.name) ?? fn.number;
|
|
36786
|
+
io.log(`\u2705 Deployed ${fn.name} (v${String(version3)}) \u2014 ${fn.url}`);
|
|
36787
|
+
return { name: fn.name, version: version3, url: fn.url, verifyJwt: fn.verifyJwt };
|
|
36788
|
+
});
|
|
36789
|
+
}
|
|
36644
36790
|
function readFlagImportMap(options, folder) {
|
|
36645
36791
|
if (options.importMap === void 0) return void 0;
|
|
36646
36792
|
const file2 = resolve14(options.cwd, options.importMap);
|
|
@@ -36704,12 +36850,12 @@ async function deployFunctions(options) {
|
|
|
36704
36850
|
)
|
|
36705
36851
|
]
|
|
36706
36852
|
};
|
|
36707
|
-
const
|
|
36853
|
+
const ready = [];
|
|
36708
36854
|
const failures = [];
|
|
36709
36855
|
for (const name of names) {
|
|
36710
36856
|
try {
|
|
36711
|
-
|
|
36712
|
-
await
|
|
36857
|
+
ready.push(
|
|
36858
|
+
await prepareOne(
|
|
36713
36859
|
options,
|
|
36714
36860
|
folder,
|
|
36715
36861
|
name,
|
|
@@ -36719,14 +36865,23 @@ async function deployFunctions(options) {
|
|
|
36719
36865
|
budget
|
|
36720
36866
|
)
|
|
36721
36867
|
);
|
|
36722
|
-
} catch (
|
|
36868
|
+
} catch (caught) {
|
|
36869
|
+
const error51 = asNaroError(caught);
|
|
36723
36870
|
if (!isNaroError(error51)) throw error51;
|
|
36724
36871
|
if (!PER_FUNCTION_CODES.has(error51.code))
|
|
36725
|
-
throw withProgress(error51,
|
|
36872
|
+
throw withProgress(error51, [], failures);
|
|
36726
36873
|
failures.push({ name, code: error51.code, message: error51.message });
|
|
36727
36874
|
io.log(`\u2717 ${name}: ${printable(error51.message)}`);
|
|
36728
36875
|
}
|
|
36729
36876
|
}
|
|
36877
|
+
let deployed = [];
|
|
36878
|
+
if (ready.length > 0)
|
|
36879
|
+
try {
|
|
36880
|
+
deployed = await deployReady(options, ready, io, budget);
|
|
36881
|
+
} catch (error51) {
|
|
36882
|
+
if (!isNaroError(error51)) throw error51;
|
|
36883
|
+
throw withProgress(error51, [], failures);
|
|
36884
|
+
}
|
|
36730
36885
|
if (failures.length > 0)
|
|
36731
36886
|
throw new NaroError(
|
|
36732
36887
|
"FUNCTIONS_DEPLOY_PARTIAL",
|
|
@@ -37248,6 +37403,8 @@ export {
|
|
|
37248
37403
|
formatRedirectEntry,
|
|
37249
37404
|
policiesForTypes,
|
|
37250
37405
|
generateTypes,
|
|
37406
|
+
isSymbolicLink,
|
|
37407
|
+
assertProjectLinkWritable,
|
|
37251
37408
|
readProjectLink,
|
|
37252
37409
|
writeProjectLink,
|
|
37253
37410
|
removeProjectLink,
|