zastro-websockets-cloudflare 0.0.0-729d313
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-endpoint.d.ts +3 -0
- package/dist/entrypoints/image-endpoint.js +15 -0
- package/dist/entrypoints/image-service.d.ts +3 -0
- package/dist/entrypoints/image-service.js +35 -0
- package/dist/entrypoints/middleware.d.ts +2 -0
- package/dist/entrypoints/middleware.js +11 -0
- package/dist/entrypoints/server.d.ts +15 -0
- package/dist/entrypoints/server.js +12 -0
- package/dist/index.d.ts +94 -0
- package/dist/index.js +307 -0
- package/dist/utils/assets.d.ts +2 -0
- package/dist/utils/assets.js +57 -0
- package/dist/utils/cloudflare-module-loader.d.ts +20 -0
- package/dist/utils/cloudflare-module-loader.js +175 -0
- package/dist/utils/env.d.ts +2 -0
- package/dist/utils/env.js +13 -0
- package/dist/utils/generate-routes-json.d.ts +9 -0
- package/dist/utils/generate-routes-json.js +225 -0
- package/dist/utils/handler.d.ts +24 -0
- package/dist/utils/handler.js +64 -0
- package/dist/utils/image-config.d.ts +38 -0
- package/dist/utils/image-config.js +33 -0
- package/dist/websocket/index.d.ts +6 -0
- package/dist/websocket/index.js +11 -0
- package/dist/websocket/middleware.d.ts +45 -0
- package/dist/websocket/middleware.js +29 -0
- package/dist/websocket/server.d.ts +33 -0
- package/dist/websocket/server.js +57 -0
- package/dist/websocket/websocket.d.ts +75 -0
- package/dist/websocket/websocket.js +131 -0
- package/package.json +42 -0
|
@@ -0,0 +1,15 @@
|
|
|
1
|
+
const prerender = false;
|
|
2
|
+
const GET = (ctx) => {
|
|
3
|
+
const href = ctx.url.searchParams.get("href");
|
|
4
|
+
if (!href) {
|
|
5
|
+
return new Response("Missing 'href' query parameter", {
|
|
6
|
+
status: 400,
|
|
7
|
+
statusText: "Missing 'href' query parameter"
|
|
8
|
+
});
|
|
9
|
+
}
|
|
10
|
+
return fetch(new URL(href, ctx.url.origin));
|
|
11
|
+
};
|
|
12
|
+
export {
|
|
13
|
+
GET,
|
|
14
|
+
prerender
|
|
15
|
+
};
|
|
@@ -0,0 +1,35 @@
|
|
|
1
|
+
import { joinPaths } from "@astrojs/internal-helpers/path";
|
|
2
|
+
import { baseService } from "astro/assets";
|
|
3
|
+
import { isESMImportedImage } from "astro/assets/utils";
|
|
4
|
+
import { isRemoteAllowed } from "../utils/assets.js";
|
|
5
|
+
const service = {
|
|
6
|
+
...baseService,
|
|
7
|
+
getURL: (options, imageConfig) => {
|
|
8
|
+
const resizingParams = ["onerror=redirect"];
|
|
9
|
+
if (options.width) resizingParams.push(`width=${options.width}`);
|
|
10
|
+
if (options.height) resizingParams.push(`height=${options.height}`);
|
|
11
|
+
if (options.quality) resizingParams.push(`quality=${options.quality}`);
|
|
12
|
+
if (options.fit) resizingParams.push(`fit=${options.fit}`);
|
|
13
|
+
if (options.format) resizingParams.push(`format=${options.format}`);
|
|
14
|
+
let imageSource = "";
|
|
15
|
+
if (isESMImportedImage(options.src)) {
|
|
16
|
+
imageSource = options.src.src;
|
|
17
|
+
} else if (isRemoteAllowed(options.src, imageConfig)) {
|
|
18
|
+
imageSource = String(options.src);
|
|
19
|
+
} else {
|
|
20
|
+
return String(options.src);
|
|
21
|
+
}
|
|
22
|
+
const imageEndpoint = joinPaths(
|
|
23
|
+
// @ts-expect-error Can't recognise import.meta.env
|
|
24
|
+
import.meta.env.BASE_URL,
|
|
25
|
+
"/cdn-cgi/image",
|
|
26
|
+
resizingParams.join(","),
|
|
27
|
+
imageSource
|
|
28
|
+
);
|
|
29
|
+
return imageEndpoint;
|
|
30
|
+
}
|
|
31
|
+
};
|
|
32
|
+
var image_service_default = service;
|
|
33
|
+
export {
|
|
34
|
+
image_service_default as default
|
|
35
|
+
};
|
|
@@ -0,0 +1,15 @@
|
|
|
1
|
+
import type { ExecutionContext, ExportedHandlerFetchHandler } from '@cloudflare/workers-types';
|
|
2
|
+
import type { SSRManifest } from 'astro';
|
|
3
|
+
type Env = {
|
|
4
|
+
[key: string]: unknown;
|
|
5
|
+
ASSETS: {
|
|
6
|
+
fetch: (req: Request | string) => Promise<Response>;
|
|
7
|
+
};
|
|
8
|
+
ASTRO_STUDIO_APP_TOKEN?: string;
|
|
9
|
+
};
|
|
10
|
+
export declare function createExports(manifest: SSRManifest): {
|
|
11
|
+
default: {
|
|
12
|
+
fetch: (request: Parameters<ExportedHandlerFetchHandler>[0], env: Env, context: ExecutionContext) => Promise<Response>;
|
|
13
|
+
};
|
|
14
|
+
};
|
|
15
|
+
export {};
|
|
@@ -0,0 +1,12 @@
|
|
|
1
|
+
import { App } from "astro/app";
|
|
2
|
+
import { handle } from "../utils/handler.js";
|
|
3
|
+
function createExports(manifest) {
|
|
4
|
+
const app = new App(manifest);
|
|
5
|
+
const fetch = async (request, env, context) => {
|
|
6
|
+
return await handle(manifest, app, request, env, context);
|
|
7
|
+
};
|
|
8
|
+
return { default: { fetch } };
|
|
9
|
+
}
|
|
10
|
+
export {
|
|
11
|
+
createExports
|
|
12
|
+
};
|
package/dist/index.d.ts
ADDED
|
@@ -0,0 +1,94 @@
|
|
|
1
|
+
import type { AstroIntegration } from 'astro';
|
|
2
|
+
import { type GetPlatformProxyOptions } from 'wrangler';
|
|
3
|
+
import { type ImageService } from './utils/image-config.js';
|
|
4
|
+
export type { Runtime } from './utils/handler.js';
|
|
5
|
+
export type Options = {
|
|
6
|
+
/** Options for handling images. */
|
|
7
|
+
imageService?: ImageService;
|
|
8
|
+
/** Configuration for `_routes.json` generation. A _routes.json file controls when your Function is invoked. This file will include three different properties:
|
|
9
|
+
*
|
|
10
|
+
* - version: Defines the version of the schema. Currently there is only one version of the schema (version 1), however, we may add more in the future and aim to be backwards compatible.
|
|
11
|
+
* - include: Defines routes that will be invoked by Functions. Accepts wildcard behavior.
|
|
12
|
+
* - exclude: Defines routes that will not be invoked by Functions. Accepts wildcard behavior. `exclude` always take priority over `include`.
|
|
13
|
+
*
|
|
14
|
+
* Wildcards match any number of path segments (slashes). For example, `/users/*` will match everything after the `/users/` path.
|
|
15
|
+
*
|
|
16
|
+
*/
|
|
17
|
+
routes?: {
|
|
18
|
+
/** Extend `_routes.json` */
|
|
19
|
+
extend: {
|
|
20
|
+
/** Paths which should be routed to the SSR function */
|
|
21
|
+
include?: {
|
|
22
|
+
/** Generally this is in pathname format, but does support wildcards, e.g. `/users`, `/products/*` */
|
|
23
|
+
pattern: string;
|
|
24
|
+
}[];
|
|
25
|
+
/** Paths which should be routed as static assets */
|
|
26
|
+
exclude?: {
|
|
27
|
+
/** Generally this is in pathname format, but does support wildcards, e.g. `/static`, `/assets/*`, `/images/avatar.jpg` */
|
|
28
|
+
pattern: string;
|
|
29
|
+
}[];
|
|
30
|
+
};
|
|
31
|
+
};
|
|
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
|
+
/**
|
|
40
|
+
* Allow bundling cloudflare worker specific file types as importable modules. Defaults to true.
|
|
41
|
+
* When enabled, allows imports of '.wasm', '.bin', and '.txt' file types
|
|
42
|
+
*
|
|
43
|
+
* See https://developers.cloudflare.com/pages/functions/module-support/
|
|
44
|
+
* for reference on how these file types are exported
|
|
45
|
+
*/
|
|
46
|
+
cloudflareModules?: boolean;
|
|
47
|
+
/**
|
|
48
|
+
* By default, Astro will be configured to use Cloudflare KV to store session data. If you want to use sessions,
|
|
49
|
+
* you must create a KV namespace and declare it in your wrangler config file. You can do this with the wrangler command:
|
|
50
|
+
*
|
|
51
|
+
* ```sh
|
|
52
|
+
* npx wrangler kv namespace create SESSION
|
|
53
|
+
* ```
|
|
54
|
+
*
|
|
55
|
+
* This will log the id of the created namespace. You can then add it to your `wrangler.json` file like this:
|
|
56
|
+
*
|
|
57
|
+
* ```json
|
|
58
|
+
* {
|
|
59
|
+
* "kv_namespaces": [
|
|
60
|
+
* {
|
|
61
|
+
* "binding": "SESSION",
|
|
62
|
+
* "id": "<your kv namespace id here>"
|
|
63
|
+
* }
|
|
64
|
+
* ]
|
|
65
|
+
* }
|
|
66
|
+
* ```
|
|
67
|
+
* By default, the driver looks for the binding named `SESSION`, but you can override this by providing a different name here.
|
|
68
|
+
*
|
|
69
|
+
* See https://developers.cloudflare.com/kv/concepts/kv-namespaces/ for more details on using KV namespaces.
|
|
70
|
+
*
|
|
71
|
+
*/
|
|
72
|
+
sessionKVBindingName?: string;
|
|
73
|
+
/**
|
|
74
|
+
* This configuration option allows you to specify a custom entryPoint for your Cloudflare Worker.
|
|
75
|
+
* The entry point is the file that will be executed when your Worker is invoked.
|
|
76
|
+
* By default, this is set to `@astrojs/cloudflare/entrypoints/server.js` and `['default']`.
|
|
77
|
+
* @docs https://docs.astro.build/en/guides/integrations-guide/cloudflare/#workerEntryPoint
|
|
78
|
+
*/
|
|
79
|
+
workerEntryPoint?: {
|
|
80
|
+
/**
|
|
81
|
+
* The path to the entry file. This should be a relative path from the root of your Astro project.
|
|
82
|
+
* @example`'src/worker.ts'`
|
|
83
|
+
* @docs https://docs.astro.build/en/guides/integrations-guide/cloudflare/#workerentrypointpath
|
|
84
|
+
*/
|
|
85
|
+
path: string | URL;
|
|
86
|
+
/**
|
|
87
|
+
* Additional named exports to use for the entry file. Astro always includes the default export (`['default']`). If you need to have other top level named exports use this option.
|
|
88
|
+
* @example ['MyDurableObject', 'namedExport']
|
|
89
|
+
* @docs https://docs.astro.build/en/guides/integrations-guide/cloudflare/#workerentrypointnamedexports
|
|
90
|
+
*/
|
|
91
|
+
namedExports?: string[];
|
|
92
|
+
};
|
|
93
|
+
};
|
|
94
|
+
export default function createIntegration(args?: Options): AstroIntegration;
|
package/dist/index.js
ADDED
|
@@ -0,0 +1,307 @@
|
|
|
1
|
+
import { createReadStream } from "node:fs";
|
|
2
|
+
import { appendFile, stat } from "node:fs/promises";
|
|
3
|
+
import { createRequire } from "node:module";
|
|
4
|
+
import { createInterface } from "node:readline/promises";
|
|
5
|
+
import { fileURLToPath, pathToFileURL } from "node:url";
|
|
6
|
+
import {
|
|
7
|
+
appendForwardSlash,
|
|
8
|
+
prependForwardSlash,
|
|
9
|
+
removeLeadingForwardSlash
|
|
10
|
+
} from "@astrojs/internal-helpers/path";
|
|
11
|
+
import { createRedirectsFromAstroRoutes, printAsRedirects } from "@astrojs/underscore-redirects";
|
|
12
|
+
import { AstroError } from "astro/errors";
|
|
13
|
+
import { defaultClientConditions } from "vite";
|
|
14
|
+
import { getPlatformProxy } from "wrangler";
|
|
15
|
+
import {
|
|
16
|
+
cloudflareModuleLoader
|
|
17
|
+
} from "./utils/cloudflare-module-loader.js";
|
|
18
|
+
import { createGetEnv } from "./utils/env.js";
|
|
19
|
+
import { createRoutesFile, getParts } from "./utils/generate-routes-json.js";
|
|
20
|
+
import { setImageConfig } from "./utils/image-config.js";
|
|
21
|
+
function wrapWithSlashes(path) {
|
|
22
|
+
return prependForwardSlash(appendForwardSlash(path));
|
|
23
|
+
}
|
|
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
|
+
function createIntegration(args) {
|
|
36
|
+
let _config;
|
|
37
|
+
let finalBuildOutput;
|
|
38
|
+
const cloudflareModulePlugin = cloudflareModuleLoader(
|
|
39
|
+
args?.cloudflareModules ?? true
|
|
40
|
+
);
|
|
41
|
+
let _routes;
|
|
42
|
+
return {
|
|
43
|
+
name: "zastro-websockets-cloudflare",
|
|
44
|
+
hooks: {
|
|
45
|
+
"astro:config:setup": ({
|
|
46
|
+
command,
|
|
47
|
+
config,
|
|
48
|
+
updateConfig,
|
|
49
|
+
logger,
|
|
50
|
+
addWatchFile,
|
|
51
|
+
addMiddleware,
|
|
52
|
+
createCodegenDir
|
|
53
|
+
}) => {
|
|
54
|
+
let session = config.session;
|
|
55
|
+
const isBuild = command === "build";
|
|
56
|
+
if (!session?.driver) {
|
|
57
|
+
const sessionDir = isBuild ? void 0 : createCodegenDir();
|
|
58
|
+
const bindingName = args?.sessionKVBindingName ?? "SESSION";
|
|
59
|
+
if (isBuild) {
|
|
60
|
+
logger.info(
|
|
61
|
+
`Enabling sessions with Cloudflare KV for production with the "${bindingName}" KV binding.`
|
|
62
|
+
);
|
|
63
|
+
logger.info(
|
|
64
|
+
`If you see the error "Invalid binding \`${bindingName}\`" in your build output, you need to add the binding to your wrangler config file.`
|
|
65
|
+
);
|
|
66
|
+
}
|
|
67
|
+
session = isBuild ? {
|
|
68
|
+
...session,
|
|
69
|
+
driver: "cloudflare-kv-binding",
|
|
70
|
+
options: {
|
|
71
|
+
binding: bindingName,
|
|
72
|
+
...session?.options
|
|
73
|
+
}
|
|
74
|
+
} : {
|
|
75
|
+
...session,
|
|
76
|
+
driver: "fs-lite",
|
|
77
|
+
options: {
|
|
78
|
+
base: fileURLToPath(new URL("sessions", sessionDir)),
|
|
79
|
+
...session?.options
|
|
80
|
+
}
|
|
81
|
+
};
|
|
82
|
+
}
|
|
83
|
+
updateConfig({
|
|
84
|
+
build: {
|
|
85
|
+
client: new URL(`.${wrapWithSlashes(config.base)}`, config.outDir),
|
|
86
|
+
server: new URL("./_worker.js/", config.outDir),
|
|
87
|
+
serverEntry: "index.js",
|
|
88
|
+
redirects: false
|
|
89
|
+
},
|
|
90
|
+
session,
|
|
91
|
+
vite: {
|
|
92
|
+
plugins: [
|
|
93
|
+
// https://developers.cloudflare.com/pages/functions/module-support/
|
|
94
|
+
// Allows imports of '.wasm', '.bin', and '.txt' file types
|
|
95
|
+
cloudflareModulePlugin,
|
|
96
|
+
{
|
|
97
|
+
name: "vite:cf-imports",
|
|
98
|
+
enforce: "pre",
|
|
99
|
+
resolveId(source) {
|
|
100
|
+
if (source.startsWith("cloudflare:")) {
|
|
101
|
+
return { id: source, external: true };
|
|
102
|
+
}
|
|
103
|
+
return null;
|
|
104
|
+
}
|
|
105
|
+
}
|
|
106
|
+
]
|
|
107
|
+
},
|
|
108
|
+
image: setImageConfig(args?.imageService ?? "compile", config.image, command, logger)
|
|
109
|
+
});
|
|
110
|
+
if (args?.platformProxy?.configPath) {
|
|
111
|
+
addWatchFile(new URL(args.platformProxy.configPath, config.root));
|
|
112
|
+
} else {
|
|
113
|
+
addWatchFile(new URL("./wrangler.toml", config.root));
|
|
114
|
+
addWatchFile(new URL("./wrangler.json", config.root));
|
|
115
|
+
addWatchFile(new URL("./wrangler.jsonc", config.root));
|
|
116
|
+
}
|
|
117
|
+
addMiddleware({
|
|
118
|
+
entrypoint: "zastro-websockets-cloudflare/entrypoints/middleware.js",
|
|
119
|
+
order: "pre"
|
|
120
|
+
});
|
|
121
|
+
},
|
|
122
|
+
"astro:routes:resolved": ({ routes }) => {
|
|
123
|
+
_routes = routes;
|
|
124
|
+
},
|
|
125
|
+
"astro:config:done": ({ setAdapter, config, buildOutput, logger }) => {
|
|
126
|
+
if (buildOutput === "static") {
|
|
127
|
+
logger.warn(
|
|
128
|
+
"[@astrojs/cloudflare] This adapter is intended to be used with server rendered pages, which this project does not contain any of. As such, this adapter is unnecessary."
|
|
129
|
+
);
|
|
130
|
+
}
|
|
131
|
+
_config = config;
|
|
132
|
+
finalBuildOutput = buildOutput;
|
|
133
|
+
let customWorkerEntryPoint;
|
|
134
|
+
if (args?.workerEntryPoint && typeof args.workerEntryPoint.path === "string") {
|
|
135
|
+
const require2 = createRequire(config.root);
|
|
136
|
+
try {
|
|
137
|
+
customWorkerEntryPoint = pathToFileURL(require2.resolve(args.workerEntryPoint.path));
|
|
138
|
+
} catch {
|
|
139
|
+
customWorkerEntryPoint = new URL(args.workerEntryPoint.path, config.root);
|
|
140
|
+
}
|
|
141
|
+
}
|
|
142
|
+
setAdapter({
|
|
143
|
+
name: "zastro-websockets-cloudflare",
|
|
144
|
+
serverEntrypoint: customWorkerEntryPoint ?? "zastro-websockets-cloudflare/entrypoints/server.js",
|
|
145
|
+
exports: args?.workerEntryPoint?.namedExports ? ["default", ...args.workerEntryPoint.namedExports] : ["default"],
|
|
146
|
+
adapterFeatures: {
|
|
147
|
+
edgeMiddleware: false,
|
|
148
|
+
buildOutput: "server"
|
|
149
|
+
},
|
|
150
|
+
supportedAstroFeatures: {
|
|
151
|
+
serverOutput: "stable",
|
|
152
|
+
hybridOutput: "stable",
|
|
153
|
+
staticOutput: "unsupported",
|
|
154
|
+
i18nDomains: "experimental",
|
|
155
|
+
sharpImageService: {
|
|
156
|
+
support: "limited",
|
|
157
|
+
message: 'Cloudflare does not support sharp at runtime. However, you can configure `imageService: "compile"` to optimize images with sharp on prerendered pages during build time.',
|
|
158
|
+
// For explicitly set image services, we suppress the warning about sharp not being supported at runtime,
|
|
159
|
+
// inferring the user is aware of the limitations.
|
|
160
|
+
suppress: args?.imageService ? "all" : "default"
|
|
161
|
+
},
|
|
162
|
+
envGetSecret: "stable"
|
|
163
|
+
}
|
|
164
|
+
});
|
|
165
|
+
},
|
|
166
|
+
"astro:server:setup": async ({ server }) => {
|
|
167
|
+
if ((args?.platformProxy?.enabled ?? true) === true) {
|
|
168
|
+
const platformProxy = await getPlatformProxy(args?.platformProxy);
|
|
169
|
+
server.httpServer?.on("close", async () => {
|
|
170
|
+
await platformProxy.dispose();
|
|
171
|
+
});
|
|
172
|
+
setProcessEnv(_config, platformProxy.env);
|
|
173
|
+
const clientLocalsSymbol = Symbol.for("astro.locals");
|
|
174
|
+
server.middlewares.use(async function middleware(req, _res, next) {
|
|
175
|
+
Reflect.set(req, clientLocalsSymbol, {
|
|
176
|
+
runtime: {
|
|
177
|
+
env: platformProxy.env,
|
|
178
|
+
cf: platformProxy.cf,
|
|
179
|
+
caches: platformProxy.caches,
|
|
180
|
+
ctx: {
|
|
181
|
+
waitUntil: (promise) => platformProxy.ctx.waitUntil(promise),
|
|
182
|
+
// Currently not available: https://developers.cloudflare.com/pages/platform/known-issues/#pages-functions
|
|
183
|
+
passThroughOnException: () => {
|
|
184
|
+
throw new AstroError(
|
|
185
|
+
"`passThroughOnException` is currently not available in Cloudflare Pages. See https://developers.cloudflare.com/pages/platform/known-issues/#pages-functions."
|
|
186
|
+
);
|
|
187
|
+
}
|
|
188
|
+
}
|
|
189
|
+
}
|
|
190
|
+
});
|
|
191
|
+
next();
|
|
192
|
+
});
|
|
193
|
+
}
|
|
194
|
+
},
|
|
195
|
+
"astro:build:setup": ({ vite, target }) => {
|
|
196
|
+
if (target === "server") {
|
|
197
|
+
vite.resolve ||= {};
|
|
198
|
+
vite.resolve.alias ||= {};
|
|
199
|
+
const aliases = [
|
|
200
|
+
{
|
|
201
|
+
find: "react-dom/server",
|
|
202
|
+
replacement: "react-dom/server.browser"
|
|
203
|
+
}
|
|
204
|
+
];
|
|
205
|
+
if (Array.isArray(vite.resolve.alias)) {
|
|
206
|
+
vite.resolve.alias = [...vite.resolve.alias, ...aliases];
|
|
207
|
+
} else {
|
|
208
|
+
for (const alias of aliases) {
|
|
209
|
+
vite.resolve.alias[alias.find] = alias.replacement;
|
|
210
|
+
}
|
|
211
|
+
}
|
|
212
|
+
vite.ssr ||= {};
|
|
213
|
+
vite.ssr.resolve ||= {};
|
|
214
|
+
vite.ssr.resolve.conditions ||= [...defaultClientConditions];
|
|
215
|
+
vite.ssr.resolve.conditions.push("workerd", "worker");
|
|
216
|
+
vite.ssr.target = "webworker";
|
|
217
|
+
vite.ssr.noExternal = true;
|
|
218
|
+
vite.build ||= {};
|
|
219
|
+
vite.build.rollupOptions ||= {};
|
|
220
|
+
vite.build.rollupOptions.output ||= {};
|
|
221
|
+
vite.build.rollupOptions.output.banner ||= "globalThis.process ??= {}; globalThis.process.env ??= {};";
|
|
222
|
+
vite.define = {
|
|
223
|
+
"process.env": "process.env",
|
|
224
|
+
// Allows the request handler to know what the binding name is
|
|
225
|
+
"globalThis.__ASTRO_SESSION_BINDING_NAME": JSON.stringify(
|
|
226
|
+
args?.sessionKVBindingName ?? "SESSION"
|
|
227
|
+
),
|
|
228
|
+
...vite.define
|
|
229
|
+
};
|
|
230
|
+
}
|
|
231
|
+
},
|
|
232
|
+
"astro:build:done": async ({ pages, dir, logger, assets }) => {
|
|
233
|
+
await cloudflareModulePlugin.afterBuildCompleted(_config);
|
|
234
|
+
let redirectsExists = false;
|
|
235
|
+
try {
|
|
236
|
+
const redirectsStat = await stat(new URL("./_redirects", _config.outDir));
|
|
237
|
+
if (redirectsStat.isFile()) {
|
|
238
|
+
redirectsExists = true;
|
|
239
|
+
}
|
|
240
|
+
} catch (_error) {
|
|
241
|
+
redirectsExists = false;
|
|
242
|
+
}
|
|
243
|
+
const redirects = [];
|
|
244
|
+
if (redirectsExists) {
|
|
245
|
+
const rl = createInterface({
|
|
246
|
+
input: createReadStream(new URL("./_redirects", _config.outDir)),
|
|
247
|
+
crlfDelay: Number.POSITIVE_INFINITY
|
|
248
|
+
});
|
|
249
|
+
for await (const line of rl) {
|
|
250
|
+
const parts = line.split(" ");
|
|
251
|
+
if (parts.length >= 2) {
|
|
252
|
+
const p = removeLeadingForwardSlash(parts[0]).split("/").filter(Boolean).map((s) => {
|
|
253
|
+
const syntax = s.replace(/\/:.*?(?=\/|$)/g, "/*").replace(/\?.*$/, "");
|
|
254
|
+
return getParts(syntax);
|
|
255
|
+
});
|
|
256
|
+
redirects.push(p);
|
|
257
|
+
}
|
|
258
|
+
}
|
|
259
|
+
}
|
|
260
|
+
let routesExists = false;
|
|
261
|
+
try {
|
|
262
|
+
const routesStat = await stat(new URL("./_routes.json", _config.outDir));
|
|
263
|
+
if (routesStat.isFile()) {
|
|
264
|
+
routesExists = true;
|
|
265
|
+
}
|
|
266
|
+
} catch (_error) {
|
|
267
|
+
routesExists = false;
|
|
268
|
+
}
|
|
269
|
+
if (!routesExists) {
|
|
270
|
+
await createRoutesFile(
|
|
271
|
+
_config,
|
|
272
|
+
logger,
|
|
273
|
+
_routes,
|
|
274
|
+
pages,
|
|
275
|
+
redirects,
|
|
276
|
+
args?.routes?.extend?.include,
|
|
277
|
+
args?.routes?.extend?.exclude
|
|
278
|
+
);
|
|
279
|
+
}
|
|
280
|
+
const trueRedirects = createRedirectsFromAstroRoutes({
|
|
281
|
+
config: _config,
|
|
282
|
+
routeToDynamicTargetMap: new Map(
|
|
283
|
+
Array.from(
|
|
284
|
+
_routes.filter((route) => route.type === "redirect").map((route) => [route, ""])
|
|
285
|
+
)
|
|
286
|
+
),
|
|
287
|
+
dir,
|
|
288
|
+
buildOutput: finalBuildOutput,
|
|
289
|
+
assets
|
|
290
|
+
});
|
|
291
|
+
if (!trueRedirects.empty()) {
|
|
292
|
+
try {
|
|
293
|
+
await appendFile(
|
|
294
|
+
new URL("./_redirects", _config.outDir),
|
|
295
|
+
printAsRedirects(trueRedirects)
|
|
296
|
+
);
|
|
297
|
+
} catch (_error) {
|
|
298
|
+
logger.error("Failed to write _redirects file");
|
|
299
|
+
}
|
|
300
|
+
}
|
|
301
|
+
}
|
|
302
|
+
}
|
|
303
|
+
};
|
|
304
|
+
}
|
|
305
|
+
export {
|
|
306
|
+
createIntegration as default
|
|
307
|
+
};
|
|
@@ -0,0 +1,57 @@
|
|
|
1
|
+
import { isRemotePath } from "@astrojs/internal-helpers/path";
|
|
2
|
+
function matchHostname(url, hostname, allowWildcard) {
|
|
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
|
+
}
|
|
47
|
+
function isRemoteAllowed(src, {
|
|
48
|
+
domains = [],
|
|
49
|
+
remotePatterns = []
|
|
50
|
+
}) {
|
|
51
|
+
if (!isRemotePath(src)) return false;
|
|
52
|
+
const url = new URL(src);
|
|
53
|
+
return domains.some((domain) => matchHostname(url, domain)) || remotePatterns.some((remotePattern) => matchPattern(url, remotePattern));
|
|
54
|
+
}
|
|
55
|
+
export {
|
|
56
|
+
isRemoteAllowed
|
|
57
|
+
};
|
|
@@ -0,0 +1,20 @@
|
|
|
1
|
+
import type { AstroConfig } from 'astro';
|
|
2
|
+
import type { PluginOption } from 'vite';
|
|
3
|
+
export interface CloudflareModulePluginExtra {
|
|
4
|
+
afterBuildCompleted(config: AstroConfig): Promise<void>;
|
|
5
|
+
}
|
|
6
|
+
/**
|
|
7
|
+
* Enables support for various non-standard extensions in module imports that cloudflare workers supports.
|
|
8
|
+
*
|
|
9
|
+
* See https://developers.cloudflare.com/pages/functions/module-support/ for reference
|
|
10
|
+
*
|
|
11
|
+
* This adds supports for imports in the following formats:
|
|
12
|
+
* - .wasm
|
|
13
|
+
* - .wasm?module
|
|
14
|
+
* - .bin
|
|
15
|
+
* - .txt
|
|
16
|
+
*
|
|
17
|
+
* @param enabled - if true, will load all cloudflare pages supported types
|
|
18
|
+
* @returns Vite plugin with additional extension method to hook into astro build
|
|
19
|
+
*/
|
|
20
|
+
export declare function cloudflareModuleLoader(enabled: boolean): PluginOption & CloudflareModulePluginExtra;
|