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
|
@@ -10,6 +10,7 @@ import { Role } from "@dineway-ai/auth";
|
|
|
10
10
|
import type { APIRoute } from "astro";
|
|
11
11
|
import { z } from "zod";
|
|
12
12
|
|
|
13
|
+
import { rejectApiTokenAuthControlWrite } from "#api/auth-control-guard.js";
|
|
13
14
|
import { apiError, handleError, unwrapResult } from "#api/error.js";
|
|
14
15
|
import {
|
|
15
16
|
handleOAuthClientDelete,
|
|
@@ -17,6 +18,11 @@ import {
|
|
|
17
18
|
handleOAuthClientUpdate,
|
|
18
19
|
} from "#api/handlers/oauth-clients.js";
|
|
19
20
|
import { isParseError, parseBody } from "#api/parse.js";
|
|
21
|
+
import { ALL_VALID_SCOPES } from "#auth/api-tokens.js";
|
|
22
|
+
import {
|
|
23
|
+
disabledExperimentalSiteContextWorkflowScopes,
|
|
24
|
+
getExperimentalSiteContextWorkflowScopesDisabledMessage,
|
|
25
|
+
} from "#site-context/experimental-workflows.js";
|
|
20
26
|
|
|
21
27
|
export const prerender = false;
|
|
22
28
|
|
|
@@ -26,7 +32,7 @@ const updateClientSchema = z.object({
|
|
|
26
32
|
.array(z.string().url("Each redirect URI must be a valid URL"))
|
|
27
33
|
.min(1, "At least one redirect URI is required")
|
|
28
34
|
.optional(),
|
|
29
|
-
scopes: z.array(z.
|
|
35
|
+
scopes: z.array(z.enum(ALL_VALID_SCOPES)).nullable().optional(),
|
|
30
36
|
});
|
|
31
37
|
|
|
32
38
|
/**
|
|
@@ -43,6 +49,9 @@ export const GET: APIRoute = async ({ params, locals }) => {
|
|
|
43
49
|
return apiError("FORBIDDEN", "Admin privileges required", 403);
|
|
44
50
|
}
|
|
45
51
|
|
|
52
|
+
const credentialGuard = rejectApiTokenAuthControlWrite(locals, "oauth_clients");
|
|
53
|
+
if (credentialGuard) return credentialGuard;
|
|
54
|
+
|
|
46
55
|
const clientId = params.id;
|
|
47
56
|
if (!clientId) {
|
|
48
57
|
return apiError("VALIDATION_ERROR", "Client ID is required", 400);
|
|
@@ -66,6 +75,9 @@ export const PUT: APIRoute = async ({ params, request, locals }) => {
|
|
|
66
75
|
return apiError("FORBIDDEN", "Admin privileges required", 403);
|
|
67
76
|
}
|
|
68
77
|
|
|
78
|
+
const credentialGuard = rejectApiTokenAuthControlWrite(locals, "oauth_clients");
|
|
79
|
+
if (credentialGuard) return credentialGuard;
|
|
80
|
+
|
|
69
81
|
const clientId = params.id;
|
|
70
82
|
if (!clientId) {
|
|
71
83
|
return apiError("VALIDATION_ERROR", "Client ID is required", 400);
|
|
@@ -74,6 +86,21 @@ export const PUT: APIRoute = async ({ params, request, locals }) => {
|
|
|
74
86
|
try {
|
|
75
87
|
const body = await parseBody(request, updateClientSchema);
|
|
76
88
|
if (isParseError(body)) return body;
|
|
89
|
+
const requestedWorkflowScopes = disabledExperimentalSiteContextWorkflowScopes(
|
|
90
|
+
body.scopes ?? [],
|
|
91
|
+
);
|
|
92
|
+
if (requestedWorkflowScopes.length > 0) {
|
|
93
|
+
return apiError(
|
|
94
|
+
"NOT_IMPLEMENTED",
|
|
95
|
+
getExperimentalSiteContextWorkflowScopesDisabledMessage(),
|
|
96
|
+
501,
|
|
97
|
+
{
|
|
98
|
+
status: "workflow_oauth_client_scopes_disabled",
|
|
99
|
+
reason: "workflow_oauth_client_scopes_disabled",
|
|
100
|
+
scopes: requestedWorkflowScopes,
|
|
101
|
+
},
|
|
102
|
+
);
|
|
103
|
+
}
|
|
77
104
|
|
|
78
105
|
const result = await handleOAuthClientUpdate(dineway.db, clientId, body);
|
|
79
106
|
return unwrapResult(result);
|
|
@@ -9,9 +9,15 @@ import { Role } from "@dineway-ai/auth";
|
|
|
9
9
|
import type { APIRoute } from "astro";
|
|
10
10
|
import { z } from "zod";
|
|
11
11
|
|
|
12
|
+
import { rejectApiTokenAuthControlWrite } from "#api/auth-control-guard.js";
|
|
12
13
|
import { apiError, handleError, unwrapResult } from "#api/error.js";
|
|
13
14
|
import { handleOAuthClientCreate, handleOAuthClientList } from "#api/handlers/oauth-clients.js";
|
|
14
15
|
import { isParseError, parseBody } from "#api/parse.js";
|
|
16
|
+
import { ALL_VALID_SCOPES } from "#auth/api-tokens.js";
|
|
17
|
+
import {
|
|
18
|
+
disabledExperimentalSiteContextWorkflowScopes,
|
|
19
|
+
getExperimentalSiteContextWorkflowScopesDisabledMessage,
|
|
20
|
+
} from "#site-context/experimental-workflows.js";
|
|
15
21
|
|
|
16
22
|
export const prerender = false;
|
|
17
23
|
|
|
@@ -24,7 +30,7 @@ const createClientSchema = z.object({
|
|
|
24
30
|
redirectUris: z
|
|
25
31
|
.array(z.string().url("Each redirect URI must be a valid URL"))
|
|
26
32
|
.min(1, "At least one redirect URI is required"),
|
|
27
|
-
scopes: z.array(z.
|
|
33
|
+
scopes: z.array(z.enum(ALL_VALID_SCOPES)).optional(),
|
|
28
34
|
});
|
|
29
35
|
|
|
30
36
|
/**
|
|
@@ -59,9 +65,27 @@ export const POST: APIRoute = async ({ request, locals }) => {
|
|
|
59
65
|
return apiError("FORBIDDEN", "Admin privileges required", 403);
|
|
60
66
|
}
|
|
61
67
|
|
|
68
|
+
const credentialGuard = rejectApiTokenAuthControlWrite(locals, "oauth_clients");
|
|
69
|
+
if (credentialGuard) return credentialGuard;
|
|
70
|
+
|
|
62
71
|
try {
|
|
63
72
|
const body = await parseBody(request, createClientSchema);
|
|
64
73
|
if (isParseError(body)) return body;
|
|
74
|
+
const requestedWorkflowScopes = disabledExperimentalSiteContextWorkflowScopes(
|
|
75
|
+
body.scopes ?? [],
|
|
76
|
+
);
|
|
77
|
+
if (requestedWorkflowScopes.length > 0) {
|
|
78
|
+
return apiError(
|
|
79
|
+
"NOT_IMPLEMENTED",
|
|
80
|
+
getExperimentalSiteContextWorkflowScopesDisabledMessage(),
|
|
81
|
+
501,
|
|
82
|
+
{
|
|
83
|
+
status: "workflow_oauth_client_scopes_disabled",
|
|
84
|
+
reason: "workflow_oauth_client_scopes_disabled",
|
|
85
|
+
scopes: requestedWorkflowScopes,
|
|
86
|
+
},
|
|
87
|
+
);
|
|
88
|
+
}
|
|
65
89
|
|
|
66
90
|
const result = await handleOAuthClientCreate(dineway.db, body);
|
|
67
91
|
return unwrapResult(result, 201);
|
|
@@ -5,15 +5,32 @@
|
|
|
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, unwrapResult } from "#api/error.js";
|
|
11
|
-
import {
|
|
12
|
+
import {
|
|
13
|
+
ensureWorkflowHitlRouteRequest,
|
|
14
|
+
hitlRequiredRouteError,
|
|
15
|
+
resolveHitlRouteActor,
|
|
16
|
+
} from "#api/hitl-route-helpers.js";
|
|
17
|
+
import { handlePluginDisable, handlePluginGet } from "#api/index.js";
|
|
18
|
+
import { isParseError, parseOptionalBody } from "#api/parse.js";
|
|
12
19
|
import { setCronTasksEnabled } from "#plugins/cron.js";
|
|
20
|
+
import {
|
|
21
|
+
logPluginActivity,
|
|
22
|
+
pluginApiRouteSource,
|
|
23
|
+
PluginHitlPayloadBuilder,
|
|
24
|
+
RiskPolicyEvaluator,
|
|
25
|
+
} from "#site-context/index.js";
|
|
13
26
|
|
|
14
27
|
export const prerender = false;
|
|
15
28
|
|
|
16
|
-
|
|
29
|
+
const hitlBodySchema = z.object({
|
|
30
|
+
hitlRequestId: z.string().min(1).optional(),
|
|
31
|
+
});
|
|
32
|
+
|
|
33
|
+
export const POST: APIRoute = async ({ params, request, locals }) => {
|
|
17
34
|
const { dineway, user } = locals;
|
|
18
35
|
const { id } = params;
|
|
19
36
|
|
|
@@ -28,12 +45,47 @@ export const POST: APIRoute = async ({ params, locals }) => {
|
|
|
28
45
|
return apiError("INVALID_REQUEST", "Plugin ID required", 400);
|
|
29
46
|
}
|
|
30
47
|
|
|
48
|
+
const body = await parseOptionalBody(request, hitlBodySchema, {});
|
|
49
|
+
if (isParseError(body)) return body;
|
|
50
|
+
|
|
51
|
+
const current = await handlePluginGet(
|
|
52
|
+
dineway.db,
|
|
53
|
+
dineway.configuredPlugins,
|
|
54
|
+
id,
|
|
55
|
+
dineway.config.marketplace,
|
|
56
|
+
);
|
|
57
|
+
if (!current.success) return unwrapResult(current);
|
|
58
|
+
|
|
59
|
+
const actor = resolveHitlRouteActor(locals);
|
|
60
|
+
const action = await new PluginHitlPayloadBuilder().buildDisableRequest(current.data.item);
|
|
61
|
+
const decision = await new RiskPolicyEvaluator({
|
|
62
|
+
db: dineway.db,
|
|
63
|
+
handlers: dineway,
|
|
64
|
+
}).evaluateWorkflowHitl({
|
|
65
|
+
actor: actor.identity,
|
|
66
|
+
hitlRequestId: body.hitlRequestId,
|
|
67
|
+
action,
|
|
68
|
+
});
|
|
69
|
+
if (!decision.allowed) {
|
|
70
|
+
const ensured = await ensureWorkflowHitlRouteRequest(dineway.db, locals, decision.action);
|
|
71
|
+
return hitlRequiredRouteError(decision, ensured);
|
|
72
|
+
}
|
|
73
|
+
|
|
31
74
|
const result = await handlePluginDisable(dineway.db, dineway.configuredPlugins, id);
|
|
32
75
|
|
|
33
76
|
if (!result.success) return unwrapResult(result);
|
|
34
77
|
|
|
35
78
|
await dineway.setPluginStatus(id, "inactive");
|
|
36
79
|
await setCronTasksEnabled(dineway.db, id, false);
|
|
80
|
+
await logPluginActivity(dineway.db, locals, {
|
|
81
|
+
action: "disabled",
|
|
82
|
+
pluginId: id,
|
|
83
|
+
...pluginApiRouteSource("disabled"),
|
|
84
|
+
summary: `Disabled plugin ${id}`,
|
|
85
|
+
detail: {
|
|
86
|
+
hitlRequestId: decision.required ? decision.hitlRequest.id : null,
|
|
87
|
+
},
|
|
88
|
+
});
|
|
37
89
|
|
|
38
90
|
return unwrapResult(result);
|
|
39
91
|
};
|
|
@@ -5,15 +5,32 @@
|
|
|
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, unwrapResult } from "#api/error.js";
|
|
11
|
-
import {
|
|
12
|
+
import {
|
|
13
|
+
ensureWorkflowHitlRouteRequest,
|
|
14
|
+
hitlRequiredRouteError,
|
|
15
|
+
resolveHitlRouteActor,
|
|
16
|
+
} from "#api/hitl-route-helpers.js";
|
|
17
|
+
import { handlePluginEnable, handlePluginGet } from "#api/index.js";
|
|
18
|
+
import { isParseError, parseOptionalBody } from "#api/parse.js";
|
|
12
19
|
import { setCronTasksEnabled } from "#plugins/cron.js";
|
|
20
|
+
import {
|
|
21
|
+
logPluginActivity,
|
|
22
|
+
pluginApiRouteSource,
|
|
23
|
+
PluginHitlPayloadBuilder,
|
|
24
|
+
RiskPolicyEvaluator,
|
|
25
|
+
} from "#site-context/index.js";
|
|
13
26
|
|
|
14
27
|
export const prerender = false;
|
|
15
28
|
|
|
16
|
-
|
|
29
|
+
const hitlBodySchema = z.object({
|
|
30
|
+
hitlRequestId: z.string().min(1).optional(),
|
|
31
|
+
});
|
|
32
|
+
|
|
33
|
+
export const POST: APIRoute = async ({ params, request, locals }) => {
|
|
17
34
|
const { dineway, user } = locals;
|
|
18
35
|
const { id } = params;
|
|
19
36
|
|
|
@@ -28,12 +45,47 @@ export const POST: APIRoute = async ({ params, locals }) => {
|
|
|
28
45
|
return apiError("INVALID_REQUEST", "Plugin ID required", 400);
|
|
29
46
|
}
|
|
30
47
|
|
|
48
|
+
const body = await parseOptionalBody(request, hitlBodySchema, {});
|
|
49
|
+
if (isParseError(body)) return body;
|
|
50
|
+
|
|
51
|
+
const current = await handlePluginGet(
|
|
52
|
+
dineway.db,
|
|
53
|
+
dineway.configuredPlugins,
|
|
54
|
+
id,
|
|
55
|
+
dineway.config.marketplace,
|
|
56
|
+
);
|
|
57
|
+
if (!current.success) return unwrapResult(current);
|
|
58
|
+
|
|
59
|
+
const actor = resolveHitlRouteActor(locals);
|
|
60
|
+
const action = await new PluginHitlPayloadBuilder().buildEnableRequest(current.data.item);
|
|
61
|
+
const decision = await new RiskPolicyEvaluator({
|
|
62
|
+
db: dineway.db,
|
|
63
|
+
handlers: dineway,
|
|
64
|
+
}).evaluateWorkflowHitl({
|
|
65
|
+
actor: actor.identity,
|
|
66
|
+
hitlRequestId: body.hitlRequestId,
|
|
67
|
+
action,
|
|
68
|
+
});
|
|
69
|
+
if (!decision.allowed) {
|
|
70
|
+
const ensured = await ensureWorkflowHitlRouteRequest(dineway.db, locals, decision.action);
|
|
71
|
+
return hitlRequiredRouteError(decision, ensured);
|
|
72
|
+
}
|
|
73
|
+
|
|
31
74
|
const result = await handlePluginEnable(dineway.db, dineway.configuredPlugins, id);
|
|
32
75
|
|
|
33
76
|
if (!result.success) return unwrapResult(result);
|
|
34
77
|
|
|
35
78
|
await dineway.setPluginStatus(id, "active");
|
|
36
79
|
await setCronTasksEnabled(dineway.db, id, true);
|
|
80
|
+
await logPluginActivity(dineway.db, locals, {
|
|
81
|
+
action: "enabled",
|
|
82
|
+
pluginId: id,
|
|
83
|
+
...pluginApiRouteSource("enabled"),
|
|
84
|
+
summary: `Enabled plugin ${id}`,
|
|
85
|
+
detail: {
|
|
86
|
+
hitlRequestId: decision.required ? decision.hitlRequest.id : null,
|
|
87
|
+
},
|
|
88
|
+
});
|
|
37
89
|
|
|
38
90
|
return unwrapResult(result);
|
|
39
91
|
};
|
|
@@ -9,13 +9,25 @@ import { z } from "zod";
|
|
|
9
9
|
|
|
10
10
|
import { requirePerm } from "#api/authorize.js";
|
|
11
11
|
import { apiError, unwrapResult } from "#api/error.js";
|
|
12
|
-
import {
|
|
12
|
+
import {
|
|
13
|
+
ensureWorkflowHitlRouteRequest,
|
|
14
|
+
hitlRequiredRouteError,
|
|
15
|
+
resolveHitlRouteActor,
|
|
16
|
+
} from "#api/hitl-route-helpers.js";
|
|
17
|
+
import { handleMarketplaceUninstall, handlePluginList } from "#api/index.js";
|
|
13
18
|
import { isParseError, parseOptionalBody } from "#api/parse.js";
|
|
19
|
+
import {
|
|
20
|
+
logPluginActivity,
|
|
21
|
+
pluginApiRouteSource,
|
|
22
|
+
PluginHitlPayloadBuilder,
|
|
23
|
+
RiskPolicyEvaluator,
|
|
24
|
+
} from "#site-context/index.js";
|
|
14
25
|
|
|
15
26
|
export const prerender = false;
|
|
16
27
|
|
|
17
28
|
const uninstallBodySchema = z.object({
|
|
18
29
|
deleteData: z.boolean().optional(),
|
|
30
|
+
hitlRequestId: z.string().min(1).optional(),
|
|
19
31
|
});
|
|
20
32
|
|
|
21
33
|
export const POST: APIRoute = async ({ params, request, locals }) => {
|
|
@@ -36,6 +48,34 @@ export const POST: APIRoute = async ({ params, request, locals }) => {
|
|
|
36
48
|
const body = await parseOptionalBody(request, uninstallBodySchema, {});
|
|
37
49
|
if (isParseError(body)) return body;
|
|
38
50
|
|
|
51
|
+
const actor = resolveHitlRouteActor(locals);
|
|
52
|
+
let approvedHitlRequestId: string | null = null;
|
|
53
|
+
const current = await handlePluginList(
|
|
54
|
+
dineway.db,
|
|
55
|
+
dineway.configuredPlugins,
|
|
56
|
+
dineway.config.marketplace,
|
|
57
|
+
);
|
|
58
|
+
if (!current.success) return unwrapResult(current);
|
|
59
|
+
const plugin = current.data.items.find((item) => item.id === id && item.source === "marketplace");
|
|
60
|
+
if (plugin) {
|
|
61
|
+
const action = await new PluginHitlPayloadBuilder().buildUninstallRequest(plugin, {
|
|
62
|
+
deleteData: body.deleteData ?? false,
|
|
63
|
+
});
|
|
64
|
+
const decision = await new RiskPolicyEvaluator({
|
|
65
|
+
db: dineway.db,
|
|
66
|
+
handlers: dineway,
|
|
67
|
+
}).evaluateWorkflowHitl({
|
|
68
|
+
actor: actor.identity,
|
|
69
|
+
hitlRequestId: body.hitlRequestId,
|
|
70
|
+
action,
|
|
71
|
+
});
|
|
72
|
+
if (!decision.allowed) {
|
|
73
|
+
const ensured = await ensureWorkflowHitlRouteRequest(dineway.db, locals, decision.action);
|
|
74
|
+
return hitlRequiredRouteError(decision, ensured);
|
|
75
|
+
}
|
|
76
|
+
approvedHitlRequestId = decision.required ? decision.hitlRequest.id : null;
|
|
77
|
+
}
|
|
78
|
+
|
|
39
79
|
const result = await handleMarketplaceUninstall(dineway.db, dineway.storage, id, {
|
|
40
80
|
deleteData: body.deleteData ?? false,
|
|
41
81
|
});
|
|
@@ -43,6 +83,16 @@ export const POST: APIRoute = async ({ params, request, locals }) => {
|
|
|
43
83
|
if (!result.success) return unwrapResult(result);
|
|
44
84
|
|
|
45
85
|
await dineway.syncMarketplacePlugins();
|
|
86
|
+
await logPluginActivity(dineway.db, locals, {
|
|
87
|
+
action: "uninstalled",
|
|
88
|
+
pluginId: id,
|
|
89
|
+
...pluginApiRouteSource("uninstalled"),
|
|
90
|
+
summary: `Uninstalled plugin ${id}`,
|
|
91
|
+
detail: {
|
|
92
|
+
deleteData: body.deleteData ?? false,
|
|
93
|
+
hitlRequestId: approvedHitlRequestId,
|
|
94
|
+
},
|
|
95
|
+
});
|
|
46
96
|
|
|
47
97
|
return unwrapResult(result);
|
|
48
98
|
};
|
|
@@ -9,8 +9,19 @@ import { z } from "zod";
|
|
|
9
9
|
|
|
10
10
|
import { requirePerm } from "#api/authorize.js";
|
|
11
11
|
import { apiError, unwrapResult } from "#api/error.js";
|
|
12
|
-
import {
|
|
12
|
+
import {
|
|
13
|
+
ensureWorkflowHitlRouteRequest,
|
|
14
|
+
hitlRequiredRouteError,
|
|
15
|
+
resolveHitlRouteActor,
|
|
16
|
+
} from "#api/hitl-route-helpers.js";
|
|
17
|
+
import { handleMarketplaceUpdate, handleMarketplaceUpdatePreview } from "#api/index.js";
|
|
13
18
|
import { isParseError, parseOptionalBody } from "#api/parse.js";
|
|
19
|
+
import {
|
|
20
|
+
logPluginActivity,
|
|
21
|
+
pluginApiRouteSource,
|
|
22
|
+
PluginHitlPayloadBuilder,
|
|
23
|
+
RiskPolicyEvaluator,
|
|
24
|
+
} from "#site-context/index.js";
|
|
14
25
|
|
|
15
26
|
export const prerender = false;
|
|
16
27
|
|
|
@@ -18,6 +29,7 @@ const updateBodySchema = z.object({
|
|
|
18
29
|
version: z.string().min(1).optional(),
|
|
19
30
|
confirmCapabilityChanges: z.boolean().optional(),
|
|
20
31
|
confirmRouteVisibilityChanges: z.boolean().optional(),
|
|
32
|
+
hitlRequestId: z.string().min(1).optional(),
|
|
21
33
|
});
|
|
22
34
|
|
|
23
35
|
export const POST: APIRoute = async ({ params, request, locals }) => {
|
|
@@ -37,6 +49,68 @@ export const POST: APIRoute = async ({ params, request, locals }) => {
|
|
|
37
49
|
|
|
38
50
|
const body = await parseOptionalBody(request, updateBodySchema, {});
|
|
39
51
|
if (isParseError(body)) return body;
|
|
52
|
+
const actor = resolveHitlRouteActor(locals);
|
|
53
|
+
const evaluator = new RiskPolicyEvaluator({
|
|
54
|
+
db: dineway.db,
|
|
55
|
+
handlers: dineway,
|
|
56
|
+
});
|
|
57
|
+
let approvedHitlRequestId: string | null = null;
|
|
58
|
+
let previewDiffs: { hasCapabilityChanges: boolean; hasNewPublicRoutes: boolean } | null = null;
|
|
59
|
+
|
|
60
|
+
if (evaluator.requiresWorkflowHitl(actor.identity)) {
|
|
61
|
+
if (!body.version) {
|
|
62
|
+
return apiError(
|
|
63
|
+
"VALIDATION_ERROR",
|
|
64
|
+
"API-token marketplace updates require an explicit version so the reviewed target is immutable.",
|
|
65
|
+
400,
|
|
66
|
+
);
|
|
67
|
+
}
|
|
68
|
+
|
|
69
|
+
const preview = await handleMarketplaceUpdatePreview(
|
|
70
|
+
dineway.db,
|
|
71
|
+
dineway.storage,
|
|
72
|
+
dineway.config.marketplace,
|
|
73
|
+
id,
|
|
74
|
+
{ version: body.version },
|
|
75
|
+
);
|
|
76
|
+
if (!preview.success) return unwrapResult(preview);
|
|
77
|
+
|
|
78
|
+
const action = await new PluginHitlPayloadBuilder().buildMarketplaceUpdateRequest({
|
|
79
|
+
id: preview.data.pluginId,
|
|
80
|
+
name: preview.data.name,
|
|
81
|
+
description: preview.data.description,
|
|
82
|
+
authorName: preview.data.authorName,
|
|
83
|
+
version: preview.data.version,
|
|
84
|
+
minDinewayVersion: preview.data.minDinewayVersion,
|
|
85
|
+
bundleSize: preview.data.bundleSize,
|
|
86
|
+
checksum: preview.data.checksum,
|
|
87
|
+
changelog: preview.data.changelog,
|
|
88
|
+
capabilities: preview.data.capabilities,
|
|
89
|
+
status: preview.data.status,
|
|
90
|
+
auditVerdict: preview.data.auditVerdict,
|
|
91
|
+
imageAuditVerdict: preview.data.imageAuditVerdict,
|
|
92
|
+
publishedAt: preview.data.publishedAt,
|
|
93
|
+
oldVersion: preview.data.oldVersion,
|
|
94
|
+
capabilityChanges: preview.data.capabilityChanges,
|
|
95
|
+
routeVisibilityChanges: preview.data.routeVisibilityChanges,
|
|
96
|
+
});
|
|
97
|
+
const decision = await evaluator.evaluateWorkflowHitl({
|
|
98
|
+
actor: actor.identity,
|
|
99
|
+
hitlRequestId: body.hitlRequestId,
|
|
100
|
+
action,
|
|
101
|
+
});
|
|
102
|
+
if (!decision.allowed) {
|
|
103
|
+
const ensured = await ensureWorkflowHitlRouteRequest(dineway.db, locals, decision.action);
|
|
104
|
+
return hitlRequiredRouteError(decision, ensured);
|
|
105
|
+
}
|
|
106
|
+
approvedHitlRequestId = decision.hitlRequest.id;
|
|
107
|
+
previewDiffs = {
|
|
108
|
+
hasCapabilityChanges:
|
|
109
|
+
preview.data.capabilityChanges.added.length > 0 ||
|
|
110
|
+
preview.data.capabilityChanges.removed.length > 0,
|
|
111
|
+
hasNewPublicRoutes: preview.data.routeVisibilityChanges.newlyPublic.length > 0,
|
|
112
|
+
};
|
|
113
|
+
}
|
|
40
114
|
|
|
41
115
|
const result = await handleMarketplaceUpdate(
|
|
42
116
|
dineway.db,
|
|
@@ -46,14 +120,35 @@ export const POST: APIRoute = async ({ params, request, locals }) => {
|
|
|
46
120
|
id,
|
|
47
121
|
{
|
|
48
122
|
version: body.version,
|
|
49
|
-
confirmCapabilityChanges:
|
|
50
|
-
|
|
123
|
+
confirmCapabilityChanges: previewDiffs
|
|
124
|
+
? previewDiffs.hasCapabilityChanges || body.confirmCapabilityChanges === true
|
|
125
|
+
: body.confirmCapabilityChanges,
|
|
126
|
+
confirmRouteVisibilityChanges: previewDiffs
|
|
127
|
+
? previewDiffs.hasNewPublicRoutes || body.confirmRouteVisibilityChanges === true
|
|
128
|
+
: body.confirmRouteVisibilityChanges,
|
|
51
129
|
},
|
|
52
130
|
);
|
|
53
131
|
|
|
54
132
|
if (!result.success) return unwrapResult(result);
|
|
55
133
|
|
|
56
134
|
await dineway.syncMarketplacePlugins();
|
|
135
|
+
await logPluginActivity(dineway.db, locals, {
|
|
136
|
+
action: "updated",
|
|
137
|
+
pluginId: id,
|
|
138
|
+
...pluginApiRouteSource("updated"),
|
|
139
|
+
summary: `Updated plugin ${id}`,
|
|
140
|
+
detail: {
|
|
141
|
+
version: result.data.newVersion,
|
|
142
|
+
oldVersion: result.data.oldVersion,
|
|
143
|
+
confirmedCapabilityChanges: previewDiffs
|
|
144
|
+
? previewDiffs.hasCapabilityChanges
|
|
145
|
+
: (body.confirmCapabilityChanges ?? false),
|
|
146
|
+
confirmedRouteVisibilityChanges: previewDiffs
|
|
147
|
+
? previewDiffs.hasNewPublicRoutes
|
|
148
|
+
: (body.confirmRouteVisibilityChanges ?? false),
|
|
149
|
+
hitlRequestId: approvedHitlRequestId,
|
|
150
|
+
},
|
|
151
|
+
});
|
|
57
152
|
|
|
58
153
|
return unwrapResult(result);
|
|
59
154
|
};
|
|
@@ -9,13 +9,25 @@ import { z } from "zod";
|
|
|
9
9
|
|
|
10
10
|
import { requirePerm } from "#api/authorize.js";
|
|
11
11
|
import { apiError, handleError, unwrapResult } from "#api/error.js";
|
|
12
|
-
import {
|
|
12
|
+
import {
|
|
13
|
+
ensureWorkflowHitlRouteRequest,
|
|
14
|
+
hitlRequiredRouteError,
|
|
15
|
+
resolveHitlRouteActor,
|
|
16
|
+
} from "#api/hitl-route-helpers.js";
|
|
17
|
+
import { handleMarketplaceInstall, handleMarketplaceInstallPreview } from "#api/index.js";
|
|
13
18
|
import { isParseError, parseOptionalBody } from "#api/parse.js";
|
|
19
|
+
import {
|
|
20
|
+
logPluginActivity,
|
|
21
|
+
pluginApiRouteSource,
|
|
22
|
+
PluginHitlPayloadBuilder,
|
|
23
|
+
RiskPolicyEvaluator,
|
|
24
|
+
} from "#site-context/index.js";
|
|
14
25
|
|
|
15
26
|
export const prerender = false;
|
|
16
27
|
|
|
17
28
|
const installBodySchema = z.object({
|
|
18
29
|
version: z.string().min(1).optional(),
|
|
30
|
+
hitlRequestId: z.string().min(1).optional(),
|
|
19
31
|
});
|
|
20
32
|
|
|
21
33
|
export const POST: APIRoute = async ({ params, request, locals }) => {
|
|
@@ -36,6 +48,55 @@ export const POST: APIRoute = async ({ params, request, locals }) => {
|
|
|
36
48
|
|
|
37
49
|
const body = await parseOptionalBody(request, installBodySchema, {});
|
|
38
50
|
if (isParseError(body)) return body;
|
|
51
|
+
const actor = resolveHitlRouteActor(locals);
|
|
52
|
+
const evaluator = new RiskPolicyEvaluator({
|
|
53
|
+
db: dineway.db,
|
|
54
|
+
handlers: dineway,
|
|
55
|
+
});
|
|
56
|
+
let approvedHitlRequestId: string | null = null;
|
|
57
|
+
|
|
58
|
+
if (evaluator.requiresWorkflowHitl(actor.identity)) {
|
|
59
|
+
if (!body.version) {
|
|
60
|
+
return apiError(
|
|
61
|
+
"VALIDATION_ERROR",
|
|
62
|
+
"API-token marketplace installs require an explicit version so the reviewed target is immutable.",
|
|
63
|
+
400,
|
|
64
|
+
);
|
|
65
|
+
}
|
|
66
|
+
|
|
67
|
+
const preview = await handleMarketplaceInstallPreview(dineway.config.marketplace, id, {
|
|
68
|
+
version: body.version,
|
|
69
|
+
siteOrigin: new URL(request.url).origin,
|
|
70
|
+
});
|
|
71
|
+
if (!preview.success) return unwrapResult(preview);
|
|
72
|
+
|
|
73
|
+
const action = await new PluginHitlPayloadBuilder().buildInstallRequest({
|
|
74
|
+
id: preview.data.pluginId,
|
|
75
|
+
name: preview.data.name,
|
|
76
|
+
description: preview.data.description,
|
|
77
|
+
authorName: preview.data.authorName,
|
|
78
|
+
version: preview.data.version,
|
|
79
|
+
minDinewayVersion: preview.data.minDinewayVersion,
|
|
80
|
+
bundleSize: preview.data.bundleSize,
|
|
81
|
+
checksum: preview.data.checksum,
|
|
82
|
+
changelog: preview.data.changelog,
|
|
83
|
+
capabilities: preview.data.capabilities,
|
|
84
|
+
status: preview.data.status,
|
|
85
|
+
auditVerdict: preview.data.auditVerdict,
|
|
86
|
+
imageAuditVerdict: preview.data.imageAuditVerdict,
|
|
87
|
+
publishedAt: preview.data.publishedAt,
|
|
88
|
+
});
|
|
89
|
+
const decision = await evaluator.evaluateWorkflowHitl({
|
|
90
|
+
actor: actor.identity,
|
|
91
|
+
hitlRequestId: body.hitlRequestId,
|
|
92
|
+
action,
|
|
93
|
+
});
|
|
94
|
+
if (!decision.allowed) {
|
|
95
|
+
const ensured = await ensureWorkflowHitlRouteRequest(dineway.db, locals, decision.action);
|
|
96
|
+
return hitlRequiredRouteError(decision, ensured);
|
|
97
|
+
}
|
|
98
|
+
approvedHitlRequestId = decision.hitlRequest.id;
|
|
99
|
+
}
|
|
39
100
|
|
|
40
101
|
const configuredPluginIds = new Set<string>(
|
|
41
102
|
dineway.configuredPlugins.map((p: { id: string }) => p.id),
|
|
@@ -55,6 +116,16 @@ export const POST: APIRoute = async ({ params, request, locals }) => {
|
|
|
55
116
|
if (!result.success) return unwrapResult(result);
|
|
56
117
|
|
|
57
118
|
await dineway.syncMarketplacePlugins();
|
|
119
|
+
await logPluginActivity(dineway.db, locals, {
|
|
120
|
+
action: "installed",
|
|
121
|
+
pluginId: id,
|
|
122
|
+
...pluginApiRouteSource("installed"),
|
|
123
|
+
summary: `Installed plugin ${id}`,
|
|
124
|
+
detail: {
|
|
125
|
+
version: result.data.version,
|
|
126
|
+
hitlRequestId: approvedHitlRequestId,
|
|
127
|
+
},
|
|
128
|
+
});
|
|
58
129
|
|
|
59
130
|
return unwrapResult(result, 201);
|
|
60
131
|
} catch (error) {
|
|
@@ -0,0 +1,35 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Admin review request detail
|
|
3
|
+
*
|
|
4
|
+
* GET /_dineway/api/admin/review-requests/:id - Get a review request
|
|
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 { handleReviewRequestGet } from "#api/handlers/review-requests.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", "Review request ID required", 400);
|
|
21
|
+
}
|
|
22
|
+
|
|
23
|
+
const dbErr = requireDb(dineway?.db);
|
|
24
|
+
if (dbErr) return dbErr;
|
|
25
|
+
|
|
26
|
+
const denied = requirePerm(user, "content:edit_any");
|
|
27
|
+
if (denied) return denied;
|
|
28
|
+
|
|
29
|
+
try {
|
|
30
|
+
const result = await handleReviewRequestGet(dineway.db, id);
|
|
31
|
+
return unwrapResult(result);
|
|
32
|
+
} catch (error) {
|
|
33
|
+
return handleError(error, "Failed to fetch review request", "REVIEW_REQUEST_GET_ERROR");
|
|
34
|
+
}
|
|
35
|
+
};
|
|
@@ -0,0 +1,52 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Admin review request resolution
|
|
3
|
+
*
|
|
4
|
+
* POST /_dineway/api/admin/review-requests/:id/resolve - Approve or reject a review request
|
|
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 { handleReviewRequestResolve } from "#api/handlers/review-requests.js";
|
|
12
|
+
import { isParseError, parseBody } from "#api/parse.js";
|
|
13
|
+
import { logReviewRouteActivity, resolveReviewRouteActor } from "#api/review-route-helpers.js";
|
|
14
|
+
import { reviewRequestResolveBody } 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", "Review request 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, reviewRequestResolveBody);
|
|
34
|
+
if (isParseError(body)) return body;
|
|
35
|
+
|
|
36
|
+
const result = await handleReviewRequestResolve(dineway.db, id, {
|
|
37
|
+
decision: body.decision,
|
|
38
|
+
reviewNote: body.reviewNote,
|
|
39
|
+
actor: resolveReviewRouteActor(locals),
|
|
40
|
+
});
|
|
41
|
+
if (!result.success) return unwrapResult(result);
|
|
42
|
+
|
|
43
|
+
await logReviewRouteActivity(dineway.db, locals, {
|
|
44
|
+
actionType: body.decision === "approved" ? "review.approved" : "review.rejected",
|
|
45
|
+
item: result.data.item,
|
|
46
|
+
});
|
|
47
|
+
|
|
48
|
+
return unwrapResult(result);
|
|
49
|
+
} catch (error) {
|
|
50
|
+
return handleError(error, "Failed to resolve review request", "REVIEW_REQUEST_RESOLVE_ERROR");
|
|
51
|
+
}
|
|
52
|
+
};
|