dineway 0.1.4 → 0.1.5
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +6 -3
- package/dist/{apply-CAPvMfoU.mjs → apply-iVSqz2qs.mjs} +132 -39
- package/dist/astro/index.d.mts +18 -9
- package/dist/astro/index.mjs +238 -16
- package/dist/astro/middleware/auth.d.mts +16 -5
- package/dist/astro/middleware/auth.mjs +74 -37
- package/dist/astro/middleware/redirect.mjs +24 -8
- package/dist/astro/middleware/request-context.mjs +18 -5
- package/dist/astro/middleware/setup.mjs +1 -1
- package/dist/astro/middleware.mjs +411 -169
- package/dist/astro/types.d.mts +25 -8
- package/dist/{byline-DeWCMU_i.mjs → byline-OhH2dlRu.mjs} +6 -21
- package/dist/{bylines-DyqBV9EQ.mjs → bylines-BGpD9_hy.mjs} +16 -6
- package/dist/cache-BdSY-gQN.mjs +42 -0
- package/dist/chunks--4F8ddV4.mjs +18 -0
- package/dist/cli/index.mjs +935 -15
- package/dist/client/external-auth-headers.d.mts +1 -1
- package/dist/client/index.d.mts +11 -3
- package/dist/client/index.mjs +4 -3
- package/dist/{connection-C9pxzuag.mjs → connection-BCNICDWN.mjs} +22 -5
- package/dist/{content-zSgdNmnt.mjs → content-DWi4d0rT.mjs} +41 -2
- package/dist/database/instrumentation.d.mts +34 -0
- package/dist/database/instrumentation.mjs +53 -0
- package/dist/db/index.d.mts +3 -3
- package/dist/db/index.mjs +2 -2
- package/dist/db/libsql.d.mts +1 -1
- package/dist/db/libsql.mjs +11 -5
- package/dist/db/postgres.d.mts +1 -1
- package/dist/db/sqlite.d.mts +1 -1
- package/dist/db/sqlite.mjs +7 -1
- package/dist/db-errors-CEqD7qH9.mjs +23 -0
- package/dist/{default-WYlzADZL.mjs → default-VjJyuuG9.mjs} +2 -0
- package/dist/{dialect-helpers-B9uSp2GJ.mjs → dialect-helpers-DhTzaUxP.mjs} +3 -0
- package/dist/{error-DrxtnGPg.mjs → error-BmL6QipT.mjs} +7 -3
- package/dist/{index-C-jx21qs.d.mts → index-yvc6E_17.d.mts} +157 -30
- package/dist/index.d.mts +11 -11
- package/dist/index.mjs +24 -22
- package/dist/{loader-qKmo0wAY.mjs → loader-sMG4TZ-u.mjs} +9 -3
- 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/page/index.d.mts +10 -2
- package/dist/page/index.mjs +22 -1
- package/dist/patterns-CrCYkMBb.mjs +92 -0
- package/dist/{placeholder-bOx1xCTY.d.mts → placeholder--wOi4TbO.d.mts} +1 -1
- package/dist/{placeholder-B3knXwNc.mjs → placeholder-Cp8g5Emj.mjs} +1 -1
- package/dist/plugins/adapt-sandbox-entry.d.mts +5 -5
- package/dist/plugins/adapt-sandbox-entry.mjs +1 -1
- package/dist/{query-BiaPl_g2.mjs → query-kDmwCsHh.mjs} +118 -50
- package/dist/{redirect-JPqLAbxa.mjs → redirect-DnEWAkVg.mjs} +43 -99
- package/dist/{registry-DSd1GWB8.mjs → registry-C0zjeB9P.mjs} +191 -123
- package/dist/request-cache-Dk5qPSOx.mjs +66 -0
- package/dist/request-context.d.mts +4 -16
- package/dist/{runner-B5l1JfOj.d.mts → runner-CFI6B6J2.d.mts} +1 -1
- package/dist/{runner-BGUGywgG.mjs → runner-DWZm2KQm.mjs} +589 -137
- package/dist/runtime.d.mts +6 -6
- package/dist/runtime.mjs +2 -2
- package/dist/{search-BNruJHDL.mjs → search-ByRGV2pq.mjs} +570 -424
- package/dist/seed/index.d.mts +2 -2
- package/dist/seed/index.mjs +11 -10
- 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 +11 -3
- package/dist/storage/s3.mjs +78 -15
- package/dist/taxonomies-1s5PaS_8.mjs +266 -0
- package/dist/transaction-Cn2rjY78.mjs +27 -0
- package/dist/{types-BgQeVaPj.d.mts → types-BuMDPy5C.d.mts} +52 -3
- package/dist/{types-DuNbGKjF.mjs → types-COeOq9nK.mjs} +6 -1
- package/dist/{types-ju-_ORz7.d.mts → types-CWbdtiux.d.mts} +13 -5
- package/dist/{types-D38djUXv.d.mts → types-Cj0KMIZV.d.mts} +16 -3
- package/dist/{types-DkvMXalq.d.mts → types-DOrVigru.d.mts} +159 -0
- package/dist/{validate-CXnRKfJK.mjs → validate-BZ5wnLLp.mjs} +2 -1
- package/dist/{validate-DVKJJ-M_.d.mts → validate-IPf8n4Fj.d.mts} +4 -51
- package/dist/{validate-CqRJb_xU.mjs → validate-VPnKoIzW.mjs} +10 -10
- package/dist/version-BKXPsfmJ.mjs +6 -0
- package/package.json +49 -38
- package/src/astro/routes/admin.astro +25 -9
- package/src/astro/routes/api/admin/api-tokens/[id].ts +4 -0
- package/src/astro/routes/api/admin/api-tokens/index.ts +24 -2
- package/src/astro/routes/api/admin/briefing.ts +76 -0
- package/src/astro/routes/api/admin/bylines/[id]/index.ts +3 -0
- package/src/astro/routes/api/admin/bylines/index.ts +2 -0
- package/src/astro/routes/api/admin/context/[id]/history.ts +35 -0
- package/src/astro/routes/api/admin/context/[id]/index.ts +35 -0
- package/src/astro/routes/api/admin/context/[id]/review.ts +57 -0
- package/src/astro/routes/api/admin/context/[id]/supersede.ts +58 -0
- package/src/astro/routes/api/admin/context/diff.ts +35 -0
- package/src/astro/routes/api/admin/context/index.ts +69 -0
- package/src/astro/routes/api/admin/context/stale.ts +35 -0
- package/src/astro/routes/api/admin/hitl-requests/[id]/index.ts +38 -0
- package/src/astro/routes/api/admin/hitl-requests/[id]/resolve.ts +54 -0
- package/src/astro/routes/api/admin/hitl-requests/index.ts +38 -0
- package/src/astro/routes/api/admin/hooks/exclusive/[hookName].ts +58 -17
- package/src/astro/routes/api/admin/oauth-clients/[id].ts +28 -1
- package/src/astro/routes/api/admin/oauth-clients/index.ts +25 -1
- package/src/astro/routes/api/admin/plugins/[id]/disable.ts +54 -2
- package/src/astro/routes/api/admin/plugins/[id]/enable.ts +54 -2
- package/src/astro/routes/api/admin/plugins/[id]/uninstall.ts +51 -1
- package/src/astro/routes/api/admin/plugins/[id]/update.ts +98 -3
- package/src/astro/routes/api/admin/plugins/marketplace/[id]/install.ts +72 -1
- package/src/astro/routes/api/admin/review-requests/[id]/index.ts +35 -0
- package/src/astro/routes/api/admin/review-requests/[id]/resolve.ts +52 -0
- package/src/astro/routes/api/admin/review-requests/index.ts +35 -0
- package/src/astro/routes/api/admin/users/[id]/disable.ts +26 -23
- package/src/astro/routes/api/admin/users/[id]/index.ts +41 -21
- package/src/astro/routes/api/auth/invite/register-options.ts +73 -0
- package/src/astro/routes/api/auth/magic-link/send.ts +2 -1
- package/src/astro/routes/api/auth/passkey/options.ts +2 -1
- package/src/astro/routes/api/auth/passkey/verify.ts +5 -1
- package/src/astro/routes/api/auth/signup/request.ts +20 -8
- package/src/astro/routes/api/comments/[collection]/[contentId]/index.ts +3 -4
- package/src/astro/routes/api/content/[collection]/[id]/compare.ts +1 -1
- package/src/astro/routes/api/content/[collection]/[id]/discard-draft.ts +16 -2
- package/src/astro/routes/api/content/[collection]/[id]/duplicate.ts +16 -0
- package/src/astro/routes/api/content/[collection]/[id]/permanent.ts +9 -0
- package/src/astro/routes/api/content/[collection]/[id]/preview-url.ts +1 -1
- package/src/astro/routes/api/content/[collection]/[id]/publish.ts +45 -1
- package/src/astro/routes/api/content/[collection]/[id]/restore.ts +12 -2
- package/src/astro/routes/api/content/[collection]/[id]/revisions.ts +1 -1
- package/src/astro/routes/api/content/[collection]/[id]/schedule.ts +24 -0
- package/src/astro/routes/api/content/[collection]/[id]/terms/[taxonomy].ts +3 -0
- package/src/astro/routes/api/content/[collection]/[id]/translations.ts +20 -0
- package/src/astro/routes/api/content/[collection]/[id]/unpublish.ts +13 -0
- package/src/astro/routes/api/content/[collection]/[id].ts +36 -0
- package/src/astro/routes/api/content/[collection]/index.ts +48 -4
- package/src/astro/routes/api/content/[collection]/trash.ts +1 -1
- package/src/astro/routes/api/health.ts +54 -0
- package/src/astro/routes/api/import/wordpress/analyze.ts +2 -10
- package/src/astro/routes/api/import/wordpress/execute.ts +40 -6
- package/src/astro/routes/api/import/wordpress/prepare.ts +36 -5
- package/src/astro/routes/api/import/wordpress/rewrite-urls.ts +33 -1
- package/src/astro/routes/api/import/wordpress-plugin/analyze.ts +3 -3
- package/src/astro/routes/api/import/wordpress-plugin/execute.ts +57 -15
- package/src/astro/routes/api/manifest.ts +13 -1
- package/src/astro/routes/api/mcp.ts +1 -0
- package/src/astro/routes/api/media/providers/[providerId]/[itemId].ts +7 -2
- package/src/astro/routes/api/media/upload-url.ts +11 -2
- package/src/astro/routes/api/media.ts +9 -7
- package/src/astro/routes/api/menus/[name]/items.ts +124 -5
- package/src/astro/routes/api/menus/[name]/reorder.ts +47 -1
- package/src/astro/routes/api/menus/[name].ts +84 -4
- package/src/astro/routes/api/menus/index.ts +46 -2
- package/src/astro/routes/api/oauth/authorize.ts +21 -8
- package/src/astro/routes/api/oauth/device/code.ts +2 -1
- package/src/astro/routes/api/oauth/device/token.ts +2 -1
- package/src/astro/routes/api/oauth/register.ts +182 -0
- package/src/astro/routes/api/oauth/token.ts +18 -7
- package/src/astro/routes/api/openapi.json.ts +3 -2
- package/src/astro/routes/api/plugins/[pluginId]/[...path].ts +21 -4
- package/src/astro/routes/api/redirects/[id].ts +103 -4
- package/src/astro/routes/api/redirects/index.ts +50 -2
- package/src/astro/routes/api/schema/collections/[slug]/fields/[fieldSlug].ts +28 -0
- package/src/astro/routes/api/schema/collections/[slug]/fields/index.ts +15 -0
- package/src/astro/routes/api/schema/collections/[slug]/fields/reorder.ts +13 -0
- package/src/astro/routes/api/schema/collections/[slug]/index.ts +27 -0
- package/src/astro/routes/api/schema/collections/index.ts +14 -0
- package/src/astro/routes/api/search/index.ts +1 -0
- package/src/astro/routes/api/search/suggest.ts +1 -0
- package/src/astro/routes/api/sections/[slug].ts +123 -4
- package/src/astro/routes/api/sections/index.ts +57 -2
- package/src/astro/routes/api/settings.ts +51 -2
- package/src/astro/routes/api/setup/admin-verify.ts +25 -5
- package/src/astro/routes/api/setup/admin.ts +16 -8
- package/src/astro/routes/api/setup/index.ts +3 -2
- package/src/astro/routes/api/taxonomies/[name]/terms/[slug].ts +141 -4
- package/src/astro/routes/api/taxonomies/[name]/terms/index.ts +64 -2
- package/src/astro/routes/api/taxonomies/index.ts +57 -2
- package/src/astro/routes/api/well-known/auth.ts +3 -1
- package/src/astro/routes/api/well-known/oauth-authorization-server.ts +8 -5
- package/src/astro/routes/api/well-known/oauth-protected-resource.ts +3 -2
- package/src/astro/routes/api/widget-areas/[name]/reorder.ts +58 -16
- package/src/astro/routes/api/widget-areas/[name]/widgets/[id].ts +124 -38
- package/src/astro/routes/api/widget-areas/[name]/widgets.ts +66 -20
- package/src/astro/routes/api/widget-areas/[name].ts +55 -7
- package/src/astro/routes/api/widget-areas/index.ts +56 -6
- package/src/components/DinewayHead.astro +15 -7
- package/src/components/DinewayMedia.astro +1 -1
- package/src/components/InlinePortableTextEditor.tsx +1 -1
- package/src/components/Table.astro +68 -41
- package/src/components/index.ts +2 -12
- package/src/components/marks.ts +19 -0
- package/LICENSE +0 -9
- /package/dist/{adapters-BlzWJG82.d.mts → adapters-C2ypTrZZ.d.mts} +0 -0
- /package/dist/{config-Cq8H0SfX.mjs → config-BXwuX8Bx.mjs} +0 -0
- /package/dist/{load-C6FCD1FU.mjs → load-Coc9HpHH.mjs} +0 -0
- /package/dist/{manifest-schema-CTSEyIJ3.mjs → manifest-schema-D1MSVnoI.mjs} +0 -0
- /package/dist/{mode-BlyYtIFO.mjs → mode-47goXBBK.mjs} +0 -0
- /package/dist/{tokens-4vgYuXsZ.mjs → tokens-CJz9ubV6.mjs} +0 -0
- /package/dist/{transport-C5FYnid7.mjs → transport-DB5eDN4x.mjs} +0 -0
- /package/dist/{transport-gIL-e43D.d.mts → transport-Wge_IzKl.d.mts} +0 -0
- /package/dist/{types-CLLdsG3g.d.mts → types-BzcUjoqg.d.mts} +0 -0
- /package/dist/{types-DShnjzb6.mjs → types-griIBQOQ.mjs} +0 -0
|
@@ -1,26 +1,31 @@
|
|
|
1
|
-
import "../
|
|
2
|
-
import {
|
|
3
|
-
import
|
|
4
|
-
import {
|
|
5
|
-
import {
|
|
1
|
+
import { getRequestContext, runWithContext } from "../request-context.mjs";
|
|
2
|
+
import { createRecorder, flushRecorder, formatServerTimingHeader, isInstrumentationEnabled, isServerTimingEnabled, kyselyLogOption } from "../database/instrumentation.mjs";
|
|
3
|
+
import "../connection-BCNICDWN.mjs";
|
|
4
|
+
import { t as validateIdentifier } from "../validate-VPnKoIzW.mjs";
|
|
5
|
+
import { a as isSqlite } from "../dialect-helpers-DhTzaUxP.mjs";
|
|
6
|
+
import { r as runMigrations } from "../runner-DWZm2KQm.mjs";
|
|
7
|
+
import { $t as validateRev, B as DEV_CONSOLE_EMAIL_PLUGIN_ID, Bt as handleContentDuplicate, Ct as handleMediaDelete, Dt as handleRevisionGet, Et as handleMediaUpdate, Ft as handleContentCountScheduled, G as resolveExclusiveHooks, Gt as handleContentPermanentDelete, H as EmailPipeline, Ht as handleContentGetIncludingTrashed, It as handleContentCountTrashed, J as sanitizeHeadersForSandbox, Jt as handleContentSchedule, K as CronExecutor, Kt as handleContentPublish, Lt as handleContentCreate, Mt as hashString, Nt as PluginStateRepository, Ot as handleRevisionList, Pt as handleContentCompare, Qt as handleContentUpdate, Rt as handleContentDelete, St as handleMediaCreate, Tt as handleMediaList, Ut as handleContentList, V as devConsoleEmailDeliver, Vt as handleContentGet, W as createHookPipeline, Wt as handleContentListTrashed, X as definePlugin, Xt as handleContentUnpublish, Y as getTrustedProxyHeaders, Yt as handleContentTranslations, Zt as handleContentUnschedule, kt as handleRevisionRestore, pt as after, q as extractRequestMeta, qt as handleContentRestore, vt as createPluginBundleStore, wt as handleMediaGet, z as PluginRouteRegistry, zt as handleContentDiscardDraft } from "../search-ByRGV2pq.mjs";
|
|
8
|
+
import { r as RevisionRepository } from "../content-DWi4d0rT.mjs";
|
|
6
9
|
import "../base64-F8-DUraK.mjs";
|
|
7
10
|
import "../types-BawVha09.mjs";
|
|
8
11
|
import { t as MediaRepository } from "../media-DMTr80Gv.mjs";
|
|
9
|
-
import {
|
|
10
|
-
import
|
|
11
|
-
import "../
|
|
12
|
-
import "../
|
|
13
|
-
import {
|
|
14
|
-
import { i as
|
|
15
|
-
import {
|
|
16
|
-
import
|
|
17
|
-
import {
|
|
18
|
-
import "../
|
|
19
|
-
import "../
|
|
20
|
-
import "../
|
|
21
|
-
import "../
|
|
12
|
+
import { p as OptionsRepository } from "../apply-iVSqz2qs.mjs";
|
|
13
|
+
import "../redirect-DnEWAkVg.mjs";
|
|
14
|
+
import "../byline-OhH2dlRu.mjs";
|
|
15
|
+
import { n as normalizeMediaValue } from "../placeholder-Cp8g5Emj.mjs";
|
|
16
|
+
import { i as setI18nConfig } from "../config-BXwuX8Bx.mjs";
|
|
17
|
+
import { i as FTSManager, n as SchemaRegistry } from "../registry-C0zjeB9P.mjs";
|
|
18
|
+
import { n as getDb } from "../loader-sMG4TZ-u.mjs";
|
|
19
|
+
import "../request-cache-Dk5qPSOx.mjs";
|
|
20
|
+
import { n as VERSION, t as COMMIT } from "../version-BKXPsfmJ.mjs";
|
|
21
|
+
import "../taxonomies-1s5PaS_8.mjs";
|
|
22
|
+
import { r as normalizeManifestRoute } from "../manifest-schema-D1MSVnoI.mjs";
|
|
23
|
+
import { a as invalidateUrlPatternCache } from "../query-kDmwCsHh.mjs";
|
|
24
|
+
import "../tokens-CJz9ubV6.mjs";
|
|
25
|
+
import "../bylines-BGpD9_hy.mjs";
|
|
26
|
+
import "../load-Coc9HpHH.mjs";
|
|
22
27
|
import "../index.mjs";
|
|
23
|
-
import { t as getAuthMode } from "../mode-
|
|
28
|
+
import { t as getAuthMode } from "../mode-47goXBBK.mjs";
|
|
24
29
|
import { Kysely, sql } from "kysely";
|
|
25
30
|
import { defineMiddleware } from "astro:middleware";
|
|
26
31
|
import virtualConfig from "virtual:dineway/config";
|
|
@@ -32,6 +37,14 @@ import { sandboxedPlugins } from "virtual:dineway/sandboxed-plugins";
|
|
|
32
37
|
import { createStorage } from "virtual:dineway/storage";
|
|
33
38
|
import { createKyselyAdapter } from "@dineway-ai/auth/adapters/kysely";
|
|
34
39
|
|
|
40
|
+
//#region src/site-context/experimental-workflows.ts
|
|
41
|
+
const EXPERIMENTAL_SITE_CONTEXT_WORKFLOWS_ENV = "DINEWAY_EXPERIMENTAL_SITE_CONTEXT_WORKFLOWS";
|
|
42
|
+
function experimentalSiteContextWorkflowsEnabled() {
|
|
43
|
+
const value = process.env[EXPERIMENTAL_SITE_CONTEXT_WORKFLOWS_ENV];
|
|
44
|
+
return value === "1" || value === "true";
|
|
45
|
+
}
|
|
46
|
+
|
|
47
|
+
//#endregion
|
|
35
48
|
//#region src/auth/challenge-store.ts
|
|
36
49
|
/**
|
|
37
50
|
* Clean up expired challenges.
|
|
@@ -118,10 +131,10 @@ async function runSystemCleanup(db, storage) {
|
|
|
118
131
|
*/
|
|
119
132
|
async function pruneExcessiveRevisions(db) {
|
|
120
133
|
const entries = await sql`
|
|
121
|
-
SELECT collection, entry_id
|
|
134
|
+
SELECT collection, entry_id
|
|
122
135
|
FROM revisions
|
|
123
136
|
GROUP BY collection, entry_id
|
|
124
|
-
HAVING
|
|
137
|
+
HAVING COUNT(*) > ${REVISION_PRUNE_THRESHOLD}
|
|
125
138
|
`.execute(db);
|
|
126
139
|
if (entries.rows.length === 0) return 0;
|
|
127
140
|
const revisionRepo = new RevisionRepository(db);
|
|
@@ -301,6 +314,8 @@ function shouldUsePiggybackScheduler(createTimer = () => globalThis.setTimeout((
|
|
|
301
314
|
|
|
302
315
|
//#endregion
|
|
303
316
|
//#region src/dineway-runtime.ts
|
|
317
|
+
const MANIFEST_CACHE_OPTION = "dineway:manifest_cache";
|
|
318
|
+
const MANIFEST_CACHE_SCHEMA_VERSION = "dineway-manifest-cache-v1";
|
|
304
319
|
const LEADING_SLASH_PATTERN = /^\//;
|
|
305
320
|
const VALID_METADATA_KINDS = new Set([
|
|
306
321
|
"meta",
|
|
@@ -314,6 +329,7 @@ const VALID_LINK_REL = new Set([
|
|
|
314
329
|
"alternate",
|
|
315
330
|
"author",
|
|
316
331
|
"license",
|
|
332
|
+
"nlweb",
|
|
317
333
|
"site.standard.document"
|
|
318
334
|
]);
|
|
319
335
|
/**
|
|
@@ -349,12 +365,48 @@ function parseStringArray(value) {
|
|
|
349
365
|
return [];
|
|
350
366
|
}
|
|
351
367
|
}
|
|
368
|
+
function isRecord(value) {
|
|
369
|
+
return !!value && typeof value === "object";
|
|
370
|
+
}
|
|
371
|
+
function isPersistedManifestCache(value) {
|
|
372
|
+
if (!isRecord(value)) return false;
|
|
373
|
+
if (typeof value.key !== "string") return false;
|
|
374
|
+
if (!isRecord(value.manifest)) return false;
|
|
375
|
+
const manifest = value.manifest;
|
|
376
|
+
return typeof manifest.version === "string" && (typeof manifest.commit === "undefined" || typeof manifest.commit === "string") && typeof manifest.hash === "string" && !!manifest.collections && typeof manifest.collections === "object" && !!manifest.plugins && typeof manifest.plugins === "object" && isRecord(manifest.features) && typeof manifest.features.siteContextWorkflows === "boolean";
|
|
377
|
+
}
|
|
378
|
+
function serializeAdminBranding(config) {
|
|
379
|
+
const admin = config.admin;
|
|
380
|
+
if (!admin) return "";
|
|
381
|
+
return JSON.stringify({
|
|
382
|
+
logo: admin.logo ?? "",
|
|
383
|
+
siteName: admin.siteName ?? "",
|
|
384
|
+
favicon: admin.favicon ?? ""
|
|
385
|
+
});
|
|
386
|
+
}
|
|
387
|
+
async function createManifestCacheKey(deps) {
|
|
388
|
+
const pluginKeys = deps.plugins.map((plugin) => `${plugin.id}@${plugin.version ?? ""}`).toSorted();
|
|
389
|
+
const sandboxedPluginKeys = deps.sandboxedPluginEntries.map((entry) => `${entry.id}@${entry.version}`).toSorted();
|
|
390
|
+
const i18nConfig = virtualConfig?.i18n;
|
|
391
|
+
const locales = (i18nConfig?.locales ?? []).toSorted();
|
|
392
|
+
return hashString([
|
|
393
|
+
MANIFEST_CACHE_SCHEMA_VERSION,
|
|
394
|
+
`version:${VERSION}:${COMMIT}`,
|
|
395
|
+
deps.config.marketplace ? "marketplace:1" : "marketplace:0",
|
|
396
|
+
`site-context-workflows:${experimentalSiteContextWorkflowsEnabled() ? "1" : "0"}`,
|
|
397
|
+
`admin:${serializeAdminBranding(deps.config)}`,
|
|
398
|
+
`plugins:${pluginKeys.join(",")}`,
|
|
399
|
+
`sandboxed:${sandboxedPluginKeys.join(",")}`,
|
|
400
|
+
`i18n:${i18nConfig?.defaultLocale ?? ""}:${locales.join(",")}`
|
|
401
|
+
].join("|"));
|
|
402
|
+
}
|
|
352
403
|
/**
|
|
353
404
|
* Map schema field types to editor field kinds
|
|
354
405
|
*/
|
|
355
406
|
const FIELD_TYPE_TO_KIND = {
|
|
356
407
|
string: "string",
|
|
357
408
|
slug: "string",
|
|
409
|
+
url: "url",
|
|
358
410
|
text: "richText",
|
|
359
411
|
number: "number",
|
|
360
412
|
integer: "number",
|
|
@@ -424,6 +476,13 @@ var DinewayRuntime = class DinewayRuntime {
|
|
|
424
476
|
runtimeDeps;
|
|
425
477
|
/** Mutable ref for the cron invokeCronHook closure to read the current pipeline */
|
|
426
478
|
pipelineRef;
|
|
479
|
+
/** Tracks whether FTS health has already been checked for this runtime instance. */
|
|
480
|
+
_searchHealthChecked = false;
|
|
481
|
+
/** Shared in-flight FTS health verification promise. */
|
|
482
|
+
_searchHealthPromise = null;
|
|
483
|
+
_cachedManifest = null;
|
|
484
|
+
_manifestPromise = null;
|
|
485
|
+
_manifestCacheKey;
|
|
427
486
|
/**
|
|
428
487
|
* Get the database instance for the current request.
|
|
429
488
|
*
|
|
@@ -437,7 +496,7 @@ var DinewayRuntime = class DinewayRuntime {
|
|
|
437
496
|
if (requestDb) return requestDb;
|
|
438
497
|
return this._db;
|
|
439
498
|
}
|
|
440
|
-
constructor(db, storage, configuredPlugins, sandboxedPlugins, sandboxedPluginEntries, hooks, enabledPlugins, pluginStates, config, mediaProviders, mediaProviderEntries, cronExecutor, cronScheduler, emailPipeline, allPipelinePlugins, pipelineFactoryOptions, runtimeDeps, pipelineRef) {
|
|
499
|
+
constructor(db, storage, configuredPlugins, sandboxedPlugins, sandboxedPluginEntries, hooks, enabledPlugins, pluginStates, config, mediaProviders, mediaProviderEntries, cronExecutor, cronScheduler, emailPipeline, allPipelinePlugins, pipelineFactoryOptions, runtimeDeps, pipelineRef, manifestCacheKey = MANIFEST_CACHE_SCHEMA_VERSION) {
|
|
441
500
|
this._db = db;
|
|
442
501
|
this.storage = storage;
|
|
443
502
|
this.configuredPlugins = configuredPlugins;
|
|
@@ -457,6 +516,7 @@ var DinewayRuntime = class DinewayRuntime {
|
|
|
457
516
|
this.pipelineFactoryOptions = pipelineFactoryOptions;
|
|
458
517
|
this.runtimeDeps = runtimeDeps;
|
|
459
518
|
this.pipelineRef = pipelineRef;
|
|
519
|
+
this._manifestCacheKey = manifestCacheKey;
|
|
460
520
|
}
|
|
461
521
|
/**
|
|
462
522
|
* Get the sandbox runner instance (for marketplace install/update)
|
|
@@ -480,6 +540,32 @@ var DinewayRuntime = class DinewayRuntime {
|
|
|
480
540
|
if (this.cronScheduler) await this.cronScheduler.stop();
|
|
481
541
|
}
|
|
482
542
|
/**
|
|
543
|
+
* Ensure search-related FTS tables are healthy before the first query.
|
|
544
|
+
*
|
|
545
|
+
* Search health is deferred off the runtime cold-start path so ordinary
|
|
546
|
+
* page loads do not pay the index verification cost. Concurrent callers
|
|
547
|
+
* share a single in-flight check, and once it has completed the result is
|
|
548
|
+
* treated as healthy for the lifetime of this runtime instance.
|
|
549
|
+
*/
|
|
550
|
+
async ensureSearchHealthy() {
|
|
551
|
+
if (this._searchHealthChecked) return;
|
|
552
|
+
if (this._searchHealthPromise) return this._searchHealthPromise;
|
|
553
|
+
if (!isSqlite(this.db)) {
|
|
554
|
+
this._searchHealthChecked = true;
|
|
555
|
+
return;
|
|
556
|
+
}
|
|
557
|
+
this._searchHealthPromise = (async () => {
|
|
558
|
+
try {
|
|
559
|
+
const repaired = await new FTSManager(this.db).verifyAndRepairAll();
|
|
560
|
+
if (repaired > 0) console.log(`Repaired ${repaired} corrupted FTS index(es)`);
|
|
561
|
+
} catch {} finally {
|
|
562
|
+
this._searchHealthChecked = true;
|
|
563
|
+
this._searchHealthPromise = null;
|
|
564
|
+
}
|
|
565
|
+
})();
|
|
566
|
+
return this._searchHealthPromise;
|
|
567
|
+
}
|
|
568
|
+
/**
|
|
483
569
|
* Update in-memory plugin status and rebuild the hook pipeline.
|
|
484
570
|
*
|
|
485
571
|
* Rebuilding the pipeline ensures disabled plugins' hooks stop firing
|
|
@@ -497,6 +583,7 @@ var DinewayRuntime = class DinewayRuntime {
|
|
|
497
583
|
this.enabledPlugins.delete(pluginId);
|
|
498
584
|
await this.rebuildHookPipeline();
|
|
499
585
|
}
|
|
586
|
+
this.invalidateManifest();
|
|
500
587
|
}
|
|
501
588
|
/**
|
|
502
589
|
* Rebuild the hook pipeline from the current set of enabled plugins.
|
|
@@ -608,10 +695,6 @@ var DinewayRuntime = class DinewayRuntime {
|
|
|
608
695
|
*/
|
|
609
696
|
static async create(deps) {
|
|
610
697
|
const db = await DinewayRuntime.getDatabase(deps);
|
|
611
|
-
if (isSqlite(db)) try {
|
|
612
|
-
const repaired = await new FTSManager(db).verifyAndRepairAll();
|
|
613
|
-
if (repaired > 0) console.log(`Repaired ${repaired} corrupted FTS index(es) at startup`);
|
|
614
|
-
} catch {}
|
|
615
698
|
const storage = DinewayRuntime.getStorage(deps);
|
|
616
699
|
let pluginStates = /* @__PURE__ */ new Map();
|
|
617
700
|
try {
|
|
@@ -625,14 +708,15 @@ var DinewayRuntime = class DinewayRuntime {
|
|
|
625
708
|
}
|
|
626
709
|
let siteInfo;
|
|
627
710
|
try {
|
|
628
|
-
const
|
|
629
|
-
|
|
630
|
-
|
|
631
|
-
|
|
711
|
+
const siteOptions = await new OptionsRepository(db).getMany([
|
|
712
|
+
"dineway:site_title",
|
|
713
|
+
"dineway:site_url",
|
|
714
|
+
"dineway:locale"
|
|
715
|
+
]);
|
|
632
716
|
siteInfo = {
|
|
633
|
-
siteName:
|
|
634
|
-
siteUrl:
|
|
635
|
-
locale: locale ?? void 0
|
|
717
|
+
siteName: siteOptions.get("dineway:site_title") ?? void 0,
|
|
718
|
+
siteUrl: siteOptions.get("dineway:site_url") ?? void 0,
|
|
719
|
+
locale: siteOptions.get("dineway:locale") ?? void 0
|
|
636
720
|
};
|
|
637
721
|
} catch {}
|
|
638
722
|
const allPipelinePlugins = [...deps.plugins];
|
|
@@ -667,10 +751,12 @@ var DinewayRuntime = class DinewayRuntime {
|
|
|
667
751
|
console.warn("[comments] Failed to register default moderator:", error);
|
|
668
752
|
}
|
|
669
753
|
const enabledPluginList = allPipelinePlugins.filter((p) => enabledPlugins.has(p.id));
|
|
754
|
+
const trustedProxyHeaders = getTrustedProxyHeaders(deps.config);
|
|
670
755
|
const pipelineFactoryOptions = {
|
|
671
756
|
db,
|
|
672
757
|
storage: storage ?? void 0,
|
|
673
|
-
siteInfo
|
|
758
|
+
siteInfo,
|
|
759
|
+
trustedProxyHeaders
|
|
674
760
|
};
|
|
675
761
|
const pipeline = createHookPipeline(enabledPluginList, pipelineFactoryOptions);
|
|
676
762
|
let cronScheduler = null;
|
|
@@ -709,8 +795,15 @@ var DinewayRuntime = class DinewayRuntime {
|
|
|
709
795
|
let cronExecutor = null;
|
|
710
796
|
try {
|
|
711
797
|
cronExecutor = new CronExecutor(db, invokeCronHook);
|
|
712
|
-
const
|
|
713
|
-
|
|
798
|
+
const executorForRecovery = cronExecutor;
|
|
799
|
+
after(async () => {
|
|
800
|
+
try {
|
|
801
|
+
const recovered = await executorForRecovery.recoverStaleLocks();
|
|
802
|
+
if (recovered > 0) console.log(`[cron] Recovered ${recovered} stale task lock(s)`);
|
|
803
|
+
} catch (error) {
|
|
804
|
+
console.error("[cron] Failed to recover stale task locks:", error);
|
|
805
|
+
}
|
|
806
|
+
});
|
|
714
807
|
if (shouldUsePiggybackScheduler()) cronScheduler = new PiggybackScheduler(cronExecutor);
|
|
715
808
|
else cronScheduler = new NodeCronScheduler(cronExecutor);
|
|
716
809
|
cronScheduler.setSystemCleanup(async () => {
|
|
@@ -725,7 +818,8 @@ var DinewayRuntime = class DinewayRuntime {
|
|
|
725
818
|
} catch (error) {
|
|
726
819
|
console.warn("[cron] Failed to initialize cron system:", error);
|
|
727
820
|
}
|
|
728
|
-
|
|
821
|
+
const manifestCacheKey = await createManifestCacheKey(deps);
|
|
822
|
+
return new DinewayRuntime(db, storage, deps.plugins, sandboxedPlugins, deps.sandboxedPluginEntries, pipeline, enabledPlugins, pluginStates, deps.config, mediaProviders, mediaProviderEntries, cronExecutor, cronScheduler, emailPipeline, allPipelinePlugins, pipelineFactoryOptions, deps, pipelineRef, manifestCacheKey);
|
|
729
823
|
}
|
|
730
824
|
/**
|
|
731
825
|
* Get a media provider by ID
|
|
@@ -761,8 +855,14 @@ var DinewayRuntime = class DinewayRuntime {
|
|
|
761
855
|
if (cached) return cached;
|
|
762
856
|
if (dbInitPromise) return dbInitPromise;
|
|
763
857
|
dbInitPromise = (async () => {
|
|
764
|
-
const db = new Kysely({
|
|
765
|
-
|
|
858
|
+
const db = new Kysely({
|
|
859
|
+
dialect: deps.createDialect(dbConfig.config),
|
|
860
|
+
log: kyselyLogOption()
|
|
861
|
+
});
|
|
862
|
+
const { applied } = await runMigrations(db);
|
|
863
|
+
if (applied.length > 0) try {
|
|
864
|
+
await new OptionsRepository(db).delete(MANIFEST_CACHE_OPTION);
|
|
865
|
+
} catch {}
|
|
766
866
|
try {
|
|
767
867
|
const [collectionCount, setupOption] = await Promise.all([db.selectFrom("_dineway_collections").select((eb) => eb.fn.countAll().as("count")).executeTakeFirstOrThrow(), db.selectFrom("options").select("value").where("name", "=", "dineway:setup_complete").executeTakeFirst()]);
|
|
768
868
|
const setupDone = (() => {
|
|
@@ -773,9 +873,9 @@ var DinewayRuntime = class DinewayRuntime {
|
|
|
773
873
|
}
|
|
774
874
|
})();
|
|
775
875
|
if (collectionCount.count === 0 && !setupDone) {
|
|
776
|
-
const { applySeed } = await import("../apply-
|
|
777
|
-
const { loadSeed } = await import("../load-
|
|
778
|
-
const { validateSeed } = await import("../validate-
|
|
876
|
+
const { applySeed } = await import("../apply-iVSqz2qs.mjs").then((n) => n.n);
|
|
877
|
+
const { loadSeed } = await import("../load-Coc9HpHH.mjs").then((n) => n.r);
|
|
878
|
+
const { validateSeed } = await import("../validate-BZ5wnLLp.mjs").then((n) => n.n);
|
|
779
879
|
const seed = await loadSeed();
|
|
780
880
|
if (validateSeed(seed).valid) {
|
|
781
881
|
await applySeed(db, seed, { onConflict: "skip" });
|
|
@@ -915,9 +1015,46 @@ var DinewayRuntime = class DinewayRuntime {
|
|
|
915
1015
|
});
|
|
916
1016
|
}
|
|
917
1017
|
/**
|
|
918
|
-
*
|
|
1018
|
+
* Return the admin manifest, reusing the runtime/persisted cache when
|
|
1019
|
+
* singleton DB state is active. Request-scoped database overrides bypass
|
|
1020
|
+
* the cache so sidecar/playground sessions see their own schema.
|
|
919
1021
|
*/
|
|
920
1022
|
async getManifest() {
|
|
1023
|
+
if (getRequestContextDatabase()) return this._buildManifest();
|
|
1024
|
+
if (this._cachedManifest) return this._cachedManifest;
|
|
1025
|
+
try {
|
|
1026
|
+
const cached = await new OptionsRepository(this._db).get(MANIFEST_CACHE_OPTION);
|
|
1027
|
+
if (isPersistedManifestCache(cached) && cached.key === this._manifestCacheKey) {
|
|
1028
|
+
this._cachedManifest = cached.manifest;
|
|
1029
|
+
return cached.manifest;
|
|
1030
|
+
}
|
|
1031
|
+
} catch {}
|
|
1032
|
+
if (!this._manifestPromise) {
|
|
1033
|
+
let manifestPromise;
|
|
1034
|
+
const isCurrentLoad = () => this._manifestPromise === manifestPromise;
|
|
1035
|
+
manifestPromise = this._loadManifest(isCurrentLoad);
|
|
1036
|
+
this._manifestPromise = manifestPromise;
|
|
1037
|
+
}
|
|
1038
|
+
return this._manifestPromise;
|
|
1039
|
+
}
|
|
1040
|
+
async _loadManifest(isCurrentLoad) {
|
|
1041
|
+
try {
|
|
1042
|
+
const manifest = await this._buildManifest();
|
|
1043
|
+
if (isCurrentLoad()) {
|
|
1044
|
+
this._cachedManifest = manifest;
|
|
1045
|
+
try {
|
|
1046
|
+
await new OptionsRepository(this._db).set(MANIFEST_CACHE_OPTION, {
|
|
1047
|
+
key: this._manifestCacheKey,
|
|
1048
|
+
manifest
|
|
1049
|
+
});
|
|
1050
|
+
} catch {}
|
|
1051
|
+
}
|
|
1052
|
+
return manifest;
|
|
1053
|
+
} finally {
|
|
1054
|
+
if (isCurrentLoad()) this._manifestPromise = null;
|
|
1055
|
+
}
|
|
1056
|
+
}
|
|
1057
|
+
async _buildManifest() {
|
|
921
1058
|
const manifestCollections = {};
|
|
922
1059
|
try {
|
|
923
1060
|
const registry = new SchemaRegistry(this.db);
|
|
@@ -1014,7 +1151,8 @@ var DinewayRuntime = class DinewayRuntime {
|
|
|
1014
1151
|
} catch (error) {
|
|
1015
1152
|
console.debug("Dineway: Could not load taxonomy definitions:", error);
|
|
1016
1153
|
}
|
|
1017
|
-
const
|
|
1154
|
+
const features = { siteContextWorkflows: experimentalSiteContextWorkflowsEnabled() };
|
|
1155
|
+
const manifestHash = await hashString(JSON.stringify(manifestCollections) + JSON.stringify(manifestPlugins) + JSON.stringify(manifestTaxonomies) + JSON.stringify(features) + serializeAdminBranding(this.config));
|
|
1018
1156
|
const authMode = getAuthMode(this.config);
|
|
1019
1157
|
const authModeValue = authMode.type === "external" ? authMode.providerType : "passkey";
|
|
1020
1158
|
const i18nConfig = virtualConfig?.i18n;
|
|
@@ -1023,21 +1161,30 @@ var DinewayRuntime = class DinewayRuntime {
|
|
|
1023
1161
|
locales: i18nConfig.locales
|
|
1024
1162
|
} : void 0;
|
|
1025
1163
|
return {
|
|
1026
|
-
version:
|
|
1164
|
+
version: VERSION,
|
|
1165
|
+
commit: COMMIT,
|
|
1027
1166
|
hash: manifestHash,
|
|
1028
1167
|
collections: manifestCollections,
|
|
1029
1168
|
plugins: manifestPlugins,
|
|
1169
|
+
features,
|
|
1030
1170
|
taxonomies: manifestTaxonomies,
|
|
1031
1171
|
authMode: authModeValue,
|
|
1032
1172
|
i18n,
|
|
1033
|
-
marketplace: !!this.config.marketplace
|
|
1173
|
+
marketplace: !!this.config.marketplace,
|
|
1174
|
+
admin: this.config.admin
|
|
1034
1175
|
};
|
|
1035
1176
|
}
|
|
1036
1177
|
/**
|
|
1037
|
-
* Invalidate
|
|
1038
|
-
* Kept for API compatibility.
|
|
1178
|
+
* Invalidate cached manifest state after schema, taxonomy, or plugin changes.
|
|
1039
1179
|
*/
|
|
1040
|
-
invalidateManifest() {
|
|
1180
|
+
invalidateManifest() {
|
|
1181
|
+
this._cachedManifest = null;
|
|
1182
|
+
this._manifestPromise = null;
|
|
1183
|
+
invalidateUrlPatternCache();
|
|
1184
|
+
new OptionsRepository(this._db).delete(MANIFEST_CACHE_OPTION).catch((error) => {
|
|
1185
|
+
console.debug("Dineway: Could not clear manifest cache:", error);
|
|
1186
|
+
});
|
|
1187
|
+
}
|
|
1041
1188
|
async handleContentList(collection, params) {
|
|
1042
1189
|
return handleContentList(this.db, collection, params);
|
|
1043
1190
|
}
|
|
@@ -1062,7 +1209,7 @@ var DinewayRuntime = class DinewayRuntime {
|
|
|
1062
1209
|
return result;
|
|
1063
1210
|
}
|
|
1064
1211
|
async handleContentUpdate(collection, id, body) {
|
|
1065
|
-
const { ContentRepository } = await import("../content-
|
|
1212
|
+
const { ContentRepository } = await import("../content-DWi4d0rT.mjs").then((n) => n.n);
|
|
1066
1213
|
const repo = new ContentRepository(this.db);
|
|
1067
1214
|
const resolvedItem = await repo.findByIdOrSlug(collection, id);
|
|
1068
1215
|
const resolvedId = resolvedItem?.id ?? id;
|
|
@@ -1113,6 +1260,7 @@ var DinewayRuntime = class DinewayRuntime {
|
|
|
1113
1260
|
data: mergedData,
|
|
1114
1261
|
authorId: bodyWithoutRev.authorId ?? void 0
|
|
1115
1262
|
});
|
|
1263
|
+
validateIdentifier(collection, "collection");
|
|
1116
1264
|
const tableName = `ec_${collection}`;
|
|
1117
1265
|
await sql`
|
|
1118
1266
|
UPDATE ${sql.ref(tableName)}
|
|
@@ -1154,7 +1302,7 @@ var DinewayRuntime = class DinewayRuntime {
|
|
|
1154
1302
|
}
|
|
1155
1303
|
};
|
|
1156
1304
|
const result = await handleContentDelete(this.db, collection, id);
|
|
1157
|
-
if (result.success) this.runAfterDeleteHooks(id, collection);
|
|
1305
|
+
if (result.success) this.runAfterDeleteHooks(id, collection, false);
|
|
1158
1306
|
return result;
|
|
1159
1307
|
}
|
|
1160
1308
|
async handleContentListTrashed(collection, params = {}) {
|
|
@@ -1164,7 +1312,9 @@ var DinewayRuntime = class DinewayRuntime {
|
|
|
1164
1312
|
return handleContentRestore(this.db, collection, id);
|
|
1165
1313
|
}
|
|
1166
1314
|
async handleContentPermanentDelete(collection, id) {
|
|
1167
|
-
|
|
1315
|
+
const result = await handleContentPermanentDelete(this.db, collection, id);
|
|
1316
|
+
if (result.success) this.runAfterDeleteHooks(id, collection, true);
|
|
1317
|
+
return result;
|
|
1168
1318
|
}
|
|
1169
1319
|
async handleContentCountTrashed(collection) {
|
|
1170
1320
|
return handleContentCountTrashed(this.db, collection);
|
|
@@ -1291,7 +1441,8 @@ var DinewayRuntime = class DinewayRuntime {
|
|
|
1291
1441
|
if (trustedPlugin && this.enabledPlugins.has(trustedPlugin.id)) {
|
|
1292
1442
|
const routeRegistry = new PluginRouteRegistry({
|
|
1293
1443
|
db: this.db,
|
|
1294
|
-
emailPipeline: this.email ?? void 0
|
|
1444
|
+
emailPipeline: this.email ?? void 0,
|
|
1445
|
+
trustedProxyHeaders: getTrustedProxyHeaders(this.config)
|
|
1295
1446
|
});
|
|
1296
1447
|
routeRegistry.register(trustedPlugin);
|
|
1297
1448
|
const routeKey = path.replace(LEADING_SLASH_PATTERN, "");
|
|
@@ -1372,7 +1523,8 @@ var DinewayRuntime = class DinewayRuntime {
|
|
|
1372
1523
|
try {
|
|
1373
1524
|
if (await plugin.invokeHook("content:beforeDelete", {
|
|
1374
1525
|
id,
|
|
1375
|
-
collection
|
|
1526
|
+
collection,
|
|
1527
|
+
permanent: false
|
|
1376
1528
|
}) === false) return false;
|
|
1377
1529
|
} catch (error) {
|
|
1378
1530
|
console.error(`Dineway: Sandboxed plugin ${pluginId} beforeDelete hook error:`, error);
|
|
@@ -1381,38 +1533,67 @@ var DinewayRuntime = class DinewayRuntime {
|
|
|
1381
1533
|
return true;
|
|
1382
1534
|
}
|
|
1383
1535
|
runAfterSaveHooks(content, collection, isNew) {
|
|
1384
|
-
|
|
1385
|
-
|
|
1386
|
-
|
|
1387
|
-
|
|
1388
|
-
|
|
1389
|
-
|
|
1390
|
-
|
|
1391
|
-
|
|
1392
|
-
|
|
1393
|
-
|
|
1536
|
+
after(async () => {
|
|
1537
|
+
if (this.hooks.hasHooks("content:afterSave")) try {
|
|
1538
|
+
await this.hooks.runContentAfterSave(content, collection, isNew);
|
|
1539
|
+
} catch (err) {
|
|
1540
|
+
console.error("Dineway afterSave hook error:", err);
|
|
1541
|
+
}
|
|
1542
|
+
const tasks = [];
|
|
1543
|
+
for (const [pluginKey, plugin] of this.sandboxedPlugins) {
|
|
1544
|
+
const [id] = pluginKey.split(":");
|
|
1545
|
+
if (!id || !this.isPluginEnabled(id)) continue;
|
|
1546
|
+
tasks.push((async () => {
|
|
1547
|
+
try {
|
|
1548
|
+
await plugin.invokeHook("content:afterSave", {
|
|
1549
|
+
content,
|
|
1550
|
+
collection,
|
|
1551
|
+
isNew
|
|
1552
|
+
});
|
|
1553
|
+
} catch (err) {
|
|
1554
|
+
console.error(`Dineway: Sandboxed plugin ${id} afterSave error:`, err);
|
|
1555
|
+
}
|
|
1556
|
+
})());
|
|
1557
|
+
}
|
|
1558
|
+
await Promise.allSettled(tasks);
|
|
1559
|
+
});
|
|
1394
1560
|
}
|
|
1395
|
-
runAfterDeleteHooks(id, collection) {
|
|
1396
|
-
if (this.hooks.hasHooks("content:afterDelete")) this.hooks.runContentAfterDelete(id, collection).catch((err) => console.error("Dineway afterDelete hook error:", err));
|
|
1561
|
+
runAfterDeleteHooks(id, collection, permanent) {
|
|
1562
|
+
if (this.hooks.hasHooks("content:afterDelete")) this.hooks.runContentAfterDelete(id, collection, permanent).catch((err) => console.error("Dineway afterDelete hook error:", err));
|
|
1397
1563
|
for (const [pluginKey, plugin] of this.sandboxedPlugins) {
|
|
1398
1564
|
const [pluginId] = pluginKey.split(":");
|
|
1399
1565
|
if (!pluginId || !this.isPluginEnabled(pluginId)) continue;
|
|
1400
1566
|
plugin.invokeHook("content:afterDelete", {
|
|
1401
1567
|
id,
|
|
1402
|
-
collection
|
|
1568
|
+
collection,
|
|
1569
|
+
permanent
|
|
1403
1570
|
}).catch((err) => console.error(`Dineway: Sandboxed plugin ${pluginId} afterDelete error:`, err));
|
|
1404
1571
|
}
|
|
1405
1572
|
}
|
|
1406
1573
|
runAfterPublishHooks(content, collection) {
|
|
1407
|
-
|
|
1408
|
-
|
|
1409
|
-
|
|
1410
|
-
|
|
1411
|
-
|
|
1412
|
-
|
|
1413
|
-
|
|
1414
|
-
|
|
1415
|
-
|
|
1574
|
+
after(async () => {
|
|
1575
|
+
if (this.hooks.hasHooks("content:afterPublish")) try {
|
|
1576
|
+
await this.hooks.runContentAfterPublish(content, collection);
|
|
1577
|
+
} catch (err) {
|
|
1578
|
+
console.error("Dineway afterPublish hook error:", err);
|
|
1579
|
+
}
|
|
1580
|
+
const tasks = [];
|
|
1581
|
+
for (const [pluginKey, plugin] of this.sandboxedPlugins) {
|
|
1582
|
+
const [pluginId] = pluginKey.split(":");
|
|
1583
|
+
if (!pluginId || !this.isPluginEnabled(pluginId)) continue;
|
|
1584
|
+
tasks.push((async () => {
|
|
1585
|
+
try {
|
|
1586
|
+
await plugin.invokeHook("content:afterPublish", {
|
|
1587
|
+
content,
|
|
1588
|
+
collection
|
|
1589
|
+
});
|
|
1590
|
+
} catch (err) {
|
|
1591
|
+
console.error(`Dineway: Sandboxed plugin ${pluginId} afterPublish error:`, err);
|
|
1592
|
+
}
|
|
1593
|
+
})());
|
|
1594
|
+
}
|
|
1595
|
+
await Promise.allSettled(tasks);
|
|
1596
|
+
});
|
|
1416
1597
|
}
|
|
1417
1598
|
runAfterUnpublishHooks(content, collection) {
|
|
1418
1599
|
if (this.hooks.hasHooks("content:afterUnpublish")) this.hooks.runContentAfterUnpublish(content, collection).catch((err) => console.error("Dineway afterUnpublish hook error:", err));
|
|
@@ -1433,7 +1614,7 @@ var DinewayRuntime = class DinewayRuntime {
|
|
|
1433
1614
|
} catch {}
|
|
1434
1615
|
try {
|
|
1435
1616
|
const headers = sanitizeHeadersForSandbox(request.headers);
|
|
1436
|
-
const meta = extractRequestMeta(request);
|
|
1617
|
+
const meta = extractRequestMeta(request, this.config);
|
|
1437
1618
|
return {
|
|
1438
1619
|
success: true,
|
|
1439
1620
|
data: await plugin.invokeRoute(routeName, body, {
|
|
@@ -1599,117 +1780,178 @@ async function getRuntime(config) {
|
|
|
1599
1780
|
runtimeInitializing = false;
|
|
1600
1781
|
}
|
|
1601
1782
|
}
|
|
1783
|
+
const ASTRO_COOKIES_SYMBOL = Symbol.for("astro.cookies");
|
|
1602
1784
|
/**
|
|
1603
1785
|
* Baseline security headers applied to all responses.
|
|
1604
1786
|
* Admin routes get additional headers (strict CSP) from auth middleware.
|
|
1605
1787
|
*/
|
|
1606
|
-
function setBaselineSecurityHeaders(response) {
|
|
1607
|
-
response.
|
|
1608
|
-
|
|
1609
|
-
|
|
1610
|
-
|
|
1788
|
+
function setBaselineSecurityHeaders(response, serverTimings) {
|
|
1789
|
+
const res = new Response(response.body, response);
|
|
1790
|
+
const astroCookies = Reflect.get(response, ASTRO_COOKIES_SYMBOL);
|
|
1791
|
+
if (astroCookies !== void 0) Reflect.set(res, ASTRO_COOKIES_SYMBOL, astroCookies);
|
|
1792
|
+
res.headers.set("X-Content-Type-Options", "nosniff");
|
|
1793
|
+
res.headers.set("Referrer-Policy", "strict-origin-when-cross-origin");
|
|
1794
|
+
res.headers.set("Permissions-Policy", "camera=(), microphone=(), geolocation=(), payment=()");
|
|
1795
|
+
if (!res.headers.has("Content-Security-Policy")) res.headers.set("X-Frame-Options", "SAMEORIGIN");
|
|
1796
|
+
if (serverTimings && serverTimings.length > 0) res.headers.set("Server-Timing", formatServerTimingHeader(serverTimings));
|
|
1797
|
+
return res;
|
|
1798
|
+
}
|
|
1799
|
+
function createServerTimings() {
|
|
1800
|
+
return isServerTimingEnabled() ? [] : void 0;
|
|
1801
|
+
}
|
|
1802
|
+
function startServerTiming(timings) {
|
|
1803
|
+
return timings ? performance.now() : 0;
|
|
1804
|
+
}
|
|
1805
|
+
function addServerTiming(timings, name, start, desc) {
|
|
1806
|
+
if (!timings) return;
|
|
1807
|
+
timings.push({
|
|
1808
|
+
name,
|
|
1809
|
+
dur: performance.now() - start,
|
|
1810
|
+
desc
|
|
1811
|
+
});
|
|
1611
1812
|
}
|
|
1612
1813
|
/** Public routes that require the runtime (sitemap, robots.txt, etc.) */
|
|
1613
1814
|
const PUBLIC_RUNTIME_ROUTES = new Set(["/sitemap.xml", "/robots.txt"]);
|
|
1614
1815
|
const SITEMAP_COLLECTION_RE = /^\/sitemap-[a-z][a-z0-9_]*\.xml$/;
|
|
1615
1816
|
const onRequest = defineMiddleware(async (context, next) => {
|
|
1616
|
-
const { locals, cookies } = context;
|
|
1817
|
+
const { locals, cookies, request } = context;
|
|
1617
1818
|
const url = context.url;
|
|
1618
|
-
const
|
|
1619
|
-
const
|
|
1620
|
-
const
|
|
1621
|
-
const
|
|
1622
|
-
|
|
1623
|
-
|
|
1624
|
-
|
|
1625
|
-
|
|
1626
|
-
|
|
1627
|
-
|
|
1628
|
-
|
|
1629
|
-
|
|
1630
|
-
|
|
1819
|
+
const queryRecorder = isInstrumentationEnabled() ? createRecorder(url.pathname, request.method, request.headers.get("x-dineway-perf-phase") ?? "default") : void 0;
|
|
1820
|
+
const serverTimings = createServerTimings();
|
|
1821
|
+
const middlewareStart = startServerTiming(serverTimings);
|
|
1822
|
+
const handleRequest = async () => {
|
|
1823
|
+
const isDinewayRoute = url.pathname.startsWith("/_dineway");
|
|
1824
|
+
const isPublicRuntimeRoute = PUBLIC_RUNTIME_ROUTES.has(url.pathname) || SITEMAP_COLLECTION_RE.test(url.pathname);
|
|
1825
|
+
const hasEditCookie = cookies.get("dineway-edit-mode")?.value === "true";
|
|
1826
|
+
const hasPreviewToken = url.searchParams.has("_preview");
|
|
1827
|
+
const requestDb = locals.__dinewayRequestDb;
|
|
1828
|
+
if (!isDinewayRoute && !isPublicRuntimeRoute && !hasEditCookie && !hasPreviewToken) {
|
|
1829
|
+
if (!(context.isPrerendered ? null : await context.session?.get("user")) && !requestDb) {
|
|
1830
|
+
if (!setupVerified) {
|
|
1831
|
+
const setupStart = startServerTiming(serverTimings);
|
|
1832
|
+
try {
|
|
1833
|
+
const { getDb } = await import("../loader-sMG4TZ-u.mjs").then((n) => n.r);
|
|
1834
|
+
await (await getDb()).selectFrom("_dineway_migrations").selectAll().limit(1).execute();
|
|
1835
|
+
setupVerified = true;
|
|
1836
|
+
} catch {
|
|
1837
|
+
return context.redirect("/_dineway/admin/setup");
|
|
1838
|
+
}
|
|
1839
|
+
addServerTiming(serverTimings, "setup", setupStart, "Setup probe");
|
|
1840
|
+
}
|
|
1841
|
+
const config = getConfig();
|
|
1842
|
+
if (config) {
|
|
1843
|
+
const runtimeStart = startServerTiming(serverTimings);
|
|
1844
|
+
try {
|
|
1845
|
+
const runtime = await getRuntime(config);
|
|
1846
|
+
setupVerified = true;
|
|
1847
|
+
locals.dineway = {
|
|
1848
|
+
collectPageMetadata: runtime.collectPageMetadata.bind(runtime),
|
|
1849
|
+
collectPageFragments: runtime.collectPageFragments.bind(runtime),
|
|
1850
|
+
ensureSearchHealthy: runtime.ensureSearchHealthy.bind(runtime)
|
|
1851
|
+
};
|
|
1852
|
+
} catch {}
|
|
1853
|
+
addServerTiming(serverTimings, "rt", runtimeStart, "Runtime init");
|
|
1854
|
+
}
|
|
1855
|
+
const renderStart = startServerTiming(serverTimings);
|
|
1856
|
+
const response = await next();
|
|
1857
|
+
addServerTiming(serverTimings, "render", renderStart, "Page render");
|
|
1858
|
+
addServerTiming(serverTimings, "mw", middlewareStart, "Total middleware");
|
|
1859
|
+
return setBaselineSecurityHeaders(response, serverTimings);
|
|
1631
1860
|
}
|
|
1632
|
-
|
|
1633
|
-
|
|
1861
|
+
}
|
|
1862
|
+
const config = getConfig();
|
|
1863
|
+
if (!config) {
|
|
1864
|
+
console.error("Dineway: No configuration found");
|
|
1865
|
+
return next();
|
|
1866
|
+
}
|
|
1867
|
+
const doInit = async () => {
|
|
1868
|
+
try {
|
|
1869
|
+
let timingStart = startServerTiming(serverTimings);
|
|
1634
1870
|
const runtime = await getRuntime(config);
|
|
1871
|
+
addServerTiming(serverTimings, "rt", timingStart, "Runtime init");
|
|
1635
1872
|
setupVerified = true;
|
|
1873
|
+
timingStart = startServerTiming(serverTimings);
|
|
1874
|
+
const manifest = await runtime.getManifest();
|
|
1875
|
+
addServerTiming(serverTimings, "manifest", timingStart, "Manifest");
|
|
1876
|
+
locals.dinewayManifest = manifest;
|
|
1636
1877
|
locals.dineway = {
|
|
1878
|
+
handleContentList: runtime.handleContentList.bind(runtime),
|
|
1879
|
+
handleContentGet: runtime.handleContentGet.bind(runtime),
|
|
1880
|
+
handleContentCreate: runtime.handleContentCreate.bind(runtime),
|
|
1881
|
+
handleContentUpdate: runtime.handleContentUpdate.bind(runtime),
|
|
1882
|
+
handleContentDelete: runtime.handleContentDelete.bind(runtime),
|
|
1883
|
+
handleContentListTrashed: runtime.handleContentListTrashed.bind(runtime),
|
|
1884
|
+
handleContentRestore: runtime.handleContentRestore.bind(runtime),
|
|
1885
|
+
handleContentPermanentDelete: runtime.handleContentPermanentDelete.bind(runtime),
|
|
1886
|
+
handleContentCountTrashed: runtime.handleContentCountTrashed.bind(runtime),
|
|
1887
|
+
handleContentGetIncludingTrashed: runtime.handleContentGetIncludingTrashed.bind(runtime),
|
|
1888
|
+
handleContentDuplicate: runtime.handleContentDuplicate.bind(runtime),
|
|
1889
|
+
handleContentPublish: runtime.handleContentPublish.bind(runtime),
|
|
1890
|
+
handleContentUnpublish: runtime.handleContentUnpublish.bind(runtime),
|
|
1891
|
+
handleContentSchedule: runtime.handleContentSchedule.bind(runtime),
|
|
1892
|
+
handleContentUnschedule: runtime.handleContentUnschedule.bind(runtime),
|
|
1893
|
+
handleContentCountScheduled: runtime.handleContentCountScheduled.bind(runtime),
|
|
1894
|
+
handleContentDiscardDraft: runtime.handleContentDiscardDraft.bind(runtime),
|
|
1895
|
+
handleContentCompare: runtime.handleContentCompare.bind(runtime),
|
|
1896
|
+
handleContentTranslations: runtime.handleContentTranslations.bind(runtime),
|
|
1897
|
+
handleMediaList: runtime.handleMediaList.bind(runtime),
|
|
1898
|
+
handleMediaGet: runtime.handleMediaGet.bind(runtime),
|
|
1899
|
+
handleMediaCreate: runtime.handleMediaCreate.bind(runtime),
|
|
1900
|
+
handleMediaUpdate: runtime.handleMediaUpdate.bind(runtime),
|
|
1901
|
+
handleMediaDelete: runtime.handleMediaDelete.bind(runtime),
|
|
1902
|
+
handleRevisionList: runtime.handleRevisionList.bind(runtime),
|
|
1903
|
+
handleRevisionGet: runtime.handleRevisionGet.bind(runtime),
|
|
1904
|
+
handleRevisionRestore: runtime.handleRevisionRestore.bind(runtime),
|
|
1905
|
+
handlePluginApiRoute: runtime.handlePluginApiRoute.bind(runtime),
|
|
1906
|
+
getPluginRouteMeta: runtime.getPluginRouteMeta.bind(runtime),
|
|
1907
|
+
getMediaProvider: runtime.getMediaProvider.bind(runtime),
|
|
1908
|
+
getMediaProviderList: runtime.getMediaProviderList.bind(runtime),
|
|
1637
1909
|
collectPageMetadata: runtime.collectPageMetadata.bind(runtime),
|
|
1638
|
-
collectPageFragments: runtime.collectPageFragments.bind(runtime)
|
|
1910
|
+
collectPageFragments: runtime.collectPageFragments.bind(runtime),
|
|
1911
|
+
ensureSearchHealthy: runtime.ensureSearchHealthy.bind(runtime),
|
|
1912
|
+
storage: runtime.storage,
|
|
1913
|
+
db: runtime.db,
|
|
1914
|
+
hooks: runtime.hooks,
|
|
1915
|
+
email: runtime.email,
|
|
1916
|
+
configuredPlugins: runtime.configuredPlugins,
|
|
1917
|
+
config,
|
|
1918
|
+
invalidateManifest: runtime.invalidateManifest.bind(runtime),
|
|
1919
|
+
getSandboxRunner: runtime.getSandboxRunner.bind(runtime),
|
|
1920
|
+
syncMarketplacePlugins: runtime.syncMarketplacePlugins.bind(runtime),
|
|
1921
|
+
setPluginStatus: runtime.setPluginStatus.bind(runtime)
|
|
1639
1922
|
};
|
|
1640
|
-
} catch {
|
|
1923
|
+
} catch (error) {
|
|
1924
|
+
console.error("Dineway middleware error:", error);
|
|
1925
|
+
}
|
|
1926
|
+
const renderStart = startServerTiming(serverTimings);
|
|
1641
1927
|
const response = await next();
|
|
1642
|
-
|
|
1643
|
-
|
|
1644
|
-
|
|
1645
|
-
|
|
1646
|
-
|
|
1647
|
-
|
|
1648
|
-
|
|
1649
|
-
|
|
1650
|
-
|
|
1651
|
-
|
|
1652
|
-
|
|
1653
|
-
|
|
1654
|
-
|
|
1655
|
-
|
|
1656
|
-
|
|
1657
|
-
handleContentList: runtime.handleContentList.bind(runtime),
|
|
1658
|
-
handleContentGet: runtime.handleContentGet.bind(runtime),
|
|
1659
|
-
handleContentCreate: runtime.handleContentCreate.bind(runtime),
|
|
1660
|
-
handleContentUpdate: runtime.handleContentUpdate.bind(runtime),
|
|
1661
|
-
handleContentDelete: runtime.handleContentDelete.bind(runtime),
|
|
1662
|
-
handleContentListTrashed: runtime.handleContentListTrashed.bind(runtime),
|
|
1663
|
-
handleContentRestore: runtime.handleContentRestore.bind(runtime),
|
|
1664
|
-
handleContentPermanentDelete: runtime.handleContentPermanentDelete.bind(runtime),
|
|
1665
|
-
handleContentCountTrashed: runtime.handleContentCountTrashed.bind(runtime),
|
|
1666
|
-
handleContentGetIncludingTrashed: runtime.handleContentGetIncludingTrashed.bind(runtime),
|
|
1667
|
-
handleContentDuplicate: runtime.handleContentDuplicate.bind(runtime),
|
|
1668
|
-
handleContentPublish: runtime.handleContentPublish.bind(runtime),
|
|
1669
|
-
handleContentUnpublish: runtime.handleContentUnpublish.bind(runtime),
|
|
1670
|
-
handleContentSchedule: runtime.handleContentSchedule.bind(runtime),
|
|
1671
|
-
handleContentUnschedule: runtime.handleContentUnschedule.bind(runtime),
|
|
1672
|
-
handleContentCountScheduled: runtime.handleContentCountScheduled.bind(runtime),
|
|
1673
|
-
handleContentDiscardDraft: runtime.handleContentDiscardDraft.bind(runtime),
|
|
1674
|
-
handleContentCompare: runtime.handleContentCompare.bind(runtime),
|
|
1675
|
-
handleContentTranslations: runtime.handleContentTranslations.bind(runtime),
|
|
1676
|
-
handleMediaList: runtime.handleMediaList.bind(runtime),
|
|
1677
|
-
handleMediaGet: runtime.handleMediaGet.bind(runtime),
|
|
1678
|
-
handleMediaCreate: runtime.handleMediaCreate.bind(runtime),
|
|
1679
|
-
handleMediaUpdate: runtime.handleMediaUpdate.bind(runtime),
|
|
1680
|
-
handleMediaDelete: runtime.handleMediaDelete.bind(runtime),
|
|
1681
|
-
handleRevisionList: runtime.handleRevisionList.bind(runtime),
|
|
1682
|
-
handleRevisionGet: runtime.handleRevisionGet.bind(runtime),
|
|
1683
|
-
handleRevisionRestore: runtime.handleRevisionRestore.bind(runtime),
|
|
1684
|
-
handlePluginApiRoute: runtime.handlePluginApiRoute.bind(runtime),
|
|
1685
|
-
getPluginRouteMeta: runtime.getPluginRouteMeta.bind(runtime),
|
|
1686
|
-
getMediaProvider: runtime.getMediaProvider.bind(runtime),
|
|
1687
|
-
getMediaProviderList: runtime.getMediaProviderList.bind(runtime),
|
|
1688
|
-
collectPageMetadata: runtime.collectPageMetadata.bind(runtime),
|
|
1689
|
-
collectPageFragments: runtime.collectPageFragments.bind(runtime),
|
|
1690
|
-
storage: runtime.storage,
|
|
1691
|
-
db: runtime.db,
|
|
1692
|
-
hooks: runtime.hooks,
|
|
1693
|
-
email: runtime.email,
|
|
1694
|
-
configuredPlugins: runtime.configuredPlugins,
|
|
1695
|
-
config,
|
|
1696
|
-
invalidateManifest: runtime.invalidateManifest.bind(runtime),
|
|
1697
|
-
getSandboxRunner: runtime.getSandboxRunner.bind(runtime),
|
|
1698
|
-
syncMarketplacePlugins: runtime.syncMarketplacePlugins.bind(runtime),
|
|
1699
|
-
setPluginStatus: runtime.setPluginStatus.bind(runtime)
|
|
1700
|
-
};
|
|
1701
|
-
} catch (error) {
|
|
1702
|
-
console.error("Dineway middleware error:", error);
|
|
1928
|
+
addServerTiming(serverTimings, "render", renderStart, "Page render");
|
|
1929
|
+
addServerTiming(serverTimings, "mw", middlewareStart, "Total middleware");
|
|
1930
|
+
return setBaselineSecurityHeaders(response, serverTimings);
|
|
1931
|
+
};
|
|
1932
|
+
if (requestDb) {
|
|
1933
|
+
const editMode = context.cookies.get("dineway-edit-mode")?.value === "true";
|
|
1934
|
+
const parentContext = getRequestContext();
|
|
1935
|
+
return runWithContext(parentContext ? {
|
|
1936
|
+
...parentContext,
|
|
1937
|
+
editMode,
|
|
1938
|
+
db: requestDb
|
|
1939
|
+
} : {
|
|
1940
|
+
editMode,
|
|
1941
|
+
db: requestDb
|
|
1942
|
+
}, doInit);
|
|
1703
1943
|
}
|
|
1704
|
-
|
|
1705
|
-
setBaselineSecurityHeaders(response);
|
|
1706
|
-
return response;
|
|
1944
|
+
return doInit();
|
|
1707
1945
|
};
|
|
1708
|
-
if (
|
|
1709
|
-
|
|
1710
|
-
|
|
1711
|
-
|
|
1712
|
-
|
|
1946
|
+
if (queryRecorder) try {
|
|
1947
|
+
return await runWithContext({
|
|
1948
|
+
editMode: false,
|
|
1949
|
+
queryRecorder
|
|
1950
|
+
}, handleRequest);
|
|
1951
|
+
} finally {
|
|
1952
|
+
flushRecorder(queryRecorder);
|
|
1953
|
+
}
|
|
1954
|
+
return handleRequest();
|
|
1713
1955
|
});
|
|
1714
1956
|
|
|
1715
1957
|
//#endregion
|