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
|
@@ -0,0 +1,76 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Admin site briefing endpoint
|
|
3
|
+
*
|
|
4
|
+
* GET /_dineway/api/admin/briefing - Build a role-scoped Site Context Engine briefing
|
|
5
|
+
*/
|
|
6
|
+
|
|
7
|
+
import { hasPermission } from "@dineway-ai/auth";
|
|
8
|
+
import type { APIRoute } from "astro";
|
|
9
|
+
|
|
10
|
+
import { apiError, handleError, requireDb, unwrapResult } from "#api/error.js";
|
|
11
|
+
import { handleSiteBriefingGet } from "#api/handlers/briefing.js";
|
|
12
|
+
import { isParseError, parseQuery } from "#api/parse.js";
|
|
13
|
+
import { siteBriefingQuery } from "#api/schemas.js";
|
|
14
|
+
import type { SiteBriefingPermissions } from "#site-context/index.js";
|
|
15
|
+
|
|
16
|
+
export const prerender = false;
|
|
17
|
+
|
|
18
|
+
export const GET: APIRoute = async ({ url, locals }) => {
|
|
19
|
+
const { dineway, user } = locals;
|
|
20
|
+
|
|
21
|
+
const dbErr = requireDb(dineway?.db);
|
|
22
|
+
if (dbErr) return dbErr;
|
|
23
|
+
|
|
24
|
+
if (!user) {
|
|
25
|
+
return apiError("UNAUTHORIZED", "Authentication required", 401);
|
|
26
|
+
}
|
|
27
|
+
|
|
28
|
+
const permissions = briefingPermissionsForUser(user);
|
|
29
|
+
if (!canReadAnyBriefingSection(permissions)) {
|
|
30
|
+
return apiError("FORBIDDEN", "Insufficient permissions", 403);
|
|
31
|
+
}
|
|
32
|
+
|
|
33
|
+
try {
|
|
34
|
+
const query = parseQuery(url, siteBriefingQuery);
|
|
35
|
+
if (isParseError(query)) return query;
|
|
36
|
+
|
|
37
|
+
const result = await handleSiteBriefingGet(
|
|
38
|
+
{
|
|
39
|
+
db: dineway.db,
|
|
40
|
+
storage: dineway.storage ?? null,
|
|
41
|
+
configuredPlugins: dineway.configuredPlugins ?? [],
|
|
42
|
+
marketplaceUrl: dineway.config.marketplace,
|
|
43
|
+
permissions,
|
|
44
|
+
},
|
|
45
|
+
{
|
|
46
|
+
scope: query.scope,
|
|
47
|
+
since: query.since,
|
|
48
|
+
contextTypes: query.contextTypes,
|
|
49
|
+
includeStale: query.includeStale,
|
|
50
|
+
tokenBudget: query.tokenBudget,
|
|
51
|
+
activityLimit: query.activityLimit,
|
|
52
|
+
},
|
|
53
|
+
);
|
|
54
|
+
return unwrapResult(result);
|
|
55
|
+
} catch (error) {
|
|
56
|
+
return handleError(error, "Failed to build site briefing", "SITE_BRIEFING_ERROR");
|
|
57
|
+
}
|
|
58
|
+
};
|
|
59
|
+
|
|
60
|
+
function briefingPermissionsForUser(user: { role: number }): SiteBriefingPermissions {
|
|
61
|
+
return {
|
|
62
|
+
canReadContent: hasPermission(user, "content:read"),
|
|
63
|
+
canReadSchema: hasPermission(user, "schema:read"),
|
|
64
|
+
canReadSettings: hasPermission(user, "settings:read"),
|
|
65
|
+
canReadPlugins: hasPermission(user, "plugins:read"),
|
|
66
|
+
};
|
|
67
|
+
}
|
|
68
|
+
|
|
69
|
+
function canReadAnyBriefingSection(permissions: SiteBriefingPermissions): boolean {
|
|
70
|
+
return (
|
|
71
|
+
permissions.canReadContent ||
|
|
72
|
+
permissions.canReadSchema ||
|
|
73
|
+
permissions.canReadSettings ||
|
|
74
|
+
permissions.canReadPlugins
|
|
75
|
+
);
|
|
76
|
+
}
|
|
@@ -5,6 +5,7 @@ import { requirePerm } from "#api/authorize.js";
|
|
|
5
5
|
import { apiError, apiSuccess, handleError } from "#api/error.js";
|
|
6
6
|
import { isParseError, parseBody } from "#api/parse.js";
|
|
7
7
|
import { bylineUpdateBody } from "#api/schemas.js";
|
|
8
|
+
import { invalidateBylineCache } from "#bylines/index.js";
|
|
8
9
|
import { BylineRepository } from "#db/repositories/byline.js";
|
|
9
10
|
|
|
10
11
|
export const prerender = false;
|
|
@@ -61,6 +62,7 @@ export const PUT: APIRoute = async ({ params, request, locals }) => {
|
|
|
61
62
|
});
|
|
62
63
|
|
|
63
64
|
if (!byline) return apiError("NOT_FOUND", "Byline not found", 404);
|
|
65
|
+
invalidateBylineCache();
|
|
64
66
|
return apiSuccess(byline);
|
|
65
67
|
} catch (error) {
|
|
66
68
|
return handleError(error, "Failed to update byline", "BYLINE_UPDATE_ERROR");
|
|
@@ -80,6 +82,7 @@ export const DELETE: APIRoute = async ({ params, locals }) => {
|
|
|
80
82
|
const repo = new BylineRepository(dineway.db);
|
|
81
83
|
const deleted = await repo.delete(params.id!);
|
|
82
84
|
if (!deleted) return apiError("NOT_FOUND", "Byline not found", 404);
|
|
85
|
+
invalidateBylineCache();
|
|
83
86
|
return apiSuccess({ deleted: true });
|
|
84
87
|
} catch (error) {
|
|
85
88
|
return handleError(error, "Failed to delete byline", "BYLINE_DELETE_ERROR");
|
|
@@ -5,6 +5,7 @@ import { requirePerm } from "#api/authorize.js";
|
|
|
5
5
|
import { apiError, apiSuccess, handleError } from "#api/error.js";
|
|
6
6
|
import { isParseError, parseBody, parseQuery } from "#api/parse.js";
|
|
7
7
|
import { bylineCreateBody, bylinesListQuery } from "#api/schemas.js";
|
|
8
|
+
import { invalidateBylineCache } from "#bylines/index.js";
|
|
8
9
|
import { BylineRepository } from "#db/repositories/byline.js";
|
|
9
10
|
|
|
10
11
|
export const prerender = false;
|
|
@@ -65,6 +66,7 @@ export const POST: APIRoute = async ({ request, locals }) => {
|
|
|
65
66
|
isGuest: body.isGuest,
|
|
66
67
|
});
|
|
67
68
|
|
|
69
|
+
invalidateBylineCache();
|
|
68
70
|
return apiSuccess(byline, 201);
|
|
69
71
|
} catch (error) {
|
|
70
72
|
return handleError(error, "Failed to create byline", "BYLINE_CREATE_ERROR");
|
|
@@ -0,0 +1,35 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Admin context supersede history
|
|
3
|
+
*
|
|
4
|
+
* GET /_dineway/api/admin/context/:id/history - Get a context entry supersede chain
|
|
5
|
+
*/
|
|
6
|
+
|
|
7
|
+
import type { APIRoute } from "astro";
|
|
8
|
+
|
|
9
|
+
import { requirePerm } from "#api/authorize.js";
|
|
10
|
+
import { apiError, handleError, requireDb, unwrapResult } from "#api/error.js";
|
|
11
|
+
import { handleContextEntryHistory } from "#api/handlers/context.js";
|
|
12
|
+
|
|
13
|
+
export const prerender = false;
|
|
14
|
+
|
|
15
|
+
export const GET: APIRoute = async ({ params, locals }) => {
|
|
16
|
+
const { dineway, user } = locals;
|
|
17
|
+
const { id } = params;
|
|
18
|
+
|
|
19
|
+
if (!id) {
|
|
20
|
+
return apiError("VALIDATION_ERROR", "Context entry ID required", 400);
|
|
21
|
+
}
|
|
22
|
+
|
|
23
|
+
const dbErr = requireDb(dineway?.db);
|
|
24
|
+
if (dbErr) return dbErr;
|
|
25
|
+
|
|
26
|
+
const denied = requirePerm(user, "settings:read");
|
|
27
|
+
if (denied) return denied;
|
|
28
|
+
|
|
29
|
+
try {
|
|
30
|
+
const result = await handleContextEntryHistory(dineway.db, id);
|
|
31
|
+
return unwrapResult(result);
|
|
32
|
+
} catch (error) {
|
|
33
|
+
return handleError(error, "Failed to load context history", "CONTEXT_HISTORY_ERROR");
|
|
34
|
+
}
|
|
35
|
+
};
|
|
@@ -0,0 +1,35 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Admin context entry detail
|
|
3
|
+
*
|
|
4
|
+
* GET /_dineway/api/admin/context/:id - Get a context entry
|
|
5
|
+
*/
|
|
6
|
+
|
|
7
|
+
import type { APIRoute } from "astro";
|
|
8
|
+
|
|
9
|
+
import { requirePerm } from "#api/authorize.js";
|
|
10
|
+
import { apiError, handleError, requireDb, unwrapResult } from "#api/error.js";
|
|
11
|
+
import { handleContextEntryGet } from "#api/handlers/context.js";
|
|
12
|
+
|
|
13
|
+
export const prerender = false;
|
|
14
|
+
|
|
15
|
+
export const GET: APIRoute = async ({ params, locals }) => {
|
|
16
|
+
const { dineway, user } = locals;
|
|
17
|
+
const { id } = params;
|
|
18
|
+
|
|
19
|
+
if (!id) {
|
|
20
|
+
return apiError("VALIDATION_ERROR", "Context entry ID required", 400);
|
|
21
|
+
}
|
|
22
|
+
|
|
23
|
+
const dbErr = requireDb(dineway?.db);
|
|
24
|
+
if (dbErr) return dbErr;
|
|
25
|
+
|
|
26
|
+
const denied = requirePerm(user, "settings:read");
|
|
27
|
+
if (denied) return denied;
|
|
28
|
+
|
|
29
|
+
try {
|
|
30
|
+
const result = await handleContextEntryGet(dineway.db, id);
|
|
31
|
+
return unwrapResult(result);
|
|
32
|
+
} catch (error) {
|
|
33
|
+
return handleError(error, "Failed to get context entry", "CONTEXT_GET_ERROR");
|
|
34
|
+
}
|
|
35
|
+
};
|
|
@@ -0,0 +1,57 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Admin context review
|
|
3
|
+
*
|
|
4
|
+
* POST /_dineway/api/admin/context/:id/review - Mark a context entry reviewed
|
|
5
|
+
*/
|
|
6
|
+
|
|
7
|
+
import type { APIRoute } from "astro";
|
|
8
|
+
|
|
9
|
+
import { requirePerm } from "#api/authorize.js";
|
|
10
|
+
import { logContextRouteActivity, resolveContextRouteActor } from "#api/context-route-helpers.js";
|
|
11
|
+
import { apiError, handleError, requireDb, unwrapResult } from "#api/error.js";
|
|
12
|
+
import { handleContextEntryReview } from "#api/handlers/context.js";
|
|
13
|
+
import { isParseError, parseBody } from "#api/parse.js";
|
|
14
|
+
import { contextEntryReviewBody } from "#api/schemas.js";
|
|
15
|
+
|
|
16
|
+
export const prerender = false;
|
|
17
|
+
|
|
18
|
+
export const POST: APIRoute = async ({ params, request, locals }) => {
|
|
19
|
+
const { dineway, user } = locals;
|
|
20
|
+
const { id } = params;
|
|
21
|
+
|
|
22
|
+
if (!id) {
|
|
23
|
+
return apiError("VALIDATION_ERROR", "Context entry ID required", 400);
|
|
24
|
+
}
|
|
25
|
+
|
|
26
|
+
const dbErr = requireDb(dineway?.db);
|
|
27
|
+
if (dbErr) return dbErr;
|
|
28
|
+
|
|
29
|
+
const denied = requirePerm(user, "content:edit_any");
|
|
30
|
+
if (denied) return denied;
|
|
31
|
+
|
|
32
|
+
try {
|
|
33
|
+
const body = await parseBody(request, contextEntryReviewBody);
|
|
34
|
+
if (isParseError(body)) return body;
|
|
35
|
+
|
|
36
|
+
const result = await handleContextEntryReview(
|
|
37
|
+
dineway.db,
|
|
38
|
+
id,
|
|
39
|
+
body,
|
|
40
|
+
resolveContextRouteActor(locals),
|
|
41
|
+
);
|
|
42
|
+
if (!result.success) return unwrapResult(result);
|
|
43
|
+
|
|
44
|
+
await logContextRouteActivity(dineway.db, locals, {
|
|
45
|
+
actionType: "context.reviewed",
|
|
46
|
+
entry: result.data.item,
|
|
47
|
+
summary: `Reviewed context entry ${result.data.item.title}`,
|
|
48
|
+
detail: {
|
|
49
|
+
validUntil: result.data.item.validUntil,
|
|
50
|
+
},
|
|
51
|
+
});
|
|
52
|
+
|
|
53
|
+
return unwrapResult(result);
|
|
54
|
+
} catch (error) {
|
|
55
|
+
return handleError(error, "Failed to review context entry", "CONTEXT_REVIEW_ERROR");
|
|
56
|
+
}
|
|
57
|
+
};
|
|
@@ -0,0 +1,58 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Admin context supersede
|
|
3
|
+
*
|
|
4
|
+
* POST /_dineway/api/admin/context/:id/supersede - Replace a context entry
|
|
5
|
+
*/
|
|
6
|
+
|
|
7
|
+
import type { APIRoute } from "astro";
|
|
8
|
+
|
|
9
|
+
import { requirePerm } from "#api/authorize.js";
|
|
10
|
+
import { logContextRouteActivity, resolveContextRouteActor } from "#api/context-route-helpers.js";
|
|
11
|
+
import { apiError, handleError, requireDb, unwrapResult } from "#api/error.js";
|
|
12
|
+
import { handleContextEntrySupersede } from "#api/handlers/context.js";
|
|
13
|
+
import { isParseError, parseBody } from "#api/parse.js";
|
|
14
|
+
import { contextEntrySupersedeBody } from "#api/schemas.js";
|
|
15
|
+
|
|
16
|
+
export const prerender = false;
|
|
17
|
+
|
|
18
|
+
export const POST: APIRoute = async ({ params, request, locals }) => {
|
|
19
|
+
const { dineway, user } = locals;
|
|
20
|
+
const { id } = params;
|
|
21
|
+
|
|
22
|
+
if (!id) {
|
|
23
|
+
return apiError("VALIDATION_ERROR", "Context entry ID required", 400);
|
|
24
|
+
}
|
|
25
|
+
|
|
26
|
+
const dbErr = requireDb(dineway?.db);
|
|
27
|
+
if (dbErr) return dbErr;
|
|
28
|
+
|
|
29
|
+
const denied = requirePerm(user, "content:edit_any");
|
|
30
|
+
if (denied) return denied;
|
|
31
|
+
|
|
32
|
+
try {
|
|
33
|
+
const body = await parseBody(request, contextEntrySupersedeBody);
|
|
34
|
+
if (isParseError(body)) return body;
|
|
35
|
+
|
|
36
|
+
const result = await handleContextEntrySupersede(
|
|
37
|
+
dineway.db,
|
|
38
|
+
id,
|
|
39
|
+
body,
|
|
40
|
+
resolveContextRouteActor(locals),
|
|
41
|
+
);
|
|
42
|
+
if (!result.success) return unwrapResult(result);
|
|
43
|
+
|
|
44
|
+
await logContextRouteActivity(dineway.db, locals, {
|
|
45
|
+
actionType: "context.superseded",
|
|
46
|
+
entry: result.data.item,
|
|
47
|
+
summary: `Superseded context entry ${id}`,
|
|
48
|
+
detail: {
|
|
49
|
+
supersedesId: id,
|
|
50
|
+
replacementId: result.data.item.id,
|
|
51
|
+
},
|
|
52
|
+
});
|
|
53
|
+
|
|
54
|
+
return unwrapResult(result);
|
|
55
|
+
} catch (error) {
|
|
56
|
+
return handleError(error, "Failed to supersede context entry", "CONTEXT_SUPERSEDE_ERROR");
|
|
57
|
+
}
|
|
58
|
+
};
|
|
@@ -0,0 +1,35 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Admin context diff
|
|
3
|
+
*
|
|
4
|
+
* GET /_dineway/api/admin/context/diff - Diff context entries since a timestamp
|
|
5
|
+
*/
|
|
6
|
+
|
|
7
|
+
import type { APIRoute } from "astro";
|
|
8
|
+
|
|
9
|
+
import { requirePerm } from "#api/authorize.js";
|
|
10
|
+
import { handleError, requireDb, unwrapResult } from "#api/error.js";
|
|
11
|
+
import { handleContextEntryDiff } from "#api/handlers/context.js";
|
|
12
|
+
import { isParseError, parseQuery } from "#api/parse.js";
|
|
13
|
+
import { contextEntryDiffQuery } from "#api/schemas.js";
|
|
14
|
+
|
|
15
|
+
export const prerender = false;
|
|
16
|
+
|
|
17
|
+
export const GET: APIRoute = async ({ url, locals }) => {
|
|
18
|
+
const { dineway, user } = locals;
|
|
19
|
+
|
|
20
|
+
const dbErr = requireDb(dineway?.db);
|
|
21
|
+
if (dbErr) return dbErr;
|
|
22
|
+
|
|
23
|
+
const denied = requirePerm(user, "settings:read");
|
|
24
|
+
if (denied) return denied;
|
|
25
|
+
|
|
26
|
+
try {
|
|
27
|
+
const query = parseQuery(url, contextEntryDiffQuery);
|
|
28
|
+
if (isParseError(query)) return query;
|
|
29
|
+
|
|
30
|
+
const result = await handleContextEntryDiff(dineway.db, query);
|
|
31
|
+
return unwrapResult(result);
|
|
32
|
+
} catch (error) {
|
|
33
|
+
return handleError(error, "Failed to diff context entries", "CONTEXT_DIFF_ERROR");
|
|
34
|
+
}
|
|
35
|
+
};
|
|
@@ -0,0 +1,69 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Admin context entry browser
|
|
3
|
+
*
|
|
4
|
+
* GET /_dineway/api/admin/context - List/search context entries
|
|
5
|
+
* POST /_dineway/api/admin/context - Add a context entry
|
|
6
|
+
*/
|
|
7
|
+
|
|
8
|
+
import type { APIRoute } from "astro";
|
|
9
|
+
|
|
10
|
+
import { requirePerm } from "#api/authorize.js";
|
|
11
|
+
import { logContextRouteActivity, resolveContextRouteActor } from "#api/context-route-helpers.js";
|
|
12
|
+
import { handleError, requireDb, unwrapResult } from "#api/error.js";
|
|
13
|
+
import { handleContextEntryCreate, handleContextEntryList } from "#api/handlers/context.js";
|
|
14
|
+
import { isParseError, parseBody, parseQuery } from "#api/parse.js";
|
|
15
|
+
import { contextEntryCreateBody, contextEntryListQuery } from "#api/schemas.js";
|
|
16
|
+
|
|
17
|
+
export const prerender = false;
|
|
18
|
+
|
|
19
|
+
export const GET: APIRoute = async ({ url, locals }) => {
|
|
20
|
+
const { dineway, user } = locals;
|
|
21
|
+
|
|
22
|
+
const dbErr = requireDb(dineway?.db);
|
|
23
|
+
if (dbErr) return dbErr;
|
|
24
|
+
|
|
25
|
+
const denied = requirePerm(user, "settings:read");
|
|
26
|
+
if (denied) return denied;
|
|
27
|
+
|
|
28
|
+
try {
|
|
29
|
+
const query = parseQuery(url, contextEntryListQuery);
|
|
30
|
+
if (isParseError(query)) return query;
|
|
31
|
+
|
|
32
|
+
const result = await handleContextEntryList(dineway.db, query);
|
|
33
|
+
return unwrapResult(result);
|
|
34
|
+
} catch (error) {
|
|
35
|
+
return handleError(error, "Failed to list context entries", "CONTEXT_LIST_ERROR");
|
|
36
|
+
}
|
|
37
|
+
};
|
|
38
|
+
|
|
39
|
+
export const POST: APIRoute = async ({ request, locals }) => {
|
|
40
|
+
const { dineway, user } = locals;
|
|
41
|
+
|
|
42
|
+
const dbErr = requireDb(dineway?.db);
|
|
43
|
+
if (dbErr) return dbErr;
|
|
44
|
+
|
|
45
|
+
const denied = requirePerm(user, "content:edit_any");
|
|
46
|
+
if (denied) return denied;
|
|
47
|
+
|
|
48
|
+
try {
|
|
49
|
+
const body = await parseBody(request, contextEntryCreateBody);
|
|
50
|
+
if (isParseError(body)) return body;
|
|
51
|
+
|
|
52
|
+
const result = await handleContextEntryCreate(
|
|
53
|
+
dineway.db,
|
|
54
|
+
body,
|
|
55
|
+
resolveContextRouteActor(locals),
|
|
56
|
+
);
|
|
57
|
+
if (!result.success) return unwrapResult(result);
|
|
58
|
+
|
|
59
|
+
await logContextRouteActivity(dineway.db, locals, {
|
|
60
|
+
actionType: "context.added",
|
|
61
|
+
entry: result.data.item,
|
|
62
|
+
summary: `Added ${result.data.item.contextType} context: ${result.data.item.title}`,
|
|
63
|
+
});
|
|
64
|
+
|
|
65
|
+
return unwrapResult(result, 201);
|
|
66
|
+
} catch (error) {
|
|
67
|
+
return handleError(error, "Failed to create context entry", "CONTEXT_CREATE_ERROR");
|
|
68
|
+
}
|
|
69
|
+
};
|
|
@@ -0,0 +1,35 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Admin stale context entries
|
|
3
|
+
*
|
|
4
|
+
* GET /_dineway/api/admin/context/stale - List current entries past valid_until
|
|
5
|
+
*/
|
|
6
|
+
|
|
7
|
+
import type { APIRoute } from "astro";
|
|
8
|
+
|
|
9
|
+
import { requirePerm } from "#api/authorize.js";
|
|
10
|
+
import { handleError, requireDb, unwrapResult } from "#api/error.js";
|
|
11
|
+
import { handleContextEntryStale } from "#api/handlers/context.js";
|
|
12
|
+
import { isParseError, parseQuery } from "#api/parse.js";
|
|
13
|
+
import { contextEntryStaleQuery } from "#api/schemas.js";
|
|
14
|
+
|
|
15
|
+
export const prerender = false;
|
|
16
|
+
|
|
17
|
+
export const GET: APIRoute = async ({ url, locals }) => {
|
|
18
|
+
const { dineway, user } = locals;
|
|
19
|
+
|
|
20
|
+
const dbErr = requireDb(dineway?.db);
|
|
21
|
+
if (dbErr) return dbErr;
|
|
22
|
+
|
|
23
|
+
const denied = requirePerm(user, "settings:read");
|
|
24
|
+
if (denied) return denied;
|
|
25
|
+
|
|
26
|
+
try {
|
|
27
|
+
const query = parseQuery(url, contextEntryStaleQuery);
|
|
28
|
+
if (isParseError(query)) return query;
|
|
29
|
+
|
|
30
|
+
const result = await handleContextEntryStale(dineway.db, query);
|
|
31
|
+
return unwrapResult(result);
|
|
32
|
+
} catch (error) {
|
|
33
|
+
return handleError(error, "Failed to list stale context entries", "CONTEXT_STALE_ERROR");
|
|
34
|
+
}
|
|
35
|
+
};
|
|
@@ -0,0 +1,38 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Admin HITL request detail
|
|
3
|
+
*
|
|
4
|
+
* GET /_dineway/api/admin/hitl-requests/:id - Get a generic HITL request
|
|
5
|
+
*/
|
|
6
|
+
|
|
7
|
+
import { Role } from "@dineway-ai/auth";
|
|
8
|
+
import type { APIRoute } from "astro";
|
|
9
|
+
|
|
10
|
+
import { apiError, handleError, requireDb, unwrapResult } from "#api/error.js";
|
|
11
|
+
import { handleHitlRequestGet } from "#api/handlers/hitl-requests.js";
|
|
12
|
+
import { resolveHitlRouteActor } from "#api/hitl-route-helpers.js";
|
|
13
|
+
|
|
14
|
+
export const prerender = false;
|
|
15
|
+
|
|
16
|
+
export const GET: APIRoute = async ({ params, locals }) => {
|
|
17
|
+
const { dineway, user } = locals;
|
|
18
|
+
const { id } = params;
|
|
19
|
+
|
|
20
|
+
if (!id) {
|
|
21
|
+
return apiError("VALIDATION_ERROR", "HITL request ID required", 400);
|
|
22
|
+
}
|
|
23
|
+
|
|
24
|
+
const dbErr = requireDb(dineway?.db);
|
|
25
|
+
if (dbErr) return dbErr;
|
|
26
|
+
|
|
27
|
+
if (!user || user.role < Role.ADMIN) {
|
|
28
|
+
return apiError("FORBIDDEN", "Admin privileges required", 403);
|
|
29
|
+
}
|
|
30
|
+
|
|
31
|
+
try {
|
|
32
|
+
const actor = resolveHitlRouteActor(locals);
|
|
33
|
+
const result = await handleHitlRequestGet(dineway.db, id, actor.access);
|
|
34
|
+
return unwrapResult(result);
|
|
35
|
+
} catch (error) {
|
|
36
|
+
return handleError(error, "Failed to fetch HITL request", "WORKFLOW_HITL_GET_ERROR");
|
|
37
|
+
}
|
|
38
|
+
};
|
|
@@ -0,0 +1,54 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Admin HITL request resolution
|
|
3
|
+
*
|
|
4
|
+
* POST /_dineway/api/admin/hitl-requests/:id/resolve - Approve or reject a generic HITL request
|
|
5
|
+
*/
|
|
6
|
+
|
|
7
|
+
import { Role } from "@dineway-ai/auth";
|
|
8
|
+
import type { APIRoute } from "astro";
|
|
9
|
+
|
|
10
|
+
import { apiError, handleError, requireDb, unwrapResult } from "#api/error.js";
|
|
11
|
+
import { handleHitlRequestResolve } from "#api/handlers/hitl-requests.js";
|
|
12
|
+
import { logHitlRouteActivity, resolveHitlRouteActor } from "#api/hitl-route-helpers.js";
|
|
13
|
+
import { isParseError, parseBody } from "#api/parse.js";
|
|
14
|
+
import { hitlRequestResolveBody } from "#api/schemas.js";
|
|
15
|
+
|
|
16
|
+
export const prerender = false;
|
|
17
|
+
|
|
18
|
+
export const POST: APIRoute = async ({ params, request, locals }) => {
|
|
19
|
+
const { dineway, user } = locals;
|
|
20
|
+
const { id } = params;
|
|
21
|
+
|
|
22
|
+
if (!id) {
|
|
23
|
+
return apiError("VALIDATION_ERROR", "HITL request ID required", 400);
|
|
24
|
+
}
|
|
25
|
+
|
|
26
|
+
const dbErr = requireDb(dineway?.db);
|
|
27
|
+
if (dbErr) return dbErr;
|
|
28
|
+
|
|
29
|
+
if (!user || user.role < Role.ADMIN) {
|
|
30
|
+
return apiError("FORBIDDEN", "Admin privileges required", 403);
|
|
31
|
+
}
|
|
32
|
+
|
|
33
|
+
try {
|
|
34
|
+
const body = await parseBody(request, hitlRequestResolveBody);
|
|
35
|
+
if (isParseError(body)) return body;
|
|
36
|
+
|
|
37
|
+
const actor = resolveHitlRouteActor(locals);
|
|
38
|
+
const result = await handleHitlRequestResolve(dineway.db, id, {
|
|
39
|
+
decision: body.decision,
|
|
40
|
+
reviewNote: body.reviewNote,
|
|
41
|
+
actor: actor.access,
|
|
42
|
+
});
|
|
43
|
+
if (!result.success) return unwrapResult(result);
|
|
44
|
+
|
|
45
|
+
await logHitlRouteActivity(dineway.db, locals, {
|
|
46
|
+
actionType: body.decision === "approved" ? "hitl.approved" : "hitl.rejected",
|
|
47
|
+
item: result.data.item,
|
|
48
|
+
});
|
|
49
|
+
|
|
50
|
+
return unwrapResult(result);
|
|
51
|
+
} catch (error) {
|
|
52
|
+
return handleError(error, "Failed to resolve HITL request", "WORKFLOW_HITL_RESOLVE_ERROR");
|
|
53
|
+
}
|
|
54
|
+
};
|
|
@@ -0,0 +1,38 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Admin HITL requests
|
|
3
|
+
*
|
|
4
|
+
* GET /_dineway/api/admin/hitl-requests - List generic HITL requests
|
|
5
|
+
*/
|
|
6
|
+
|
|
7
|
+
import { Role } from "@dineway-ai/auth";
|
|
8
|
+
import type { APIRoute } from "astro";
|
|
9
|
+
|
|
10
|
+
import { apiError, handleError, requireDb, unwrapResult } from "#api/error.js";
|
|
11
|
+
import { handleHitlRequestList } from "#api/handlers/hitl-requests.js";
|
|
12
|
+
import { resolveHitlRouteActor } from "#api/hitl-route-helpers.js";
|
|
13
|
+
import { isParseError, parseQuery } from "#api/parse.js";
|
|
14
|
+
import { hitlRequestListQuery } from "#api/schemas.js";
|
|
15
|
+
|
|
16
|
+
export const prerender = false;
|
|
17
|
+
|
|
18
|
+
export const GET: APIRoute = async ({ url, locals }) => {
|
|
19
|
+
const { dineway, user } = locals;
|
|
20
|
+
|
|
21
|
+
const dbErr = requireDb(dineway?.db);
|
|
22
|
+
if (dbErr) return dbErr;
|
|
23
|
+
|
|
24
|
+
if (!user || user.role < Role.ADMIN) {
|
|
25
|
+
return apiError("FORBIDDEN", "Admin privileges required", 403);
|
|
26
|
+
}
|
|
27
|
+
|
|
28
|
+
try {
|
|
29
|
+
const query = parseQuery(url, hitlRequestListQuery);
|
|
30
|
+
if (isParseError(query)) return query;
|
|
31
|
+
|
|
32
|
+
const actor = resolveHitlRouteActor(locals);
|
|
33
|
+
const result = await handleHitlRequestList(dineway.db, actor.access, query);
|
|
34
|
+
return unwrapResult(result);
|
|
35
|
+
} catch (error) {
|
|
36
|
+
return handleError(error, "Failed to list HITL requests", "WORKFLOW_HITL_LIST_ERROR");
|
|
37
|
+
}
|
|
38
|
+
};
|
|
@@ -13,8 +13,18 @@ import { z } from "zod";
|
|
|
13
13
|
|
|
14
14
|
import { requirePerm } from "#api/authorize.js";
|
|
15
15
|
import { apiError, apiSuccess, handleError } from "#api/error.js";
|
|
16
|
+
import {
|
|
17
|
+
ensureWorkflowHitlRouteRequest,
|
|
18
|
+
hitlRequiredRouteError,
|
|
19
|
+
resolveHitlRouteActor,
|
|
20
|
+
} from "#api/hitl-route-helpers.js";
|
|
16
21
|
import { isParseError, parseBody } from "#api/parse.js";
|
|
17
|
-
import {
|
|
22
|
+
import {
|
|
23
|
+
ExclusiveHookHitlPayloadBuilder,
|
|
24
|
+
exclusiveHookApiRouteSource,
|
|
25
|
+
logExclusiveHookActivity,
|
|
26
|
+
RiskPolicyEvaluator,
|
|
27
|
+
} from "#site-context/index.js";
|
|
18
28
|
|
|
19
29
|
export const prerender = false;
|
|
20
30
|
|
|
@@ -23,6 +33,7 @@ const HOOK_NAME_RE = /^[a-z]+:[a-zA-Z]+$/;
|
|
|
23
33
|
|
|
24
34
|
const setSelectionSchema = z.object({
|
|
25
35
|
pluginId: z.string().min(1).nullable(),
|
|
36
|
+
hitlRequestId: z.string().min(1).optional(),
|
|
26
37
|
});
|
|
27
38
|
|
|
28
39
|
export const PUT: APIRoute = async ({ params, request, locals }) => {
|
|
@@ -55,20 +66,14 @@ export const PUT: APIRoute = async ({ params, request, locals }) => {
|
|
|
55
66
|
|
|
56
67
|
const body = await parseBody(request, setSelectionSchema);
|
|
57
68
|
if (isParseError(body)) return body;
|
|
58
|
-
|
|
59
|
-
|
|
60
|
-
|
|
61
|
-
|
|
62
|
-
|
|
63
|
-
|
|
64
|
-
|
|
65
|
-
|
|
66
|
-
} else {
|
|
67
|
-
// Validate that the pluginId is an actual provider for this hook
|
|
68
|
-
const providers = pipeline.getExclusiveHookProviders(hookName);
|
|
69
|
-
const isValidProvider = providers.some(
|
|
70
|
-
(p: { pluginId: string }) => p.pluginId === body.pluginId,
|
|
71
|
-
);
|
|
69
|
+
const providers = pipeline
|
|
70
|
+
.getExclusiveHookProviders(hookName)
|
|
71
|
+
.map((provider: { pluginId: string; pluginName?: string }) => ({
|
|
72
|
+
pluginId: provider.pluginId,
|
|
73
|
+
pluginName: provider.pluginName ?? provider.pluginId,
|
|
74
|
+
}));
|
|
75
|
+
if (body.pluginId !== null) {
|
|
76
|
+
const isValidProvider = providers.some((provider) => provider.pluginId === body.pluginId);
|
|
72
77
|
if (!isValidProvider) {
|
|
73
78
|
return apiError(
|
|
74
79
|
"VALIDATION_ERROR",
|
|
@@ -76,11 +81,47 @@ export const PUT: APIRoute = async ({ params, request, locals }) => {
|
|
|
76
81
|
400,
|
|
77
82
|
);
|
|
78
83
|
}
|
|
84
|
+
}
|
|
79
85
|
|
|
80
|
-
|
|
81
|
-
|
|
86
|
+
const previousPluginId = await pipeline.getExclusiveHookSelection(hookName);
|
|
87
|
+
const actor = resolveHitlRouteActor(locals);
|
|
88
|
+
const evaluator = new RiskPolicyEvaluator({
|
|
89
|
+
db: dineway.db,
|
|
90
|
+
handlers: dineway,
|
|
91
|
+
});
|
|
92
|
+
let approvedHitlRequestId: string | null = null;
|
|
93
|
+
|
|
94
|
+
if (evaluator.requiresWorkflowHitl(actor.identity)) {
|
|
95
|
+
const action = await new ExclusiveHookHitlPayloadBuilder().buildSetSelectionRequest({
|
|
96
|
+
hookName,
|
|
97
|
+
currentPluginId: previousPluginId,
|
|
98
|
+
requestedPluginId: body.pluginId,
|
|
99
|
+
providers,
|
|
100
|
+
});
|
|
101
|
+
const decision = await evaluator.evaluateWorkflowHitl({
|
|
102
|
+
actor: actor.identity,
|
|
103
|
+
hitlRequestId: body.hitlRequestId,
|
|
104
|
+
action,
|
|
105
|
+
});
|
|
106
|
+
if (!decision.allowed) {
|
|
107
|
+
const ensured = await ensureWorkflowHitlRouteRequest(dineway.db, locals, decision.action);
|
|
108
|
+
return hitlRequiredRouteError(decision, ensured);
|
|
109
|
+
}
|
|
110
|
+
approvedHitlRequestId = decision.hitlRequest.id;
|
|
82
111
|
}
|
|
83
112
|
|
|
113
|
+
await pipeline.setExclusiveHookSelection(hookName, body.pluginId);
|
|
114
|
+
await logExclusiveHookActivity(dineway.db, locals, {
|
|
115
|
+
action: "updated",
|
|
116
|
+
hookName,
|
|
117
|
+
previousPluginId,
|
|
118
|
+
selectedPluginId: body.pluginId,
|
|
119
|
+
...exclusiveHookApiRouteSource("updated"),
|
|
120
|
+
detail: {
|
|
121
|
+
hitlRequestId: approvedHitlRequestId,
|
|
122
|
+
},
|
|
123
|
+
});
|
|
124
|
+
|
|
84
125
|
return apiSuccess({
|
|
85
126
|
hookName,
|
|
86
127
|
selectedPluginId: body.pluginId,
|