@vinext/cloudflare 1.0.0-beta.8 → 1.0.0-beta.9
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 +9 -0
- package/dist/cache/cdn-adapter.worker.d.ts +1 -0
- package/dist/cache/cdn-adapter.worker.js +6 -4
- package/dist/cache/kv-data-adapter.d.ts +4 -0
- package/dist/cache/kv-data-adapter.js +5 -1
- package/dist/cache/response-store-adapter.d.ts +33 -0
- package/dist/cache/response-store-adapter.js +7 -1
- package/dist/cache/response-store-adapter.self-contained.worker.d.ts +1 -0
- package/dist/cache/response-store-adapter.self-contained.worker.js +3 -1
- package/dist/cache/response-store-adapter.service-binding.worker.d.ts +1 -0
- package/dist/cache/response-store-adapter.service-binding.worker.js +3 -1
- package/dist/cache/response-store-adapter.worker.d.ts +1 -1
- package/dist/cache/response-store-adapter.worker.js +48 -38
- package/dist/cdn-warm.d.ts +1 -1
- package/dist/cdn-warm.js +23 -7
- package/dist/deploy-help.js +20 -14
- package/dist/deploy.d.ts +13 -5
- package/dist/deploy.js +175 -99
- package/dist/tpr.d.ts +25 -72
- package/dist/tpr.js +45 -603
- package/dist/version-deploy.js +4 -2
- package/dist/wrangler-config.d.ts +19 -0
- package/dist/wrangler-config.js +294 -0
- package/package.json +4 -8
package/dist/deploy.js
CHANGED
|
@@ -1,7 +1,8 @@
|
|
|
1
1
|
import { writeCacheabilityManifestArtifact } from "./cacheability-artifact.js";
|
|
2
2
|
import { DEFAULT_CACHEABILITY_PROBE_RETRY_DELAY_MS, probeStagedWorkerCacheability, readPrerenderSecret } from "./cacheability-probe.js";
|
|
3
3
|
import { CdnOperationProgress, createCdnWarmTargets, createPrerenderWarmPlan, waitForCdnWarmTargetReadiness, warmCdnCache } from "./cdn-warm.js";
|
|
4
|
-
import { parseWranglerConfig
|
|
4
|
+
import { parseWranglerConfig } from "./wrangler-config.js";
|
|
5
|
+
import { resolveTPRRoutes, selectRoutes } from "./tpr.js";
|
|
5
6
|
import { VINEXT_EXPECTED_WORKER_VERSION_HEADER } from "./version-headers.js";
|
|
6
7
|
import { formatImageOptimizationHint, formatMissingCacheAdapterError, resolveCdnAdapterConfig, resolveKvDataAdapterConfig, viteConfigHasCacheAdapter, viteConfigHasCloudflarePlugin, viteConfigHasImageAdapter, workerEntryHasCacheHandler } from "./deploy-config.js";
|
|
7
8
|
import { assertCdnVersionMetadataConfig } from "./wrangler-version-metadata.js";
|
|
@@ -14,6 +15,7 @@ import path from "node:path";
|
|
|
14
15
|
import { cacheabilityRoutePathname } from "vinext/internal/server/cacheability-manifest";
|
|
15
16
|
import { setTimeout } from "node:timers/promises";
|
|
16
17
|
import { DEFAULT_REMOTE_PATH_DISCOVERY_PHASE_TIMEOUT_MS, DEFAULT_REMOTE_PATH_DISCOVERY_RETRY_DELAY_MS, discoverPrerenderPathManifest, emitPrerenderPathManifest } from "vinext/internal/build/prerender-paths";
|
|
18
|
+
import { normalizePathTrailingSlash } from "vinext/shims/url-utils";
|
|
17
19
|
import os from "node:os";
|
|
18
20
|
import { spawn } from "node:child_process";
|
|
19
21
|
import { parseArgs } from "node:util";
|
|
@@ -21,7 +23,7 @@ import { pathToFileURL } from "node:url";
|
|
|
21
23
|
import { runPrerender } from "vinext/internal/build/run-prerender";
|
|
22
24
|
import { loadDotenv } from "vinext/internal/config/dotenv";
|
|
23
25
|
import { findVinextNextConfigInPlugins, loadNextConfig, resolveNextConfig, resolveNextConfigInput } from "vinext/internal/config/next-config";
|
|
24
|
-
import { findVinextCacheConfigInPlugins, findVinextPrerenderConfigInPlugins, findVinextRouteRootConfigInPlugins, formatVinextPrerenderLabel, hasBuildIdentityResponseHeader, hasUncachedRequestRouting, hasVerbatimResponseVary, isConfiguredCdnResponsePolicyHeader, requiresRouteCacheabilityProbeManifest, resolveVinextPrerenderDecision, supportsCanonicalRscWarmup
|
|
26
|
+
import { cacheWarmupStatusSource, findVinextCacheConfigInPlugins, findVinextPrerenderConfigInPlugins, findVinextRouteRootConfigInPlugins, formatVinextPrerenderLabel, hasBuildIdentityResponseHeader, hasUncachedRequestRouting, hasVerbatimResponseVary, isConfiguredCdnResponsePolicyHeader, requiresRouteCacheabilityProbeManifest, resolveVinextPrerenderDecision, supportsCanonicalRscWarmup } from "vinext/internal/config/prerender";
|
|
25
27
|
import { detectProject, findInNodeModules, formatMissingCloudflarePluginError, getMissingDeps } from "vinext/internal/utils/project";
|
|
26
28
|
import { PHASE_PRODUCTION_BUILD } from "vinext/shims/constants";
|
|
27
29
|
//#region src/deploy.ts
|
|
@@ -71,6 +73,7 @@ function formatUnknownError(error) {
|
|
|
71
73
|
if (error instanceof Error && error.message) return error.message;
|
|
72
74
|
return String(error);
|
|
73
75
|
}
|
|
76
|
+
var StagedWarmupError = class extends Error {};
|
|
74
77
|
/** Deploy command flag definitions for util.parseArgs. */
|
|
75
78
|
const deployArgOptions = {
|
|
76
79
|
help: {
|
|
@@ -126,6 +129,10 @@ const deployArgOptions = {
|
|
|
126
129
|
type: "boolean",
|
|
127
130
|
default: false
|
|
128
131
|
},
|
|
132
|
+
"no-promote": {
|
|
133
|
+
type: "boolean",
|
|
134
|
+
default: false
|
|
135
|
+
},
|
|
129
136
|
"warm-cdn-no-promote": {
|
|
130
137
|
type: "boolean",
|
|
131
138
|
default: false
|
|
@@ -135,6 +142,13 @@ const deployArgOptions = {
|
|
|
135
142
|
type: "boolean",
|
|
136
143
|
default: false
|
|
137
144
|
},
|
|
145
|
+
"experimental-traffic-aware-warm-cache": {
|
|
146
|
+
type: "boolean",
|
|
147
|
+
default: false
|
|
148
|
+
},
|
|
149
|
+
"traffic-aware-coverage": { type: "string" },
|
|
150
|
+
"traffic-aware-limit": { type: "string" },
|
|
151
|
+
"traffic-aware-window": { type: "string" },
|
|
138
152
|
"experimental-tpr": {
|
|
139
153
|
type: "boolean",
|
|
140
154
|
default: false
|
|
@@ -186,13 +200,13 @@ function parseDeployArgs(args) {
|
|
|
186
200
|
warmCdnReadinessProbes: values["warm-cdn-readiness-probes"] === void 0 ? void 0 : parsePositiveIntegerArg(values["warm-cdn-readiness-probes"], "--warm-cdn-readiness-probes"),
|
|
187
201
|
warmCdnReadinessProbeDelay: values["warm-cdn-readiness-probe-delay"] === void 0 ? void 0 : validateTimerDelay(parseNonNegativeIntegerArg(values["warm-cdn-readiness-probe-delay"], "--warm-cdn-readiness-probe-delay"), "--warm-cdn-readiness-probe-delay", values["warm-cdn-readiness-probe-delay"]),
|
|
188
202
|
dangerouslyPromoteOnCdnWarmError: values["dangerously-promote-on-cdn-warm-error"],
|
|
189
|
-
warmCdnPromote: !values["warm-cdn-no-promote"],
|
|
203
|
+
warmCdnPromote: !values["no-promote"] && !values["warm-cdn-no-promote"],
|
|
190
204
|
warmCdnPromotionDelay: values["warm-cdn-promotion-delay"] === void 0 ? void 0 : validatePromotionDelay(parseNonNegativeIntegerArg(values["warm-cdn-promotion-delay"], "--warm-cdn-promotion-delay"), values["warm-cdn-promotion-delay"]),
|
|
191
205
|
warmCdnIncludeFallbacks: values["warm-cdn-include-fallbacks"],
|
|
192
|
-
experimentalTPR: values["experimental-tpr"],
|
|
193
|
-
tprCoverage: parseIntArg("
|
|
194
|
-
tprLimit: parseIntArg("
|
|
195
|
-
tprWindow: parseIntArg("
|
|
206
|
+
experimentalTPR: values["experimental-traffic-aware-warm-cache"] || values["experimental-tpr"],
|
|
207
|
+
tprCoverage: parseIntArg("traffic-aware-coverage", values["traffic-aware-coverage"] ?? values["tpr-coverage"]),
|
|
208
|
+
tprLimit: parseIntArg("traffic-aware-limit", values["traffic-aware-limit"] ?? values["tpr-limit"]),
|
|
209
|
+
tprWindow: parseIntArg("traffic-aware-window", values["traffic-aware-window"] ?? values["tpr-window"])
|
|
196
210
|
};
|
|
197
211
|
}
|
|
198
212
|
/**
|
|
@@ -387,6 +401,7 @@ async function runWranglerKVBulkPut(root, options, execute = spawn, nodeExecutab
|
|
|
387
401
|
}
|
|
388
402
|
}
|
|
389
403
|
async function runWranglerDeploy(root, options, execute = spawn) {
|
|
404
|
+
if (options.promote === false) return runWranglerVersionUpload(root, options).previewUrl ?? "(Preview URL not detected in wrangler output)";
|
|
390
405
|
const spawnOptions = {
|
|
391
406
|
cwd: root,
|
|
392
407
|
stdio: [
|
|
@@ -427,6 +442,33 @@ async function runWranglerDeploy(root, options, execute = spawn) {
|
|
|
427
442
|
function hasCdnWarmRequests(plan) {
|
|
428
443
|
return plan.paths.length + (plan.pagesDataPaths?.length ?? 0) + (plan.routeHandlerPaths?.length ?? 0) + plan.rscPaths.length + plan.loadingShellPaths.length > 0;
|
|
429
444
|
}
|
|
445
|
+
function selectTPRWarmPlan(plan, traffic, coverage, limit) {
|
|
446
|
+
const canonical = (pathname) => normalizePathTrailingSlash(pathname, false);
|
|
447
|
+
const resolved = new Set(Object.entries(plan.routePatterns ?? {}).map(([pathname, route]) => canonical(route.cacheabilityProbe?.concretePathname ?? pathname)));
|
|
448
|
+
const requestsByPath = /* @__PURE__ */ new Map();
|
|
449
|
+
for (const { path, requests } of traffic) {
|
|
450
|
+
const pathname = canonical(path);
|
|
451
|
+
if (!resolved.has(pathname)) continue;
|
|
452
|
+
requestsByPath.set(pathname, (requestsByPath.get(pathname) ?? 0) + requests);
|
|
453
|
+
}
|
|
454
|
+
const selected = new Set(selectRoutes(Array.from(requestsByPath, ([path, requests]) => ({
|
|
455
|
+
path,
|
|
456
|
+
requests
|
|
457
|
+
})).sort((a, b) => b.requests - a.requests), coverage, limit).routes.map(({ path }) => path));
|
|
458
|
+
const includes = (pathname) => selected.has(canonical(plan.routePatterns?.[pathname]?.cacheabilityProbe?.concretePathname ?? pathname));
|
|
459
|
+
const filter = (pathnames) => pathnames?.filter(includes);
|
|
460
|
+
return {
|
|
461
|
+
...plan,
|
|
462
|
+
appPaths: filter(plan.appPaths),
|
|
463
|
+
loadingShellPaths: filter(plan.loadingShellPaths) ?? [],
|
|
464
|
+
pagesDataPaths: filter(plan.pagesDataPaths),
|
|
465
|
+
pagesPaths: filter(plan.pagesPaths),
|
|
466
|
+
paths: filter(plan.paths) ?? [],
|
|
467
|
+
routeHandlerPaths: filter(plan.routeHandlerPaths),
|
|
468
|
+
routePatterns: plan.routePatterns ? Object.fromEntries(Object.entries(plan.routePatterns).filter(([pathname]) => includes(pathname))) : void 0,
|
|
469
|
+
rscPaths: filter(plan.rscPaths) ?? []
|
|
470
|
+
};
|
|
471
|
+
}
|
|
430
472
|
function projectRequiresRouteCacheabilityProbeManifest(project, cacheConfig) {
|
|
431
473
|
return (project.isAppRouter || project.isPagesRouter) && requiresRouteCacheabilityProbeManifest(cacheConfig);
|
|
432
474
|
}
|
|
@@ -493,10 +535,11 @@ async function deployUploadedVersionWithCdnWarmup(root, paths, options) {
|
|
|
493
535
|
};
|
|
494
536
|
const discoverWarmPlan = async (targetUrl, headers) => {
|
|
495
537
|
if (!options.discoverWarmPlan) return;
|
|
496
|
-
const
|
|
538
|
+
const discovered = await options.discoverWarmPlan({
|
|
497
539
|
headers,
|
|
498
540
|
targetUrl
|
|
499
541
|
});
|
|
542
|
+
const plan = options.selectWarmPlan?.(discovered) ?? discovered;
|
|
500
543
|
deploymentId = plan.deploymentId;
|
|
501
544
|
expectedBuildId = plan.buildIdentity;
|
|
502
545
|
expectedRscBuildId = plan.rscBuildId;
|
|
@@ -542,10 +585,16 @@ async function deployUploadedVersionWithCdnWarmup(root, paths, options) {
|
|
|
542
585
|
statusSource: options.statusSource
|
|
543
586
|
});
|
|
544
587
|
const wranglerConfig = parseWranglerConfig(root, options.config);
|
|
545
|
-
|
|
546
|
-
|
|
588
|
+
let deploymentStatus;
|
|
589
|
+
try {
|
|
590
|
+
deploymentStatus = runWranglerDeploymentStatus(root, options);
|
|
591
|
+
} catch (error) {
|
|
592
|
+
if (!hasPreparedWarmPlan) throw error;
|
|
593
|
+
throw new StagedWarmupError(formatUnknownError(error), { cause: error });
|
|
594
|
+
}
|
|
595
|
+
if (options.expectedDeploymentState && !deploymentStateEquals(deploymentStatus, options.expectedDeploymentState)) throw new StagedWarmupError("Two-stage CDN warming stopped because Worker deployment traffic or deployment identity changed before the final version could be staged. No final version was promoted.");
|
|
547
596
|
const stagingTraffic = getZeroPercentStagingTraffic(deploymentStatus, upload.versionId);
|
|
548
|
-
if (hasPreparedWarmPlan && !stagingTraffic) throw new
|
|
597
|
+
if (hasPreparedWarmPlan && !stagingTraffic) throw new StagedWarmupError("Two-stage CDN warming stopped because Worker deployment traffic changed before the final version could be staged. No final version was promoted.");
|
|
549
598
|
let staged = null;
|
|
550
599
|
let triggersDeployedUrl = options.triggersDeployedUrl ?? null;
|
|
551
600
|
let stagedCacheFilled = false;
|
|
@@ -637,7 +686,7 @@ async function deployUploadedVersionWithCdnWarmup(root, paths, options) {
|
|
|
637
686
|
routeHandlerPaths: warmResult.retryPlan.routeHandlerPaths,
|
|
638
687
|
rscPaths: warmResult.retryPlan.rscPaths
|
|
639
688
|
};
|
|
640
|
-
if (
|
|
689
|
+
if (options.warmCdnCertify && warmResult.warmed > 0) {
|
|
641
690
|
console.log(` CDN warmup: certifying ${warmResult.warmed} staged cache entr${warmResult.warmed === 1 ? "y" : "ies"} before promotion...`);
|
|
642
691
|
const certification = await warmUploadedVersion(targetUrl, headers, true, warmResult.warmedPlan, true);
|
|
643
692
|
if (certification.warmed !== warmResult.warmed) throw new Error(`CDN warmup certified ${certification.warmed}/${warmResult.warmed} staged cache entries as reusable.`);
|
|
@@ -650,7 +699,7 @@ async function deployUploadedVersionWithCdnWarmup(root, paths, options) {
|
|
|
650
699
|
}
|
|
651
700
|
else if (initialWarmRequests > 0) {
|
|
652
701
|
const message = "CDN warmup failed: pre-traffic warmup needs a production URL and Worker name for version overrides. Configure a route/custom domain and Worker name, or deploy without --experimental-warm-cdn-cache.";
|
|
653
|
-
if (!allowUnverifiedPromotion) throw new
|
|
702
|
+
if (!allowUnverifiedPromotion) throw new StagedWarmupError(`${message} ${getStagedVersionCleanupNote()}`);
|
|
654
703
|
console.warn(` ${message} Promoting because the dangerous override is enabled.`);
|
|
655
704
|
}
|
|
656
705
|
} else {
|
|
@@ -665,19 +714,18 @@ async function deployUploadedVersionWithCdnWarmup(root, paths, options) {
|
|
|
665
714
|
if (options.warmCdnPromote === false) {
|
|
666
715
|
if (!staged) throw new Error("CDN warmup cannot skip promotion because the uploaded Worker version could not be staged at 0% traffic. The current deployment must have exactly one version serving 100% traffic.");
|
|
667
716
|
const remainingWarmRequests = countRemainingWarmRequests();
|
|
668
|
-
if (!hasPreparedWarmPlan && options.discoverWarmPlan && discoveredWarmRequests === 0) throw withStagedVersionCleanupNote(/* @__PURE__ */ new Error("CDN warmup cannot skip promotion because no build-discovered requests were found to warm."));
|
|
717
|
+
if (!options.allowEmptyWarmPlan && !hasPreparedWarmPlan && options.discoverWarmPlan && discoveredWarmRequests === 0) throw withStagedVersionCleanupNote(/* @__PURE__ */ new Error("CDN warmup cannot skip promotion because no build-discovered requests were found to warm."));
|
|
669
718
|
if (remainingWarmRequests > 0) throw withStagedVersionCleanupNote(/* @__PURE__ */ new Error(`CDN warmup cannot skip promotion because ${remainingWarmRequests} request(s) remain unwarmed.`));
|
|
670
719
|
if (hasPreparedWarmPlan && stagedDeploymentState) {
|
|
671
720
|
let currentDeployment;
|
|
672
721
|
try {
|
|
673
722
|
currentDeployment = runWranglerDeploymentStatus(root, options);
|
|
674
723
|
} catch (error) {
|
|
675
|
-
|
|
676
|
-
throw new Error(`${message} CDN warmup cannot confirm that the uploaded Worker remains staged at 0% traffic; production Worker triggers/routes remain applied. Inspect \`wrangler deployments status\` before continuing.`, { cause: error });
|
|
724
|
+
throw new StagedWarmupError(`${error instanceof Error ? error.message : String(error)} CDN warmup cannot confirm that the uploaded Worker remains staged at 0% traffic; production Worker triggers/routes remain applied. Inspect \`wrangler deployments status\` before continuing.`, { cause: error });
|
|
677
725
|
}
|
|
678
|
-
if (!deploymentStateEquals(currentDeployment, stagedDeploymentState)) throw new
|
|
726
|
+
if (!deploymentStateEquals(currentDeployment, stagedDeploymentState)) throw new StagedWarmupError("Two-stage CDN warming stopped because Worker deployment traffic or deployment identity changed before the no-promote handoff. The uploaded Worker is not confirmed staged at 0% traffic; production Worker triggers/routes remain applied.");
|
|
679
727
|
}
|
|
680
|
-
console.log(
|
|
728
|
+
console.log(` CDN warmup: promotion disabled; uploaded Worker version ${upload.versionId} remains staged at 0% traffic and production Worker triggers/routes remain applied.`);
|
|
681
729
|
return staged.deployedUrl ?? triggersDeployedUrl ?? upload.previewUrl ?? "(URL not detected in wrangler output)";
|
|
682
730
|
}
|
|
683
731
|
let deployed;
|
|
@@ -752,15 +800,19 @@ function deploymentStateEquals(actual, expected) {
|
|
|
752
800
|
function reconcileVersionDeployFailure(root, options, error, expected) {
|
|
753
801
|
const message = error instanceof Error ? error.message : String(error);
|
|
754
802
|
let reconciliation;
|
|
803
|
+
let mayNeedCleanup = true;
|
|
755
804
|
try {
|
|
756
805
|
const current = runWranglerDeploymentStatus(root, options);
|
|
757
806
|
if (deploymentTrafficEquals(current.versions, expected.desiredTraffic)) reconciliation = expected.desiredDescription;
|
|
758
|
-
else if (deploymentStateEquals(current, expected.priorState))
|
|
759
|
-
|
|
807
|
+
else if (deploymentStateEquals(current, expected.priorState)) {
|
|
808
|
+
reconciliation = expected.priorDescription;
|
|
809
|
+
mayNeedCleanup = false;
|
|
810
|
+
} else reconciliation = "Worker deployment state differs from both the requested and prior state, so the deployment outcome is unknown or another deployment changed it.";
|
|
760
811
|
} catch (reconciliationError) {
|
|
761
812
|
reconciliation = `Worker deployment status could not be read after the command failed, so the deployment outcome is unknown (${reconciliationError instanceof Error ? reconciliationError.message : String(reconciliationError)}).`;
|
|
762
813
|
}
|
|
763
|
-
|
|
814
|
+
const detail = `${message} ${reconciliation}`;
|
|
815
|
+
return mayNeedCleanup ? new StagedWarmupError(detail, { cause: error }) : new Error(detail, { cause: error });
|
|
764
816
|
}
|
|
765
817
|
function assertDeploymentStateUnchanged(root, options, expected, message) {
|
|
766
818
|
if (!deploymentStateEquals(runWranglerDeploymentStatus(root, options), expected)) throw new Error(message);
|
|
@@ -788,8 +840,7 @@ async function deployWithCacheabilityProbe(root, options) {
|
|
|
788
840
|
stagedProbeDeployment = runWranglerDeploymentStatus(root, options);
|
|
789
841
|
if (!deploymentTrafficEquals(stagedProbeDeployment.versions, probeTraffic)) throw new Error("Two-stage CDN warming stopped because Worker deployment traffic changed immediately after the probe version was staged.");
|
|
790
842
|
} catch (error) {
|
|
791
|
-
|
|
792
|
-
throw new Error(`${message} The probe staging command completed, but its current deployment state could not be confirmed; production Worker triggers/routes were not changed. Inspect \`wrangler deployments status\` and remove the staged probe version if necessary.`, { cause: error });
|
|
843
|
+
throw new StagedWarmupError(`${error instanceof Error ? error.message : String(error)} The probe staging command completed, but its current deployment state could not be confirmed; production Worker triggers/routes were not changed. Inspect \`wrangler deployments status\` and remove the staged probe version if necessary.`, { cause: error });
|
|
793
844
|
}
|
|
794
845
|
let prepared;
|
|
795
846
|
try {
|
|
@@ -885,6 +936,7 @@ async function deployWithCacheabilityProbe(root, options) {
|
|
|
885
936
|
routeHandlerPaths: probe.cacheableTargets.filter((target) => target.kind === "app-route").map((target) => target.sourcePathname),
|
|
886
937
|
rscPaths: probe.cacheableTargets.filter((target) => target.kind === "rsc-full").map((target) => target.sourcePathname)
|
|
887
938
|
};
|
|
939
|
+
const selectedFinalPlan = options.selectWarmPlan?.(finalPlan) ?? finalPlan;
|
|
888
940
|
assertDeploymentStateUnchanged(root, options, stagedProbeDeployment, "Two-stage CDN warming stopped because Worker deployment traffic or deployment identity changed while cacheability was being probed. No final version was promoted.");
|
|
889
941
|
const finalConfig = writeCacheabilityManifestArtifact(root, options.config, probe.manifest);
|
|
890
942
|
const finalUpload = runWranglerVersionUpload(root, {
|
|
@@ -897,7 +949,7 @@ async function deployWithCacheabilityProbe(root, options) {
|
|
|
897
949
|
prepared = {
|
|
898
950
|
optionalWarmTargetKeys: new Set(probe.speculativeTargets.map(cdnWarmTargetKey)),
|
|
899
951
|
prerenderSecret,
|
|
900
|
-
plan:
|
|
952
|
+
plan: selectedFinalPlan,
|
|
901
953
|
upload: finalUpload
|
|
902
954
|
};
|
|
903
955
|
} catch (error) {
|
|
@@ -952,12 +1004,10 @@ function buildVersionOverrideHeaders(workerName, versionId) {
|
|
|
952
1004
|
};
|
|
953
1005
|
}
|
|
954
1006
|
function withStagedVersionCleanupNote(error) {
|
|
955
|
-
|
|
956
|
-
return new Error(`${message} ${getStagedVersionCleanupNote()}`, { cause: error });
|
|
1007
|
+
return new StagedWarmupError(`${error instanceof Error ? error.message : String(error)} ${getStagedVersionCleanupNote()}`, { cause: error });
|
|
957
1008
|
}
|
|
958
1009
|
function withStagedProbeVersionCleanupNote(error) {
|
|
959
|
-
|
|
960
|
-
return new Error(`${message} The probe version may remain staged at 0% with the previous version still serving 100% traffic; production Worker triggers/routes were not changed.`, { cause: error });
|
|
1010
|
+
return new StagedWarmupError(`${error instanceof Error ? error.message : String(error)} The probe version may remain staged at 0% with the previous version still serving 100% traffic; production Worker triggers/routes were not changed.`, { cause: error });
|
|
961
1011
|
}
|
|
962
1012
|
function getStagedVersionCleanupNote() {
|
|
963
1013
|
return "The uploaded version may remain staged at 0% with the previous version still serving 100% traffic; Worker triggers/routes may also have changed because trigger deployment runs before warming. Rerun deploy to promote it or use `wrangler versions deploy` to choose the desired version split.";
|
|
@@ -1020,15 +1070,46 @@ async function deploy(options) {
|
|
|
1020
1070
|
nextOutput: nextConfig.output
|
|
1021
1071
|
});
|
|
1022
1072
|
const hasStrictResponseVary = hasVerbatimResponseVary(viteConfigMetadata.cacheConfig);
|
|
1023
|
-
const
|
|
1073
|
+
const warmupStatusSource = cacheWarmupStatusSource(viteConfigMetadata.cacheConfig);
|
|
1074
|
+
const hasStagedRequestRouting = hasUncachedRequestRouting(viteConfigMetadata.cacheConfig) || warmupStatusSource === "data-cache";
|
|
1024
1075
|
const hasBuildIdentityHeader = hasBuildIdentityResponseHeader(viteConfigMetadata.cacheConfig);
|
|
1025
1076
|
const hasCanonicalRscWarmup = supportsCanonicalRscWarmup(viteConfigMetadata.cacheConfig);
|
|
1026
|
-
const hasVinextCacheWarmupStatus = usesVinextCacheWarmupStatus(viteConfigMetadata.cacheConfig);
|
|
1027
1077
|
const needsCacheabilityProbeManifest = projectRequiresRouteCacheabilityProbeManifest(info, viteConfigMetadata.cacheConfig);
|
|
1028
1078
|
const shouldEmitPrerenderPathManifest = !options.skipBuild && prerenderDecision;
|
|
1029
1079
|
if (!options.skipBuild) await runBuild(info, buildEnv);
|
|
1030
1080
|
else console.log("\n Skipping build (--skip-build)");
|
|
1031
|
-
|
|
1081
|
+
const canWarmTpr = options.experimentalTPR && !prerenderDecision && hasBuildIdentityHeader;
|
|
1082
|
+
if (options.experimentalTPR && prerenderDecision) console.log(" TPR: Skipping route selection (all-route prerendering configured)");
|
|
1083
|
+
else if (options.experimentalTPR && !hasBuildIdentityHeader) console.log(workerEntryHasCacheHandler(root) ? " TPR: Skipping pre-warm (legacy imperative cache handlers must migrate to declarative vinext({ cache }) for standard warming)" : " TPR: Skipping pre-warm (configured cache does not expose build identity)");
|
|
1084
|
+
const tpr = canWarmTpr ? await resolveTPRRoutes({
|
|
1085
|
+
root,
|
|
1086
|
+
config: options.config,
|
|
1087
|
+
env: buildEnv,
|
|
1088
|
+
hostname: warmCdnTarget ? new URL(warmCdnTarget).hostname : void 0,
|
|
1089
|
+
window: Math.max(1, options.tprWindow ?? 24)
|
|
1090
|
+
}) : null;
|
|
1091
|
+
if (tpr?.skipped) console.log(` TPR: Skipped (${tpr.skipped})`);
|
|
1092
|
+
const tprRoutes = tpr?.routes ?? [];
|
|
1093
|
+
const wranglerOptions = {
|
|
1094
|
+
env: deployEnv === "production" && !options.env ? void 0 : deployEnv,
|
|
1095
|
+
name: options.name,
|
|
1096
|
+
config: options.config,
|
|
1097
|
+
verbose: options.verbose
|
|
1098
|
+
};
|
|
1099
|
+
let shouldWarmTpr = tprRoutes.length > 0;
|
|
1100
|
+
if (shouldWarmTpr && !options.warmCdnCache) {
|
|
1101
|
+
try {
|
|
1102
|
+
shouldWarmTpr = getZeroPercentStagingTraffic(runWranglerDeploymentStatus(root, wranglerOptions), "tpr-preflight") !== null;
|
|
1103
|
+
} catch {
|
|
1104
|
+
shouldWarmTpr = false;
|
|
1105
|
+
}
|
|
1106
|
+
if (!shouldWarmTpr) console.log(" TPR: Skipping pre-warm (current deployment cannot be staged safely)");
|
|
1107
|
+
}
|
|
1108
|
+
const shouldWarmCdnCache = options.warmCdnCache || shouldWarmTpr;
|
|
1109
|
+
const shouldSelectTpr = shouldWarmTpr && !options.warmCdnCache;
|
|
1110
|
+
const candidatePathsOnly = shouldSelectTpr && !needsCacheabilityProbeManifest;
|
|
1111
|
+
const shouldPrerenderLocally = prerenderDecision && (!shouldWarmCdnCache || prerenderDecision.reason === "next-export");
|
|
1112
|
+
if (shouldWarmCdnCache && cdnAdapterConfig) {
|
|
1032
1113
|
const wrangler = await loadProjectWranglerApi(info.root);
|
|
1033
1114
|
const previousCwd = process.cwd();
|
|
1034
1115
|
try {
|
|
@@ -1060,7 +1141,7 @@ async function deploy(options) {
|
|
|
1060
1141
|
routeRootConfig: viteConfigMetadata.routeRootConfig
|
|
1061
1142
|
});
|
|
1062
1143
|
let ranPrerender = false;
|
|
1063
|
-
if (
|
|
1144
|
+
if (shouldPrerenderLocally) {
|
|
1064
1145
|
console.log(`\n ${formatVinextPrerenderLabel(prerenderDecision)}`);
|
|
1065
1146
|
if (nextConfig.enablePrerenderSourceMaps) {
|
|
1066
1147
|
process.setSourceMapsEnabled(true);
|
|
@@ -1079,78 +1160,73 @@ async function deploy(options) {
|
|
|
1079
1160
|
} catch (error) {
|
|
1080
1161
|
console.log(` KV cache: Skipping prerender upload (${formatUnknownError(error)}). Continuing with deploy.`);
|
|
1081
1162
|
}
|
|
1082
|
-
|
|
1083
|
-
|
|
1084
|
-
|
|
1085
|
-
|
|
1086
|
-
|
|
1087
|
-
|
|
1088
|
-
|
|
1089
|
-
|
|
1163
|
+
let url;
|
|
1164
|
+
if (shouldWarmCdnCache) try {
|
|
1165
|
+
url = await deployWithCdnWarmup(root, [], {
|
|
1166
|
+
...wranglerOptions,
|
|
1167
|
+
allowEmptyWarmPlan: tprRoutes.length > 0 && !options.warmCdnCache,
|
|
1168
|
+
cacheabilityProbe: needsCacheabilityProbeManifest,
|
|
1169
|
+
discoverWarmPlan: async ({ headers, targetUrl }) => {
|
|
1170
|
+
const discovery = await discoverPrerenderPathManifest({
|
|
1171
|
+
root: info.root,
|
|
1172
|
+
candidatePaths: tprRoutes.map(({ path }) => path),
|
|
1173
|
+
candidatePathsOnly,
|
|
1174
|
+
nextConfig,
|
|
1175
|
+
buildIdentity: hasBuildIdentityHeader ? "response-header" : void 0,
|
|
1176
|
+
includeCanonicalRsc: hasCanonicalRscWarmup,
|
|
1177
|
+
requestRouting: hasStagedRequestRouting ? "uncached-stage" : void 0,
|
|
1178
|
+
responseVary: hasStrictResponseVary ? "verbatim" : void 0,
|
|
1179
|
+
isResponsePolicyHeader: (name) => isConfiguredCdnResponsePolicyHeader(viteConfigMetadata.cacheConfig, name),
|
|
1180
|
+
routeRootConfig: viteConfigMetadata.routeRootConfig,
|
|
1181
|
+
pathDiscoveryTarget: {
|
|
1182
|
+
baseUrl: targetUrl,
|
|
1183
|
+
headers,
|
|
1184
|
+
phaseTimeoutMs: options.warmCdnDiscoveryTimeout ?? DEFAULT_REMOTE_PATH_DISCOVERY_PHASE_TIMEOUT_MS,
|
|
1185
|
+
retries: options.warmCdnDiscoveryRetries,
|
|
1186
|
+
retryDelayMs: DEFAULT_REMOTE_PATH_DISCOVERY_RETRY_DELAY_MS
|
|
1187
|
+
}
|
|
1188
|
+
});
|
|
1189
|
+
if (!discovery) return {
|
|
1190
|
+
loadingShellPaths: [],
|
|
1191
|
+
paths: [],
|
|
1192
|
+
rscPaths: []
|
|
1193
|
+
};
|
|
1194
|
+
return createPrerenderWarmPlan(root, discovery, {
|
|
1195
|
+
includeCanonicalRsc: hasCanonicalRscWarmup,
|
|
1196
|
+
includeFallbackShells: options.warmCdnIncludeFallbacks,
|
|
1197
|
+
strict: options.warmCdnCertify === true || !options.dangerouslyPromoteOnCdnWarmError
|
|
1198
|
+
});
|
|
1199
|
+
},
|
|
1200
|
+
selectWarmPlan: shouldSelectTpr ? (plan) => selectTPRWarmPlan(plan, tprRoutes, Math.max(1, Math.min(100, options.tprCoverage ?? 90)), Math.max(1, options.tprLimit ?? 1e3)) : void 0,
|
|
1201
|
+
statusSource: warmupStatusSource,
|
|
1202
|
+
warmCdnConcurrency: options.warmCdnConcurrency,
|
|
1203
|
+
warmCdnTarget,
|
|
1204
|
+
warmCdnTimeout: options.warmCdnTimeout,
|
|
1205
|
+
warmCdnRetries: options.warmCdnRetries,
|
|
1206
|
+
warmCdnDiscoveryTimeout: options.warmCdnDiscoveryTimeout,
|
|
1207
|
+
warmCdnDiscoveryRetries: options.warmCdnDiscoveryRetries,
|
|
1208
|
+
warmCdnProbeTimeout: options.warmCdnProbeTimeout,
|
|
1209
|
+
warmCdnProbeRetries: options.warmCdnProbeRetries,
|
|
1210
|
+
warmCdnCertify: options.warmCdnCertify,
|
|
1211
|
+
warmCdnReadinessTimeout: options.warmCdnReadinessTimeout,
|
|
1212
|
+
warmCdnReadinessRetries: options.warmCdnReadinessRetries,
|
|
1213
|
+
warmCdnReadinessProbes: options.warmCdnReadinessProbes,
|
|
1214
|
+
warmCdnReadinessProbeDelay: options.warmCdnReadinessProbeDelay,
|
|
1215
|
+
dangerouslyPromoteOnCdnWarmError: options.dangerouslyPromoteOnCdnWarmError,
|
|
1216
|
+
warmCdnPromote: options.warmCdnPromote,
|
|
1217
|
+
warmCdnPromotionDelay: options.warmCdnPromotionDelay
|
|
1090
1218
|
});
|
|
1091
|
-
|
|
1219
|
+
} catch (error) {
|
|
1220
|
+
if (options.warmCdnCache || options.warmCdnPromote === false && error instanceof StagedWarmupError) throw error;
|
|
1221
|
+
console.log(` TPR: Skipping pre-warm (${formatUnknownError(error)}). Continuing with deploy.`);
|
|
1092
1222
|
}
|
|
1093
|
-
|
|
1094
|
-
env: deployEnv === "production" && !options.env ? void 0 : deployEnv,
|
|
1095
|
-
name: options.name,
|
|
1096
|
-
config: options.config,
|
|
1097
|
-
verbose: options.verbose
|
|
1098
|
-
};
|
|
1099
|
-
let url;
|
|
1100
|
-
if (options.warmCdnCache) url = await deployWithCdnWarmup(root, [], {
|
|
1223
|
+
if (url === void 0) url = await runWranglerDeploy(root, {
|
|
1101
1224
|
...wranglerOptions,
|
|
1102
|
-
|
|
1103
|
-
discoverWarmPlan: async ({ headers, targetUrl }) => {
|
|
1104
|
-
const discovery = await discoverPrerenderPathManifest({
|
|
1105
|
-
root: info.root,
|
|
1106
|
-
nextConfig,
|
|
1107
|
-
buildIdentity: hasBuildIdentityHeader ? "response-header" : void 0,
|
|
1108
|
-
includeCanonicalRsc: hasCanonicalRscWarmup,
|
|
1109
|
-
requestRouting: hasStagedRequestRouting ? "uncached-stage" : void 0,
|
|
1110
|
-
responseVary: hasStrictResponseVary ? "verbatim" : void 0,
|
|
1111
|
-
isResponsePolicyHeader: (name) => isConfiguredCdnResponsePolicyHeader(viteConfigMetadata.cacheConfig, name),
|
|
1112
|
-
routeRootConfig: viteConfigMetadata.routeRootConfig,
|
|
1113
|
-
pathDiscoveryTarget: {
|
|
1114
|
-
baseUrl: targetUrl,
|
|
1115
|
-
headers,
|
|
1116
|
-
phaseTimeoutMs: options.warmCdnDiscoveryTimeout ?? DEFAULT_REMOTE_PATH_DISCOVERY_PHASE_TIMEOUT_MS,
|
|
1117
|
-
retries: options.warmCdnDiscoveryRetries,
|
|
1118
|
-
retryDelayMs: DEFAULT_REMOTE_PATH_DISCOVERY_RETRY_DELAY_MS
|
|
1119
|
-
}
|
|
1120
|
-
});
|
|
1121
|
-
if (!discovery) return {
|
|
1122
|
-
loadingShellPaths: [],
|
|
1123
|
-
paths: [],
|
|
1124
|
-
rscPaths: []
|
|
1125
|
-
};
|
|
1126
|
-
return createPrerenderWarmPlan(root, discovery, {
|
|
1127
|
-
includeCanonicalRsc: hasCanonicalRscWarmup,
|
|
1128
|
-
includeFallbackShells: options.warmCdnIncludeFallbacks,
|
|
1129
|
-
strict: options.warmCdnCertify === true || !options.dangerouslyPromoteOnCdnWarmError
|
|
1130
|
-
});
|
|
1131
|
-
},
|
|
1132
|
-
statusSource: hasVinextCacheWarmupStatus ? "vinext" : "cloudflare",
|
|
1133
|
-
warmCdnConcurrency: options.warmCdnConcurrency,
|
|
1134
|
-
warmCdnTarget,
|
|
1135
|
-
warmCdnTimeout: options.warmCdnTimeout,
|
|
1136
|
-
warmCdnRetries: options.warmCdnRetries,
|
|
1137
|
-
warmCdnDiscoveryTimeout: options.warmCdnDiscoveryTimeout,
|
|
1138
|
-
warmCdnDiscoveryRetries: options.warmCdnDiscoveryRetries,
|
|
1139
|
-
warmCdnProbeTimeout: options.warmCdnProbeTimeout,
|
|
1140
|
-
warmCdnProbeRetries: options.warmCdnProbeRetries,
|
|
1141
|
-
warmCdnCertify: options.warmCdnCertify,
|
|
1142
|
-
warmCdnReadinessTimeout: options.warmCdnReadinessTimeout,
|
|
1143
|
-
warmCdnReadinessRetries: options.warmCdnReadinessRetries,
|
|
1144
|
-
warmCdnReadinessProbes: options.warmCdnReadinessProbes,
|
|
1145
|
-
warmCdnReadinessProbeDelay: options.warmCdnReadinessProbeDelay,
|
|
1146
|
-
dangerouslyPromoteOnCdnWarmError: options.dangerouslyPromoteOnCdnWarmError,
|
|
1147
|
-
warmCdnPromote: options.warmCdnPromote,
|
|
1148
|
-
warmCdnPromotionDelay: options.warmCdnPromotionDelay
|
|
1225
|
+
promote: options.warmCdnPromote
|
|
1149
1226
|
});
|
|
1150
|
-
else url = await runWranglerDeploy(root, wranglerOptions);
|
|
1151
1227
|
console.log("\n ─────────────────────────────────────────");
|
|
1152
|
-
console.log(` Deployed to: ${url}`);
|
|
1228
|
+
console.log(` ${options.warmCdnPromote === false ? "Version URL" : "Deployed to"}: ${url}`);
|
|
1153
1229
|
console.log(" ─────────────────────────────────────────\n");
|
|
1154
1230
|
}
|
|
1155
1231
|
//#endregion
|
|
1156
|
-
export { DEFAULT_CDN_WARM_PROMOTION_DELAY_MS, buildNodeCliInvocation, buildVersionOverrideHeaders, buildWranglerDeployArgs, buildWranglerInvocation, buildWranglerKVBulkPutArgs, deploy, deployWithCdnWarmup, getZeroPercentStagingTraffic, hasCdnWarmRequests, parseDeployArgs, projectRequiresRouteCacheabilityProbeManifest, resolveCdnWarmupTargetUrl, resolveWorkerNameForVersionOverride, resolveWranglerBin, runWranglerDeploy, runWranglerKVBulkPut, validateWranglerEnvName, withCloudflareEnv };
|
|
1232
|
+
export { DEFAULT_CDN_WARM_PROMOTION_DELAY_MS, buildNodeCliInvocation, buildVersionOverrideHeaders, buildWranglerDeployArgs, buildWranglerInvocation, buildWranglerKVBulkPutArgs, deploy, deployWithCdnWarmup, getZeroPercentStagingTraffic, hasCdnWarmRequests, parseDeployArgs, projectRequiresRouteCacheabilityProbeManifest, resolveCdnWarmupTargetUrl, resolveWorkerNameForVersionOverride, resolveWranglerBin, runWranglerDeploy, runWranglerKVBulkPut, selectTPRWarmPlan, validateWranglerEnvName, withCloudflareEnv };
|
package/dist/tpr.d.ts
CHANGED
|
@@ -1,71 +1,32 @@
|
|
|
1
|
+
import { parseWranglerConfig } from "./wrangler-config.js";
|
|
1
2
|
//#region src/tpr.d.ts
|
|
2
|
-
/**
|
|
3
|
-
* TPR: Traffic-aware Pre-Rendering
|
|
4
|
-
*
|
|
5
|
-
* Uses Cloudflare zone analytics to determine which pages actually get
|
|
6
|
-
* traffic, and pre-renders only those during deploy. The pre-rendered
|
|
7
|
-
* HTML is uploaded to KV in the same format ISR uses at runtime — no
|
|
8
|
-
* runtime changes needed.
|
|
9
|
-
*
|
|
10
|
-
* Flow:
|
|
11
|
-
* 1. Parse wrangler config to find custom domain and KV namespace
|
|
12
|
-
* 2. Resolve the Cloudflare zone for the custom domain
|
|
13
|
-
* 3. Query zone analytics (GraphQL) for top pages by request count
|
|
14
|
-
* 4. Walk ranked list until coverage threshold is met
|
|
15
|
-
* 5. Start the built production server locally
|
|
16
|
-
* 6. Fetch each hot route to produce HTML
|
|
17
|
-
* 7. Upload pre-rendered HTML to KV (same KVCacheEntry format ISR reads)
|
|
18
|
-
*
|
|
19
|
-
* TPR is an experimental feature enabled via --experimental-tpr. It
|
|
20
|
-
* gracefully skips when no custom domain, no API token, no traffic data,
|
|
21
|
-
* or no KV namespace is configured.
|
|
22
|
-
*/
|
|
23
3
|
export type TPROptions = {
|
|
24
4
|
/** Project root directory. */
|
|
25
5
|
root: string;
|
|
26
6
|
/** Wrangler config path, relative to root unless absolute. */
|
|
27
7
|
config?: string;
|
|
28
|
-
/**
|
|
29
|
-
|
|
30
|
-
/**
|
|
31
|
-
|
|
8
|
+
/** Wrangler environment whose custom domain should be analyzed. */
|
|
9
|
+
env?: string;
|
|
10
|
+
/** Explicit domain used to resolve the analytics zone, overriding Wrangler routes. */
|
|
11
|
+
hostname?: string;
|
|
32
12
|
/** Analytics lookback window in hours. Default: 24. */
|
|
33
13
|
window: number;
|
|
34
14
|
};
|
|
35
|
-
export type
|
|
36
|
-
|
|
37
|
-
totalPaths: number;
|
|
38
|
-
/** Number of pages successfully pre-rendered and uploaded. */
|
|
39
|
-
prerenderedCount: number;
|
|
40
|
-
/** Actual traffic coverage achieved (percentage). */
|
|
41
|
-
coverageAchieved: number;
|
|
42
|
-
/** Wall-clock duration of the TPR step in milliseconds. */
|
|
43
|
-
durationMs: number;
|
|
15
|
+
export type TPRRouteResult = {
|
|
16
|
+
routes: TrafficEntry[];
|
|
44
17
|
/** If TPR was skipped, the reason. */
|
|
45
18
|
skipped?: string;
|
|
46
19
|
};
|
|
47
|
-
type
|
|
48
|
-
|
|
49
|
-
|
|
50
|
-
headers: Record<string, string>;
|
|
20
|
+
export type TrafficEntry = {
|
|
21
|
+
path: string;
|
|
22
|
+
requests: number;
|
|
51
23
|
};
|
|
52
|
-
type
|
|
53
|
-
|
|
54
|
-
|
|
55
|
-
|
|
56
|
-
|
|
57
|
-
legacyEnv?: boolean;
|
|
58
|
-
env?: Record<string, WranglerEnvironmentConfig>;
|
|
24
|
+
export type SelectedRoutes = {
|
|
25
|
+
routes: TrafficEntry[];
|
|
26
|
+
totalRequests: number;
|
|
27
|
+
coveredRequests: number;
|
|
28
|
+
coveragePercent: number;
|
|
59
29
|
};
|
|
60
|
-
export type WranglerEnvironmentConfig = {
|
|
61
|
-
customDomain?: string;
|
|
62
|
-
name?: string;
|
|
63
|
-
};
|
|
64
|
-
/**
|
|
65
|
-
* Parse wrangler config (JSONC or TOML) to extract the fields TPR needs:
|
|
66
|
-
* account_id, VINEXT_KV_CACHE KV namespace ID, and custom domain.
|
|
67
|
-
*/
|
|
68
|
-
export declare function parseWranglerConfig(root: string, configPath?: string): WranglerConfig | null;
|
|
69
30
|
/**
|
|
70
31
|
* Generate zone lookup candidates from shortest (2-part) to longest.
|
|
71
32
|
* Tries the most common case first (e.g., "example.com") and progressively
|
|
@@ -76,25 +37,17 @@ export declare function parseWranglerConfig(root: string, configPath?: string):
|
|
|
76
37
|
* "example.com" → ["example.com"]
|
|
77
38
|
*/
|
|
78
39
|
export declare function domainCandidates(domain: string): string[];
|
|
79
|
-
|
|
40
|
+
/** Filter out non-page requests (static assets, API routes, internal routes). */
|
|
41
|
+
export declare function filterTrafficPaths(entries: TrafficEntry[]): TrafficEntry[];
|
|
80
42
|
/**
|
|
81
|
-
*
|
|
82
|
-
*
|
|
83
|
-
* Key format matches the runtime KVCacheHandler exactly:
|
|
84
|
-
* createKvKeySpace().entryKey(isrCacheKey("app", pathname, buildId) + ":html")
|
|
85
|
-
* → "cache:app:<buildId>:<pathname>:html"
|
|
43
|
+
* Walk the ranked traffic list, accumulating request counts until the
|
|
44
|
+
* coverage target is met or the hard cap is reached.
|
|
86
45
|
*/
|
|
87
|
-
export declare function
|
|
88
|
-
key: string;
|
|
89
|
-
value: string;
|
|
90
|
-
expiration_ttl: number;
|
|
91
|
-
}>;
|
|
46
|
+
export declare function selectRoutes(traffic: TrafficEntry[], coverageTarget: number, limit: number): SelectedRoutes;
|
|
92
47
|
/**
|
|
93
|
-
*
|
|
94
|
-
*
|
|
95
|
-
* Designed to be called between the build step and wrangler deploy in the
|
|
96
|
-
* `vinext-cloudflare deploy` pipeline. Gracefully skips (never errors) when
|
|
97
|
-
* the prerequisites aren't met.
|
|
48
|
+
* Resolve ranked traffic paths. The standard CDN pre-warming flow owns route
|
|
49
|
+
* matching, coverage selection, rendering, and cache admission.
|
|
98
50
|
*/
|
|
99
|
-
export declare function
|
|
100
|
-
//#endregion
|
|
51
|
+
export declare function resolveTPRRoutes(options: TPROptions): Promise<TPRRouteResult>;
|
|
52
|
+
//#endregion
|
|
53
|
+
export { parseWranglerConfig };
|