@astrojs/cloudflare 13.0.0-alpha.0 → 13.0.0-alpha.1
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/entrypoints/image-service.js +0 -1
- package/dist/entrypoints/image-transform-endpoint.d.ts +3 -0
- package/dist/entrypoints/image-transform-endpoint.js +10 -0
- package/dist/entrypoints/preview.d.ts +11 -0
- package/dist/entrypoints/preview.js +137 -0
- package/dist/entrypoints/server.d.ts +4 -13
- package/dist/entrypoints/server.js +4 -9
- package/dist/index.d.ts +16 -8
- package/dist/index.js +100 -84
- package/dist/utils/assets.js +1 -45
- package/dist/utils/cloudflare-module-loader.d.ts +1 -5
- package/dist/utils/cloudflare-module-loader.js +10 -36
- package/dist/utils/handler.d.ts +7 -16
- package/dist/utils/handler.js +12 -20
- package/dist/utils/image-binding-transform.d.ts +2 -0
- package/dist/utils/image-binding-transform.js +30 -0
- package/dist/utils/image-config.d.ts +7 -7
- package/dist/utils/image-config.js +7 -0
- package/dist/vite-plugin-config.d.ts +6 -0
- package/dist/vite-plugin-config.js +20 -0
- package/dist/wrangler.d.ts +10 -0
- package/dist/wrangler.js +29 -0
- package/package.json +17 -10
- package/types.d.ts +20 -0
- package/dist/entrypoints/middleware.d.ts +0 -2
- package/dist/entrypoints/middleware.js +0 -11
|
@@ -0,0 +1,10 @@
|
|
|
1
|
+
import { transform } from "../utils/image-binding-transform.js";
|
|
2
|
+
const prerender = false;
|
|
3
|
+
const GET = async (ctx) => {
|
|
4
|
+
const { env } = await import("cloudflare:workers");
|
|
5
|
+
return transform(ctx.request.url, env.IMAGES, env.ASSETS);
|
|
6
|
+
};
|
|
7
|
+
export {
|
|
8
|
+
GET,
|
|
9
|
+
prerender
|
|
10
|
+
};
|
|
@@ -0,0 +1,11 @@
|
|
|
1
|
+
import type { CreatePreviewServer } from 'astro';
|
|
2
|
+
import { type ResolvedServerUrls } from 'vite';
|
|
3
|
+
declare const createPreviewServer: CreatePreviewServer;
|
|
4
|
+
/** Display server host and startup time */
|
|
5
|
+
export declare function serverStart({ startupTime, resolvedUrls, host, base, }: {
|
|
6
|
+
startupTime: number;
|
|
7
|
+
resolvedUrls: ResolvedServerUrls;
|
|
8
|
+
host: string | undefined;
|
|
9
|
+
base: string;
|
|
10
|
+
}): string;
|
|
11
|
+
export { createPreviewServer as default };
|
|
@@ -0,0 +1,137 @@
|
|
|
1
|
+
import {
|
|
2
|
+
preview
|
|
3
|
+
} from "vite";
|
|
4
|
+
import { fileURLToPath } from "node:url";
|
|
5
|
+
import { cloudflare as cfVitePlugin } from "@cloudflare/vite-plugin";
|
|
6
|
+
import colors from "piccolore";
|
|
7
|
+
import { performance } from "node:perf_hooks";
|
|
8
|
+
import { hasWranglerConfig, defaultCloudflareConfig } from "../wrangler.js";
|
|
9
|
+
import { copyFileSync, existsSync } from "node:fs";
|
|
10
|
+
const createPreviewServer = async ({
|
|
11
|
+
logger,
|
|
12
|
+
base,
|
|
13
|
+
outDir,
|
|
14
|
+
headers,
|
|
15
|
+
port,
|
|
16
|
+
host,
|
|
17
|
+
createCodegenDir,
|
|
18
|
+
root
|
|
19
|
+
}) => {
|
|
20
|
+
const startServerTime = performance.now();
|
|
21
|
+
let previewServer;
|
|
22
|
+
let cfPluginConfig = { viteEnvironment: { name: "ssr" } };
|
|
23
|
+
if (!hasWranglerConfig(outDir)) {
|
|
24
|
+
cfPluginConfig.config = defaultCloudflareConfig();
|
|
25
|
+
const codegenDir = createCodegenDir();
|
|
26
|
+
const devVarsPath = new URL(".dev.vars", outDir);
|
|
27
|
+
const devVarsCodegenPath = new URL(".dev.vars", codegenDir);
|
|
28
|
+
if (existsSync(devVarsPath)) {
|
|
29
|
+
copyFileSync(devVarsPath, devVarsCodegenPath);
|
|
30
|
+
}
|
|
31
|
+
}
|
|
32
|
+
try {
|
|
33
|
+
previewServer = await preview({
|
|
34
|
+
configFile: false,
|
|
35
|
+
base,
|
|
36
|
+
appType: "mpa",
|
|
37
|
+
build: {
|
|
38
|
+
outDir: fileURLToPath(outDir)
|
|
39
|
+
},
|
|
40
|
+
root: fileURLToPath(root),
|
|
41
|
+
preview: {
|
|
42
|
+
host,
|
|
43
|
+
port,
|
|
44
|
+
headers,
|
|
45
|
+
open: false,
|
|
46
|
+
allowedHosts: []
|
|
47
|
+
},
|
|
48
|
+
plugins: [cfVitePlugin(cfPluginConfig)]
|
|
49
|
+
});
|
|
50
|
+
} catch (err) {
|
|
51
|
+
if (err instanceof Error) {
|
|
52
|
+
logger.error(err.stack || err.message);
|
|
53
|
+
}
|
|
54
|
+
throw err;
|
|
55
|
+
}
|
|
56
|
+
const customShortcuts = [
|
|
57
|
+
// Disable default Vite shortcuts that don't work well with Astro
|
|
58
|
+
{ key: "r", description: "" },
|
|
59
|
+
{ key: "u", description: "" },
|
|
60
|
+
{ key: "c", description: "" },
|
|
61
|
+
{ key: "s", description: "" }
|
|
62
|
+
];
|
|
63
|
+
previewServer.bindCLIShortcuts({
|
|
64
|
+
customShortcuts
|
|
65
|
+
});
|
|
66
|
+
logger.info(
|
|
67
|
+
serverStart({
|
|
68
|
+
startupTime: performance.now() - startServerTime,
|
|
69
|
+
resolvedUrls: previewServer.resolvedUrls ?? { local: [], network: [] },
|
|
70
|
+
host,
|
|
71
|
+
base
|
|
72
|
+
})
|
|
73
|
+
);
|
|
74
|
+
function closed() {
|
|
75
|
+
return new Promise((resolve, reject) => {
|
|
76
|
+
previewServer.httpServer.addListener("close", resolve);
|
|
77
|
+
previewServer.httpServer.addListener("error", reject);
|
|
78
|
+
});
|
|
79
|
+
}
|
|
80
|
+
return {
|
|
81
|
+
host,
|
|
82
|
+
port,
|
|
83
|
+
closed,
|
|
84
|
+
server: previewServer.httpServer,
|
|
85
|
+
stop: previewServer.close.bind(previewServer)
|
|
86
|
+
};
|
|
87
|
+
};
|
|
88
|
+
function serverStart({
|
|
89
|
+
startupTime,
|
|
90
|
+
resolvedUrls,
|
|
91
|
+
host,
|
|
92
|
+
base
|
|
93
|
+
}) {
|
|
94
|
+
const version = "13.0.0-alpha.1";
|
|
95
|
+
const localPrefix = `${colors.dim("\u2503")} Local `;
|
|
96
|
+
const networkPrefix = `${colors.dim("\u2503")} Network `;
|
|
97
|
+
const emptyPrefix = " ".repeat(11);
|
|
98
|
+
const localUrlMessages = resolvedUrls.local.map((url, i) => {
|
|
99
|
+
return `${i === 0 ? localPrefix : emptyPrefix}${colors.cyan(new URL(url).origin + base)}`;
|
|
100
|
+
});
|
|
101
|
+
const networkUrlMessages = resolvedUrls.network.map((url, i) => {
|
|
102
|
+
return `${i === 0 ? networkPrefix : emptyPrefix}${colors.cyan(new URL(url).origin + base)}`;
|
|
103
|
+
});
|
|
104
|
+
if (networkUrlMessages.length === 0) {
|
|
105
|
+
const networkLogging = getNetworkLogging(host);
|
|
106
|
+
if (networkLogging === "host-to-expose") {
|
|
107
|
+
networkUrlMessages.push(`${networkPrefix}${colors.dim("use --host to expose")}`);
|
|
108
|
+
} else if (networkLogging === "visible") {
|
|
109
|
+
networkUrlMessages.push(`${networkPrefix}${colors.dim("unable to find network to expose")}`);
|
|
110
|
+
}
|
|
111
|
+
}
|
|
112
|
+
const messages = [
|
|
113
|
+
"",
|
|
114
|
+
`${colors.bgGreen(colors.bold(` astro `))} ${colors.green(`v${version}`)} ${colors.dim(`ready in`)} ${Math.round(
|
|
115
|
+
startupTime
|
|
116
|
+
)} ${colors.dim("ms")}`,
|
|
117
|
+
"",
|
|
118
|
+
...localUrlMessages,
|
|
119
|
+
...networkUrlMessages,
|
|
120
|
+
""
|
|
121
|
+
];
|
|
122
|
+
return messages.filter((msg) => typeof msg === "string").join("\n");
|
|
123
|
+
}
|
|
124
|
+
const LOCAL_IP_HOSTS = /* @__PURE__ */ new Set(["localhost", "127.0.0.1"]);
|
|
125
|
+
function getNetworkLogging(host) {
|
|
126
|
+
if (!host) {
|
|
127
|
+
return "host-to-expose";
|
|
128
|
+
} else if (typeof host === "string" && LOCAL_IP_HOSTS.has(host)) {
|
|
129
|
+
return "none";
|
|
130
|
+
} else {
|
|
131
|
+
return "visible";
|
|
132
|
+
}
|
|
133
|
+
}
|
|
134
|
+
export {
|
|
135
|
+
createPreviewServer as default,
|
|
136
|
+
serverStart
|
|
137
|
+
};
|
|
@@ -1,14 +1,5 @@
|
|
|
1
|
-
import
|
|
2
|
-
|
|
3
|
-
|
|
4
|
-
[key: string]: unknown;
|
|
5
|
-
ASSETS: {
|
|
6
|
-
fetch: (req: Request | string) => Promise<Response>;
|
|
7
|
-
};
|
|
1
|
+
import { handle } from '../utils/handler.js';
|
|
2
|
+
declare const _default: {
|
|
3
|
+
fetch: typeof handle;
|
|
8
4
|
};
|
|
9
|
-
export
|
|
10
|
-
default: {
|
|
11
|
-
fetch: (request: Parameters<ExportedHandlerFetchHandler>[0], env: Env, context: ExecutionContext) => Promise<Response>;
|
|
12
|
-
};
|
|
13
|
-
};
|
|
14
|
-
export {};
|
|
5
|
+
export default _default;
|
|
@@ -1,12 +1,7 @@
|
|
|
1
|
-
import { App } from "astro/app";
|
|
2
1
|
import { handle } from "../utils/handler.js";
|
|
3
|
-
|
|
4
|
-
|
|
5
|
-
|
|
6
|
-
return await handle(manifest, app, request, env, context);
|
|
7
|
-
};
|
|
8
|
-
return { default: { fetch } };
|
|
9
|
-
}
|
|
2
|
+
var server_default = {
|
|
3
|
+
fetch: handle
|
|
4
|
+
};
|
|
10
5
|
export {
|
|
11
|
-
|
|
6
|
+
server_default as default
|
|
12
7
|
};
|
package/dist/index.d.ts
CHANGED
|
@@ -1,5 +1,4 @@
|
|
|
1
1
|
import type { AstroIntegration } from 'astro';
|
|
2
|
-
import { type GetPlatformProxyOptions } from 'wrangler';
|
|
3
2
|
import { type ImageService } from './utils/image-config.js';
|
|
4
3
|
export type { Runtime } from './utils/handler.js';
|
|
5
4
|
export type Options = {
|
|
@@ -29,13 +28,6 @@ export type Options = {
|
|
|
29
28
|
}[];
|
|
30
29
|
};
|
|
31
30
|
};
|
|
32
|
-
/**
|
|
33
|
-
* Proxy configuration for the platform.
|
|
34
|
-
*/
|
|
35
|
-
platformProxy?: GetPlatformProxyOptions & {
|
|
36
|
-
/** Toggle the proxy. Default `undefined`, which equals to `true`. */
|
|
37
|
-
enabled?: boolean;
|
|
38
|
-
};
|
|
39
31
|
/**
|
|
40
32
|
* Allow bundling cloudflare worker specific file types as importable modules. Defaults to true.
|
|
41
33
|
* When enabled, allows imports of '.wasm', '.bin', and '.txt' file types
|
|
@@ -70,6 +62,22 @@ export type Options = {
|
|
|
70
62
|
*
|
|
71
63
|
*/
|
|
72
64
|
sessionKVBindingName?: string;
|
|
65
|
+
/**
|
|
66
|
+
* When configured as `cloudflare-binding`, the Cloudflare Images binding will be used to transform images:
|
|
67
|
+
* - https://developers.cloudflare.com/images/transform-images/bindings/
|
|
68
|
+
*
|
|
69
|
+
* By default, this will use the "IMAGES" binding name, but this can be customised in your `wrangler.json`:
|
|
70
|
+
*
|
|
71
|
+
* ```json
|
|
72
|
+
* {
|
|
73
|
+
* "images": {
|
|
74
|
+
* "binding": "IMAGES" // <-- this should match `imagesBindingName`
|
|
75
|
+
* }
|
|
76
|
+
* }
|
|
77
|
+
* ```
|
|
78
|
+
*
|
|
79
|
+
*/
|
|
80
|
+
imagesBindingName?: string;
|
|
73
81
|
/**
|
|
74
82
|
* This configuration option allows you to specify a custom entryPoint for your Cloudflare Worker.
|
|
75
83
|
* The entry point is the file that will be executed when your Worker is invoked.
|
package/dist/index.js
CHANGED
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import { createReadStream } from "node:fs";
|
|
1
|
+
import { createReadStream, copyFileSync, existsSync, readFileSync } from "node:fs";
|
|
2
2
|
import { appendFile, stat } from "node:fs/promises";
|
|
3
3
|
import { createRequire } from "node:module";
|
|
4
4
|
import { createInterface } from "node:readline/promises";
|
|
@@ -9,29 +9,16 @@ import {
|
|
|
9
9
|
removeLeadingForwardSlash
|
|
10
10
|
} from "@astrojs/internal-helpers/path";
|
|
11
11
|
import { createRedirectsFromAstroRoutes, printAsRedirects } from "@astrojs/underscore-redirects";
|
|
12
|
-
import {
|
|
13
|
-
import {
|
|
14
|
-
import { getPlatformProxy } from "wrangler";
|
|
15
|
-
import {
|
|
16
|
-
cloudflareModuleLoader
|
|
17
|
-
} from "./utils/cloudflare-module-loader.js";
|
|
18
|
-
import { createGetEnv } from "./utils/env.js";
|
|
12
|
+
import { cloudflare as cfVitePlugin } from "@cloudflare/vite-plugin";
|
|
13
|
+
import { cloudflareModuleLoader } from "./utils/cloudflare-module-loader.js";
|
|
19
14
|
import { createRoutesFile, getParts } from "./utils/generate-routes-json.js";
|
|
20
15
|
import { setImageConfig } from "./utils/image-config.js";
|
|
16
|
+
import { createConfigPlugin } from "./vite-plugin-config.js";
|
|
17
|
+
import { hasWranglerConfig, defaultCloudflareConfig } from "./wrangler.js";
|
|
18
|
+
import { parse } from "dotenv";
|
|
21
19
|
function wrapWithSlashes(path) {
|
|
22
20
|
return prependForwardSlash(appendForwardSlash(path));
|
|
23
21
|
}
|
|
24
|
-
function setProcessEnv(config, env) {
|
|
25
|
-
const getEnv = createGetEnv(env);
|
|
26
|
-
if (config.env?.schema) {
|
|
27
|
-
for (const key of Object.keys(config.env.schema)) {
|
|
28
|
-
const value = getEnv(key);
|
|
29
|
-
if (value !== void 0) {
|
|
30
|
-
process.env[key] = value;
|
|
31
|
-
}
|
|
32
|
-
}
|
|
33
|
-
}
|
|
34
|
-
}
|
|
35
22
|
function createIntegration(args) {
|
|
36
23
|
let _config;
|
|
37
24
|
let finalBuildOutput;
|
|
@@ -49,9 +36,18 @@ function createIntegration(args) {
|
|
|
49
36
|
updateConfig,
|
|
50
37
|
logger,
|
|
51
38
|
addWatchFile,
|
|
52
|
-
|
|
39
|
+
createCodegenDir
|
|
53
40
|
}) => {
|
|
54
41
|
let session = config.session;
|
|
42
|
+
if (args?.imageService === "cloudflare-binding") {
|
|
43
|
+
const bindingName = args?.imagesBindingName ?? "IMAGES";
|
|
44
|
+
logger.info(
|
|
45
|
+
`Enabling image processing with Cloudflare Images for production with the "${bindingName}" Images binding.`
|
|
46
|
+
);
|
|
47
|
+
logger.info(
|
|
48
|
+
`If you see the error "Invalid binding \`${bindingName}\`" in your build output, you need to add the binding to your wrangler config file.`
|
|
49
|
+
);
|
|
50
|
+
}
|
|
55
51
|
if (!session?.driver) {
|
|
56
52
|
logger.info(
|
|
57
53
|
`Enabling sessions with Cloudflare KV with the "${SESSION_KV_BINDING_NAME}" KV binding.`
|
|
@@ -68,6 +64,16 @@ function createIntegration(args) {
|
|
|
68
64
|
}
|
|
69
65
|
};
|
|
70
66
|
}
|
|
67
|
+
const cfPluginConfig = { viteEnvironment: { name: "ssr" } };
|
|
68
|
+
if (!hasWranglerConfig(config.root)) {
|
|
69
|
+
cfPluginConfig.config = defaultCloudflareConfig();
|
|
70
|
+
const codegenDir = createCodegenDir();
|
|
71
|
+
const devVarsPath = new URL(".dev.vars", config.root);
|
|
72
|
+
const devVarsCodegenPath = new URL(".dev.vars", codegenDir);
|
|
73
|
+
if (existsSync(devVarsPath)) {
|
|
74
|
+
copyFileSync(devVarsPath, devVarsCodegenPath);
|
|
75
|
+
}
|
|
76
|
+
}
|
|
71
77
|
updateConfig({
|
|
72
78
|
build: {
|
|
73
79
|
client: new URL(`.${wrapWithSlashes(config.base)}`, config.outDir),
|
|
@@ -78,11 +84,12 @@ function createIntegration(args) {
|
|
|
78
84
|
session,
|
|
79
85
|
vite: {
|
|
80
86
|
plugins: [
|
|
87
|
+
cfVitePlugin(cfPluginConfig),
|
|
81
88
|
// https://developers.cloudflare.com/pages/functions/module-support/
|
|
82
89
|
// Allows imports of '.wasm', '.bin', and '.txt' file types
|
|
83
90
|
cloudflareModulePlugin,
|
|
84
91
|
{
|
|
85
|
-
name: "
|
|
92
|
+
name: "@astrojs/cloudflare:cf-imports",
|
|
86
93
|
enforce: "pre",
|
|
87
94
|
resolveId(source) {
|
|
88
95
|
if (source.startsWith("cloudflare:")) {
|
|
@@ -90,29 +97,72 @@ function createIntegration(args) {
|
|
|
90
97
|
}
|
|
91
98
|
return null;
|
|
92
99
|
}
|
|
93
|
-
}
|
|
100
|
+
},
|
|
101
|
+
{
|
|
102
|
+
name: "@astrojs/cloudflare:environment",
|
|
103
|
+
configEnvironment(environmentName, _options) {
|
|
104
|
+
const isServerEnvironment = ["ssr", "prerender"].includes(environmentName);
|
|
105
|
+
if (isServerEnvironment && _options.optimizeDeps?.noDiscovery === false) {
|
|
106
|
+
return {
|
|
107
|
+
optimizeDeps: {
|
|
108
|
+
include: [
|
|
109
|
+
"astro",
|
|
110
|
+
"astro/runtime/**",
|
|
111
|
+
"astro > html-escaper",
|
|
112
|
+
"astro > mrmime",
|
|
113
|
+
"astro > zod/v4",
|
|
114
|
+
"astro > zod/v4/core",
|
|
115
|
+
"astro > clsx",
|
|
116
|
+
"astro > cssesc",
|
|
117
|
+
"astro > cookie",
|
|
118
|
+
"astro > devalue",
|
|
119
|
+
"astro > @oslojs/encoding",
|
|
120
|
+
"astro > es-module-lexer",
|
|
121
|
+
"astro > unstorage",
|
|
122
|
+
"astro > neotraverse/modern"
|
|
123
|
+
],
|
|
124
|
+
exclude: [
|
|
125
|
+
"unstorage/drivers/cloudflare-kv-binding",
|
|
126
|
+
"astro:toolbar:internal",
|
|
127
|
+
"virtual:astro:middleware"
|
|
128
|
+
]
|
|
129
|
+
}
|
|
130
|
+
};
|
|
131
|
+
}
|
|
132
|
+
}
|
|
133
|
+
},
|
|
134
|
+
{
|
|
135
|
+
enforce: "post",
|
|
136
|
+
name: "@astrojs/cloudflare:cf-externals",
|
|
137
|
+
applyToEnvironment: (environment) => environment.name === "ssr",
|
|
138
|
+
config(conf) {
|
|
139
|
+
if (conf.ssr) {
|
|
140
|
+
conf.ssr.external = void 0;
|
|
141
|
+
conf.ssr.noExternal = true;
|
|
142
|
+
}
|
|
143
|
+
}
|
|
144
|
+
},
|
|
145
|
+
createConfigPlugin({
|
|
146
|
+
sessionKVBindingName: SESSION_KV_BINDING_NAME
|
|
147
|
+
})
|
|
94
148
|
]
|
|
95
149
|
},
|
|
96
150
|
image: setImageConfig(args?.imageService ?? "compile", config.image, command, logger)
|
|
97
151
|
});
|
|
98
|
-
|
|
99
|
-
|
|
100
|
-
|
|
101
|
-
addWatchFile(new URL("./wrangler.toml", config.root));
|
|
102
|
-
addWatchFile(new URL("./wrangler.json", config.root));
|
|
103
|
-
addWatchFile(new URL("./wrangler.jsonc", config.root));
|
|
104
|
-
}
|
|
105
|
-
addMiddleware({
|
|
106
|
-
entrypoint: "@astrojs/cloudflare/entrypoints/middleware.js",
|
|
107
|
-
order: "pre"
|
|
108
|
-
});
|
|
152
|
+
addWatchFile(new URL("./wrangler.toml", config.root));
|
|
153
|
+
addWatchFile(new URL("./wrangler.json", config.root));
|
|
154
|
+
addWatchFile(new URL("./wrangler.jsonc", config.root));
|
|
109
155
|
},
|
|
110
156
|
"astro:routes:resolved": ({ routes }) => {
|
|
111
157
|
_routes = routes;
|
|
112
158
|
},
|
|
113
|
-
"astro:config:done": ({ setAdapter, config, buildOutput }) => {
|
|
159
|
+
"astro:config:done": ({ setAdapter, config, buildOutput, injectTypes, logger }) => {
|
|
114
160
|
_config = config;
|
|
115
161
|
finalBuildOutput = buildOutput;
|
|
162
|
+
injectTypes({
|
|
163
|
+
filename: "cloudflare.d.ts",
|
|
164
|
+
content: '/// <reference types="@astrojs/cloudflare/types.d.ts" />'
|
|
165
|
+
});
|
|
116
166
|
let customWorkerEntryPoint;
|
|
117
167
|
if (args?.workerEntryPoint && typeof args.workerEntryPoint.path === "string") {
|
|
118
168
|
const require2 = createRequire(config.root);
|
|
@@ -130,6 +180,7 @@ function createIntegration(args) {
|
|
|
130
180
|
edgeMiddleware: false,
|
|
131
181
|
buildOutput: "server"
|
|
132
182
|
},
|
|
183
|
+
previewEntrypoint: "@astrojs/cloudflare/entrypoints/preview",
|
|
133
184
|
supportedAstroFeatures: {
|
|
134
185
|
serverOutput: "stable",
|
|
135
186
|
hybridOutput: "stable",
|
|
@@ -145,75 +196,40 @@ function createIntegration(args) {
|
|
|
145
196
|
envGetSecret: "stable"
|
|
146
197
|
}
|
|
147
198
|
});
|
|
148
|
-
|
|
149
|
-
|
|
150
|
-
|
|
151
|
-
|
|
152
|
-
|
|
153
|
-
|
|
154
|
-
}
|
|
155
|
-
|
|
156
|
-
|
|
157
|
-
|
|
158
|
-
|
|
159
|
-
server.middlewares.use(async function middleware(req, _res, next) {
|
|
160
|
-
Reflect.set(req, clientLocalsSymbol, {
|
|
161
|
-
runtime: {
|
|
162
|
-
env: platformProxy.env,
|
|
163
|
-
cf: platformProxy.cf,
|
|
164
|
-
caches: platformProxy.caches,
|
|
165
|
-
ctx: {
|
|
166
|
-
waitUntil: (promise) => platformProxy.ctx.waitUntil(promise),
|
|
167
|
-
// Currently not available: https://developers.cloudflare.com/pages/platform/known-issues/#pages-functions
|
|
168
|
-
passThroughOnException: () => {
|
|
169
|
-
throw new AstroError(
|
|
170
|
-
"`passThroughOnException` is currently not available in Cloudflare Pages. See https://developers.cloudflare.com/pages/platform/known-issues/#pages-functions."
|
|
171
|
-
);
|
|
172
|
-
}
|
|
173
|
-
}
|
|
174
|
-
}
|
|
175
|
-
});
|
|
176
|
-
next();
|
|
177
|
-
});
|
|
199
|
+
const devVarsPath = new URL(".dev.vars", config.root);
|
|
200
|
+
if (existsSync(devVarsPath)) {
|
|
201
|
+
try {
|
|
202
|
+
const data = readFileSync(devVarsPath, "utf-8");
|
|
203
|
+
const parsed = parse(data);
|
|
204
|
+
Object.assign(process.env, parsed);
|
|
205
|
+
} catch {
|
|
206
|
+
logger.error(
|
|
207
|
+
`Unable to parse .dev.vars, variables will not be available to your application.`
|
|
208
|
+
);
|
|
209
|
+
}
|
|
178
210
|
}
|
|
179
211
|
},
|
|
180
212
|
"astro:build:setup": ({ vite, target }) => {
|
|
181
213
|
if (target === "server") {
|
|
182
214
|
vite.resolve ||= {};
|
|
183
215
|
vite.resolve.alias ||= {};
|
|
184
|
-
const aliases = [
|
|
185
|
-
{
|
|
186
|
-
find: "react-dom/server",
|
|
187
|
-
replacement: "react-dom/server.browser"
|
|
188
|
-
}
|
|
189
|
-
];
|
|
190
|
-
if (Array.isArray(vite.resolve.alias)) {
|
|
191
|
-
vite.resolve.alias = [...vite.resolve.alias, ...aliases];
|
|
192
|
-
} else {
|
|
193
|
-
for (const alias of aliases) {
|
|
194
|
-
vite.resolve.alias[alias.find] = alias.replacement;
|
|
195
|
-
}
|
|
196
|
-
}
|
|
197
216
|
vite.ssr ||= {};
|
|
198
|
-
vite.ssr.resolve ||= {};
|
|
199
|
-
vite.ssr.resolve.conditions ||= [...defaultClientConditions];
|
|
200
|
-
vite.ssr.resolve.conditions.push("workerd", "worker");
|
|
201
|
-
vite.ssr.target = "webworker";
|
|
202
217
|
vite.ssr.noExternal = true;
|
|
203
218
|
vite.build ||= {};
|
|
204
219
|
vite.build.rollupOptions ||= {};
|
|
205
220
|
vite.build.rollupOptions.output ||= {};
|
|
221
|
+
vite.build.rollupOptions.external = ["sharp"];
|
|
206
222
|
vite.build.rollupOptions.output.banner ||= "globalThis.process ??= {}; globalThis.process.env ??= {};";
|
|
207
223
|
vite.define = {
|
|
208
224
|
"process.env": "process.env",
|
|
209
|
-
|
|
210
|
-
|
|
225
|
+
"globalThis.__ASTRO_IMAGES_BINDING_NAME": JSON.stringify(
|
|
226
|
+
args?.imagesBindingName ?? "IMAGES"
|
|
227
|
+
),
|
|
211
228
|
...vite.define
|
|
212
229
|
};
|
|
213
230
|
}
|
|
214
231
|
},
|
|
215
232
|
"astro:build:done": async ({ pages, dir, logger, assets }) => {
|
|
216
|
-
await cloudflareModulePlugin.afterBuildCompleted(_config);
|
|
217
233
|
let redirectsExists = false;
|
|
218
234
|
try {
|
|
219
235
|
const redirectsStat = await stat(new URL("./_redirects", _config.outDir));
|
package/dist/utils/assets.js
CHANGED
|
@@ -1,49 +1,5 @@
|
|
|
1
1
|
import { isRemotePath } from "@astrojs/internal-helpers/path";
|
|
2
|
-
|
|
3
|
-
if (!hostname) {
|
|
4
|
-
return true;
|
|
5
|
-
}
|
|
6
|
-
if (!allowWildcard || !hostname.startsWith("*")) {
|
|
7
|
-
return hostname === url.hostname;
|
|
8
|
-
}
|
|
9
|
-
if (hostname.startsWith("**.")) {
|
|
10
|
-
const slicedHostname = hostname.slice(2);
|
|
11
|
-
return slicedHostname !== url.hostname && url.hostname.endsWith(slicedHostname);
|
|
12
|
-
}
|
|
13
|
-
if (hostname.startsWith("*.")) {
|
|
14
|
-
const slicedHostname = hostname.slice(1);
|
|
15
|
-
const additionalSubdomains = url.hostname.replace(slicedHostname, "").split(".").filter(Boolean);
|
|
16
|
-
return additionalSubdomains.length === 1;
|
|
17
|
-
}
|
|
18
|
-
return false;
|
|
19
|
-
}
|
|
20
|
-
function matchPort(url, port) {
|
|
21
|
-
return !port || port === url.port;
|
|
22
|
-
}
|
|
23
|
-
function matchProtocol(url, protocol) {
|
|
24
|
-
return !protocol || protocol === url.protocol.slice(0, -1);
|
|
25
|
-
}
|
|
26
|
-
function matchPathname(url, pathname, allowWildcard) {
|
|
27
|
-
if (!pathname) {
|
|
28
|
-
return true;
|
|
29
|
-
}
|
|
30
|
-
if (!allowWildcard || !pathname.endsWith("*")) {
|
|
31
|
-
return pathname === url.pathname;
|
|
32
|
-
}
|
|
33
|
-
if (pathname.endsWith("/**")) {
|
|
34
|
-
const slicedPathname = pathname.slice(0, -2);
|
|
35
|
-
return slicedPathname !== url.pathname && url.pathname.startsWith(slicedPathname);
|
|
36
|
-
}
|
|
37
|
-
if (pathname.endsWith("/*")) {
|
|
38
|
-
const slicedPathname = pathname.slice(0, -1);
|
|
39
|
-
const additionalPathChunks = url.pathname.replace(slicedPathname, "").split("/").filter(Boolean);
|
|
40
|
-
return additionalPathChunks.length === 1;
|
|
41
|
-
}
|
|
42
|
-
return false;
|
|
43
|
-
}
|
|
44
|
-
function matchPattern(url, remotePattern) {
|
|
45
|
-
return matchProtocol(url, remotePattern.protocol) && matchHostname(url, remotePattern.hostname, true) && matchPort(url, remotePattern.port) && matchPathname(url, remotePattern.pathname, true);
|
|
46
|
-
}
|
|
2
|
+
import { matchHostname, matchPattern } from "@astrojs/internal-helpers/remote";
|
|
47
3
|
function isRemoteAllowed(src, {
|
|
48
4
|
domains = [],
|
|
49
5
|
remotePatterns = []
|
|
@@ -1,8 +1,4 @@
|
|
|
1
|
-
import type { AstroConfig } from 'astro';
|
|
2
1
|
import type { PluginOption } from 'vite';
|
|
3
|
-
export interface CloudflareModulePluginExtra {
|
|
4
|
-
afterBuildCompleted(config: AstroConfig): Promise<void>;
|
|
5
|
-
}
|
|
6
2
|
/**
|
|
7
3
|
* Enables support for various non-standard extensions in module imports that cloudflare workers supports.
|
|
8
4
|
*
|
|
@@ -17,4 +13,4 @@ export interface CloudflareModulePluginExtra {
|
|
|
17
13
|
* @param enabled - if true, will load all cloudflare pages supported types
|
|
18
14
|
* @returns Vite plugin with additional extension method to hook into astro build
|
|
19
15
|
*/
|
|
20
|
-
export declare function cloudflareModuleLoader(enabled: boolean): PluginOption
|
|
16
|
+
export declare function cloudflareModuleLoader(enabled: boolean): PluginOption;
|
|
@@ -1,6 +1,5 @@
|
|
|
1
1
|
import * as fs from "node:fs/promises";
|
|
2
2
|
import * as path from "node:path";
|
|
3
|
-
import * as url from "node:url";
|
|
4
3
|
function cloudflareModuleLoader(enabled) {
|
|
5
4
|
const adaptersByExtension = enabled ? { ...defaultAdapters } : {};
|
|
6
5
|
const extensions = Object.keys(adaptersByExtension);
|
|
@@ -10,6 +9,9 @@ function cloudflareModuleLoader(enabled) {
|
|
|
10
9
|
return {
|
|
11
10
|
name: "vite:cf-module-loader",
|
|
12
11
|
enforce: "pre",
|
|
12
|
+
applyToEnvironment(environment) {
|
|
13
|
+
return environment.name === "ssr" || environment.name === "client";
|
|
14
|
+
},
|
|
13
15
|
configResolved(config) {
|
|
14
16
|
isDev = config.command === "serve";
|
|
15
17
|
},
|
|
@@ -20,7 +22,7 @@ function cloudflareModuleLoader(enabled) {
|
|
|
20
22
|
rollupOptions: {
|
|
21
23
|
// mark the wasm files as external so that they are not bundled and instead are loaded from the files
|
|
22
24
|
external: extensions.map(
|
|
23
|
-
(x) => new RegExp(`^${MAGIC_STRING}.+${escapeRegExp(x)}
|
|
25
|
+
(x) => new RegExp(`^${MAGIC_STRING}.+${escapeRegExp(x)}$`, "i")
|
|
24
26
|
)
|
|
25
27
|
}
|
|
26
28
|
}
|
|
@@ -50,18 +52,18 @@ function cloudflareModuleLoader(enabled) {
|
|
|
50
52
|
const assetName = `${path.basename(filePath).split(".")[0]}.${hash}${extension}`;
|
|
51
53
|
this.emitFile({
|
|
52
54
|
type: "asset",
|
|
53
|
-
// emit the data explicitly as an
|
|
55
|
+
// emit the data explicitly as an asset with `fileName` rather than `name` so that
|
|
54
56
|
// vite doesn't give it a random hash-id in its name--We need to be able to easily rewrite from
|
|
55
|
-
// the
|
|
57
|
+
// the loader and the actual asset later in the build for the worker
|
|
56
58
|
fileName: assetName,
|
|
57
59
|
source: data
|
|
58
60
|
});
|
|
59
61
|
const chunkId = this.emitFile({
|
|
60
62
|
type: "prebuilt-chunk",
|
|
61
|
-
fileName:
|
|
63
|
+
fileName: assetName,
|
|
62
64
|
code: inlineModule
|
|
63
65
|
});
|
|
64
|
-
return `import module from "${MAGIC_STRING}${chunkId}${extension}
|
|
66
|
+
return `import module from "${MAGIC_STRING}${chunkId}${extension}";export default module;`;
|
|
65
67
|
},
|
|
66
68
|
// output original wasm file relative to the chunk now that chunking has been achieved
|
|
67
69
|
renderChunk(code, chunk, _) {
|
|
@@ -71,13 +73,13 @@ function cloudflareModuleLoader(enabled) {
|
|
|
71
73
|
for (const ext of extensions) {
|
|
72
74
|
const extension = ext.replace(/\?\w+$/, "");
|
|
73
75
|
replaced = replaced.replaceAll(
|
|
74
|
-
new RegExp(`${MAGIC_STRING}([^\\s]+?)${escapeRegExp(extension)}
|
|
76
|
+
new RegExp(`${MAGIC_STRING}([^\\s]+?)${escapeRegExp(extension)}`, "g"),
|
|
75
77
|
(_s, assetId) => {
|
|
76
78
|
const fileName = this.getFileName(assetId);
|
|
77
79
|
const relativePath = path.relative(path.dirname(chunk.fileName), fileName).replaceAll("\\", "/");
|
|
78
80
|
replacements.push({
|
|
79
81
|
chunkName: chunk.name,
|
|
80
|
-
cloudflareImport: relativePath
|
|
82
|
+
cloudflareImport: relativePath,
|
|
81
83
|
nodejsImport: relativePath
|
|
82
84
|
});
|
|
83
85
|
return `./${relativePath}`;
|
|
@@ -104,34 +106,6 @@ function cloudflareModuleLoader(enabled) {
|
|
|
104
106
|
replacement.fileName.push(chunk.fileName);
|
|
105
107
|
}
|
|
106
108
|
}
|
|
107
|
-
},
|
|
108
|
-
/**
|
|
109
|
-
* Once prerendering is complete, restore the imports in the _worker.js to cloudflare compatible ones, removing the .mjs suffix.
|
|
110
|
-
*/
|
|
111
|
-
async afterBuildCompleted(config) {
|
|
112
|
-
const baseDir = url.fileURLToPath(config.outDir);
|
|
113
|
-
const replacementsByFileName = /* @__PURE__ */ new Map();
|
|
114
|
-
for (const replacement of replacements) {
|
|
115
|
-
if (!replacement.fileName) {
|
|
116
|
-
continue;
|
|
117
|
-
}
|
|
118
|
-
for (const fileName of replacement.fileName) {
|
|
119
|
-
const repls = replacementsByFileName.get(fileName) || [];
|
|
120
|
-
if (!repls.length) {
|
|
121
|
-
replacementsByFileName.set(fileName, repls);
|
|
122
|
-
}
|
|
123
|
-
repls.push(replacement);
|
|
124
|
-
}
|
|
125
|
-
}
|
|
126
|
-
for (const [fileName, repls] of replacementsByFileName.entries()) {
|
|
127
|
-
const filepath = path.join(baseDir, "_worker.js", fileName);
|
|
128
|
-
const contents = await fs.readFile(filepath, "utf-8");
|
|
129
|
-
let updated = contents;
|
|
130
|
-
for (const replacement of repls) {
|
|
131
|
-
updated = updated.replaceAll(replacement.nodejsImport, replacement.cloudflareImport);
|
|
132
|
-
}
|
|
133
|
-
await fs.writeFile(filepath, updated, "utf-8");
|
|
134
|
-
}
|
|
135
109
|
}
|
|
136
110
|
};
|
|
137
111
|
}
|
package/dist/utils/handler.d.ts
CHANGED
|
@@ -1,23 +1,14 @@
|
|
|
1
|
-
import type {
|
|
2
|
-
|
|
3
|
-
import type { App } from 'astro/app';
|
|
4
|
-
type Env = {
|
|
1
|
+
import type { Response as CfResponse, ExecutionContext, ExportedHandlerFetchHandler } from '@cloudflare/workers-types';
|
|
2
|
+
export type Env = {
|
|
5
3
|
[key: string]: unknown;
|
|
6
4
|
ASSETS: {
|
|
7
|
-
fetch: (req: Request | string) => Promise<
|
|
5
|
+
fetch: (req: Request | string) => Promise<CfResponse>;
|
|
8
6
|
};
|
|
9
7
|
};
|
|
10
|
-
export interface Runtime
|
|
11
|
-
|
|
12
|
-
env: Env & T;
|
|
13
|
-
cf: Parameters<ExportedHandlerFetchHandler>[0]['cf'];
|
|
14
|
-
caches: CloudflareCacheStorage;
|
|
15
|
-
ctx: ExecutionContext;
|
|
16
|
-
};
|
|
8
|
+
export interface Runtime {
|
|
9
|
+
cfContext: ExecutionContext;
|
|
17
10
|
}
|
|
18
11
|
declare global {
|
|
19
|
-
var
|
|
20
|
-
var __env__: Partial<Env>;
|
|
12
|
+
var __ASTRO_IMAGES_BINDING_NAME: string;
|
|
21
13
|
}
|
|
22
|
-
export declare function handle(
|
|
23
|
-
export {};
|
|
14
|
+
export declare function handle(request: Parameters<ExportedHandlerFetchHandler>[0], env: Env, context: ExecutionContext): Promise<CfResponse>;
|
package/dist/utils/handler.js
CHANGED
|
@@ -1,13 +1,19 @@
|
|
|
1
1
|
import { env as globalEnv } from "cloudflare:workers";
|
|
2
|
+
import { sessionKVBindingName } from "virtual:astro-cloudflare:config";
|
|
3
|
+
import { createApp } from "astro/app/entrypoint";
|
|
2
4
|
import { setGetEnv } from "astro/env/setup";
|
|
3
5
|
import { createGetEnv } from "../utils/env.js";
|
|
4
6
|
setGetEnv(createGetEnv(globalEnv));
|
|
5
|
-
async function handle(
|
|
7
|
+
async function handle(request, env, context) {
|
|
8
|
+
const app = createApp(import.meta.env.DEV);
|
|
6
9
|
const { pathname } = new URL(request.url);
|
|
7
|
-
|
|
8
|
-
|
|
9
|
-
|
|
10
|
-
|
|
10
|
+
if (env[sessionKVBindingName]) {
|
|
11
|
+
const sessionConfigOptions = app.manifest.sessionConfig?.options ?? {};
|
|
12
|
+
Object.assign(sessionConfigOptions, {
|
|
13
|
+
binding: env[sessionKVBindingName]
|
|
14
|
+
});
|
|
15
|
+
}
|
|
16
|
+
if (app.manifest.assets.has(pathname)) {
|
|
11
17
|
return env.ASSETS.fetch(request.url.replace(/\.html$/, ""));
|
|
12
18
|
}
|
|
13
19
|
const routeData = app.match(request);
|
|
@@ -20,21 +26,7 @@ async function handle(manifest, app, request, env, context) {
|
|
|
20
26
|
}
|
|
21
27
|
}
|
|
22
28
|
const locals = {
|
|
23
|
-
|
|
24
|
-
env,
|
|
25
|
-
cf: request.cf,
|
|
26
|
-
caches,
|
|
27
|
-
ctx: {
|
|
28
|
-
waitUntil: (promise) => context.waitUntil(promise),
|
|
29
|
-
// Currently not available: https://developers.cloudflare.com/pages/platform/known-issues/#pages-functions
|
|
30
|
-
passThroughOnException: () => {
|
|
31
|
-
throw new Error(
|
|
32
|
-
"`passThroughOnException` is currently not available in Cloudflare Pages. See https://developers.cloudflare.com/pages/platform/known-issues/#pages-functions."
|
|
33
|
-
);
|
|
34
|
-
},
|
|
35
|
-
props: {}
|
|
36
|
-
}
|
|
37
|
-
}
|
|
29
|
+
cfContext: context
|
|
38
30
|
};
|
|
39
31
|
const response = await app.render(
|
|
40
32
|
request,
|
|
@@ -0,0 +1,30 @@
|
|
|
1
|
+
import { imageConfig } from "astro:assets";
|
|
2
|
+
import { isRemotePath } from "@astrojs/internal-helpers/path";
|
|
3
|
+
import { isRemoteAllowed } from "@astrojs/internal-helpers/remote";
|
|
4
|
+
async function transform(rawUrl, images, assets) {
|
|
5
|
+
const url = new URL(rawUrl);
|
|
6
|
+
const href = url.searchParams.get("href");
|
|
7
|
+
if (!href || isRemotePath(href) && !isRemoteAllowed(href, imageConfig)) {
|
|
8
|
+
return new Response("Forbidden", { status: 403 });
|
|
9
|
+
}
|
|
10
|
+
const imageSrc = new URL(href, url.origin);
|
|
11
|
+
const content = await (isRemotePath(href) ? fetch(imageSrc) : assets.fetch(imageSrc));
|
|
12
|
+
if (!content.body) {
|
|
13
|
+
return new Response(null, { status: 404 });
|
|
14
|
+
}
|
|
15
|
+
const input = images.input(content.body);
|
|
16
|
+
const format = url.searchParams.get("f");
|
|
17
|
+
if (!format || !["avif", "webp", "jpeg"].includes(format)) {
|
|
18
|
+
return new Response(`The "${format}" format is not supported`, { status: 400 });
|
|
19
|
+
}
|
|
20
|
+
return (await input.transform({
|
|
21
|
+
width: url.searchParams.has("w") ? parseInt(url.searchParams.get("w")) : void 0,
|
|
22
|
+
height: url.searchParams.has("h") ? parseInt(url.searchParams.get("h")) : void 0,
|
|
23
|
+
// `quality` is documented, but doesn't appear to work in manual testing...
|
|
24
|
+
// quality: url.searchParams.get('q'),
|
|
25
|
+
fit: url.searchParams.get("fit")
|
|
26
|
+
}).output({ format: `image/${format}` })).response();
|
|
27
|
+
}
|
|
28
|
+
export {
|
|
29
|
+
transform
|
|
30
|
+
};
|
|
@@ -1,20 +1,20 @@
|
|
|
1
1
|
import type { AstroConfig, AstroIntegrationLogger, HookParameters } from 'astro';
|
|
2
|
-
export type ImageService = 'passthrough' | 'cloudflare' | 'compile' | 'custom';
|
|
2
|
+
export type ImageService = 'passthrough' | 'cloudflare' | 'cloudflare-binding' | 'compile' | 'custom';
|
|
3
3
|
export declare function setImageConfig(service: ImageService, config: AstroConfig['image'], command: HookParameters<'astro:config:setup'>['command'], logger: AstroIntegrationLogger): {
|
|
4
4
|
service: import("astro").ImageServiceConfig<Record<string, any>>;
|
|
5
|
-
responsiveStyles: boolean;
|
|
6
5
|
endpoint: {
|
|
7
6
|
route: string;
|
|
8
7
|
entrypoint?: string | undefined;
|
|
9
8
|
};
|
|
10
9
|
domains: string[];
|
|
11
10
|
remotePatterns: {
|
|
12
|
-
port?: string | undefined;
|
|
13
11
|
protocol?: string | undefined;
|
|
14
12
|
hostname?: string | undefined;
|
|
13
|
+
port?: string | undefined;
|
|
15
14
|
pathname?: string | undefined;
|
|
16
15
|
}[];
|
|
17
|
-
|
|
16
|
+
responsiveStyles: boolean;
|
|
17
|
+
layout?: "none" | "fixed" | "constrained" | "full-width" | undefined;
|
|
18
18
|
objectFit?: string | undefined;
|
|
19
19
|
objectPosition?: string | undefined;
|
|
20
20
|
breakpoints?: number[] | undefined;
|
|
@@ -23,15 +23,15 @@ export declare function setImageConfig(service: ImageService, config: AstroConfi
|
|
|
23
23
|
endpoint: {
|
|
24
24
|
entrypoint: string | undefined;
|
|
25
25
|
};
|
|
26
|
-
responsiveStyles: boolean;
|
|
27
26
|
domains: string[];
|
|
28
27
|
remotePatterns: {
|
|
29
|
-
port?: string | undefined;
|
|
30
28
|
protocol?: string | undefined;
|
|
31
29
|
hostname?: string | undefined;
|
|
30
|
+
port?: string | undefined;
|
|
32
31
|
pathname?: string | undefined;
|
|
33
32
|
}[];
|
|
34
|
-
|
|
33
|
+
responsiveStyles: boolean;
|
|
34
|
+
layout?: "none" | "fixed" | "constrained" | "full-width" | undefined;
|
|
35
35
|
objectFit?: string | undefined;
|
|
36
36
|
objectPosition?: string | undefined;
|
|
37
37
|
breakpoints?: number[] | undefined;
|
|
@@ -8,6 +8,13 @@ function setImageConfig(service, config, command, logger) {
|
|
|
8
8
|
...config,
|
|
9
9
|
service: command === "dev" ? sharpImageService() : { entrypoint: "@astrojs/cloudflare/image-service" }
|
|
10
10
|
};
|
|
11
|
+
case "cloudflare-binding":
|
|
12
|
+
return {
|
|
13
|
+
...config,
|
|
14
|
+
endpoint: {
|
|
15
|
+
entrypoint: "@astrojs/cloudflare/image-transform-endpoint"
|
|
16
|
+
}
|
|
17
|
+
};
|
|
11
18
|
case "compile":
|
|
12
19
|
return {
|
|
13
20
|
...config,
|
|
@@ -0,0 +1,20 @@
|
|
|
1
|
+
const VIRTUAL_CONFIG_ID = "virtual:astro-cloudflare:config";
|
|
2
|
+
const RESOLVED_VIRTUAL_CONFIG_ID = "\0" + VIRTUAL_CONFIG_ID;
|
|
3
|
+
function createConfigPlugin(config) {
|
|
4
|
+
return {
|
|
5
|
+
name: "vite:astro-cloudflare-config",
|
|
6
|
+
resolveId(id) {
|
|
7
|
+
if (id === VIRTUAL_CONFIG_ID) {
|
|
8
|
+
return RESOLVED_VIRTUAL_CONFIG_ID;
|
|
9
|
+
}
|
|
10
|
+
},
|
|
11
|
+
load(id) {
|
|
12
|
+
if (id === RESOLVED_VIRTUAL_CONFIG_ID) {
|
|
13
|
+
return `export const sessionKVBindingName = ${JSON.stringify(config.sessionKVBindingName)};`;
|
|
14
|
+
}
|
|
15
|
+
}
|
|
16
|
+
};
|
|
17
|
+
}
|
|
18
|
+
export {
|
|
19
|
+
createConfigPlugin
|
|
20
|
+
};
|
|
@@ -0,0 +1,10 @@
|
|
|
1
|
+
import type { PluginConfig } from '@cloudflare/vite-plugin';
|
|
2
|
+
/**
|
|
3
|
+
* Checks whether a wrangler file exists at the given path
|
|
4
|
+
* @param root
|
|
5
|
+
*/
|
|
6
|
+
export declare function hasWranglerConfig(root: URL): boolean;
|
|
7
|
+
/**
|
|
8
|
+
* Returns the default wrangler configuration used by Astro Cloudflare configuration.
|
|
9
|
+
*/
|
|
10
|
+
export declare function defaultCloudflareConfig(): PluginConfig['config'];
|
package/dist/wrangler.js
ADDED
|
@@ -0,0 +1,29 @@
|
|
|
1
|
+
import { existsSync } from "node:fs";
|
|
2
|
+
function hasWranglerConfig(root) {
|
|
3
|
+
return existsSync(new URL("wrangler.jsonc", root)) || existsSync(new URL("wrangler.toml", root)) || existsSync(new URL("wrangler.json", root));
|
|
4
|
+
}
|
|
5
|
+
function defaultCloudflareConfig() {
|
|
6
|
+
return {
|
|
7
|
+
// TODO: better way to handle name, maybe package.json#name ?
|
|
8
|
+
name: "test-application",
|
|
9
|
+
compatibility_date: "2025-05-21",
|
|
10
|
+
main: "@astrojs/cloudflare/entrypoints/server",
|
|
11
|
+
assets: {
|
|
12
|
+
directory: "./dist",
|
|
13
|
+
binding: "ASSETS"
|
|
14
|
+
},
|
|
15
|
+
images: {
|
|
16
|
+
binding: "IMAGES"
|
|
17
|
+
},
|
|
18
|
+
kv_namespaces: [
|
|
19
|
+
{
|
|
20
|
+
binding: "SESSION",
|
|
21
|
+
id: "SESSION"
|
|
22
|
+
}
|
|
23
|
+
]
|
|
24
|
+
};
|
|
25
|
+
}
|
|
26
|
+
export {
|
|
27
|
+
defaultCloudflareConfig,
|
|
28
|
+
hasWranglerConfig
|
|
29
|
+
};
|
package/package.json
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@astrojs/cloudflare",
|
|
3
3
|
"description": "Deploy your site to Cloudflare Workers/Pages",
|
|
4
|
-
"version": "13.0.0-alpha.
|
|
4
|
+
"version": "13.0.0-alpha.1",
|
|
5
5
|
"type": "module",
|
|
6
6
|
"types": "./dist/index.d.ts",
|
|
7
7
|
"author": "withastro",
|
|
@@ -19,22 +19,29 @@
|
|
|
19
19
|
"homepage": "https://docs.astro.build/en/guides/integrations-guide/cloudflare/",
|
|
20
20
|
"exports": {
|
|
21
21
|
".": "./dist/index.js",
|
|
22
|
+
"./entrypoints/server": "./dist/entrypoints/server.js",
|
|
23
|
+
"./entrypoints/preview": "./dist/entrypoints/preview.js",
|
|
22
24
|
"./entrypoints/server.js": "./dist/entrypoints/server.js",
|
|
23
|
-
"./entrypoints/middleware.js": "./dist/entrypoints/middleware.js",
|
|
24
25
|
"./image-service": "./dist/entrypoints/image-service.js",
|
|
25
26
|
"./image-endpoint": "./dist/entrypoints/image-endpoint.js",
|
|
27
|
+
"./image-transform-endpoint": "./dist/entrypoints/image-transform-endpoint.js",
|
|
26
28
|
"./handler": "./dist/utils/handler.js",
|
|
29
|
+
"./types.d.ts": "./types.d.ts",
|
|
27
30
|
"./package.json": "./package.json"
|
|
28
31
|
},
|
|
29
32
|
"files": [
|
|
30
|
-
"dist"
|
|
33
|
+
"dist",
|
|
34
|
+
"types.d.ts"
|
|
31
35
|
],
|
|
32
36
|
"dependencies": {
|
|
33
|
-
"@cloudflare/
|
|
37
|
+
"@cloudflare/vite-plugin": "^1.17.0",
|
|
38
|
+
"@cloudflare/workers-types": "^4.20251121.0",
|
|
39
|
+
"dotenv": "^17.2.3",
|
|
40
|
+
"piccolore": "^0.1.3",
|
|
34
41
|
"tinyglobby": "^0.2.15",
|
|
35
|
-
"vite": "^7.1.
|
|
36
|
-
"wrangler": "4.
|
|
37
|
-
"@astrojs/internal-helpers": "0.7.
|
|
42
|
+
"vite": "^7.1.12",
|
|
43
|
+
"wrangler": "4.53.0",
|
|
44
|
+
"@astrojs/internal-helpers": "0.7.5",
|
|
38
45
|
"@astrojs/underscore-redirects": "1.0.0"
|
|
39
46
|
},
|
|
40
47
|
"peerDependencies": {
|
|
@@ -42,9 +49,9 @@
|
|
|
42
49
|
},
|
|
43
50
|
"devDependencies": {
|
|
44
51
|
"cheerio": "1.1.2",
|
|
45
|
-
"devalue": "^5.
|
|
46
|
-
"rollup": "^4.
|
|
47
|
-
"astro": "6.0.0-alpha.
|
|
52
|
+
"devalue": "^5.5.0",
|
|
53
|
+
"rollup": "^4.53.3",
|
|
54
|
+
"astro": "6.0.0-alpha.1",
|
|
48
55
|
"astro-scripts": "0.0.14"
|
|
49
56
|
},
|
|
50
57
|
"publishConfig": {
|
package/types.d.ts
ADDED
|
@@ -0,0 +1,20 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Cloudflare Worker Request types
|
|
3
|
+
* Extends the global Request object with Cloudflare-specific properties
|
|
4
|
+
*/
|
|
5
|
+
|
|
6
|
+
import type { IncomingRequestCfProperties } from '@cloudflare/workers-types';
|
|
7
|
+
|
|
8
|
+
declare global {
|
|
9
|
+
interface Request {
|
|
10
|
+
/**
|
|
11
|
+
* Cloudflare-specific properties available on incoming requests
|
|
12
|
+
* Contains metadata about the request such as:
|
|
13
|
+
* - Geographic information (country, colo, timezone)
|
|
14
|
+
* - TLS/Security details (cipher, protocol version)
|
|
15
|
+
* - Bot Management scores
|
|
16
|
+
* - Client information (ASN, TCP metrics)
|
|
17
|
+
*/
|
|
18
|
+
readonly cf?: IncomingRequestCfProperties;
|
|
19
|
+
}
|
|
20
|
+
}
|