@vinext/cloudflare 1.0.0-beta.1 → 1.0.0-beta.11

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.
Files changed (66) hide show
  1. package/README.md +193 -1
  2. package/dist/cache/cdn-adapter-config.d.ts +31 -0
  3. package/dist/cache/cdn-adapter-config.js +95 -0
  4. package/dist/cache/cdn-adapter.d.ts +48 -15
  5. package/dist/cache/cdn-adapter.js +50 -13
  6. package/dist/cache/cdn-adapter.runtime.d.ts +26 -4
  7. package/dist/cache/cdn-adapter.runtime.js +150 -37
  8. package/dist/cache/cdn-adapter.worker.d.ts +31 -0
  9. package/dist/cache/cdn-adapter.worker.js +373 -0
  10. package/dist/cache/cdn-build-id.d.ts +6 -0
  11. package/dist/cache/cdn-build-id.js +9 -0
  12. package/dist/cache/config.d.ts +137 -0
  13. package/dist/cache/config.js +87 -0
  14. package/dist/cache/kv-data-adapter.d.ts +32 -8
  15. package/dist/cache/kv-data-adapter.js +5 -1
  16. package/dist/cache/kv-data-adapter.runtime.d.ts +45 -13
  17. package/dist/cache/kv-data-adapter.runtime.js +132 -52
  18. package/dist/cache/kv-key.d.ts +15 -0
  19. package/dist/cache/kv-key.js +43 -0
  20. package/dist/cache/response-store-adapter.d.ts +73 -0
  21. package/dist/cache/response-store-adapter.js +64 -0
  22. package/dist/cache/response-store-adapter.self-contained.worker.d.ts +18 -0
  23. package/dist/cache/response-store-adapter.self-contained.worker.js +12 -0
  24. package/dist/cache/response-store-adapter.service-binding.worker.d.ts +16 -0
  25. package/dist/cache/response-store-adapter.service-binding.worker.js +11 -0
  26. package/dist/cache/response-store-adapter.worker.d.ts +14 -0
  27. package/dist/cache/response-store-adapter.worker.js +278 -0
  28. package/dist/cache/response-store-cdn.runtime.d.ts +5 -0
  29. package/dist/cache/response-store-cdn.runtime.js +41 -0
  30. package/dist/cache/response-store-data.runtime.d.ts +34 -0
  31. package/dist/cache/response-store-data.runtime.js +300 -0
  32. package/dist/cacheability-artifact.d.ts +10 -0
  33. package/dist/cacheability-artifact.js +215 -0
  34. package/dist/cacheability-manifest-limits.d.ts +4 -0
  35. package/dist/cacheability-manifest-limits.js +7 -0
  36. package/dist/cacheability-probe.d.ts +49 -0
  37. package/dist/cacheability-probe.js +660 -0
  38. package/dist/cdn-warm.d.ts +110 -12
  39. package/dist/cdn-warm.js +880 -82
  40. package/dist/cli.d.ts +1 -1
  41. package/dist/cli.js +15 -1
  42. package/dist/deploy-config.d.ts +14 -11
  43. package/dist/deploy-config.js +24 -5
  44. package/dist/deploy-help.d.ts +3 -4
  45. package/dist/deploy-help.js +65 -22
  46. package/dist/deploy.d.ts +139 -42
  47. package/dist/deploy.js +946 -132
  48. package/dist/images/images-optimizer.d.ts +5 -5
  49. package/dist/images/images-optimizer.runtime.d.ts +1 -5
  50. package/dist/prerender-kv-populate.d.ts +3 -4
  51. package/dist/prerender-kv-populate.js +51 -18
  52. package/dist/tpr.d.ts +34 -70
  53. package/dist/tpr.js +50 -603
  54. package/dist/utils/cache-control-metadata.d.ts +3 -4
  55. package/dist/version-deploy.d.ts +46 -17
  56. package/dist/version-deploy.js +151 -14
  57. package/dist/version-headers.d.ts +2 -0
  58. package/dist/version-headers.js +2 -0
  59. package/dist/worker-deployment-url.d.ts +9 -0
  60. package/dist/worker-deployment-url.js +45 -0
  61. package/dist/workers-dev-url.d.ts +2 -3
  62. package/dist/wrangler-config.d.ts +19 -0
  63. package/dist/wrangler-config.js +294 -0
  64. package/dist/wrangler-version-metadata.d.ts +7 -0
  65. package/dist/wrangler-version-metadata.js +9 -0
  66. package/package.json +21 -11
@@ -0,0 +1,294 @@
1
+ import fs from "node:fs";
2
+ import path from "node:path";
3
+ //#region src/wrangler-config.ts
4
+ /** Narrow Wrangler config projection shared by deploy-time features. */
5
+ /**
6
+ * Parse the Wrangler fields used by TPR and staged CDN warming.
7
+ */
8
+ function parseWranglerConfig(root, configPath) {
9
+ if (configPath) {
10
+ const filepath = path.resolve(root, configPath);
11
+ if (!fs.existsSync(filepath)) return null;
12
+ const content = fs.readFileSync(filepath, "utf-8");
13
+ if (filepath.endsWith(".toml")) return extractFromTOML(content);
14
+ try {
15
+ return extractFromJSON(JSON.parse(stripJsonCommentsAndTrailingCommas(content)));
16
+ } catch {
17
+ return null;
18
+ }
19
+ }
20
+ for (const filename of ["wrangler.jsonc", "wrangler.json"]) {
21
+ const filepath = path.join(root, filename);
22
+ if (fs.existsSync(filepath)) {
23
+ const content = fs.readFileSync(filepath, "utf-8");
24
+ try {
25
+ return extractFromJSON(JSON.parse(stripJsonCommentsAndTrailingCommas(content)));
26
+ } catch {
27
+ continue;
28
+ }
29
+ }
30
+ }
31
+ const tomlPath = path.join(root, "wrangler.toml");
32
+ if (fs.existsSync(tomlPath)) return extractFromTOML(fs.readFileSync(tomlPath, "utf-8"));
33
+ return null;
34
+ }
35
+ /**
36
+ * Strip single-line (//), multi-line comments, and trailing commas from JSONC
37
+ * while preserving strings that contain comment-like text or commas.
38
+ */
39
+ function stripJsonCommentsAndTrailingCommas(str) {
40
+ let result = "";
41
+ let inString = false;
42
+ let inSingleLine = false;
43
+ let inMultiLine = false;
44
+ let escapeNext = false;
45
+ for (let i = 0; i < str.length; i++) {
46
+ const ch = str[i];
47
+ const next = str[i + 1];
48
+ if (escapeNext) {
49
+ if (!inSingleLine && !inMultiLine) result += ch;
50
+ escapeNext = false;
51
+ continue;
52
+ }
53
+ if (ch === "\\" && inString) {
54
+ result += ch;
55
+ escapeNext = true;
56
+ continue;
57
+ }
58
+ if (inSingleLine) {
59
+ if (ch === "\n") {
60
+ inSingleLine = false;
61
+ result += ch;
62
+ }
63
+ continue;
64
+ }
65
+ if (inMultiLine) {
66
+ if (ch === "*" && next === "/") {
67
+ inMultiLine = false;
68
+ i++;
69
+ }
70
+ continue;
71
+ }
72
+ if (ch === "\"" && !inString) {
73
+ inString = true;
74
+ result += ch;
75
+ continue;
76
+ }
77
+ if (ch === "\"" && inString) {
78
+ inString = false;
79
+ result += ch;
80
+ continue;
81
+ }
82
+ if (!inString && ch === "/" && next === "/") {
83
+ inSingleLine = true;
84
+ i++;
85
+ continue;
86
+ }
87
+ if (!inString && ch === "/" && next === "*") {
88
+ inMultiLine = true;
89
+ i++;
90
+ continue;
91
+ }
92
+ if (!inString && ch === "," && isJsonTrailingComma(str, i + 1)) continue;
93
+ result += ch;
94
+ }
95
+ return result;
96
+ }
97
+ function isJsonTrailingComma(str, start) {
98
+ for (let i = start; i < str.length; i++) {
99
+ const ch = str[i];
100
+ const next = str[i + 1];
101
+ if (ch === void 0) return false;
102
+ if (/\s/.test(ch)) continue;
103
+ if (ch === "/" && next === "/") {
104
+ i += 2;
105
+ while (i < str.length && str[i] !== "\n") i++;
106
+ continue;
107
+ }
108
+ if (ch === "/" && next === "*") {
109
+ i += 2;
110
+ while (i < str.length) {
111
+ if (str[i] === "*" && str[i + 1] === "/") {
112
+ i++;
113
+ break;
114
+ }
115
+ i++;
116
+ }
117
+ continue;
118
+ }
119
+ return ch === "}" || ch === "]";
120
+ }
121
+ return false;
122
+ }
123
+ function extractFromJSON(config) {
124
+ const result = {};
125
+ if (typeof config.name === "string" && config.name.length > 0) result.name = config.name;
126
+ if (typeof config.legacy_env === "boolean") result.legacyEnv = config.legacy_env;
127
+ if (typeof config.account_id === "string") result.accountId = config.account_id;
128
+ if (Array.isArray(config.kv_namespaces)) {
129
+ const namespace = config.kv_namespaces.find((value) => value && typeof value === "object" && (value.binding === "VINEXT_KV_CACHE" || value.binding === "VINEXT_CACHE"));
130
+ if (namespace && typeof namespace.id === "string" && namespace.id !== "<your-kv-namespace-id>") result.kvNamespaceId = namespace.id;
131
+ }
132
+ const domain = extractDomainFromRoutes(config.routes) ?? extractDomainFromCustomDomains(config);
133
+ if (domain) result.customDomain = domain;
134
+ const env = extractEnvConfigs(config.env);
135
+ if (env) result.env = env;
136
+ return result;
137
+ }
138
+ function extractEnvConfigs(envs) {
139
+ if (!envs || typeof envs !== "object" || Array.isArray(envs)) return void 0;
140
+ const result = {};
141
+ for (const [envName, rawConfig] of Object.entries(envs)) {
142
+ if (!rawConfig || typeof rawConfig !== "object" || Array.isArray(rawConfig)) continue;
143
+ const envConfig = extractEnvironmentConfig(rawConfig);
144
+ if (envConfig.name || envConfig.customDomain) result[envName] = envConfig;
145
+ }
146
+ return Object.keys(result).length > 0 ? result : void 0;
147
+ }
148
+ function extractEnvironmentConfig(config) {
149
+ const result = {};
150
+ if (typeof config.name === "string" && config.name.length > 0) result.name = config.name;
151
+ const domain = extractDomainFromRoutes(config.routes) ?? extractDomainFromCustomDomains(config);
152
+ if (domain) result.customDomain = domain;
153
+ return result;
154
+ }
155
+ function extractDomainFromRoutes(routes) {
156
+ if (!Array.isArray(routes)) return null;
157
+ for (const route of routes) if (typeof route === "string") {
158
+ const domain = cleanDomain(route);
159
+ if (domain && !domain.includes("workers.dev")) return domain;
160
+ } else if (route && typeof route === "object") {
161
+ const r = route;
162
+ const pattern = typeof r.zone_name === "string" ? r.zone_name : typeof r.pattern === "string" ? r.pattern : null;
163
+ if (pattern) {
164
+ const domain = cleanDomain(pattern);
165
+ if (domain && !domain.includes("workers.dev")) return domain;
166
+ }
167
+ }
168
+ return null;
169
+ }
170
+ function extractDomainFromCustomDomains(config) {
171
+ if (Array.isArray(config.custom_domains)) {
172
+ for (const d of config.custom_domains) if (typeof d === "string" && !d.includes("workers.dev")) return cleanDomain(d);
173
+ }
174
+ return null;
175
+ }
176
+ /** Strip protocol and trailing wildcards from a route pattern to get a bare domain. */
177
+ function cleanDomain(raw) {
178
+ return raw.replace(/^https?:\/\//, "").replace(/\/\*$/, "").replace(/\/+$/, "").split("/")[0] || null;
179
+ }
180
+ /**
181
+ * Simple extraction of specific fields from wrangler.toml content.
182
+ * Not a full TOML parser — just enough for the fields we need.
183
+ */
184
+ function extractFromTOML(content) {
185
+ const result = {};
186
+ const nameMatch = content.match(/^name\s*=\s*"([^"]+)"/m);
187
+ if (nameMatch) result.name = nameMatch[1];
188
+ const legacyEnvMatch = content.match(/^legacy_env\s*=\s*(true|false)\s*$/m);
189
+ if (legacyEnvMatch) result.legacyEnv = legacyEnvMatch[1] === "true";
190
+ const accountMatch = content.match(/^account_id\s*=\s*"([^"]+)"/m);
191
+ if (accountMatch) result.accountId = accountMatch[1];
192
+ for (const block of content.split(/\[\[kv_namespaces\]\]/).slice(1)) {
193
+ const section = block.split(/\[\[/)[0];
194
+ const binding = section.match(/binding\s*=\s*"([^"]+)"/)?.[1];
195
+ const id = section.match(/\bid\s*=\s*"([^"]+)"/)?.[1];
196
+ if ((binding === "VINEXT_KV_CACHE" || binding === "VINEXT_CACHE") && id && id !== "<your-kv-namespace-id>") result.kvNamespaceId = id;
197
+ }
198
+ const routeMatch = content.match(/^route\s*=\s*"([^"]+)"/m);
199
+ if (routeMatch) {
200
+ const domain = cleanDomain(routeMatch[1]);
201
+ if (domain && !domain.includes("workers.dev")) result.customDomain = domain;
202
+ }
203
+ if (!result.customDomain) {
204
+ const routeBlocks = content.split(/\[\[routes\]\]/);
205
+ for (let i = 1; i < routeBlocks.length; i++) {
206
+ const patternMatch = routeBlocks[i].split(/\[\[/)[0].match(/pattern\s*=\s*"([^"]+)"/);
207
+ if (patternMatch) {
208
+ const domain = cleanDomain(patternMatch[1]);
209
+ if (domain && !domain.includes("workers.dev")) {
210
+ result.customDomain = domain;
211
+ break;
212
+ }
213
+ }
214
+ }
215
+ }
216
+ const env = extractEnvConfigsFromTOML(content);
217
+ if (env) result.env = env;
218
+ return result;
219
+ }
220
+ function extractEnvConfigsFromTOML(content) {
221
+ const result = {};
222
+ for (const section of getTomlSections(content)) {
223
+ const envName = section.header.match(/^env\.([^.]+)$/)?.[1];
224
+ if (envName) {
225
+ const envConfig = result[envName] ?? {};
226
+ const nameMatch = section.body.match(/^name\s*=\s*"([^"]+)"/m);
227
+ if (nameMatch) envConfig.name = nameMatch[1];
228
+ const domain = extractTomlScalarRouteDomain(section.body) ?? extractTomlRoutesArrayDomain(section.body);
229
+ if (domain) envConfig.customDomain = domain;
230
+ if (envConfig.name || envConfig.customDomain) result[envName] = envConfig;
231
+ continue;
232
+ }
233
+ const routesEnvName = section.header.match(/^env\.([^.]+)\.routes$/)?.[1];
234
+ if (routesEnvName) {
235
+ const envConfig = result[routesEnvName] ?? {};
236
+ const domain = extractTomlRouteBlockDomain(section.body);
237
+ if (domain) envConfig.customDomain = domain;
238
+ if (envConfig.name || envConfig.customDomain) result[routesEnvName] = envConfig;
239
+ }
240
+ }
241
+ return Object.keys(result).length > 0 ? result : void 0;
242
+ }
243
+ function getTomlSections(content) {
244
+ const sections = [];
245
+ let currentHeader = null;
246
+ let currentBody = [];
247
+ for (const line of content.split("\n")) {
248
+ const header = parseTomlSectionHeader(line);
249
+ if (header) {
250
+ if (currentHeader) sections.push({
251
+ header: currentHeader,
252
+ body: currentBody.join("\n")
253
+ });
254
+ currentHeader = header;
255
+ currentBody = [];
256
+ } else if (currentHeader) currentBody.push(line);
257
+ }
258
+ if (currentHeader) sections.push({
259
+ header: currentHeader,
260
+ body: currentBody.join("\n")
261
+ });
262
+ return sections;
263
+ }
264
+ function parseTomlSectionHeader(line) {
265
+ const trimmed = line.trim();
266
+ if (!trimmed.startsWith("[") || !trimmed.endsWith("]")) return null;
267
+ const isArrayHeader = trimmed.startsWith("[[") && trimmed.endsWith("]]");
268
+ const start = isArrayHeader ? 2 : 1;
269
+ const end = isArrayHeader ? trimmed.length - 2 : trimmed.length - 1;
270
+ const header = trimmed.slice(start, end).trim();
271
+ return header.length > 0 ? header : null;
272
+ }
273
+ function extractTomlScalarRouteDomain(section) {
274
+ const routeMatch = section.match(/^route\s*=\s*"([^"]+)"/m);
275
+ if (!routeMatch) return null;
276
+ const domain = cleanDomain(routeMatch[1]);
277
+ return domain && !domain.includes("workers.dev") ? domain : null;
278
+ }
279
+ function extractTomlRoutesArrayDomain(section) {
280
+ const routesMatch = section.match(/^routes\s*=\s*\[([\s\S]*?)\]/m);
281
+ if (!routesMatch) return null;
282
+ const patternMatch = (routesMatch[1] ?? "").match(/(?:pattern\s*=\s*)?"([^"]+)"/);
283
+ if (!patternMatch) return null;
284
+ const domain = cleanDomain(patternMatch[1]);
285
+ return domain && !domain.includes("workers.dev") ? domain : null;
286
+ }
287
+ function extractTomlRouteBlockDomain(section) {
288
+ const patternMatch = section.match(/^pattern\s*=\s*"([^"]+)"/m) ?? section.match(/^zone_name\s*=\s*"([^"]+)"/m);
289
+ if (!patternMatch) return null;
290
+ const domain = cleanDomain(patternMatch[1]);
291
+ return domain && !domain.includes("workers.dev") ? domain : null;
292
+ }
293
+ //#endregion
294
+ export { parseWranglerConfig };
@@ -0,0 +1,7 @@
1
+ //#region src/wrangler-version-metadata.d.ts
2
+ export declare function assertCdnVersionMetadataConfig({ binding, configuredBinding, configPath }: {
3
+ binding: string;
4
+ configuredBinding: string | undefined;
5
+ configPath: string | undefined;
6
+ }): void;
7
+ //#endregion
@@ -0,0 +1,9 @@
1
+ //#region src/wrangler-version-metadata.ts
2
+ function assertCdnVersionMetadataConfig({ binding, configuredBinding, configPath }) {
3
+ if (configuredBinding === binding) return;
4
+ const location = configPath ? ` in ${configPath}` : "";
5
+ const found = configuredBinding ? ` declares ${JSON.stringify(configuredBinding)} instead` : " does not declare version_metadata";
6
+ throw new Error(`[vinext] Cloudflare CDN warmup requires version metadata binding ${JSON.stringify(binding)}, but the effective Wrangler config${location}${found}. Deploy the generated Wrangler config finalized by cdnAdapter(), or add the binding to this effective config and align cdnAdapter({ versionMetadataBinding }) when using a custom name.`);
7
+ }
8
+ //#endregion
9
+ export { assertCdnVersionMetadataConfig };
package/package.json CHANGED
@@ -1,7 +1,8 @@
1
1
  {
2
2
  "name": "@vinext/cloudflare",
3
- "version": "1.0.0-beta.1",
4
- "description": "Cloudflare adapters for vinext (KV data cache and Images-backed image optimization).",
3
+ "version": "1.0.0-beta.11",
4
+ "description": "Cloudflare cache and image adapters for vinext.",
5
+ "homepage": "https://vinext.dev/",
5
6
  "license": "MIT",
6
7
  "repository": {
7
8
  "type": "git",
@@ -29,10 +30,6 @@
29
30
  "types": "./dist/deploy-config.d.ts",
30
31
  "import": "./dist/deploy-config.js"
31
32
  },
32
- "./internal/tpr": {
33
- "types": "./dist/tpr.d.ts",
34
- "import": "./dist/tpr.js"
35
- },
36
33
  "./internal/cdn-warm": {
37
34
  "types": "./dist/cdn-warm.d.ts",
38
35
  "import": "./dist/cdn-warm.js"
@@ -50,20 +47,33 @@
50
47
  "import": "./dist/images/*.js"
51
48
  }
52
49
  },
50
+ "dependencies": {
51
+ "@cloudflare/workers-response-store": "0.1.0-beta.2"
52
+ },
53
53
  "devDependencies": {
54
+ "@cloudflare/vite-plugin": "2.0.0-beta.sha-805ec1ff3",
54
55
  "@types/node": "^25.9.2",
55
- "vite": "npm:@voidzero-dev/vite-plus-core@0.2.2",
56
- "vite-plus": "0.2.2",
57
- "vinext": "1.0.0-beta.1"
56
+ "miniflare": "5.20260730.0-alpha",
57
+ "vite": "npm:@voidzero-dev/vite-plus-core@0.3.2",
58
+ "vite-plus": "0.3.2",
59
+ "vitest": "4.1.11",
60
+ "vinext": "1.0.0-beta.13"
58
61
  },
59
62
  "peerDependencies": {
60
- "vinext": ">=0.0.0"
63
+ "@cloudflare/vite-plugin": "*",
64
+ "vinext": "^1.0.0-beta.13"
65
+ },
66
+ "peerDependenciesMeta": {
67
+ "@cloudflare/vite-plugin": {
68
+ "optional": true
69
+ }
61
70
  },
62
71
  "engines": {
63
72
  "node": ">=22"
64
73
  },
65
74
  "scripts": {
66
75
  "build": "vp pack",
67
- "dev": "vp pack --watch"
76
+ "dev": "vp pack --watch",
77
+ "test": "vp run vinext#build && vp run @cloudflare/workers-response-store#build && vp run @vinext/cloudflare#build && VINEXT_RESPONSE_STORE_MODE=self-contained VINEXT_RESPONSE_STORE_LOCATION_HINT=weur pnpm --filter response-store-demo run build && VINEXT_RESPONSE_STORE_LOCATION_HINT=wnam pnpm --filter response-store-demo run build && vitest run"
68
78
  }
69
79
  }