emdash 0.9.0 → 0.11.0
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/{adapters-DoNJiveC.d.mts → adapters-BktHA7EO.d.mts} +1 -1
- package/dist/{adapters-DoNJiveC.d.mts.map → adapters-BktHA7EO.d.mts.map} +1 -1
- package/dist/{apply-BzltprvY.mjs → apply-Ded_1vng.mjs} +167 -254
- package/dist/apply-Ded_1vng.mjs.map +1 -0
- package/dist/astro/index.d.mts +6 -6
- package/dist/astro/index.mjs +10 -2
- package/dist/astro/index.mjs.map +1 -1
- package/dist/astro/middleware/auth.d.mts +5 -5
- package/dist/astro/middleware/auth.mjs +5 -5
- package/dist/astro/middleware/redirect.mjs +5 -5
- package/dist/astro/middleware/request-context.mjs +4 -4
- package/dist/astro/middleware/setup.mjs +1 -1
- package/dist/astro/middleware.d.mts.map +1 -1
- package/dist/astro/middleware.mjs +94 -43
- package/dist/astro/middleware.mjs.map +1 -1
- package/dist/astro/types.d.mts +12 -11
- package/dist/astro/types.d.mts.map +1 -1
- package/dist/{base64-BRICGH2l.mjs → base64-MBPo9ozB.mjs} +1 -1
- package/dist/{base64-BRICGH2l.mjs.map → base64-MBPo9ozB.mjs.map} +1 -1
- package/dist/{byline-BSaNL1w7.mjs → byline-gFn1r0vA.mjs} +4 -4
- package/dist/{byline-BSaNL1w7.mjs.map → byline-gFn1r0vA.mjs.map} +1 -1
- package/dist/{bylines-CvJ3PYz2.mjs → bylines-DTFI8nDM.mjs} +5 -5
- package/dist/{bylines-CvJ3PYz2.mjs.map → bylines-DTFI8nDM.mjs.map} +1 -1
- package/dist/{cache-C6N_hhN7.mjs → cache-BAJbeoZ8.mjs} +3 -3
- package/dist/{cache-C6N_hhN7.mjs.map → cache-BAJbeoZ8.mjs.map} +1 -1
- package/dist/{chunks-NBQVDOci.mjs → chunks-BK1oZS-l.mjs} +2 -2
- package/dist/{chunks-NBQVDOci.mjs.map → chunks-BK1oZS-l.mjs.map} +1 -1
- package/dist/cli/index.mjs +342 -95
- package/dist/cli/index.mjs.map +1 -1
- package/dist/client/cf-access.d.mts +1 -1
- package/dist/client/index.d.mts +1 -1
- package/dist/client/index.mjs +1 -1
- package/dist/{config-BI0V3ICQ.mjs → config-CVssduLe.mjs} +1 -1
- package/dist/{config-BI0V3ICQ.mjs.map → config-CVssduLe.mjs.map} +1 -1
- package/dist/{content-8lOYF0pr.mjs → content-CERxPUN0.mjs} +14 -3
- package/dist/content-CERxPUN0.mjs.map +1 -0
- package/dist/database/instrumentation.d.mts +6 -4
- package/dist/database/instrumentation.d.mts.map +1 -1
- package/dist/database/instrumentation.mjs +19 -7
- package/dist/database/instrumentation.mjs.map +1 -1
- package/dist/db/index.d.mts +3 -3
- package/dist/db/index.mjs +1 -1
- package/dist/db/libsql.d.mts +1 -1
- package/dist/db/postgres.d.mts +1 -1
- package/dist/db/sqlite.d.mts +1 -1
- package/dist/{db-errors-WRezodiz.mjs → db-errors-B7P2pSCn.mjs} +1 -1
- package/dist/{db-errors-WRezodiz.mjs.map → db-errors-B7P2pSCn.mjs.map} +1 -1
- package/dist/{default-D8ksjWhO.mjs → default-pHuz9WF6.mjs} +1 -1
- package/dist/{default-D8ksjWhO.mjs.map → default-pHuz9WF6.mjs.map} +1 -1
- package/dist/{error-D_-tqP-I.mjs → error-DqnRMM5z.mjs} +1 -1
- package/dist/{error-D_-tqP-I.mjs.map → error-DqnRMM5z.mjs.map} +1 -1
- package/dist/{index-BFRaVcD6.d.mts → index-Cg-rC4Gj.d.mts} +110 -87
- package/dist/index-Cg-rC4Gj.d.mts.map +1 -0
- package/dist/index.d.mts +11 -11
- package/dist/index.mjs +29 -28
- package/dist/{load-DDqMMvZL.mjs → load-DR1VwFXR.mjs} +2 -2
- package/dist/{load-DDqMMvZL.mjs.map → load-DR1VwFXR.mjs.map} +1 -1
- package/dist/{loader-CKLbBnhK.mjs → loader-ou_PXAjg.mjs} +31 -6
- package/dist/loader-ou_PXAjg.mjs.map +1 -0
- package/dist/{manifest-schema-DqWNC3lM.mjs → manifest-schema-CXAbd1vH.mjs} +1 -1
- package/dist/{manifest-schema-DqWNC3lM.mjs.map → manifest-schema-CXAbd1vH.mjs.map} +1 -1
- package/dist/media/index.d.mts +1 -1
- package/dist/media/index.mjs +1 -1
- package/dist/media/local-runtime.d.mts +7 -7
- package/dist/media/local-runtime.mjs +3 -3
- package/dist/{media-BW32b4gi.mjs → media-1fFhub9c.mjs} +22 -10
- package/dist/media-1fFhub9c.mjs.map +1 -0
- package/dist/{mode-ier8jbBk.mjs → mode-YhqNVef_.mjs} +1 -1
- package/dist/{mode-ier8jbBk.mjs.map → mode-YhqNVef_.mjs.map} +1 -1
- package/dist/{options-BVp3UsTS.mjs → options-nPxWnrya.mjs} +1 -1
- package/dist/{options-BVp3UsTS.mjs.map → options-nPxWnrya.mjs.map} +1 -1
- package/dist/page/index.d.mts +2 -2
- package/dist/{patterns-CrCYkMBb.mjs → patterns-DsUZ4uxI.mjs} +1 -1
- package/dist/{patterns-CrCYkMBb.mjs.map → patterns-DsUZ4uxI.mjs.map} +1 -1
- package/dist/{placeholder-BE4o_2dc.d.mts → placeholder-CDPtkelt.d.mts} +1 -1
- package/dist/{placeholder-BE4o_2dc.d.mts.map → placeholder-CDPtkelt.d.mts.map} +1 -1
- package/dist/{placeholder-CIJejMlK.mjs → placeholder-Ci0RLeCk.mjs} +1 -1
- package/dist/{placeholder-CIJejMlK.mjs.map → placeholder-Ci0RLeCk.mjs.map} +1 -1
- package/dist/plugins/adapt-sandbox-entry.d.mts +5 -5
- package/dist/plugins/adapt-sandbox-entry.mjs +2 -2
- package/dist/{public-url-DByxYjUw.mjs → public-url-B1AxbbbQ.mjs} +1 -1
- package/dist/{public-url-DByxYjUw.mjs.map → public-url-B1AxbbbQ.mjs.map} +1 -1
- package/dist/{query-Cg9ZKRQ0.mjs → query-8c_meo_K.mjs} +13 -13
- package/dist/{query-Cg9ZKRQ0.mjs.map → query-8c_meo_K.mjs.map} +1 -1
- package/dist/{redirect-BhUBKRc1.mjs → redirect-C5H7VGIX.mjs} +3 -3
- package/dist/{redirect-BhUBKRc1.mjs.map → redirect-C5H7VGIX.mjs.map} +1 -1
- package/dist/{registry-Dw70ChxB.mjs → registry-Do34mz_P.mjs} +7 -6
- package/dist/registry-Do34mz_P.mjs.map +1 -0
- package/dist/{request-cache-B-bmkipQ.mjs → request-cache-D4I69LeL.mjs} +6 -2
- package/dist/request-cache-D4I69LeL.mjs.map +1 -0
- package/dist/request-context.d.mts +27 -1
- package/dist/request-context.d.mts.map +1 -1
- package/dist/request-context.mjs +16 -3
- package/dist/request-context.mjs.map +1 -1
- package/dist/{runner-C7ADox5q.mjs → runner-DIcU2UCC.mjs} +465 -148
- package/dist/runner-DIcU2UCC.mjs.map +1 -0
- package/dist/{runner-Bnoj7vjK.d.mts → runner-Iu3IZSDM.d.mts} +2 -2
- package/dist/{runner-Bnoj7vjK.d.mts.map → runner-Iu3IZSDM.d.mts.map} +1 -1
- package/dist/runtime.d.mts +6 -6
- package/dist/runtime.mjs +3 -3
- package/dist/{search-dOGEccMa.mjs → search-DuWhx4NG.mjs} +322 -108
- package/dist/search-DuWhx4NG.mjs.map +1 -0
- package/dist/{secrets-CW3reAnU.mjs → secrets-CZ8rxLX3.mjs} +3 -3
- package/dist/{secrets-CW3reAnU.mjs.map → secrets-CZ8rxLX3.mjs.map} +1 -1
- package/dist/seed/index.d.mts +2 -2
- package/dist/seed/index.mjs +15 -14
- package/dist/seo/index.d.mts +1 -1
- package/dist/storage/local.d.mts +1 -1
- package/dist/storage/local.mjs +1 -1
- package/dist/storage/s3.d.mts +1 -1
- package/dist/storage/s3.mjs +1 -1
- package/dist/taxonomies-Bw76xAxo.mjs +407 -0
- package/dist/taxonomies-Bw76xAxo.mjs.map +1 -0
- package/dist/taxonomy-D6NvlKo8.mjs +218 -0
- package/dist/taxonomy-D6NvlKo8.mjs.map +1 -0
- package/dist/{tokens-D7zMmWi2.mjs → tokens-CyRDPVW2.mjs} +2 -2
- package/dist/{tokens-D7zMmWi2.mjs.map → tokens-CyRDPVW2.mjs.map} +1 -1
- package/dist/{transaction-Cn2rjY78.mjs → transaction-D44LBXvU.mjs} +1 -1
- package/dist/{transaction-Cn2rjY78.mjs.map → transaction-D44LBXvU.mjs.map} +1 -1
- package/dist/{transport-DNEfeMaU.d.mts → transport-DX_5rpsq.d.mts} +1 -1
- package/dist/{transport-DNEfeMaU.d.mts.map → transport-DX_5rpsq.d.mts.map} +1 -1
- package/dist/{transport-BeMCmin1.mjs → transport-xpzIjCIB.mjs} +1 -1
- package/dist/{transport-BeMCmin1.mjs.map → transport-xpzIjCIB.mjs.map} +1 -1
- package/dist/{types-CIOg5AR8.mjs → types-56BKbld_.mjs} +1 -1
- package/dist/types-56BKbld_.mjs.map +1 -0
- package/dist/{types-CRxNbK-Z.mjs → types-BIgulNsW.mjs} +2 -2
- package/dist/{types-CRxNbK-Z.mjs.map → types-BIgulNsW.mjs.map} +1 -1
- package/dist/{types-CrtWgIvl.d.mts → types-BQx6ZXpR.d.mts} +10 -1
- package/dist/types-BQx6ZXpR.d.mts.map +1 -0
- package/dist/{types-CJsYGpco.d.mts → types-B_CXXnzh.d.mts} +1 -1
- package/dist/{types-CJsYGpco.d.mts.map → types-B_CXXnzh.d.mts.map} +1 -1
- package/dist/{types-M78DQ1lx.d.mts → types-C-aFbqmA.d.mts} +1 -1
- package/dist/{types-M78DQ1lx.d.mts.map → types-C-aFbqmA.d.mts.map} +1 -1
- package/dist/types-DiI8NOG_.mjs +16 -0
- package/dist/types-DiI8NOG_.mjs.map +1 -0
- package/dist/{types-BuBIptGk.d.mts → types-IN5z_S3P.d.mts} +158 -92
- package/dist/types-IN5z_S3P.d.mts.map +1 -0
- package/dist/{types-BSyXeCFW.d.mts → types-IZSZfEwv.d.mts} +4 -3
- package/dist/types-IZSZfEwv.d.mts.map +1 -0
- package/dist/{types-CDbKp7ND.mjs → types-K-EkEQCI.mjs} +1 -1
- package/dist/{types-CDbKp7ND.mjs.map → types-K-EkEQCI.mjs.map} +1 -1
- package/dist/{validate-BfQh_C_y.d.mts → validate-CO3JjFV5.d.mts} +22 -5
- package/dist/validate-CO3JjFV5.d.mts.map +1 -0
- package/dist/{validate-Baqf0slj.mjs → validate-UK4Ja1uo.mjs} +14 -10
- package/dist/validate-UK4Ja1uo.mjs.map +1 -0
- package/dist/{validation-BfEI7tNe.mjs → validation-Vc5DQkJa.mjs} +5 -5
- package/dist/{validation-BfEI7tNe.mjs.map → validation-Vc5DQkJa.mjs.map} +1 -1
- package/dist/version-Bg31I_Ff.mjs +7 -0
- package/dist/{version-DoxrVdYf.mjs.map → version-Bg31I_Ff.mjs.map} +1 -1
- package/dist/{zod-generator-CC0xNe_K.mjs → zod-generator-CHnJUP2l.mjs} +8 -3
- package/dist/zod-generator-CHnJUP2l.mjs.map +1 -0
- package/package.json +9 -8
- package/src/api/errors.ts +5 -0
- package/src/api/handlers/content.ts +20 -0
- package/src/api/handlers/dashboard.ts +29 -36
- package/src/api/handlers/media-allowlist.ts +40 -0
- package/src/api/handlers/media.ts +1 -1
- package/src/api/handlers/menus.ts +400 -89
- package/src/api/handlers/taxonomies.ts +273 -97
- package/src/api/handlers/validate-media-fields.ts +125 -0
- package/src/api/schemas/common.ts +7 -0
- package/src/api/schemas/media.ts +23 -3
- package/src/api/schemas/menus.ts +23 -0
- package/src/api/schemas/schema.ts +11 -2
- package/src/api/schemas/taxonomies.ts +39 -0
- package/src/astro/integration/routes.ts +10 -0
- package/src/astro/middleware.ts +46 -11
- package/src/astro/routes/api/content/[collection]/[id]/permanent.ts +1 -1
- package/src/astro/routes/api/import/wordpress/rewrite-url-helpers.ts +196 -0
- package/src/astro/routes/api/import/wordpress/rewrite-urls.ts +9 -177
- package/src/astro/routes/api/media/upload-url.ts +10 -4
- package/src/astro/routes/api/media.ts +12 -4
- package/src/astro/routes/api/menus/[name]/items.ts +16 -6
- package/src/astro/routes/api/menus/[name]/reorder.ts +8 -3
- package/src/astro/routes/api/menus/[name]/translations.ts +82 -0
- package/src/astro/routes/api/menus/[name].ts +19 -10
- package/src/astro/routes/api/menus/index.ts +9 -6
- package/src/astro/routes/api/taxonomies/[name]/terms/[slug]/translations.ts +89 -0
- package/src/astro/routes/api/taxonomies/[name]/terms/[slug].ts +22 -22
- package/src/astro/routes/api/taxonomies/[name]/terms/index.ts +11 -14
- package/src/astro/routes/api/taxonomies/index.ts +9 -6
- package/src/astro/types.ts +5 -1
- package/src/auth/rate-limit.ts +3 -3
- package/src/cli/commands/bundle-utils.ts +81 -6
- package/src/cli/commands/bundle.ts +18 -15
- package/src/cli/commands/export-seed.ts +139 -24
- package/src/cli/commands/plugin-init.ts +216 -90
- package/src/database/instrumentation.ts +22 -8
- package/src/database/migrations/016_api_tokens.ts +18 -3
- package/src/database/migrations/036_i18n_menus_and_taxonomies.ts +477 -0
- package/src/database/migrations/037_credential_algorithm.ts +18 -0
- package/src/database/migrations/runner.ts +4 -0
- package/src/database/repositories/content.ts +11 -0
- package/src/database/repositories/media.ts +40 -10
- package/src/database/repositories/taxonomy.ts +193 -89
- package/src/database/types.ts +12 -3
- package/src/emdash-runtime.ts +16 -3
- package/src/fields/file.ts +7 -6
- package/src/fields/image.ts +12 -11
- package/src/fields/types.ts +3 -0
- package/src/i18n/resolve.ts +37 -0
- package/src/index.ts +1 -1
- package/src/loader.ts +49 -2
- package/src/mcp/server.ts +114 -26
- package/src/media/mime.ts +75 -0
- package/src/menus/index.ts +143 -124
- package/src/menus/types.ts +15 -1
- package/src/plugins/types.ts +81 -191
- package/src/request-cache.ts +6 -2
- package/src/request-context.ts +42 -2
- package/src/schema/registry.ts +5 -5
- package/src/schema/types.ts +3 -2
- package/src/schema/zod-generator.ts +12 -2
- package/src/seed/apply.ts +157 -54
- package/src/seed/types.ts +18 -1
- package/src/seed/validate.ts +27 -13
- package/src/taxonomies/index.ts +230 -213
- package/src/taxonomies/types.ts +10 -0
- package/dist/apply-BzltprvY.mjs.map +0 -1
- package/dist/content-8lOYF0pr.mjs.map +0 -1
- package/dist/index-BFRaVcD6.d.mts.map +0 -1
- package/dist/loader-CKLbBnhK.mjs.map +0 -1
- package/dist/media-BW32b4gi.mjs.map +0 -1
- package/dist/registry-Dw70ChxB.mjs.map +0 -1
- package/dist/request-cache-B-bmkipQ.mjs.map +0 -1
- package/dist/runner-C7ADox5q.mjs.map +0 -1
- package/dist/search-dOGEccMa.mjs.map +0 -1
- package/dist/taxonomies-ZlRtD6AG.mjs +0 -315
- package/dist/taxonomies-ZlRtD6AG.mjs.map +0 -1
- package/dist/types-4fVtCIm0.mjs +0 -68
- package/dist/types-4fVtCIm0.mjs.map +0 -1
- package/dist/types-BSyXeCFW.d.mts.map +0 -1
- package/dist/types-BuBIptGk.d.mts.map +0 -1
- package/dist/types-CIOg5AR8.mjs.map +0 -1
- package/dist/types-CrtWgIvl.d.mts.map +0 -1
- package/dist/validate-Baqf0slj.mjs.map +0 -1
- package/dist/validate-BfQh_C_y.d.mts.map +0 -1
- package/dist/version-DoxrVdYf.mjs +0 -7
- package/dist/zod-generator-CC0xNe_K.mjs.map +0 -1
|
@@ -1,5 +1,6 @@
|
|
|
1
1
|
import { t as validateIdentifier } from "./validate-VPnKoIzW.mjs";
|
|
2
2
|
import { c as listTablesLike, i as currentTimestampValue, n as columnExists, o as isSqlite, r as currentTimestamp, t as binaryType } from "./dialect-helpers-BKCvISIQ.mjs";
|
|
3
|
+
import { n as getI18nConfig } from "./config-CVssduLe.mjs";
|
|
3
4
|
import { createRequire } from "node:module";
|
|
4
5
|
import { Migrator, sql } from "kysely";
|
|
5
6
|
|
|
@@ -22,8 +23,8 @@ var __exportAll = (all, no_symbols) => {
|
|
|
22
23
|
//#endregion
|
|
23
24
|
//#region src/database/migrations/001_initial.ts
|
|
24
25
|
var _001_initial_exports = /* @__PURE__ */ __exportAll({
|
|
25
|
-
down: () => down$
|
|
26
|
-
up: () => up$
|
|
26
|
+
down: () => down$35,
|
|
27
|
+
up: () => up$35
|
|
27
28
|
});
|
|
28
29
|
/**
|
|
29
30
|
* Initial schema migration
|
|
@@ -32,7 +33,7 @@ var _001_initial_exports = /* @__PURE__ */ __exportAll({
|
|
|
32
33
|
* by the SchemaRegistry when collections are added via the admin UI.
|
|
33
34
|
* This migration only creates system tables.
|
|
34
35
|
*/
|
|
35
|
-
async function up$
|
|
36
|
+
async function up$35(db) {
|
|
36
37
|
await db.schema.createTable("revisions").ifNotExists().addColumn("id", "text", (col) => col.primaryKey()).addColumn("collection", "text", (col) => col.notNull()).addColumn("entry_id", "text", (col) => col.notNull()).addColumn("data", "text", (col) => col.notNull()).addColumn("author_id", "text").addColumn("created_at", "text", (col) => col.defaultTo(currentTimestamp(db))).execute();
|
|
37
38
|
await db.schema.createIndex("idx_revisions_entry").ifNotExists().on("revisions").columns(["collection", "entry_id"]).execute();
|
|
38
39
|
await db.schema.createTable("taxonomies").ifNotExists().addColumn("id", "text", (col) => col.primaryKey()).addColumn("name", "text", (col) => col.notNull()).addColumn("slug", "text", (col) => col.notNull()).addColumn("label", "text", (col) => col.notNull()).addColumn("parent_id", "text").addColumn("data", "text").addUniqueConstraint("taxonomies_name_slug_unique", ["name", "slug"]).addForeignKeyConstraint("taxonomies_parent_fk", ["parent_id"], "taxonomies", ["id"], (cb) => cb.onDelete("set null")).execute();
|
|
@@ -52,7 +53,7 @@ async function up$33(db) {
|
|
|
52
53
|
await db.schema.createIndex("idx_audit_action").ifNotExists().on("audit_logs").column("action").execute();
|
|
53
54
|
await db.schema.createIndex("idx_audit_timestamp").ifNotExists().on("audit_logs").column("timestamp").execute();
|
|
54
55
|
}
|
|
55
|
-
async function down$
|
|
56
|
+
async function down$35(db) {
|
|
56
57
|
await db.schema.dropTable("audit_logs").execute();
|
|
57
58
|
await db.schema.dropTable("options").execute();
|
|
58
59
|
await db.schema.dropTable("users").execute();
|
|
@@ -65,26 +66,26 @@ async function down$33(db) {
|
|
|
65
66
|
//#endregion
|
|
66
67
|
//#region src/database/migrations/002_media_status.ts
|
|
67
68
|
var _002_media_status_exports = /* @__PURE__ */ __exportAll({
|
|
68
|
-
down: () => down$
|
|
69
|
-
up: () => up$
|
|
69
|
+
down: () => down$34,
|
|
70
|
+
up: () => up$34
|
|
70
71
|
});
|
|
71
72
|
/**
|
|
72
73
|
* Add status column to media table for tracking upload state.
|
|
73
74
|
* Status values: 'pending' | 'ready' | 'failed'
|
|
74
75
|
*/
|
|
75
|
-
async function up$
|
|
76
|
+
async function up$34(db) {
|
|
76
77
|
await db.schema.alterTable("media").addColumn("status", "text", (col) => col.notNull().defaultTo("ready")).execute();
|
|
77
78
|
await db.schema.createIndex("idx_media_status").on("media").column("status").execute();
|
|
78
79
|
}
|
|
79
|
-
async function down$
|
|
80
|
+
async function down$34(db) {
|
|
80
81
|
await db.schema.dropIndex("idx_media_status").execute();
|
|
81
82
|
}
|
|
82
83
|
|
|
83
84
|
//#endregion
|
|
84
85
|
//#region src/database/migrations/003_schema_registry.ts
|
|
85
86
|
var _003_schema_registry_exports = /* @__PURE__ */ __exportAll({
|
|
86
|
-
down: () => down$
|
|
87
|
-
up: () => up$
|
|
87
|
+
down: () => down$33,
|
|
88
|
+
up: () => up$33
|
|
88
89
|
});
|
|
89
90
|
/**
|
|
90
91
|
* Migration: Schema Registry Tables
|
|
@@ -92,14 +93,14 @@ var _003_schema_registry_exports = /* @__PURE__ */ __exportAll({
|
|
|
92
93
|
* Creates the schema registry tables that store collection and field definitions.
|
|
93
94
|
* This enables dynamic schema management where D1 is the source of truth.
|
|
94
95
|
*/
|
|
95
|
-
async function up$
|
|
96
|
+
async function up$33(db) {
|
|
96
97
|
await db.schema.createTable("_emdash_collections").addColumn("id", "text", (col) => col.primaryKey()).addColumn("slug", "text", (col) => col.notNull().unique()).addColumn("label", "text", (col) => col.notNull()).addColumn("label_singular", "text").addColumn("description", "text").addColumn("icon", "text").addColumn("supports", "text").addColumn("source", "text").addColumn("created_at", "text", (col) => col.defaultTo(currentTimestamp(db))).addColumn("updated_at", "text", (col) => col.defaultTo(currentTimestamp(db))).execute();
|
|
97
98
|
await db.schema.createTable("_emdash_fields").addColumn("id", "text", (col) => col.primaryKey()).addColumn("collection_id", "text", (col) => col.notNull()).addColumn("slug", "text", (col) => col.notNull()).addColumn("label", "text", (col) => col.notNull()).addColumn("type", "text", (col) => col.notNull()).addColumn("column_type", "text", (col) => col.notNull()).addColumn("required", "integer", (col) => col.defaultTo(0)).addColumn("unique", "integer", (col) => col.defaultTo(0)).addColumn("default_value", "text").addColumn("validation", "text").addColumn("widget", "text").addColumn("options", "text").addColumn("sort_order", "integer", (col) => col.defaultTo(0)).addColumn("created_at", "text", (col) => col.defaultTo(currentTimestamp(db))).addForeignKeyConstraint("fields_collection_fk", ["collection_id"], "_emdash_collections", ["id"], (cb) => cb.onDelete("cascade")).execute();
|
|
98
99
|
await db.schema.createIndex("idx_fields_collection_slug").on("_emdash_fields").columns(["collection_id", "slug"]).unique().execute();
|
|
99
100
|
await db.schema.createIndex("idx_fields_collection").on("_emdash_fields").column("collection_id").execute();
|
|
100
101
|
await db.schema.createIndex("idx_fields_sort").on("_emdash_fields").columns(["collection_id", "sort_order"]).execute();
|
|
101
102
|
}
|
|
102
|
-
async function down$
|
|
103
|
+
async function down$33(db) {
|
|
103
104
|
await db.schema.dropTable("_emdash_fields").execute();
|
|
104
105
|
await db.schema.dropTable("_emdash_collections").execute();
|
|
105
106
|
}
|
|
@@ -107,8 +108,8 @@ async function down$31(db) {
|
|
|
107
108
|
//#endregion
|
|
108
109
|
//#region src/database/migrations/004_plugins.ts
|
|
109
110
|
var _004_plugins_exports = /* @__PURE__ */ __exportAll({
|
|
110
|
-
down: () => down$
|
|
111
|
-
up: () => up$
|
|
111
|
+
down: () => down$32,
|
|
112
|
+
up: () => up$32
|
|
112
113
|
});
|
|
113
114
|
/**
|
|
114
115
|
* Migration: Plugin System Tables
|
|
@@ -118,7 +119,7 @@ var _004_plugins_exports = /* @__PURE__ */ __exportAll({
|
|
|
118
119
|
*
|
|
119
120
|
* @see PLUGIN-SYSTEM.md § Plugin Storage
|
|
120
121
|
*/
|
|
121
|
-
async function up$
|
|
122
|
+
async function up$32(db) {
|
|
122
123
|
await db.schema.createTable("_plugin_storage").addColumn("plugin_id", "text", (col) => col.notNull()).addColumn("collection", "text", (col) => col.notNull()).addColumn("id", "text", (col) => col.notNull()).addColumn("data", "text", (col) => col.notNull()).addColumn("created_at", "text", (col) => col.defaultTo(currentTimestamp(db))).addColumn("updated_at", "text", (col) => col.defaultTo(currentTimestamp(db))).addPrimaryKeyConstraint("pk_plugin_storage", [
|
|
123
124
|
"plugin_id",
|
|
124
125
|
"collection",
|
|
@@ -136,7 +137,7 @@ async function up$30(db) {
|
|
|
136
137
|
"index_name"
|
|
137
138
|
]).execute();
|
|
138
139
|
}
|
|
139
|
-
async function down$
|
|
140
|
+
async function down$32(db) {
|
|
140
141
|
await db.schema.dropTable("_plugin_indexes").execute();
|
|
141
142
|
await db.schema.dropTable("_plugin_state").execute();
|
|
142
143
|
await db.schema.dropTable("_plugin_storage").execute();
|
|
@@ -145,8 +146,8 @@ async function down$30(db) {
|
|
|
145
146
|
//#endregion
|
|
146
147
|
//#region src/database/migrations/005_menus.ts
|
|
147
148
|
var _005_menus_exports = /* @__PURE__ */ __exportAll({
|
|
148
|
-
down: () => down$
|
|
149
|
-
up: () => up$
|
|
149
|
+
down: () => down$31,
|
|
150
|
+
up: () => up$31
|
|
150
151
|
});
|
|
151
152
|
/**
|
|
152
153
|
* Navigation Menus migration
|
|
@@ -154,13 +155,13 @@ var _005_menus_exports = /* @__PURE__ */ __exportAll({
|
|
|
154
155
|
* Creates tables for admin-editable navigation menus.
|
|
155
156
|
* Menu items can reference content entries, taxonomy terms, or custom URLs.
|
|
156
157
|
*/
|
|
157
|
-
async function up$
|
|
158
|
+
async function up$31(db) {
|
|
158
159
|
await db.schema.createTable("_emdash_menus").addColumn("id", "text", (col) => col.primaryKey()).addColumn("name", "text", (col) => col.notNull().unique()).addColumn("label", "text", (col) => col.notNull()).addColumn("created_at", "text", (col) => col.defaultTo(currentTimestamp(db))).addColumn("updated_at", "text", (col) => col.defaultTo(currentTimestamp(db))).execute();
|
|
159
160
|
await db.schema.createTable("_emdash_menu_items").addColumn("id", "text", (col) => col.primaryKey()).addColumn("menu_id", "text", (col) => col.notNull()).addColumn("parent_id", "text").addColumn("sort_order", "integer", (col) => col.notNull().defaultTo(0)).addColumn("type", "text", (col) => col.notNull()).addColumn("reference_collection", "text").addColumn("reference_id", "text").addColumn("custom_url", "text").addColumn("label", "text", (col) => col.notNull()).addColumn("title_attr", "text").addColumn("target", "text").addColumn("css_classes", "text").addColumn("created_at", "text", (col) => col.defaultTo(currentTimestamp(db))).addForeignKeyConstraint("menu_items_menu_fk", ["menu_id"], "_emdash_menus", ["id"], (cb) => cb.onDelete("cascade")).addForeignKeyConstraint("menu_items_parent_fk", ["parent_id"], "_emdash_menu_items", ["id"], (cb) => cb.onDelete("cascade")).execute();
|
|
160
161
|
await db.schema.createIndex("idx_menu_items_menu").on("_emdash_menu_items").columns(["menu_id", "sort_order"]).execute();
|
|
161
162
|
await db.schema.createIndex("idx_menu_items_parent").on("_emdash_menu_items").column("parent_id").execute();
|
|
162
163
|
}
|
|
163
|
-
async function down$
|
|
164
|
+
async function down$31(db) {
|
|
164
165
|
await db.schema.dropTable("_emdash_menu_items").execute();
|
|
165
166
|
await db.schema.dropTable("_emdash_menus").execute();
|
|
166
167
|
}
|
|
@@ -168,8 +169,8 @@ async function down$29(db) {
|
|
|
168
169
|
//#endregion
|
|
169
170
|
//#region src/database/migrations/006_taxonomy_defs.ts
|
|
170
171
|
var _006_taxonomy_defs_exports = /* @__PURE__ */ __exportAll({
|
|
171
|
-
down: () => down$
|
|
172
|
-
up: () => up$
|
|
172
|
+
down: () => down$30,
|
|
173
|
+
up: () => up$30
|
|
173
174
|
});
|
|
174
175
|
/**
|
|
175
176
|
* Taxonomy definitions migration
|
|
@@ -177,7 +178,7 @@ var _006_taxonomy_defs_exports = /* @__PURE__ */ __exportAll({
|
|
|
177
178
|
* Adds _emdash_taxonomy_defs table to store taxonomy definitions (category, tag, custom)
|
|
178
179
|
* and seeds default category and tag taxonomies.
|
|
179
180
|
*/
|
|
180
|
-
async function up$
|
|
181
|
+
async function up$30(db) {
|
|
181
182
|
await db.schema.createTable("_emdash_taxonomy_defs").addColumn("id", "text", (col) => col.primaryKey()).addColumn("name", "text", (col) => col.notNull().unique()).addColumn("label", "text", (col) => col.notNull()).addColumn("label_singular", "text").addColumn("hierarchical", "integer", (col) => col.defaultTo(0)).addColumn("collections", "text").addColumn("created_at", "text", (col) => col.defaultTo(currentTimestamp(db))).execute();
|
|
182
183
|
await db.insertInto("_emdash_taxonomy_defs").values([{
|
|
183
184
|
id: "taxdef_category",
|
|
@@ -195,22 +196,22 @@ async function up$28(db) {
|
|
|
195
196
|
collections: JSON.stringify(["posts"])
|
|
196
197
|
}]).execute();
|
|
197
198
|
}
|
|
198
|
-
async function down$
|
|
199
|
+
async function down$30(db) {
|
|
199
200
|
await db.schema.dropTable("_emdash_taxonomy_defs").execute();
|
|
200
201
|
}
|
|
201
202
|
|
|
202
203
|
//#endregion
|
|
203
204
|
//#region src/database/migrations/007_widgets.ts
|
|
204
205
|
var _007_widgets_exports = /* @__PURE__ */ __exportAll({
|
|
205
|
-
down: () => down$
|
|
206
|
-
up: () => up$
|
|
206
|
+
down: () => down$29,
|
|
207
|
+
up: () => up$29
|
|
207
208
|
});
|
|
208
|
-
async function up$
|
|
209
|
+
async function up$29(db) {
|
|
209
210
|
await db.schema.createTable("_emdash_widget_areas").addColumn("id", "text", (col) => col.primaryKey()).addColumn("name", "text", (col) => col.notNull().unique()).addColumn("label", "text", (col) => col.notNull()).addColumn("description", "text").addColumn("created_at", "text", (col) => col.defaultTo(sql`CURRENT_TIMESTAMP`)).execute();
|
|
210
211
|
await db.schema.createTable("_emdash_widgets").addColumn("id", "text", (col) => col.primaryKey()).addColumn("area_id", "text", (col) => col.notNull().references("_emdash_widget_areas.id").onDelete("cascade")).addColumn("sort_order", "integer", (col) => col.notNull().defaultTo(0)).addColumn("type", "text", (col) => col.notNull()).addColumn("title", "text").addColumn("content", "text").addColumn("menu_name", "text").addColumn("component_id", "text").addColumn("component_props", "text").addColumn("created_at", "text", (col) => col.defaultTo(sql`CURRENT_TIMESTAMP`)).execute();
|
|
211
212
|
await db.schema.createIndex("idx_widgets_area").on("_emdash_widgets").columns(["area_id", "sort_order"]).execute();
|
|
212
213
|
}
|
|
213
|
-
async function down$
|
|
214
|
+
async function down$29(db) {
|
|
214
215
|
await db.schema.dropTable("_emdash_widgets").execute();
|
|
215
216
|
await db.schema.dropTable("_emdash_widget_areas").execute();
|
|
216
217
|
}
|
|
@@ -218,8 +219,8 @@ async function down$27(db) {
|
|
|
218
219
|
//#endregion
|
|
219
220
|
//#region src/database/migrations/008_auth.ts
|
|
220
221
|
var _008_auth_exports = /* @__PURE__ */ __exportAll({
|
|
221
|
-
down: () => down$
|
|
222
|
-
up: () => up$
|
|
222
|
+
down: () => down$28,
|
|
223
|
+
up: () => up$28
|
|
223
224
|
});
|
|
224
225
|
/**
|
|
225
226
|
* Auth migration - passkey-first authentication
|
|
@@ -233,7 +234,7 @@ var _008_auth_exports = /* @__PURE__ */ __exportAll({
|
|
|
233
234
|
* - Creates oauth_accounts table (external provider links)
|
|
234
235
|
* - Creates allowed_domains table (self-signup)
|
|
235
236
|
*/
|
|
236
|
-
async function up$
|
|
237
|
+
async function up$28(db) {
|
|
237
238
|
await db.schema.createTable("users_new").addColumn("id", "text", (col) => col.primaryKey()).addColumn("email", "text", (col) => col.notNull().unique()).addColumn("name", "text").addColumn("avatar_url", "text").addColumn("role", "integer", (col) => col.notNull().defaultTo(10)).addColumn("email_verified", "integer", (col) => col.notNull().defaultTo(0)).addColumn("data", "text").addColumn("created_at", "text", (col) => col.defaultTo(currentTimestamp(db))).addColumn("updated_at", "text", (col) => col.defaultTo(currentTimestamp(db))).execute();
|
|
238
239
|
await sql`
|
|
239
240
|
INSERT INTO users_new (id, email, name, role, data, created_at, updated_at)
|
|
@@ -266,7 +267,7 @@ async function up$26(db) {
|
|
|
266
267
|
await db.schema.createTable("auth_challenges").addColumn("challenge", "text", (col) => col.primaryKey()).addColumn("type", "text", (col) => col.notNull()).addColumn("user_id", "text").addColumn("data", "text").addColumn("expires_at", "text", (col) => col.notNull()).addColumn("created_at", "text", (col) => col.defaultTo(currentTimestamp(db))).execute();
|
|
267
268
|
await db.schema.createIndex("idx_auth_challenges_expires").on("auth_challenges").column("expires_at").execute();
|
|
268
269
|
}
|
|
269
|
-
async function down$
|
|
270
|
+
async function down$28(db) {
|
|
270
271
|
await db.schema.dropTable("auth_challenges").execute();
|
|
271
272
|
await db.schema.dropTable("allowed_domains").execute();
|
|
272
273
|
await db.schema.dropTable("oauth_accounts").execute();
|
|
@@ -299,8 +300,8 @@ async function down$26(db) {
|
|
|
299
300
|
//#endregion
|
|
300
301
|
//#region src/database/migrations/009_user_disabled.ts
|
|
301
302
|
var _009_user_disabled_exports = /* @__PURE__ */ __exportAll({
|
|
302
|
-
down: () => down$
|
|
303
|
-
up: () => up$
|
|
303
|
+
down: () => down$27,
|
|
304
|
+
up: () => up$27
|
|
304
305
|
});
|
|
305
306
|
/**
|
|
306
307
|
* User disabled column - for soft-disabling users
|
|
@@ -309,19 +310,19 @@ var _009_user_disabled_exports = /* @__PURE__ */ __exportAll({
|
|
|
309
310
|
* - Adds disabled column to users table (INTEGER, default 0)
|
|
310
311
|
* - Disabled users cannot log in
|
|
311
312
|
*/
|
|
312
|
-
async function up$
|
|
313
|
+
async function up$27(db) {
|
|
313
314
|
await sql`ALTER TABLE users ADD COLUMN disabled INTEGER NOT NULL DEFAULT 0`.execute(db);
|
|
314
315
|
await db.schema.createIndex("idx_users_disabled").on("users").column("disabled").execute();
|
|
315
316
|
}
|
|
316
|
-
async function down$
|
|
317
|
+
async function down$27(db) {
|
|
317
318
|
await db.schema.dropIndex("idx_users_disabled").execute();
|
|
318
319
|
}
|
|
319
320
|
|
|
320
321
|
//#endregion
|
|
321
322
|
//#region src/database/migrations/011_sections.ts
|
|
322
323
|
var _011_sections_exports = /* @__PURE__ */ __exportAll({
|
|
323
|
-
down: () => down$
|
|
324
|
-
up: () => up$
|
|
324
|
+
down: () => down$26,
|
|
325
|
+
up: () => up$26
|
|
325
326
|
});
|
|
326
327
|
/**
|
|
327
328
|
* Migration: Add sections tables and performance indexes
|
|
@@ -330,13 +331,13 @@ var _011_sections_exports = /* @__PURE__ */ __exportAll({
|
|
|
330
331
|
* They provide a library of pre-built page sections (heroes, CTAs, testimonials, etc.)
|
|
331
332
|
* that content authors can browse and insert with a single click.
|
|
332
333
|
*/
|
|
333
|
-
async function up$
|
|
334
|
+
async function up$26(db) {
|
|
334
335
|
await db.schema.createTable("_emdash_section_categories").addColumn("id", "text", (col) => col.primaryKey()).addColumn("slug", "text", (col) => col.notNull().unique()).addColumn("label", "text", (col) => col.notNull()).addColumn("sort_order", "integer", (col) => col.defaultTo(0)).addColumn("created_at", "text", (col) => col.defaultTo(sql`CURRENT_TIMESTAMP`)).execute();
|
|
335
336
|
await db.schema.createTable("_emdash_sections").addColumn("id", "text", (col) => col.primaryKey()).addColumn("slug", "text", (col) => col.notNull().unique()).addColumn("title", "text", (col) => col.notNull()).addColumn("description", "text").addColumn("category_id", "text", (col) => col.references("_emdash_section_categories.id").onDelete("set null")).addColumn("keywords", "text").addColumn("content", "text", (col) => col.notNull()).addColumn("preview_media_id", "text").addColumn("source", "text", (col) => col.notNull().defaultTo("user")).addColumn("theme_id", "text").addColumn("created_at", "text", (col) => col.defaultTo(sql`CURRENT_TIMESTAMP`)).addColumn("updated_at", "text", (col) => col.defaultTo(sql`CURRENT_TIMESTAMP`)).execute();
|
|
336
337
|
await db.schema.createIndex("idx_sections_category").on("_emdash_sections").columns(["category_id"]).execute();
|
|
337
338
|
await db.schema.createIndex("idx_sections_source").on("_emdash_sections").columns(["source"]).execute();
|
|
338
339
|
}
|
|
339
|
-
async function down$
|
|
340
|
+
async function down$26(db) {
|
|
340
341
|
await db.schema.dropIndex("idx_sections_source").execute();
|
|
341
342
|
await db.schema.dropIndex("idx_sections_category").execute();
|
|
342
343
|
await db.schema.dropTable("_emdash_sections").execute();
|
|
@@ -346,8 +347,8 @@ async function down$24(db) {
|
|
|
346
347
|
//#endregion
|
|
347
348
|
//#region src/database/migrations/012_search.ts
|
|
348
349
|
var _012_search_exports = /* @__PURE__ */ __exportAll({
|
|
349
|
-
down: () => down$
|
|
350
|
-
up: () => up$
|
|
350
|
+
down: () => down$25,
|
|
351
|
+
up: () => up$25
|
|
351
352
|
});
|
|
352
353
|
/**
|
|
353
354
|
* Migration: Search Support
|
|
@@ -355,11 +356,11 @@ var _012_search_exports = /* @__PURE__ */ __exportAll({
|
|
|
355
356
|
* Adds search configuration to collections and searchable flag to fields.
|
|
356
357
|
* FTS5 tables are created dynamically when search is enabled for a collection.
|
|
357
358
|
*/
|
|
358
|
-
async function up$
|
|
359
|
+
async function up$25(db) {
|
|
359
360
|
await db.schema.alterTable("_emdash_collections").addColumn("search_config", "text").execute();
|
|
360
361
|
await db.schema.alterTable("_emdash_fields").addColumn("searchable", "integer", (col) => col.defaultTo(0)).execute();
|
|
361
362
|
}
|
|
362
|
-
async function down$
|
|
363
|
+
async function down$25(db) {
|
|
363
364
|
await db.schema.alterTable("_emdash_fields").dropColumn("searchable").execute();
|
|
364
365
|
await db.schema.alterTable("_emdash_collections").dropColumn("search_config").execute();
|
|
365
366
|
}
|
|
@@ -367,8 +368,8 @@ async function down$23(db) {
|
|
|
367
368
|
//#endregion
|
|
368
369
|
//#region src/database/migrations/013_scheduled_publishing.ts
|
|
369
370
|
var _013_scheduled_publishing_exports = /* @__PURE__ */ __exportAll({
|
|
370
|
-
down: () => down$
|
|
371
|
-
up: () => up$
|
|
371
|
+
down: () => down$24,
|
|
372
|
+
up: () => up$24
|
|
372
373
|
});
|
|
373
374
|
/**
|
|
374
375
|
* Migration: Add scheduled publishing support
|
|
@@ -377,7 +378,7 @@ var _013_scheduled_publishing_exports = /* @__PURE__ */ __exportAll({
|
|
|
377
378
|
* When scheduled_at is set and status is 'scheduled', the content
|
|
378
379
|
* will be auto-published when the scheduled time is reached.
|
|
379
380
|
*/
|
|
380
|
-
async function up$
|
|
381
|
+
async function up$24(db) {
|
|
381
382
|
const tableNames = await listTablesLike(db, "ec_%");
|
|
382
383
|
for (const tableName of tableNames) {
|
|
383
384
|
const table = { name: tableName };
|
|
@@ -392,7 +393,7 @@ async function up$22(db) {
|
|
|
392
393
|
`.execute(db);
|
|
393
394
|
}
|
|
394
395
|
}
|
|
395
|
-
async function down$
|
|
396
|
+
async function down$24(db) {
|
|
396
397
|
const tableNames = await listTablesLike(db, "ec_%");
|
|
397
398
|
for (const tableName of tableNames) {
|
|
398
399
|
const table = { name: tableName };
|
|
@@ -409,10 +410,10 @@ async function down$22(db) {
|
|
|
409
410
|
//#endregion
|
|
410
411
|
//#region src/database/migrations/014_draft_revisions.ts
|
|
411
412
|
var _014_draft_revisions_exports = /* @__PURE__ */ __exportAll({
|
|
412
|
-
down: () => down$
|
|
413
|
-
up: () => up$
|
|
413
|
+
down: () => down$23,
|
|
414
|
+
up: () => up$23
|
|
414
415
|
});
|
|
415
|
-
async function up$
|
|
416
|
+
async function up$23(db) {
|
|
416
417
|
const tables = await db.selectFrom("_emdash_collections").select("slug").execute();
|
|
417
418
|
for (const row of tables) {
|
|
418
419
|
const tableName = `ec_${row.slug}`;
|
|
@@ -434,7 +435,7 @@ async function up$21(db) {
|
|
|
434
435
|
`.execute(db);
|
|
435
436
|
}
|
|
436
437
|
}
|
|
437
|
-
async function down$
|
|
438
|
+
async function down$23(db) {
|
|
438
439
|
const tables = await db.selectFrom("_emdash_collections").select("slug").execute();
|
|
439
440
|
for (const row of tables) {
|
|
440
441
|
const tableName = `ec_${row.slug}`;
|
|
@@ -458,8 +459,8 @@ async function down$21(db) {
|
|
|
458
459
|
//#endregion
|
|
459
460
|
//#region src/database/migrations/015_indexes.ts
|
|
460
461
|
var _015_indexes_exports = /* @__PURE__ */ __exportAll({
|
|
461
|
-
down: () => down$
|
|
462
|
-
up: () => up$
|
|
462
|
+
down: () => down$22,
|
|
463
|
+
up: () => up$22
|
|
463
464
|
});
|
|
464
465
|
/**
|
|
465
466
|
* Add performance indexes for common query patterns.
|
|
@@ -472,7 +473,7 @@ var _015_indexes_exports = /* @__PURE__ */ __exportAll({
|
|
|
472
473
|
* 5. Retroactive author_id + updated_at on existing ec_* content tables
|
|
473
474
|
* (new tables get these from createContentTable() in registry.ts)
|
|
474
475
|
*/
|
|
475
|
-
async function up$
|
|
476
|
+
async function up$22(db) {
|
|
476
477
|
await db.schema.createIndex("idx_media_mime_type").on("media").column("mime_type").execute();
|
|
477
478
|
await db.schema.createIndex("idx_media_filename").on("media").column("filename").execute();
|
|
478
479
|
await db.schema.createIndex("idx_media_created_at").on("media").column("created_at").execute();
|
|
@@ -492,7 +493,7 @@ async function up$20(db) {
|
|
|
492
493
|
`.execute(db);
|
|
493
494
|
}
|
|
494
495
|
}
|
|
495
|
-
async function down$
|
|
496
|
+
async function down$22(db) {
|
|
496
497
|
const tableNames = await listTablesLike(db, "ec_%");
|
|
497
498
|
for (const tableName of tableNames) {
|
|
498
499
|
const table = { name: tableName };
|
|
@@ -510,8 +511,8 @@ async function down$20(db) {
|
|
|
510
511
|
//#endregion
|
|
511
512
|
//#region src/database/migrations/016_api_tokens.ts
|
|
512
513
|
var _016_api_tokens_exports = /* @__PURE__ */ __exportAll({
|
|
513
|
-
down: () => down$
|
|
514
|
-
up: () => up$
|
|
514
|
+
down: () => down$21,
|
|
515
|
+
up: () => up$21
|
|
515
516
|
});
|
|
516
517
|
/**
|
|
517
518
|
* API token tables for programmatic access.
|
|
@@ -520,27 +521,35 @@ var _016_api_tokens_exports = /* @__PURE__ */ __exportAll({
|
|
|
520
521
|
* 1. _emdash_api_tokens — Personal Access Tokens (ec_pat_...)
|
|
521
522
|
* 2. _emdash_oauth_tokens — OAuth access/refresh tokens (ec_oat_/ec_ort_...)
|
|
522
523
|
* 3. _emdash_device_codes — OAuth Device Flow state (RFC 8628)
|
|
524
|
+
*
|
|
525
|
+
* Every CREATE is guarded with `.ifNotExists()` so the migration is safe to
|
|
526
|
+
* re-run against a partially-applied schema. See #954 for the failure mode:
|
|
527
|
+
* if `up()` crashes mid-way (D1 subrequest limit, isolate cancellation,
|
|
528
|
+
* transient connection error), the migration record never gets inserted
|
|
529
|
+
* into `_emdash_migrations`, and the next request retries `up()` from the
|
|
530
|
+
* top. Without these guards, the retry crashed with `table ... already
|
|
531
|
+
* exists` and blocked every subsequent boot of the Worker.
|
|
523
532
|
*/
|
|
524
|
-
async function up$
|
|
525
|
-
await db.schema.createTable("_emdash_api_tokens").addColumn("id", "text", (col) => col.primaryKey()).addColumn("name", "text", (col) => col.notNull()).addColumn("token_hash", "text", (col) => col.notNull().unique()).addColumn("prefix", "text", (col) => col.notNull()).addColumn("user_id", "text", (col) => col.notNull()).addColumn("scopes", "text", (col) => col.notNull()).addColumn("expires_at", "text").addColumn("last_used_at", "text").addColumn("created_at", "text", (col) => col.defaultTo(currentTimestamp(db))).addForeignKeyConstraint("api_tokens_user_fk", ["user_id"], "users", ["id"], (cb) => cb.onDelete("cascade")).execute();
|
|
526
|
-
await db.schema.createIndex("idx_api_tokens_token_hash").on("_emdash_api_tokens").column("token_hash").execute();
|
|
527
|
-
await db.schema.createIndex("idx_api_tokens_user_id").on("_emdash_api_tokens").column("user_id").execute();
|
|
528
|
-
await db.schema.createTable("_emdash_oauth_tokens").addColumn("token_hash", "text", (col) => col.primaryKey()).addColumn("token_type", "text", (col) => col.notNull()).addColumn("user_id", "text", (col) => col.notNull()).addColumn("scopes", "text", (col) => col.notNull()).addColumn("client_type", "text", (col) => col.notNull().defaultTo("cli")).addColumn("expires_at", "text", (col) => col.notNull()).addColumn("refresh_token_hash", "text").addColumn("created_at", "text", (col) => col.defaultTo(currentTimestamp(db))).addForeignKeyConstraint("oauth_tokens_user_fk", ["user_id"], "users", ["id"], (cb) => cb.onDelete("cascade")).execute();
|
|
529
|
-
await db.schema.createIndex("idx_oauth_tokens_user_id").on("_emdash_oauth_tokens").column("user_id").execute();
|
|
530
|
-
await db.schema.createIndex("idx_oauth_tokens_expires").on("_emdash_oauth_tokens").column("expires_at").execute();
|
|
531
|
-
await db.schema.createTable("_emdash_device_codes").addColumn("device_code", "text", (col) => col.primaryKey()).addColumn("user_code", "text", (col) => col.notNull().unique()).addColumn("scopes", "text", (col) => col.notNull()).addColumn("user_id", "text").addColumn("status", "text", (col) => col.notNull().defaultTo("pending")).addColumn("expires_at", "text", (col) => col.notNull()).addColumn("interval", "integer", (col) => col.notNull().defaultTo(5)).addColumn("created_at", "text", (col) => col.defaultTo(currentTimestamp(db))).execute();
|
|
533
|
+
async function up$21(db) {
|
|
534
|
+
await db.schema.createTable("_emdash_api_tokens").ifNotExists().addColumn("id", "text", (col) => col.primaryKey()).addColumn("name", "text", (col) => col.notNull()).addColumn("token_hash", "text", (col) => col.notNull().unique()).addColumn("prefix", "text", (col) => col.notNull()).addColumn("user_id", "text", (col) => col.notNull()).addColumn("scopes", "text", (col) => col.notNull()).addColumn("expires_at", "text").addColumn("last_used_at", "text").addColumn("created_at", "text", (col) => col.defaultTo(currentTimestamp(db))).addForeignKeyConstraint("api_tokens_user_fk", ["user_id"], "users", ["id"], (cb) => cb.onDelete("cascade")).execute();
|
|
535
|
+
await db.schema.createIndex("idx_api_tokens_token_hash").ifNotExists().on("_emdash_api_tokens").column("token_hash").execute();
|
|
536
|
+
await db.schema.createIndex("idx_api_tokens_user_id").ifNotExists().on("_emdash_api_tokens").column("user_id").execute();
|
|
537
|
+
await db.schema.createTable("_emdash_oauth_tokens").ifNotExists().addColumn("token_hash", "text", (col) => col.primaryKey()).addColumn("token_type", "text", (col) => col.notNull()).addColumn("user_id", "text", (col) => col.notNull()).addColumn("scopes", "text", (col) => col.notNull()).addColumn("client_type", "text", (col) => col.notNull().defaultTo("cli")).addColumn("expires_at", "text", (col) => col.notNull()).addColumn("refresh_token_hash", "text").addColumn("created_at", "text", (col) => col.defaultTo(currentTimestamp(db))).addForeignKeyConstraint("oauth_tokens_user_fk", ["user_id"], "users", ["id"], (cb) => cb.onDelete("cascade")).execute();
|
|
538
|
+
await db.schema.createIndex("idx_oauth_tokens_user_id").ifNotExists().on("_emdash_oauth_tokens").column("user_id").execute();
|
|
539
|
+
await db.schema.createIndex("idx_oauth_tokens_expires").ifNotExists().on("_emdash_oauth_tokens").column("expires_at").execute();
|
|
540
|
+
await db.schema.createTable("_emdash_device_codes").ifNotExists().addColumn("device_code", "text", (col) => col.primaryKey()).addColumn("user_code", "text", (col) => col.notNull().unique()).addColumn("scopes", "text", (col) => col.notNull()).addColumn("user_id", "text").addColumn("status", "text", (col) => col.notNull().defaultTo("pending")).addColumn("expires_at", "text", (col) => col.notNull()).addColumn("interval", "integer", (col) => col.notNull().defaultTo(5)).addColumn("created_at", "text", (col) => col.defaultTo(currentTimestamp(db))).execute();
|
|
532
541
|
}
|
|
533
|
-
async function down$
|
|
534
|
-
await db.schema.dropTable("_emdash_device_codes").execute();
|
|
535
|
-
await db.schema.dropTable("_emdash_oauth_tokens").execute();
|
|
536
|
-
await db.schema.dropTable("_emdash_api_tokens").execute();
|
|
542
|
+
async function down$21(db) {
|
|
543
|
+
await db.schema.dropTable("_emdash_device_codes").ifExists().execute();
|
|
544
|
+
await db.schema.dropTable("_emdash_oauth_tokens").ifExists().execute();
|
|
545
|
+
await db.schema.dropTable("_emdash_api_tokens").ifExists().execute();
|
|
537
546
|
}
|
|
538
547
|
|
|
539
548
|
//#endregion
|
|
540
549
|
//#region src/database/migrations/017_authorization_codes.ts
|
|
541
550
|
var _017_authorization_codes_exports = /* @__PURE__ */ __exportAll({
|
|
542
|
-
down: () => down$
|
|
543
|
-
up: () => up$
|
|
551
|
+
down: () => down$20,
|
|
552
|
+
up: () => up$20
|
|
544
553
|
});
|
|
545
554
|
/**
|
|
546
555
|
* Authorization codes for OAuth 2.1 Authorization Code + PKCE flow.
|
|
@@ -550,20 +559,20 @@ var _017_authorization_codes_exports = /* @__PURE__ */ __exportAll({
|
|
|
550
559
|
*
|
|
551
560
|
* Also adds client_id tracking to oauth_tokens for per-client revocation.
|
|
552
561
|
*/
|
|
553
|
-
async function up$
|
|
562
|
+
async function up$20(db) {
|
|
554
563
|
await db.schema.createTable("_emdash_authorization_codes").addColumn("code_hash", "text", (col) => col.primaryKey()).addColumn("client_id", "text", (col) => col.notNull()).addColumn("redirect_uri", "text", (col) => col.notNull()).addColumn("user_id", "text", (col) => col.notNull()).addColumn("scopes", "text", (col) => col.notNull()).addColumn("code_challenge", "text", (col) => col.notNull()).addColumn("code_challenge_method", "text", (col) => col.notNull().defaultTo("S256")).addColumn("resource", "text").addColumn("expires_at", "text", (col) => col.notNull()).addColumn("created_at", "text", (col) => col.defaultTo(currentTimestamp(db))).addForeignKeyConstraint("auth_codes_user_fk", ["user_id"], "users", ["id"], (cb) => cb.onDelete("cascade")).execute();
|
|
555
564
|
await db.schema.createIndex("idx_auth_codes_expires").on("_emdash_authorization_codes").column("expires_at").execute();
|
|
556
565
|
await sql`ALTER TABLE _emdash_oauth_tokens ADD COLUMN client_id TEXT`.execute(db);
|
|
557
566
|
}
|
|
558
|
-
async function down$
|
|
567
|
+
async function down$20(db) {
|
|
559
568
|
await db.schema.dropTable("_emdash_authorization_codes").execute();
|
|
560
569
|
}
|
|
561
570
|
|
|
562
571
|
//#endregion
|
|
563
572
|
//#region src/database/migrations/018_seo.ts
|
|
564
573
|
var _018_seo_exports = /* @__PURE__ */ __exportAll({
|
|
565
|
-
down: () => down$
|
|
566
|
-
up: () => up$
|
|
574
|
+
down: () => down$19,
|
|
575
|
+
up: () => up$19
|
|
567
576
|
});
|
|
568
577
|
/**
|
|
569
578
|
* Migration: SEO support
|
|
@@ -576,7 +585,7 @@ var _018_seo_exports = /* @__PURE__ */ __exportAll({
|
|
|
576
585
|
* need it. The `has_seo` flag controls whether the admin shows SEO fields
|
|
577
586
|
* and whether the collection's content appears in sitemaps.
|
|
578
587
|
*/
|
|
579
|
-
async function up$
|
|
588
|
+
async function up$19(db) {
|
|
580
589
|
await db.schema.createTable("_emdash_seo").addColumn("collection", "text", (col) => col.notNull()).addColumn("content_id", "text", (col) => col.notNull()).addColumn("seo_title", "text").addColumn("seo_description", "text").addColumn("seo_image", "text").addColumn("seo_canonical", "text").addColumn("seo_no_index", "integer", (col) => col.notNull().defaultTo(0)).addColumn("created_at", "text", (col) => col.notNull().defaultTo(currentTimestamp(db))).addColumn("updated_at", "text", (col) => col.notNull().defaultTo(currentTimestamp(db))).addPrimaryKeyConstraint("_emdash_seo_pk", ["collection", "content_id"]).execute();
|
|
581
590
|
await sql`
|
|
582
591
|
CREATE INDEX idx_emdash_seo_collection
|
|
@@ -587,7 +596,7 @@ async function up$17(db) {
|
|
|
587
596
|
ADD COLUMN has_seo INTEGER NOT NULL DEFAULT 0
|
|
588
597
|
`.execute(db);
|
|
589
598
|
}
|
|
590
|
-
async function down$
|
|
599
|
+
async function down$19(db) {
|
|
591
600
|
await sql`DROP TABLE IF EXISTS _emdash_seo`.execute(db);
|
|
592
601
|
await sql`
|
|
593
602
|
ALTER TABLE _emdash_collections
|
|
@@ -598,8 +607,8 @@ async function down$17(db) {
|
|
|
598
607
|
//#endregion
|
|
599
608
|
//#region src/database/migrations/019_i18n.ts
|
|
600
609
|
var _019_i18n_exports = /* @__PURE__ */ __exportAll({
|
|
601
|
-
down: () => down$
|
|
602
|
-
up: () => up$
|
|
610
|
+
down: () => down$18,
|
|
611
|
+
up: () => up$18
|
|
603
612
|
});
|
|
604
613
|
/**
|
|
605
614
|
* Quote an identifier for use in raw SQL. Escapes embedded double-quotes
|
|
@@ -712,7 +721,7 @@ async function upPostgres(db) {
|
|
|
712
721
|
ADD COLUMN translatable INTEGER NOT NULL DEFAULT 1
|
|
713
722
|
`.execute(db);
|
|
714
723
|
}
|
|
715
|
-
async function up$
|
|
724
|
+
async function up$18(db) {
|
|
716
725
|
if (!isSqlite(db)) return upPostgres(db);
|
|
717
726
|
const orphanedTmps = await listTablesLike(db, "ec_%_i18n_tmp");
|
|
718
727
|
for (const tmpName of orphanedTmps) {
|
|
@@ -829,7 +838,7 @@ async function downPostgres(db) {
|
|
|
829
838
|
await sql`ALTER TABLE ${sql.ref(t)} DROP COLUMN translation_group`.execute(db);
|
|
830
839
|
}
|
|
831
840
|
}
|
|
832
|
-
async function down$
|
|
841
|
+
async function down$18(db) {
|
|
833
842
|
if (!isSqlite(db)) return downPostgres(db);
|
|
834
843
|
await sql`
|
|
835
844
|
ALTER TABLE _emdash_fields
|
|
@@ -936,8 +945,8 @@ async function down$16(db) {
|
|
|
936
945
|
//#endregion
|
|
937
946
|
//#region src/database/migrations/020_collection_url_pattern.ts
|
|
938
947
|
var _020_collection_url_pattern_exports = /* @__PURE__ */ __exportAll({
|
|
939
|
-
down: () => down$
|
|
940
|
-
up: () => up$
|
|
948
|
+
down: () => down$17,
|
|
949
|
+
up: () => up$17
|
|
941
950
|
});
|
|
942
951
|
/**
|
|
943
952
|
* Migration: URL pattern for collections
|
|
@@ -946,13 +955,13 @@ var _020_collection_url_pattern_exports = /* @__PURE__ */ __exportAll({
|
|
|
946
955
|
* can declare its own URL structure (e.g. "/{slug}" for pages, "/blog/{slug}"
|
|
947
956
|
* for posts). Used for menu URL resolution, sitemaps, and path-based lookups.
|
|
948
957
|
*/
|
|
949
|
-
async function up$
|
|
958
|
+
async function up$17(db) {
|
|
950
959
|
await sql`
|
|
951
960
|
ALTER TABLE _emdash_collections
|
|
952
961
|
ADD COLUMN url_pattern TEXT
|
|
953
962
|
`.execute(db);
|
|
954
963
|
}
|
|
955
|
-
async function down$
|
|
964
|
+
async function down$17(db) {
|
|
956
965
|
await sql`
|
|
957
966
|
ALTER TABLE _emdash_collections
|
|
958
967
|
DROP COLUMN url_pattern
|
|
@@ -962,8 +971,8 @@ async function down$15(db) {
|
|
|
962
971
|
//#endregion
|
|
963
972
|
//#region src/database/migrations/021_remove_section_categories.ts
|
|
964
973
|
var _021_remove_section_categories_exports = /* @__PURE__ */ __exportAll({
|
|
965
|
-
down: () => down$
|
|
966
|
-
up: () => up$
|
|
974
|
+
down: () => down$16,
|
|
975
|
+
up: () => up$16
|
|
967
976
|
});
|
|
968
977
|
/**
|
|
969
978
|
* Migration: Remove section categories
|
|
@@ -972,12 +981,12 @@ var _021_remove_section_categories_exports = /* @__PURE__ */ __exportAll({
|
|
|
972
981
|
* Rather than building the missing UI for a feature with very little need at this stage,
|
|
973
982
|
* we're removing the feature entirely.
|
|
974
983
|
*/
|
|
975
|
-
async function up$
|
|
984
|
+
async function up$16(db) {
|
|
976
985
|
await db.schema.dropIndex("idx_sections_category").ifExists().execute();
|
|
977
986
|
await db.schema.alterTable("_emdash_sections").dropColumn("category_id").execute();
|
|
978
987
|
await db.schema.dropTable("_emdash_section_categories").execute();
|
|
979
988
|
}
|
|
980
|
-
async function down$
|
|
989
|
+
async function down$16(db) {
|
|
981
990
|
await db.schema.createTable("_emdash_section_categories").addColumn("id", "text", (col) => col.primaryKey()).addColumn("slug", "text", (col) => col.notNull().unique()).addColumn("label", "text", (col) => col.notNull()).addColumn("sort_order", "integer", (col) => col.defaultTo(0)).addColumn("created_at", "text", (col) => col.defaultTo(sql`CURRENT_TIMESTAMP`)).execute();
|
|
982
991
|
await db.schema.alterTable("_emdash_sections").addColumn("category_id", "text", (col) => col.references("_emdash_section_categories.id").onDelete("set null")).execute();
|
|
983
992
|
await db.schema.createIndex("idx_sections_category").on("_emdash_sections").columns(["category_id"]).execute();
|
|
@@ -986,8 +995,8 @@ async function down$14(db) {
|
|
|
986
995
|
//#endregion
|
|
987
996
|
//#region src/database/migrations/022_marketplace_plugin_state.ts
|
|
988
997
|
var _022_marketplace_plugin_state_exports = /* @__PURE__ */ __exportAll({
|
|
989
|
-
down: () => down$
|
|
990
|
-
up: () => up$
|
|
998
|
+
down: () => down$15,
|
|
999
|
+
up: () => up$15
|
|
991
1000
|
});
|
|
992
1001
|
/**
|
|
993
1002
|
* Migration: Add marketplace fields to _plugin_state
|
|
@@ -996,7 +1005,7 @@ var _022_marketplace_plugin_state_exports = /* @__PURE__ */ __exportAll({
|
|
|
996
1005
|
* whether a plugin was installed from config or marketplace,
|
|
997
1006
|
* and which marketplace version is installed.
|
|
998
1007
|
*/
|
|
999
|
-
async function up$
|
|
1008
|
+
async function up$15(db) {
|
|
1000
1009
|
await sql`
|
|
1001
1010
|
ALTER TABLE _plugin_state
|
|
1002
1011
|
ADD COLUMN source TEXT NOT NULL DEFAULT 'config'
|
|
@@ -1011,7 +1020,7 @@ async function up$13(db) {
|
|
|
1011
1020
|
WHERE source = 'marketplace'
|
|
1012
1021
|
`.execute(db);
|
|
1013
1022
|
}
|
|
1014
|
-
async function down$
|
|
1023
|
+
async function down$15(db) {
|
|
1015
1024
|
await sql`
|
|
1016
1025
|
DROP INDEX IF EXISTS idx_plugin_state_source
|
|
1017
1026
|
`.execute(db);
|
|
@@ -1028,8 +1037,8 @@ async function down$13(db) {
|
|
|
1028
1037
|
//#endregion
|
|
1029
1038
|
//#region src/database/migrations/023_plugin_metadata.ts
|
|
1030
1039
|
var _023_plugin_metadata_exports = /* @__PURE__ */ __exportAll({
|
|
1031
|
-
down: () => down$
|
|
1032
|
-
up: () => up$
|
|
1040
|
+
down: () => down$14,
|
|
1041
|
+
up: () => up$14
|
|
1033
1042
|
});
|
|
1034
1043
|
/**
|
|
1035
1044
|
* Migration: Add display metadata to _plugin_state
|
|
@@ -1038,7 +1047,7 @@ var _023_plugin_metadata_exports = /* @__PURE__ */ __exportAll({
|
|
|
1038
1047
|
* so the admin UI can show meaningful info without re-fetching
|
|
1039
1048
|
* from the marketplace on every page load.
|
|
1040
1049
|
*/
|
|
1041
|
-
async function up$
|
|
1050
|
+
async function up$14(db) {
|
|
1042
1051
|
await sql`
|
|
1043
1052
|
ALTER TABLE _plugin_state
|
|
1044
1053
|
ADD COLUMN display_name TEXT
|
|
@@ -1048,7 +1057,7 @@ async function up$12(db) {
|
|
|
1048
1057
|
ADD COLUMN description TEXT
|
|
1049
1058
|
`.execute(db);
|
|
1050
1059
|
}
|
|
1051
|
-
async function down$
|
|
1060
|
+
async function down$14(db) {
|
|
1052
1061
|
await sql`
|
|
1053
1062
|
ALTER TABLE _plugin_state
|
|
1054
1063
|
DROP COLUMN description
|
|
@@ -1062,8 +1071,8 @@ async function down$12(db) {
|
|
|
1062
1071
|
//#endregion
|
|
1063
1072
|
//#region src/database/migrations/024_media_placeholders.ts
|
|
1064
1073
|
var _024_media_placeholders_exports = /* @__PURE__ */ __exportAll({
|
|
1065
|
-
down: () => down$
|
|
1066
|
-
up: () => up$
|
|
1074
|
+
down: () => down$13,
|
|
1075
|
+
up: () => up$13
|
|
1067
1076
|
});
|
|
1068
1077
|
/**
|
|
1069
1078
|
* Migration: Add placeholder columns to media table
|
|
@@ -1071,7 +1080,7 @@ var _024_media_placeholders_exports = /* @__PURE__ */ __exportAll({
|
|
|
1071
1080
|
* Stores blurhash and dominant_color for LQIP (Low Quality Image Placeholder)
|
|
1072
1081
|
* support. Generated at upload time from image pixel data.
|
|
1073
1082
|
*/
|
|
1074
|
-
async function up$
|
|
1083
|
+
async function up$13(db) {
|
|
1075
1084
|
await sql`
|
|
1076
1085
|
ALTER TABLE media
|
|
1077
1086
|
ADD COLUMN blurhash TEXT
|
|
@@ -1081,7 +1090,7 @@ async function up$11(db) {
|
|
|
1081
1090
|
ADD COLUMN dominant_color TEXT
|
|
1082
1091
|
`.execute(db);
|
|
1083
1092
|
}
|
|
1084
|
-
async function down$
|
|
1093
|
+
async function down$13(db) {
|
|
1085
1094
|
await sql`
|
|
1086
1095
|
ALTER TABLE media
|
|
1087
1096
|
DROP COLUMN dominant_color
|
|
@@ -1095,8 +1104,8 @@ async function down$11(db) {
|
|
|
1095
1104
|
//#endregion
|
|
1096
1105
|
//#region src/database/migrations/025_oauth_clients.ts
|
|
1097
1106
|
var _025_oauth_clients_exports = /* @__PURE__ */ __exportAll({
|
|
1098
|
-
down: () => down$
|
|
1099
|
-
up: () => up$
|
|
1107
|
+
down: () => down$12,
|
|
1108
|
+
up: () => up$12
|
|
1100
1109
|
});
|
|
1101
1110
|
/**
|
|
1102
1111
|
* Migration: Create OAuth clients table
|
|
@@ -1107,18 +1116,18 @@ var _025_oauth_clients_exports = /* @__PURE__ */ __exportAll({
|
|
|
1107
1116
|
* Each client has a set of pre-registered redirect URIs (JSON array).
|
|
1108
1117
|
* The authorize endpoint rejects any redirect_uri not in the client's list.
|
|
1109
1118
|
*/
|
|
1110
|
-
async function up$
|
|
1119
|
+
async function up$12(db) {
|
|
1111
1120
|
await db.schema.createTable("_emdash_oauth_clients").addColumn("id", "text", (col) => col.primaryKey()).addColumn("name", "text", (col) => col.notNull()).addColumn("redirect_uris", "text", (col) => col.notNull()).addColumn("scopes", "text").addColumn("created_at", "text", (col) => col.defaultTo(currentTimestamp(db))).addColumn("updated_at", "text", (col) => col.defaultTo(currentTimestamp(db))).execute();
|
|
1112
1121
|
}
|
|
1113
|
-
async function down$
|
|
1122
|
+
async function down$12(db) {
|
|
1114
1123
|
await db.schema.dropTable("_emdash_oauth_clients").execute();
|
|
1115
1124
|
}
|
|
1116
1125
|
|
|
1117
1126
|
//#endregion
|
|
1118
1127
|
//#region src/database/migrations/026_cron_tasks.ts
|
|
1119
1128
|
var _026_cron_tasks_exports = /* @__PURE__ */ __exportAll({
|
|
1120
|
-
down: () => down$
|
|
1121
|
-
up: () => up$
|
|
1129
|
+
down: () => down$11,
|
|
1130
|
+
up: () => up$11
|
|
1122
1131
|
});
|
|
1123
1132
|
/**
|
|
1124
1133
|
* Migration: Create cron tasks table for plugin scheduled tasks.
|
|
@@ -1129,7 +1138,7 @@ var _026_cron_tasks_exports = /* @__PURE__ */ __exportAll({
|
|
|
1129
1138
|
* The `next_run_at` + `status` + `enabled` index drives the "find overdue
|
|
1130
1139
|
* tasks" query used by CronExecutor.tick().
|
|
1131
1140
|
*/
|
|
1132
|
-
async function up$
|
|
1141
|
+
async function up$11(db) {
|
|
1133
1142
|
await db.schema.createTable("_emdash_cron_tasks").addColumn("id", "text", (col) => col.primaryKey()).addColumn("plugin_id", "text", (col) => col.notNull()).addColumn("task_name", "text", (col) => col.notNull()).addColumn("schedule", "text", (col) => col.notNull()).addColumn("is_oneshot", "integer", (col) => col.notNull().defaultTo(0)).addColumn("data", "text").addColumn("next_run_at", "text", (col) => col.notNull()).addColumn("last_run_at", "text").addColumn("status", "text", (col) => col.notNull().defaultTo("idle")).addColumn("locked_at", "text").addColumn("enabled", "integer", (col) => col.notNull().defaultTo(1)).addColumn("created_at", "text", (col) => col.defaultTo(currentTimestamp(db))).addUniqueConstraint("uq_cron_tasks_plugin_task", ["plugin_id", "task_name"]).execute();
|
|
1134
1143
|
await db.schema.createIndex("idx_cron_tasks_due").on("_emdash_cron_tasks").columns([
|
|
1135
1144
|
"enabled",
|
|
@@ -1138,17 +1147,17 @@ async function up$9(db) {
|
|
|
1138
1147
|
]).execute();
|
|
1139
1148
|
await db.schema.createIndex("idx_cron_tasks_plugin").on("_emdash_cron_tasks").column("plugin_id").execute();
|
|
1140
1149
|
}
|
|
1141
|
-
async function down$
|
|
1150
|
+
async function down$11(db) {
|
|
1142
1151
|
await db.schema.dropTable("_emdash_cron_tasks").execute();
|
|
1143
1152
|
}
|
|
1144
1153
|
|
|
1145
1154
|
//#endregion
|
|
1146
1155
|
//#region src/database/migrations/027_comments.ts
|
|
1147
1156
|
var _027_comments_exports = /* @__PURE__ */ __exportAll({
|
|
1148
|
-
down: () => down$
|
|
1149
|
-
up: () => up$
|
|
1157
|
+
down: () => down$10,
|
|
1158
|
+
up: () => up$10
|
|
1150
1159
|
});
|
|
1151
|
-
async function up$
|
|
1160
|
+
async function up$10(db) {
|
|
1152
1161
|
await db.schema.createTable("_emdash_comments").addColumn("id", "text", (col) => col.primaryKey()).addColumn("collection", "text", (col) => col.notNull()).addColumn("content_id", "text", (col) => col.notNull()).addColumn("parent_id", "text", (col) => col.references("_emdash_comments.id").onDelete("cascade")).addColumn("author_name", "text", (col) => col.notNull()).addColumn("author_email", "text", (col) => col.notNull()).addColumn("author_url", "text").addColumn("author_user_id", "text", (col) => col.references("users.id").onDelete("set null")).addColumn("body", "text", (col) => col.notNull()).addColumn("status", "text", (col) => col.notNull().defaultTo("pending")).addColumn("ip_hash", "text").addColumn("user_agent", "text").addColumn("moderation_metadata", "text").addColumn("created_at", "text", (col) => col.defaultTo(currentTimestamp(db))).addColumn("updated_at", "text", (col) => col.defaultTo(currentTimestamp(db))).execute();
|
|
1153
1162
|
await db.schema.createIndex("idx_comments_content").on("_emdash_comments").columns([
|
|
1154
1163
|
"collection",
|
|
@@ -1164,30 +1173,30 @@ async function up$8(db) {
|
|
|
1164
1173
|
await db.schema.alterTable("_emdash_collections").addColumn("comments_closed_after_days", "integer", (col) => col.defaultTo(90)).execute();
|
|
1165
1174
|
await db.schema.alterTable("_emdash_collections").addColumn("comments_auto_approve_users", "integer", (col) => col.defaultTo(1)).execute();
|
|
1166
1175
|
}
|
|
1167
|
-
async function down$
|
|
1176
|
+
async function down$10(db) {
|
|
1168
1177
|
await db.schema.dropTable("_emdash_comments").execute();
|
|
1169
1178
|
}
|
|
1170
1179
|
|
|
1171
1180
|
//#endregion
|
|
1172
1181
|
//#region src/database/migrations/028_drop_author_url.ts
|
|
1173
1182
|
var _028_drop_author_url_exports = /* @__PURE__ */ __exportAll({
|
|
1174
|
-
down: () => down$
|
|
1175
|
-
up: () => up$
|
|
1183
|
+
down: () => down$9,
|
|
1184
|
+
up: () => up$9
|
|
1176
1185
|
});
|
|
1177
|
-
async function up$
|
|
1186
|
+
async function up$9(db) {
|
|
1178
1187
|
await sql`ALTER TABLE _emdash_comments DROP COLUMN author_url`.execute(db);
|
|
1179
1188
|
}
|
|
1180
|
-
async function down$
|
|
1189
|
+
async function down$9(db) {
|
|
1181
1190
|
await db.schema.alterTable("_emdash_comments").addColumn("author_url", "text").execute();
|
|
1182
1191
|
}
|
|
1183
1192
|
|
|
1184
1193
|
//#endregion
|
|
1185
1194
|
//#region src/database/migrations/029_redirects.ts
|
|
1186
1195
|
var _029_redirects_exports = /* @__PURE__ */ __exportAll({
|
|
1187
|
-
down: () => down$
|
|
1188
|
-
up: () => up$
|
|
1196
|
+
down: () => down$8,
|
|
1197
|
+
up: () => up$8
|
|
1189
1198
|
});
|
|
1190
|
-
async function up$
|
|
1199
|
+
async function up$8(db) {
|
|
1191
1200
|
await db.schema.createTable("_emdash_redirects").addColumn("id", "text", (col) => col.primaryKey()).addColumn("source", "text", (col) => col.notNull()).addColumn("destination", "text", (col) => col.notNull()).addColumn("type", "integer", (col) => col.notNull().defaultTo(301)).addColumn("is_pattern", "integer", (col) => col.notNull().defaultTo(0)).addColumn("enabled", "integer", (col) => col.notNull().defaultTo(1)).addColumn("hits", "integer", (col) => col.notNull().defaultTo(0)).addColumn("last_hit_at", "text").addColumn("group_name", "text").addColumn("auto", "integer", (col) => col.notNull().defaultTo(0)).addColumn("created_at", "text", (col) => col.defaultTo(currentTimestamp(db))).addColumn("updated_at", "text", (col) => col.defaultTo(currentTimestamp(db))).execute();
|
|
1192
1201
|
await db.schema.createIndex("idx_redirects_source").on("_emdash_redirects").column("source").execute();
|
|
1193
1202
|
await db.schema.createIndex("idx_redirects_enabled").on("_emdash_redirects").column("enabled").execute();
|
|
@@ -1196,7 +1205,7 @@ async function up$6(db) {
|
|
|
1196
1205
|
await db.schema.createIndex("idx_404_log_path").on("_emdash_404_log").column("path").execute();
|
|
1197
1206
|
await db.schema.createIndex("idx_404_log_created").on("_emdash_404_log").column("created_at").execute();
|
|
1198
1207
|
}
|
|
1199
|
-
async function down$
|
|
1208
|
+
async function down$8(db) {
|
|
1200
1209
|
await db.schema.dropTable("_emdash_404_log").execute();
|
|
1201
1210
|
await db.schema.dropTable("_emdash_redirects").execute();
|
|
1202
1211
|
}
|
|
@@ -1204,8 +1213,8 @@ async function down$6(db) {
|
|
|
1204
1213
|
//#endregion
|
|
1205
1214
|
//#region src/database/migrations/030_widen_scheduled_index.ts
|
|
1206
1215
|
var _030_widen_scheduled_index_exports = /* @__PURE__ */ __exportAll({
|
|
1207
|
-
down: () => down$
|
|
1208
|
-
up: () => up$
|
|
1216
|
+
down: () => down$7,
|
|
1217
|
+
up: () => up$7
|
|
1209
1218
|
});
|
|
1210
1219
|
/**
|
|
1211
1220
|
* Migration: Widen scheduled publishing index
|
|
@@ -1214,7 +1223,7 @@ var _030_widen_scheduled_index_exports = /* @__PURE__ */ __exportAll({
|
|
|
1214
1223
|
* Published posts can now have scheduled draft changes, so widen the
|
|
1215
1224
|
* index to cover all rows where scheduled_at IS NOT NULL.
|
|
1216
1225
|
*/
|
|
1217
|
-
async function up$
|
|
1226
|
+
async function up$7(db) {
|
|
1218
1227
|
const tableNames = await listTablesLike(db, "ec_%");
|
|
1219
1228
|
for (const tableName of tableNames) {
|
|
1220
1229
|
const table = { name: tableName };
|
|
@@ -1228,7 +1237,7 @@ async function up$5(db) {
|
|
|
1228
1237
|
`.execute(db);
|
|
1229
1238
|
}
|
|
1230
1239
|
}
|
|
1231
|
-
async function down$
|
|
1240
|
+
async function down$7(db) {
|
|
1232
1241
|
const tableNames = await listTablesLike(db, "ec_%");
|
|
1233
1242
|
for (const tableName of tableNames) {
|
|
1234
1243
|
const table = { name: tableName };
|
|
@@ -1246,10 +1255,10 @@ async function down$5(db) {
|
|
|
1246
1255
|
//#endregion
|
|
1247
1256
|
//#region src/database/migrations/031_bylines.ts
|
|
1248
1257
|
var _031_bylines_exports = /* @__PURE__ */ __exportAll({
|
|
1249
|
-
down: () => down$
|
|
1250
|
-
up: () => up$
|
|
1258
|
+
down: () => down$6,
|
|
1259
|
+
up: () => up$6
|
|
1251
1260
|
});
|
|
1252
|
-
async function up$
|
|
1261
|
+
async function up$6(db) {
|
|
1253
1262
|
await db.schema.createTable("_emdash_bylines").addColumn("id", "text", (col) => col.primaryKey()).addColumn("slug", "text", (col) => col.notNull().unique()).addColumn("display_name", "text", (col) => col.notNull()).addColumn("bio", "text").addColumn("avatar_media_id", "text", (col) => col.references("media.id").onDelete("set null")).addColumn("website_url", "text").addColumn("user_id", "text", (col) => col.references("users.id").onDelete("set null")).addColumn("is_guest", "integer", (col) => col.notNull().defaultTo(0)).addColumn("created_at", "text", (col) => col.defaultTo(currentTimestamp(db))).addColumn("updated_at", "text", (col) => col.defaultTo(currentTimestamp(db))).execute();
|
|
1254
1263
|
await sql`
|
|
1255
1264
|
CREATE UNIQUE INDEX ${sql.ref("idx_bylines_user_id_unique")}
|
|
@@ -1281,7 +1290,7 @@ async function up$4(db) {
|
|
|
1281
1290
|
`.execute(db);
|
|
1282
1291
|
}
|
|
1283
1292
|
}
|
|
1284
|
-
async function down$
|
|
1293
|
+
async function down$6(db) {
|
|
1285
1294
|
const tableNames = await listTablesLike(db, "ec_%");
|
|
1286
1295
|
for (const tableName of tableNames) {
|
|
1287
1296
|
await sql`
|
|
@@ -1299,8 +1308,8 @@ async function down$4(db) {
|
|
|
1299
1308
|
//#endregion
|
|
1300
1309
|
//#region src/database/migrations/032_rate_limits.ts
|
|
1301
1310
|
var _032_rate_limits_exports = /* @__PURE__ */ __exportAll({
|
|
1302
|
-
down: () => down$
|
|
1303
|
-
up: () => up$
|
|
1311
|
+
down: () => down$5,
|
|
1312
|
+
up: () => up$5
|
|
1304
1313
|
});
|
|
1305
1314
|
/**
|
|
1306
1315
|
* Migration: Rate limits table + device code polling tracking.
|
|
@@ -1311,12 +1320,12 @@ var _032_rate_limits_exports = /* @__PURE__ */ __exportAll({
|
|
|
1311
1320
|
* 2. Add last_polled_at column to _emdash_device_codes for
|
|
1312
1321
|
* RFC 8628 slow_down enforcement.
|
|
1313
1322
|
*/
|
|
1314
|
-
async function up$
|
|
1323
|
+
async function up$5(db) {
|
|
1315
1324
|
await db.schema.createTable("_emdash_rate_limits").addColumn("key", "text", (col) => col.notNull()).addColumn("window", "text", (col) => col.notNull()).addColumn("count", "integer", (col) => col.notNull().defaultTo(1)).addPrimaryKeyConstraint("pk_rate_limits", ["key", "window"]).execute();
|
|
1316
1325
|
await db.schema.createIndex("idx_rate_limits_window").on("_emdash_rate_limits").column("window").execute();
|
|
1317
1326
|
await db.schema.alterTable("_emdash_device_codes").addColumn("last_polled_at", "text").execute();
|
|
1318
1327
|
}
|
|
1319
|
-
async function down$
|
|
1328
|
+
async function down$5(db) {
|
|
1320
1329
|
await db.schema.dropTable("_emdash_rate_limits").execute();
|
|
1321
1330
|
await db.schema.alterTable("_emdash_device_codes").dropColumn("last_polled_at").execute();
|
|
1322
1331
|
}
|
|
@@ -1324,8 +1333,8 @@ async function down$3(db) {
|
|
|
1324
1333
|
//#endregion
|
|
1325
1334
|
//#region src/database/migrations/033_optimize_content_indexes.ts
|
|
1326
1335
|
var _033_optimize_content_indexes_exports = /* @__PURE__ */ __exportAll({
|
|
1327
|
-
down: () => down$
|
|
1328
|
-
up: () => up$
|
|
1336
|
+
down: () => down$4,
|
|
1337
|
+
up: () => up$4
|
|
1329
1338
|
});
|
|
1330
1339
|
/**
|
|
1331
1340
|
* Migration: Optimize content table indexes for D1 performance
|
|
@@ -1338,7 +1347,7 @@ var _033_optimize_content_indexes_exports = /* @__PURE__ */ __exportAll({
|
|
|
1338
1347
|
*
|
|
1339
1348
|
* Impact: Reduces D1 row reads by 90%+ for admin panel operations.
|
|
1340
1349
|
*/
|
|
1341
|
-
async function up$
|
|
1350
|
+
async function up$4(db) {
|
|
1342
1351
|
const tableNames = await listTablesLike(db, "ec_%");
|
|
1343
1352
|
for (const tableName of tableNames) {
|
|
1344
1353
|
const table = { name: tableName };
|
|
@@ -1380,7 +1389,7 @@ async function up$2(db) {
|
|
|
1380
1389
|
WHERE status = 'trash'
|
|
1381
1390
|
`.execute(db);
|
|
1382
1391
|
}
|
|
1383
|
-
async function down$
|
|
1392
|
+
async function down$4(db) {
|
|
1384
1393
|
const tableNames = await listTablesLike(db, "ec_%");
|
|
1385
1394
|
for (const tableName of tableNames) {
|
|
1386
1395
|
const table = { name: tableName };
|
|
@@ -1413,10 +1422,10 @@ async function down$2(db) {
|
|
|
1413
1422
|
//#endregion
|
|
1414
1423
|
//#region src/database/migrations/034_published_at_index.ts
|
|
1415
1424
|
var _034_published_at_index_exports = /* @__PURE__ */ __exportAll({
|
|
1416
|
-
down: () => down$
|
|
1417
|
-
up: () => up$
|
|
1425
|
+
down: () => down$3,
|
|
1426
|
+
up: () => up$3
|
|
1418
1427
|
});
|
|
1419
|
-
async function up$
|
|
1428
|
+
async function up$3(db) {
|
|
1420
1429
|
const tableNames = await listTablesLike(db, "ec_%");
|
|
1421
1430
|
for (const tableName of tableNames) {
|
|
1422
1431
|
const table = { name: tableName };
|
|
@@ -1426,7 +1435,7 @@ async function up$1(db) {
|
|
|
1426
1435
|
`.execute(db);
|
|
1427
1436
|
}
|
|
1428
1437
|
}
|
|
1429
|
-
async function down$
|
|
1438
|
+
async function down$3(db) {
|
|
1430
1439
|
const tableNames = await listTablesLike(db, "ec_%");
|
|
1431
1440
|
for (const tableName of tableNames) {
|
|
1432
1441
|
const table = { name: tableName };
|
|
@@ -1437,8 +1446,8 @@ async function down$1(db) {
|
|
|
1437
1446
|
//#endregion
|
|
1438
1447
|
//#region src/database/migrations/035_bounded_404_log.ts
|
|
1439
1448
|
var _035_bounded_404_log_exports = /* @__PURE__ */ __exportAll({
|
|
1440
|
-
down: () => down,
|
|
1441
|
-
up: () => up
|
|
1449
|
+
down: () => down$2,
|
|
1450
|
+
up: () => up$2
|
|
1442
1451
|
});
|
|
1443
1452
|
/**
|
|
1444
1453
|
* Migration: Bounded 404 logging
|
|
@@ -1456,7 +1465,7 @@ var _035_bounded_404_log_exports = /* @__PURE__ */ __exportAll({
|
|
|
1456
1465
|
* path and summing hits
|
|
1457
1466
|
* - Adds a UNIQUE index on `path` so upsert semantics work
|
|
1458
1467
|
*/
|
|
1459
|
-
async function up(db) {
|
|
1468
|
+
async function up$2(db) {
|
|
1460
1469
|
const hitsExists = await columnExists(db, "_emdash_404_log", "hits");
|
|
1461
1470
|
if (!hitsExists) await db.schema.alterTable("_emdash_404_log").addColumn("hits", "integer", (col) => col.notNull().defaultTo(1)).execute();
|
|
1462
1471
|
if (!await columnExists(db, "_emdash_404_log", "last_seen_at")) await db.schema.alterTable("_emdash_404_log").addColumn("last_seen_at", "text").execute();
|
|
@@ -1505,7 +1514,7 @@ async function up(db) {
|
|
|
1505
1514
|
await db.schema.dropIndex("idx_404_log_path").ifExists().execute();
|
|
1506
1515
|
await db.schema.createIndex("idx_404_log_last_seen").ifNotExists().on("_emdash_404_log").column("last_seen_at").execute();
|
|
1507
1516
|
}
|
|
1508
|
-
async function down(db) {
|
|
1517
|
+
async function down$2(db) {
|
|
1509
1518
|
await db.schema.dropIndex("idx_404_log_last_seen").ifExists().execute();
|
|
1510
1519
|
await db.schema.dropIndex("idx_404_log_path_unique").ifExists().execute();
|
|
1511
1520
|
await db.schema.createIndex("idx_404_log_path").ifNotExists().on("_emdash_404_log").column("path").execute();
|
|
@@ -1513,6 +1522,312 @@ async function down(db) {
|
|
|
1513
1522
|
await db.schema.alterTable("_emdash_404_log").dropColumn("hits").execute();
|
|
1514
1523
|
}
|
|
1515
1524
|
|
|
1525
|
+
//#endregion
|
|
1526
|
+
//#region src/database/migrations/036_i18n_menus_and_taxonomies.ts
|
|
1527
|
+
var _036_i18n_menus_and_taxonomies_exports = /* @__PURE__ */ __exportAll({
|
|
1528
|
+
down: () => down$1,
|
|
1529
|
+
up: () => up$1
|
|
1530
|
+
});
|
|
1531
|
+
/**
|
|
1532
|
+
* i18n for menus + taxonomies. Adds `locale` + `translation_group` to system
|
|
1533
|
+
* tables and stores translation_groups (not row ids) in
|
|
1534
|
+
* `_emdash_menu_items.reference_id` and `content_taxonomies.taxonomy_id`.
|
|
1535
|
+
* Backfill locale and column DEFAULTs use the site's configured defaultLocale.
|
|
1536
|
+
*/
|
|
1537
|
+
function getDefaultLocale() {
|
|
1538
|
+
return getI18nConfig()?.defaultLocale ?? "en";
|
|
1539
|
+
}
|
|
1540
|
+
async function up$1(db) {
|
|
1541
|
+
const defaultLocale = getDefaultLocale();
|
|
1542
|
+
if (isSqlite(db)) {
|
|
1543
|
+
await sql.raw(`PRAGMA foreign_keys = OFF`).execute(db);
|
|
1544
|
+
try {
|
|
1545
|
+
await rebuildMenus(db, defaultLocale);
|
|
1546
|
+
await addItemColumns(db, defaultLocale);
|
|
1547
|
+
await rebuildTaxonomies(db, defaultLocale);
|
|
1548
|
+
await rebuildTaxonomyDefs(db, defaultLocale);
|
|
1549
|
+
await rebuildContentTaxonomies(db);
|
|
1550
|
+
await remapMenuItemRefs(db);
|
|
1551
|
+
} finally {
|
|
1552
|
+
await sql.raw(`PRAGMA foreign_keys = ON`).execute(db);
|
|
1553
|
+
}
|
|
1554
|
+
return;
|
|
1555
|
+
}
|
|
1556
|
+
await pgWiden(db, "_emdash_menus", ["name"], ["name", "locale"], defaultLocale);
|
|
1557
|
+
await pgWiden(db, "_emdash_menu_items", null, null, defaultLocale);
|
|
1558
|
+
await pgWiden(db, "taxonomies", ["name", "slug"], [
|
|
1559
|
+
"name",
|
|
1560
|
+
"slug",
|
|
1561
|
+
"locale"
|
|
1562
|
+
], defaultLocale);
|
|
1563
|
+
await pgWiden(db, "_emdash_taxonomy_defs", ["name"], ["name", "locale"], defaultLocale);
|
|
1564
|
+
await pgRemapContentTaxonomies(db);
|
|
1565
|
+
await remapMenuItemRefs(db);
|
|
1566
|
+
}
|
|
1567
|
+
async function rebuildMenus(db, defaultLocale) {
|
|
1568
|
+
if (await hasColumn(db, "_emdash_menus", "locale")) return;
|
|
1569
|
+
await sql.raw(`DROP TABLE IF EXISTS "_emdash_menus_new"`).execute(db);
|
|
1570
|
+
await db.schema.createTable("_emdash_menus_new").addColumn("id", "text", (c) => c.primaryKey()).addColumn("name", "text", (c) => c.notNull()).addColumn("label", "text", (c) => c.notNull()).addColumn("created_at", "text", (c) => c.defaultTo(currentTimestamp(db))).addColumn("updated_at", "text", (c) => c.defaultTo(currentTimestamp(db))).addColumn("locale", "text", (c) => c.notNull().defaultTo(defaultLocale)).addColumn("translation_group", "text").addUniqueConstraint("_emdash_menus_name_locale_unique", ["name", "locale"]).execute();
|
|
1571
|
+
await sql`
|
|
1572
|
+
INSERT INTO _emdash_menus_new (id, name, label, created_at, updated_at, locale, translation_group)
|
|
1573
|
+
SELECT id, name, label, created_at, updated_at, ${defaultLocale}, id FROM _emdash_menus
|
|
1574
|
+
`.execute(db);
|
|
1575
|
+
await db.schema.dropTable("_emdash_menus").execute();
|
|
1576
|
+
await sql`ALTER TABLE _emdash_menus_new RENAME TO _emdash_menus`.execute(db);
|
|
1577
|
+
await db.schema.createIndex("idx__emdash_menus_locale").on("_emdash_menus").column("locale").execute();
|
|
1578
|
+
await db.schema.createIndex("idx__emdash_menus_translation_group").on("_emdash_menus").column("translation_group").execute();
|
|
1579
|
+
}
|
|
1580
|
+
async function addItemColumns(db, defaultLocale) {
|
|
1581
|
+
if (await hasColumn(db, "_emdash_menu_items", "locale")) return;
|
|
1582
|
+
await db.schema.alterTable("_emdash_menu_items").addColumn("locale", "text", (c) => c.notNull().defaultTo(defaultLocale)).execute();
|
|
1583
|
+
await db.schema.alterTable("_emdash_menu_items").addColumn("translation_group", "text").execute();
|
|
1584
|
+
await sql`UPDATE _emdash_menu_items SET translation_group = id`.execute(db);
|
|
1585
|
+
await db.schema.createIndex("idx__emdash_menu_items_locale").on("_emdash_menu_items").column("locale").execute();
|
|
1586
|
+
await db.schema.createIndex("idx__emdash_menu_items_translation_group").on("_emdash_menu_items").column("translation_group").execute();
|
|
1587
|
+
}
|
|
1588
|
+
async function rebuildTaxonomies(db, defaultLocale) {
|
|
1589
|
+
if (await hasColumn(db, "taxonomies", "locale")) return;
|
|
1590
|
+
await sql.raw(`DROP TABLE IF EXISTS "taxonomies_new"`).execute(db);
|
|
1591
|
+
await sql`DROP INDEX IF EXISTS idx_taxonomies_name`.execute(db);
|
|
1592
|
+
await db.schema.createTable("taxonomies_new").addColumn("id", "text", (c) => c.primaryKey()).addColumn("name", "text", (c) => c.notNull()).addColumn("slug", "text", (c) => c.notNull()).addColumn("label", "text", (c) => c.notNull()).addColumn("parent_id", "text").addColumn("data", "text").addColumn("locale", "text", (c) => c.notNull().defaultTo(defaultLocale)).addColumn("translation_group", "text").addUniqueConstraint("taxonomies_name_slug_locale_unique", [
|
|
1593
|
+
"name",
|
|
1594
|
+
"slug",
|
|
1595
|
+
"locale"
|
|
1596
|
+
]).addForeignKeyConstraint("taxonomies_parent_fk", ["parent_id"], "taxonomies", ["id"], (cb) => cb.onDelete("set null")).execute();
|
|
1597
|
+
await sql`
|
|
1598
|
+
INSERT INTO taxonomies_new (id, name, slug, label, parent_id, data, locale, translation_group)
|
|
1599
|
+
SELECT id, name, slug, label, parent_id, data, ${defaultLocale}, id FROM taxonomies
|
|
1600
|
+
`.execute(db);
|
|
1601
|
+
await db.schema.dropTable("taxonomies").execute();
|
|
1602
|
+
await sql`ALTER TABLE taxonomies_new RENAME TO taxonomies`.execute(db);
|
|
1603
|
+
await db.schema.createIndex("idx_taxonomies_name").on("taxonomies").column("name").execute();
|
|
1604
|
+
await db.schema.createIndex("idx_taxonomies_locale").on("taxonomies").column("locale").execute();
|
|
1605
|
+
await db.schema.createIndex("idx_taxonomies_translation_group").on("taxonomies").column("translation_group").execute();
|
|
1606
|
+
}
|
|
1607
|
+
async function rebuildTaxonomyDefs(db, defaultLocale) {
|
|
1608
|
+
if (await hasColumn(db, "_emdash_taxonomy_defs", "locale")) return;
|
|
1609
|
+
await sql.raw(`DROP TABLE IF EXISTS "_emdash_taxonomy_defs_new"`).execute(db);
|
|
1610
|
+
await db.schema.createTable("_emdash_taxonomy_defs_new").addColumn("id", "text", (c) => c.primaryKey()).addColumn("name", "text", (c) => c.notNull()).addColumn("label", "text", (c) => c.notNull()).addColumn("label_singular", "text").addColumn("hierarchical", "integer", (c) => c.defaultTo(0)).addColumn("collections", "text").addColumn("created_at", "text", (c) => c.defaultTo(currentTimestamp(db))).addColumn("locale", "text", (c) => c.notNull().defaultTo(defaultLocale)).addColumn("translation_group", "text").addUniqueConstraint("_emdash_taxonomy_defs_name_locale_unique", ["name", "locale"]).execute();
|
|
1611
|
+
await sql`
|
|
1612
|
+
INSERT INTO _emdash_taxonomy_defs_new
|
|
1613
|
+
(id, name, label, label_singular, hierarchical, collections, created_at, locale, translation_group)
|
|
1614
|
+
SELECT id, name, label, label_singular, hierarchical, collections, created_at, ${defaultLocale}, id
|
|
1615
|
+
FROM _emdash_taxonomy_defs
|
|
1616
|
+
`.execute(db);
|
|
1617
|
+
await db.schema.dropTable("_emdash_taxonomy_defs").execute();
|
|
1618
|
+
await sql`ALTER TABLE _emdash_taxonomy_defs_new RENAME TO _emdash_taxonomy_defs`.execute(db);
|
|
1619
|
+
await db.schema.createIndex("idx__emdash_taxonomy_defs_locale").on("_emdash_taxonomy_defs").column("locale").execute();
|
|
1620
|
+
await db.schema.createIndex("idx__emdash_taxonomy_defs_translation_group").on("_emdash_taxonomy_defs").column("translation_group").execute();
|
|
1621
|
+
}
|
|
1622
|
+
async function rebuildContentTaxonomies(db) {
|
|
1623
|
+
if ((await sql`PRAGMA foreign_key_list(content_taxonomies)`.execute(db)).rows.length === 0) return;
|
|
1624
|
+
await sql.raw(`DROP TABLE IF EXISTS "content_taxonomies_new"`).execute(db);
|
|
1625
|
+
await db.schema.createTable("content_taxonomies_new").addColumn("collection", "text", (c) => c.notNull()).addColumn("entry_id", "text", (c) => c.notNull()).addColumn("taxonomy_id", "text", (c) => c.notNull()).addPrimaryKeyConstraint("content_taxonomies_pk", [
|
|
1626
|
+
"collection",
|
|
1627
|
+
"entry_id",
|
|
1628
|
+
"taxonomy_id"
|
|
1629
|
+
]).execute();
|
|
1630
|
+
await sql`
|
|
1631
|
+
INSERT OR IGNORE INTO content_taxonomies_new (collection, entry_id, taxonomy_id)
|
|
1632
|
+
SELECT ct.collection, ct.entry_id, COALESCE(
|
|
1633
|
+
(SELECT t.translation_group FROM taxonomies t WHERE t.id = ct.taxonomy_id),
|
|
1634
|
+
ct.taxonomy_id
|
|
1635
|
+
)
|
|
1636
|
+
FROM content_taxonomies ct
|
|
1637
|
+
`.execute(db);
|
|
1638
|
+
await db.schema.dropTable("content_taxonomies").execute();
|
|
1639
|
+
await sql`ALTER TABLE content_taxonomies_new RENAME TO content_taxonomies`.execute(db);
|
|
1640
|
+
}
|
|
1641
|
+
async function remapMenuItemRefs(db) {
|
|
1642
|
+
const collections = await sql`SELECT slug FROM _emdash_collections`.execute(db);
|
|
1643
|
+
for (const { slug } of collections.rows) {
|
|
1644
|
+
validateIdentifier(slug, "collection slug");
|
|
1645
|
+
const ec = sql.ref(`ec_${slug}`);
|
|
1646
|
+
await sql`
|
|
1647
|
+
UPDATE _emdash_menu_items SET reference_id = (
|
|
1648
|
+
SELECT translation_group FROM ${ec} WHERE ${ec}.id = _emdash_menu_items.reference_id
|
|
1649
|
+
)
|
|
1650
|
+
WHERE reference_collection = ${slug} AND reference_id IS NOT NULL
|
|
1651
|
+
AND EXISTS (SELECT 1 FROM ${ec} WHERE ${ec}.id = _emdash_menu_items.reference_id)
|
|
1652
|
+
`.execute(db);
|
|
1653
|
+
}
|
|
1654
|
+
await sql`
|
|
1655
|
+
UPDATE _emdash_menu_items SET reference_id = (
|
|
1656
|
+
SELECT translation_group FROM taxonomies WHERE taxonomies.id = _emdash_menu_items.reference_id
|
|
1657
|
+
)
|
|
1658
|
+
WHERE type = 'taxonomy' AND reference_id IS NOT NULL
|
|
1659
|
+
AND EXISTS (SELECT 1 FROM taxonomies WHERE taxonomies.id = _emdash_menu_items.reference_id)
|
|
1660
|
+
`.execute(db);
|
|
1661
|
+
}
|
|
1662
|
+
async function pgWiden(db, table, oldCols, newCols, defaultLocale) {
|
|
1663
|
+
validateSystemIdent(table);
|
|
1664
|
+
const ref = sql.ref(table);
|
|
1665
|
+
await sql`ALTER TABLE ${ref} ADD COLUMN IF NOT EXISTS locale TEXT NOT NULL DEFAULT ${sql.lit(defaultLocale)}`.execute(db);
|
|
1666
|
+
await sql`ALTER TABLE ${ref} ADD COLUMN IF NOT EXISTS translation_group TEXT`.execute(db);
|
|
1667
|
+
await sql`UPDATE ${ref} SET translation_group = id WHERE translation_group IS NULL`.execute(db);
|
|
1668
|
+
await sql`CREATE INDEX IF NOT EXISTS ${sql.ref(`idx_${table}_locale`)} ON ${ref} (locale)`.execute(db);
|
|
1669
|
+
await sql`
|
|
1670
|
+
CREATE INDEX IF NOT EXISTS ${sql.ref(`idx_${table}_translation_group`)} ON ${ref} (translation_group)
|
|
1671
|
+
`.execute(db);
|
|
1672
|
+
if (!oldCols || !newCols) return;
|
|
1673
|
+
for (const c of [...oldCols, ...newCols]) validateSystemIdent(c);
|
|
1674
|
+
const cons = await sql`
|
|
1675
|
+
SELECT conname FROM pg_constraint c
|
|
1676
|
+
WHERE c.conrelid = ${table}::regclass AND c.contype = 'u'
|
|
1677
|
+
AND array_length(c.conkey, 1) = ${oldCols.length}
|
|
1678
|
+
AND (
|
|
1679
|
+
SELECT array_agg(a.attname ORDER BY pos.ord)
|
|
1680
|
+
FROM unnest(c.conkey) WITH ORDINALITY AS pos(attnum, ord)
|
|
1681
|
+
JOIN pg_attribute a ON a.attrelid = c.conrelid AND a.attnum = pos.attnum
|
|
1682
|
+
)::text[] = ${oldCols}::text[]
|
|
1683
|
+
`.execute(db);
|
|
1684
|
+
for (const c of cons.rows) await sql`ALTER TABLE ${ref} DROP CONSTRAINT ${sql.ref(c.conname)}`.execute(db);
|
|
1685
|
+
const cols = sql.join(newCols.map((c) => sql.ref(c)), sql`, `);
|
|
1686
|
+
await sql`
|
|
1687
|
+
ALTER TABLE ${ref}
|
|
1688
|
+
ADD CONSTRAINT ${sql.ref(`${table}_${newCols.join("_")}_unique`)} UNIQUE (${cols})
|
|
1689
|
+
`.execute(db);
|
|
1690
|
+
}
|
|
1691
|
+
async function pgRemapContentTaxonomies(db) {
|
|
1692
|
+
const fks = await sql`
|
|
1693
|
+
SELECT conname FROM pg_constraint
|
|
1694
|
+
WHERE conrelid = 'content_taxonomies'::regclass AND contype = 'f'
|
|
1695
|
+
`.execute(db);
|
|
1696
|
+
for (const c of fks.rows) await sql`ALTER TABLE content_taxonomies DROP CONSTRAINT ${sql.ref(c.conname)}`.execute(db);
|
|
1697
|
+
await sql`
|
|
1698
|
+
UPDATE content_taxonomies SET taxonomy_id = t.translation_group
|
|
1699
|
+
FROM taxonomies t WHERE t.id = content_taxonomies.taxonomy_id
|
|
1700
|
+
`.execute(db);
|
|
1701
|
+
}
|
|
1702
|
+
async function hasColumn(db, table, column) {
|
|
1703
|
+
return (await sql`PRAGMA table_info(${sql.ref(table)})`.execute(db)).rows.some((r) => r.name === column);
|
|
1704
|
+
}
|
|
1705
|
+
const SYSTEM_IDENT = /^[_a-z][a-z0-9_]*$/;
|
|
1706
|
+
function validateSystemIdent(name) {
|
|
1707
|
+
if (!SYSTEM_IDENT.test(name)) throw new Error(`Invalid identifier: "${name}"`);
|
|
1708
|
+
}
|
|
1709
|
+
/**
|
|
1710
|
+
* down() is destructive on multi-locale installs (dropping `locale` collapses
|
|
1711
|
+
* translated rows onto an ambiguous unique key). Refuse to run when any row
|
|
1712
|
+
* sits at a locale other than the configured defaultLocale.
|
|
1713
|
+
*/
|
|
1714
|
+
async function assertSingleLocale(db, defaultLocale) {
|
|
1715
|
+
for (const table of [
|
|
1716
|
+
"_emdash_menus",
|
|
1717
|
+
"_emdash_menu_items",
|
|
1718
|
+
"taxonomies",
|
|
1719
|
+
"_emdash_taxonomy_defs"
|
|
1720
|
+
]) {
|
|
1721
|
+
validateSystemIdent(table);
|
|
1722
|
+
const result = await sql`
|
|
1723
|
+
SELECT COUNT(*) AS count FROM ${sql.ref(table)} WHERE locale != ${defaultLocale}
|
|
1724
|
+
`.execute(db);
|
|
1725
|
+
const count = Number(result.rows[0]?.count ?? 0);
|
|
1726
|
+
if (count > 0) throw new Error(`Cannot revert migration 036_i18n_menus_and_taxonomies: ${count} row(s) in "${table}" use a non-default locale (defaultLocale="${defaultLocale}"). Reverting would drop them silently. Export translations first (or delete them) and re-run the rollback. See packages/core/src/database/migrations/036_i18n_menus_and_taxonomies.ts.`);
|
|
1727
|
+
}
|
|
1728
|
+
}
|
|
1729
|
+
async function down$1(db) {
|
|
1730
|
+
const defaultLocale = getDefaultLocale();
|
|
1731
|
+
await assertSingleLocale(db, defaultLocale);
|
|
1732
|
+
const widenedTables = [
|
|
1733
|
+
"_emdash_menus",
|
|
1734
|
+
"_emdash_menu_items",
|
|
1735
|
+
"taxonomies",
|
|
1736
|
+
"_emdash_taxonomy_defs"
|
|
1737
|
+
];
|
|
1738
|
+
if (isSqlite(db)) {
|
|
1739
|
+
await sql.raw(`PRAGMA foreign_keys = OFF`).execute(db);
|
|
1740
|
+
try {
|
|
1741
|
+
for (const t of widenedTables) {
|
|
1742
|
+
await sql.raw(`DROP INDEX IF EXISTS idx_${t}_locale`).execute(db);
|
|
1743
|
+
await sql.raw(`DROP INDEX IF EXISTS idx_${t}_translation_group`).execute(db);
|
|
1744
|
+
}
|
|
1745
|
+
await rebuildContentTaxonomiesDown(db, defaultLocale);
|
|
1746
|
+
await rebuildMenusDown(db);
|
|
1747
|
+
await rebuildMenuItemsDown(db);
|
|
1748
|
+
await rebuildTaxonomiesDown(db);
|
|
1749
|
+
await rebuildTaxonomyDefsDown(db);
|
|
1750
|
+
} finally {
|
|
1751
|
+
await sql.raw(`PRAGMA foreign_keys = ON`).execute(db);
|
|
1752
|
+
}
|
|
1753
|
+
return;
|
|
1754
|
+
}
|
|
1755
|
+
for (const t of widenedTables) {
|
|
1756
|
+
await sql.raw(`DROP INDEX IF EXISTS idx_${t}_locale`).execute(db);
|
|
1757
|
+
await sql.raw(`DROP INDEX IF EXISTS idx_${t}_translation_group`).execute(db);
|
|
1758
|
+
await sql.raw(`ALTER TABLE "${t}" DROP COLUMN IF EXISTS locale`).execute(db);
|
|
1759
|
+
await sql.raw(`ALTER TABLE "${t}" DROP COLUMN IF EXISTS translation_group`).execute(db);
|
|
1760
|
+
}
|
|
1761
|
+
}
|
|
1762
|
+
async function rebuildContentTaxonomiesDown(db, defaultLocale) {
|
|
1763
|
+
await sql.raw(`DROP TABLE IF EXISTS "content_taxonomies_new"`).execute(db);
|
|
1764
|
+
await db.schema.createTable("content_taxonomies_new").addColumn("collection", "text", (c) => c.notNull()).addColumn("entry_id", "text", (c) => c.notNull()).addColumn("taxonomy_id", "text", (c) => c.notNull()).addPrimaryKeyConstraint("content_taxonomies_pk", [
|
|
1765
|
+
"collection",
|
|
1766
|
+
"entry_id",
|
|
1767
|
+
"taxonomy_id"
|
|
1768
|
+
]).addForeignKeyConstraint("content_taxonomies_taxonomy_fk", ["taxonomy_id"], "taxonomies", ["id"], (cb) => cb.onDelete("cascade")).execute();
|
|
1769
|
+
await sql`
|
|
1770
|
+
INSERT OR IGNORE INTO content_taxonomies_new (collection, entry_id, taxonomy_id)
|
|
1771
|
+
SELECT ct.collection, ct.entry_id, COALESCE(
|
|
1772
|
+
(SELECT t.id FROM taxonomies t WHERE t.translation_group = ct.taxonomy_id AND t.locale = ${defaultLocale}),
|
|
1773
|
+
ct.taxonomy_id
|
|
1774
|
+
)
|
|
1775
|
+
FROM content_taxonomies ct
|
|
1776
|
+
`.execute(db);
|
|
1777
|
+
await db.schema.dropTable("content_taxonomies").execute();
|
|
1778
|
+
await sql`ALTER TABLE content_taxonomies_new RENAME TO content_taxonomies`.execute(db);
|
|
1779
|
+
}
|
|
1780
|
+
async function rebuildMenusDown(db) {
|
|
1781
|
+
await sql.raw(`DROP TABLE IF EXISTS "_emdash_menus_old"`).execute(db);
|
|
1782
|
+
await db.schema.createTable("_emdash_menus_old").addColumn("id", "text", (c) => c.primaryKey()).addColumn("name", "text", (c) => c.notNull().unique()).addColumn("label", "text", (c) => c.notNull()).addColumn("created_at", "text", (c) => c.defaultTo(currentTimestamp(db))).addColumn("updated_at", "text", (c) => c.defaultTo(currentTimestamp(db))).execute();
|
|
1783
|
+
await sql`
|
|
1784
|
+
INSERT INTO _emdash_menus_old (id, name, label, created_at, updated_at)
|
|
1785
|
+
SELECT id, name, label, created_at, updated_at FROM _emdash_menus
|
|
1786
|
+
`.execute(db);
|
|
1787
|
+
await db.schema.dropTable("_emdash_menus").execute();
|
|
1788
|
+
await sql`ALTER TABLE _emdash_menus_old RENAME TO _emdash_menus`.execute(db);
|
|
1789
|
+
}
|
|
1790
|
+
async function rebuildMenuItemsDown(db) {
|
|
1791
|
+
await sql.raw(`ALTER TABLE _emdash_menu_items DROP COLUMN locale`).execute(db);
|
|
1792
|
+
await sql.raw(`ALTER TABLE _emdash_menu_items DROP COLUMN translation_group`).execute(db);
|
|
1793
|
+
}
|
|
1794
|
+
async function rebuildTaxonomiesDown(db) {
|
|
1795
|
+
await sql.raw(`DROP TABLE IF EXISTS "taxonomies_old"`).execute(db);
|
|
1796
|
+
await db.schema.createTable("taxonomies_old").addColumn("id", "text", (c) => c.primaryKey()).addColumn("name", "text", (c) => c.notNull()).addColumn("slug", "text", (c) => c.notNull()).addColumn("label", "text", (c) => c.notNull()).addColumn("parent_id", "text").addColumn("data", "text").addUniqueConstraint("taxonomies_name_slug_unique", ["name", "slug"]).addForeignKeyConstraint("taxonomies_parent_fk", ["parent_id"], "taxonomies_old", ["id"], (cb) => cb.onDelete("set null")).execute();
|
|
1797
|
+
await sql`
|
|
1798
|
+
INSERT INTO taxonomies_old (id, name, slug, label, parent_id, data)
|
|
1799
|
+
SELECT id, name, slug, label, parent_id, data FROM taxonomies
|
|
1800
|
+
`.execute(db);
|
|
1801
|
+
await db.schema.dropTable("taxonomies").execute();
|
|
1802
|
+
await sql`ALTER TABLE taxonomies_old RENAME TO taxonomies`.execute(db);
|
|
1803
|
+
await db.schema.createIndex("idx_taxonomies_name").on("taxonomies").column("name").execute();
|
|
1804
|
+
}
|
|
1805
|
+
async function rebuildTaxonomyDefsDown(db) {
|
|
1806
|
+
await sql.raw(`DROP TABLE IF EXISTS "_emdash_taxonomy_defs_old"`).execute(db);
|
|
1807
|
+
await db.schema.createTable("_emdash_taxonomy_defs_old").addColumn("id", "text", (c) => c.primaryKey()).addColumn("name", "text", (c) => c.notNull().unique()).addColumn("label", "text", (c) => c.notNull()).addColumn("label_singular", "text").addColumn("hierarchical", "integer", (c) => c.defaultTo(0)).addColumn("collections", "text").addColumn("created_at", "text", (c) => c.defaultTo(currentTimestamp(db))).execute();
|
|
1808
|
+
await sql`
|
|
1809
|
+
INSERT INTO _emdash_taxonomy_defs_old
|
|
1810
|
+
(id, name, label, label_singular, hierarchical, collections, created_at)
|
|
1811
|
+
SELECT id, name, label, label_singular, hierarchical, collections, created_at
|
|
1812
|
+
FROM _emdash_taxonomy_defs
|
|
1813
|
+
`.execute(db);
|
|
1814
|
+
await db.schema.dropTable("_emdash_taxonomy_defs").execute();
|
|
1815
|
+
await sql`ALTER TABLE _emdash_taxonomy_defs_old RENAME TO _emdash_taxonomy_defs`.execute(db);
|
|
1816
|
+
}
|
|
1817
|
+
|
|
1818
|
+
//#endregion
|
|
1819
|
+
//#region src/database/migrations/037_credential_algorithm.ts
|
|
1820
|
+
var _037_credential_algorithm_exports = /* @__PURE__ */ __exportAll({
|
|
1821
|
+
down: () => down,
|
|
1822
|
+
up: () => up
|
|
1823
|
+
});
|
|
1824
|
+
async function up(db) {
|
|
1825
|
+
if (!await columnExists(db, "credentials", "algorithm")) await db.schema.alterTable("credentials").addColumn("algorithm", "integer", (col) => col.notNull().defaultTo(-7)).execute();
|
|
1826
|
+
}
|
|
1827
|
+
async function down(db) {
|
|
1828
|
+
if (await columnExists(db, "credentials", "algorithm")) await db.schema.alterTable("credentials").dropColumn("algorithm").execute();
|
|
1829
|
+
}
|
|
1830
|
+
|
|
1516
1831
|
//#endregion
|
|
1517
1832
|
//#region src/database/migrations/runner.ts
|
|
1518
1833
|
const MIGRATIONS = Object.freeze({
|
|
@@ -1549,7 +1864,9 @@ const MIGRATIONS = Object.freeze({
|
|
|
1549
1864
|
"032_rate_limits": _032_rate_limits_exports,
|
|
1550
1865
|
"033_optimize_content_indexes": _033_optimize_content_indexes_exports,
|
|
1551
1866
|
"034_published_at_index": _034_published_at_index_exports,
|
|
1552
|
-
"035_bounded_404_log": _035_bounded_404_log_exports
|
|
1867
|
+
"035_bounded_404_log": _035_bounded_404_log_exports,
|
|
1868
|
+
"036_i18n_menus_and_taxonomies": _036_i18n_menus_and_taxonomies_exports,
|
|
1869
|
+
"037_credential_algorithm": _037_credential_algorithm_exports
|
|
1553
1870
|
});
|
|
1554
1871
|
/** Total number of registered migrations. Exported for use in tests. */
|
|
1555
1872
|
const MIGRATION_COUNT = Object.keys(MIGRATIONS).length;
|
|
@@ -1746,4 +2063,4 @@ async function rollbackMigration(db) {
|
|
|
1746
2063
|
|
|
1747
2064
|
//#endregion
|
|
1748
2065
|
export { __exportAll as i, rollbackMigration as n, runMigrations as r, getMigrationStatus as t };
|
|
1749
|
-
//# sourceMappingURL=runner-
|
|
2066
|
+
//# sourceMappingURL=runner-DIcU2UCC.mjs.map
|