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
|
@@ -7,15 +7,36 @@
|
|
|
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, requireDb, unwrapResult } from "#api/error.js";
|
|
13
14
|
import { handleTermDelete, handleTermGet, handleTermUpdate } from "#api/handlers/taxonomies.js";
|
|
14
|
-
import {
|
|
15
|
+
import {
|
|
16
|
+
ensureWorkflowHitlRouteRequest,
|
|
17
|
+
hitlRequiredRouteError,
|
|
18
|
+
resolveHitlRouteActor,
|
|
19
|
+
} from "#api/hitl-route-helpers.js";
|
|
20
|
+
import { isParseError, parseBody, parseQuery } from "#api/parse.js";
|
|
15
21
|
import { updateTermBody } from "#api/schemas.js";
|
|
22
|
+
import {
|
|
23
|
+
activityChangedKeys,
|
|
24
|
+
logTaxonomyActivity,
|
|
25
|
+
RiskPolicyEvaluator,
|
|
26
|
+
taxonomyApiRouteSource,
|
|
27
|
+
TaxonomyHitlPayloadBuilder,
|
|
28
|
+
} from "#site-context/index.js";
|
|
16
29
|
|
|
17
30
|
export const prerender = false;
|
|
18
31
|
|
|
32
|
+
const updateTermHitlBody = updateTermBody.extend({
|
|
33
|
+
hitlRequestId: z.string().min(1).optional(),
|
|
34
|
+
});
|
|
35
|
+
|
|
36
|
+
const deleteTermQuery = z.object({
|
|
37
|
+
hitlRequestId: z.string().min(1).optional(),
|
|
38
|
+
});
|
|
39
|
+
|
|
19
40
|
/**
|
|
20
41
|
* Get a single term
|
|
21
42
|
*/
|
|
@@ -59,10 +80,68 @@ export const PUT: APIRoute = async ({ params, request, locals }) => {
|
|
|
59
80
|
if (denied) return denied;
|
|
60
81
|
|
|
61
82
|
try {
|
|
62
|
-
const body = await parseBody(request,
|
|
83
|
+
const body = await parseBody(request, updateTermHitlBody);
|
|
63
84
|
if (isParseError(body)) return body;
|
|
64
85
|
|
|
65
|
-
const
|
|
86
|
+
const current = await handleTermGet(dineway.db, name, slug);
|
|
87
|
+
if (!current.success) return unwrapResult(current);
|
|
88
|
+
|
|
89
|
+
const { hitlRequestId, ...termInput } = body;
|
|
90
|
+
const actor = resolveHitlRouteActor(locals);
|
|
91
|
+
const evaluator = new RiskPolicyEvaluator({
|
|
92
|
+
db: dineway.db,
|
|
93
|
+
handlers: dineway,
|
|
94
|
+
});
|
|
95
|
+
let approvedHitlRequestId: string | null = null;
|
|
96
|
+
|
|
97
|
+
if (evaluator.requiresWorkflowHitl(actor.identity)) {
|
|
98
|
+
const payloadBuilder = new TaxonomyHitlPayloadBuilder(dineway.db);
|
|
99
|
+
const taxonomy = await payloadBuilder.loadTaxonomyDefinition(name);
|
|
100
|
+
if (!taxonomy) {
|
|
101
|
+
return apiError("NOT_FOUND", `Taxonomy '${name}' not found`, 404);
|
|
102
|
+
}
|
|
103
|
+
|
|
104
|
+
const action = await payloadBuilder.buildUpdateTermRequest({
|
|
105
|
+
taxonomy,
|
|
106
|
+
currentTerm: {
|
|
107
|
+
id: current.data.term.id,
|
|
108
|
+
name: current.data.term.name,
|
|
109
|
+
slug: current.data.term.slug,
|
|
110
|
+
label: current.data.term.label,
|
|
111
|
+
parentId: current.data.term.parentId,
|
|
112
|
+
description: current.data.term.description ?? null,
|
|
113
|
+
},
|
|
114
|
+
...termInput,
|
|
115
|
+
});
|
|
116
|
+
const decision = await evaluator.evaluateWorkflowHitl({
|
|
117
|
+
actor: actor.identity,
|
|
118
|
+
hitlRequestId,
|
|
119
|
+
action,
|
|
120
|
+
});
|
|
121
|
+
if (!decision.allowed) {
|
|
122
|
+
const ensured = await ensureWorkflowHitlRouteRequest(dineway.db, locals, decision.action);
|
|
123
|
+
return hitlRequiredRouteError(decision, ensured);
|
|
124
|
+
}
|
|
125
|
+
approvedHitlRequestId = decision.hitlRequest.id;
|
|
126
|
+
}
|
|
127
|
+
|
|
128
|
+
const result = await handleTermUpdate(dineway.db, name, slug, termInput);
|
|
129
|
+
if (result.success) {
|
|
130
|
+
await logTaxonomyActivity(dineway.db, locals, {
|
|
131
|
+
action: "term_updated",
|
|
132
|
+
taxonomyName: name,
|
|
133
|
+
termId: result.data.term.id,
|
|
134
|
+
termSlug: result.data.term.slug,
|
|
135
|
+
...taxonomyApiRouteSource("term_updated"),
|
|
136
|
+
detail: {
|
|
137
|
+
changedKeys: activityChangedKeys(termInput),
|
|
138
|
+
label: result.data.term.label,
|
|
139
|
+
parentId: result.data.term.parentId,
|
|
140
|
+
description: result.data.term.description ?? null,
|
|
141
|
+
hitlRequestId: approvedHitlRequestId,
|
|
142
|
+
},
|
|
143
|
+
});
|
|
144
|
+
}
|
|
66
145
|
return unwrapResult(result);
|
|
67
146
|
} catch (error) {
|
|
68
147
|
return handleError(error, "Failed to update term", "TERM_UPDATE_ERROR");
|
|
@@ -72,7 +151,7 @@ export const PUT: APIRoute = async ({ params, request, locals }) => {
|
|
|
72
151
|
/**
|
|
73
152
|
* Delete a term
|
|
74
153
|
*/
|
|
75
|
-
export const DELETE: APIRoute = async ({ params, locals }) => {
|
|
154
|
+
export const DELETE: APIRoute = async ({ params, request, locals }) => {
|
|
76
155
|
const { dineway, user } = locals;
|
|
77
156
|
const { name, slug } = params;
|
|
78
157
|
|
|
@@ -86,8 +165,66 @@ export const DELETE: APIRoute = async ({ params, locals }) => {
|
|
|
86
165
|
const denied = requirePerm(user, "taxonomies:manage");
|
|
87
166
|
if (denied) return denied;
|
|
88
167
|
|
|
168
|
+
const query = parseQuery(new URL(request.url), deleteTermQuery);
|
|
169
|
+
if (isParseError(query)) return query;
|
|
170
|
+
|
|
89
171
|
try {
|
|
172
|
+
const current = await handleTermGet(dineway.db, name, slug);
|
|
173
|
+
if (!current.success) return unwrapResult(current);
|
|
174
|
+
|
|
175
|
+
const actor = resolveHitlRouteActor(locals);
|
|
176
|
+
const evaluator = new RiskPolicyEvaluator({
|
|
177
|
+
db: dineway.db,
|
|
178
|
+
handlers: dineway,
|
|
179
|
+
});
|
|
180
|
+
let approvedHitlRequestId: string | null = null;
|
|
181
|
+
|
|
182
|
+
if (evaluator.requiresWorkflowHitl(actor.identity)) {
|
|
183
|
+
const payloadBuilder = new TaxonomyHitlPayloadBuilder(dineway.db);
|
|
184
|
+
const taxonomy = await payloadBuilder.loadTaxonomyDefinition(name);
|
|
185
|
+
if (!taxonomy) {
|
|
186
|
+
return apiError("NOT_FOUND", `Taxonomy '${name}' not found`, 404);
|
|
187
|
+
}
|
|
188
|
+
|
|
189
|
+
const action = await payloadBuilder.buildDeleteTermRequest({
|
|
190
|
+
taxonomy,
|
|
191
|
+
currentTerm: {
|
|
192
|
+
id: current.data.term.id,
|
|
193
|
+
name: current.data.term.name,
|
|
194
|
+
slug: current.data.term.slug,
|
|
195
|
+
label: current.data.term.label,
|
|
196
|
+
parentId: current.data.term.parentId,
|
|
197
|
+
description: current.data.term.description ?? null,
|
|
198
|
+
},
|
|
199
|
+
});
|
|
200
|
+
const decision = await evaluator.evaluateWorkflowHitl({
|
|
201
|
+
actor: actor.identity,
|
|
202
|
+
hitlRequestId: query.hitlRequestId,
|
|
203
|
+
action,
|
|
204
|
+
});
|
|
205
|
+
if (!decision.allowed) {
|
|
206
|
+
const ensured = await ensureWorkflowHitlRouteRequest(dineway.db, locals, decision.action);
|
|
207
|
+
return hitlRequiredRouteError(decision, ensured);
|
|
208
|
+
}
|
|
209
|
+
approvedHitlRequestId = decision.hitlRequest.id;
|
|
210
|
+
}
|
|
211
|
+
|
|
90
212
|
const result = await handleTermDelete(dineway.db, name, slug);
|
|
213
|
+
if (result.success) {
|
|
214
|
+
await logTaxonomyActivity(dineway.db, locals, {
|
|
215
|
+
action: "term_deleted",
|
|
216
|
+
taxonomyName: name,
|
|
217
|
+
termId: current.data.term.id,
|
|
218
|
+
termSlug: current.data.term.slug,
|
|
219
|
+
...taxonomyApiRouteSource("term_deleted"),
|
|
220
|
+
detail: {
|
|
221
|
+
label: current.data.term.label,
|
|
222
|
+
parentId: current.data.term.parentId,
|
|
223
|
+
description: current.data.term.description ?? null,
|
|
224
|
+
hitlRequestId: approvedHitlRequestId,
|
|
225
|
+
},
|
|
226
|
+
});
|
|
227
|
+
}
|
|
91
228
|
return unwrapResult(result);
|
|
92
229
|
} catch (error) {
|
|
93
230
|
return handleError(error, "Failed to delete term", "TERM_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 { apiError, handleError, requireDb, unwrapResult } from "#api/error.js";
|
|
12
13
|
import { handleTermCreate, handleTermList } from "#api/handlers/taxonomies.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 { createTermBody } from "#api/schemas.js";
|
|
21
|
+
import {
|
|
22
|
+
logTaxonomyActivity,
|
|
23
|
+
RiskPolicyEvaluator,
|
|
24
|
+
taxonomyApiRouteSource,
|
|
25
|
+
TaxonomyHitlPayloadBuilder,
|
|
26
|
+
} from "#site-context/index.js";
|
|
15
27
|
|
|
16
28
|
export const prerender = false;
|
|
17
29
|
|
|
30
|
+
const createTermHitlBody = createTermBody.extend({
|
|
31
|
+
hitlRequestId: z.string().min(1).optional(),
|
|
32
|
+
});
|
|
33
|
+
|
|
18
34
|
/**
|
|
19
35
|
* List all terms for a taxonomy
|
|
20
36
|
*/
|
|
@@ -58,10 +74,56 @@ export const POST: APIRoute = async ({ params, request, locals }) => {
|
|
|
58
74
|
if (denied) return denied;
|
|
59
75
|
|
|
60
76
|
try {
|
|
61
|
-
const body = await parseBody(request,
|
|
77
|
+
const body = await parseBody(request, createTermHitlBody);
|
|
62
78
|
if (isParseError(body)) return body;
|
|
63
79
|
|
|
64
|
-
const
|
|
80
|
+
const { hitlRequestId, ...termInput } = body;
|
|
81
|
+
const actor = resolveHitlRouteActor(locals);
|
|
82
|
+
const evaluator = new RiskPolicyEvaluator({
|
|
83
|
+
db: dineway.db,
|
|
84
|
+
handlers: dineway,
|
|
85
|
+
});
|
|
86
|
+
let approvedHitlRequestId: string | null = null;
|
|
87
|
+
|
|
88
|
+
if (evaluator.requiresWorkflowHitl(actor.identity)) {
|
|
89
|
+
const payloadBuilder = new TaxonomyHitlPayloadBuilder(dineway.db);
|
|
90
|
+
const taxonomy = await payloadBuilder.loadTaxonomyDefinition(name);
|
|
91
|
+
if (!taxonomy) {
|
|
92
|
+
return apiError("NOT_FOUND", `Taxonomy '${name}' not found`, 404);
|
|
93
|
+
}
|
|
94
|
+
|
|
95
|
+
const action = await payloadBuilder.buildCreateTermRequest({
|
|
96
|
+
taxonomy,
|
|
97
|
+
...termInput,
|
|
98
|
+
});
|
|
99
|
+
const decision = await evaluator.evaluateWorkflowHitl({
|
|
100
|
+
actor: actor.identity,
|
|
101
|
+
hitlRequestId,
|
|
102
|
+
action,
|
|
103
|
+
});
|
|
104
|
+
if (!decision.allowed) {
|
|
105
|
+
const ensured = await ensureWorkflowHitlRouteRequest(dineway.db, locals, decision.action);
|
|
106
|
+
return hitlRequiredRouteError(decision, ensured);
|
|
107
|
+
}
|
|
108
|
+
approvedHitlRequestId = decision.hitlRequest.id;
|
|
109
|
+
}
|
|
110
|
+
|
|
111
|
+
const result = await handleTermCreate(dineway.db, name, termInput);
|
|
112
|
+
if (result.success) {
|
|
113
|
+
await logTaxonomyActivity(dineway.db, locals, {
|
|
114
|
+
action: "term_created",
|
|
115
|
+
taxonomyName: name,
|
|
116
|
+
termId: result.data.term.id,
|
|
117
|
+
termSlug: result.data.term.slug,
|
|
118
|
+
...taxonomyApiRouteSource("term_created"),
|
|
119
|
+
detail: {
|
|
120
|
+
label: result.data.term.label,
|
|
121
|
+
parentId: result.data.term.parentId,
|
|
122
|
+
description: result.data.term.description ?? null,
|
|
123
|
+
hitlRequestId: approvedHitlRequestId,
|
|
124
|
+
},
|
|
125
|
+
});
|
|
126
|
+
}
|
|
65
127
|
return unwrapResult(result, 201);
|
|
66
128
|
} catch (error) {
|
|
67
129
|
return handleError(error, "Failed to create term", "TERM_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 { handleError, requireDb, unwrapResult } from "#api/error.js";
|
|
12
13
|
import { handleTaxonomyCreate, handleTaxonomyList } from "#api/handlers/taxonomies.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 { createTaxonomyDefBody } from "#api/schemas.js";
|
|
21
|
+
import {
|
|
22
|
+
logTaxonomyActivity,
|
|
23
|
+
RiskPolicyEvaluator,
|
|
24
|
+
taxonomyApiRouteSource,
|
|
25
|
+
TaxonomyHitlPayloadBuilder,
|
|
26
|
+
} from "#site-context/index.js";
|
|
15
27
|
|
|
16
28
|
export const prerender = false;
|
|
17
29
|
|
|
30
|
+
const createTaxonomyHitlBody = createTaxonomyDefBody.extend({
|
|
31
|
+
hitlRequestId: z.string().min(1).optional(),
|
|
32
|
+
});
|
|
33
|
+
|
|
18
34
|
/**
|
|
19
35
|
* List taxonomy definitions
|
|
20
36
|
*/
|
|
@@ -48,10 +64,49 @@ export const POST: APIRoute = async ({ request, locals }) => {
|
|
|
48
64
|
if (denied) return denied;
|
|
49
65
|
|
|
50
66
|
try {
|
|
51
|
-
const body = await parseBody(request,
|
|
67
|
+
const body = await parseBody(request, createTaxonomyHitlBody);
|
|
52
68
|
if (isParseError(body)) return body;
|
|
53
69
|
|
|
54
|
-
const
|
|
70
|
+
const { hitlRequestId, ...taxonomyInput } = body;
|
|
71
|
+
const actor = resolveHitlRouteActor(locals);
|
|
72
|
+
const evaluator = new RiskPolicyEvaluator({
|
|
73
|
+
db: dineway.db,
|
|
74
|
+
handlers: dineway,
|
|
75
|
+
});
|
|
76
|
+
let approvedHitlRequestId: string | null = null;
|
|
77
|
+
|
|
78
|
+
if (evaluator.requiresWorkflowHitl(actor.identity)) {
|
|
79
|
+
const action = await new TaxonomyHitlPayloadBuilder(dineway.db).buildCreateTaxonomyRequest(
|
|
80
|
+
taxonomyInput,
|
|
81
|
+
);
|
|
82
|
+
const decision = await evaluator.evaluateWorkflowHitl({
|
|
83
|
+
actor: actor.identity,
|
|
84
|
+
hitlRequestId,
|
|
85
|
+
action,
|
|
86
|
+
});
|
|
87
|
+
if (!decision.allowed) {
|
|
88
|
+
const ensured = await ensureWorkflowHitlRouteRequest(dineway.db, locals, decision.action);
|
|
89
|
+
return hitlRequiredRouteError(decision, ensured);
|
|
90
|
+
}
|
|
91
|
+
approvedHitlRequestId = decision.hitlRequest.id;
|
|
92
|
+
}
|
|
93
|
+
|
|
94
|
+
const result = await handleTaxonomyCreate(dineway.db, taxonomyInput);
|
|
95
|
+
if (result.success) dineway.invalidateManifest();
|
|
96
|
+
if (result.success) {
|
|
97
|
+
await logTaxonomyActivity(dineway.db, locals, {
|
|
98
|
+
action: "created",
|
|
99
|
+
taxonomyId: result.data.taxonomy.id,
|
|
100
|
+
taxonomyName: result.data.taxonomy.name,
|
|
101
|
+
...taxonomyApiRouteSource("created"),
|
|
102
|
+
detail: {
|
|
103
|
+
label: result.data.taxonomy.label,
|
|
104
|
+
hierarchical: result.data.taxonomy.hierarchical,
|
|
105
|
+
collections: result.data.taxonomy.collections,
|
|
106
|
+
hitlRequestId: approvedHitlRequestId,
|
|
107
|
+
},
|
|
108
|
+
});
|
|
109
|
+
}
|
|
55
110
|
return unwrapResult(result, 201);
|
|
56
111
|
} catch (error) {
|
|
57
112
|
return handleError(error, "Failed to create taxonomy", "TAXONOMY_CREATE_ERROR");
|
|
@@ -10,6 +10,8 @@ import type { APIRoute } from "astro";
|
|
|
10
10
|
import { getAuthMode } from "#auth/mode.js";
|
|
11
11
|
import { OptionsRepository } from "#db/repositories/options.js";
|
|
12
12
|
|
|
13
|
+
import { VERSION } from "../../../../version.js";
|
|
14
|
+
|
|
13
15
|
export const prerender = false;
|
|
14
16
|
|
|
15
17
|
export const GET: APIRoute = async ({ locals }) => {
|
|
@@ -35,7 +37,7 @@ export const GET: APIRoute = async ({ locals }) => {
|
|
|
35
37
|
const response: Record<string, unknown> = {
|
|
36
38
|
instance: {
|
|
37
39
|
name: siteName,
|
|
38
|
-
version:
|
|
40
|
+
version: VERSION,
|
|
39
41
|
},
|
|
40
42
|
auth: {
|
|
41
43
|
mode: isExternal ? "external" : "passkey",
|
|
@@ -1,8 +1,9 @@
|
|
|
1
1
|
/**
|
|
2
|
-
* GET
|
|
2
|
+
* GET /.well-known/oauth-authorization-server/_dineway
|
|
3
3
|
*
|
|
4
|
-
* RFC 8414 Authorization Server Metadata.
|
|
5
|
-
*
|
|
4
|
+
* RFC 8414 Authorization Server Metadata. The issuer pathname (`/_dineway`)
|
|
5
|
+
* is appended after the well-known prefix so standards-compliant OAuth/MCP
|
|
6
|
+
* clients can discover the metadata from the issuer URL.
|
|
6
7
|
*
|
|
7
8
|
* Public, unauthenticated.
|
|
8
9
|
*/
|
|
@@ -10,7 +11,8 @@
|
|
|
10
11
|
import type { APIRoute } from "astro";
|
|
11
12
|
|
|
12
13
|
import { getPublicOrigin } from "#api/public-url.js";
|
|
13
|
-
import {
|
|
14
|
+
import { ALL_VALID_SCOPES } from "#auth/api-tokens.js";
|
|
15
|
+
import { filterExperimentalSiteContextWorkflowScopes } from "#site-context/experimental-workflows.js";
|
|
14
16
|
|
|
15
17
|
export const prerender = false;
|
|
16
18
|
|
|
@@ -23,7 +25,7 @@ export const GET: APIRoute = async ({ url, locals }) => {
|
|
|
23
25
|
issuer,
|
|
24
26
|
authorization_endpoint: `${origin}/_dineway/oauth/authorize`,
|
|
25
27
|
token_endpoint: `${origin}/_dineway/api/oauth/token`,
|
|
26
|
-
scopes_supported:
|
|
28
|
+
scopes_supported: filterExperimentalSiteContextWorkflowScopes(ALL_VALID_SCOPES),
|
|
27
29
|
response_types_supported: ["code"],
|
|
28
30
|
grant_types_supported: [
|
|
29
31
|
"authorization_code",
|
|
@@ -31,6 +33,7 @@ export const GET: APIRoute = async ({ url, locals }) => {
|
|
|
31
33
|
"urn:ietf:params:oauth:grant-type:device_code",
|
|
32
34
|
],
|
|
33
35
|
code_challenge_methods_supported: ["S256"],
|
|
36
|
+
registration_endpoint: `${origin}/_dineway/api/oauth/register`,
|
|
34
37
|
token_endpoint_auth_methods_supported: ["none"],
|
|
35
38
|
client_id_metadata_document_supported: true,
|
|
36
39
|
device_authorization_endpoint: `${origin}/_dineway/api/oauth/device/code`,
|
|
@@ -14,7 +14,8 @@
|
|
|
14
14
|
import type { APIRoute } from "astro";
|
|
15
15
|
|
|
16
16
|
import { getPublicOrigin } from "#api/public-url.js";
|
|
17
|
-
import {
|
|
17
|
+
import { ALL_VALID_SCOPES } from "#auth/api-tokens.js";
|
|
18
|
+
import { filterExperimentalSiteContextWorkflowScopes } from "#site-context/experimental-workflows.js";
|
|
18
19
|
|
|
19
20
|
export const prerender = false;
|
|
20
21
|
|
|
@@ -25,7 +26,7 @@ export const GET: APIRoute = async ({ url, locals }) => {
|
|
|
25
26
|
{
|
|
26
27
|
resource: `${origin}/_dineway/api/mcp`,
|
|
27
28
|
authorization_servers: [`${origin}/_dineway`],
|
|
28
|
-
scopes_supported:
|
|
29
|
+
scopes_supported: filterExperimentalSiteContextWorkflowScopes(ALL_VALID_SCOPES),
|
|
29
30
|
bearer_methods_supported: ["header"],
|
|
30
31
|
},
|
|
31
32
|
{
|
|
@@ -5,14 +5,30 @@
|
|
|
5
5
|
*/
|
|
6
6
|
|
|
7
7
|
import type { APIRoute } from "astro";
|
|
8
|
+
import { z } from "zod";
|
|
8
9
|
|
|
9
10
|
import { requirePerm } from "#api/authorize.js";
|
|
10
11
|
import { apiError, apiSuccess, handleError } from "#api/error.js";
|
|
12
|
+
import {
|
|
13
|
+
ensureWorkflowHitlRouteRequest,
|
|
14
|
+
hitlRequiredRouteError,
|
|
15
|
+
resolveHitlRouteActor,
|
|
16
|
+
} from "#api/hitl-route-helpers.js";
|
|
11
17
|
import { isParseError, parseBody } from "#api/parse.js";
|
|
12
18
|
import { reorderWidgetsBody } from "#api/schemas.js";
|
|
19
|
+
import {
|
|
20
|
+
logWidgetActivity,
|
|
21
|
+
RiskPolicyEvaluator,
|
|
22
|
+
widgetApiRouteSource,
|
|
23
|
+
WidgetHitlPayloadBuilder,
|
|
24
|
+
} from "#site-context/index.js";
|
|
13
25
|
|
|
14
26
|
export const prerender = false;
|
|
15
27
|
|
|
28
|
+
const reorderWidgetsHitlBody = reorderWidgetsBody.extend({
|
|
29
|
+
hitlRequestId: z.string().min(1).optional(),
|
|
30
|
+
});
|
|
31
|
+
|
|
16
32
|
export const POST: APIRoute = async ({ params, request, locals }) => {
|
|
17
33
|
const { dineway, user } = locals;
|
|
18
34
|
const db = dineway.db;
|
|
@@ -26,37 +42,52 @@ export const POST: APIRoute = async ({ params, request, locals }) => {
|
|
|
26
42
|
}
|
|
27
43
|
|
|
28
44
|
try {
|
|
29
|
-
|
|
30
|
-
const area = await
|
|
31
|
-
.selectFrom("_dineway_widget_areas")
|
|
32
|
-
.select("id")
|
|
33
|
-
.where("name", "=", name)
|
|
34
|
-
.executeTakeFirst();
|
|
45
|
+
const payloadBuilder = new WidgetHitlPayloadBuilder(db);
|
|
46
|
+
const area = await payloadBuilder.loadWidgetAreaSnapshot(name);
|
|
35
47
|
|
|
36
48
|
if (!area) {
|
|
37
49
|
return apiError("NOT_FOUND", `Widget area "${name}" not found`, 404);
|
|
38
50
|
}
|
|
39
51
|
|
|
40
|
-
const body = await parseBody(request,
|
|
52
|
+
const body = await parseBody(request, reorderWidgetsHitlBody);
|
|
41
53
|
if (isParseError(body)) return body;
|
|
54
|
+
const { hitlRequestId, widgetIds } = body;
|
|
42
55
|
|
|
43
56
|
// Verify all widget IDs belong to this area
|
|
44
|
-
const
|
|
45
|
-
|
|
46
|
-
.select("id")
|
|
47
|
-
.where("area_id", "=", area.id)
|
|
48
|
-
.execute();
|
|
49
|
-
|
|
50
|
-
const existingIds = new Set(existingWidgets.map((w) => w.id));
|
|
51
|
-
for (const id of body.widgetIds) {
|
|
57
|
+
const existingIds = new Set(area.widgets.map((widget) => widget.id));
|
|
58
|
+
for (const id of widgetIds) {
|
|
52
59
|
if (!existingIds.has(id)) {
|
|
53
60
|
return apiError("VALIDATION_ERROR", `Widget "${id}" not found in area "${name}"`, 400);
|
|
54
61
|
}
|
|
55
62
|
}
|
|
56
63
|
|
|
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 payloadBuilder.buildReorderWidgetsRequest({
|
|
73
|
+
area,
|
|
74
|
+
widgetIds,
|
|
75
|
+
});
|
|
76
|
+
const decision = await evaluator.evaluateWorkflowHitl({
|
|
77
|
+
actor: actor.identity,
|
|
78
|
+
hitlRequestId,
|
|
79
|
+
action,
|
|
80
|
+
});
|
|
81
|
+
if (!decision.allowed) {
|
|
82
|
+
const ensured = await ensureWorkflowHitlRouteRequest(db, locals, decision.action);
|
|
83
|
+
return hitlRequiredRouteError(decision, ensured);
|
|
84
|
+
}
|
|
85
|
+
approvedHitlRequestId = decision.hitlRequest.id;
|
|
86
|
+
}
|
|
87
|
+
|
|
57
88
|
// Update sort_order for each widget
|
|
58
89
|
await Promise.all(
|
|
59
|
-
|
|
90
|
+
widgetIds.map((id, index) =>
|
|
60
91
|
db
|
|
61
92
|
.updateTable("_dineway_widgets")
|
|
62
93
|
.set({ sort_order: index })
|
|
@@ -65,6 +96,17 @@ export const POST: APIRoute = async ({ params, request, locals }) => {
|
|
|
65
96
|
),
|
|
66
97
|
);
|
|
67
98
|
|
|
99
|
+
await logWidgetActivity(db, locals, {
|
|
100
|
+
action: "reordered",
|
|
101
|
+
areaId: area.id,
|
|
102
|
+
areaName: area.name,
|
|
103
|
+
...widgetApiRouteSource("reordered"),
|
|
104
|
+
detail: {
|
|
105
|
+
widgetIds,
|
|
106
|
+
hitlRequestId: approvedHitlRequestId,
|
|
107
|
+
},
|
|
108
|
+
});
|
|
109
|
+
|
|
68
110
|
return apiSuccess({ success: true });
|
|
69
111
|
} catch (error) {
|
|
70
112
|
return handleError(error, "Failed to reorder widgets", "WIDGET_REORDER_ERROR");
|