acrylblends 0.7.2 → 0.7.4

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 (88) hide show
  1. package/docs/framework/README.md +4 -3
  2. package/docs/framework/UPSTREAM.md +1 -1
  3. package/docs/framework/getting-started/aws-lambda.md +115 -0
  4. package/docs/framework/getting-started/bun.md +1 -3
  5. package/docs/framework/getting-started/cloudflare-pages.md +53 -0
  6. package/docs/framework/getting-started/cloudflare-workers.md +67 -0
  7. package/docs/framework/getting-started/lambda-edge.md +41 -0
  8. package/docs/framework/getting-started/netlify.md +25 -0
  9. package/docs/framework/getting-started/other-runtimes.md +20 -9
  10. package/docs/framework/getting-started/service-worker.md +31 -0
  11. package/docs/framework/getting-started/vercel.md +28 -0
  12. package/docs/framework/guides/client-modules.md +34 -0
  13. package/docs/framework/guides/create-acrylblends.md +40 -2
  14. package/docs/framework/guides/faq.md +2 -2
  15. package/docs/framework/helpers/conninfo.md +1 -1
  16. package/docs/framework/helpers/ssg.md +1 -1
  17. package/docs/framework/helpers/streaming.md +120 -0
  18. package/docs/framework/helpers/websocket.md +2 -2
  19. package/docs/framework/middleware/builtin/ip-restriction.md +1 -1
  20. package/docs/framework/upstream.json +3 -3
  21. package/lib/aws-lambda.d.ts +324 -0
  22. package/lib/aws-lambda.js +357 -0
  23. package/lib/bun.d.ts +75 -0
  24. package/lib/bun.js +134 -0
  25. package/lib/cloudflare-pages.d.ts +58 -0
  26. package/lib/cloudflare-pages.js +78 -0
  27. package/lib/cloudflare-workers.d.ts +21 -0
  28. package/lib/cloudflare-workers.js +80 -0
  29. package/lib/index-CseujaYI.d.ts +31 -0
  30. package/lib/index-DaJtL7ci.d.ts +156 -0
  31. package/lib/lambda-edge.d.ts +92 -0
  32. package/lib/lambda-edge.js +105 -0
  33. package/lib/netlify.d.ts +29 -0
  34. package/lib/netlify.js +30 -0
  35. package/lib/node-server/register.js +1 -1
  36. package/lib/node-server/serve-static.js +1 -1
  37. package/lib/node-server.js +3 -3
  38. package/lib/serve-static-Cp5adzGo.js +77 -0
  39. package/lib/serve-static.d.ts +1 -30
  40. package/lib/serve-static.js +1 -76
  41. package/lib/service-worker.d.ts +48 -0
  42. package/lib/service-worker.js +38 -0
  43. package/lib/ssg.d.ts +1 -155
  44. package/lib/vercel.d.ts +10 -0
  45. package/lib/vercel.js +9 -0
  46. package/package.json +33 -1
  47. package/plugins/acryl-inspect/upstream.json +1 -1
  48. package/plugins/acryl-node-server/upstream.json +1 -1
  49. package/plugins/acryl-router/src/core/adapter/aws-lambda/conninfo.ts +73 -0
  50. package/plugins/acryl-router/src/core/adapter/aws-lambda/handler.ts +682 -0
  51. package/plugins/acryl-router/src/core/adapter/aws-lambda/index.ts +14 -0
  52. package/plugins/acryl-router/src/core/adapter/aws-lambda/types.ts +173 -0
  53. package/plugins/acryl-router/src/core/adapter/bun/conninfo.ts +43 -0
  54. package/plugins/acryl-router/src/core/adapter/bun/index.ts +11 -0
  55. package/plugins/acryl-router/src/core/adapter/bun/serve-static.ts +32 -0
  56. package/plugins/acryl-router/src/core/adapter/bun/server.ts +14 -0
  57. package/plugins/acryl-router/src/core/adapter/bun/ssg.ts +26 -0
  58. package/plugins/acryl-router/src/core/adapter/bun/websocket.ts +113 -0
  59. package/plugins/acryl-router/src/core/adapter/cloudflare-pages/conninfo.ts +26 -0
  60. package/plugins/acryl-router/src/core/adapter/cloudflare-pages/handler.ts +122 -0
  61. package/plugins/acryl-router/src/core/adapter/cloudflare-pages/index.ts +11 -0
  62. package/plugins/acryl-router/src/core/adapter/cloudflare-workers/conninfo.ts +7 -0
  63. package/plugins/acryl-router/src/core/adapter/cloudflare-workers/index.ts +8 -0
  64. package/plugins/acryl-router/src/core/adapter/cloudflare-workers/serve-static-module.ts +12 -0
  65. package/plugins/acryl-router/src/core/adapter/cloudflare-workers/serve-static.ts +41 -0
  66. package/plugins/acryl-router/src/core/adapter/cloudflare-workers/utils.ts +50 -0
  67. package/plugins/acryl-router/src/core/adapter/cloudflare-workers/websocket.ts +52 -0
  68. package/plugins/acryl-router/src/core/adapter/lambda-edge/conninfo.ts +15 -0
  69. package/plugins/acryl-router/src/core/adapter/lambda-edge/handler.ts +239 -0
  70. package/plugins/acryl-router/src/core/adapter/lambda-edge/index.ts +14 -0
  71. package/plugins/acryl-router/src/core/adapter/netlify/conninfo.ts +57 -0
  72. package/plugins/acryl-router/src/core/adapter/netlify/handler.ts +10 -0
  73. package/plugins/acryl-router/src/core/adapter/netlify/index.ts +6 -0
  74. package/plugins/acryl-router/src/core/adapter/netlify/mod.ts +2 -0
  75. package/plugins/acryl-router/src/core/adapter/service-worker/handler.ts +37 -0
  76. package/plugins/acryl-router/src/core/adapter/service-worker/index.ts +36 -0
  77. package/plugins/acryl-router/src/core/adapter/service-worker/types.ts +14 -0
  78. package/plugins/acryl-router/src/core/adapter/vercel/conninfo.ts +8 -0
  79. package/plugins/acryl-router/src/core/adapter/vercel/handler.ts +8 -0
  80. package/plugins/acryl-router/src/core/adapter/vercel/index.ts +7 -0
  81. package/plugins/acryl-router/upstream.json +2 -2
  82. package/plugins/acryl-router-http/upstream.json +1 -1
  83. package/plugins/acryl-state/upstream.json +1 -1
  84. package/plugins/desktop/upstream.json +1 -1
  85. package/plugins/desktop-web/upstream.json +1 -1
  86. package/templates/todo/upstream.json +1 -1
  87. package/lib/{serve-static-B14MF1Va.js → serve-static-B849HlX2.js} +1 -1
  88. package/lib/{transpile-CTnWof4z.js → transpile-QUK9b3eG.js} +1 -1
@@ -0,0 +1,357 @@
1
+ import { decodeBase64, encodeBase64 } from "./utils/encode.js";
2
+ import { pipeline } from "node:stream/promises";
3
+ //#region ../../plugins/acryl-router/src/core/adapter/aws-lambda/handler.ts
4
+ function sanitizeHeaderValue(value) {
5
+ if (!/[^\x00-\x7F]/.test(value)) return value;
6
+ return encodeURIComponent(value);
7
+ }
8
+ const getRequestContext = (event) => {
9
+ return event.requestContext;
10
+ };
11
+ async function* readWebStream(reader) {
12
+ let readResult = await reader.read();
13
+ while (!readResult.done) {
14
+ yield readResult.value;
15
+ readResult = await reader.read();
16
+ }
17
+ }
18
+ const streamToNodeStream = (reader, writer) => pipeline(readWebStream(reader), writer);
19
+ const streamHandle = (app) => {
20
+ return awslambda.streamifyResponse(async (event, responseStream, context) => {
21
+ const processor = getProcessor(event);
22
+ try {
23
+ const req = processor.createRequest(event);
24
+ const requestContext = getRequestContext(event);
25
+ const res = await app.fetch(req, {
26
+ event,
27
+ requestContext,
28
+ context
29
+ });
30
+ const headers = {};
31
+ const cookies = [];
32
+ res.headers.forEach((value, name) => {
33
+ if (name === "set-cookie") cookies.push(value);
34
+ else headers[name] = value;
35
+ });
36
+ const httpResponseMetadata = {
37
+ statusCode: res.status,
38
+ headers,
39
+ cookies
40
+ };
41
+ responseStream = awslambda.HttpResponseStream.from(responseStream, httpResponseMetadata);
42
+ if (res.body) await streamToNodeStream(res.body.getReader(), responseStream);
43
+ else responseStream.write("");
44
+ } catch (error) {
45
+ console.error("Error processing request:", error);
46
+ responseStream.write("Internal Server Error");
47
+ } finally {
48
+ responseStream.end();
49
+ }
50
+ });
51
+ };
52
+ /**
53
+ * Converts a Acryl application to an AWS Lambda handler.
54
+ *
55
+ * Accepts events from API Gateway (v1 and v2), Application Load Balancer (ALB),
56
+ * and Lambda Function URLs.
57
+ *
58
+ * @param app - The Acryl application instance
59
+ * @param options - Optional configuration
60
+ * @param options.isContentTypeBinary - A function to determine if the content type is binary.
61
+ * If not provided, the default function will be used.
62
+ * @returns Lambda handler function
63
+ *
64
+ * @example
65
+ * ```js
66
+ * import { Acryl } from 'acrylblends'
67
+ * import { handle } from 'acrylblends/aws-lambda'
68
+ *
69
+ * const app = new Acryl()
70
+ *
71
+ * app.get('/', (c) => c.text('Hello from Lambda'))
72
+ * app.get('/json', (c) => c.json({ message: 'Hello JSON' }))
73
+ *
74
+ * export const handler = handle(app)
75
+ * ```
76
+ *
77
+ * @example
78
+ * ```js
79
+ * // With custom binary content type detection
80
+ * import { handle, defaultIsContentTypeBinary } from 'acrylblends/aws-lambda'
81
+ * export const handler = handle(app, {
82
+ * isContentTypeBinary: (contentType) => {
83
+ * if (defaultIsContentTypeBinary(contentType)) {
84
+ * // default logic same as prior to v4.8.4
85
+ * return true
86
+ * }
87
+ * return contentType.startsWith('image/') || contentType === 'application/pdf'
88
+ * }
89
+ * })
90
+ * ```
91
+ */
92
+ const handle = (app, { isContentTypeBinary } = { isContentTypeBinary: void 0 }) => {
93
+ return async (event, lambdaContext) => {
94
+ const processor = getProcessor(event);
95
+ let req, requestContext;
96
+ try {
97
+ req = processor.createRequest(event);
98
+ requestContext = getRequestContext(event);
99
+ } catch (error) {
100
+ console.error("Error processing request:", error);
101
+ const errorResponse = error instanceof TypeError ? new Response("Invalid request", { status: 400 }) : new Response("Internal Server Error", { status: 500 });
102
+ return processor.createResult(event, errorResponse, { isContentTypeBinary });
103
+ }
104
+ const res = await app.fetch(req, {
105
+ event,
106
+ requestContext,
107
+ lambdaContext
108
+ });
109
+ return processor.createResult(event, res, { isContentTypeBinary });
110
+ };
111
+ };
112
+ var EventProcessor = class {
113
+ getHeaderValue(headers, key) {
114
+ return headers ? Array.isArray(headers[key]) ? headers[key][0] : headers[key] : void 0;
115
+ }
116
+ getDomainName(event) {
117
+ if (event.requestContext && "domainName" in event.requestContext) return event.requestContext.domainName;
118
+ const hostFromHeaders = this.getHeaderValue(event.headers, "host");
119
+ if (hostFromHeaders) return hostFromHeaders;
120
+ const multiValueHeaders = "multiValueHeaders" in event ? event.multiValueHeaders : {};
121
+ return this.getHeaderValue(multiValueHeaders, "host");
122
+ }
123
+ createRequest(event) {
124
+ const queryString = this.getQueryString(event);
125
+ const urlPath = `https://${this.getDomainName(event)}${this.getPath(event)}`;
126
+ const url = queryString ? `${urlPath}?${queryString}` : urlPath;
127
+ const headers = this.getHeaders(event);
128
+ const requestInit = {
129
+ headers,
130
+ method: this.getMethod(event)
131
+ };
132
+ if (event.body) {
133
+ const body = event.isBase64Encoded ? decodeBase64(event.body) : new TextEncoder().encode(event.body);
134
+ requestInit.body = body;
135
+ headers.set("content-length", body.length.toString());
136
+ }
137
+ return new Request(url, requestInit);
138
+ }
139
+ async createResult(event, res, options) {
140
+ const contentType = res.headers.get("content-type");
141
+ const isContentTypeBinary = options.isContentTypeBinary ?? defaultIsContentTypeBinary;
142
+ let isBase64Encoded = contentType && isContentTypeBinary(contentType) ? true : false;
143
+ if (!isBase64Encoded) {
144
+ const contentEncoding = res.headers.get("content-encoding");
145
+ isBase64Encoded = isContentEncodingBinary(contentEncoding);
146
+ }
147
+ const result = {
148
+ body: isBase64Encoded ? encodeBase64(await res.arrayBuffer()) : await res.text(),
149
+ statusCode: res.status,
150
+ isBase64Encoded,
151
+ ..."multiValueHeaders" in event && event.multiValueHeaders ? { multiValueHeaders: {} } : { headers: {} }
152
+ };
153
+ this.setCookies(event, res, result);
154
+ if (result.multiValueHeaders) res.headers.forEach((value, key) => {
155
+ result.multiValueHeaders[key] = [value];
156
+ });
157
+ else res.headers.forEach((value, key) => {
158
+ result.headers[key] = value;
159
+ });
160
+ return result;
161
+ }
162
+ setCookies(_event, res, result) {
163
+ if (res.headers.has("set-cookie")) {
164
+ const cookies = res.headers.getSetCookie ? res.headers.getSetCookie() : Array.from(res.headers.entries()).filter(([k]) => k === "set-cookie").map(([, v]) => v);
165
+ if (Array.isArray(cookies)) {
166
+ this.setCookiesToResult(result, cookies);
167
+ res.headers.delete("set-cookie");
168
+ }
169
+ }
170
+ }
171
+ };
172
+ var EventV2Processor = class extends EventProcessor {
173
+ getPath(event) {
174
+ return event.rawPath;
175
+ }
176
+ getMethod(event) {
177
+ return event.requestContext.http.method;
178
+ }
179
+ getQueryString(event) {
180
+ return event.rawQueryString;
181
+ }
182
+ getCookies(event, headers) {
183
+ if (Array.isArray(event.cookies)) headers.set("Cookie", event.cookies.join("; "));
184
+ }
185
+ setCookiesToResult(result, cookies) {
186
+ result.cookies = cookies;
187
+ }
188
+ getHeaders(event) {
189
+ const headers = new Headers();
190
+ this.getCookies(event, headers);
191
+ if (event.headers) {
192
+ for (const [k, v] of Object.entries(event.headers)) if (v) headers.set(k, v);
193
+ }
194
+ return headers;
195
+ }
196
+ };
197
+ const v2Processor = new EventV2Processor();
198
+ var EventV1Processor = class extends EventProcessor {
199
+ getPath(event) {
200
+ return event.path;
201
+ }
202
+ getMethod(event) {
203
+ return event.httpMethod;
204
+ }
205
+ getQueryString(event) {
206
+ if (event.multiValueQueryStringParameters) return Object.entries(event.multiValueQueryStringParameters || {}).filter(([, value]) => value).map(([key, values]) => values.map((value) => `${encodeURIComponent(key)}=${encodeURIComponent(value)}`).join("&")).join("&");
207
+ else return Object.entries(event.queryStringParameters || {}).filter(([, value]) => value !== void 0).map(([key, value]) => `${encodeURIComponent(key)}=${encodeURIComponent(value || "")}`).join("&");
208
+ }
209
+ getCookies(_event, _headers) {}
210
+ getHeaders(event) {
211
+ const headers = new Headers();
212
+ this.getCookies(event, headers);
213
+ if (event.multiValueHeaders) {
214
+ for (const [k, values] of Object.entries(event.multiValueHeaders)) if (values) values.forEach((v) => headers.append(k, sanitizeHeaderValue(v)));
215
+ }
216
+ if (event.headers) {
217
+ for (const [k, v] of Object.entries(event.headers)) if (v && !headers.has(k)) headers.set(k, sanitizeHeaderValue(v));
218
+ }
219
+ return headers;
220
+ }
221
+ setCookiesToResult(result, cookies) {
222
+ result.multiValueHeaders = { "set-cookie": cookies };
223
+ }
224
+ };
225
+ const v1Processor = new EventV1Processor();
226
+ var ALBProcessor = class extends EventProcessor {
227
+ getHeaders(event) {
228
+ const headers = new Headers();
229
+ if (event.multiValueHeaders) {
230
+ for (const [key, values] of Object.entries(event.multiValueHeaders)) if (values && Array.isArray(values)) {
231
+ const sanitizedValue = sanitizeHeaderValue(values.join("; "));
232
+ headers.set(key, sanitizedValue);
233
+ }
234
+ } else for (const [key, value] of Object.entries(event.headers ?? {})) if (value) headers.set(key, sanitizeHeaderValue(value));
235
+ return headers;
236
+ }
237
+ getPath(event) {
238
+ return event.path;
239
+ }
240
+ getMethod(event) {
241
+ return event.httpMethod;
242
+ }
243
+ getQueryString(event) {
244
+ if (event.multiValueQueryStringParameters) return Object.entries(event.multiValueQueryStringParameters || {}).filter(([, value]) => value).map(([key, value]) => `${key}=${value.join(`&${key}=`)}`).join("&");
245
+ else return Object.entries(event.queryStringParameters || {}).filter(([, value]) => value !== void 0).map(([key, value]) => `${key}=${value}`).join("&");
246
+ }
247
+ getCookies(event, headers) {
248
+ let cookie;
249
+ if (event.multiValueHeaders) cookie = event.multiValueHeaders["cookie"]?.join("; ");
250
+ else cookie = event.headers ? event.headers["cookie"] : void 0;
251
+ if (cookie) headers.append("Cookie", cookie);
252
+ }
253
+ setCookiesToResult(result, cookies) {
254
+ if (result.multiValueHeaders) result.multiValueHeaders["set-cookie"] = cookies;
255
+ else result.headers["set-cookie"] = cookies[0];
256
+ }
257
+ };
258
+ const albProcessor = new ALBProcessor();
259
+ var LatticeV2Processor = class extends EventProcessor {
260
+ getPath(event) {
261
+ return event.path;
262
+ }
263
+ getMethod(event) {
264
+ return event.method;
265
+ }
266
+ getQueryString() {
267
+ return "";
268
+ }
269
+ getHeaders(event) {
270
+ const headers = new Headers();
271
+ if (event.headers) {
272
+ for (const [k, values] of Object.entries(event.headers)) if (values) values.forEach((v) => headers.append(k, sanitizeHeaderValue(v)));
273
+ }
274
+ return headers;
275
+ }
276
+ getCookies() {}
277
+ setCookiesToResult(result, cookies) {
278
+ result.headers = {
279
+ ...result.headers,
280
+ "set-cookie": cookies
281
+ };
282
+ }
283
+ };
284
+ const latticeV2Processor = new LatticeV2Processor();
285
+ const getProcessor = (event) => {
286
+ if (isProxyEventALB(event)) return albProcessor;
287
+ if (isProxyEventV2(event)) return v2Processor;
288
+ if (isLatticeEventV2(event)) return latticeV2Processor;
289
+ return v1Processor;
290
+ };
291
+ const isProxyEventALB = (event) => {
292
+ if (event.requestContext) return Object.hasOwn(event.requestContext, "elb");
293
+ return false;
294
+ };
295
+ const isProxyEventV2 = (event) => {
296
+ return Object.hasOwn(event, "rawPath") && Object.hasOwn(event.requestContext ?? {}, "http");
297
+ };
298
+ const isLatticeEventV2 = (event) => {
299
+ if (event.requestContext) return Object.hasOwn(event.requestContext, "serviceArn");
300
+ return false;
301
+ };
302
+ /**
303
+ * Check if the given content type is binary.
304
+ * This is a default function and may be overwritten by the user via `isContentTypeBinary` option in handler().
305
+ * @param contentType The content type to check.
306
+ * @returns True if the content type is binary, false otherwise.
307
+ */
308
+ const defaultIsContentTypeBinary = (contentType) => {
309
+ if (/^application\/vnd\.(?:apple\.installer|mozilla\.xul)\+xml\s*(?:;|$)/i.test(contentType)) return true;
310
+ return !/^text\/(?:plain|html|css|javascript|csv)|(?:\/|\+)(?:json|xml)\s*(?:;|$)/i.test(contentType);
311
+ };
312
+ const isContentEncodingBinary = (contentEncoding) => {
313
+ return !!contentEncoding && !/^identity$/i.test(contentEncoding);
314
+ };
315
+ //#endregion
316
+ //#region ../../plugins/acryl-router/src/core/adapter/aws-lambda/conninfo.ts
317
+ /**
318
+ * Get connection information from AWS Lambda
319
+ *
320
+ * Extracts client IP from various Lambda event sources:
321
+ * - API Gateway v1 (REST API): requestContext.identity.sourceIp
322
+ * - API Gateway v2 (HTTP API/Function URLs): requestContext.http.sourceIp
323
+ * - ALB: Falls back to x-forwarded-for header
324
+ *
325
+ * @param c - Context
326
+ * @returns Connection information including remote address
327
+ * @example
328
+ * ```ts
329
+ * import { Acryl } from 'acrylblends'
330
+ * import { handle, getConnInfo } from 'acrylblends/aws-lambda'
331
+ *
332
+ * const app = new Acryl()
333
+ *
334
+ * app.get('/', (c) => {
335
+ * const info = getConnInfo(c)
336
+ * return c.text(`Your IP: ${info.remote.address}`)
337
+ * })
338
+ *
339
+ * export const handler = handle(app)
340
+ * ```
341
+ */
342
+ const getConnInfo = (c) => {
343
+ const requestContext = c.env.requestContext;
344
+ let address;
345
+ if ("identity" in requestContext && requestContext.identity?.sourceIp) address = requestContext.identity.sourceIp;
346
+ else if ("http" in requestContext && requestContext.http?.sourceIp) address = requestContext.http.sourceIp;
347
+ else {
348
+ const xff = c.req.header("x-forwarded-for");
349
+ if (xff) {
350
+ const ips = xff.split(",");
351
+ address = ips[ips.length - 1].trim();
352
+ }
353
+ }
354
+ return { remote: { address } };
355
+ };
356
+ //#endregion
357
+ export { defaultIsContentTypeBinary, getConnInfo, handle, streamHandle };
package/lib/bun.d.ts ADDED
@@ -0,0 +1,75 @@
1
+ import { L as MiddlewareHandler, t as Context, v as Env } from "./context-DS3fYyG-.js";
2
+ import { r as GetConnInfo } from "./types-Dv_nV2cv.js";
3
+ import { f as FileSystemModule, m as ToSSGAdaptorInterface } from "./index-DaJtL7ci.js";
4
+ import { a as WSEvents, n as UpgradeWebSocket } from "./index-BvFh1Gfx.js";
5
+ import { t as ServeStaticOptions } from "./index-CseujaYI.js";
6
+
7
+ //#region ../../plugins/acryl-router/src/core/adapter/bun/serve-static.d.ts
8
+ declare const serveStatic: <E extends Env = Env>(options?: ServeStaticOptions<E>) => MiddlewareHandler;
9
+ //#endregion
10
+ //#region ../../plugins/acryl-router/src/core/adapter/bun/ssg.d.ts
11
+ /**
12
+ * @experimental
13
+ * `bunFileSystemModule` is an experimental feature.
14
+ * The API might be changed.
15
+ */
16
+ declare const bunFileSystemModule: FileSystemModule;
17
+ /**
18
+ * @experimental
19
+ * `toSSG` is an experimental feature.
20
+ * The API might be changed.
21
+ */
22
+ declare const toSSG: ToSSGAdaptorInterface;
23
+ //#endregion
24
+ //#region ../../plugins/acryl-router/src/core/adapter/bun/websocket.d.ts
25
+ /**
26
+ * @internal
27
+ */
28
+ interface BunServerWebSocket<T> {
29
+ send(data: string | ArrayBuffer | Uint8Array, compress?: boolean): void;
30
+ close(code?: number, reason?: string): void;
31
+ data: T;
32
+ readyState: 0 | 1 | 2 | 3;
33
+ }
34
+ interface BunWebSocketHandler<T> {
35
+ open(ws: BunServerWebSocket<T>): void;
36
+ close(ws: BunServerWebSocket<T>, code?: number, reason?: string): void;
37
+ message(ws: BunServerWebSocket<T>, message: string | {
38
+ buffer: ArrayBufferLike;
39
+ }): void;
40
+ }
41
+ interface CreateWebSocket<T> {
42
+ upgradeWebSocket: UpgradeWebSocket<T>;
43
+ websocket: BunWebSocketHandler<BunWebSocketData>;
44
+ }
45
+ interface BunWebSocketData {
46
+ events: WSEvents;
47
+ url: URL;
48
+ protocol: string;
49
+ }
50
+ declare const upgradeWebSocket: UpgradeWebSocket<any>;
51
+ declare const websocket: BunWebSocketHandler<BunWebSocketData>;
52
+ /**
53
+ * @deprecated Import `upgradeWebSocket` and `websocket` directly from `acryl-router/bun` instead.
54
+ * @returns A function to create a Bun WebSocket handler.
55
+ */
56
+ declare const createBunWebSocket: <T>() => CreateWebSocket<T>;
57
+ //#endregion
58
+ //#region ../../plugins/acryl-router/src/core/adapter/bun/conninfo.d.ts
59
+ /**
60
+ * Get ConnInfo with Bun
61
+ * @param c Context
62
+ * @returns ConnInfo
63
+ */
64
+ declare const getConnInfo: GetConnInfo;
65
+ //#endregion
66
+ //#region ../../plugins/acryl-router/src/core/adapter/bun/server.d.ts
67
+ /**
68
+ * Get Bun Server Object from Context
69
+ * @template T - The type of Bun Server
70
+ * @param c Context
71
+ * @returns Bun Server
72
+ */
73
+ declare const getBunServer: <T>(c: Context) => T | undefined;
74
+ //#endregion
75
+ export { type BunWebSocketData, type BunWebSocketHandler, bunFileSystemModule, createBunWebSocket, getBunServer, getConnInfo, serveStatic, toSSG, upgradeWebSocket, websocket };
package/lib/bun.js ADDED
@@ -0,0 +1,134 @@
1
+ import { t as serveStatic$1 } from "./serve-static-Cp5adzGo.js";
2
+ import { c as toSSG$1 } from "./ssg-BwjcA-Ge.js";
3
+ import { WSContext, createWSMessageEvent, defineWebSocketHelper } from "./ws.js";
4
+ import { stat } from "node:fs/promises";
5
+ import { join } from "node:path";
6
+ //#region ../../plugins/acryl-router/src/core/adapter/bun/serve-static.ts
7
+ const serveStatic = (options = {}) => {
8
+ return async function serveStatic(c, next) {
9
+ const getContent = async (path) => {
10
+ const file = Bun.file(path);
11
+ return await file.exists() ? file : null;
12
+ };
13
+ const isDir = async (path) => {
14
+ let isDir;
15
+ try {
16
+ isDir = (await stat(path)).isDirectory();
17
+ } catch {}
18
+ return isDir;
19
+ };
20
+ return serveStatic$1({
21
+ ...options,
22
+ getContent,
23
+ join,
24
+ isDir
25
+ })(c, next);
26
+ };
27
+ };
28
+ //#endregion
29
+ //#region ../../plugins/acryl-router/src/core/adapter/bun/ssg.ts
30
+ /**
31
+ * @experimental
32
+ * `bunFileSystemModule` is an experimental feature.
33
+ * The API might be changed.
34
+ */
35
+ const bunFileSystemModule = {
36
+ writeFile: async (path, data) => {
37
+ await Bun.write(path, data);
38
+ },
39
+ mkdir: async () => {}
40
+ };
41
+ /**
42
+ * @experimental
43
+ * `toSSG` is an experimental feature.
44
+ * The API might be changed.
45
+ */
46
+ const toSSG = async (app, options) => {
47
+ return toSSG$1(app, bunFileSystemModule, options);
48
+ };
49
+ //#endregion
50
+ //#region ../../plugins/acryl-router/src/core/adapter/bun/server.ts
51
+ /**
52
+ * Get Bun Server Object from Context
53
+ * @template T - The type of Bun Server
54
+ * @param c Context
55
+ * @returns Bun Server
56
+ */
57
+ const getBunServer = (c) => "server" in c.env ? c.env.server : c.env;
58
+ //#endregion
59
+ //#region ../../plugins/acryl-router/src/core/adapter/bun/websocket.ts
60
+ /**
61
+ * @internal
62
+ */
63
+ const createWSContext = (ws) => {
64
+ return new WSContext({
65
+ send: (source, options) => {
66
+ ws.send(source, options?.compress);
67
+ },
68
+ raw: ws,
69
+ readyState: ws.readyState,
70
+ url: ws.data.url,
71
+ protocol: ws.data.protocol,
72
+ close(code, reason) {
73
+ ws.close(code, reason);
74
+ }
75
+ });
76
+ };
77
+ const upgradeWebSocket = defineWebSocketHelper((c, events) => {
78
+ const server = getBunServer(c);
79
+ if (!server) throw new TypeError("env has to include the 2nd argument of fetch.");
80
+ if (server.upgrade(c.req.raw, { data: {
81
+ events,
82
+ url: new URL(c.req.url),
83
+ protocol: c.req.header("sec-websocket-protocol")?.split(",")[0]?.trim() ?? ""
84
+ } })) return new Response(null);
85
+ });
86
+ const websocket = {
87
+ open(ws) {
88
+ const websocketListeners = ws.data.events;
89
+ if (websocketListeners.onOpen) websocketListeners.onOpen(new Event("open"), createWSContext(ws));
90
+ },
91
+ close(ws, code, reason) {
92
+ const websocketListeners = ws.data.events;
93
+ if (websocketListeners.onClose) websocketListeners.onClose(new CloseEvent("close", {
94
+ code,
95
+ reason
96
+ }), createWSContext(ws));
97
+ },
98
+ message(ws, message) {
99
+ const websocketListeners = ws.data.events;
100
+ if (websocketListeners.onMessage) {
101
+ const normalizedReceiveData = typeof message === "string" ? message : message.buffer;
102
+ websocketListeners.onMessage(createWSMessageEvent(normalizedReceiveData), createWSContext(ws));
103
+ }
104
+ }
105
+ };
106
+ /**
107
+ * @deprecated Import `upgradeWebSocket` and `websocket` directly from `acryl-router/bun` instead.
108
+ * @returns A function to create a Bun WebSocket handler.
109
+ */
110
+ const createBunWebSocket = () => ({
111
+ upgradeWebSocket,
112
+ websocket
113
+ });
114
+ //#endregion
115
+ //#region ../../plugins/acryl-router/src/core/adapter/bun/conninfo.ts
116
+ /**
117
+ * Get ConnInfo with Bun
118
+ * @param c Context
119
+ * @returns ConnInfo
120
+ */
121
+ const getConnInfo = (c) => {
122
+ const server = getBunServer(c);
123
+ if (!server) throw new TypeError("env has to include the 2nd argument of fetch.");
124
+ if (typeof server.requestIP !== "function") throw new TypeError("server.requestIP is not a function.");
125
+ const info = server.requestIP(c.req.raw);
126
+ if (!info) return { remote: {} };
127
+ return { remote: {
128
+ address: info.address,
129
+ addressType: info.family === "IPv6" || info.family === "IPv4" ? info.family : void 0,
130
+ port: info.port
131
+ } };
132
+ };
133
+ //#endregion
134
+ export { bunFileSystemModule, createBunWebSocket, getBunServer, getConnInfo, serveStatic, toSSG, upgradeWebSocket, websocket };
@@ -0,0 +1,58 @@
1
+ import { L as MiddlewareHandler, Y as Schema, g as BlankSchema, j as Input, v as Env } from "./context-DS3fYyG-.js";
2
+ import { r as GetConnInfo } from "./types-Dv_nV2cv.js";
3
+ import { t as Acryl } from "./app-D8riatvv.js";
4
+
5
+ //#region ../../plugins/acryl-router/src/core/adapter/cloudflare-pages/handler.d.ts
6
+ type Params<P extends string = any> = Record<P, string | string[]>;
7
+ type EventContext<Env = {}, P extends string = any, Data = Record<string, unknown>> = {
8
+ request: Request;
9
+ functionPath: string;
10
+ waitUntil: (promise: Promise<unknown>) => void;
11
+ passThroughOnException: () => void;
12
+ props: any;
13
+ next: (input?: Request | string, init?: RequestInit) => Promise<Response>;
14
+ env: Env & {
15
+ ASSETS: {
16
+ fetch: typeof fetch;
17
+ };
18
+ };
19
+ params: Params<P>;
20
+ data: Data;
21
+ };
22
+ declare type PagesFunction<Env = unknown, Params extends string = any, Data extends Record<string, unknown> = Record<string, unknown>> = (context: EventContext<Env, Params, Data>) => Response | Promise<Response>;
23
+ declare const handle: <E extends Env = Env, S extends Schema = BlankSchema, BasePath extends string = "/">(app: Acryl<E, S, BasePath>) => PagesFunction<E["Bindings"]>;
24
+ declare function handleMiddleware<E extends Env = {}, P extends string = any, I extends Input = {}>(middleware: MiddlewareHandler<E & {
25
+ Bindings: {
26
+ eventContext: EventContext;
27
+ };
28
+ }, P, I>): PagesFunction<E['Bindings']>;
29
+ /**
30
+ *
31
+ * @description `serveStatic()` is for advanced mode:
32
+ * https://developers.cloudflare.com/pages/platform/functions/advanced-mode/#set-up-a-function
33
+ */
34
+ declare const serveStatic: () => MiddlewareHandler;
35
+ //#endregion
36
+ //#region ../../plugins/acryl-router/src/core/adapter/cloudflare-pages/conninfo.d.ts
37
+ /**
38
+ * Get connection information from Cloudflare Pages
39
+ * @param c - Context
40
+ * @returns Connection information including remote address
41
+ * @example
42
+ * ```ts
43
+ * import { Acryl } from 'acrylblends'
44
+ * import { handle, getConnInfo } from 'acrylblends/cloudflare-pages'
45
+ *
46
+ * const app = new Acryl()
47
+ *
48
+ * app.get('/', (c) => {
49
+ * const info = getConnInfo(c)
50
+ * return c.text(`Your IP: ${info.remote.address}`)
51
+ * })
52
+ *
53
+ * export const onRequest = handle(app)
54
+ * ```
55
+ */
56
+ declare const getConnInfo: GetConnInfo;
57
+ //#endregion
58
+ export { type EventContext, getConnInfo, handle, handleMiddleware, serveStatic };
@@ -0,0 +1,78 @@
1
+ import { HTTPException } from "./http-exception.js";
2
+ import { t as Context } from "./context-DDO0cfuP.js";
3
+ //#region ../../plugins/acryl-router/src/core/adapter/cloudflare-pages/handler.ts
4
+ const handle = (app) => (eventContext) => {
5
+ return app.fetch(eventContext.request, {
6
+ ...eventContext.env,
7
+ eventContext
8
+ }, {
9
+ waitUntil: eventContext.waitUntil,
10
+ passThroughOnException: eventContext.passThroughOnException,
11
+ props: {}
12
+ });
13
+ };
14
+ function handleMiddleware(middleware) {
15
+ return async (executionCtx) => {
16
+ const context = new Context(executionCtx.request, {
17
+ env: {
18
+ ...executionCtx.env,
19
+ eventContext: executionCtx
20
+ },
21
+ executionCtx
22
+ });
23
+ let response = void 0;
24
+ try {
25
+ response = await middleware(context, async () => {
26
+ try {
27
+ context.res = await executionCtx.next();
28
+ } catch (error) {
29
+ if (error instanceof Error) context.error = error;
30
+ else throw error;
31
+ }
32
+ });
33
+ } catch (error) {
34
+ if (error instanceof Error) context.error = error;
35
+ else throw error;
36
+ }
37
+ if (response) return response;
38
+ if (context.error instanceof HTTPException) return context.error.getResponse();
39
+ if (context.error) throw context.error;
40
+ return context.res;
41
+ };
42
+ }
43
+ /**
44
+ *
45
+ * @description `serveStatic()` is for advanced mode:
46
+ * https://developers.cloudflare.com/pages/platform/functions/advanced-mode/#set-up-a-function
47
+ */
48
+ const serveStatic = () => {
49
+ return async (c) => {
50
+ const res = await c.env.ASSETS.fetch(c.req.raw);
51
+ if (res.status === 404) return c.notFound();
52
+ return res;
53
+ };
54
+ };
55
+ //#endregion
56
+ //#region ../../plugins/acryl-router/src/core/adapter/cloudflare-pages/conninfo.ts
57
+ /**
58
+ * Get connection information from Cloudflare Pages
59
+ * @param c - Context
60
+ * @returns Connection information including remote address
61
+ * @example
62
+ * ```ts
63
+ * import { Acryl } from 'acrylblends'
64
+ * import { handle, getConnInfo } from 'acrylblends/cloudflare-pages'
65
+ *
66
+ * const app = new Acryl()
67
+ *
68
+ * app.get('/', (c) => {
69
+ * const info = getConnInfo(c)
70
+ * return c.text(`Your IP: ${info.remote.address}`)
71
+ * })
72
+ *
73
+ * export const onRequest = handle(app)
74
+ * ```
75
+ */
76
+ const getConnInfo = (c) => ({ remote: { address: c.req.header("cf-connecting-ip") } });
77
+ //#endregion
78
+ export { getConnInfo, handle, handleMiddleware, serveStatic };