@emdash-cms/cloudflare 0.0.1
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dist/auth/index.d.mts +81 -0
- package/dist/auth/index.mjs +147 -0
- package/dist/cache/config.d.mts +52 -0
- package/dist/cache/config.mjs +55 -0
- package/dist/cache/runtime.d.mts +40 -0
- package/dist/cache/runtime.mjs +191 -0
- package/dist/d1-introspector-bZf0_ylK.mjs +57 -0
- package/dist/db/d1.d.mts +43 -0
- package/dist/db/d1.mjs +74 -0
- package/dist/db/do.d.mts +96 -0
- package/dist/db/do.mjs +489 -0
- package/dist/db/playground-middleware.d.mts +20 -0
- package/dist/db/playground-middleware.mjs +533 -0
- package/dist/db/playground.d.mts +39 -0
- package/dist/db/playground.mjs +26 -0
- package/dist/do-class-DY2Ba2RJ.mjs +174 -0
- package/dist/do-class-x5Xh_G62.d.mts +73 -0
- package/dist/do-dialect-BhFcRSFQ.mjs +58 -0
- package/dist/do-playground-routes-CmwFeGwJ.mjs +49 -0
- package/dist/do-types-CY0G0oyh.d.mts +14 -0
- package/dist/images-4RT9Ag8_.d.mts +76 -0
- package/dist/index.d.mts +200 -0
- package/dist/index.mjs +214 -0
- package/dist/media/images-runtime.d.mts +10 -0
- package/dist/media/images-runtime.mjs +215 -0
- package/dist/media/stream-runtime.d.mts +10 -0
- package/dist/media/stream-runtime.mjs +218 -0
- package/dist/plugins/index.d.mts +32 -0
- package/dist/plugins/index.mjs +163 -0
- package/dist/sandbox/index.d.mts +255 -0
- package/dist/sandbox/index.mjs +945 -0
- package/dist/storage/r2.d.mts +31 -0
- package/dist/storage/r2.mjs +116 -0
- package/dist/stream-DdbcvKi0.d.mts +78 -0
- package/package.json +109 -0
- package/src/auth/cloudflare-access.ts +303 -0
- package/src/auth/index.ts +16 -0
- package/src/cache/config.ts +81 -0
- package/src/cache/runtime.ts +328 -0
- package/src/cloudflare.d.ts +31 -0
- package/src/db/d1-introspector.ts +120 -0
- package/src/db/d1.ts +112 -0
- package/src/db/do-class.ts +275 -0
- package/src/db/do-dialect.ts +125 -0
- package/src/db/do-playground-routes.ts +65 -0
- package/src/db/do-preview-routes.ts +48 -0
- package/src/db/do-preview-sign.ts +100 -0
- package/src/db/do-preview.ts +268 -0
- package/src/db/do-types.ts +12 -0
- package/src/db/do.ts +62 -0
- package/src/db/playground-middleware.ts +340 -0
- package/src/db/playground-toolbar.ts +341 -0
- package/src/db/playground.ts +49 -0
- package/src/db/preview-toolbar.ts +220 -0
- package/src/index.ts +285 -0
- package/src/media/images-runtime.ts +353 -0
- package/src/media/images.ts +114 -0
- package/src/media/stream-runtime.ts +392 -0
- package/src/media/stream.ts +118 -0
- package/src/plugins/index.ts +7 -0
- package/src/plugins/vectorize-search.ts +393 -0
- package/src/sandbox/bridge.ts +1008 -0
- package/src/sandbox/index.ts +13 -0
- package/src/sandbox/runner.ts +357 -0
- package/src/sandbox/types.ts +181 -0
- package/src/sandbox/wrapper.ts +238 -0
- package/src/storage/r2.ts +200 -0
|
@@ -0,0 +1,174 @@
|
|
|
1
|
+
import { DurableObject } from "cloudflare:workers";
|
|
2
|
+
|
|
3
|
+
//#region src/db/do-class.ts
|
|
4
|
+
/**
|
|
5
|
+
* EmDashPreviewDB — Durable Object for preview databases
|
|
6
|
+
*
|
|
7
|
+
* Each preview session gets its own DO with isolated SQLite storage.
|
|
8
|
+
* The DO is populated from a snapshot of the source EmDash site
|
|
9
|
+
* and serves read-only queries until its TTL expires.
|
|
10
|
+
*
|
|
11
|
+
* Not used in production — preview only.
|
|
12
|
+
*/
|
|
13
|
+
/** Default TTL for preview data (1 hour) */
|
|
14
|
+
const DEFAULT_TTL_MS = 3600 * 1e3;
|
|
15
|
+
/** Valid identifier pattern for snapshot table/column names */
|
|
16
|
+
const SAFE_IDENTIFIER = /^[a-z_][a-z0-9_]*$/;
|
|
17
|
+
/** SQL command prefixes that indicate read-only statements */
|
|
18
|
+
const READ_PREFIXES = [
|
|
19
|
+
"SELECT",
|
|
20
|
+
"PRAGMA",
|
|
21
|
+
"EXPLAIN",
|
|
22
|
+
"WITH"
|
|
23
|
+
];
|
|
24
|
+
var EmDashPreviewDB = class extends DurableObject {
|
|
25
|
+
/**
|
|
26
|
+
* Execute a single SQL statement.
|
|
27
|
+
*
|
|
28
|
+
* Called via RPC from the Kysely driver connection.
|
|
29
|
+
*/
|
|
30
|
+
query(sql, params) {
|
|
31
|
+
const cursor = params?.length ? this.ctx.storage.sql.exec(sql, ...params) : this.ctx.storage.sql.exec(sql);
|
|
32
|
+
const rows = [];
|
|
33
|
+
for (const row of cursor) rows.push(row);
|
|
34
|
+
return {
|
|
35
|
+
rows,
|
|
36
|
+
changes: READ_PREFIXES.some((p) => sql.trimStart().toUpperCase().startsWith(p)) ? void 0 : cursor.rowsWritten
|
|
37
|
+
};
|
|
38
|
+
}
|
|
39
|
+
/**
|
|
40
|
+
* Execute multiple statements in a single synchronous transaction.
|
|
41
|
+
*
|
|
42
|
+
* Used for snapshot import.
|
|
43
|
+
*/
|
|
44
|
+
batch(statements) {
|
|
45
|
+
this.ctx.storage.transactionSync(() => {
|
|
46
|
+
for (const stmt of statements) if (stmt.params?.length) this.ctx.storage.sql.exec(stmt.sql, ...stmt.params);
|
|
47
|
+
else this.ctx.storage.sql.exec(stmt.sql);
|
|
48
|
+
});
|
|
49
|
+
}
|
|
50
|
+
/**
|
|
51
|
+
* Invalidate the cached snapshot so the next populateFromSnapshot call
|
|
52
|
+
* re-fetches from the source site.
|
|
53
|
+
*/
|
|
54
|
+
invalidateSnapshot() {
|
|
55
|
+
try {
|
|
56
|
+
this.ctx.storage.sql.exec("DELETE FROM _emdash_do_meta WHERE key = 'snapshot_fetched_at'");
|
|
57
|
+
} catch {}
|
|
58
|
+
}
|
|
59
|
+
/**
|
|
60
|
+
* Get snapshot metadata (generated-at timestamp).
|
|
61
|
+
* Returns null if the DO has no snapshot loaded.
|
|
62
|
+
*/
|
|
63
|
+
getSnapshotMeta() {
|
|
64
|
+
try {
|
|
65
|
+
const value = this.ctx.storage.sql.exec("SELECT value FROM _emdash_do_meta WHERE key = 'snapshot_generated_at'").one().value;
|
|
66
|
+
if (typeof value !== "string") return null;
|
|
67
|
+
return { generatedAt: value };
|
|
68
|
+
} catch {
|
|
69
|
+
return null;
|
|
70
|
+
}
|
|
71
|
+
}
|
|
72
|
+
/**
|
|
73
|
+
* Populate from a snapshot (preview mode).
|
|
74
|
+
*
|
|
75
|
+
* Fetches content from a source EmDash site and loads it into
|
|
76
|
+
* this DO's SQLite. Sets a TTL alarm for cleanup.
|
|
77
|
+
*/
|
|
78
|
+
async populateFromSnapshot(sourceUrl, signature, options) {
|
|
79
|
+
const ttlMs = (options?.ttl ?? DEFAULT_TTL_MS / 1e3) * 1e3;
|
|
80
|
+
try {
|
|
81
|
+
const meta = this.ctx.storage.sql.exec("SELECT value FROM _emdash_do_meta WHERE key = 'snapshot_fetched_at'").one();
|
|
82
|
+
const fetchedAt = Number(meta.value);
|
|
83
|
+
if (Date.now() - fetchedAt < ttlMs) {
|
|
84
|
+
this.ctx.storage.setAlarm(Date.now() + ttlMs);
|
|
85
|
+
const gen = this.ctx.storage.sql.exec("SELECT value FROM _emdash_do_meta WHERE key = 'snapshot_generated_at'").one();
|
|
86
|
+
return { generatedAt: String(gen.value) };
|
|
87
|
+
}
|
|
88
|
+
} catch (error) {
|
|
89
|
+
if (!(error instanceof Error) || !error.message.includes("no such table")) throw error;
|
|
90
|
+
}
|
|
91
|
+
const url = `${sourceUrl}/_emdash/api/snapshot${options?.drafts ? "?drafts=true" : ""}`;
|
|
92
|
+
const response = await fetch(url, {
|
|
93
|
+
headers: { "X-Preview-Signature": signature },
|
|
94
|
+
signal: AbortSignal.timeout(1e4)
|
|
95
|
+
});
|
|
96
|
+
if (!response.ok) {
|
|
97
|
+
const body = await response.text().catch(() => "");
|
|
98
|
+
throw new Error(`Snapshot fetch failed: ${response.status} ${response.statusText}${body ? ` — ${body}` : ""}`);
|
|
99
|
+
}
|
|
100
|
+
const snapshot = await response.json();
|
|
101
|
+
this.ctx.storage.transactionSync(() => {
|
|
102
|
+
this.dropAllTables();
|
|
103
|
+
this.applySnapshot(snapshot);
|
|
104
|
+
});
|
|
105
|
+
this.ctx.storage.setAlarm(Date.now() + ttlMs);
|
|
106
|
+
return { generatedAt: snapshot.generatedAt };
|
|
107
|
+
}
|
|
108
|
+
/**
|
|
109
|
+
* Set a cleanup alarm after the given number of seconds.
|
|
110
|
+
*
|
|
111
|
+
* Used by the playground middleware to set TTL after initialization
|
|
112
|
+
* is complete (initialization runs on the Worker side via RPC).
|
|
113
|
+
*/
|
|
114
|
+
setTtlAlarm(ttlSeconds) {
|
|
115
|
+
this.ctx.storage.setAlarm(Date.now() + ttlSeconds * 1e3);
|
|
116
|
+
}
|
|
117
|
+
/**
|
|
118
|
+
* Alarm handler — clean up expired preview/playground data.
|
|
119
|
+
*
|
|
120
|
+
* Drops all user tables to reclaim storage.
|
|
121
|
+
*/
|
|
122
|
+
alarm() {
|
|
123
|
+
this.dropAllTables();
|
|
124
|
+
}
|
|
125
|
+
/**
|
|
126
|
+
* Drop all user tables in the DO's SQLite database.
|
|
127
|
+
* Preserves SQLite and Cloudflare internal tables.
|
|
128
|
+
*/
|
|
129
|
+
dropAllTables() {
|
|
130
|
+
const tables = [...this.ctx.storage.sql.exec("SELECT name FROM sqlite_master WHERE type = 'table' AND name NOT LIKE 'sqlite_%' AND name NOT LIKE '_cf_%'")];
|
|
131
|
+
for (const row of tables) {
|
|
132
|
+
const name = String(row.name);
|
|
133
|
+
if (!SAFE_IDENTIFIER.test(name)) continue;
|
|
134
|
+
this.ctx.storage.sql.exec(`DROP TABLE IF EXISTS "${name}"`);
|
|
135
|
+
}
|
|
136
|
+
}
|
|
137
|
+
applySnapshot(snapshot) {
|
|
138
|
+
const validateSnapshotIdentifier = (name, context) => {
|
|
139
|
+
if (!SAFE_IDENTIFIER.test(name)) throw new Error(`Invalid ${context} in snapshot: ${JSON.stringify(name)}`);
|
|
140
|
+
};
|
|
141
|
+
this.ctx.storage.sql.exec(`
|
|
142
|
+
CREATE TABLE IF NOT EXISTS _emdash_do_meta (key TEXT PRIMARY KEY, value TEXT)
|
|
143
|
+
`);
|
|
144
|
+
for (const [tableName, rows] of Object.entries(snapshot.tables)) {
|
|
145
|
+
if (tableName === "_emdash_do_meta") continue;
|
|
146
|
+
if (!rows.length) continue;
|
|
147
|
+
validateSnapshotIdentifier(tableName, "table name");
|
|
148
|
+
const schemaInfo = snapshot.schema?.[tableName];
|
|
149
|
+
const columns = schemaInfo?.columns ?? Object.keys(rows[0]);
|
|
150
|
+
columns.forEach((c) => validateSnapshotIdentifier(c, `column name in ${tableName}`));
|
|
151
|
+
const colDefs = columns.map((c) => {
|
|
152
|
+
const colType = schemaInfo?.types?.[c] ?? "TEXT";
|
|
153
|
+
return `"${c}" ${[
|
|
154
|
+
"TEXT",
|
|
155
|
+
"INTEGER",
|
|
156
|
+
"REAL",
|
|
157
|
+
"BLOB",
|
|
158
|
+
"JSON"
|
|
159
|
+
].includes(colType.toUpperCase()) ? colType.toUpperCase() : "TEXT"}`;
|
|
160
|
+
}).join(", ");
|
|
161
|
+
this.ctx.storage.sql.exec(`CREATE TABLE IF NOT EXISTS "${tableName}" (${colDefs})`);
|
|
162
|
+
const placeholders = columns.map(() => "?").join(", ");
|
|
163
|
+
const insertSql = `INSERT INTO "${tableName}" (${columns.map((c) => `"${c}"`).join(", ")}) VALUES (${placeholders})`;
|
|
164
|
+
for (const row of rows) {
|
|
165
|
+
const values = columns.map((c) => row[c] ?? null);
|
|
166
|
+
this.ctx.storage.sql.exec(insertSql, ...values);
|
|
167
|
+
}
|
|
168
|
+
}
|
|
169
|
+
this.ctx.storage.sql.exec(`INSERT OR REPLACE INTO _emdash_do_meta VALUES ('snapshot_fetched_at', ?), ('snapshot_generated_at', ?)`, String(Date.now()), snapshot.generatedAt);
|
|
170
|
+
}
|
|
171
|
+
};
|
|
172
|
+
|
|
173
|
+
//#endregion
|
|
174
|
+
export { EmDashPreviewDB as t };
|
|
@@ -0,0 +1,73 @@
|
|
|
1
|
+
import { DurableObject } from "cloudflare:workers";
|
|
2
|
+
|
|
3
|
+
//#region src/db/do-class.d.ts
|
|
4
|
+
/** Result shape returned by query() */
|
|
5
|
+
interface QueryResult {
|
|
6
|
+
rows: Record<string, unknown>[];
|
|
7
|
+
/** Number of rows written. Undefined for read-only queries. */
|
|
8
|
+
changes?: number;
|
|
9
|
+
}
|
|
10
|
+
/** A single statement for batch execution */
|
|
11
|
+
interface BatchStatement {
|
|
12
|
+
sql: string;
|
|
13
|
+
params?: unknown[];
|
|
14
|
+
}
|
|
15
|
+
declare class EmDashPreviewDB extends DurableObject {
|
|
16
|
+
/**
|
|
17
|
+
* Execute a single SQL statement.
|
|
18
|
+
*
|
|
19
|
+
* Called via RPC from the Kysely driver connection.
|
|
20
|
+
*/
|
|
21
|
+
query(sql: string, params?: unknown[]): QueryResult;
|
|
22
|
+
/**
|
|
23
|
+
* Execute multiple statements in a single synchronous transaction.
|
|
24
|
+
*
|
|
25
|
+
* Used for snapshot import.
|
|
26
|
+
*/
|
|
27
|
+
batch(statements: BatchStatement[]): void;
|
|
28
|
+
/**
|
|
29
|
+
* Invalidate the cached snapshot so the next populateFromSnapshot call
|
|
30
|
+
* re-fetches from the source site.
|
|
31
|
+
*/
|
|
32
|
+
invalidateSnapshot(): void;
|
|
33
|
+
/**
|
|
34
|
+
* Get snapshot metadata (generated-at timestamp).
|
|
35
|
+
* Returns null if the DO has no snapshot loaded.
|
|
36
|
+
*/
|
|
37
|
+
getSnapshotMeta(): {
|
|
38
|
+
generatedAt: string;
|
|
39
|
+
} | null;
|
|
40
|
+
/**
|
|
41
|
+
* Populate from a snapshot (preview mode).
|
|
42
|
+
*
|
|
43
|
+
* Fetches content from a source EmDash site and loads it into
|
|
44
|
+
* this DO's SQLite. Sets a TTL alarm for cleanup.
|
|
45
|
+
*/
|
|
46
|
+
populateFromSnapshot(sourceUrl: string, signature: string, options?: {
|
|
47
|
+
drafts?: boolean;
|
|
48
|
+
ttl?: number;
|
|
49
|
+
}): Promise<{
|
|
50
|
+
generatedAt: string;
|
|
51
|
+
}>;
|
|
52
|
+
/**
|
|
53
|
+
* Set a cleanup alarm after the given number of seconds.
|
|
54
|
+
*
|
|
55
|
+
* Used by the playground middleware to set TTL after initialization
|
|
56
|
+
* is complete (initialization runs on the Worker side via RPC).
|
|
57
|
+
*/
|
|
58
|
+
setTtlAlarm(ttlSeconds: number): void;
|
|
59
|
+
/**
|
|
60
|
+
* Alarm handler — clean up expired preview/playground data.
|
|
61
|
+
*
|
|
62
|
+
* Drops all user tables to reclaim storage.
|
|
63
|
+
*/
|
|
64
|
+
alarm(): void;
|
|
65
|
+
/**
|
|
66
|
+
* Drop all user tables in the DO's SQLite database.
|
|
67
|
+
* Preserves SQLite and Cloudflare internal tables.
|
|
68
|
+
*/
|
|
69
|
+
private dropAllTables;
|
|
70
|
+
private applySnapshot;
|
|
71
|
+
}
|
|
72
|
+
//#endregion
|
|
73
|
+
export { EmDashPreviewDB as t };
|
|
@@ -0,0 +1,58 @@
|
|
|
1
|
+
import { t as D1Introspector } from "./d1-introspector-bZf0_ylK.mjs";
|
|
2
|
+
import { SqliteAdapter, SqliteQueryCompiler } from "kysely";
|
|
3
|
+
|
|
4
|
+
//#region src/db/do-dialect.ts
|
|
5
|
+
var PreviewDODialect = class {
|
|
6
|
+
#config;
|
|
7
|
+
constructor(config) {
|
|
8
|
+
this.#config = config;
|
|
9
|
+
}
|
|
10
|
+
createAdapter() {
|
|
11
|
+
return new SqliteAdapter();
|
|
12
|
+
}
|
|
13
|
+
createDriver() {
|
|
14
|
+
return new PreviewDODriver(this.#config);
|
|
15
|
+
}
|
|
16
|
+
createQueryCompiler() {
|
|
17
|
+
return new SqliteQueryCompiler();
|
|
18
|
+
}
|
|
19
|
+
createIntrospector(db) {
|
|
20
|
+
return new D1Introspector(db);
|
|
21
|
+
}
|
|
22
|
+
};
|
|
23
|
+
var PreviewDODriver = class {
|
|
24
|
+
#config;
|
|
25
|
+
constructor(config) {
|
|
26
|
+
this.#config = config;
|
|
27
|
+
}
|
|
28
|
+
async init() {}
|
|
29
|
+
async acquireConnection() {
|
|
30
|
+
return new PreviewDOConnection(this.#config.getStub());
|
|
31
|
+
}
|
|
32
|
+
async beginTransaction() {}
|
|
33
|
+
async commitTransaction() {}
|
|
34
|
+
async rollbackTransaction() {}
|
|
35
|
+
async releaseConnection() {}
|
|
36
|
+
async destroy() {}
|
|
37
|
+
};
|
|
38
|
+
var PreviewDOConnection = class {
|
|
39
|
+
#stub;
|
|
40
|
+
constructor(stub) {
|
|
41
|
+
this.#stub = stub;
|
|
42
|
+
}
|
|
43
|
+
async executeQuery(compiledQuery) {
|
|
44
|
+
const sqlText = compiledQuery.sql;
|
|
45
|
+
const params = compiledQuery.parameters;
|
|
46
|
+
const result = await this.#stub.query(sqlText, params);
|
|
47
|
+
return {
|
|
48
|
+
rows: result.rows,
|
|
49
|
+
numAffectedRows: result.changes !== void 0 ? BigInt(result.changes) : void 0
|
|
50
|
+
};
|
|
51
|
+
}
|
|
52
|
+
async *streamQuery() {
|
|
53
|
+
throw new Error("Preview DO dialect does not support streaming");
|
|
54
|
+
}
|
|
55
|
+
};
|
|
56
|
+
|
|
57
|
+
//#endregion
|
|
58
|
+
export { PreviewDODialect as t };
|
|
@@ -0,0 +1,49 @@
|
|
|
1
|
+
//#region src/db/do-playground-routes.ts
|
|
2
|
+
/**
|
|
3
|
+
* Playground mode route gating.
|
|
4
|
+
*
|
|
5
|
+
* Unlike preview mode (which blocks everything except read-only API routes),
|
|
6
|
+
* playground mode allows most routes including the admin UI and write APIs.
|
|
7
|
+
* Only auth, setup, and abuse-prone routes are blocked.
|
|
8
|
+
*
|
|
9
|
+
* Pure function -- no Worker or Cloudflare dependencies.
|
|
10
|
+
*/
|
|
11
|
+
/**
|
|
12
|
+
* Routes blocked in playground mode.
|
|
13
|
+
*
|
|
14
|
+
* These are either security-sensitive (auth, setup, tokens, OAuth),
|
|
15
|
+
* abuse-prone (media upload, plugin install), or pointless in a
|
|
16
|
+
* temporary playground (snapshot export, user management).
|
|
17
|
+
*/
|
|
18
|
+
/**
|
|
19
|
+
* Auth routes that ARE allowed in playground mode.
|
|
20
|
+
* /auth/me is needed by the admin UI to identify the current user.
|
|
21
|
+
*/
|
|
22
|
+
const AUTH_ALLOWLIST = new Set(["/_emdash/api/auth/me"]);
|
|
23
|
+
const BLOCKED_PREFIXES = [
|
|
24
|
+
"/_emdash/api/auth/",
|
|
25
|
+
"/_emdash/api/setup/",
|
|
26
|
+
"/_emdash/api/oauth/",
|
|
27
|
+
"/_emdash/api/tokens/",
|
|
28
|
+
"/_emdash/api/users/invite",
|
|
29
|
+
"/_emdash/api/plugins/install",
|
|
30
|
+
"/_emdash/api/plugins/marketplace",
|
|
31
|
+
"/_emdash/api/media/upload",
|
|
32
|
+
"/_emdash/api/snapshot"
|
|
33
|
+
];
|
|
34
|
+
/**
|
|
35
|
+
* Check whether a request should be blocked in playground mode.
|
|
36
|
+
*
|
|
37
|
+
* Playground allows most CMS functionality: content CRUD, schema editing,
|
|
38
|
+
* taxonomies, menus, widgets, search, settings, and the full admin UI.
|
|
39
|
+
* Only auth, setup, user management, media uploads, and plugin
|
|
40
|
+
* installation are blocked.
|
|
41
|
+
*/
|
|
42
|
+
function isBlockedInPlayground(pathname) {
|
|
43
|
+
if (AUTH_ALLOWLIST.has(pathname)) return false;
|
|
44
|
+
for (const prefix of BLOCKED_PREFIXES) if (pathname === prefix || pathname.startsWith(prefix)) return true;
|
|
45
|
+
return false;
|
|
46
|
+
}
|
|
47
|
+
|
|
48
|
+
//#endregion
|
|
49
|
+
export { isBlockedInPlayground as t };
|
|
@@ -0,0 +1,14 @@
|
|
|
1
|
+
//#region src/db/do-types.d.ts
|
|
2
|
+
/**
|
|
3
|
+
* Shared Durable Object config types (preview-only)
|
|
4
|
+
*
|
|
5
|
+
* Imported by both the config-time entry (index.ts) and the runtime entry (do.ts).
|
|
6
|
+
* This module must NOT import from cloudflare:workers so it stays safe at config time.
|
|
7
|
+
*/
|
|
8
|
+
/** Durable Object preview database configuration */
|
|
9
|
+
interface PreviewDOConfig {
|
|
10
|
+
/** Wrangler binding name for the DO namespace */
|
|
11
|
+
binding: string;
|
|
12
|
+
}
|
|
13
|
+
//#endregion
|
|
14
|
+
export { PreviewDOConfig as t };
|
|
@@ -0,0 +1,76 @@
|
|
|
1
|
+
import { MediaProviderDescriptor } from "emdash/media";
|
|
2
|
+
|
|
3
|
+
//#region src/media/images.d.ts
|
|
4
|
+
/**
|
|
5
|
+
* Cloudflare Images configuration
|
|
6
|
+
*/
|
|
7
|
+
interface CloudflareImagesConfig {
|
|
8
|
+
/**
|
|
9
|
+
* Cloudflare Account ID (for API calls)
|
|
10
|
+
* If not provided, reads from accountIdEnvVar at runtime
|
|
11
|
+
*/
|
|
12
|
+
accountId?: string;
|
|
13
|
+
/**
|
|
14
|
+
* Environment variable name containing the Account ID
|
|
15
|
+
* @default "CF_ACCOUNT_ID"
|
|
16
|
+
*/
|
|
17
|
+
accountIdEnvVar?: string;
|
|
18
|
+
/**
|
|
19
|
+
* Cloudflare Images Account Hash (for delivery URLs)
|
|
20
|
+
* This is different from the Account ID - find it in the Cloudflare dashboard
|
|
21
|
+
* under Images > Overview > "Account Hash"
|
|
22
|
+
* If not provided, reads from accountHashEnvVar at runtime
|
|
23
|
+
*/
|
|
24
|
+
accountHash?: string;
|
|
25
|
+
/**
|
|
26
|
+
* Environment variable name containing the Account Hash
|
|
27
|
+
* @default "CF_IMAGES_ACCOUNT_HASH"
|
|
28
|
+
*/
|
|
29
|
+
accountHashEnvVar?: string;
|
|
30
|
+
/**
|
|
31
|
+
* API Token with Images permissions
|
|
32
|
+
* If not provided, reads from apiTokenEnvVar at runtime
|
|
33
|
+
* Should have "Cloudflare Images: Read" and "Cloudflare Images: Edit" permissions
|
|
34
|
+
*/
|
|
35
|
+
apiToken?: string;
|
|
36
|
+
/**
|
|
37
|
+
* Environment variable name containing the API token
|
|
38
|
+
* @default "CF_IMAGES_TOKEN"
|
|
39
|
+
*/
|
|
40
|
+
apiTokenEnvVar?: string;
|
|
41
|
+
/**
|
|
42
|
+
* Custom delivery domain (optional)
|
|
43
|
+
* If not specified, uses imagedelivery.net
|
|
44
|
+
* @example "images.example.com"
|
|
45
|
+
*/
|
|
46
|
+
deliveryDomain?: string;
|
|
47
|
+
/**
|
|
48
|
+
* Default variant to use for display
|
|
49
|
+
* @default "public"
|
|
50
|
+
*/
|
|
51
|
+
defaultVariant?: string;
|
|
52
|
+
}
|
|
53
|
+
/**
|
|
54
|
+
* Cloudflare Images media provider
|
|
55
|
+
*
|
|
56
|
+
* @example
|
|
57
|
+
* ```ts
|
|
58
|
+
* import { cloudflareImages } from "@emdash-cms/cloudflare";
|
|
59
|
+
*
|
|
60
|
+
* emdash({
|
|
61
|
+
* mediaProviders: [
|
|
62
|
+
* // Uses CF_ACCOUNT_ID and CF_IMAGES_TOKEN env vars by default
|
|
63
|
+
* cloudflareImages({}),
|
|
64
|
+
*
|
|
65
|
+
* // Or with custom env var names
|
|
66
|
+
* cloudflareImages({
|
|
67
|
+
* accountIdEnvVar: "MY_CF_ACCOUNT",
|
|
68
|
+
* apiTokenEnvVar: "MY_CF_IMAGES_KEY",
|
|
69
|
+
* }),
|
|
70
|
+
* ],
|
|
71
|
+
* })
|
|
72
|
+
* ```
|
|
73
|
+
*/
|
|
74
|
+
declare function cloudflareImages(config: CloudflareImagesConfig): MediaProviderDescriptor<CloudflareImagesConfig>;
|
|
75
|
+
//#endregion
|
|
76
|
+
export { cloudflareImages as n, CloudflareImagesConfig as t };
|
package/dist/index.d.mts
ADDED
|
@@ -0,0 +1,200 @@
|
|
|
1
|
+
import { CloudflareCacheConfig } from "./cache/runtime.mjs";
|
|
2
|
+
import { cloudflareCache } from "./cache/config.mjs";
|
|
3
|
+
import { t as PreviewDOConfig } from "./do-types-CY0G0oyh.mjs";
|
|
4
|
+
import { n as cloudflareImages, t as CloudflareImagesConfig } from "./images-4RT9Ag8_.mjs";
|
|
5
|
+
import { n as cloudflareStream, t as CloudflareStreamConfig } from "./stream-DdbcvKi0.mjs";
|
|
6
|
+
import { AuthDescriptor, DatabaseDescriptor, StorageDescriptor } from "emdash";
|
|
7
|
+
|
|
8
|
+
//#region src/index.d.ts
|
|
9
|
+
/**
|
|
10
|
+
* D1 configuration
|
|
11
|
+
*/
|
|
12
|
+
interface D1Config {
|
|
13
|
+
/**
|
|
14
|
+
* Name of the D1 binding in wrangler.toml
|
|
15
|
+
*/
|
|
16
|
+
binding: string;
|
|
17
|
+
/**
|
|
18
|
+
* Read replication session mode.
|
|
19
|
+
*
|
|
20
|
+
* - `"disabled"` — No sessions. All queries go to primary. (default)
|
|
21
|
+
* - `"auto"` — Automatic session management. Anonymous requests use
|
|
22
|
+
* `"first-unconstrained"` (nearest replica). Authenticated requests
|
|
23
|
+
* use bookmark cookies for read-your-writes consistency.
|
|
24
|
+
* - `"primary-first"` — Like `"auto"`, but the first query in every
|
|
25
|
+
* session goes to the primary. Use this if your site has very
|
|
26
|
+
* frequent writes and you need stronger consistency guarantees
|
|
27
|
+
* at the cost of higher read latency.
|
|
28
|
+
*
|
|
29
|
+
* Read replication must also be enabled on the D1 database itself
|
|
30
|
+
* (via dashboard or REST API).
|
|
31
|
+
*/
|
|
32
|
+
session?: "disabled" | "auto" | "primary-first";
|
|
33
|
+
/**
|
|
34
|
+
* Cookie name for storing the session bookmark.
|
|
35
|
+
* Only used when session is `"auto"` or `"primary-first"`.
|
|
36
|
+
*
|
|
37
|
+
* @default "__ec_d1_bookmark"
|
|
38
|
+
*/
|
|
39
|
+
bookmarkCookie?: string;
|
|
40
|
+
}
|
|
41
|
+
/**
|
|
42
|
+
* R2 storage configuration
|
|
43
|
+
*/
|
|
44
|
+
interface R2StorageConfig {
|
|
45
|
+
/**
|
|
46
|
+
* Name of the R2 binding in wrangler.toml
|
|
47
|
+
*/
|
|
48
|
+
binding: string;
|
|
49
|
+
/**
|
|
50
|
+
* Public URL for accessing files (optional CDN)
|
|
51
|
+
*/
|
|
52
|
+
publicUrl?: string;
|
|
53
|
+
}
|
|
54
|
+
/**
|
|
55
|
+
* Configuration for Cloudflare Access authentication
|
|
56
|
+
*/
|
|
57
|
+
interface AccessConfig {
|
|
58
|
+
/**
|
|
59
|
+
* Your Cloudflare Access team domain
|
|
60
|
+
* @example "myteam.cloudflareaccess.com"
|
|
61
|
+
*/
|
|
62
|
+
teamDomain: string;
|
|
63
|
+
/**
|
|
64
|
+
* Application Audience (AUD) tag from Access application settings.
|
|
65
|
+
* For Cloudflare Workers, use `audienceEnvVar` instead to read at runtime.
|
|
66
|
+
*/
|
|
67
|
+
audience?: string;
|
|
68
|
+
/**
|
|
69
|
+
* Environment variable name containing the audience tag.
|
|
70
|
+
* Read at runtime from environment.
|
|
71
|
+
* @default "CF_ACCESS_AUDIENCE"
|
|
72
|
+
*/
|
|
73
|
+
audienceEnvVar?: string;
|
|
74
|
+
/**
|
|
75
|
+
* Automatically create EmDash users on first login
|
|
76
|
+
* @default true
|
|
77
|
+
*/
|
|
78
|
+
autoProvision?: boolean;
|
|
79
|
+
/**
|
|
80
|
+
* Role level for users not matching any group in roleMapping
|
|
81
|
+
* @default 30 (Editor)
|
|
82
|
+
*/
|
|
83
|
+
defaultRole?: number;
|
|
84
|
+
/**
|
|
85
|
+
* Update user's role on each login based on current IdP groups
|
|
86
|
+
* When false, role is only set on first provisioning
|
|
87
|
+
* @default false
|
|
88
|
+
*/
|
|
89
|
+
syncRoles?: boolean;
|
|
90
|
+
/**
|
|
91
|
+
* Map IdP group names to EmDash role levels
|
|
92
|
+
* First match wins if user is in multiple groups
|
|
93
|
+
*
|
|
94
|
+
* @example
|
|
95
|
+
* ```ts
|
|
96
|
+
* roleMapping: {
|
|
97
|
+
* "Admins": 50, // Admin
|
|
98
|
+
* "Developers": 40, // Developer
|
|
99
|
+
* "Content Team": 30, // Editor
|
|
100
|
+
* }
|
|
101
|
+
* ```
|
|
102
|
+
*/
|
|
103
|
+
roleMapping?: Record<string, number>;
|
|
104
|
+
}
|
|
105
|
+
/**
|
|
106
|
+
* Cloudflare D1 database adapter
|
|
107
|
+
*
|
|
108
|
+
* For Cloudflare Workers with D1 binding.
|
|
109
|
+
* Migrations run automatically at setup time - no need for manual SQL files.
|
|
110
|
+
*
|
|
111
|
+
* Uses a custom introspector that works around D1's restriction on
|
|
112
|
+
* cross-joins with pragma_table_info().
|
|
113
|
+
*
|
|
114
|
+
* @example
|
|
115
|
+
* ```ts
|
|
116
|
+
* database: d1({ binding: "DB" })
|
|
117
|
+
* ```
|
|
118
|
+
*/
|
|
119
|
+
declare function d1(config: D1Config): DatabaseDescriptor;
|
|
120
|
+
/**
|
|
121
|
+
* Durable Object preview database adapter
|
|
122
|
+
*
|
|
123
|
+
* Each preview session gets an isolated SQLite database inside a DO,
|
|
124
|
+
* populated from a snapshot of the source EmDash site.
|
|
125
|
+
*
|
|
126
|
+
* Not for production use — preview only.
|
|
127
|
+
*
|
|
128
|
+
* @example
|
|
129
|
+
* ```ts
|
|
130
|
+
* database: previewDatabase({ binding: "PREVIEW_DB" })
|
|
131
|
+
* ```
|
|
132
|
+
*/
|
|
133
|
+
declare function previewDatabase(config: PreviewDOConfig): DatabaseDescriptor;
|
|
134
|
+
/**
|
|
135
|
+
* Durable Object playground database adapter
|
|
136
|
+
*
|
|
137
|
+
* Each playground session gets an isolated SQLite database inside a DO,
|
|
138
|
+
* populated from a seed file with migrations run at init time.
|
|
139
|
+
* Unlike preview, playground is writable and has admin access.
|
|
140
|
+
*
|
|
141
|
+
* Not for production use -- playground/demo only.
|
|
142
|
+
*
|
|
143
|
+
* @example
|
|
144
|
+
* ```ts
|
|
145
|
+
* database: playgroundDatabase({ binding: "PLAYGROUND_DB" })
|
|
146
|
+
* ```
|
|
147
|
+
*/
|
|
148
|
+
declare function playgroundDatabase(config: PreviewDOConfig): DatabaseDescriptor;
|
|
149
|
+
/**
|
|
150
|
+
* Cloudflare R2 binding adapter
|
|
151
|
+
*
|
|
152
|
+
* Uses R2 bindings directly when running on Cloudflare Workers.
|
|
153
|
+
* Does NOT support signed upload URLs (use s3() with R2 credentials instead).
|
|
154
|
+
*
|
|
155
|
+
* Requires R2 binding in wrangler.toml:
|
|
156
|
+
* ```toml
|
|
157
|
+
* [[r2_buckets]]
|
|
158
|
+
* binding = "MEDIA"
|
|
159
|
+
* bucket_name = "my-media-bucket"
|
|
160
|
+
* ```
|
|
161
|
+
*
|
|
162
|
+
* @example
|
|
163
|
+
* ```ts
|
|
164
|
+
* storage: r2({ binding: "MEDIA" })
|
|
165
|
+
* ```
|
|
166
|
+
*/
|
|
167
|
+
declare function r2(config: R2StorageConfig): StorageDescriptor;
|
|
168
|
+
/**
|
|
169
|
+
* Cloudflare Access authentication adapter
|
|
170
|
+
*
|
|
171
|
+
* Use this to configure EmDash to authenticate via Cloudflare Access.
|
|
172
|
+
* When Access is configured, passkey auth is disabled.
|
|
173
|
+
*
|
|
174
|
+
* @example
|
|
175
|
+
* ```ts
|
|
176
|
+
* auth: access({
|
|
177
|
+
* teamDomain: "myteam.cloudflareaccess.com",
|
|
178
|
+
* audience: "abc123...",
|
|
179
|
+
* roleMapping: {
|
|
180
|
+
* "Admins": 50,
|
|
181
|
+
* "Editors": 30,
|
|
182
|
+
* },
|
|
183
|
+
* })
|
|
184
|
+
* ```
|
|
185
|
+
*/
|
|
186
|
+
declare function access(config: AccessConfig): AuthDescriptor;
|
|
187
|
+
/**
|
|
188
|
+
* Cloudflare Worker Loader sandbox adapter
|
|
189
|
+
*
|
|
190
|
+
* Returns the module path for the Cloudflare sandbox runner.
|
|
191
|
+
* Use this in the `sandboxRunner` config option.
|
|
192
|
+
*
|
|
193
|
+
* @example
|
|
194
|
+
* ```ts
|
|
195
|
+
* sandboxRunner: sandbox()
|
|
196
|
+
* ```
|
|
197
|
+
*/
|
|
198
|
+
declare function sandbox(): string;
|
|
199
|
+
//#endregion
|
|
200
|
+
export { AccessConfig, type CloudflareCacheConfig, type CloudflareImagesConfig, type CloudflareStreamConfig, D1Config, type PreviewDOConfig, R2StorageConfig, access, cloudflareCache, cloudflareImages, cloudflareStream, d1, playgroundDatabase, previewDatabase, r2, sandbox };
|