dineway 0.1.4 → 0.1.6
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-BApX1xhM.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-hmtC3Cmv.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
|
@@ -18,6 +18,11 @@ import {
|
|
|
18
18
|
import { parseBody, isParseError } from "#api/parse.js";
|
|
19
19
|
import { updateFieldBody } from "#api/schemas.js";
|
|
20
20
|
import type { UpdateFieldInput } from "#schema/types.js";
|
|
21
|
+
import {
|
|
22
|
+
activityChangedKeys,
|
|
23
|
+
logSchemaActivity,
|
|
24
|
+
schemaApiRouteSource,
|
|
25
|
+
} from "#site-context/activity-events.js";
|
|
21
26
|
|
|
22
27
|
export const prerender = false;
|
|
23
28
|
|
|
@@ -57,6 +62,19 @@ export const PUT: APIRoute = async ({ params, request, locals }) => {
|
|
|
57
62
|
fieldSlug,
|
|
58
63
|
body as UpdateFieldInput,
|
|
59
64
|
);
|
|
65
|
+
if (result.success) dineway.invalidateManifest();
|
|
66
|
+
if (result.success) {
|
|
67
|
+
await logSchemaActivity(dineway.db, locals, {
|
|
68
|
+
action: "field_updated",
|
|
69
|
+
collection: collectionSlug,
|
|
70
|
+
field: fieldSlug,
|
|
71
|
+
...schemaApiRouteSource("field_updated"),
|
|
72
|
+
summary: `Updated field ${fieldSlug} in ${collectionSlug}`,
|
|
73
|
+
detail: {
|
|
74
|
+
changedFields: activityChangedKeys(body),
|
|
75
|
+
},
|
|
76
|
+
});
|
|
77
|
+
}
|
|
60
78
|
return unwrapResult(result);
|
|
61
79
|
};
|
|
62
80
|
|
|
@@ -72,5 +90,15 @@ export const DELETE: APIRoute = async ({ params, locals }) => {
|
|
|
72
90
|
if (denied) return denied;
|
|
73
91
|
|
|
74
92
|
const result = await handleSchemaFieldDelete(dineway.db, collectionSlug, fieldSlug);
|
|
93
|
+
if (result.success) dineway.invalidateManifest();
|
|
94
|
+
if (result.success) {
|
|
95
|
+
await logSchemaActivity(dineway.db, locals, {
|
|
96
|
+
action: "field_deleted",
|
|
97
|
+
collection: collectionSlug,
|
|
98
|
+
field: fieldSlug,
|
|
99
|
+
...schemaApiRouteSource("field_deleted"),
|
|
100
|
+
summary: `Deleted field ${fieldSlug} from ${collectionSlug}`,
|
|
101
|
+
});
|
|
102
|
+
}
|
|
75
103
|
return unwrapResult(result);
|
|
76
104
|
};
|
|
@@ -13,6 +13,7 @@ import { handleSchemaFieldList, handleSchemaFieldCreate } from "#api/index.js";
|
|
|
13
13
|
import { parseBody, isParseError } from "#api/parse.js";
|
|
14
14
|
import { createFieldBody } from "#api/schemas.js";
|
|
15
15
|
import type { CreateFieldInput } from "#schema/types.js";
|
|
16
|
+
import { logSchemaActivity, schemaApiRouteSource } from "#site-context/activity-events.js";
|
|
16
17
|
|
|
17
18
|
export const prerender = false;
|
|
18
19
|
|
|
@@ -48,5 +49,19 @@ export const POST: APIRoute = async ({ params, request, locals }) => {
|
|
|
48
49
|
collectionSlug,
|
|
49
50
|
body as CreateFieldInput,
|
|
50
51
|
);
|
|
52
|
+
if (result.success) dineway.invalidateManifest();
|
|
53
|
+
if (result.success) {
|
|
54
|
+
await logSchemaActivity(dineway.db, locals, {
|
|
55
|
+
action: "field_created",
|
|
56
|
+
collection: collectionSlug,
|
|
57
|
+
field: body.slug,
|
|
58
|
+
...schemaApiRouteSource("field_created"),
|
|
59
|
+
summary: `Created field ${body.slug} in ${collectionSlug}`,
|
|
60
|
+
detail: {
|
|
61
|
+
fieldType: body.type,
|
|
62
|
+
label: body.label,
|
|
63
|
+
},
|
|
64
|
+
});
|
|
65
|
+
}
|
|
51
66
|
return unwrapResult(result, 201);
|
|
52
67
|
};
|
|
@@ -11,6 +11,7 @@ import { requireDb, unwrapResult } from "#api/error.js";
|
|
|
11
11
|
import { handleSchemaFieldReorder } from "#api/index.js";
|
|
12
12
|
import { parseBody, isParseError } from "#api/parse.js";
|
|
13
13
|
import { fieldReorderBody } from "#api/schemas.js";
|
|
14
|
+
import { logSchemaActivity, schemaApiRouteSource } from "#site-context/activity-events.js";
|
|
14
15
|
|
|
15
16
|
export const prerender = false;
|
|
16
17
|
|
|
@@ -28,5 +29,17 @@ export const POST: APIRoute = async ({ params, request, locals }) => {
|
|
|
28
29
|
if (isParseError(body)) return body;
|
|
29
30
|
|
|
30
31
|
const result = await handleSchemaFieldReorder(dineway.db, collectionSlug, body.fieldSlugs);
|
|
32
|
+
if (result.success) dineway.invalidateManifest();
|
|
33
|
+
if (result.success) {
|
|
34
|
+
await logSchemaActivity(dineway.db, locals, {
|
|
35
|
+
action: "fields_reordered",
|
|
36
|
+
collection: collectionSlug,
|
|
37
|
+
...schemaApiRouteSource("fields_reordered"),
|
|
38
|
+
summary: `Reordered fields in ${collectionSlug}`,
|
|
39
|
+
detail: {
|
|
40
|
+
fieldCount: body.fieldSlugs.length,
|
|
41
|
+
},
|
|
42
|
+
});
|
|
43
|
+
}
|
|
31
44
|
return unwrapResult(result);
|
|
32
45
|
};
|
|
@@ -18,6 +18,11 @@ import {
|
|
|
18
18
|
import { parseBody, parseQuery, isParseError } from "#api/parse.js";
|
|
19
19
|
import { collectionGetQuery, updateCollectionBody } from "#api/schemas.js";
|
|
20
20
|
import type { UpdateCollectionInput } from "#schema/types.js";
|
|
21
|
+
import {
|
|
22
|
+
activityChangedKeys,
|
|
23
|
+
logSchemaActivity,
|
|
24
|
+
schemaApiRouteSource,
|
|
25
|
+
} from "#site-context/activity-events.js";
|
|
21
26
|
|
|
22
27
|
export const prerender = false;
|
|
23
28
|
|
|
@@ -59,6 +64,18 @@ export const PUT: APIRoute = async ({ params, request, locals }) => {
|
|
|
59
64
|
// eslint-disable-next-line typescript-eslint(no-unsafe-type-assertion) -- parseBody validates via Zod
|
|
60
65
|
body as UpdateCollectionInput,
|
|
61
66
|
);
|
|
67
|
+
if (result.success) dineway.invalidateManifest();
|
|
68
|
+
if (result.success) {
|
|
69
|
+
await logSchemaActivity(dineway.db, locals, {
|
|
70
|
+
action: "collection_updated",
|
|
71
|
+
collection: slug,
|
|
72
|
+
...schemaApiRouteSource("collection_updated"),
|
|
73
|
+
summary: `Updated collection ${slug}`,
|
|
74
|
+
detail: {
|
|
75
|
+
changedFields: activityChangedKeys(body),
|
|
76
|
+
},
|
|
77
|
+
});
|
|
78
|
+
}
|
|
62
79
|
return unwrapResult(result);
|
|
63
80
|
};
|
|
64
81
|
|
|
@@ -76,5 +93,15 @@ export const DELETE: APIRoute = async ({ params, url, locals }) => {
|
|
|
76
93
|
const result = await handleSchemaCollectionDelete(dineway.db, slug, {
|
|
77
94
|
force,
|
|
78
95
|
});
|
|
96
|
+
if (result.success) dineway.invalidateManifest();
|
|
97
|
+
if (result.success) {
|
|
98
|
+
await logSchemaActivity(dineway.db, locals, {
|
|
99
|
+
action: "collection_deleted",
|
|
100
|
+
collection: slug,
|
|
101
|
+
...schemaApiRouteSource("collection_deleted"),
|
|
102
|
+
summary: `Deleted collection ${slug}`,
|
|
103
|
+
detail: { force },
|
|
104
|
+
});
|
|
105
|
+
}
|
|
79
106
|
return unwrapResult(result);
|
|
80
107
|
};
|
|
@@ -13,6 +13,7 @@ import { handleSchemaCollectionList, handleSchemaCollectionCreate } from "#api/i
|
|
|
13
13
|
import { parseBody, isParseError } from "#api/parse.js";
|
|
14
14
|
import { createCollectionBody } from "#api/schemas.js";
|
|
15
15
|
import type { CreateCollectionInput } from "#schema/types.js";
|
|
16
|
+
import { logSchemaActivity, schemaApiRouteSource } from "#site-context/activity-events.js";
|
|
16
17
|
|
|
17
18
|
export const prerender = false;
|
|
18
19
|
|
|
@@ -43,5 +44,18 @@ export const POST: APIRoute = async ({ request, locals }) => {
|
|
|
43
44
|
|
|
44
45
|
// eslint-disable-next-line typescript-eslint(no-unsafe-type-assertion) -- Zod schema output narrowed to CreateCollectionInput
|
|
45
46
|
const result = await handleSchemaCollectionCreate(dineway.db, body as CreateCollectionInput);
|
|
47
|
+
if (result.success) dineway.invalidateManifest();
|
|
48
|
+
if (result.success) {
|
|
49
|
+
await logSchemaActivity(dineway.db, locals, {
|
|
50
|
+
action: "collection_created",
|
|
51
|
+
collection: body.slug,
|
|
52
|
+
...schemaApiRouteSource("collection_created"),
|
|
53
|
+
summary: `Created collection ${body.slug}`,
|
|
54
|
+
detail: {
|
|
55
|
+
label: body.label,
|
|
56
|
+
labelSingular: body.labelSingular ?? null,
|
|
57
|
+
},
|
|
58
|
+
});
|
|
59
|
+
}
|
|
46
60
|
return unwrapResult(result, 201);
|
|
47
61
|
};
|
|
@@ -7,6 +7,7 @@
|
|
|
7
7
|
*/
|
|
8
8
|
|
|
9
9
|
import type { APIRoute } from "astro";
|
|
10
|
+
import { z } from "zod";
|
|
10
11
|
|
|
11
12
|
import { requirePerm } from "#api/authorize.js";
|
|
12
13
|
import { apiError, handleError, unwrapResult } from "#api/error.js";
|
|
@@ -15,11 +16,31 @@ import {
|
|
|
15
16
|
handleSectionGet,
|
|
16
17
|
handleSectionUpdate,
|
|
17
18
|
} from "#api/handlers/sections.js";
|
|
18
|
-
import {
|
|
19
|
+
import {
|
|
20
|
+
ensureWorkflowHitlRouteRequest,
|
|
21
|
+
hitlRequiredRouteError,
|
|
22
|
+
resolveHitlRouteActor,
|
|
23
|
+
} from "#api/hitl-route-helpers.js";
|
|
24
|
+
import { isParseError, parseBody, parseQuery } from "#api/parse.js";
|
|
19
25
|
import { updateSectionBody } from "#api/schemas.js";
|
|
26
|
+
import {
|
|
27
|
+
activityChangedKeys,
|
|
28
|
+
logSectionActivity,
|
|
29
|
+
RiskPolicyEvaluator,
|
|
30
|
+
sectionApiRouteSource,
|
|
31
|
+
SectionHitlPayloadBuilder,
|
|
32
|
+
} from "#site-context/index.js";
|
|
20
33
|
|
|
21
34
|
export const prerender = false;
|
|
22
35
|
|
|
36
|
+
const updateSectionHitlBody = updateSectionBody.extend({
|
|
37
|
+
hitlRequestId: z.string().min(1).optional(),
|
|
38
|
+
});
|
|
39
|
+
|
|
40
|
+
const deleteSectionQuery = z.object({
|
|
41
|
+
hitlRequestId: z.string().min(1).optional(),
|
|
42
|
+
});
|
|
43
|
+
|
|
23
44
|
export const GET: APIRoute = async ({ params, locals }) => {
|
|
24
45
|
const { dineway, user } = locals;
|
|
25
46
|
const db = dineway.db;
|
|
@@ -53,17 +74,65 @@ export const PUT: APIRoute = async ({ params, request, locals }) => {
|
|
|
53
74
|
}
|
|
54
75
|
|
|
55
76
|
try {
|
|
56
|
-
const body = await parseBody(request,
|
|
77
|
+
const body = await parseBody(request, updateSectionHitlBody);
|
|
57
78
|
if (isParseError(body)) return body;
|
|
58
79
|
|
|
59
|
-
const
|
|
80
|
+
const current = await new SectionHitlPayloadBuilder(db).loadSectionSnapshot(slug);
|
|
81
|
+
if (!current) {
|
|
82
|
+
return apiError("NOT_FOUND", `Section "${slug}" not found`, 404);
|
|
83
|
+
}
|
|
84
|
+
|
|
85
|
+
const { hitlRequestId, ...sectionInput } = body;
|
|
86
|
+
const actor = resolveHitlRouteActor(locals);
|
|
87
|
+
const evaluator = new RiskPolicyEvaluator({
|
|
88
|
+
db,
|
|
89
|
+
handlers: dineway,
|
|
90
|
+
});
|
|
91
|
+
let approvedHitlRequestId: string | null = null;
|
|
92
|
+
|
|
93
|
+
if (evaluator.requiresWorkflowHitl(actor.identity)) {
|
|
94
|
+
const action = await new SectionHitlPayloadBuilder(db).buildUpdateSectionRequest({
|
|
95
|
+
section: current,
|
|
96
|
+
...sectionInput,
|
|
97
|
+
});
|
|
98
|
+
const decision = await evaluator.evaluateWorkflowHitl({
|
|
99
|
+
actor: actor.identity,
|
|
100
|
+
hitlRequestId,
|
|
101
|
+
action,
|
|
102
|
+
});
|
|
103
|
+
if (!decision.allowed) {
|
|
104
|
+
const ensured = await ensureWorkflowHitlRouteRequest(db, locals, decision.action);
|
|
105
|
+
return hitlRequiredRouteError(decision, ensured);
|
|
106
|
+
}
|
|
107
|
+
approvedHitlRequestId = decision.hitlRequest.id;
|
|
108
|
+
}
|
|
109
|
+
|
|
110
|
+
const result = await handleSectionUpdate(db, slug, sectionInput);
|
|
111
|
+
if (result.success) {
|
|
112
|
+
await logSectionActivity(db, locals, {
|
|
113
|
+
action: "updated",
|
|
114
|
+
sectionId: result.data.id,
|
|
115
|
+
sectionSlug: result.data.slug,
|
|
116
|
+
...sectionApiRouteSource("updated"),
|
|
117
|
+
detail: {
|
|
118
|
+
changedKeys: activityChangedKeys(sectionInput),
|
|
119
|
+
source: current.source,
|
|
120
|
+
themeId: current.themeId,
|
|
121
|
+
previewMediaId:
|
|
122
|
+
sectionInput.previewMediaId !== undefined
|
|
123
|
+
? sectionInput.previewMediaId
|
|
124
|
+
: current.previewMediaId,
|
|
125
|
+
hitlRequestId: approvedHitlRequestId,
|
|
126
|
+
},
|
|
127
|
+
});
|
|
128
|
+
}
|
|
60
129
|
return unwrapResult(result);
|
|
61
130
|
} catch (error) {
|
|
62
131
|
return handleError(error, "Failed to update section", "SECTION_UPDATE_ERROR");
|
|
63
132
|
}
|
|
64
133
|
};
|
|
65
134
|
|
|
66
|
-
export const DELETE: APIRoute = async ({ params, locals }) => {
|
|
135
|
+
export const DELETE: APIRoute = async ({ params, request, locals }) => {
|
|
67
136
|
const { dineway, user } = locals;
|
|
68
137
|
const db = dineway.db;
|
|
69
138
|
const { slug } = params;
|
|
@@ -75,8 +144,58 @@ export const DELETE: APIRoute = async ({ params, locals }) => {
|
|
|
75
144
|
return apiError("VALIDATION_ERROR", "slug is required", 400);
|
|
76
145
|
}
|
|
77
146
|
|
|
147
|
+
const query = parseQuery(new URL(request.url), deleteSectionQuery);
|
|
148
|
+
if (isParseError(query)) return query;
|
|
149
|
+
|
|
78
150
|
try {
|
|
151
|
+
const current = await new SectionHitlPayloadBuilder(db).loadSectionSnapshot(slug);
|
|
152
|
+
if (!current) {
|
|
153
|
+
return apiError("NOT_FOUND", `Section "${slug}" not found`, 404);
|
|
154
|
+
}
|
|
155
|
+
|
|
156
|
+
if (current.source === "theme") {
|
|
157
|
+
const result = await handleSectionDelete(db, slug);
|
|
158
|
+
return unwrapResult(result);
|
|
159
|
+
}
|
|
160
|
+
|
|
161
|
+
const actor = resolveHitlRouteActor(locals);
|
|
162
|
+
const evaluator = new RiskPolicyEvaluator({
|
|
163
|
+
db,
|
|
164
|
+
handlers: dineway,
|
|
165
|
+
});
|
|
166
|
+
let approvedHitlRequestId: string | null = null;
|
|
167
|
+
|
|
168
|
+
if (evaluator.requiresWorkflowHitl(actor.identity)) {
|
|
169
|
+
const action = await new SectionHitlPayloadBuilder(db).buildDeleteSectionRequest({
|
|
170
|
+
section: current,
|
|
171
|
+
});
|
|
172
|
+
const decision = await evaluator.evaluateWorkflowHitl({
|
|
173
|
+
actor: actor.identity,
|
|
174
|
+
hitlRequestId: query.hitlRequestId,
|
|
175
|
+
action,
|
|
176
|
+
});
|
|
177
|
+
if (!decision.allowed) {
|
|
178
|
+
const ensured = await ensureWorkflowHitlRouteRequest(db, locals, decision.action);
|
|
179
|
+
return hitlRequiredRouteError(decision, ensured);
|
|
180
|
+
}
|
|
181
|
+
approvedHitlRequestId = decision.hitlRequest.id;
|
|
182
|
+
}
|
|
183
|
+
|
|
79
184
|
const result = await handleSectionDelete(db, slug);
|
|
185
|
+
if (result.success) {
|
|
186
|
+
await logSectionActivity(db, locals, {
|
|
187
|
+
action: "deleted",
|
|
188
|
+
sectionId: current.id,
|
|
189
|
+
sectionSlug: current.slug,
|
|
190
|
+
...sectionApiRouteSource("deleted"),
|
|
191
|
+
detail: {
|
|
192
|
+
source: current.source,
|
|
193
|
+
themeId: current.themeId,
|
|
194
|
+
previewMediaId: current.previewMediaId,
|
|
195
|
+
hitlRequestId: approvedHitlRequestId,
|
|
196
|
+
},
|
|
197
|
+
});
|
|
198
|
+
}
|
|
80
199
|
return unwrapResult(result);
|
|
81
200
|
} catch (error) {
|
|
82
201
|
return handleError(error, "Failed to delete section", "SECTION_DELETE_ERROR");
|
|
@@ -6,15 +6,31 @@
|
|
|
6
6
|
*/
|
|
7
7
|
|
|
8
8
|
import type { APIRoute } from "astro";
|
|
9
|
+
import { z } from "zod";
|
|
9
10
|
|
|
10
11
|
import { requirePerm } from "#api/authorize.js";
|
|
11
12
|
import { handleError, unwrapResult } from "#api/error.js";
|
|
12
13
|
import { handleSectionCreate, handleSectionList } from "#api/handlers/sections.js";
|
|
14
|
+
import {
|
|
15
|
+
ensureWorkflowHitlRouteRequest,
|
|
16
|
+
hitlRequiredRouteError,
|
|
17
|
+
resolveHitlRouteActor,
|
|
18
|
+
} from "#api/hitl-route-helpers.js";
|
|
13
19
|
import { isParseError, parseBody, parseQuery } from "#api/parse.js";
|
|
14
20
|
import { createSectionBody, sectionsListQuery } from "#api/schemas.js";
|
|
21
|
+
import {
|
|
22
|
+
logSectionActivity,
|
|
23
|
+
RiskPolicyEvaluator,
|
|
24
|
+
sectionApiRouteSource,
|
|
25
|
+
SectionHitlPayloadBuilder,
|
|
26
|
+
} from "#site-context/index.js";
|
|
15
27
|
|
|
16
28
|
export const prerender = false;
|
|
17
29
|
|
|
30
|
+
const createSectionHitlBody = createSectionBody.extend({
|
|
31
|
+
hitlRequestId: z.string().min(1).optional(),
|
|
32
|
+
});
|
|
33
|
+
|
|
18
34
|
export const GET: APIRoute = async ({ url, locals }) => {
|
|
19
35
|
const { dineway, user } = locals;
|
|
20
36
|
const db = dineway.db;
|
|
@@ -41,10 +57,49 @@ export const POST: APIRoute = async ({ request, locals }) => {
|
|
|
41
57
|
if (denied) return denied;
|
|
42
58
|
|
|
43
59
|
try {
|
|
44
|
-
const body = await parseBody(request,
|
|
60
|
+
const body = await parseBody(request, createSectionHitlBody);
|
|
45
61
|
if (isParseError(body)) return body;
|
|
46
62
|
|
|
47
|
-
const
|
|
63
|
+
const { hitlRequestId, ...sectionInput } = body;
|
|
64
|
+
const actor = resolveHitlRouteActor(locals);
|
|
65
|
+
const evaluator = new RiskPolicyEvaluator({
|
|
66
|
+
db,
|
|
67
|
+
handlers: dineway,
|
|
68
|
+
});
|
|
69
|
+
let approvedHitlRequestId: string | null = null;
|
|
70
|
+
|
|
71
|
+
if (evaluator.requiresWorkflowHitl(actor.identity)) {
|
|
72
|
+
const action = await new SectionHitlPayloadBuilder(db).buildCreateSectionRequest(
|
|
73
|
+
sectionInput,
|
|
74
|
+
);
|
|
75
|
+
const decision = await evaluator.evaluateWorkflowHitl({
|
|
76
|
+
actor: actor.identity,
|
|
77
|
+
hitlRequestId,
|
|
78
|
+
action,
|
|
79
|
+
});
|
|
80
|
+
if (!decision.allowed) {
|
|
81
|
+
const ensured = await ensureWorkflowHitlRouteRequest(db, locals, decision.action);
|
|
82
|
+
return hitlRequiredRouteError(decision, ensured);
|
|
83
|
+
}
|
|
84
|
+
approvedHitlRequestId = decision.hitlRequest.id;
|
|
85
|
+
}
|
|
86
|
+
|
|
87
|
+
const result = await handleSectionCreate(db, sectionInput);
|
|
88
|
+
if (result.success) {
|
|
89
|
+
await logSectionActivity(db, locals, {
|
|
90
|
+
action: "created",
|
|
91
|
+
sectionId: result.data.id,
|
|
92
|
+
sectionSlug: result.data.slug,
|
|
93
|
+
...sectionApiRouteSource("created"),
|
|
94
|
+
detail: {
|
|
95
|
+
title: result.data.title,
|
|
96
|
+
source: result.data.source,
|
|
97
|
+
themeId: result.data.themeId ?? null,
|
|
98
|
+
previewMediaId: sectionInput.previewMediaId ?? null,
|
|
99
|
+
hitlRequestId: approvedHitlRequestId,
|
|
100
|
+
},
|
|
101
|
+
});
|
|
102
|
+
}
|
|
48
103
|
return unwrapResult(result, 201);
|
|
49
104
|
} catch (error) {
|
|
50
105
|
return handleError(error, "Failed to create section", "SECTION_CREATE_ERROR");
|
|
@@ -6,15 +6,31 @@
|
|
|
6
6
|
*/
|
|
7
7
|
|
|
8
8
|
import type { APIRoute } from "astro";
|
|
9
|
+
import { z } from "zod";
|
|
9
10
|
|
|
10
11
|
import { requirePerm } from "#api/authorize.js";
|
|
11
12
|
import { apiError, handleError, unwrapResult } from "#api/error.js";
|
|
12
13
|
import { handleSettingsGet, handleSettingsUpdate } from "#api/handlers/settings.js";
|
|
14
|
+
import {
|
|
15
|
+
ensureWorkflowHitlRouteRequest,
|
|
16
|
+
hitlRequiredRouteError,
|
|
17
|
+
resolveHitlRouteActor,
|
|
18
|
+
} from "#api/hitl-route-helpers.js";
|
|
13
19
|
import { isParseError, parseBody } from "#api/parse.js";
|
|
14
20
|
import { settingsUpdateBody } from "#api/schemas.js";
|
|
21
|
+
import {
|
|
22
|
+
logSiteActivitySafely,
|
|
23
|
+
RiskPolicyEvaluator,
|
|
24
|
+
settingsApiRouteSource,
|
|
25
|
+
SettingsHitlPayloadBuilder,
|
|
26
|
+
} from "#site-context/index.js";
|
|
15
27
|
|
|
16
28
|
export const prerender = false;
|
|
17
29
|
|
|
30
|
+
const settingsHitlBody = settingsUpdateBody.extend({
|
|
31
|
+
hitlRequestId: z.string().min(1).optional(),
|
|
32
|
+
});
|
|
33
|
+
|
|
18
34
|
/**
|
|
19
35
|
* GET /_dineway/api/settings
|
|
20
36
|
*
|
|
@@ -56,10 +72,43 @@ export const POST: APIRoute = async ({ request, locals }) => {
|
|
|
56
72
|
if (denied) return denied;
|
|
57
73
|
|
|
58
74
|
try {
|
|
59
|
-
const body = await parseBody(request,
|
|
75
|
+
const body = await parseBody(request, settingsHitlBody);
|
|
60
76
|
if (isParseError(body)) return body;
|
|
61
77
|
|
|
62
|
-
const
|
|
78
|
+
const { hitlRequestId, ...settingsInput } = body;
|
|
79
|
+
const actor = resolveHitlRouteActor(locals);
|
|
80
|
+
const action = await new SettingsHitlPayloadBuilder(dineway.db).buildUpdateSettingsRequest(
|
|
81
|
+
settingsInput,
|
|
82
|
+
);
|
|
83
|
+
const decision = await new RiskPolicyEvaluator({
|
|
84
|
+
db: dineway.db,
|
|
85
|
+
handlers: dineway,
|
|
86
|
+
}).evaluateWorkflowHitl({
|
|
87
|
+
actor: actor.identity,
|
|
88
|
+
hitlRequestId,
|
|
89
|
+
action,
|
|
90
|
+
});
|
|
91
|
+
if (!decision.allowed) {
|
|
92
|
+
const ensured = await ensureWorkflowHitlRouteRequest(dineway.db, locals, decision.action);
|
|
93
|
+
return hitlRequiredRouteError(decision, ensured);
|
|
94
|
+
}
|
|
95
|
+
|
|
96
|
+
const result = await handleSettingsUpdate(dineway.db, dineway.storage, settingsInput);
|
|
97
|
+
if (!result.success) return unwrapResult(result);
|
|
98
|
+
|
|
99
|
+
await logSiteActivitySafely(dineway.db, locals, {
|
|
100
|
+
actionType: "settings.updated",
|
|
101
|
+
subjectType: "site_settings",
|
|
102
|
+
subjectId: "site",
|
|
103
|
+
scope: "site",
|
|
104
|
+
...settingsApiRouteSource("updated"),
|
|
105
|
+
summary: action.summary ?? "Updated site settings",
|
|
106
|
+
detail: {
|
|
107
|
+
changedKeys: Object.keys(settingsInput).toSorted(),
|
|
108
|
+
touchesSeo: Object.hasOwn(settingsInput, "seo"),
|
|
109
|
+
hitlRequestId: decision.required ? decision.hitlRequest.id : null,
|
|
110
|
+
},
|
|
111
|
+
});
|
|
63
112
|
return unwrapResult(result);
|
|
64
113
|
} catch (error) {
|
|
65
114
|
return handleError(error, "Failed to update settings", "SETTINGS_UPDATE_ERROR");
|
|
@@ -8,7 +8,7 @@ import type { APIRoute } from "astro";
|
|
|
8
8
|
|
|
9
9
|
export const prerender = false;
|
|
10
10
|
|
|
11
|
-
import { Role } from "@dineway-ai/auth";
|
|
11
|
+
import { Role, secureCompare } from "@dineway-ai/auth";
|
|
12
12
|
import { createKyselyAdapter } from "@dineway-ai/auth/adapters/kysely";
|
|
13
13
|
import { verifyRegistrationResponse, registerPasskey } from "@dineway-ai/auth/passkey";
|
|
14
14
|
|
|
@@ -18,9 +18,10 @@ import { getPublicOrigin } from "#api/public-url.js";
|
|
|
18
18
|
import { setupAdminVerifyBody } from "#api/schemas.js";
|
|
19
19
|
import { createChallengeStore } from "#auth/challenge-store.js";
|
|
20
20
|
import { getPasskeyConfig } from "#auth/passkey-config.js";
|
|
21
|
+
import { SETUP_NONCE_COOKIE } from "#auth/setup-nonce.js";
|
|
21
22
|
import { OptionsRepository } from "#db/repositories/options.js";
|
|
22
23
|
|
|
23
|
-
export const POST: APIRoute = async ({ request, locals }) => {
|
|
24
|
+
export const POST: APIRoute = async ({ cookies, request, locals }) => {
|
|
24
25
|
const { dineway } = locals;
|
|
25
26
|
|
|
26
27
|
if (!dineway?.db) {
|
|
@@ -45,12 +46,30 @@ export const POST: APIRoute = async ({ request, locals }) => {
|
|
|
45
46
|
}
|
|
46
47
|
|
|
47
48
|
// Get setup state
|
|
48
|
-
const setupState = await options.get
|
|
49
|
+
const setupState = await options.get<{
|
|
50
|
+
step?: string;
|
|
51
|
+
email?: string;
|
|
52
|
+
name?: string | null;
|
|
53
|
+
nonce?: string;
|
|
54
|
+
}>("dineway:setup_state");
|
|
49
55
|
|
|
50
56
|
if (!setupState || setupState.step !== "admin") {
|
|
51
57
|
return apiError("INVALID_STATE", "Invalid setup state. Please restart setup.", 400);
|
|
52
58
|
}
|
|
53
59
|
|
|
60
|
+
const cookieNonce = cookies.get(SETUP_NONCE_COOKIE)?.value;
|
|
61
|
+
if (!setupState.nonce || !cookieNonce || !secureCompare(cookieNonce, setupState.nonce)) {
|
|
62
|
+
return apiError(
|
|
63
|
+
"INVALID_STATE",
|
|
64
|
+
"Setup session expired or tampered with. Please restart the admin step.",
|
|
65
|
+
400,
|
|
66
|
+
);
|
|
67
|
+
}
|
|
68
|
+
|
|
69
|
+
if (!setupState.email) {
|
|
70
|
+
return apiError("INVALID_STATE", "Invalid setup state. Please restart setup.", 400);
|
|
71
|
+
}
|
|
72
|
+
|
|
54
73
|
// Parse request body
|
|
55
74
|
const body = await parseBody(request, setupAdminVerifyBody);
|
|
56
75
|
if (isParseError(body)) return body;
|
|
@@ -73,7 +92,7 @@ export const POST: APIRoute = async ({ request, locals }) => {
|
|
|
73
92
|
// Create the admin user
|
|
74
93
|
const user = await adapter.createUser({
|
|
75
94
|
email: setupState.email,
|
|
76
|
-
name: setupState.name,
|
|
95
|
+
name: setupState.name ?? null,
|
|
77
96
|
role: Role.ADMIN,
|
|
78
97
|
emailVerified: false, // No email verification for first user
|
|
79
98
|
});
|
|
@@ -84,8 +103,9 @@ export const POST: APIRoute = async ({ request, locals }) => {
|
|
|
84
103
|
// Mark setup as complete
|
|
85
104
|
await options.set("dineway:setup_complete", true);
|
|
86
105
|
|
|
87
|
-
// Clean up setup state
|
|
106
|
+
// Clean up setup state and the session nonce cookie
|
|
88
107
|
await options.delete("dineway:setup_state");
|
|
108
|
+
cookies.delete(SETUP_NONCE_COOKIE, { path: "/_dineway/" });
|
|
89
109
|
|
|
90
110
|
return apiSuccess({
|
|
91
111
|
success: true,
|
|
@@ -8,6 +8,7 @@ import type { APIRoute } from "astro";
|
|
|
8
8
|
|
|
9
9
|
export const prerender = false;
|
|
10
10
|
|
|
11
|
+
import { generateToken } from "@dineway-ai/auth";
|
|
11
12
|
import { createKyselyAdapter } from "@dineway-ai/auth/adapters/kysely";
|
|
12
13
|
import { generateRegistrationOptions } from "@dineway-ai/auth/passkey";
|
|
13
14
|
|
|
@@ -17,9 +18,10 @@ import { getPublicOrigin } from "#api/public-url.js";
|
|
|
17
18
|
import { setupAdminBody } from "#api/schemas.js";
|
|
18
19
|
import { createChallengeStore } from "#auth/challenge-store.js";
|
|
19
20
|
import { getPasskeyConfig } from "#auth/passkey-config.js";
|
|
21
|
+
import { SETUP_NONCE_COOKIE, SETUP_NONCE_MAX_AGE_SECONDS } from "#auth/setup-nonce.js";
|
|
20
22
|
import { OptionsRepository } from "#db/repositories/options.js";
|
|
21
23
|
|
|
22
|
-
export const POST: APIRoute = async ({ request, locals }) => {
|
|
24
|
+
export const POST: APIRoute = async ({ cookies, request, locals }) => {
|
|
23
25
|
const { dineway } = locals;
|
|
24
26
|
|
|
25
27
|
if (!dineway?.db) {
|
|
@@ -47,12 +49,7 @@ export const POST: APIRoute = async ({ request, locals }) => {
|
|
|
47
49
|
const body = await parseBody(request, setupAdminBody);
|
|
48
50
|
if (isParseError(body)) return body;
|
|
49
51
|
|
|
50
|
-
|
|
51
|
-
await options.set("dineway:setup_state", {
|
|
52
|
-
step: "admin",
|
|
53
|
-
email: body.email.toLowerCase(),
|
|
54
|
-
name: body.name || null,
|
|
55
|
-
});
|
|
52
|
+
const nonce = generateToken();
|
|
56
53
|
|
|
57
54
|
// Get passkey config
|
|
58
55
|
const url = new URL(request.url);
|
|
@@ -78,12 +75,23 @@ export const POST: APIRoute = async ({ request, locals }) => {
|
|
|
78
75
|
challengeStore,
|
|
79
76
|
);
|
|
80
77
|
|
|
81
|
-
// Store the
|
|
78
|
+
// Store the nonce with the setup state. The verify endpoint compares
|
|
79
|
+
// it to an HttpOnly cookie so the admin step stays bound to this browser.
|
|
82
80
|
await options.set("dineway:setup_state", {
|
|
83
81
|
step: "admin",
|
|
84
82
|
email: body.email.toLowerCase(),
|
|
85
83
|
name: body.name || null,
|
|
86
84
|
tempUserId: tempUser.id,
|
|
85
|
+
nonce,
|
|
86
|
+
});
|
|
87
|
+
|
|
88
|
+
const publicOrigin = new URL(siteUrl);
|
|
89
|
+
cookies.set(SETUP_NONCE_COOKIE, nonce, {
|
|
90
|
+
path: "/_dineway/",
|
|
91
|
+
httpOnly: true,
|
|
92
|
+
sameSite: "strict",
|
|
93
|
+
secure: publicOrigin.protocol === "https:",
|
|
94
|
+
maxAge: SETUP_NONCE_MAX_AGE_SECONDS,
|
|
87
95
|
});
|
|
88
96
|
|
|
89
97
|
return apiSuccess({
|
|
@@ -89,9 +89,10 @@ export const POST: APIRoute = async ({ request, url, locals }) => {
|
|
|
89
89
|
const options = new OptionsRepository(dineway.db);
|
|
90
90
|
|
|
91
91
|
// Store the canonical site URL from the setup request.
|
|
92
|
-
//
|
|
92
|
+
// Keep the first value so later unauthenticated setup calls cannot
|
|
93
|
+
// rewrite the public origin during the setup window.
|
|
93
94
|
const siteUrl = getPublicOrigin(url, dineway.config);
|
|
94
|
-
await options.
|
|
95
|
+
await options.setIfAbsent("dineway:site_url", siteUrl);
|
|
95
96
|
|
|
96
97
|
if (useExternalAuth) {
|
|
97
98
|
// External auth mode: mark setup complete now
|