void 0.21.4 → 0.21.6

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/dist/cli/cli.mjs CHANGED
@@ -2020,7 +2020,7 @@ if (helpPath) {
2020
2020
  log.error(formatCloudflareUserMessage(err instanceof Error ? err.message : String(err)));
2021
2021
  process.exit(1);
2022
2022
  }
2023
- import("../deploy-BVwow28d.mjs").then(({ runDeploy }) => {
2023
+ import("../deploy-f1j5MyEP.mjs").then(({ runDeploy }) => {
2024
2024
  runDeploy(root, {
2025
2025
  projectSlug: deployArgs.projectSlug,
2026
2026
  dir: deployArgs.dir,
@@ -2052,8 +2052,8 @@ else if (command === "cloudflare") runSubcommandGroup("cloudflare", cloudflareSu
2052
2052
  else if (command === "project") runSubcommandGroup("project", projectSubcommands, parseProjectArgs, (root, parsed) => import("../project-cmd-B44I8J_W.mjs").then(({ runProjectCommand }) => runProjectCommand(root, parsed)));
2053
2053
  else if (command === "secret") runSubcommandGroup("secret", secretSubcommands, parseSecretArgs, (root, parsed) => import("../secret-DN9sSNiV.mjs").then(({ runSecretCommand }) => runSecretCommand(root, parsed)));
2054
2054
  else if (command === "domain") runSubcommandGroup("domain", domainSubcommands, parseDomainArgs, (root, parsed) => import("../domain-Dmhvb2oU.mjs").then(({ runDomainCommand }) => runDomainCommand(root, parsed)));
2055
- else if (command === "email") runSubcommandGroup("email", emailSubcommands, parseEmailArgs, (root, parsed) => import("../email-BxHabktK.mjs").then(({ runEmailCommand }) => runEmailCommand(root, parsed)));
2056
- else if (command === "db") runSubcommandGroup("db", dbSubcommands, parseDbArgs, (root, parsed) => import("../db-CTXIWD42.mjs").then(({ runDbCommand }) => runDbCommand(root, parsed)));
2055
+ else if (command === "email") runSubcommandGroup("email", emailSubcommands, parseEmailArgs, (root, parsed) => import("../email-BXBtqadx.mjs").then(({ runEmailCommand }) => runEmailCommand(root, parsed)));
2056
+ else if (command === "db") runSubcommandGroup("db", dbSubcommands, parseDbArgs, (root, parsed) => import("../db-CyHAAGkK.mjs").then(({ runDbCommand }) => runDbCommand(root, parsed)));
2057
2057
  else if (command === "env") runSubcommandGroup("env", envSubcommands, parseEnvArgs, (root, parsed) => import("../env-Csi-tMbT.mjs").then(({ runEnvCommand }) => runEnvCommand(root, parsed)));
2058
2058
  else if (command === "gen") runSubcommandGroup("gen", genSubcommands, parseGenArgs, (root, parsed) => import("../gen-Vnv2f65C.mjs").then(({ runGenCommand }) => runGenCommand(root, parsed)));
2059
2059
  else if (command === "github") runSubcommandGroup("github", githubSubcommands, parseGithubArgs, (root, parsed) => import("../github-cmd-BED3_9JD.mjs").then(({ runGithubCommand }) => runGithubCommand(root, parsed)));
@@ -2222,7 +2222,7 @@ else if (command === "prepare") {
2222
2222
  return;
2223
2223
  }
2224
2224
  case "deploy": {
2225
- const { runDeploy } = await import("../deploy-BVwow28d.mjs");
2225
+ const { runDeploy } = await import("../deploy-f1j5MyEP.mjs");
2226
2226
  await runDeploy(root);
2227
2227
  return;
2228
2228
  }
@@ -2235,8 +2235,8 @@ else if (command === "prepare") {
2235
2235
  case "domain": return runSubcommandGroup("domain", domainSubcommands, parseDomainArgs, (r, p) => import("../domain-Dmhvb2oU.mjs").then(({ runDomainCommand }) => runDomainCommand(r, p)));
2236
2236
  case "github": return runSubcommandGroup("github", githubSubcommands, parseGithubArgs, (r, p) => import("../github-cmd-BED3_9JD.mjs").then(({ runGithubCommand }) => runGithubCommand(r, p)));
2237
2237
  case "build": return runSubcommandGroup("build", buildSubcommands, parseBuildArgs, (r, p) => import("../build-cmd-Dpt0jd-x.mjs").then(({ runBuildCommand }) => runBuildCommand(r, p)));
2238
- case "email": return runSubcommandGroup("email", emailSubcommands, parseEmailArgs, (r, p) => import("../email-BxHabktK.mjs").then(({ runEmailCommand }) => runEmailCommand(r, p)));
2239
- case "db": return runSubcommandGroup("db", dbSubcommands, parseDbArgs, (r, p) => import("../db-CTXIWD42.mjs").then(({ runDbCommand }) => runDbCommand(r, p)));
2238
+ case "email": return runSubcommandGroup("email", emailSubcommands, parseEmailArgs, (r, p) => import("../email-BXBtqadx.mjs").then(({ runEmailCommand }) => runEmailCommand(r, p)));
2239
+ case "db": return runSubcommandGroup("db", dbSubcommands, parseDbArgs, (r, p) => import("../db-CyHAAGkK.mjs").then(({ runDbCommand }) => runDbCommand(r, p)));
2240
2240
  case "env": return runSubcommandGroup("env", envSubcommands, parseEnvArgs, (r, p) => import("../env-Csi-tMbT.mjs").then(({ runEnvCommand }) => runEnvCommand(r, p)));
2241
2241
  case "gen": return runSubcommandGroup("gen", genSubcommands, parseGenArgs, (r, p) => import("../gen-Vnv2f65C.mjs").then(({ runGenCommand }) => runGenCommand(r, p)));
2242
2242
  case "prepare": {
@@ -862,7 +862,7 @@ async function runMigrate(root, dialect, remote) {
862
862
  log.error(getErrorMessage(error));
863
863
  process.exit(1);
864
864
  }
865
- const { checkWranglerMigrationApplySet, parseRootWranglerConfig } = await import("./deploy-BVwow28d.mjs");
865
+ const { checkWranglerMigrationApplySet, parseRootWranglerConfig } = await import("./deploy-f1j5MyEP.mjs");
866
866
  const applySet = await checkWranglerMigrationApplySet(context.operation.configPath, parseRootWranglerConfig(context.operation.configPath), binding, context.migrationsDir, rawMigrations);
867
867
  if (!applySet.ok) {
868
868
  log.error(applySet.reason);
@@ -57,7 +57,7 @@ import { applyEdits, modify, parse } from "jsonc-parser";
57
57
  import { isDeepStrictEqual } from "node:util";
58
58
  import { Minimatch } from "minimatch";
59
59
  import { activateCloudflareVersion, assertCloudflareBindingsPreserved, assertCloudflareDurableObjectLifecycleSupported, assertExistingCloudflareConfig, encodeCloudflareVersionMessage, extractWorkersDevSubdomain, normalizeWorkersDevSubdomain, parseRootWranglerConfig, parseRootWranglerConfig as parseRootWranglerConfig$1, readBindingFieldPresence, readCloudflareTriggerConfig, readConfigEntryString, readExistingCloudflareWorker, readStoredResourceName, readWranglerTopLevelString, renderCloudflareStaticEntry, resolveD1MigrateTarget, stageCloudflareStaticAssets, writeCloudflareFrameworkDeployConfig, writeCloudflareStaticDeployConfig } from "@void/deploy-cloudflare";
60
- import { getWorkerConfigPath, readBuildOutput } from "@cloudflare/build-output-utils";
60
+ import { getWorkerAssetsDir, getWorkerBundleDir, getWorkerConfigPath, readBuildOutput } from "@cloudflare/build-output-utils";
61
61
  import ignore from "ignore";
62
62
  import { hash } from "blake3-jit";
63
63
  //#region src/asset-routing.ts
@@ -1857,6 +1857,321 @@ async function prerenderPagesNode(options) {
1857
1857
  return result;
1858
1858
  }
1859
1859
  //#endregion
1860
+ //#region src/cli/cf-version-api.ts
1861
+ function object(value) {
1862
+ return value && typeof value === "object" && !Array.isArray(value) ? value : null;
1863
+ }
1864
+ function requiredString(value, label) {
1865
+ if (typeof value !== "string" || !value) throw new Error(`The Cloudflare ${label} is missing from the verified Worker output.`);
1866
+ return value;
1867
+ }
1868
+ function textValue(value, label) {
1869
+ if (typeof value !== "string") throw new Error(`The Cloudflare ${label} is missing from the verified Worker output.`);
1870
+ return value;
1871
+ }
1872
+ const moduleContentTypes = {
1873
+ esm: "application/javascript+module",
1874
+ cjs: "application/javascript",
1875
+ wasm: "application/wasm",
1876
+ text: "text/plain",
1877
+ data: "application/octet-stream",
1878
+ json: "text/plain",
1879
+ sourcemap: "application/source-map"
1880
+ };
1881
+ function bindingsFromOutput(env, workerName, activeSecrets, explicitSecrets) {
1882
+ const inherited = new Map(activeSecrets.bindings.map((binding) => [binding.name, binding.type]));
1883
+ const names = /* @__PURE__ */ new Set([
1884
+ ...Object.keys(env),
1885
+ ...inherited.keys(),
1886
+ ...Object.keys(explicitSecrets)
1887
+ ]);
1888
+ const bindings = [];
1889
+ for (const name of names) {
1890
+ const value = object(env[name]);
1891
+ const explicit = explicitSecrets[name];
1892
+ if (explicit !== void 0) {
1893
+ if (typeof explicit !== "string" || inherited.get(name) === "secret_key" || value && value.type !== "secret") throw new Error(`Cloudflare secret ${name} has an invalid explicit value or binding.`);
1894
+ bindings.push({
1895
+ name,
1896
+ type: "secret_text",
1897
+ text: explicit
1898
+ });
1899
+ continue;
1900
+ }
1901
+ if (inherited.has(name)) {
1902
+ if (value && ![
1903
+ "secret",
1904
+ "inherit",
1905
+ "unsafe:inherit"
1906
+ ].includes(String(value.type))) throw new Error(`Cloudflare secret ${name} conflicts with a Worker binding.`);
1907
+ bindings.push({
1908
+ name,
1909
+ type: "inherit",
1910
+ version_id: activeSecrets.versionId
1911
+ });
1912
+ continue;
1913
+ }
1914
+ if (!value) throw new Error(`Cloudflare binding ${name} is missing from the Worker output.`);
1915
+ switch (value.type) {
1916
+ case "text":
1917
+ bindings.push({
1918
+ name,
1919
+ type: "plain_text",
1920
+ text: textValue(value.value, name)
1921
+ });
1922
+ break;
1923
+ case "json":
1924
+ bindings.push({
1925
+ name,
1926
+ type: "json",
1927
+ json: value.value
1928
+ });
1929
+ break;
1930
+ case "kv":
1931
+ bindings.push({
1932
+ name,
1933
+ type: "kv_namespace",
1934
+ namespace_id: requiredString(value.id, name)
1935
+ });
1936
+ break;
1937
+ case "d1":
1938
+ bindings.push({
1939
+ name,
1940
+ type: "d1",
1941
+ database_id: requiredString(value.id, name)
1942
+ });
1943
+ break;
1944
+ case "r2":
1945
+ bindings.push({
1946
+ name,
1947
+ type: "r2_bucket",
1948
+ bucket_name: requiredString(value.name, name),
1949
+ ...value.jurisdiction ? { jurisdiction: value.jurisdiction } : {}
1950
+ });
1951
+ break;
1952
+ case "durable-object":
1953
+ bindings.push({
1954
+ name,
1955
+ type: "durable_object_namespace",
1956
+ class_name: requiredString(value.exportName, name),
1957
+ ...value.worker !== workerName ? { script_name: requiredString(value.worker, name) } : {}
1958
+ });
1959
+ break;
1960
+ case "assets":
1961
+ bindings.push({
1962
+ name,
1963
+ type: "assets"
1964
+ });
1965
+ break;
1966
+ default: throw new Error(`Cloudflare binding ${name} cannot be uploaded with pinned secrets.`);
1967
+ }
1968
+ }
1969
+ return bindings;
1970
+ }
1971
+ function exportsFromOutput(exports) {
1972
+ if (exports === void 0) return;
1973
+ const entries = object(exports);
1974
+ if (!entries) throw new Error("Cloudflare Durable Object exports were not readable.");
1975
+ const result = {};
1976
+ for (const [name, raw] of Object.entries(entries)) {
1977
+ const value = object(raw);
1978
+ if (!value || value.type !== "durable-object") throw new Error(`Cloudflare export ${name} cannot be uploaded with pinned secrets.`);
1979
+ if (value.state === "deleted") result[name] = {
1980
+ type: "durable-object",
1981
+ state: "deleted"
1982
+ };
1983
+ else if (value.storage === "sqlite" || value.storage === "legacy-kv") result[name] = {
1984
+ type: "durable-object",
1985
+ storage: value.storage,
1986
+ state: "created"
1987
+ };
1988
+ else throw new Error(`Cloudflare Durable Object export ${name} has no storage type.`);
1989
+ }
1990
+ return result;
1991
+ }
1992
+ function assetConfigFromOutput(value) {
1993
+ if (value === void 0) return;
1994
+ const config = object(value);
1995
+ if (!config) throw new Error("Cloudflare asset configuration was not readable.");
1996
+ const supported = /* @__PURE__ */ new Set([
1997
+ "basePath",
1998
+ "htmlHandling",
1999
+ "notFoundHandling",
2000
+ "runWorkerFirst"
2001
+ ]);
2002
+ if (Object.keys(config).some((key) => !supported.has(key))) throw new Error("Cloudflare asset configuration has an unsupported setting.");
2003
+ return {
2004
+ ...config.basePath === void 0 ? {} : { base_path: config.basePath },
2005
+ ...config.htmlHandling === void 0 ? {} : { html_handling: config.htmlHandling },
2006
+ ...config.notFoundHandling === void 0 ? {} : { not_found_handling: config.notFoundHandling },
2007
+ ...config.runWorkerFirst === void 0 ? {} : { run_worker_first: config.runWorkerFirst }
2008
+ };
2009
+ }
2010
+ async function apiResult(url, token, method, body, verifyUploader, timeout = 12e4) {
2011
+ if (!verifyUploader()) throw new Error("The Cloudflare uploader changed during deployment.");
2012
+ const form = body instanceof FormData;
2013
+ const response = await fetch(url, {
2014
+ method,
2015
+ headers: {
2016
+ Authorization: `Bearer ${token}`,
2017
+ ...body && !form ? { "Content-Type": "application/json" } : {}
2018
+ },
2019
+ ...body ? { body: form ? body : JSON.stringify(body) } : {},
2020
+ redirect: "manual",
2021
+ signal: AbortSignal.timeout(timeout)
2022
+ });
2023
+ const parsed = object(await response.json());
2024
+ const result = object(parsed?.result);
2025
+ if (!response.ok || parsed?.success !== true || !result) {
2026
+ const error = Array.isArray(parsed?.errors) ? object(parsed.errors[0]) : null;
2027
+ const code = Number.isSafeInteger(error?.code) ? ` [code: ${error.code}]` : "";
2028
+ const message = typeof error?.message === "string" ? ` ${error.message}` : "";
2029
+ throw new Error(`Cloudflare version upload failed (${response.status})${code}.${message}`);
2030
+ }
2031
+ return result;
2032
+ }
2033
+ async function uploadAssets(options) {
2034
+ if (!options.output.assetsDirectory) return;
2035
+ const directory = getWorkerAssetsDir(options.output.directory);
2036
+ const manifest = {};
2037
+ const byHash = /* @__PURE__ */ new Map();
2038
+ const ignored = ignore().add([
2039
+ "/.assetsignore",
2040
+ "/_headers",
2041
+ "/_redirects",
2042
+ ".DS_Store",
2043
+ ".env",
2044
+ ".env.*",
2045
+ ".dev.vars",
2046
+ ".dev.vars.*"
2047
+ ]);
2048
+ const ignorePath = join(directory, ".assetsignore");
2049
+ try {
2050
+ ignored.add(readFileSync(ignorePath, "utf8"));
2051
+ } catch (cause) {
2052
+ if (!(cause instanceof Error && "code" in cause && cause.code === "ENOENT")) throw cause;
2053
+ }
2054
+ for (const entry of readdirSync(directory, {
2055
+ recursive: true,
2056
+ withFileTypes: true
2057
+ })) {
2058
+ if (entry.isDirectory()) continue;
2059
+ if (!entry.isFile()) throw new Error("The Cloudflare asset output contains an unsupported entry.");
2060
+ const path = join(entry.parentPath, entry.name);
2061
+ const relativeName = relative(directory, path).replaceAll("\\", "/");
2062
+ if (ignored.ignores(relativeName)) continue;
2063
+ const name = `/${relativeName}`;
2064
+ const content = readFileSync(path);
2065
+ const extension = extname(entry.name).slice(1);
2066
+ const hash = createHash("sha256").update(content.toString("base64") + extension).digest("hex").slice(0, 32);
2067
+ manifest[name] = {
2068
+ hash,
2069
+ size: content.length
2070
+ };
2071
+ byHash.set(hash, path);
2072
+ }
2073
+ const session = await apiResult(`${options.accountUrl}/workers/scripts/${encodeURIComponent(options.workerName)}/assets-upload-session`, options.token, "POST", { manifest }, options.verifyUploader);
2074
+ let jwt = requiredString(session.jwt, "asset upload token");
2075
+ if (!Array.isArray(session.buckets)) throw new Error("Cloudflare did not provide asset upload batches.");
2076
+ for (const bucket of session.buckets) {
2077
+ if (!Array.isArray(bucket) || !bucket.every((hash) => typeof hash === "string")) throw new Error("Cloudflare returned an invalid asset upload batch.");
2078
+ const form = new FormData();
2079
+ for (const hash of bucket) {
2080
+ const path = byHash.get(hash);
2081
+ if (!path) throw new Error("Cloudflare requested an asset outside the verified Worker output.");
2082
+ form.append(hash, readFileSync(path).toString("base64"));
2083
+ }
2084
+ jwt = requiredString((await apiResult(`${options.accountUrl}/workers/assets/upload?base64=true`, jwt, "POST", form, options.verifyUploader)).jwt, "asset completion token");
2085
+ }
2086
+ return jwt;
2087
+ }
2088
+ /** The Workers beta API is the only upload endpoint that accepts a version UUID as an inheritance source. */
2089
+ async function uploadPinnedCloudflareVersion(options) {
2090
+ const activeSecrets = options.output.activeSecrets;
2091
+ if (!activeSecrets) throw new Error("The active Worker secret source was not verified.");
2092
+ const config = (await readBuildOutput(options.output.directory)).workers.default.config;
2093
+ if (config.name !== options.workerName || !config.manifest || config.manifest.type !== "complete") throw new Error("The verified Cloudflare Worker output changed before upload.");
2094
+ const unsupported = Object.keys(config).filter((key) => !(/* @__PURE__ */ new Set([
2095
+ "name",
2096
+ "compatibilityDate",
2097
+ "compatibilityFlags",
2098
+ "assets",
2099
+ "domains",
2100
+ "observability",
2101
+ "workersDev",
2102
+ "previewUrls",
2103
+ "unsafe",
2104
+ "env",
2105
+ "exports",
2106
+ "manifest",
2107
+ "triggers"
2108
+ ])).has(key));
2109
+ if (unsupported.length) throw new Error(`Cloudflare Worker setting ${unsupported[0]} cannot be uploaded with pinned secrets.`);
2110
+ const unsafe = object(config.unsafe);
2111
+ const metadata = object(unsafe?.metadata);
2112
+ if (unsafe && Object.keys(unsafe).some((key) => key !== "metadata") || metadata && Object.keys(metadata).some((key) => key !== "keep_bindings") || metadata?.keep_bindings !== void 0 && (!Array.isArray(metadata.keep_bindings) || !metadata.keep_bindings.every((type) => typeof type === "string"))) throw new Error("Cloudflare Worker upload metadata has an unsupported setting.");
2113
+ const explicitSecrets = options.secretsFilePath ? object(JSON.parse(readFileSync(options.secretsFilePath, "utf8"))) : {};
2114
+ if (!explicitSecrets) throw new Error("The explicit Cloudflare secrets file was not readable.");
2115
+ const bindings = bindingsFromOutput(config.env ?? {}, options.workerName, activeSecrets, explicitSecrets);
2116
+ const active = await apiResult(`${options.apiBaseUrl.replace(/\/$/, "")}/accounts/${encodeURIComponent(options.accountId)}/workers/workers/${encodeURIComponent(options.workerName)}/versions/${encodeURIComponent(activeSecrets.versionId)}`, options.token, "GET", void 0, options.verifyUploader);
2117
+ if (active.id !== activeSecrets.versionId || !Array.isArray(active.bindings)) throw new Error("The active Cloudflare Worker bindings could not be verified.");
2118
+ const activeBindingNames = /* @__PURE__ */ new Set();
2119
+ const candidateNames = new Set(bindings.map((binding) => String(binding.name)));
2120
+ const keptTypes = new Set(metadata?.keep_bindings ?? []);
2121
+ for (const entry of active.bindings) {
2122
+ const binding = object(entry);
2123
+ if (!binding || typeof binding.name !== "string" || typeof binding.type !== "string") throw new Error("The active Cloudflare Worker bindings could not be verified.");
2124
+ activeBindingNames.add(binding.name);
2125
+ if (!candidateNames.has(binding.name) && keptTypes.has(binding.type) && ["plain_text", "json"].includes(binding.type)) {
2126
+ bindings.push({
2127
+ name: binding.name,
2128
+ type: "inherit",
2129
+ version_id: activeSecrets.versionId
2130
+ });
2131
+ candidateNames.add(binding.name);
2132
+ }
2133
+ }
2134
+ if (activeSecrets.bindings.some(({ name }) => !activeBindingNames.has(name))) throw new Error("The active Cloudflare Worker secrets changed before upload.");
2135
+ const exports = exportsFromOutput(config.exports);
2136
+ const assetConfig = assetConfigFromOutput(config.assets);
2137
+ if (bindings.some((binding) => binding.type === "assets") && !options.output.assetsDirectory) throw new Error("The Cloudflare Worker has an assets binding without verified assets.");
2138
+ const modules = [];
2139
+ for (const [name, entry] of Object.entries(config.manifest.modules)) {
2140
+ const type = moduleContentTypes[entry.type];
2141
+ if (!type || name.startsWith("/") || name.split("/").includes("..")) throw new Error(`Cloudflare Worker module ${name} cannot be uploaded with pinned secrets.`);
2142
+ modules.push({
2143
+ name,
2144
+ content_type: type,
2145
+ content_base64: readFileSync(join(getWorkerBundleDir(options.output.directory), name)).toString("base64")
2146
+ });
2147
+ }
2148
+ const accountUrl = `${options.apiBaseUrl.replace(/\/$/, "")}/accounts/${encodeURIComponent(options.accountId)}`;
2149
+ const jwt = await uploadAssets({
2150
+ output: options.output,
2151
+ accountUrl,
2152
+ workerName: options.workerName,
2153
+ token: options.token,
2154
+ verifyUploader: options.verifyUploader
2155
+ });
2156
+ const uploaded = await apiResult(`${accountUrl}/workers/workers/${encodeURIComponent(options.workerName)}/versions${options.atomic ? "?deploy=true" : ""}`, options.token, "POST", {
2157
+ main_module: config.manifest.mainModule,
2158
+ modules,
2159
+ compatibility_date: config.compatibilityDate,
2160
+ compatibility_flags: config.compatibilityFlags,
2161
+ bindings,
2162
+ ...exports ? { exports } : {},
2163
+ ...jwt ? { assets: {
2164
+ jwt,
2165
+ ...assetConfig ? { config: assetConfig } : {}
2166
+ } } : {},
2167
+ annotations: { "workers/message": options.message ?? "" }
2168
+ }, options.verifyUploader);
2169
+ return {
2170
+ id: requiredString(uploaded.id, "Worker Version ID"),
2171
+ urls: Array.isArray(uploaded.urls) ? uploaded.urls.filter((url) => typeof url === "string") : []
2172
+ };
2173
+ }
2174
+ //#endregion
1860
2175
  //#region src/cli/cf-version-runner.ts
1861
2176
  function failed(message) {
1862
2177
  return {
@@ -1885,7 +2200,19 @@ function safePositional(value) {
1885
2200
  return code < 32 || code === 127;
1886
2201
  });
1887
2202
  }
1888
- /** Pin opaque secrets to the live version in the private, disposable Build Output. */
2203
+ /** Existing-Worker handoffs retain their separate link and binding checks. */
2204
+ function createActiveSecretPinner(options) {
2205
+ const { output } = options;
2206
+ if (!output || options.handoffPending) return;
2207
+ return (activeVersionId, bindings) => pinActiveWorkerSecrets({
2208
+ output,
2209
+ activeVersionId,
2210
+ bindings,
2211
+ requiredNames: options.requiredNames,
2212
+ explicitNames: options.explicitNames
2213
+ });
2214
+ }
2215
+ /** Record the live secret source for the version-aware API uploader. */
1889
2216
  async function pinActiveWorkerSecrets(options) {
1890
2217
  const { activeVersionId, bindings, requiredNames, explicitNames = [] } = options;
1891
2218
  if (!/^[0-9a-f]{8}-(?:[0-9a-f]{4}-){3}[0-9a-f]{12}$/i.test(activeVersionId)) return false;
@@ -1896,31 +2223,17 @@ async function pinActiveWorkerSecrets(options) {
1896
2223
  const path = getWorkerConfigPath(options.output.directory);
1897
2224
  const worker = parseJson(readFileSync(path, "utf8"));
1898
2225
  if (!record(worker) || worker.env !== void 0 && !record(worker.env)) return false;
1899
- const env = { ...worker.env ?? {} };
1900
- for (const name of explicit) delete env[name];
2226
+ const env = worker.env ?? {};
1901
2227
  for (const [name, value] of Object.entries(env)) if (record(value) && (value.type === "secret" || value.type === "inherit" || value.type === "unsafe:inherit") && !secretNames.has(name) && !explicit.has(name)) return false;
1902
2228
  for (const { name } of bindings) {
1903
2229
  if (explicit.has(name)) continue;
1904
2230
  const current = env[name];
1905
2231
  if (current !== void 0 && (!record(current) || current.type !== "secret" && current.type !== "inherit" && current.type !== "unsafe:inherit")) return false;
1906
- env[name] = {
1907
- type: "unsafe:inherit",
1908
- version_id: activeVersionId
1909
- };
1910
2232
  }
1911
- const unsafe = record(worker.unsafe) ? { ...worker.unsafe } : {};
1912
- const metadata = record(unsafe.metadata) ? { ...unsafe.metadata } : {};
1913
- if (metadata.bindings !== void 0) return false;
1914
- if (metadata.keep_bindings !== void 0 && (!Array.isArray(metadata.keep_bindings) || !metadata.keep_bindings.every((type) => typeof type === "string"))) return false;
1915
- metadata.keep_bindings = (metadata.keep_bindings ?? []).filter((type) => type !== "secret_text" && type !== "secret_key");
1916
- unsafe.metadata = metadata;
1917
- const next = {
1918
- ...worker,
1919
- env,
1920
- unsafe
2233
+ options.output.activeSecrets = {
2234
+ versionId: activeVersionId,
2235
+ bindings: [...bindings]
1921
2236
  };
1922
- writeFileSync(path, JSON.stringify(next), { mode: 384 });
1923
- await readBuildOutput(options.output.directory);
1924
2237
  return true;
1925
2238
  }
1926
2239
  /** Prevent cf's prebuilt uploader from creating a resource as a side effect. */
@@ -2077,6 +2390,32 @@ function createCfVersionRunner(options) {
2077
2390
  return failed("Cloudflare resources could not be verified before upload.");
2078
2391
  }
2079
2392
  };
2393
+ const uploadPinnedVersion = async (args, atomic) => {
2394
+ if (!options.pinnedUpload || !options.pinnedUpload.verifyUploader()) return failed("The version-aware Cloudflare uploader is unavailable.");
2395
+ const token = await options.pinnedUpload.getToken();
2396
+ if (!token) return failed("Cloudflare session has no bearer for version-aware upload.");
2397
+ try {
2398
+ const version = await uploadPinnedCloudflareVersion({
2399
+ output,
2400
+ accountId: options.pinnedUpload.accountId,
2401
+ apiBaseUrl: options.pinnedUpload.apiBaseUrl,
2402
+ workerName,
2403
+ token,
2404
+ ...flag(args, "--message") ? { message: flag(args, "--message") } : {},
2405
+ ...flag(args, "--secrets-file") ? { secretsFilePath: flag(args, "--secrets-file") } : {},
2406
+ atomic,
2407
+ verifyUploader: options.pinnedUpload.verifyUploader
2408
+ });
2409
+ const preview = version.urls.find((url) => /^https:\/\//.test(url));
2410
+ return {
2411
+ status: 0,
2412
+ stdout: `Worker Version ID: ${version.id}\n${preview ? `Version Preview URL: ${preview}\n` : ""}`,
2413
+ stderr: ""
2414
+ };
2415
+ } catch (cause) {
2416
+ return failed(cause instanceof Error ? cause.message : "Cloudflare version upload failed.");
2417
+ }
2418
+ };
2080
2419
  return async (args, command) => {
2081
2420
  if (args[0] === "deployments" && args[1] === "status") {
2082
2421
  const result = await run([
@@ -2172,6 +2511,7 @@ function createCfVersionRunner(options) {
2172
2511
  if (flag(args, "--name") !== workerName || args.includes("--assets") && flag(args, "--assets") !== output.assetsDirectory) return failed("The Cloudflare version upload target changed.");
2173
2512
  const verified = await verifyResources(output.directory);
2174
2513
  if (verified.status !== 0 || verified.signal || verified.error) return verified;
2514
+ if (output.activeSecrets) return uploadPinnedVersion(args, false);
2175
2515
  return run([
2176
2516
  "workers",
2177
2517
  "versions",
@@ -2216,6 +2556,7 @@ function createCfVersionRunner(options) {
2216
2556
  if (flag(args, "--name") !== workerName || args.includes("--assets") && flag(args, "--assets") !== output.assetsDirectory) return failed("The Cloudflare bootstrap target changed.");
2217
2557
  const verified = await verifyResources(output.directory);
2218
2558
  if (verified.status !== 0 || verified.signal || verified.error) return verified;
2559
+ if (output.activeSecrets) return uploadPinnedVersion(args, true);
2219
2560
  return run([
2220
2561
  "deploy",
2221
2562
  "--prebuilt",
@@ -7492,6 +7833,12 @@ async function runCloudflareDeploy(root, options, cliLog, deps = {}) {
7492
7833
  output: cfOutput,
7493
7834
  workerName,
7494
7835
  runCf: cfCommand,
7836
+ pinnedUpload: {
7837
+ accountId,
7838
+ apiBaseUrl,
7839
+ getToken: () => runWranglerAuthToken(runWrangler, generatedConfigPath),
7840
+ verifyUploader: cfUploaderIsPinned
7841
+ },
7495
7842
  verifyResources: createCfResourceVerifier({
7496
7843
  configPath: generatedConfigPath,
7497
7844
  runCf: cfCommand,
@@ -7499,6 +7846,12 @@ async function runCloudflareDeploy(root, options, cliLog, deps = {}) {
7499
7846
  verifyCompatibilityRunner: assertUploaderStillPinned
7500
7847
  })
7501
7848
  }) : runWrangler;
7849
+ const pinActiveSecrets = createActiveSecretPinner({
7850
+ output: cfOutput,
7851
+ handoffPending: pinnedHandoffLink !== null,
7852
+ requiredNames: schemaFacts.requiredKeys,
7853
+ ...initialAuthSecret ? { explicitNames: [BETTER_AUTH_SECRET_NAME] } : {}
7854
+ });
7502
7855
  const execution = await activateCloudflareVersionWithProgress(deps.activateVersion ?? activateCloudflareVersion, {
7503
7856
  runWrangler: activationRunner,
7504
7857
  verifyUploader: cfOutput ? cfUploaderIsPinned : assertUploaderStillPinned,
@@ -7545,13 +7898,7 @@ async function runCloudflareDeploy(root, options, cliLog, deps = {}) {
7545
7898
  previousTrafficConfig: readWranglerPublishedTrafficSnapshot(configPath),
7546
7899
  queueConsumerCleanup,
7547
7900
  verifyInheritedSecrets: true,
7548
- ...cfOutput && existingWorker && !pinnedHandoffLink ? { pinActiveSecrets: (activeVersionId, bindings) => pinActiveWorkerSecrets({
7549
- output: cfOutput,
7550
- activeVersionId,
7551
- bindings,
7552
- requiredNames: schemaFacts.requiredKeys,
7553
- ...initialAuthSecret ? { explicitNames: [BETTER_AUTH_SECRET_NAME] } : {}
7554
- }) } : {},
7901
+ ...pinActiveSecrets ? { pinActiveSecrets } : {},
7555
7902
  atomic,
7556
7903
  ...initialAuthSecret ? { candidateSecrets: { [BETTER_AUTH_SECRET_NAME]: initialAuthSecret } } : {}
7557
7904
  }).finally(() => cfOutput?.dispose());
@@ -7971,6 +8318,12 @@ async function runCloudflareStaticDeploy(root, options, voidConfig, preset, cliL
7971
8318
  output: cfOutput,
7972
8319
  workerName,
7973
8320
  runCf: cfCommand,
8321
+ pinnedUpload: {
8322
+ accountId,
8323
+ apiBaseUrl,
8324
+ getToken: () => runWranglerAuthToken(runWrangler, staticConfigPath),
8325
+ verifyUploader: cfUploaderIsPinned
8326
+ },
7974
8327
  verifyResources: createCfResourceVerifier({
7975
8328
  configPath: staticConfigPath,
7976
8329
  runCf: cfCommand,
@@ -1,2 +1,2 @@
1
- import { A as parseRootWranglerConfig, J as runDeploy, f as checkWranglerMigrationApplySet } from "./deploy-F1exK5F4.mjs";
1
+ import { A as parseRootWranglerConfig, J as runDeploy, f as checkWranglerMigrationApplySet } from "./deploy-CAOwIvwP.mjs";
2
2
  export { checkWranglerMigrationApplySet, parseRootWranglerConfig, runDeploy };
@@ -1,6 +1,6 @@
1
1
  import { a as join } from "./dist-BVqXeR_h.mjs";
2
2
  import { c as import_picocolors, i as createSpinner } from "./output-CCH48AMM.mjs";
3
- import { L as resolveDeployTransport, O as isWranglerNonInteractiveOrCI, X as runWranglerAuthToken, _ as deriveWorkerName, _t as findEmailConfigConflicts, bt as renderEmailChecklist, gt as createNodeEmailDns, h as createDeployWranglerRunner, ht as applyEmailSetup, k as loadProvisionModule, v as discoverRootWranglerConfig, vt as preflightEmail, yt as renderAddressMap } from "./deploy-F1exK5F4.mjs";
3
+ import { L as resolveDeployTransport, O as isWranglerNonInteractiveOrCI, X as runWranglerAuthToken, _ as deriveWorkerName, _t as findEmailConfigConflicts, bt as renderEmailChecklist, gt as createNodeEmailDns, h as createDeployWranglerRunner, ht as applyEmailSetup, k as loadProvisionModule, v as discoverRootWranglerConfig, vt as preflightEmail, yt as renderAddressMap } from "./deploy-CAOwIvwP.mjs";
4
4
  import { n as readProjectPaths } from "./project-paths-GgcMozYz.mjs";
5
5
  import { c as getToken, d as openBrowser } from "./auth-DLNN0D3Z.mjs";
6
6
  import { o as readProjectConfig } from "./project-C0Fqu05O.mjs";
package/dist/index.mjs CHANGED
@@ -1,7 +1,7 @@
1
1
  import { n as __toESM } from "./rolldown-runtime-DXIUcv95.mjs";
2
2
  import { a as join, l as relative, n as dirname, u as resolve } from "./dist-BVqXeR_h.mjs";
3
3
  import { d as require_picocolors } from "./output-CCH48AMM.mjs";
4
- import { G as resolveWorkerDirName, St as hasDocumentRoutes, V as resolveDistDir, ct as prerenderPagesNode, dt as collectRevalidate, ft as hasRevalidate, mt as SEND_EMAIL_BINDING, ot as generateQueueResolverSource, pt as scanDurableObjectModules, st as prerenderPages, ut as collectPages, wt as resolveAssetRoutingPolicy, xt as hasApiRoutes } from "./deploy-F1exK5F4.mjs";
4
+ import { G as resolveWorkerDirName, St as hasDocumentRoutes, V as resolveDistDir, ct as prerenderPagesNode, dt as collectRevalidate, ft as hasRevalidate, mt as SEND_EMAIL_BINDING, ot as generateQueueResolverSource, pt as scanDurableObjectModules, st as prerenderPages, ut as collectPages, wt as resolveAssetRoutingPolicy, xt as hasApiRoutes } from "./deploy-CAOwIvwP.mjs";
5
5
  import { i as resolveProjectPaths, n as readProjectPaths, t as assertNoRootSourceConventionConflicts } from "./project-paths-GgcMozYz.mjs";
6
6
  import { n as loadVoidAuthConfig, t as findVoidAuthConfig } from "./config-DPByhVck.mjs";
7
7
  import { r as scopedAccessCredentials } from "./cf-access-DRsQRe6k.mjs";
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "void",
3
- "version": "0.21.4",
3
+ "version": "0.21.6",
4
4
  "repository": {
5
5
  "type": "git",
6
6
  "url": "git+https://github.com/voidzero-dev/void.git",
@@ -325,11 +325,11 @@
325
325
  "@cloudflare/vite-plugin": "1.54.7",
326
326
  "@cloudflare/workers-types": "^4.20260702.1",
327
327
  "@napi-rs/keyring": "2.0.0",
328
- "@void/deploy-cloudflare": "0.21.4",
329
- "@void/deploy-core": "0.21.4",
330
- "@void/edge": "0.21.4",
331
- "@void/isr": "0.21.4",
332
- "@void/platform": "0.21.4",
328
+ "@void/deploy-cloudflare": "0.21.6",
329
+ "@void/deploy-core": "0.21.6",
330
+ "@void/edge": "0.21.6",
331
+ "@void/isr": "0.21.6",
332
+ "@void/platform": "0.21.6",
333
333
  "acorn": "^8.15.0",
334
334
  "better-auth": "^1.7.3",
335
335
  "better-sqlite3": "^13.0.3",
@@ -379,7 +379,7 @@
379
379
  "zod": "^4.6.1"
380
380
  },
381
381
  "peerDependencies": {
382
- "@void/md": "0.21.4",
382
+ "@void/md": "0.21.6",
383
383
  "arktype": ">=2.0.0",
384
384
  "valibot": ">=1.0.0-beta.7",
385
385
  "vite": "^8.0.0",