emdash 0.0.0-b → 0.0.2
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/README.md +87 -43
- package/dist/adapters-BLMa4JGD.d.mts +106 -0
- package/dist/adapters-BLMa4JGD.d.mts.map +1 -0
- package/dist/apply-Bjfq_b4-.mjs +1293 -0
- package/dist/apply-Bjfq_b4-.mjs.map +1 -0
- package/dist/astro/index.d.mts +51 -0
- package/dist/astro/index.d.mts.map +1 -0
- package/dist/astro/index.mjs +1336 -0
- package/dist/astro/index.mjs.map +1 -0
- package/dist/astro/middleware/auth.d.mts +31 -0
- package/dist/astro/middleware/auth.d.mts.map +1 -0
- package/dist/astro/middleware/auth.mjs +654 -0
- package/dist/astro/middleware/auth.mjs.map +1 -0
- package/dist/astro/middleware/redirect.d.mts +22 -0
- package/dist/astro/middleware/redirect.d.mts.map +1 -0
- package/dist/astro/middleware/redirect.mjs +63 -0
- package/dist/astro/middleware/redirect.mjs.map +1 -0
- package/dist/astro/middleware/request-context.d.mts +18 -0
- package/dist/astro/middleware/request-context.d.mts.map +1 -0
- package/dist/astro/middleware/request-context.mjs +1310 -0
- package/dist/astro/middleware/request-context.mjs.map +1 -0
- package/dist/astro/middleware/setup.d.mts +20 -0
- package/dist/astro/middleware/setup.d.mts.map +1 -0
- package/dist/astro/middleware/setup.mjs +47 -0
- package/dist/astro/middleware/setup.mjs.map +1 -0
- package/dist/astro/middleware.d.mts +13 -0
- package/dist/astro/middleware.d.mts.map +1 -0
- package/dist/astro/middleware.mjs +1613 -0
- package/dist/astro/middleware.mjs.map +1 -0
- package/dist/astro/types.d.mts +250 -0
- package/dist/astro/types.d.mts.map +1 -0
- package/dist/astro/types.mjs +1 -0
- package/dist/base64-MBPo9ozB.mjs +59 -0
- package/dist/base64-MBPo9ozB.mjs.map +1 -0
- package/dist/byline-CL847F26.mjs +213 -0
- package/dist/byline-CL847F26.mjs.map +1 -0
- package/dist/bylines-C2a-2TGt.mjs +136 -0
- package/dist/bylines-C2a-2TGt.mjs.map +1 -0
- package/dist/chunk-ClPoSABd.mjs +21 -0
- package/dist/cli/index.d.mts +1 -0
- package/dist/cli/index.mjs +3909 -0
- package/dist/cli/index.mjs.map +1 -0
- package/dist/client/cf-access.d.mts +60 -0
- package/dist/client/cf-access.d.mts.map +1 -0
- package/dist/client/cf-access.mjs +179 -0
- package/dist/client/cf-access.mjs.map +1 -0
- package/dist/client/index.d.mts +398 -0
- package/dist/client/index.d.mts.map +1 -0
- package/dist/client/index.mjs +346 -0
- package/dist/client/index.mjs.map +1 -0
- package/dist/config-CKE8p9xM.mjs +55 -0
- package/dist/config-CKE8p9xM.mjs.map +1 -0
- package/dist/connection-B4zVnQIa.mjs +40 -0
- package/dist/connection-B4zVnQIa.mjs.map +1 -0
- package/dist/content-D6C2WsZC.mjs +824 -0
- package/dist/content-D6C2WsZC.mjs.map +1 -0
- package/dist/db/index.d.mts +4 -0
- package/dist/db/index.mjs +62 -0
- package/dist/db/index.mjs.map +1 -0
- package/dist/db/libsql.d.mts +11 -0
- package/dist/db/libsql.d.mts.map +1 -0
- package/dist/db/libsql.mjs +17 -0
- package/dist/db/libsql.mjs.map +1 -0
- package/dist/db/postgres.d.mts +11 -0
- package/dist/db/postgres.d.mts.map +1 -0
- package/dist/db/postgres.mjs +30 -0
- package/dist/db/postgres.mjs.map +1 -0
- package/dist/db/sqlite.d.mts +11 -0
- package/dist/db/sqlite.d.mts.map +1 -0
- package/dist/db/sqlite.mjs +16 -0
- package/dist/db/sqlite.mjs.map +1 -0
- package/dist/default-Cyi4aAxu.mjs +81 -0
- package/dist/default-Cyi4aAxu.mjs.map +1 -0
- package/dist/dialect-helpers-B9uSp2GJ.mjs +90 -0
- package/dist/dialect-helpers-B9uSp2GJ.mjs.map +1 -0
- package/dist/error-Cxz0tQeO.mjs +27 -0
- package/dist/error-Cxz0tQeO.mjs.map +1 -0
- package/dist/index-C1xF3OGh.d.mts +4527 -0
- package/dist/index-C1xF3OGh.d.mts.map +1 -0
- package/dist/index.d.mts +16 -0
- package/dist/index.mjs +30 -0
- package/dist/load-yOOlckBj.mjs +28 -0
- package/dist/load-yOOlckBj.mjs.map +1 -0
- package/dist/loader-fz8Q_3EO.mjs +447 -0
- package/dist/loader-fz8Q_3EO.mjs.map +1 -0
- package/dist/manifest-schema-Dcl0R6nM.mjs +184 -0
- package/dist/manifest-schema-Dcl0R6nM.mjs.map +1 -0
- package/dist/media/index.d.mts +26 -0
- package/dist/media/index.d.mts.map +1 -0
- package/dist/media/index.mjs +55 -0
- package/dist/media/index.mjs.map +1 -0
- package/dist/media/local-runtime.d.mts +39 -0
- package/dist/media/local-runtime.d.mts.map +1 -0
- package/dist/media/local-runtime.mjs +133 -0
- package/dist/media/local-runtime.mjs.map +1 -0
- package/dist/media-DqHVh136.mjs +200 -0
- package/dist/media-DqHVh136.mjs.map +1 -0
- package/dist/mode-C2EzN1uE.mjs +23 -0
- package/dist/mode-C2EzN1uE.mjs.map +1 -0
- package/dist/page/index.d.mts +140 -0
- package/dist/page/index.d.mts.map +1 -0
- package/dist/page/index.mjs +416 -0
- package/dist/page/index.mjs.map +1 -0
- package/dist/placeholder-CmGAmqeO.d.mts +276 -0
- package/dist/placeholder-CmGAmqeO.d.mts.map +1 -0
- package/dist/placeholder-SmpOx-_v.mjs +243 -0
- package/dist/placeholder-SmpOx-_v.mjs.map +1 -0
- package/dist/plugin-utils.d.mts +58 -0
- package/dist/plugin-utils.d.mts.map +1 -0
- package/dist/plugin-utils.mjs +78 -0
- package/dist/plugin-utils.mjs.map +1 -0
- package/dist/plugins/adapt-sandbox-entry.d.mts +22 -0
- package/dist/plugins/adapt-sandbox-entry.d.mts.map +1 -0
- package/dist/plugins/adapt-sandbox-entry.mjs +113 -0
- package/dist/plugins/adapt-sandbox-entry.mjs.map +1 -0
- package/dist/query-CS_iSj34.mjs +460 -0
- package/dist/query-CS_iSj34.mjs.map +1 -0
- package/dist/redirect-DIfIni3r.mjs +329 -0
- package/dist/redirect-DIfIni3r.mjs.map +1 -0
- package/dist/registry-D_w5HW4G.mjs +863 -0
- package/dist/registry-D_w5HW4G.mjs.map +1 -0
- package/dist/request-context.d.mts +49 -0
- package/dist/request-context.d.mts.map +1 -0
- package/dist/request-context.mjs +43 -0
- package/dist/request-context.mjs.map +1 -0
- package/dist/runner-C0hCbYnD.mjs +1412 -0
- package/dist/runner-C0hCbYnD.mjs.map +1 -0
- package/dist/runner-EAtf0ZIe.d.mts +27 -0
- package/dist/runner-EAtf0ZIe.d.mts.map +1 -0
- package/dist/runtime.d.mts +26 -0
- package/dist/runtime.d.mts.map +1 -0
- package/dist/runtime.mjs +42 -0
- package/dist/runtime.mjs.map +1 -0
- package/dist/search-DG603UrT.mjs +9211 -0
- package/dist/search-DG603UrT.mjs.map +1 -0
- package/dist/seed/index.d.mts +3 -0
- package/dist/seed/index.mjs +15 -0
- package/dist/seo/index.d.mts +70 -0
- package/dist/seo/index.d.mts.map +1 -0
- package/dist/seo/index.mjs +70 -0
- package/dist/seo/index.mjs.map +1 -0
- package/dist/storage/local.d.mts +39 -0
- package/dist/storage/local.d.mts.map +1 -0
- package/dist/storage/local.mjs +166 -0
- package/dist/storage/local.mjs.map +1 -0
- package/dist/storage/s3.d.mts +32 -0
- package/dist/storage/s3.d.mts.map +1 -0
- package/dist/storage/s3.mjs +175 -0
- package/dist/storage/s3.mjs.map +1 -0
- package/dist/tokens-DpgrkrXK.mjs +171 -0
- package/dist/tokens-DpgrkrXK.mjs.map +1 -0
- package/dist/transport-BFGblqwG.d.mts +42 -0
- package/dist/transport-BFGblqwG.d.mts.map +1 -0
- package/dist/transport-yxiQsi8I.mjs +418 -0
- package/dist/transport-yxiQsi8I.mjs.map +1 -0
- package/dist/types-BRuPJGdV.d.mts +102 -0
- package/dist/types-BRuPJGdV.d.mts.map +1 -0
- package/dist/types-C4-fAxN3.d.mts +182 -0
- package/dist/types-C4-fAxN3.d.mts.map +1 -0
- package/dist/types-CMMN0pNg.mjs +31 -0
- package/dist/types-CMMN0pNg.mjs.map +1 -0
- package/dist/types-CUBbjgmP.mjs +16 -0
- package/dist/types-CUBbjgmP.mjs.map +1 -0
- package/dist/types-DRjfYOEv.d.mts +426 -0
- package/dist/types-DRjfYOEv.d.mts.map +1 -0
- package/dist/types-DY5zk5HN.mjs +73 -0
- package/dist/types-DY5zk5HN.mjs.map +1 -0
- package/dist/types-DaNLHo_T.d.mts +184 -0
- package/dist/types-DaNLHo_T.d.mts.map +1 -0
- package/dist/types-DvhsUmSJ.d.mts +1111 -0
- package/dist/types-DvhsUmSJ.d.mts.map +1 -0
- package/dist/validate-CpBtVMsD.d.mts +378 -0
- package/dist/validate-CpBtVMsD.d.mts.map +1 -0
- package/dist/validate-CqRJb_xU.mjs +97 -0
- package/dist/validate-CqRJb_xU.mjs.map +1 -0
- package/dist/validate-O7PWmlnq.mjs +328 -0
- package/dist/validate-O7PWmlnq.mjs.map +1 -0
- package/locals.d.ts +46 -0
- package/package.json +233 -19
- package/src/api/authorize.ts +63 -0
- package/src/api/csrf.ts +48 -0
- package/src/api/error.ts +99 -0
- package/src/api/errors.ts +445 -0
- package/src/api/escape.ts +9 -0
- package/src/api/handlers/api-tokens.ts +240 -0
- package/src/api/handlers/comments.ts +314 -0
- package/src/api/handlers/content.ts +1315 -0
- package/src/api/handlers/dashboard.ts +205 -0
- package/src/api/handlers/device-flow.ts +684 -0
- package/src/api/handlers/index.ts +163 -0
- package/src/api/handlers/manifest.ts +158 -0
- package/src/api/handlers/marketplace.ts +930 -0
- package/src/api/handlers/media.ts +207 -0
- package/src/api/handlers/menus.ts +493 -0
- package/src/api/handlers/oauth-authorization.ts +429 -0
- package/src/api/handlers/oauth-clients.ts +349 -0
- package/src/api/handlers/oauth-user-lookup.ts +39 -0
- package/src/api/handlers/plugins.ts +254 -0
- package/src/api/handlers/redirects.ts +360 -0
- package/src/api/handlers/revision.ts +145 -0
- package/src/api/handlers/schema.ts +534 -0
- package/src/api/handlers/sections.ts +289 -0
- package/src/api/handlers/seo.ts +115 -0
- package/src/api/handlers/settings.ts +49 -0
- package/src/api/handlers/snapshot.ts +350 -0
- package/src/api/handlers/taxonomies.ts +523 -0
- package/src/api/index.ts +6 -0
- package/src/api/openapi/document.ts +2368 -0
- package/src/api/openapi/index.ts +1 -0
- package/src/api/parse.ts +139 -0
- package/src/api/redirect.ts +14 -0
- package/src/api/rev.ts +67 -0
- package/src/api/schemas/auth.ts +112 -0
- package/src/api/schemas/bylines.ts +85 -0
- package/src/api/schemas/comments.ts +117 -0
- package/src/api/schemas/common.ts +89 -0
- package/src/api/schemas/content.ts +191 -0
- package/src/api/schemas/import.ts +52 -0
- package/src/api/schemas/index.ts +17 -0
- package/src/api/schemas/media.ts +116 -0
- package/src/api/schemas/menus.ts +111 -0
- package/src/api/schemas/redirects.ts +155 -0
- package/src/api/schemas/schema.ts +203 -0
- package/src/api/schemas/search.ts +63 -0
- package/src/api/schemas/sections.ts +67 -0
- package/src/api/schemas/settings.ts +63 -0
- package/src/api/schemas/setup.ts +37 -0
- package/src/api/schemas/taxonomies.ts +113 -0
- package/src/api/schemas/users.ts +96 -0
- package/src/api/schemas/widgets.ts +80 -0
- package/src/api/site-url.ts +25 -0
- package/src/api/types.ts +82 -0
- package/src/astro/index.ts +27 -0
- package/src/astro/integration/index.ts +303 -0
- package/src/astro/integration/routes.ts +834 -0
- package/src/astro/integration/runtime.ts +338 -0
- package/src/astro/integration/virtual-modules.ts +469 -0
- package/src/astro/integration/vite-config.ts +335 -0
- package/src/astro/middleware/auth.ts +743 -0
- package/src/astro/middleware/redirect.ts +89 -0
- package/src/astro/middleware/request-context.ts +129 -0
- package/src/astro/middleware/setup.ts +89 -0
- package/src/astro/middleware.ts +398 -0
- package/src/astro/routes/PluginRegistry.tsx +15 -0
- package/src/astro/routes/admin.astro +81 -0
- package/src/astro/routes/api/admin/allowed-domains/[domain].ts +112 -0
- package/src/astro/routes/api/admin/allowed-domains/index.ts +108 -0
- package/src/astro/routes/api/admin/api-tokens/[id].ts +40 -0
- package/src/astro/routes/api/admin/api-tokens/index.ts +68 -0
- package/src/astro/routes/api/admin/bylines/[id]/index.ts +87 -0
- package/src/astro/routes/api/admin/bylines/index.ts +72 -0
- package/src/astro/routes/api/admin/comments/[id]/status.ts +116 -0
- package/src/astro/routes/api/admin/comments/[id].ts +64 -0
- package/src/astro/routes/api/admin/comments/bulk.ts +42 -0
- package/src/astro/routes/api/admin/comments/counts.ts +30 -0
- package/src/astro/routes/api/admin/comments/index.ts +46 -0
- package/src/astro/routes/api/admin/hooks/exclusive/[hookName].ts +91 -0
- package/src/astro/routes/api/admin/hooks/exclusive/index.ts +51 -0
- package/src/astro/routes/api/admin/oauth-clients/[id].ts +110 -0
- package/src/astro/routes/api/admin/oauth-clients/index.ts +71 -0
- package/src/astro/routes/api/admin/plugins/[id]/disable.ts +39 -0
- package/src/astro/routes/api/admin/plugins/[id]/enable.ts +39 -0
- package/src/astro/routes/api/admin/plugins/[id]/index.ts +38 -0
- package/src/astro/routes/api/admin/plugins/[id]/uninstall.ts +48 -0
- package/src/astro/routes/api/admin/plugins/[id]/update.ts +59 -0
- package/src/astro/routes/api/admin/plugins/index.ts +32 -0
- package/src/astro/routes/api/admin/plugins/marketplace/[id]/icon.ts +61 -0
- package/src/astro/routes/api/admin/plugins/marketplace/[id]/index.ts +33 -0
- package/src/astro/routes/api/admin/plugins/marketplace/[id]/install.ts +62 -0
- package/src/astro/routes/api/admin/plugins/marketplace/index.ts +38 -0
- package/src/astro/routes/api/admin/plugins/updates.ts +28 -0
- package/src/astro/routes/api/admin/themes/marketplace/[id]/index.ts +33 -0
- package/src/astro/routes/api/admin/themes/marketplace/[id]/thumbnail.ts +61 -0
- package/src/astro/routes/api/admin/themes/marketplace/index.ts +45 -0
- package/src/astro/routes/api/admin/users/[id]/disable.ts +69 -0
- package/src/astro/routes/api/admin/users/[id]/enable.ts +48 -0
- package/src/astro/routes/api/admin/users/[id]/index.ts +146 -0
- package/src/astro/routes/api/admin/users/[id]/send-recovery.ts +72 -0
- package/src/astro/routes/api/admin/users/index.ts +66 -0
- package/src/astro/routes/api/auth/dev-bypass.ts +139 -0
- package/src/astro/routes/api/auth/invite/accept.ts +52 -0
- package/src/astro/routes/api/auth/invite/complete.ts +84 -0
- package/src/astro/routes/api/auth/invite/index.ts +99 -0
- package/src/astro/routes/api/auth/logout.ts +40 -0
- package/src/astro/routes/api/auth/magic-link/send.ts +89 -0
- package/src/astro/routes/api/auth/magic-link/verify.ts +71 -0
- package/src/astro/routes/api/auth/me.ts +60 -0
- package/src/astro/routes/api/auth/oauth/[provider]/callback.ts +219 -0
- package/src/astro/routes/api/auth/oauth/[provider].ts +119 -0
- package/src/astro/routes/api/auth/passkey/[id].ts +124 -0
- package/src/astro/routes/api/auth/passkey/index.ts +54 -0
- package/src/astro/routes/api/auth/passkey/options.ts +82 -0
- package/src/astro/routes/api/auth/passkey/register/options.ts +86 -0
- package/src/astro/routes/api/auth/passkey/register/verify.ts +115 -0
- package/src/astro/routes/api/auth/passkey/verify.ts +66 -0
- package/src/astro/routes/api/auth/signup/complete.ts +85 -0
- package/src/astro/routes/api/auth/signup/request.ts +77 -0
- package/src/astro/routes/api/auth/signup/verify.ts +53 -0
- package/src/astro/routes/api/comments/[collection]/[contentId]/index.ts +312 -0
- package/src/astro/routes/api/content/[collection]/[id]/compare.ts +28 -0
- package/src/astro/routes/api/content/[collection]/[id]/discard-draft.ts +54 -0
- package/src/astro/routes/api/content/[collection]/[id]/duplicate.ts +61 -0
- package/src/astro/routes/api/content/[collection]/[id]/permanent.ts +33 -0
- package/src/astro/routes/api/content/[collection]/[id]/preview-url.ts +107 -0
- package/src/astro/routes/api/content/[collection]/[id]/publish.ts +56 -0
- package/src/astro/routes/api/content/[collection]/[id]/restore.ts +54 -0
- package/src/astro/routes/api/content/[collection]/[id]/revisions.ts +31 -0
- package/src/astro/routes/api/content/[collection]/[id]/schedule.ts +101 -0
- package/src/astro/routes/api/content/[collection]/[id]/terms/[taxonomy].ts +140 -0
- package/src/astro/routes/api/content/[collection]/[id]/translations.ts +30 -0
- package/src/astro/routes/api/content/[collection]/[id]/unpublish.ts +56 -0
- package/src/astro/routes/api/content/[collection]/[id].ts +137 -0
- package/src/astro/routes/api/content/[collection]/index.ts +59 -0
- package/src/astro/routes/api/content/[collection]/trash.ts +33 -0
- package/src/astro/routes/api/dashboard.ts +32 -0
- package/src/astro/routes/api/dev/emails.ts +36 -0
- package/src/astro/routes/api/import/probe.ts +47 -0
- package/src/astro/routes/api/import/wordpress/analyze.ts +510 -0
- package/src/astro/routes/api/import/wordpress/execute.ts +283 -0
- package/src/astro/routes/api/import/wordpress/media.ts +338 -0
- package/src/astro/routes/api/import/wordpress/prepare.ts +181 -0
- package/src/astro/routes/api/import/wordpress/rewrite-urls.ts +393 -0
- package/src/astro/routes/api/import/wordpress-plugin/analyze.ts +111 -0
- package/src/astro/routes/api/import/wordpress-plugin/callback.ts +58 -0
- package/src/astro/routes/api/import/wordpress-plugin/execute.ts +347 -0
- package/src/astro/routes/api/manifest.ts +62 -0
- package/src/astro/routes/api/mcp.ts +124 -0
- package/src/astro/routes/api/media/[id]/confirm.ts +93 -0
- package/src/astro/routes/api/media/[id].ts +145 -0
- package/src/astro/routes/api/media/file/[key].ts +79 -0
- package/src/astro/routes/api/media/providers/[providerId]/[itemId].ts +86 -0
- package/src/astro/routes/api/media/providers/[providerId]/index.ts +111 -0
- package/src/astro/routes/api/media/providers/index.ts +30 -0
- package/src/astro/routes/api/media/upload-url.ts +137 -0
- package/src/astro/routes/api/media.ts +190 -0
- package/src/astro/routes/api/menus/[name]/items.ts +87 -0
- package/src/astro/routes/api/menus/[name]/reorder.ts +33 -0
- package/src/astro/routes/api/menus/[name].ts +65 -0
- package/src/astro/routes/api/menus/index.ts +47 -0
- package/src/astro/routes/api/oauth/authorize.ts +412 -0
- package/src/astro/routes/api/oauth/device/authorize.ts +45 -0
- package/src/astro/routes/api/oauth/device/code.ts +51 -0
- package/src/astro/routes/api/oauth/device/token.ts +69 -0
- package/src/astro/routes/api/oauth/token/refresh.ts +38 -0
- package/src/astro/routes/api/oauth/token/revoke.ts +38 -0
- package/src/astro/routes/api/oauth/token.ts +184 -0
- package/src/astro/routes/api/openapi.json.ts +32 -0
- package/src/astro/routes/api/plugins/[pluginId]/[...path].ts +92 -0
- package/src/astro/routes/api/redirects/404s/index.ts +72 -0
- package/src/astro/routes/api/redirects/404s/summary.ts +33 -0
- package/src/astro/routes/api/redirects/[id].ts +84 -0
- package/src/astro/routes/api/redirects/index.ts +52 -0
- package/src/astro/routes/api/revisions/[revisionId]/index.ts +29 -0
- package/src/astro/routes/api/revisions/[revisionId]/restore.ts +58 -0
- package/src/astro/routes/api/schema/collections/[slug]/fields/[fieldSlug].ts +76 -0
- package/src/astro/routes/api/schema/collections/[slug]/fields/index.ts +52 -0
- package/src/astro/routes/api/schema/collections/[slug]/fields/reorder.ts +32 -0
- package/src/astro/routes/api/schema/collections/[slug]/index.ts +80 -0
- package/src/astro/routes/api/schema/collections/index.ts +47 -0
- package/src/astro/routes/api/schema/index.ts +109 -0
- package/src/astro/routes/api/schema/orphans/[slug].ts +36 -0
- package/src/astro/routes/api/schema/orphans/index.ts +26 -0
- package/src/astro/routes/api/search/enable.ts +64 -0
- package/src/astro/routes/api/search/index.ts +55 -0
- package/src/astro/routes/api/search/rebuild.ts +72 -0
- package/src/astro/routes/api/search/stats.ts +35 -0
- package/src/astro/routes/api/search/suggest.ts +53 -0
- package/src/astro/routes/api/sections/[slug].ts +84 -0
- package/src/astro/routes/api/sections/index.ts +52 -0
- package/src/astro/routes/api/settings/email.ts +150 -0
- package/src/astro/routes/api/settings.ts +67 -0
- package/src/astro/routes/api/setup/admin-verify.ts +100 -0
- package/src/astro/routes/api/setup/admin.ts +94 -0
- package/src/astro/routes/api/setup/dev-bypass.ts +199 -0
- package/src/astro/routes/api/setup/dev-reset.ts +40 -0
- package/src/astro/routes/api/setup/index.ts +126 -0
- package/src/astro/routes/api/setup/status.ts +122 -0
- package/src/astro/routes/api/snapshot.ts +75 -0
- package/src/astro/routes/api/taxonomies/[name]/terms/[slug].ts +95 -0
- package/src/astro/routes/api/taxonomies/[name]/terms/index.ts +69 -0
- package/src/astro/routes/api/taxonomies/index.ts +59 -0
- package/src/astro/routes/api/themes/preview.ts +77 -0
- package/src/astro/routes/api/typegen.ts +114 -0
- package/src/astro/routes/api/well-known/auth.ts +68 -0
- package/src/astro/routes/api/well-known/oauth-authorization-server.ts +44 -0
- package/src/astro/routes/api/well-known/oauth-protected-resource.ts +37 -0
- package/src/astro/routes/api/widget-areas/[name]/reorder.ts +68 -0
- package/src/astro/routes/api/widget-areas/[name]/widgets/[id].ts +127 -0
- package/src/astro/routes/api/widget-areas/[name]/widgets.ts +80 -0
- package/src/astro/routes/api/widget-areas/[name].ts +87 -0
- package/src/astro/routes/api/widget-areas/index.ts +99 -0
- package/src/astro/routes/api/widget-components.ts +22 -0
- package/src/astro/routes/robots.txt.ts +77 -0
- package/src/astro/routes/sitemap.xml.ts +97 -0
- package/src/astro/storage/adapters.ts +74 -0
- package/src/astro/storage/index.ts +19 -0
- package/src/astro/storage/types.ts +60 -0
- package/src/astro/types.ts +346 -0
- package/src/auth/api-tokens.ts +25 -0
- package/src/auth/challenge-store.ts +80 -0
- package/src/auth/mode.ts +96 -0
- package/src/auth/oauth-state-store.ts +96 -0
- package/src/auth/passkey-config.ts +27 -0
- package/src/auth/rate-limit.ts +158 -0
- package/src/auth/scopes.ts +33 -0
- package/src/auth/types.ts +104 -0
- package/src/aws-sdk.d.ts +100 -0
- package/src/bylines/index.ts +237 -0
- package/src/cleanup.ts +153 -0
- package/src/cli/client-factory.ts +100 -0
- package/src/cli/commands/auth.ts +46 -0
- package/src/cli/commands/bundle-utils.ts +247 -0
- package/src/cli/commands/bundle.ts +609 -0
- package/src/cli/commands/content.ts +442 -0
- package/src/cli/commands/dev.ts +191 -0
- package/src/cli/commands/doctor.ts +211 -0
- package/src/cli/commands/export-seed.ts +630 -0
- package/src/cli/commands/import/wordpress.ts +1056 -0
- package/src/cli/commands/init.ts +192 -0
- package/src/cli/commands/login.ts +547 -0
- package/src/cli/commands/media.ts +165 -0
- package/src/cli/commands/menu.ts +67 -0
- package/src/cli/commands/plugin-init.ts +291 -0
- package/src/cli/commands/plugin-validate.ts +31 -0
- package/src/cli/commands/plugin.ts +33 -0
- package/src/cli/commands/publish.ts +697 -0
- package/src/cli/commands/schema.ts +233 -0
- package/src/cli/commands/search-cmd.ts +54 -0
- package/src/cli/commands/seed.ts +286 -0
- package/src/cli/commands/taxonomy.ts +128 -0
- package/src/cli/commands/types.ts +68 -0
- package/src/cli/credentials.ts +236 -0
- package/src/cli/index.ts +70 -0
- package/src/cli/output.ts +75 -0
- package/src/cli/wxr/parser.ts +969 -0
- package/src/client/cf-access.ts +193 -0
- package/src/client/index.ts +854 -0
- package/src/client/portable-text.ts +413 -0
- package/src/client/transport.ts +200 -0
- package/src/comments/moderator.ts +46 -0
- package/src/comments/notifications.ts +144 -0
- package/src/comments/query.ts +105 -0
- package/src/comments/service.ts +213 -0
- package/src/components/Break.astro +45 -0
- package/src/components/Button.astro +71 -0
- package/src/components/Buttons.astro +49 -0
- package/src/components/Code.astro +59 -0
- package/src/components/Columns.astro +59 -0
- package/src/components/CommentForm.astro +315 -0
- package/src/components/Comments.astro +232 -0
- package/src/components/Cover.astro +128 -0
- package/src/components/EmDashBodyEnd.astro +32 -0
- package/src/components/EmDashBodyStart.astro +32 -0
- package/src/components/EmDashHead.astro +53 -0
- package/src/components/EmDashImage.astro +178 -0
- package/src/components/EmDashMedia.astro +167 -0
- package/src/components/Embed.astro +128 -0
- package/src/components/File.astro +122 -0
- package/src/components/Gallery.astro +93 -0
- package/src/components/HtmlBlock.astro +33 -0
- package/src/components/Image.astro +178 -0
- package/src/components/InlineEditor.astro +27 -0
- package/src/components/InlinePortableTextEditor.tsx +1905 -0
- package/src/components/LiveSearch.astro +614 -0
- package/src/components/PortableText.astro +51 -0
- package/src/components/Pullquote.astro +51 -0
- package/src/components/Table.astro +108 -0
- package/src/components/WidgetArea.astro +22 -0
- package/src/components/WidgetRenderer.astro +72 -0
- package/src/components/index.ts +116 -0
- package/src/components/marks/Link.astro +31 -0
- package/src/components/marks/StrikeThrough.astro +7 -0
- package/src/components/marks/Subscript.astro +7 -0
- package/src/components/marks/Superscript.astro +7 -0
- package/src/components/marks/Underline.astro +7 -0
- package/src/components/widgets/Archives.astro +65 -0
- package/src/components/widgets/Categories.astro +35 -0
- package/src/components/widgets/RecentPosts.astro +51 -0
- package/src/components/widgets/Search.astro +18 -0
- package/src/components/widgets/Tags.astro +38 -0
- package/src/content/converters/index.ts +9 -0
- package/src/content/converters/portable-text-to-prosemirror.ts +385 -0
- package/src/content/converters/prosemirror-to-portable-text.ts +413 -0
- package/src/content/converters/types.ts +120 -0
- package/src/content/index.ts +5 -0
- package/src/database/connection.ts +67 -0
- package/src/database/dialect-helpers.ts +138 -0
- package/src/database/index.ts +5 -0
- package/src/database/migrations/001_initial.ts +170 -0
- package/src/database/migrations/002_media_status.ts +26 -0
- package/src/database/migrations/003_schema_registry.ts +79 -0
- package/src/database/migrations/004_plugins.ts +62 -0
- package/src/database/migrations/005_menus.ts +67 -0
- package/src/database/migrations/006_taxonomy_defs.ts +51 -0
- package/src/database/migrations/007_widgets.ts +42 -0
- package/src/database/migrations/008_auth.ts +194 -0
- package/src/database/migrations/009_user_disabled.ts +27 -0
- package/src/database/migrations/011_sections.ts +65 -0
- package/src/database/migrations/012_search.ts +25 -0
- package/src/database/migrations/013_scheduled_publishing.ts +51 -0
- package/src/database/migrations/014_draft_revisions.ts +72 -0
- package/src/database/migrations/015_indexes.ts +82 -0
- package/src/database/migrations/016_api_tokens.ts +89 -0
- package/src/database/migrations/017_authorization_codes.ts +45 -0
- package/src/database/migrations/018_seo.ts +56 -0
- package/src/database/migrations/019_i18n.ts +618 -0
- package/src/database/migrations/020_collection_url_pattern.ts +23 -0
- package/src/database/migrations/021_remove_section_categories.ts +43 -0
- package/src/database/migrations/022_marketplace_plugin_state.ts +46 -0
- package/src/database/migrations/023_plugin_metadata.ts +33 -0
- package/src/database/migrations/024_media_placeholders.ts +32 -0
- package/src/database/migrations/025_oauth_clients.ts +28 -0
- package/src/database/migrations/026_cron_tasks.ts +49 -0
- package/src/database/migrations/027_comments.ts +87 -0
- package/src/database/migrations/028_drop_author_url.ts +9 -0
- package/src/database/migrations/029_redirects.ts +67 -0
- package/src/database/migrations/030_widen_scheduled_index.ts +48 -0
- package/src/database/migrations/031_bylines.ts +90 -0
- package/src/database/migrations/032_rate_limits.ts +39 -0
- package/src/database/migrations/runner.ts +170 -0
- package/src/database/repositories/audit.ts +294 -0
- package/src/database/repositories/byline.ts +387 -0
- package/src/database/repositories/comment.ts +458 -0
- package/src/database/repositories/content.ts +1144 -0
- package/src/database/repositories/index.ts +30 -0
- package/src/database/repositories/media.ts +347 -0
- package/src/database/repositories/options.ts +150 -0
- package/src/database/repositories/plugin-storage.ts +373 -0
- package/src/database/repositories/redirect.ts +480 -0
- package/src/database/repositories/revision.ts +200 -0
- package/src/database/repositories/seo.ts +176 -0
- package/src/database/repositories/taxonomy.ts +294 -0
- package/src/database/repositories/types.ts +132 -0
- package/src/database/repositories/user.ts +258 -0
- package/src/database/transaction.ts +54 -0
- package/src/database/types.ts +501 -0
- package/src/database/validate.ts +138 -0
- package/src/db/adapters.ts +125 -0
- package/src/db/index.ts +37 -0
- package/src/db/libsql.ts +23 -0
- package/src/db/postgres.ts +30 -0
- package/src/db/sqlite.ts +27 -0
- package/src/emdash-runtime.ts +2096 -0
- package/src/fields/boolean.ts +34 -0
- package/src/fields/datetime.ts +44 -0
- package/src/fields/file.ts +41 -0
- package/src/fields/image.ts +34 -0
- package/src/fields/index.ts +42 -0
- package/src/fields/integer.ts +50 -0
- package/src/fields/json.ts +37 -0
- package/src/fields/multiselect.ts +48 -0
- package/src/fields/number.ts +52 -0
- package/src/fields/portable-text.ts +33 -0
- package/src/fields/reference.ts +29 -0
- package/src/fields/richtext.ts +31 -0
- package/src/fields/select.ts +46 -0
- package/src/fields/slug.ts +38 -0
- package/src/fields/text.ts +55 -0
- package/src/fields/textarea.ts +52 -0
- package/src/fields/types.ts +64 -0
- package/src/i18n/config.ts +68 -0
- package/src/import/index.ts +90 -0
- package/src/import/menus.ts +436 -0
- package/src/import/registry.ts +111 -0
- package/src/import/sections.ts +103 -0
- package/src/import/settings.ts +281 -0
- package/src/import/sources/wordpress-plugin.ts +641 -0
- package/src/import/sources/wordpress-rest.ts +191 -0
- package/src/import/sources/wxr.ts +330 -0
- package/src/import/ssrf.ts +260 -0
- package/src/import/types.ts +418 -0
- package/src/import/utils.ts +412 -0
- package/src/index.ts +481 -0
- package/src/loader.ts +770 -0
- package/src/mcp/server.ts +1463 -0
- package/src/media/index.ts +32 -0
- package/src/media/local-runtime.ts +213 -0
- package/src/media/local.ts +46 -0
- package/src/media/normalize.ts +190 -0
- package/src/media/placeholder.ts +150 -0
- package/src/media/provider-loader.ts +78 -0
- package/src/media/types.ts +279 -0
- package/src/menus/index.ts +324 -0
- package/src/menus/types.ts +112 -0
- package/src/page/context.ts +93 -0
- package/src/page/fragments.ts +89 -0
- package/src/page/index.ts +58 -0
- package/src/page/jsonld.ts +94 -0
- package/src/page/metadata.ts +185 -0
- package/src/page/seo-contributions.ts +136 -0
- package/src/plugin-utils.ts +80 -0
- package/src/plugins/adapt-sandbox-entry.ts +207 -0
- package/src/plugins/context.ts +833 -0
- package/src/plugins/cron.ts +361 -0
- package/src/plugins/define-plugin.ts +259 -0
- package/src/plugins/email-console.ts +73 -0
- package/src/plugins/email.ts +209 -0
- package/src/plugins/hooks.ts +1273 -0
- package/src/plugins/index.ts +193 -0
- package/src/plugins/manager.ts +595 -0
- package/src/plugins/manifest-schema.ts +230 -0
- package/src/plugins/marketplace.ts +460 -0
- package/src/plugins/request-meta.ts +139 -0
- package/src/plugins/routes.ts +302 -0
- package/src/plugins/sandbox/index.ts +18 -0
- package/src/plugins/sandbox/noop.ts +76 -0
- package/src/plugins/sandbox/types.ts +173 -0
- package/src/plugins/scheduler/node.ts +122 -0
- package/src/plugins/scheduler/piggyback.ts +71 -0
- package/src/plugins/scheduler/types.ts +27 -0
- package/src/plugins/state.ts +208 -0
- package/src/plugins/storage-indexes.ts +326 -0
- package/src/plugins/storage-query.ts +240 -0
- package/src/plugins/types.ts +1284 -0
- package/src/preview/helpers.ts +27 -0
- package/src/preview/index.ts +40 -0
- package/src/preview/tokens.ts +279 -0
- package/src/preview/urls.ts +118 -0
- package/src/query.ts +674 -0
- package/src/redirects/patterns.ts +224 -0
- package/src/request-context.ts +67 -0
- package/src/runtime.ts +21 -0
- package/src/schema/index.ts +29 -0
- package/src/schema/query.ts +44 -0
- package/src/schema/registry.ts +965 -0
- package/src/schema/types.ts +276 -0
- package/src/schema/zod-generator.ts +413 -0
- package/src/search/fts-manager.ts +452 -0
- package/src/search/index.ts +26 -0
- package/src/search/query.ts +396 -0
- package/src/search/text-extraction.ts +162 -0
- package/src/search/types.ts +114 -0
- package/src/sections/index.ts +226 -0
- package/src/sections/types.ts +86 -0
- package/src/seed/apply.ts +1141 -0
- package/src/seed/default.ts +86 -0
- package/src/seed/index.ts +28 -0
- package/src/seed/load.ts +35 -0
- package/src/seed/types.ts +341 -0
- package/src/seed/validate.ts +642 -0
- package/src/seo/index.ts +179 -0
- package/src/settings/index.ts +203 -0
- package/src/settings/types.ts +58 -0
- package/src/storage/index.ts +28 -0
- package/src/storage/local.ts +249 -0
- package/src/storage/s3.ts +263 -0
- package/src/storage/types.ts +204 -0
- package/src/taxonomies/index.ts +309 -0
- package/src/taxonomies/types.ts +61 -0
- package/src/ui.ts +75 -0
- package/src/utils/base64.ts +73 -0
- package/src/utils/hash.ts +36 -0
- package/src/utils/sanitize.ts +20 -0
- package/src/utils/slugify.ts +29 -0
- package/src/utils/url.ts +48 -0
- package/src/virtual-modules.d.ts +111 -0
- package/src/visual-editing/editable.ts +108 -0
- package/src/visual-editing/toolbar.ts +1229 -0
- package/src/widgets/components.ts +105 -0
- package/src/widgets/index.ts +131 -0
- package/src/widgets/types.ts +81 -0
|
@@ -0,0 +1,194 @@
|
|
|
1
|
+
import type { Kysely } from "kysely";
|
|
2
|
+
import { sql } from "kysely";
|
|
3
|
+
|
|
4
|
+
import { binaryType, currentTimestamp, currentTimestampValue } from "../dialect-helpers.js";
|
|
5
|
+
|
|
6
|
+
/**
|
|
7
|
+
* Auth migration - passkey-first authentication
|
|
8
|
+
*
|
|
9
|
+
* Changes:
|
|
10
|
+
* - Removes password_hash from users (no passwords)
|
|
11
|
+
* - Adds role as integer (RBAC levels)
|
|
12
|
+
* - Adds email_verified, avatar_url, updated_at to users
|
|
13
|
+
* - Creates credentials table (passkeys)
|
|
14
|
+
* - Creates auth_tokens table (magic links, invites)
|
|
15
|
+
* - Creates oauth_accounts table (external provider links)
|
|
16
|
+
* - Creates allowed_domains table (self-signup)
|
|
17
|
+
*/
|
|
18
|
+
export async function up(db: Kysely<unknown>): Promise<void> {
|
|
19
|
+
// SQLite doesn't support DROP COLUMN directly, so we need to recreate the table
|
|
20
|
+
// Create new users table with updated schema
|
|
21
|
+
await db.schema
|
|
22
|
+
.createTable("users_new")
|
|
23
|
+
.addColumn("id", "text", (col) => col.primaryKey())
|
|
24
|
+
.addColumn("email", "text", (col) => col.notNull().unique())
|
|
25
|
+
.addColumn("name", "text")
|
|
26
|
+
.addColumn("avatar_url", "text")
|
|
27
|
+
.addColumn("role", "integer", (col) => col.notNull().defaultTo(10)) // SUBSCRIBER
|
|
28
|
+
.addColumn("email_verified", "integer", (col) => col.notNull().defaultTo(0))
|
|
29
|
+
.addColumn("data", "text")
|
|
30
|
+
.addColumn("created_at", "text", (col) => col.defaultTo(currentTimestamp(db)))
|
|
31
|
+
.addColumn("updated_at", "text", (col) => col.defaultTo(currentTimestamp(db)))
|
|
32
|
+
.execute();
|
|
33
|
+
|
|
34
|
+
// Migrate existing data (map old role strings to new integer levels)
|
|
35
|
+
await sql`
|
|
36
|
+
INSERT INTO users_new (id, email, name, role, data, created_at, updated_at)
|
|
37
|
+
SELECT
|
|
38
|
+
id,
|
|
39
|
+
email,
|
|
40
|
+
name,
|
|
41
|
+
CASE role
|
|
42
|
+
WHEN 'admin' THEN 50
|
|
43
|
+
WHEN 'editor' THEN 40
|
|
44
|
+
WHEN 'author' THEN 30
|
|
45
|
+
WHEN 'contributor' THEN 20
|
|
46
|
+
ELSE 10
|
|
47
|
+
END,
|
|
48
|
+
data,
|
|
49
|
+
created_at,
|
|
50
|
+
${currentTimestampValue(db)}
|
|
51
|
+
FROM users
|
|
52
|
+
`.execute(db);
|
|
53
|
+
|
|
54
|
+
// Drop old table and rename new one
|
|
55
|
+
await db.schema.dropTable("users").execute();
|
|
56
|
+
await sql`ALTER TABLE users_new RENAME TO users`.execute(db);
|
|
57
|
+
|
|
58
|
+
// Recreate index
|
|
59
|
+
await db.schema.createIndex("idx_users_email").on("users").column("email").execute();
|
|
60
|
+
|
|
61
|
+
// Passkey credentials
|
|
62
|
+
await db.schema
|
|
63
|
+
.createTable("credentials")
|
|
64
|
+
.addColumn("id", "text", (col) => col.primaryKey()) // Base64url credential ID
|
|
65
|
+
.addColumn("user_id", "text", (col) => col.notNull())
|
|
66
|
+
.addColumn("public_key", binaryType(db), (col) => col.notNull()) // COSE public key
|
|
67
|
+
.addColumn("counter", "integer", (col) => col.notNull().defaultTo(0))
|
|
68
|
+
.addColumn("device_type", "text", (col) => col.notNull()) // 'singleDevice' | 'multiDevice'
|
|
69
|
+
.addColumn("backed_up", "integer", (col) => col.notNull().defaultTo(0))
|
|
70
|
+
.addColumn("transports", "text") // JSON array
|
|
71
|
+
.addColumn("name", "text") // User-friendly name
|
|
72
|
+
.addColumn("created_at", "text", (col) => col.defaultTo(currentTimestamp(db)))
|
|
73
|
+
.addColumn("last_used_at", "text", (col) => col.defaultTo(currentTimestamp(db)))
|
|
74
|
+
.addForeignKeyConstraint("credentials_user_fk", ["user_id"], "users", ["id"], (cb) =>
|
|
75
|
+
cb.onDelete("cascade"),
|
|
76
|
+
)
|
|
77
|
+
.execute();
|
|
78
|
+
|
|
79
|
+
await db.schema.createIndex("idx_credentials_user").on("credentials").column("user_id").execute();
|
|
80
|
+
|
|
81
|
+
// Auth tokens (magic links, email verification, invites, recovery)
|
|
82
|
+
await db.schema
|
|
83
|
+
.createTable("auth_tokens")
|
|
84
|
+
.addColumn("hash", "text", (col) => col.primaryKey()) // SHA-256 hash of token
|
|
85
|
+
.addColumn("user_id", "text")
|
|
86
|
+
.addColumn("email", "text") // For pre-user tokens
|
|
87
|
+
.addColumn("type", "text", (col) => col.notNull()) // 'magic_link' | 'email_verify' | 'invite' | 'recovery'
|
|
88
|
+
.addColumn("role", "integer") // For invites
|
|
89
|
+
.addColumn("invited_by", "text")
|
|
90
|
+
.addColumn("expires_at", "text", (col) => col.notNull())
|
|
91
|
+
.addColumn("created_at", "text", (col) => col.defaultTo(currentTimestamp(db)))
|
|
92
|
+
.addForeignKeyConstraint("auth_tokens_user_fk", ["user_id"], "users", ["id"], (cb) =>
|
|
93
|
+
cb.onDelete("cascade"),
|
|
94
|
+
)
|
|
95
|
+
.addForeignKeyConstraint("auth_tokens_invited_by_fk", ["invited_by"], "users", ["id"], (cb) =>
|
|
96
|
+
cb.onDelete("set null"),
|
|
97
|
+
)
|
|
98
|
+
.execute();
|
|
99
|
+
|
|
100
|
+
await db.schema.createIndex("idx_auth_tokens_email").on("auth_tokens").column("email").execute();
|
|
101
|
+
|
|
102
|
+
// OAuth accounts (external provider links)
|
|
103
|
+
await db.schema
|
|
104
|
+
.createTable("oauth_accounts")
|
|
105
|
+
.addColumn("provider", "text", (col) => col.notNull())
|
|
106
|
+
.addColumn("provider_account_id", "text", (col) => col.notNull())
|
|
107
|
+
.addColumn("user_id", "text", (col) => col.notNull())
|
|
108
|
+
.addColumn("created_at", "text", (col) => col.defaultTo(currentTimestamp(db)))
|
|
109
|
+
.addPrimaryKeyConstraint("oauth_accounts_pk", ["provider", "provider_account_id"])
|
|
110
|
+
.addForeignKeyConstraint("oauth_accounts_user_fk", ["user_id"], "users", ["id"], (cb) =>
|
|
111
|
+
cb.onDelete("cascade"),
|
|
112
|
+
)
|
|
113
|
+
.execute();
|
|
114
|
+
|
|
115
|
+
await db.schema
|
|
116
|
+
.createIndex("idx_oauth_accounts_user")
|
|
117
|
+
.on("oauth_accounts")
|
|
118
|
+
.column("user_id")
|
|
119
|
+
.execute();
|
|
120
|
+
|
|
121
|
+
// Allowed domains for self-signup
|
|
122
|
+
await db.schema
|
|
123
|
+
.createTable("allowed_domains")
|
|
124
|
+
.addColumn("domain", "text", (col) => col.primaryKey())
|
|
125
|
+
.addColumn("default_role", "integer", (col) => col.notNull().defaultTo(20)) // CONTRIBUTOR
|
|
126
|
+
.addColumn("enabled", "integer", (col) => col.notNull().defaultTo(1))
|
|
127
|
+
.addColumn("created_at", "text", (col) => col.defaultTo(currentTimestamp(db)))
|
|
128
|
+
.execute();
|
|
129
|
+
|
|
130
|
+
// WebAuthn challenges (ephemeral, with TTL)
|
|
131
|
+
await db.schema
|
|
132
|
+
.createTable("auth_challenges")
|
|
133
|
+
.addColumn("challenge", "text", (col) => col.primaryKey()) // Base64url challenge
|
|
134
|
+
.addColumn("type", "text", (col) => col.notNull()) // 'registration' | 'authentication'
|
|
135
|
+
.addColumn("user_id", "text") // For registration, the user being registered
|
|
136
|
+
.addColumn("data", "text") // JSON for additional context
|
|
137
|
+
.addColumn("expires_at", "text", (col) => col.notNull())
|
|
138
|
+
.addColumn("created_at", "text", (col) => col.defaultTo(currentTimestamp(db)))
|
|
139
|
+
.execute();
|
|
140
|
+
|
|
141
|
+
// Index for efficient cleanup of expired challenges
|
|
142
|
+
await db.schema
|
|
143
|
+
.createIndex("idx_auth_challenges_expires")
|
|
144
|
+
.on("auth_challenges")
|
|
145
|
+
.column("expires_at")
|
|
146
|
+
.execute();
|
|
147
|
+
}
|
|
148
|
+
|
|
149
|
+
export async function down(db: Kysely<unknown>): Promise<void> {
|
|
150
|
+
// Drop new tables
|
|
151
|
+
await db.schema.dropTable("auth_challenges").execute();
|
|
152
|
+
await db.schema.dropTable("allowed_domains").execute();
|
|
153
|
+
await db.schema.dropTable("oauth_accounts").execute();
|
|
154
|
+
await db.schema.dropTable("auth_tokens").execute();
|
|
155
|
+
await db.schema.dropTable("credentials").execute();
|
|
156
|
+
|
|
157
|
+
// Recreate old users table with password_hash
|
|
158
|
+
await db.schema
|
|
159
|
+
.createTable("users_old")
|
|
160
|
+
.addColumn("id", "text", (col) => col.primaryKey())
|
|
161
|
+
.addColumn("email", "text", (col) => col.notNull().unique())
|
|
162
|
+
.addColumn("password_hash", "text", (col) => col.notNull())
|
|
163
|
+
.addColumn("name", "text")
|
|
164
|
+
.addColumn("role", "text", (col) => col.defaultTo("subscriber"))
|
|
165
|
+
.addColumn("avatar_id", "text")
|
|
166
|
+
.addColumn("data", "text")
|
|
167
|
+
.addColumn("created_at", "text", (col) => col.defaultTo(currentTimestamp(db)))
|
|
168
|
+
.execute();
|
|
169
|
+
|
|
170
|
+
// Migrate data back (users will have empty password_hash)
|
|
171
|
+
await sql`
|
|
172
|
+
INSERT INTO users_old (id, email, password_hash, name, role, data, created_at)
|
|
173
|
+
SELECT
|
|
174
|
+
id,
|
|
175
|
+
email,
|
|
176
|
+
'', -- No way to restore password
|
|
177
|
+
name,
|
|
178
|
+
CASE role
|
|
179
|
+
WHEN 50 THEN 'admin'
|
|
180
|
+
WHEN 40 THEN 'editor'
|
|
181
|
+
WHEN 30 THEN 'author'
|
|
182
|
+
WHEN 20 THEN 'contributor'
|
|
183
|
+
ELSE 'subscriber'
|
|
184
|
+
END,
|
|
185
|
+
data,
|
|
186
|
+
created_at
|
|
187
|
+
FROM users
|
|
188
|
+
`.execute(db);
|
|
189
|
+
|
|
190
|
+
await db.schema.dropTable("users").execute();
|
|
191
|
+
await sql`ALTER TABLE users_old RENAME TO users`.execute(db);
|
|
192
|
+
|
|
193
|
+
await db.schema.createIndex("idx_users_email").on("users").column("email").execute();
|
|
194
|
+
}
|
|
@@ -0,0 +1,27 @@
|
|
|
1
|
+
import type { Kysely } from "kysely";
|
|
2
|
+
import { sql } from "kysely";
|
|
3
|
+
|
|
4
|
+
/**
|
|
5
|
+
* User disabled column - for soft-disabling users
|
|
6
|
+
*
|
|
7
|
+
* Changes:
|
|
8
|
+
* - Adds disabled column to users table (INTEGER, default 0)
|
|
9
|
+
* - Disabled users cannot log in
|
|
10
|
+
*/
|
|
11
|
+
export async function up(db: Kysely<unknown>): Promise<void> {
|
|
12
|
+
// SQLite supports ADD COLUMN
|
|
13
|
+
await sql`ALTER TABLE users ADD COLUMN disabled INTEGER NOT NULL DEFAULT 0`.execute(db);
|
|
14
|
+
|
|
15
|
+
// Create index for querying active users
|
|
16
|
+
await db.schema.createIndex("idx_users_disabled").on("users").column("disabled").execute();
|
|
17
|
+
}
|
|
18
|
+
|
|
19
|
+
export async function down(db: Kysely<unknown>): Promise<void> {
|
|
20
|
+
// SQLite doesn't support DROP COLUMN directly, but we can drop the index
|
|
21
|
+
// For full rollback, table would need to be recreated
|
|
22
|
+
await db.schema.dropIndex("idx_users_disabled").execute();
|
|
23
|
+
|
|
24
|
+
// SQLite 3.35.0+ supports DROP COLUMN, but for compatibility:
|
|
25
|
+
// We'll leave the column but document that it's deprecated
|
|
26
|
+
// In production, you'd recreate the table without the column
|
|
27
|
+
}
|
|
@@ -0,0 +1,65 @@
|
|
|
1
|
+
import { type Kysely, sql } from "kysely";
|
|
2
|
+
|
|
3
|
+
/**
|
|
4
|
+
* Migration: Add sections tables and performance indexes
|
|
5
|
+
*
|
|
6
|
+
* Sections are reusable content blocks that can be inserted into any Portable Text field.
|
|
7
|
+
* They provide a library of pre-built page sections (heroes, CTAs, testimonials, etc.)
|
|
8
|
+
* that content authors can browse and insert with a single click.
|
|
9
|
+
*/
|
|
10
|
+
export async function up(db: Kysely<unknown>): Promise<void> {
|
|
11
|
+
// Section categories table
|
|
12
|
+
await db.schema
|
|
13
|
+
.createTable("_emdash_section_categories")
|
|
14
|
+
.addColumn("id", "text", (col) => col.primaryKey())
|
|
15
|
+
.addColumn("slug", "text", (col) => col.notNull().unique())
|
|
16
|
+
.addColumn("label", "text", (col) => col.notNull())
|
|
17
|
+
.addColumn("sort_order", "integer", (col) => col.defaultTo(0))
|
|
18
|
+
.addColumn("created_at", "text", (col) => col.defaultTo(sql`CURRENT_TIMESTAMP`))
|
|
19
|
+
.execute();
|
|
20
|
+
|
|
21
|
+
// Sections table
|
|
22
|
+
await db.schema
|
|
23
|
+
.createTable("_emdash_sections")
|
|
24
|
+
.addColumn("id", "text", (col) => col.primaryKey())
|
|
25
|
+
.addColumn("slug", "text", (col) => col.notNull().unique())
|
|
26
|
+
.addColumn("title", "text", (col) => col.notNull())
|
|
27
|
+
.addColumn("description", "text")
|
|
28
|
+
// Categorization
|
|
29
|
+
.addColumn("category_id", "text", (col) =>
|
|
30
|
+
col.references("_emdash_section_categories.id").onDelete("set null"),
|
|
31
|
+
)
|
|
32
|
+
.addColumn("keywords", "text") // JSON array for search
|
|
33
|
+
// Content (Portable Text array)
|
|
34
|
+
.addColumn("content", "text", (col) => col.notNull()) // JSON
|
|
35
|
+
// Preview image (optional)
|
|
36
|
+
.addColumn("preview_media_id", "text")
|
|
37
|
+
// Source tracking
|
|
38
|
+
.addColumn("source", "text", (col) => col.notNull().defaultTo("user")) // 'theme', 'user', 'import'
|
|
39
|
+
.addColumn("theme_id", "text") // Which theme provided it (if source='theme')
|
|
40
|
+
// Metadata
|
|
41
|
+
.addColumn("created_at", "text", (col) => col.defaultTo(sql`CURRENT_TIMESTAMP`))
|
|
42
|
+
.addColumn("updated_at", "text", (col) => col.defaultTo(sql`CURRENT_TIMESTAMP`))
|
|
43
|
+
.execute();
|
|
44
|
+
|
|
45
|
+
// Index for efficient category lookups
|
|
46
|
+
await db.schema
|
|
47
|
+
.createIndex("idx_sections_category")
|
|
48
|
+
.on("_emdash_sections")
|
|
49
|
+
.columns(["category_id"])
|
|
50
|
+
.execute();
|
|
51
|
+
|
|
52
|
+
// Index for filtering by source
|
|
53
|
+
await db.schema
|
|
54
|
+
.createIndex("idx_sections_source")
|
|
55
|
+
.on("_emdash_sections")
|
|
56
|
+
.columns(["source"])
|
|
57
|
+
.execute();
|
|
58
|
+
}
|
|
59
|
+
|
|
60
|
+
export async function down(db: Kysely<unknown>): Promise<void> {
|
|
61
|
+
await db.schema.dropIndex("idx_content_taxonomies_term").execute();
|
|
62
|
+
await db.schema.dropIndex("idx_media_mime_type").execute();
|
|
63
|
+
await db.schema.dropTable("_emdash_sections").execute();
|
|
64
|
+
await db.schema.dropTable("_emdash_section_categories").execute();
|
|
65
|
+
}
|
|
@@ -0,0 +1,25 @@
|
|
|
1
|
+
import type { Kysely } from "kysely";
|
|
2
|
+
|
|
3
|
+
/**
|
|
4
|
+
* Migration: Search Support
|
|
5
|
+
*
|
|
6
|
+
* Adds search configuration to collections and searchable flag to fields.
|
|
7
|
+
* FTS5 tables are created dynamically when search is enabled for a collection.
|
|
8
|
+
*/
|
|
9
|
+
export async function up(db: Kysely<unknown>): Promise<void> {
|
|
10
|
+
// Add search_config to collections (JSON: { enabled, weights })
|
|
11
|
+
await db.schema.alterTable("_emdash_collections").addColumn("search_config", "text").execute();
|
|
12
|
+
|
|
13
|
+
// Add searchable flag to fields
|
|
14
|
+
await db.schema
|
|
15
|
+
.alterTable("_emdash_fields")
|
|
16
|
+
.addColumn("searchable", "integer", (col) => col.defaultTo(0))
|
|
17
|
+
.execute();
|
|
18
|
+
}
|
|
19
|
+
|
|
20
|
+
export async function down(db: Kysely<unknown>): Promise<void> {
|
|
21
|
+
// SQLite doesn't support DROP COLUMN in older versions, but modern SQLite does
|
|
22
|
+
// These columns are safe to drop
|
|
23
|
+
await db.schema.alterTable("_emdash_fields").dropColumn("searchable").execute();
|
|
24
|
+
await db.schema.alterTable("_emdash_collections").dropColumn("search_config").execute();
|
|
25
|
+
}
|
|
@@ -0,0 +1,51 @@
|
|
|
1
|
+
import type { Kysely } from "kysely";
|
|
2
|
+
import { sql } from "kysely";
|
|
3
|
+
|
|
4
|
+
import { listTablesLike } from "../dialect-helpers.js";
|
|
5
|
+
|
|
6
|
+
/**
|
|
7
|
+
* Migration: Add scheduled publishing support
|
|
8
|
+
*
|
|
9
|
+
* Adds scheduled_at column to all ec_* content tables.
|
|
10
|
+
* When scheduled_at is set and status is 'scheduled', the content
|
|
11
|
+
* will be auto-published when the scheduled time is reached.
|
|
12
|
+
*/
|
|
13
|
+
export async function up(db: Kysely<unknown>): Promise<void> {
|
|
14
|
+
// Get all ec_* content tables
|
|
15
|
+
const tableNames = await listTablesLike(db, "ec_%");
|
|
16
|
+
|
|
17
|
+
// Add scheduled_at column to each content table
|
|
18
|
+
for (const tableName of tableNames) {
|
|
19
|
+
const table = { name: tableName };
|
|
20
|
+
await sql`
|
|
21
|
+
ALTER TABLE ${sql.ref(table.name)}
|
|
22
|
+
ADD COLUMN scheduled_at TEXT
|
|
23
|
+
`.execute(db);
|
|
24
|
+
|
|
25
|
+
// Create index for efficient scheduled content queries
|
|
26
|
+
await sql`
|
|
27
|
+
CREATE INDEX ${sql.ref(`idx_${table.name}_scheduled`)}
|
|
28
|
+
ON ${sql.ref(table.name)} (scheduled_at)
|
|
29
|
+
WHERE scheduled_at IS NOT NULL AND status = 'scheduled'
|
|
30
|
+
`.execute(db);
|
|
31
|
+
}
|
|
32
|
+
}
|
|
33
|
+
|
|
34
|
+
export async function down(db: Kysely<unknown>): Promise<void> {
|
|
35
|
+
// Get all ec_* content tables
|
|
36
|
+
const tableNames = await listTablesLike(db, "ec_%");
|
|
37
|
+
|
|
38
|
+
// Drop scheduled_at column from each content table
|
|
39
|
+
for (const tableName of tableNames) {
|
|
40
|
+
const table = { name: tableName };
|
|
41
|
+
// Drop index first
|
|
42
|
+
await sql`
|
|
43
|
+
DROP INDEX IF EXISTS ${sql.ref(`idx_${table.name}_scheduled`)}
|
|
44
|
+
`.execute(db);
|
|
45
|
+
|
|
46
|
+
await sql`
|
|
47
|
+
ALTER TABLE ${sql.ref(table.name)}
|
|
48
|
+
DROP COLUMN scheduled_at
|
|
49
|
+
`.execute(db);
|
|
50
|
+
}
|
|
51
|
+
}
|
|
@@ -0,0 +1,72 @@
|
|
|
1
|
+
import type { Kysely } from "kysely";
|
|
2
|
+
import { sql } from "kysely";
|
|
3
|
+
|
|
4
|
+
export async function up(db: Kysely<unknown>): Promise<void> {
|
|
5
|
+
// Get all content tables
|
|
6
|
+
const tables = await db
|
|
7
|
+
// eslint-disable-next-line typescript-eslint(no-unsafe-type-assertion) -- Kysely migration runs against unknown schema
|
|
8
|
+
.selectFrom("_emdash_collections" as never)
|
|
9
|
+
// eslint-disable-next-line typescript-eslint(no-unsafe-type-assertion) -- Kysely migration runs against unknown schema
|
|
10
|
+
.select("slug" as never)
|
|
11
|
+
.execute();
|
|
12
|
+
|
|
13
|
+
// eslint-disable-next-line typescript-eslint(no-unsafe-type-assertion) -- Kysely execute returns unknown[]; narrowing to known shape
|
|
14
|
+
for (const row of tables as Array<{ slug: string }>) {
|
|
15
|
+
const tableName = `ec_${row.slug}`;
|
|
16
|
+
|
|
17
|
+
// Add live_revision_id column
|
|
18
|
+
await sql`
|
|
19
|
+
ALTER TABLE ${sql.ref(tableName)}
|
|
20
|
+
ADD COLUMN live_revision_id TEXT REFERENCES revisions(id)
|
|
21
|
+
`.execute(db);
|
|
22
|
+
|
|
23
|
+
// Add draft_revision_id column
|
|
24
|
+
await sql`
|
|
25
|
+
ALTER TABLE ${sql.ref(tableName)}
|
|
26
|
+
ADD COLUMN draft_revision_id TEXT REFERENCES revisions(id)
|
|
27
|
+
`.execute(db);
|
|
28
|
+
|
|
29
|
+
// Create indexes for the new columns
|
|
30
|
+
await sql`
|
|
31
|
+
CREATE INDEX ${sql.ref(`idx_${row.slug}_live_revision`)}
|
|
32
|
+
ON ${sql.ref(tableName)} (live_revision_id)
|
|
33
|
+
`.execute(db);
|
|
34
|
+
|
|
35
|
+
await sql`
|
|
36
|
+
CREATE INDEX ${sql.ref(`idx_${row.slug}_draft_revision`)}
|
|
37
|
+
ON ${sql.ref(tableName)} (draft_revision_id)
|
|
38
|
+
`.execute(db);
|
|
39
|
+
}
|
|
40
|
+
}
|
|
41
|
+
|
|
42
|
+
export async function down(db: Kysely<unknown>): Promise<void> {
|
|
43
|
+
const tables = await db
|
|
44
|
+
// eslint-disable-next-line typescript-eslint(no-unsafe-type-assertion) -- Kysely migration runs against unknown schema
|
|
45
|
+
.selectFrom("_emdash_collections" as never)
|
|
46
|
+
// eslint-disable-next-line typescript-eslint(no-unsafe-type-assertion) -- Kysely migration runs against unknown schema
|
|
47
|
+
.select("slug" as never)
|
|
48
|
+
.execute();
|
|
49
|
+
|
|
50
|
+
// eslint-disable-next-line typescript-eslint(no-unsafe-type-assertion) -- Kysely execute returns unknown[]; narrowing to known shape
|
|
51
|
+
for (const row of tables as Array<{ slug: string }>) {
|
|
52
|
+
const tableName = `ec_${row.slug}`;
|
|
53
|
+
|
|
54
|
+
await sql`
|
|
55
|
+
DROP INDEX IF EXISTS ${sql.ref(`idx_${row.slug}_draft_revision`)}
|
|
56
|
+
`.execute(db);
|
|
57
|
+
|
|
58
|
+
await sql`
|
|
59
|
+
DROP INDEX IF EXISTS ${sql.ref(`idx_${row.slug}_live_revision`)}
|
|
60
|
+
`.execute(db);
|
|
61
|
+
|
|
62
|
+
await sql`
|
|
63
|
+
ALTER TABLE ${sql.ref(tableName)}
|
|
64
|
+
DROP COLUMN draft_revision_id
|
|
65
|
+
`.execute(db);
|
|
66
|
+
|
|
67
|
+
await sql`
|
|
68
|
+
ALTER TABLE ${sql.ref(tableName)}
|
|
69
|
+
DROP COLUMN live_revision_id
|
|
70
|
+
`.execute(db);
|
|
71
|
+
}
|
|
72
|
+
}
|
|
@@ -0,0 +1,82 @@
|
|
|
1
|
+
import type { Kysely } from "kysely";
|
|
2
|
+
import { sql } from "kysely";
|
|
3
|
+
|
|
4
|
+
import { listTablesLike } from "../dialect-helpers.js";
|
|
5
|
+
|
|
6
|
+
/**
|
|
7
|
+
* Add performance indexes for common query patterns.
|
|
8
|
+
*
|
|
9
|
+
* Covers:
|
|
10
|
+
* 1. Media table: mime_type, filename, created_at
|
|
11
|
+
* 2. content_taxonomies: reverse lookup by taxonomy_id
|
|
12
|
+
* 3. taxonomies: parent_id FK
|
|
13
|
+
* 4. audit_logs: compound (resource_type, resource_id)
|
|
14
|
+
* 5. Retroactive author_id + updated_at on existing ec_* content tables
|
|
15
|
+
* (new tables get these from createContentTable() in registry.ts)
|
|
16
|
+
*/
|
|
17
|
+
export async function up(db: Kysely<unknown>): Promise<void> {
|
|
18
|
+
// ── Media indexes ────────────────────────────────────────────────
|
|
19
|
+
await db.schema.createIndex("idx_media_mime_type").on("media").column("mime_type").execute();
|
|
20
|
+
await db.schema.createIndex("idx_media_filename").on("media").column("filename").execute();
|
|
21
|
+
await db.schema.createIndex("idx_media_created_at").on("media").column("created_at").execute();
|
|
22
|
+
|
|
23
|
+
// ── Taxonomy indexes ─────────────────────────────────────────────
|
|
24
|
+
// Reverse lookup: find entries with a specific term
|
|
25
|
+
await db.schema
|
|
26
|
+
.createIndex("idx_content_taxonomies_term")
|
|
27
|
+
.on("content_taxonomies")
|
|
28
|
+
.column("taxonomy_id")
|
|
29
|
+
.execute();
|
|
30
|
+
|
|
31
|
+
// Hierarchical queries filter on parent_id FK
|
|
32
|
+
await db.schema
|
|
33
|
+
.createIndex("idx_taxonomies_parent")
|
|
34
|
+
.on("taxonomies")
|
|
35
|
+
.column("parent_id")
|
|
36
|
+
.execute();
|
|
37
|
+
|
|
38
|
+
// ── Audit log indexes ────────────────────────────────────────────
|
|
39
|
+
// findByResource() compound query
|
|
40
|
+
await db.schema
|
|
41
|
+
.createIndex("idx_audit_resource")
|
|
42
|
+
.on("audit_logs")
|
|
43
|
+
.columns(["resource_type", "resource_id"])
|
|
44
|
+
.execute();
|
|
45
|
+
|
|
46
|
+
// ── Retroactive content table indexes ────────────────────────────
|
|
47
|
+
// Add author_id and updated_at indexes to all existing ec_* tables.
|
|
48
|
+
// New tables created after this migration get these from createContentTable().
|
|
49
|
+
const tableNames = await listTablesLike(db, "ec_%");
|
|
50
|
+
|
|
51
|
+
for (const tableName of tableNames) {
|
|
52
|
+
const table = { name: tableName };
|
|
53
|
+
await sql`
|
|
54
|
+
CREATE INDEX ${sql.ref(`idx_${table.name}_author`)}
|
|
55
|
+
ON ${sql.ref(table.name)} (author_id)
|
|
56
|
+
`.execute(db);
|
|
57
|
+
|
|
58
|
+
await sql`
|
|
59
|
+
CREATE INDEX ${sql.ref(`idx_${table.name}_updated`)}
|
|
60
|
+
ON ${sql.ref(table.name)} (updated_at)
|
|
61
|
+
`.execute(db);
|
|
62
|
+
}
|
|
63
|
+
}
|
|
64
|
+
|
|
65
|
+
export async function down(db: Kysely<unknown>): Promise<void> {
|
|
66
|
+
// Drop retroactive content table indexes
|
|
67
|
+
const tableNames = await listTablesLike(db, "ec_%");
|
|
68
|
+
|
|
69
|
+
for (const tableName of tableNames) {
|
|
70
|
+
const table = { name: tableName };
|
|
71
|
+
await sql`DROP INDEX IF EXISTS ${sql.ref(`idx_${table.name}_updated`)}`.execute(db);
|
|
72
|
+
await sql`DROP INDEX IF EXISTS ${sql.ref(`idx_${table.name}_author`)}`.execute(db);
|
|
73
|
+
}
|
|
74
|
+
|
|
75
|
+
// Drop system table indexes
|
|
76
|
+
await db.schema.dropIndex("idx_audit_resource").execute();
|
|
77
|
+
await db.schema.dropIndex("idx_taxonomies_parent").execute();
|
|
78
|
+
await db.schema.dropIndex("idx_content_taxonomies_term").execute();
|
|
79
|
+
await db.schema.dropIndex("idx_media_created_at").execute();
|
|
80
|
+
await db.schema.dropIndex("idx_media_filename").execute();
|
|
81
|
+
await db.schema.dropIndex("idx_media_mime_type").execute();
|
|
82
|
+
}
|
|
@@ -0,0 +1,89 @@
|
|
|
1
|
+
import type { Kysely } from "kysely";
|
|
2
|
+
|
|
3
|
+
import { currentTimestamp } from "../dialect-helpers.js";
|
|
4
|
+
|
|
5
|
+
/**
|
|
6
|
+
* API token tables for programmatic access.
|
|
7
|
+
*
|
|
8
|
+
* Three tables:
|
|
9
|
+
* 1. _emdash_api_tokens — Personal Access Tokens (ec_pat_...)
|
|
10
|
+
* 2. _emdash_oauth_tokens — OAuth access/refresh tokens (ec_oat_/ec_ort_...)
|
|
11
|
+
* 3. _emdash_device_codes — OAuth Device Flow state (RFC 8628)
|
|
12
|
+
*/
|
|
13
|
+
export async function up(db: Kysely<unknown>): Promise<void> {
|
|
14
|
+
// ── Personal Access Tokens ───────────────────────────────────────
|
|
15
|
+
await db.schema
|
|
16
|
+
.createTable("_emdash_api_tokens")
|
|
17
|
+
.addColumn("id", "text", (col) => col.primaryKey())
|
|
18
|
+
.addColumn("name", "text", (col) => col.notNull())
|
|
19
|
+
.addColumn("token_hash", "text", (col) => col.notNull().unique())
|
|
20
|
+
.addColumn("prefix", "text", (col) => col.notNull())
|
|
21
|
+
.addColumn("user_id", "text", (col) => col.notNull())
|
|
22
|
+
.addColumn("scopes", "text", (col) => col.notNull()) // JSON array
|
|
23
|
+
.addColumn("expires_at", "text") // null = no expiry
|
|
24
|
+
.addColumn("last_used_at", "text")
|
|
25
|
+
.addColumn("created_at", "text", (col) => col.defaultTo(currentTimestamp(db)))
|
|
26
|
+
.addForeignKeyConstraint("api_tokens_user_fk", ["user_id"], "users", ["id"], (cb) =>
|
|
27
|
+
cb.onDelete("cascade"),
|
|
28
|
+
)
|
|
29
|
+
.execute();
|
|
30
|
+
|
|
31
|
+
await db.schema
|
|
32
|
+
.createIndex("idx_api_tokens_token_hash")
|
|
33
|
+
.on("_emdash_api_tokens")
|
|
34
|
+
.column("token_hash")
|
|
35
|
+
.execute();
|
|
36
|
+
|
|
37
|
+
await db.schema
|
|
38
|
+
.createIndex("idx_api_tokens_user_id")
|
|
39
|
+
.on("_emdash_api_tokens")
|
|
40
|
+
.column("user_id")
|
|
41
|
+
.execute();
|
|
42
|
+
|
|
43
|
+
// ── OAuth Tokens ─────────────────────────────────────────────────
|
|
44
|
+
await db.schema
|
|
45
|
+
.createTable("_emdash_oauth_tokens")
|
|
46
|
+
.addColumn("token_hash", "text", (col) => col.primaryKey())
|
|
47
|
+
.addColumn("token_type", "text", (col) => col.notNull()) // 'access' | 'refresh'
|
|
48
|
+
.addColumn("user_id", "text", (col) => col.notNull())
|
|
49
|
+
.addColumn("scopes", "text", (col) => col.notNull()) // JSON array
|
|
50
|
+
.addColumn("client_type", "text", (col) => col.notNull().defaultTo("cli"))
|
|
51
|
+
.addColumn("expires_at", "text", (col) => col.notNull())
|
|
52
|
+
.addColumn("refresh_token_hash", "text") // links access → refresh
|
|
53
|
+
.addColumn("created_at", "text", (col) => col.defaultTo(currentTimestamp(db)))
|
|
54
|
+
.addForeignKeyConstraint("oauth_tokens_user_fk", ["user_id"], "users", ["id"], (cb) =>
|
|
55
|
+
cb.onDelete("cascade"),
|
|
56
|
+
)
|
|
57
|
+
.execute();
|
|
58
|
+
|
|
59
|
+
await db.schema
|
|
60
|
+
.createIndex("idx_oauth_tokens_user_id")
|
|
61
|
+
.on("_emdash_oauth_tokens")
|
|
62
|
+
.column("user_id")
|
|
63
|
+
.execute();
|
|
64
|
+
|
|
65
|
+
await db.schema
|
|
66
|
+
.createIndex("idx_oauth_tokens_expires")
|
|
67
|
+
.on("_emdash_oauth_tokens")
|
|
68
|
+
.column("expires_at")
|
|
69
|
+
.execute();
|
|
70
|
+
|
|
71
|
+
// ── Device Codes (OAuth Device Flow, RFC 8628) ───────────────────
|
|
72
|
+
await db.schema
|
|
73
|
+
.createTable("_emdash_device_codes")
|
|
74
|
+
.addColumn("device_code", "text", (col) => col.primaryKey())
|
|
75
|
+
.addColumn("user_code", "text", (col) => col.notNull().unique())
|
|
76
|
+
.addColumn("scopes", "text", (col) => col.notNull()) // JSON array
|
|
77
|
+
.addColumn("user_id", "text") // set when user authorizes
|
|
78
|
+
.addColumn("status", "text", (col) => col.notNull().defaultTo("pending"))
|
|
79
|
+
.addColumn("expires_at", "text", (col) => col.notNull())
|
|
80
|
+
.addColumn("interval", "integer", (col) => col.notNull().defaultTo(5))
|
|
81
|
+
.addColumn("created_at", "text", (col) => col.defaultTo(currentTimestamp(db)))
|
|
82
|
+
.execute();
|
|
83
|
+
}
|
|
84
|
+
|
|
85
|
+
export async function down(db: Kysely<unknown>): Promise<void> {
|
|
86
|
+
await db.schema.dropTable("_emdash_device_codes").execute();
|
|
87
|
+
await db.schema.dropTable("_emdash_oauth_tokens").execute();
|
|
88
|
+
await db.schema.dropTable("_emdash_api_tokens").execute();
|
|
89
|
+
}
|
|
@@ -0,0 +1,45 @@
|
|
|
1
|
+
import type { Kysely } from "kysely";
|
|
2
|
+
import { sql } from "kysely";
|
|
3
|
+
|
|
4
|
+
import { currentTimestamp } from "../dialect-helpers.js";
|
|
5
|
+
|
|
6
|
+
/**
|
|
7
|
+
* Authorization codes for OAuth 2.1 Authorization Code + PKCE flow.
|
|
8
|
+
*
|
|
9
|
+
* Used by MCP clients (Claude Desktop, VS Code, etc.) to authenticate
|
|
10
|
+
* via the standard OAuth authorization code grant.
|
|
11
|
+
*
|
|
12
|
+
* Also adds client_id tracking to oauth_tokens for per-client revocation.
|
|
13
|
+
*/
|
|
14
|
+
export async function up(db: Kysely<unknown>): Promise<void> {
|
|
15
|
+
await db.schema
|
|
16
|
+
.createTable("_emdash_authorization_codes")
|
|
17
|
+
.addColumn("code_hash", "text", (col) => col.primaryKey()) // SHA-256 hash of authorization code
|
|
18
|
+
.addColumn("client_id", "text", (col) => col.notNull()) // CIMD URL or opaque string
|
|
19
|
+
.addColumn("redirect_uri", "text", (col) => col.notNull()) // Must match exactly on exchange
|
|
20
|
+
.addColumn("user_id", "text", (col) => col.notNull())
|
|
21
|
+
.addColumn("scopes", "text", (col) => col.notNull()) // JSON array
|
|
22
|
+
.addColumn("code_challenge", "text", (col) => col.notNull()) // S256 challenge
|
|
23
|
+
.addColumn("code_challenge_method", "text", (col) => col.notNull().defaultTo("S256"))
|
|
24
|
+
.addColumn("resource", "text") // RFC 8707 resource indicator
|
|
25
|
+
.addColumn("expires_at", "text", (col) => col.notNull())
|
|
26
|
+
.addColumn("created_at", "text", (col) => col.defaultTo(currentTimestamp(db)))
|
|
27
|
+
.addForeignKeyConstraint("auth_codes_user_fk", ["user_id"], "users", ["id"], (cb) =>
|
|
28
|
+
cb.onDelete("cascade"),
|
|
29
|
+
)
|
|
30
|
+
.execute();
|
|
31
|
+
|
|
32
|
+
await db.schema
|
|
33
|
+
.createIndex("idx_auth_codes_expires")
|
|
34
|
+
.on("_emdash_authorization_codes")
|
|
35
|
+
.column("expires_at")
|
|
36
|
+
.execute();
|
|
37
|
+
|
|
38
|
+
// Track which client obtained a token (for per-client revocation)
|
|
39
|
+
await sql`ALTER TABLE _emdash_oauth_tokens ADD COLUMN client_id TEXT`.execute(db);
|
|
40
|
+
}
|
|
41
|
+
|
|
42
|
+
export async function down(db: Kysely<unknown>): Promise<void> {
|
|
43
|
+
await db.schema.dropTable("_emdash_authorization_codes").execute();
|
|
44
|
+
// SQLite doesn't support DROP COLUMN, but this is only for dev rollback
|
|
45
|
+
}
|