@astrojs/cloudflare 7.7.1 → 8.0.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
@@ -0,0 +1,221 @@
1
+ import { mkdirSync, readFileSync, statSync, writeFileSync } from 'fs';
2
+ import assert from 'node:assert';
3
+ import { fileURLToPath } from 'url';
4
+ import TOML from '@iarna/toml';
5
+ import { AstroError } from 'astro/errors';
6
+ import dotenv from 'dotenv';
7
+ import { Miniflare } from 'miniflare';
8
+ class LocalRuntime {
9
+ _astroConfig;
10
+ _logger;
11
+ _miniflare;
12
+ miniflareBindings;
13
+ secrets;
14
+ cfObject;
15
+ constructor(astroConfig, runtimeConfig, logger) {
16
+ this._astroConfig = astroConfig;
17
+ this._logger = logger;
18
+ let varBindings = {};
19
+ let kvBindings = [];
20
+ let d1Bindings = [];
21
+ let r2Bindings = [];
22
+ let durableObjectBindings = {};
23
+ for (const bindingName in runtimeConfig.bindings) {
24
+ const bindingData = runtimeConfig.bindings[bindingName];
25
+ switch (bindingData.type) {
26
+ case 'var':
27
+ varBindings[bindingName] = bindingData.value;
28
+ break;
29
+ case 'kv':
30
+ kvBindings.push(bindingName);
31
+ break;
32
+ case 'd1':
33
+ d1Bindings.push(bindingName);
34
+ break;
35
+ case 'r2':
36
+ r2Bindings.push(bindingName);
37
+ break;
38
+ case 'durable-object':
39
+ durableObjectBindings[bindingName] = {
40
+ className: bindingData.className,
41
+ scriptName: bindingData.service?.name,
42
+ };
43
+ break;
44
+ }
45
+ }
46
+ this._miniflare = new Miniflare({
47
+ cachePersist: `${runtimeConfig.persistTo}/cache`,
48
+ d1Persist: `${runtimeConfig.persistTo}/d1`,
49
+ r2Persist: `${runtimeConfig.persistTo}/r2`,
50
+ kvPersist: `${runtimeConfig.persistTo}/kv`,
51
+ durableObjectsPersist: `${runtimeConfig.persistTo}/do`,
52
+ workers: [
53
+ {
54
+ name: 'worker',
55
+ script: '',
56
+ modules: true,
57
+ cacheWarnUsage: true,
58
+ cache: true,
59
+ bindings: varBindings,
60
+ d1Databases: d1Bindings,
61
+ r2Buckets: r2Bindings,
62
+ kvNamespaces: kvBindings,
63
+ durableObjects: durableObjectBindings,
64
+ },
65
+ ],
66
+ });
67
+ }
68
+ async getBindings() {
69
+ await this._miniflare.ready;
70
+ if (!this.miniflareBindings) {
71
+ this.miniflareBindings = await this._miniflare.getBindings();
72
+ }
73
+ return this.miniflareBindings;
74
+ }
75
+ async getSecrets() {
76
+ await this._miniflare.ready;
77
+ if (!this.secrets) {
78
+ try {
79
+ this.secrets = dotenv.parse(readFileSync(fileURLToPath(new URL('./.dev.vars', this._astroConfig.root))));
80
+ }
81
+ catch (error) {
82
+ const e = error;
83
+ if (e.code === 'ENOENT') {
84
+ this._logger.info('There is no `.dev.vars` file in the root directory, if you have encrypted secrets or environmental variables you Cloudflare recommends to put them in this file');
85
+ this.secrets = {};
86
+ }
87
+ else {
88
+ throw new AstroError('Failed to load secrets file', e.message);
89
+ }
90
+ }
91
+ }
92
+ return this.secrets;
93
+ }
94
+ async getCaches() {
95
+ await this._miniflare.ready;
96
+ return this._miniflare.getCaches();
97
+ }
98
+ async getCF() {
99
+ await this._miniflare.ready;
100
+ const MAX_CACHE_AGE = 1000 * 60 * 60 * 24 * 7; // 7 days;
101
+ // Try load cached cfObject, if this fails, we'll catch the error and refetch.
102
+ // If this succeeds, and the file is stale, that's fine: it's very likely
103
+ // we'll be fetching the same data anyways.
104
+ try {
105
+ const cachedCFObject = JSON.parse(readFileSync(fileURLToPath(new URL('cf.json', this._astroConfig.cacheDir)), 'utf8'));
106
+ const cfObjectStats = statSync(fileURLToPath(new URL('cf.json', this._astroConfig.cacheDir)));
107
+ assert(Date.now() - cfObjectStats.mtimeMs <= MAX_CACHE_AGE);
108
+ this.cfObject = cachedCFObject;
109
+ }
110
+ catch { }
111
+ const CF_ENDPOINT = 'https://workers.cloudflare.com/cf.json';
112
+ if (!this.cfObject) {
113
+ this.cfObject = await fetch(CF_ENDPOINT).then((res) => res.json());
114
+ mkdirSync(this._astroConfig.cacheDir);
115
+ writeFileSync(fileURLToPath(new URL('cf.json', this._astroConfig.cacheDir)), JSON.stringify(this.cfObject), 'utf8');
116
+ }
117
+ return this.cfObject;
118
+ }
119
+ async dispose() {
120
+ await this._miniflare.dispose();
121
+ }
122
+ }
123
+ export class LocalWorkersRuntime extends LocalRuntime {
124
+ constructor(astroConfig, runtimeConfig, logger) {
125
+ let _wranglerConfig;
126
+ try {
127
+ _wranglerConfig = TOML.parse(readFileSync(fileURLToPath(new URL('./wrangler.toml', astroConfig.root)), 'utf-8').replace(/\r\n/g, '\n'));
128
+ }
129
+ catch (error) {
130
+ const e = error;
131
+ if (e.code === 'ENOENT') {
132
+ logger.error('Missing file `wrangler.toml in root directory`');
133
+ }
134
+ else {
135
+ throw new AstroError('Failed to load wrangler config', e.message);
136
+ }
137
+ }
138
+ const runtimeConfigWithWrangler = {
139
+ ...runtimeConfig,
140
+ bindings: {},
141
+ };
142
+ if (_wranglerConfig?.vars) {
143
+ for (const key in _wranglerConfig.vars) {
144
+ runtimeConfigWithWrangler.bindings[key] = {
145
+ type: 'var',
146
+ value: _wranglerConfig.vars[key],
147
+ };
148
+ }
149
+ }
150
+ if (_wranglerConfig?.kv_namespaces) {
151
+ for (const ns of _wranglerConfig.kv_namespaces) {
152
+ runtimeConfigWithWrangler.bindings[ns.binding] = {
153
+ type: 'kv',
154
+ };
155
+ }
156
+ }
157
+ if (_wranglerConfig?.d1_databases) {
158
+ for (const db of _wranglerConfig.d1_databases) {
159
+ runtimeConfigWithWrangler.bindings[db.binding] = {
160
+ type: 'd1',
161
+ };
162
+ }
163
+ }
164
+ if (_wranglerConfig?.r2_buckets) {
165
+ for (const bucket of _wranglerConfig.r2_buckets) {
166
+ runtimeConfigWithWrangler.bindings[bucket.binding] = {
167
+ type: 'r2',
168
+ };
169
+ }
170
+ }
171
+ if (_wranglerConfig?.durable_objects) {
172
+ for (const durableObject of _wranglerConfig.durable_objects.bindings) {
173
+ runtimeConfigWithWrangler.bindings[durableObject.name] = {
174
+ type: 'durable-object',
175
+ className: durableObject.class_name,
176
+ service: durableObject.script_name
177
+ ? {
178
+ name: durableObject.script_name,
179
+ }
180
+ : undefined,
181
+ };
182
+ }
183
+ }
184
+ super(astroConfig, runtimeConfigWithWrangler, logger);
185
+ }
186
+ }
187
+ export class LocalPagesRuntime extends LocalRuntime {
188
+ constructor(astroConfig, runtimeConfig, logger) {
189
+ super(astroConfig, runtimeConfig, logger);
190
+ }
191
+ }
192
+ let localRuntime;
193
+ export function getLocalRuntime(astroConfig, runtimeConfig, logger) {
194
+ if (localRuntime)
195
+ return localRuntime;
196
+ if (runtimeConfig.type === 'pages') {
197
+ localRuntime = new LocalPagesRuntime(astroConfig, runtimeConfig, logger);
198
+ }
199
+ else {
200
+ localRuntime = new LocalWorkersRuntime(astroConfig, runtimeConfig, logger);
201
+ }
202
+ return localRuntime;
203
+ }
204
+ export function getRuntimeConfig(userConfig) {
205
+ if (!userConfig || userConfig.mode === 'off')
206
+ return { mode: 'off' };
207
+ // we know that we have `mode: local` below
208
+ if (userConfig.type === 'pages')
209
+ return {
210
+ mode: 'local',
211
+ type: 'pages',
212
+ persistTo: userConfig.persistTo ?? '.wrangler/state/v3',
213
+ bindings: userConfig.bindings ?? {},
214
+ };
215
+ // we know that we have `type: workers` below
216
+ return {
217
+ mode: 'local',
218
+ type: 'workers',
219
+ persistTo: userConfig.persistTo ?? '.wrangler/state/v3',
220
+ };
221
+ }
@@ -6,11 +6,11 @@
6
6
  * Until further notice, we will be using this file as a workaround
7
7
  * TODO: Tackle this file, once their is an decision on the upstream request
8
8
  */
9
+ import * as fs from 'node:fs';
10
+ import { dirname, resolve } from 'node:path';
9
11
  import TOML from '@iarna/toml';
10
12
  import dotenv from 'dotenv';
11
13
  import { findUpSync } from 'find-up';
12
- import * as fs from 'node:fs';
13
- import { dirname, resolve } from 'node:path';
14
14
  let _wrangler;
15
15
  function findWranglerToml(referencePath = process.cwd(), preferJson = false) {
16
16
  if (preferJson) {
@@ -1,5 +1,5 @@
1
- import esbuild from 'esbuild';
2
1
  import { basename } from 'node:path';
2
+ import esbuild from 'esbuild';
3
3
  /**
4
4
  *
5
5
  * @param relativePathToAssets - relative path from the final location for the current esbuild output bundle, to the assets directory.
@@ -1,4 +1,4 @@
1
- import { type Plugin } from 'vite';
1
+ import type { AstroConfig } from 'astro';
2
2
  /**
3
3
  * Loads '*.wasm?module' imports as WebAssembly modules, which is the only way to load WASM in cloudflare workers.
4
4
  * Current proposal for WASM modules: https://github.com/WebAssembly/esm-integration/tree/main/proposals/esm-integration
@@ -11,4 +11,4 @@ import { type Plugin } from 'vite';
11
11
  export declare function wasmModuleLoader({ disabled, assetsDirectory, }: {
12
12
  disabled: boolean;
13
13
  assetsDirectory: string;
14
- }): Plugin;
14
+ }): NonNullable<AstroConfig['vite']['plugins']>[number];
@@ -1,6 +1,5 @@
1
1
  import * as fs from 'node:fs';
2
2
  import * as path from 'node:path';
3
- import {} from 'vite';
4
3
  /**
5
4
  * Loads '*.wasm?module' imports as WebAssembly modules, which is the only way to load WASM in cloudflare workers.
6
5
  * Current proposal for WASM modules: https://github.com/WebAssembly/esm-integration/tree/main/proposals/esm-integration
@@ -76,7 +75,7 @@ export default wasmModule;
76
75
  return;
77
76
  if (!/__WASM_ASSET__/g.test(code))
78
77
  return;
79
- const final = code.replaceAll(/__WASM_ASSET__([a-z\d]+).wasm.mjs/g, (s, assetId) => {
78
+ const final = code.replaceAll(/__WASM_ASSET__([A-Za-z\d]+).wasm.mjs/g, (s, assetId) => {
80
79
  const fileName = this.getFileName(assetId);
81
80
  const relativePath = path
82
81
  .relative(path.dirname(chunk.fileName), fileName)
package/package.json CHANGED
@@ -2,7 +2,7 @@
2
2
  "//comment": "test changeset-bot",
3
3
  "name": "@astrojs/cloudflare",
4
4
  "description": "Deploy your site to Cloudflare Workers/Pages",
5
- "version": "7.7.1",
5
+ "version": "8.0.0",
6
6
  "type": "module",
7
7
  "types": "./dist/index.d.ts",
8
8
  "author": "withastro",
@@ -36,18 +36,17 @@
36
36
  "dotenv": "^16.3.1",
37
37
  "esbuild": "^0.19.5",
38
38
  "find-up": "^6.3.0",
39
- "tiny-glob": "^0.2.9",
40
- "vite": "^4.5.0"
39
+ "tiny-glob": "^0.2.9"
41
40
  },
42
41
  "peerDependencies": {
43
- "astro": "^3.4.3"
42
+ "astro": "^3.0.0 || ^4.0.0"
44
43
  },
45
44
  "devDependencies": {
46
45
  "execa": "^8.0.1",
47
46
  "fast-glob": "^3.3.1",
48
47
  "@types/iarna__toml": "^2.0.2",
49
48
  "strip-ansi": "^7.1.0",
50
- "astro": "^3.4.3",
49
+ "astro": "^4.0.0",
51
50
  "chai": "^4.3.10",
52
51
  "cheerio": "1.0.0-rc.12",
53
52
  "mocha": "^10.2.0",
@@ -1,2 +0,0 @@
1
- import type { IncomingRequestCfProperties } from '@cloudflare/workers-types/experimental';
2
- export declare function getCFObject(runtimeMode: string): Promise<IncomingRequestCfProperties | void>;
@@ -1,67 +0,0 @@
1
- export async function getCFObject(runtimeMode) {
2
- const CF_ENDPOINT = 'https://workers.cloudflare.com/cf.json';
3
- const CF_FALLBACK = {
4
- asOrganization: '',
5
- asn: 395747,
6
- colo: 'DFW',
7
- city: 'Austin',
8
- region: 'Texas',
9
- regionCode: 'TX',
10
- metroCode: '635',
11
- postalCode: '78701',
12
- country: 'US',
13
- continent: 'NA',
14
- timezone: 'America/Chicago',
15
- latitude: '30.27130',
16
- longitude: '-97.74260',
17
- clientTcpRtt: 0,
18
- httpProtocol: 'HTTP/1.1',
19
- requestPriority: 'weight=192;exclusive=0',
20
- tlsCipher: 'AEAD-AES128-GCM-SHA256',
21
- tlsVersion: 'TLSv1.3',
22
- tlsClientAuth: {
23
- certPresented: '0',
24
- certVerified: 'NONE',
25
- certRevoked: '0',
26
- certIssuerDN: '',
27
- certSubjectDN: '',
28
- certIssuerDNRFC2253: '',
29
- certSubjectDNRFC2253: '',
30
- certIssuerDNLegacy: '',
31
- certSubjectDNLegacy: '',
32
- certSerial: '',
33
- certIssuerSerial: '',
34
- certSKI: '',
35
- certIssuerSKI: '',
36
- certFingerprintSHA1: '',
37
- certFingerprintSHA256: '',
38
- certNotBefore: '',
39
- certNotAfter: '',
40
- },
41
- edgeRequestKeepAliveStatus: 0,
42
- hostMetadata: undefined,
43
- clientTrustScore: 99,
44
- botManagement: {
45
- corporateProxy: false,
46
- verifiedBot: false,
47
- ja3Hash: '25b4882c2bcb50cd6b469ff28c596742',
48
- staticResource: false,
49
- detectionIds: [],
50
- score: 99,
51
- },
52
- };
53
- if (runtimeMode === 'local') {
54
- return CF_FALLBACK;
55
- }
56
- else if (runtimeMode === 'remote') {
57
- try {
58
- const res = await fetch(CF_ENDPOINT);
59
- const cfText = await res.text();
60
- const storedCf = JSON.parse(cfText);
61
- return storedCf;
62
- }
63
- catch (e) {
64
- return CF_FALLBACK;
65
- }
66
- }
67
- }