acrylblends 0.7.3 → 0.7.5

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 (115) hide show
  1. package/dist/index.js +5 -1
  2. package/dist/index.js.map +1 -1
  3. package/docs/framework/README.md +6 -4
  4. package/docs/framework/UPSTREAM.md +1 -1
  5. package/docs/framework/getting-started/aws-lambda.md +115 -0
  6. package/docs/framework/getting-started/bun.md +1 -3
  7. package/docs/framework/getting-started/cloudflare-pages.md +53 -0
  8. package/docs/framework/getting-started/cloudflare-workers.md +67 -0
  9. package/docs/framework/getting-started/deploy.md +5 -5
  10. package/docs/framework/getting-started/lambda-edge.md +41 -0
  11. package/docs/framework/getting-started/netlify.md +25 -0
  12. package/docs/framework/getting-started/other-runtimes.md +20 -9
  13. package/docs/framework/getting-started/service-worker.md +33 -0
  14. package/docs/framework/getting-started/vercel.md +28 -0
  15. package/docs/framework/guides/create-acrylblends.md +40 -2
  16. package/docs/framework/guides/data.md +202 -0
  17. package/docs/framework/guides/faq.md +2 -2
  18. package/docs/framework/guides/forms-and-sessions.md +34 -30
  19. package/docs/framework/helpers/conninfo.md +1 -1
  20. package/docs/framework/helpers/ssg.md +1 -1
  21. package/docs/framework/helpers/streaming.md +3 -2
  22. package/docs/framework/helpers/websocket.md +2 -2
  23. package/docs/framework/middleware/builtin/ip-restriction.md +1 -1
  24. package/docs/framework/upstream.json +3 -3
  25. package/lib/aws-lambda.d.ts +324 -0
  26. package/lib/aws-lambda.js +357 -0
  27. package/lib/bun.d.ts +75 -0
  28. package/lib/bun.js +134 -0
  29. package/lib/cloudflare-pages.d.ts +58 -0
  30. package/lib/cloudflare-pages.js +78 -0
  31. package/lib/cloudflare-workers.d.ts +21 -0
  32. package/lib/cloudflare-workers.js +80 -0
  33. package/lib/db/sqlite.d.ts +27 -0
  34. package/lib/db/sqlite.js +197 -0
  35. package/lib/db.d.ts +2 -0
  36. package/lib/db.js +2 -0
  37. package/lib/index-CseujaYI.d.ts +31 -0
  38. package/lib/index-D4FAsBZu.d.ts +85 -0
  39. package/lib/index-DaJtL7ci.d.ts +156 -0
  40. package/lib/lambda-edge.d.ts +92 -0
  41. package/lib/lambda-edge.js +105 -0
  42. package/lib/netlify.d.ts +29 -0
  43. package/lib/netlify.js +30 -0
  44. package/lib/node-server/register.js +1 -1
  45. package/lib/node-server/serve-static.js +1 -1
  46. package/lib/node-server.js +3 -3
  47. package/lib/serve-static-Cp5adzGo.js +77 -0
  48. package/lib/serve-static.d.ts +1 -30
  49. package/lib/serve-static.js +1 -76
  50. package/lib/service-worker.d.ts +48 -0
  51. package/lib/service-worker.js +38 -0
  52. package/lib/src-MWcsMS8i.js +85 -0
  53. package/lib/ssg.d.ts +1 -155
  54. package/lib/vercel.d.ts +10 -0
  55. package/lib/vercel.js +9 -0
  56. package/package.json +41 -1
  57. package/plugins/acryl-db/LICENSE +47 -0
  58. package/plugins/acryl-db/plugin.json +12 -0
  59. package/plugins/acryl-db/src/cordis.ts +13 -0
  60. package/plugins/acryl-db/src/facade/database.ts +41 -0
  61. package/plugins/acryl-db/src/facade/migrations.ts +50 -0
  62. package/plugins/acryl-db/src/facade/schema.ts +9 -0
  63. package/plugins/acryl-db/src/index.ts +19 -0
  64. package/plugins/acryl-db/src/migration-files.ts +31 -0
  65. package/plugins/acryl-db/upstream.json +18 -0
  66. package/plugins/acryl-db-sqlite/LICENSE +47 -0
  67. package/plugins/acryl-db-sqlite/plugin.json +13 -0
  68. package/plugins/acryl-db-sqlite/src/facade/node.ts +199 -0
  69. package/plugins/acryl-db-sqlite/src/index.ts +88 -0
  70. package/plugins/acryl-db-sqlite/src/open.ts +61 -0
  71. package/plugins/acryl-db-sqlite/upstream.json +21 -0
  72. package/plugins/acryl-inspect/upstream.json +1 -1
  73. package/plugins/acryl-node-server/upstream.json +1 -1
  74. package/plugins/acryl-router/src/core/adapter/aws-lambda/conninfo.ts +73 -0
  75. package/plugins/acryl-router/src/core/adapter/aws-lambda/handler.ts +682 -0
  76. package/plugins/acryl-router/src/core/adapter/aws-lambda/index.ts +14 -0
  77. package/plugins/acryl-router/src/core/adapter/aws-lambda/types.ts +173 -0
  78. package/plugins/acryl-router/src/core/adapter/bun/conninfo.ts +43 -0
  79. package/plugins/acryl-router/src/core/adapter/bun/index.ts +11 -0
  80. package/plugins/acryl-router/src/core/adapter/bun/serve-static.ts +32 -0
  81. package/plugins/acryl-router/src/core/adapter/bun/server.ts +14 -0
  82. package/plugins/acryl-router/src/core/adapter/bun/ssg.ts +26 -0
  83. package/plugins/acryl-router/src/core/adapter/bun/websocket.ts +113 -0
  84. package/plugins/acryl-router/src/core/adapter/cloudflare-pages/conninfo.ts +26 -0
  85. package/plugins/acryl-router/src/core/adapter/cloudflare-pages/handler.ts +122 -0
  86. package/plugins/acryl-router/src/core/adapter/cloudflare-pages/index.ts +11 -0
  87. package/plugins/acryl-router/src/core/adapter/cloudflare-workers/conninfo.ts +7 -0
  88. package/plugins/acryl-router/src/core/adapter/cloudflare-workers/index.ts +8 -0
  89. package/plugins/acryl-router/src/core/adapter/cloudflare-workers/serve-static-module.ts +12 -0
  90. package/plugins/acryl-router/src/core/adapter/cloudflare-workers/serve-static.ts +41 -0
  91. package/plugins/acryl-router/src/core/adapter/cloudflare-workers/utils.ts +50 -0
  92. package/plugins/acryl-router/src/core/adapter/cloudflare-workers/websocket.ts +52 -0
  93. package/plugins/acryl-router/src/core/adapter/lambda-edge/conninfo.ts +15 -0
  94. package/plugins/acryl-router/src/core/adapter/lambda-edge/handler.ts +239 -0
  95. package/plugins/acryl-router/src/core/adapter/lambda-edge/index.ts +14 -0
  96. package/plugins/acryl-router/src/core/adapter/netlify/conninfo.ts +57 -0
  97. package/plugins/acryl-router/src/core/adapter/netlify/handler.ts +10 -0
  98. package/plugins/acryl-router/src/core/adapter/netlify/index.ts +6 -0
  99. package/plugins/acryl-router/src/core/adapter/netlify/mod.ts +2 -0
  100. package/plugins/acryl-router/src/core/adapter/service-worker/handler.ts +37 -0
  101. package/plugins/acryl-router/src/core/adapter/service-worker/index.ts +36 -0
  102. package/plugins/acryl-router/src/core/adapter/service-worker/types.ts +14 -0
  103. package/plugins/acryl-router/src/core/adapter/vercel/conninfo.ts +8 -0
  104. package/plugins/acryl-router/src/core/adapter/vercel/handler.ts +8 -0
  105. package/plugins/acryl-router/src/core/adapter/vercel/index.ts +7 -0
  106. package/plugins/acryl-router/upstream.json +2 -2
  107. package/plugins/acryl-router-http/upstream.json +1 -1
  108. package/plugins/acryl-state/upstream.json +1 -1
  109. package/plugins/desktop/upstream.json +1 -1
  110. package/plugins/desktop-web/main.ts +13 -3
  111. package/plugins/desktop-web/upstream.json +1 -1
  112. package/plugins/tsconfig.json +1 -0
  113. package/templates/todo/upstream.json +1 -1
  114. package/lib/{serve-static-B14MF1Va.js → serve-static-B849HlX2.js} +1 -1
  115. package/lib/{transpile-CTnWof4z.js → transpile-QUK9b3eG.js} +1 -1
@@ -1,77 +1,2 @@
1
- import { tryDecodeURI } from "./utils/url.js";
2
- import { parseAccept } from "./utils/accept.js";
3
- import { COMPRESSIBLE_CONTENT_TYPE_REGEX } from "./utils/compress.js";
4
- import { getMimeType } from "./utils/mime.js";
5
- //#region ../../plugins/acryl-router/src/core/middleware/serve-static/path.ts
6
- /**
7
- * `defaultJoin` does not support Windows paths and always uses `/` separators.
8
- * If you need Windows path support, please use `join` exported from `node:path` etc. instead.
9
- */
10
- const defaultJoin = (...paths) => {
11
- let result = paths.filter((p) => p !== "").join("/");
12
- result = result.replace(/(?<=\/)\/+/g, "");
13
- const segments = result.split("/");
14
- const resolved = [];
15
- for (const segment of segments) if (segment === ".." && resolved.length > 0 && resolved.at(-1) !== "..") resolved.pop();
16
- else if (segment !== ".") resolved.push(segment);
17
- return resolved.join("/") || ".";
18
- };
19
- //#endregion
20
- //#region ../../plugins/acryl-router/src/core/middleware/serve-static/index.ts
21
- const ENCODINGS = {
22
- br: ".br",
23
- zstd: ".zst",
24
- gzip: ".gz"
25
- };
26
- const ENCODINGS_ORDERED_KEYS = Object.keys(ENCODINGS);
27
- const DEFAULT_DOCUMENT = "index.html";
28
- /**
29
- * This middleware is not directly used by the user. Create a wrapper specifying `getContent()` by the environment such as Deno or Bun.
30
- */
31
- const serveStatic = (options) => {
32
- const root = options.root ?? "./";
33
- const optionPath = options.path;
34
- const join = options.join ?? defaultJoin;
35
- return async (c, next) => {
36
- if (c.finalized) return next();
37
- if (c.req.method !== "GET" && c.req.method !== "HEAD") return next();
38
- let filename;
39
- if (options.path) filename = options.path;
40
- else try {
41
- if (!options.allowPercentInPath && c.req.path.includes("%")) throw new Error();
42
- filename = tryDecodeURI(c.req.path);
43
- if (/(?:^|[\/\\])\.{1,2}(?:$|[\/\\])|[\/\\]{2,}|\\/.test(filename)) throw new Error();
44
- } catch {
45
- await options.onNotFound?.(c.req.path, c);
46
- return next();
47
- }
48
- let path = join(root, !optionPath && options.rewriteRequestPath ? options.rewriteRequestPath(filename) : filename);
49
- if (options.isDir && await options.isDir(path)) path = join(path, DEFAULT_DOCUMENT);
50
- const getContent = options.getContent;
51
- let content = await getContent(path, c);
52
- if (content instanceof Response) return c.newResponse(content.body, content);
53
- if (content != null) {
54
- const mimeType = options.mimes && getMimeType(path, options.mimes) || getMimeType(path);
55
- c.header("Content-Type", mimeType || "application/octet-stream");
56
- if (options.precompressed && (!mimeType || COMPRESSIBLE_CONTENT_TYPE_REGEX.test(mimeType))) {
57
- const acceptEncodingSet = new Set(parseAccept(c.req.header("Accept-Encoding") ?? "").filter((encoding) => encoding.q > 0).map((encoding) => encoding.type));
58
- for (const encoding of ENCODINGS_ORDERED_KEYS) {
59
- if (!acceptEncodingSet.has(encoding)) continue;
60
- const compressedContent = await getContent(path + ENCODINGS[encoding], c);
61
- if (compressedContent) {
62
- content = compressedContent;
63
- c.header("Content-Encoding", encoding);
64
- c.header("Vary", "Accept-Encoding", { append: true });
65
- break;
66
- }
67
- }
68
- }
69
- await options.onFound?.(path, c);
70
- return c.body(content);
71
- }
72
- await options.onNotFound?.(path, c);
73
- await next();
74
- };
75
- };
76
- //#endregion
1
+ import { t as serveStatic } from "./serve-static-Cp5adzGo.js";
77
2
  export { serveStatic };
@@ -0,0 +1,48 @@
1
+ import { Y as Schema, v as Env } from "./context-DS3fYyG-.js";
2
+ import { t as Acryl } from "./app-D8riatvv.js";
3
+
4
+ //#region ../../plugins/acryl-router/src/core/adapter/service-worker/types.d.ts
5
+ interface ExtendableEvent extends Event {
6
+ waitUntil(f: Promise<any>): void;
7
+ }
8
+ interface FetchEvent extends ExtendableEvent {
9
+ readonly clientId: string;
10
+ readonly handled: Promise<void>;
11
+ readonly preloadResponse: Promise<any>;
12
+ readonly request: Request;
13
+ readonly resultingClientId: string;
14
+ respondWith(r: Response | PromiseLike<Response>): void;
15
+ }
16
+ //#endregion
17
+ //#region ../../plugins/acryl-router/src/core/adapter/service-worker/handler.d.ts
18
+ type Handler = (evt: FetchEvent) => void;
19
+ type HandleOptions = {
20
+ fetch?: typeof fetch;
21
+ };
22
+ /**
23
+ * Adapter for Service Worker
24
+ */
25
+ declare const handle: <E extends Env, S extends Schema, BasePath extends string>(app: Acryl<E, S, BasePath>, opts?: HandleOptions) => Handler;
26
+ //#endregion
27
+ //#region ../../plugins/acryl-router/src/core/adapter/service-worker/index.d.ts
28
+ /**
29
+ * Registers a Acryl app to handle fetch events in a service worker.
30
+ * This sets up `addEventListener('fetch', handle(app, options))` for the provided app.
31
+ *
32
+ * @param app - The Acryl application instance
33
+ * @param options - Options for handling requests (fetch defaults to undefined)
34
+ * @example
35
+ * ```ts
36
+ * import { Acryl } from 'acrylblends'
37
+ * import { fire } from 'acrylblends/service-worker'
38
+ *
39
+ * const app = new Acryl()
40
+ *
41
+ * app.get('/', (c) => c.text('Hi'))
42
+ *
43
+ * fire(app)
44
+ * ```
45
+ */
46
+ declare const fire: <E extends Env, S extends Schema, BasePath extends string>(app: Acryl<E, S, BasePath>, options?: HandleOptions) => void;
47
+ //#endregion
48
+ export { fire, handle };
@@ -0,0 +1,38 @@
1
+ //#region ../../plugins/acryl-router/src/core/adapter/service-worker/handler.ts
2
+ /**
3
+ * Adapter for Service Worker
4
+ */
5
+ const handle = (app, opts = { fetch: globalThis.fetch.bind(globalThis) }) => {
6
+ return (evt) => {
7
+ evt.respondWith((async () => {
8
+ const res = await app.fetch(evt.request, {}, evt);
9
+ if (opts.fetch && res.status === 404) return await opts.fetch(evt.request);
10
+ return res;
11
+ })());
12
+ };
13
+ };
14
+ //#endregion
15
+ //#region ../../plugins/acryl-router/src/core/adapter/service-worker/index.ts
16
+ /**
17
+ * Registers a Acryl app to handle fetch events in a service worker.
18
+ * This sets up `addEventListener('fetch', handle(app, options))` for the provided app.
19
+ *
20
+ * @param app - The Acryl application instance
21
+ * @param options - Options for handling requests (fetch defaults to undefined)
22
+ * @example
23
+ * ```ts
24
+ * import { Acryl } from 'acrylblends'
25
+ * import { fire } from 'acrylblends/service-worker'
26
+ *
27
+ * const app = new Acryl()
28
+ *
29
+ * app.get('/', (c) => c.text('Hi'))
30
+ *
31
+ * fire(app)
32
+ * ```
33
+ */
34
+ const fire = (app, options) => {
35
+ addEventListener("fetch", handle(app, options));
36
+ };
37
+ //#endregion
38
+ export { fire, handle };
@@ -0,0 +1,85 @@
1
+ import { readFile, readdir } from "node:fs/promises";
2
+ import { join } from "node:path";
3
+ import { fileURLToPath } from "node:url";
4
+ //#region ../../plugins/acryl-db/src/facade/schema.ts
5
+ /** Validate a prefix before using it as part of a SQL identifier. */
6
+ function validateSchemaPrefix(prefix) {
7
+ if (!/^[A-Za-z_][A-Za-z0-9_]*$/.test(prefix)) throw new Error(`Invalid SQL schema prefix ${JSON.stringify(prefix)}`);
8
+ if (prefix.toLowerCase().startsWith("sqlite_")) throw new Error(`SQL schema prefix ${JSON.stringify(prefix)} is reserved`);
9
+ }
10
+ //#endregion
11
+ //#region ../../plugins/acryl-db/src/facade/migrations.ts
12
+ /**
13
+ * Apply all pending migrations atomically, tracking their version in the named metadata table.
14
+ *
15
+ * The bookkeeping SQL runs unchanged on SQLite and Postgres: no `STRICT` table, `ON CONFLICT DO NOTHING`
16
+ * instead of `INSERT OR IGNORE`, and the version written as a checked integer rather than a binding,
17
+ * since the two dialects spell placeholders differently.
18
+ */
19
+ async function applyMigrations(database, migrations, options) {
20
+ const { table } = options;
21
+ validateSchemaPrefix(table);
22
+ for (let index = 0; index < migrations.length; index++) if (migrations[index]?.version !== index + 1) throw new Error("Migrations must have contiguous versions starting at 1");
23
+ await database.transaction(async (transaction) => {
24
+ await transaction.exec(`CREATE TABLE IF NOT EXISTS ${table} (
25
+ singleton INTEGER PRIMARY KEY CHECK (singleton = 1),
26
+ version INTEGER NOT NULL CHECK (version >= 0)
27
+ )`);
28
+ await transaction.exec(`INSERT INTO ${table} (singleton, version) VALUES (1, 0) ON CONFLICT DO NOTHING`);
29
+ const row = await transaction.get(`SELECT version FROM ${table} WHERE singleton = 1`);
30
+ if (row === void 0) throw new Error("Schema metadata is missing");
31
+ const storedVersion = Number(row.version);
32
+ const currentVersion = migrations.at(-1)?.version ?? 0;
33
+ if (storedVersion > currentVersion) throw new Error(`Schema version ${storedVersion} is newer than supported version ${currentVersion}`);
34
+ for (const migration of migrations) {
35
+ if (migration.version <= storedVersion) continue;
36
+ for (const statement of migration.statements) await transaction.exec(statement);
37
+ await transaction.exec(`UPDATE ${table} SET version = ${String(migration.version)} WHERE singleton = 1`);
38
+ }
39
+ });
40
+ }
41
+ //#endregion
42
+ //#region ../../plugins/acryl-db/src/migration-files.ts
43
+ /**
44
+ * An app's migrations as numbered SQL files: `migrations/001-notes.sql`, `002-tags.sql`, ... Each file is one migration, run as one
45
+ * `exec` (so it may hold several statements), numbered from 1 with no gaps.
46
+ */
47
+ const FILE = /^(\d+)-[a-z0-9][a-z0-9-]*\.sql$/u;
48
+ /**
49
+ * Read every `NNN-name.sql` file of a folder, in number order.
50
+ * @throws when a `.sql` file is not named `NNN-name.sql`, or the numbers do not run 1, 2, 3, ... without gaps or repeats.
51
+ */
52
+ async function readMigrationFiles(folder) {
53
+ const dir = typeof folder === "string" ? folder : fileURLToPath(folder);
54
+ const numbered = (await readdir(dir)).filter((name) => name.endsWith(".sql")).sort().map((name) => {
55
+ const match = FILE.exec(name);
56
+ if (match?.[1] === void 0) throw new Error(`acryl-db: migration file ${name} in ${dir} must be named NNN-name.sql, like 001-notes.sql`);
57
+ return {
58
+ name,
59
+ version: Number(match[1])
60
+ };
61
+ }).sort((a, b) => a.version - b.version);
62
+ numbered.forEach((file, index) => {
63
+ if (file.version !== index + 1) throw new Error(`acryl-db: migration ${file.name} in ${dir} should be number ${String(index + 1)}; the files must be numbered 1, 2, 3, ... with no gaps or repeats`);
64
+ });
65
+ return Promise.all(numbered.map(async (file) => ({
66
+ version: file.version,
67
+ statements: [await readFile(join(dir, file.name), "utf8")]
68
+ })));
69
+ }
70
+ //#endregion
71
+ //#region ../../plugins/acryl-db/src/index.ts
72
+ /**
73
+ * The `db` port: what an app's code sees of its relational database, whichever provider (`acryl-db-sqlite`, `acryl-db-postgres`) serves
74
+ * it. Plain code (an acrylblends app) opens a database with a provider's `openDb`; a Cordis plugin declares `inject: ['db']`, imports
75
+ * `acryl-db/cordis` for the `ctx.db` type, and never imports a driver.
76
+ *
77
+ * Bindings are positional `?` placeholders on every provider; a provider whose database spells them differently translates them.
78
+ * This entry imports nothing from Cordis, at runtime or in its types.
79
+ */
80
+ /** The service name every `db` provider registers. */
81
+ const DB_SERVICE = "db";
82
+ /** The table that records an app's migration version. */
83
+ const MIGRATIONS_TABLE = "_migrations";
84
+ //#endregion
85
+ export { validateSchemaPrefix as a, applyMigrations as i, MIGRATIONS_TABLE as n, readMigrationFiles as r, DB_SERVICE as t };
package/lib/ssg.d.ts CHANGED
@@ -1,156 +1,2 @@
1
- import { L as MiddlewareHandler, Y as Schema, t as Context, v as Env } from "./context-DS3fYyG-.js";
2
- import { t as Acryl } from "./app-D8riatvv.js";
3
-
4
- //#region ../../plugins/acryl-router/src/core/helper/ssg/ssg.d.ts
5
- declare const DEFAULT_OUTPUT_DIR = "./static";
6
- /**
7
- * @experimental
8
- * `FileSystemModule` is an experimental feature.
9
- * The API might be changed.
10
- */
11
- interface FileSystemModule {
12
- writeFile(path: string, data: string | Uint8Array): Promise<void>;
13
- mkdir(path: string, options: {
14
- recursive: boolean;
15
- }): Promise<void | string>;
16
- }
17
- /**
18
- * @experimental
19
- * `ToSSGResult` is an experimental feature.
20
- * The API might be changed.
21
- */
22
- interface ToSSGResult {
23
- success: boolean;
24
- files: string[];
25
- error?: Error;
26
- }
27
- declare const defaultExtensionMap: Record<string, string>;
28
- type BeforeRequestHook = (req: Request) => Request | false | Promise<Request | false>;
29
- type AfterResponseHook = (res: Response) => Response | false | Promise<Response | false>;
30
- type AfterGenerateHook = (result: ToSSGResult, fsModule: FileSystemModule, options?: ToSSGOptions) => void | Promise<void>;
31
- declare const combineBeforeRequestHooks: (hooks: BeforeRequestHook | BeforeRequestHook[]) => BeforeRequestHook;
32
- declare const combineAfterResponseHooks: (hooks: AfterResponseHook | AfterResponseHook[]) => AfterResponseHook;
33
- declare const combineAfterGenerateHooks: (hooks: AfterGenerateHook | AfterGenerateHook[], fsModule: FileSystemModule, options?: ToSSGOptions) => AfterGenerateHook;
34
- interface SSGPlugin {
35
- beforeRequestHook?: BeforeRequestHook | BeforeRequestHook[];
36
- afterResponseHook?: AfterResponseHook | AfterResponseHook[];
37
- afterGenerateHook?: AfterGenerateHook | AfterGenerateHook[];
38
- }
39
- interface ToSSGOptions {
40
- dir?: string;
41
- /**
42
- * @deprecated Use plugins[].beforeRequestHook instead.
43
- */
44
- beforeRequestHook?: BeforeRequestHook | BeforeRequestHook[];
45
- /**
46
- * @deprecated Use plugins[].afterResponseHook instead.
47
- */
48
- afterResponseHook?: AfterResponseHook | AfterResponseHook[];
49
- /**
50
- * @deprecated Use plugins[].afterGenerateHook instead.
51
- */
52
- afterGenerateHook?: AfterGenerateHook | AfterGenerateHook[];
53
- concurrency?: number;
54
- extensionMap?: Record<string, string>;
55
- plugins?: SSGPlugin[];
56
- }
57
- /**
58
- * @experimental
59
- * `fetchRoutesContent` is an experimental feature.
60
- * The API might be changed.
61
- */
62
- declare const fetchRoutesContent: <E extends Env = Env, S extends Schema = {}, BasePath extends string = "/">(app: Acryl<E, S, BasePath>, beforeRequestHook?: BeforeRequestHook, afterResponseHook?: AfterResponseHook, concurrency?: number) => Generator<Promise<Generator<Promise<{
63
- routePath: string;
64
- mimeType: string;
65
- content: string | ArrayBuffer;
66
- } | undefined>> | undefined>>;
67
- declare const saveContentToFile: (data: Promise<{
68
- routePath: string;
69
- content: string | ArrayBuffer;
70
- mimeType: string;
71
- } | undefined>, fsModule: FileSystemModule, outDir: string, extensionMap?: Record<string, string>) => Promise<string | undefined>;
72
- /**
73
- * @experimental
74
- * `ToSSGInterface` is an experimental feature.
75
- * The API might be changed.
76
- */
77
- interface ToSSGInterface {
78
- (app: Acryl<any, any, any>, fsModule: FileSystemModule, options?: ToSSGOptions): Promise<ToSSGResult>;
79
- }
80
- /**
81
- * @experimental
82
- * `ToSSGAdaptorInterface` is an experimental feature.
83
- * The API might be changed.
84
- */
85
- interface ToSSGAdaptorInterface<E extends Env = Env, S extends Schema = {}, BasePath extends string = '/'> {
86
- (app: Acryl<E, S, BasePath>, options?: ToSSGOptions): Promise<ToSSGResult>;
87
- }
88
- /**
89
- * @experimental
90
- * `toSSG` is an experimental feature.
91
- * The API might be changed.
92
- */
93
- declare const toSSG: ToSSGInterface;
94
- //#endregion
95
- //#region ../../plugins/acryl-router/src/core/helper/ssg/middleware.d.ts
96
- declare const X_ACRYL_DISABLE_SSG_HEADER_KEY = "x-acryl-disable-ssg";
97
- interface SSGParam {
98
- [key: string]: string;
99
- }
100
- type SSGParams = SSGParam[];
101
- interface SSGParamsMiddleware {
102
- <E extends Env = Env>(generateParams: (c: Context<E>) => SSGParams | Promise<SSGParams>): MiddlewareHandler<E>;
103
- <E extends Env = Env>(params: SSGParams): MiddlewareHandler<E>;
104
- }
105
- /**
106
- * Define SSG Route
107
- */
108
- declare const ssgParams: SSGParamsMiddleware;
109
- /**
110
- * @experimental
111
- * `isSSGContext` is an experimental feature.
112
- * The API might be changed.
113
- */
114
- declare const isSSGContext: (c: Context) => boolean;
115
- /**
116
- * @experimental
117
- * `disableSSG` is an experimental feature.
118
- * The API might be changed.
119
- */
120
- declare const disableSSG: () => MiddlewareHandler;
121
- /**
122
- * @experimental
123
- * `onlySSG` is an experimental feature.
124
- * The API might be changed.
125
- */
126
- declare const onlySSG: () => MiddlewareHandler;
127
- //#endregion
128
- //#region ../../plugins/acryl-router/src/core/helper/ssg/plugins.d.ts
129
- /**
130
- * The default plugin that defines the recommended behavior.
131
- *
132
- * @experimental
133
- * `defaultPlugin` is an experimental feature.
134
- * The API might be changed.
135
- */
136
- declare const defaultPlugin: () => SSGPlugin;
137
- /**
138
- * The redirect plugin that generates HTML redirect pages for HTTP redirect responses for status codes 301, 302, 303, 307 and 308.
139
- *
140
- * When used with `defaultPlugin`, place `redirectPlugin` before it, because `defaultPlugin` skips non-200 responses.
141
- *
142
- * ```ts
143
- * // ✅ Will work as expected
144
- * toSSG(app, fs, { plugins: [redirectPlugin(), defaultPlugin()] })
145
- *
146
- * // ❌ Will not work as expected
147
- * toSSG(app, fs, { plugins: [defaultPlugin(), redirectPlugin()] })
148
- * ```
149
- *
150
- * @experimental
151
- * `redirectPlugin` is an experimental feature.
152
- * The API might be changed.
153
- */
154
- declare const redirectPlugin: () => SSGPlugin;
155
- //#endregion
1
+ import { C as saveContentToFile, S as fetchRoutesContent, _ as ToSSGResult, a as isSSGContext, b as combineBeforeRequestHooks, c as AfterGenerateHook, d as DEFAULT_OUTPUT_DIR, f as FileSystemModule, g as ToSSGOptions, h as ToSSGInterface, i as disableSSG, l as AfterResponseHook, m as ToSSGAdaptorInterface, n as redirectPlugin, o as onlySSG, p as SSGPlugin, r as X_ACRYL_DISABLE_SSG_HEADER_KEY, s as ssgParams, t as defaultPlugin, u as BeforeRequestHook, v as combineAfterGenerateHooks, w as toSSG, x as defaultExtensionMap, y as combineAfterResponseHooks } from "./index-DaJtL7ci.js";
156
2
  export { AfterGenerateHook, AfterResponseHook, BeforeRequestHook, DEFAULT_OUTPUT_DIR, FileSystemModule, SSGPlugin, ToSSGAdaptorInterface, ToSSGInterface, ToSSGOptions, ToSSGResult, X_ACRYL_DISABLE_SSG_HEADER_KEY, combineAfterGenerateHooks, combineAfterResponseHooks, combineBeforeRequestHooks, defaultExtensionMap, defaultPlugin, disableSSG, fetchRoutesContent, isSSGContext, onlySSG, redirectPlugin, saveContentToFile, ssgParams, toSSG };
@@ -0,0 +1,10 @@
1
+ import { r as GetConnInfo } from "./types-Dv_nV2cv.js";
2
+ import { t as Acryl } from "./app-D8riatvv.js";
3
+
4
+ //#region ../../plugins/acryl-router/src/core/adapter/vercel/handler.d.ts
5
+ declare const handle: (app: Acryl<any, any, any>) => (req: Request) => Response | Promise<Response>;
6
+ //#endregion
7
+ //#region ../../plugins/acryl-router/src/core/adapter/vercel/conninfo.d.ts
8
+ declare const getConnInfo: GetConnInfo;
9
+ //#endregion
10
+ export { getConnInfo, handle };
package/lib/vercel.js ADDED
@@ -0,0 +1,9 @@
1
+ //#region ../../plugins/acryl-router/src/core/adapter/vercel/handler.ts
2
+ const handle = (app) => (req) => {
3
+ return app.fetch(req);
4
+ };
5
+ //#endregion
6
+ //#region ../../plugins/acryl-router/src/core/adapter/vercel/conninfo.ts
7
+ const getConnInfo = (c) => ({ remote: { address: c.req.header("x-real-ip") } });
8
+ //#endregion
9
+ export { getConnInfo, handle };
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "acrylblends",
3
- "version": "0.7.3",
3
+ "version": "0.7.5",
4
4
  "description": "The Acryl web framework (import { Acryl } from \"acrylblends\") and the acrylblends command that scaffolds Cordis apps.",
5
5
  "license": "MIT",
6
6
  "type": "module",
@@ -190,6 +190,38 @@
190
190
  "types": "./lib/testing.d.ts",
191
191
  "default": "./lib/testing.js"
192
192
  },
193
+ "./aws-lambda": {
194
+ "types": "./lib/aws-lambda.d.ts",
195
+ "default": "./lib/aws-lambda.js"
196
+ },
197
+ "./bun": {
198
+ "types": "./lib/bun.d.ts",
199
+ "default": "./lib/bun.js"
200
+ },
201
+ "./cloudflare-pages": {
202
+ "types": "./lib/cloudflare-pages.d.ts",
203
+ "default": "./lib/cloudflare-pages.js"
204
+ },
205
+ "./cloudflare-workers": {
206
+ "types": "./lib/cloudflare-workers.d.ts",
207
+ "default": "./lib/cloudflare-workers.js"
208
+ },
209
+ "./lambda-edge": {
210
+ "types": "./lib/lambda-edge.d.ts",
211
+ "default": "./lib/lambda-edge.js"
212
+ },
213
+ "./netlify": {
214
+ "types": "./lib/netlify.d.ts",
215
+ "default": "./lib/netlify.js"
216
+ },
217
+ "./service-worker": {
218
+ "types": "./lib/service-worker.d.ts",
219
+ "default": "./lib/service-worker.js"
220
+ },
221
+ "./vercel": {
222
+ "types": "./lib/vercel.d.ts",
223
+ "default": "./lib/vercel.js"
224
+ },
193
225
  "./ws": {
194
226
  "types": "./lib/ws.d.ts",
195
227
  "default": "./lib/ws.js"
@@ -386,6 +418,14 @@
386
418
  "types": "./lib/node-server/register.d.ts",
387
419
  "default": "./lib/node-server/register.js"
388
420
  },
421
+ "./db": {
422
+ "types": "./lib/db.d.ts",
423
+ "default": "./lib/db.js"
424
+ },
425
+ "./db/sqlite": {
426
+ "types": "./lib/db/sqlite.d.ts",
427
+ "default": "./lib/db/sqlite.js"
428
+ },
389
429
  "./package.json": "./package.json",
390
430
  "./cli": {
391
431
  "types": "./dist/index.d.ts",
@@ -0,0 +1,47 @@
1
+ MIT License
2
+
3
+ Copyright (c) 2026 WebBoxes s.r.o.
4
+
5
+ Permission is hereby granted, free of charge, to any person obtaining a copy
6
+ of this software and associated documentation files (the "Software"), to deal
7
+ in the Software without restriction, including without limitation the rights
8
+ to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
9
+ copies of the Software, and to permit persons to whom the Software is
10
+ furnished to do so, subject to the following conditions:
11
+
12
+ The above copyright notice and this permission notice shall be included in all
13
+ copies or substantial portions of the Software.
14
+
15
+ THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
16
+ IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
17
+ FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
18
+ AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
19
+ LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
20
+ OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
21
+ SOFTWARE.
22
+
23
+ ---
24
+
25
+ The files under src/facade are derived from the SQLite facade of chord in pi (https://github.com/earendil-works/pi, packages/chord, commit d5b3de22d0e24a3e9c38a9410d3329b099717283), used under this license:
26
+
27
+ MIT License
28
+
29
+ Copyright (c) 2025 Mario Zechner
30
+
31
+ Permission is hereby granted, free of charge, to any person obtaining a copy
32
+ of this software and associated documentation files (the "Software"), to deal
33
+ in the Software without restriction, including without limitation the rights
34
+ to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
35
+ copies of the Software, and to permit persons to whom the Software is
36
+ furnished to do so, subject to the following conditions:
37
+
38
+ The above copyright notice and this permission notice shall be included in all
39
+ copies or substantial portions of the Software.
40
+
41
+ THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
42
+ IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
43
+ FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
44
+ AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
45
+ LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
46
+ OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
47
+ SOFTWARE.
@@ -0,0 +1,12 @@
1
+ {
2
+ "name": "acryl-db",
3
+ "description": "The db port: the relational database an app plugin sees through inject: ['db'], with numbered SQL migrations. Types and the migration runner; a provider (acryl-db-sqlite) serves it. Vendored from ACRYL.",
4
+ "requires": [],
5
+ "inject": [],
6
+ "provides": [],
7
+ "dependencies": {
8
+ "@deepseek-ai/cordis": "4.0.4"
9
+ },
10
+ "mount": "it is the port, not a service: a plugin declares inject: ['db'] and imports its types from './plugins/acryl-db/src/index.ts' (or the ctx.db type from './plugins/acryl-db/src/cordis.ts'); add acryl-db-sqlite to provide it",
11
+ "omit": ["src/conformance.ts", "**/*.test.*", "**/*.case.ts"]
12
+ }
@@ -0,0 +1,13 @@
1
+ /**
2
+ * The `ctx.db` type for Cordis plugins: `import type {} from 'acryl-db/cordis'` beside `inject: ['db']`. Kept out of the root entry, so
3
+ * plain code that uses the port never names Cordis.
4
+ */
5
+
6
+ import type {} from '@deepseek-ai/cordis'
7
+ import type { Db } from './facade/database.ts'
8
+
9
+ declare module '@deepseek-ai/cordis' {
10
+ interface Context {
11
+ db: Db
12
+ }
13
+ }
@@ -0,0 +1,41 @@
1
+ /** Values supported by the portable SQL drivers. */
2
+ export type SqlValue = null | number | bigint | string | Uint8Array;
3
+
4
+ /**
5
+ * Asynchronous SQL operations shared by a database and its transaction handles.
6
+ *
7
+ * `exec` runs SQL text without bindings and may contain several statements. `run`, `get`, and `all`
8
+ * execute one statement with positional bindings. Adapters may cache prepared statements by SQL text,
9
+ * so callers pass values as bindings instead of interpolating them. `run` resolves the number of rows
10
+ * the statement changed.
11
+ */
12
+ export interface DbExecutor {
13
+ exec(sql: string): Promise<void>;
14
+ run(sql: string, ...params: SqlValue[]): Promise<{ readonly changes: number }>;
15
+ get<T extends object>(sql: string, ...params: SqlValue[]): Promise<T | undefined>;
16
+ all<T extends object>(sql: string, ...params: SqlValue[]): Promise<T[]>;
17
+ }
18
+
19
+ /**
20
+ * Minimal portable SQL database facade.
21
+ *
22
+ * All operations are asynchronous so adapters may execute outside the caller's runtime.
23
+ *
24
+ * `transaction` passes the callback a transaction handle. All work in the transaction
25
+ * must use that handle; the handle is invalid after the callback settles. Adapters must
26
+ * queue unrelated operations and other transactions until the transaction finishes. The
27
+ * returned promise settles after commit or rollback. Calling the database itself (including
28
+ * `transaction`) from inside a callback therefore waits for that transaction and
29
+ * never settles.
30
+ *
31
+ * When the callback rejects, the adapter must roll the transaction back before rejecting
32
+ * with that same error. If rollback fails, it must reject with a different error (for
33
+ * example an `AggregateError`) so callers cannot mistake the callback error for a
34
+ * guaranteed rollback.
35
+ *
36
+ * Closing is the adapter's: the plugin that opened a database closes it, so the facade an
37
+ * app receives has no `close`.
38
+ */
39
+ export interface Db extends DbExecutor {
40
+ transaction<T>(callback: (transaction: DbExecutor) => Promise<T>): Promise<T>;
41
+ }
@@ -0,0 +1,50 @@
1
+ import type { Db } from "./database.ts";
2
+ import { validateSchemaPrefix } from "./schema.ts";
3
+
4
+ export type Migration = {
5
+ readonly version: number;
6
+ readonly statements: readonly string[];
7
+ };
8
+
9
+ type SchemaRow = { readonly version: number | bigint };
10
+
11
+ /**
12
+ * Apply all pending migrations atomically, tracking their version in the named metadata table.
13
+ *
14
+ * The bookkeeping SQL runs unchanged on SQLite and Postgres: no `STRICT` table, `ON CONFLICT DO NOTHING`
15
+ * instead of `INSERT OR IGNORE`, and the version written as a checked integer rather than a binding,
16
+ * since the two dialects spell placeholders differently.
17
+ */
18
+ export async function applyMigrations(
19
+ database: Db,
20
+ migrations: readonly Migration[],
21
+ options: { readonly table: string },
22
+ ): Promise<void> {
23
+ const { table } = options;
24
+ validateSchemaPrefix(table);
25
+ for (let index = 0; index < migrations.length; index++) {
26
+ if (migrations[index]?.version !== index + 1) {
27
+ throw new Error("Migrations must have contiguous versions starting at 1");
28
+ }
29
+ }
30
+
31
+ await database.transaction(async (transaction) => {
32
+ await transaction.exec(`CREATE TABLE IF NOT EXISTS ${table} (
33
+ singleton INTEGER PRIMARY KEY CHECK (singleton = 1),
34
+ version INTEGER NOT NULL CHECK (version >= 0)
35
+ )`);
36
+ await transaction.exec(`INSERT INTO ${table} (singleton, version) VALUES (1, 0) ON CONFLICT DO NOTHING`);
37
+ const row = await transaction.get<SchemaRow>(`SELECT version FROM ${table} WHERE singleton = 1`);
38
+ if (row === undefined) throw new Error("Schema metadata is missing");
39
+ const storedVersion = Number(row.version);
40
+ const currentVersion = migrations.at(-1)?.version ?? 0;
41
+ if (storedVersion > currentVersion) {
42
+ throw new Error(`Schema version ${storedVersion} is newer than supported version ${currentVersion}`);
43
+ }
44
+ for (const migration of migrations) {
45
+ if (migration.version <= storedVersion) continue;
46
+ for (const statement of migration.statements) await transaction.exec(statement);
47
+ await transaction.exec(`UPDATE ${table} SET version = ${String(migration.version)} WHERE singleton = 1`);
48
+ }
49
+ });
50
+ }