dineway 0.1.3 → 0.1.4
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/package.json +6 -3
- package/src/astro/routes/PluginRegistry.tsx +21 -0
- package/src/astro/routes/admin.astro +83 -0
- package/src/astro/routes/api/admin/allowed-domains/[domain].ts +112 -0
- package/src/astro/routes/api/admin/allowed-domains/index.ts +108 -0
- package/src/astro/routes/api/admin/api-tokens/[id].ts +40 -0
- package/src/astro/routes/api/admin/api-tokens/index.ts +68 -0
- package/src/astro/routes/api/admin/bylines/[id]/index.ts +87 -0
- package/src/astro/routes/api/admin/bylines/index.ts +72 -0
- package/src/astro/routes/api/admin/comments/[id]/status.ts +120 -0
- package/src/astro/routes/api/admin/comments/[id].ts +64 -0
- package/src/astro/routes/api/admin/comments/bulk.ts +42 -0
- package/src/astro/routes/api/admin/comments/counts.ts +30 -0
- package/src/astro/routes/api/admin/comments/index.ts +46 -0
- package/src/astro/routes/api/admin/hooks/exclusive/[hookName].ts +91 -0
- package/src/astro/routes/api/admin/hooks/exclusive/index.ts +51 -0
- package/src/astro/routes/api/admin/oauth-clients/[id].ts +110 -0
- package/src/astro/routes/api/admin/oauth-clients/index.ts +71 -0
- package/src/astro/routes/api/admin/plugins/[id]/disable.ts +39 -0
- package/src/astro/routes/api/admin/plugins/[id]/enable.ts +39 -0
- package/src/astro/routes/api/admin/plugins/[id]/index.ts +38 -0
- package/src/astro/routes/api/admin/plugins/[id]/uninstall.ts +48 -0
- package/src/astro/routes/api/admin/plugins/[id]/update.ts +59 -0
- package/src/astro/routes/api/admin/plugins/index.ts +32 -0
- package/src/astro/routes/api/admin/plugins/marketplace/[id]/icon.ts +62 -0
- package/src/astro/routes/api/admin/plugins/marketplace/[id]/index.ts +33 -0
- package/src/astro/routes/api/admin/plugins/marketplace/[id]/install.ts +64 -0
- package/src/astro/routes/api/admin/plugins/marketplace/index.ts +38 -0
- package/src/astro/routes/api/admin/plugins/updates.ts +28 -0
- package/src/astro/routes/api/admin/themes/marketplace/[id]/index.ts +33 -0
- package/src/astro/routes/api/admin/themes/marketplace/[id]/thumbnail.ts +62 -0
- package/src/astro/routes/api/admin/themes/marketplace/index.ts +45 -0
- package/src/astro/routes/api/admin/users/[id]/disable.ts +69 -0
- package/src/astro/routes/api/admin/users/[id]/enable.ts +48 -0
- package/src/astro/routes/api/admin/users/[id]/index.ts +146 -0
- package/src/astro/routes/api/admin/users/[id]/send-recovery.ts +72 -0
- package/src/astro/routes/api/admin/users/index.ts +66 -0
- package/src/astro/routes/api/auth/dev-bypass.ts +139 -0
- package/src/astro/routes/api/auth/invite/accept.ts +52 -0
- package/src/astro/routes/api/auth/invite/complete.ts +86 -0
- package/src/astro/routes/api/auth/invite/index.ts +99 -0
- package/src/astro/routes/api/auth/logout.ts +40 -0
- package/src/astro/routes/api/auth/magic-link/send.ts +89 -0
- package/src/astro/routes/api/auth/magic-link/verify.ts +71 -0
- package/src/astro/routes/api/auth/me.ts +60 -0
- package/src/astro/routes/api/auth/oauth/[provider]/callback.ts +221 -0
- package/src/astro/routes/api/auth/oauth/[provider].ts +120 -0
- package/src/astro/routes/api/auth/passkey/[id].ts +124 -0
- package/src/astro/routes/api/auth/passkey/index.ts +54 -0
- package/src/astro/routes/api/auth/passkey/options.ts +84 -0
- package/src/astro/routes/api/auth/passkey/register/options.ts +88 -0
- package/src/astro/routes/api/auth/passkey/register/verify.ts +119 -0
- package/src/astro/routes/api/auth/passkey/verify.ts +68 -0
- package/src/astro/routes/api/auth/signup/complete.ts +87 -0
- package/src/astro/routes/api/auth/signup/request.ts +77 -0
- package/src/astro/routes/api/auth/signup/verify.ts +53 -0
- package/src/astro/routes/api/comments/[collection]/[contentId]/index.ts +311 -0
- package/src/astro/routes/api/content/[collection]/[id]/compare.ts +28 -0
- package/src/astro/routes/api/content/[collection]/[id]/discard-draft.ts +54 -0
- package/src/astro/routes/api/content/[collection]/[id]/duplicate.ts +61 -0
- package/src/astro/routes/api/content/[collection]/[id]/permanent.ts +33 -0
- package/src/astro/routes/api/content/[collection]/[id]/preview-url.ts +107 -0
- package/src/astro/routes/api/content/[collection]/[id]/publish.ts +56 -0
- package/src/astro/routes/api/content/[collection]/[id]/restore.ts +54 -0
- package/src/astro/routes/api/content/[collection]/[id]/revisions.ts +31 -0
- package/src/astro/routes/api/content/[collection]/[id]/schedule.ts +105 -0
- package/src/astro/routes/api/content/[collection]/[id]/terms/[taxonomy].ts +140 -0
- package/src/astro/routes/api/content/[collection]/[id]/translations.ts +30 -0
- package/src/astro/routes/api/content/[collection]/[id]/unpublish.ts +56 -0
- package/src/astro/routes/api/content/[collection]/[id].ts +137 -0
- package/src/astro/routes/api/content/[collection]/index.ts +59 -0
- package/src/astro/routes/api/content/[collection]/trash.ts +33 -0
- package/src/astro/routes/api/dashboard.ts +32 -0
- package/src/astro/routes/api/dev/emails.ts +36 -0
- package/src/astro/routes/api/import/probe.ts +47 -0
- package/src/astro/routes/api/import/wordpress/analyze.ts +531 -0
- package/src/astro/routes/api/import/wordpress/execute.ts +296 -0
- package/src/astro/routes/api/import/wordpress/media.ts +338 -0
- package/src/astro/routes/api/import/wordpress/prepare.ts +181 -0
- package/src/astro/routes/api/import/wordpress/rewrite-urls.ts +393 -0
- package/src/astro/routes/api/import/wordpress-plugin/analyze.ts +111 -0
- package/src/astro/routes/api/import/wordpress-plugin/callback.ts +58 -0
- package/src/astro/routes/api/import/wordpress-plugin/execute.ts +357 -0
- package/src/astro/routes/api/manifest.ts +63 -0
- package/src/astro/routes/api/mcp.ts +124 -0
- package/src/astro/routes/api/media/[id]/confirm.ts +93 -0
- package/src/astro/routes/api/media/[id].ts +145 -0
- package/src/astro/routes/api/media/file/[...key].ts +79 -0
- package/src/astro/routes/api/media/providers/[providerId]/[itemId].ts +86 -0
- package/src/astro/routes/api/media/providers/[providerId]/index.ts +111 -0
- package/src/astro/routes/api/media/providers/index.ts +30 -0
- package/src/astro/routes/api/media/upload-url.ts +137 -0
- package/src/astro/routes/api/media.ts +202 -0
- package/src/astro/routes/api/menus/[name]/items.ts +87 -0
- package/src/astro/routes/api/menus/[name]/reorder.ts +33 -0
- package/src/astro/routes/api/menus/[name].ts +65 -0
- package/src/astro/routes/api/menus/index.ts +47 -0
- package/src/astro/routes/api/oauth/authorize.ts +417 -0
- package/src/astro/routes/api/oauth/device/authorize.ts +45 -0
- package/src/astro/routes/api/oauth/device/code.ts +55 -0
- package/src/astro/routes/api/oauth/device/token.ts +69 -0
- package/src/astro/routes/api/oauth/token/refresh.ts +38 -0
- package/src/astro/routes/api/oauth/token/revoke.ts +38 -0
- package/src/astro/routes/api/oauth/token.ts +184 -0
- package/src/astro/routes/api/openapi.json.ts +32 -0
- package/src/astro/routes/api/plugins/[pluginId]/[...path].ts +92 -0
- package/src/astro/routes/api/redirects/404s/index.ts +72 -0
- package/src/astro/routes/api/redirects/404s/summary.ts +33 -0
- package/src/astro/routes/api/redirects/[id].ts +84 -0
- package/src/astro/routes/api/redirects/index.ts +52 -0
- package/src/astro/routes/api/revisions/[revisionId]/index.ts +29 -0
- package/src/astro/routes/api/revisions/[revisionId]/restore.ts +62 -0
- package/src/astro/routes/api/schema/collections/[slug]/fields/[fieldSlug].ts +76 -0
- package/src/astro/routes/api/schema/collections/[slug]/fields/index.ts +52 -0
- package/src/astro/routes/api/schema/collections/[slug]/fields/reorder.ts +32 -0
- package/src/astro/routes/api/schema/collections/[slug]/index.ts +80 -0
- package/src/astro/routes/api/schema/collections/index.ts +47 -0
- package/src/astro/routes/api/schema/index.ts +109 -0
- package/src/astro/routes/api/schema/orphans/[slug].ts +36 -0
- package/src/astro/routes/api/schema/orphans/index.ts +26 -0
- package/src/astro/routes/api/search/enable.ts +64 -0
- package/src/astro/routes/api/search/index.ts +51 -0
- package/src/astro/routes/api/search/rebuild.ts +72 -0
- package/src/astro/routes/api/search/stats.ts +35 -0
- package/src/astro/routes/api/search/suggest.ts +49 -0
- package/src/astro/routes/api/sections/[slug].ts +84 -0
- package/src/astro/routes/api/sections/index.ts +52 -0
- package/src/astro/routes/api/settings/email.ts +150 -0
- package/src/astro/routes/api/settings.ts +67 -0
- package/src/astro/routes/api/setup/admin-verify.ts +102 -0
- package/src/astro/routes/api/setup/admin.ts +96 -0
- package/src/astro/routes/api/setup/dev-bypass.ts +200 -0
- package/src/astro/routes/api/setup/dev-reset.ts +40 -0
- package/src/astro/routes/api/setup/index.ts +127 -0
- package/src/astro/routes/api/setup/status.ts +122 -0
- package/src/astro/routes/api/snapshot.ts +76 -0
- package/src/astro/routes/api/taxonomies/[name]/terms/[slug].ts +95 -0
- package/src/astro/routes/api/taxonomies/[name]/terms/index.ts +69 -0
- package/src/astro/routes/api/taxonomies/index.ts +59 -0
- package/src/astro/routes/api/themes/preview.ts +78 -0
- package/src/astro/routes/api/typegen.ts +114 -0
- package/src/astro/routes/api/well-known/auth.ts +69 -0
- package/src/astro/routes/api/well-known/oauth-authorization-server.ts +45 -0
- package/src/astro/routes/api/well-known/oauth-protected-resource.ts +38 -0
- package/src/astro/routes/api/widget-areas/[name]/reorder.ts +72 -0
- package/src/astro/routes/api/widget-areas/[name]/widgets/[id].ts +127 -0
- package/src/astro/routes/api/widget-areas/[name]/widgets.ts +80 -0
- package/src/astro/routes/api/widget-areas/[name].ts +87 -0
- package/src/astro/routes/api/widget-areas/index.ts +99 -0
- package/src/astro/routes/api/widget-components.ts +22 -0
- package/src/astro/routes/robots.txt.ts +81 -0
- package/src/astro/routes/sitemap-[collection].xml.ts +104 -0
- package/src/astro/routes/sitemap.xml.ts +92 -0
- package/src/components/Break.astro +45 -0
- package/src/components/Button.astro +71 -0
- package/src/components/Buttons.astro +49 -0
- package/src/components/Code.astro +59 -0
- package/src/components/Columns.astro +59 -0
- package/src/components/CommentForm.astro +315 -0
- package/src/components/Comments.astro +232 -0
- package/src/components/Cover.astro +128 -0
- package/src/components/DinewayBodyEnd.astro +32 -0
- package/src/components/DinewayBodyStart.astro +32 -0
- package/src/components/DinewayHead.astro +53 -0
- package/src/components/DinewayImage.astro +178 -0
- package/src/components/DinewayMedia.astro +167 -0
- package/src/components/Embed.astro +128 -0
- package/src/components/File.astro +122 -0
- package/src/components/Gallery.astro +93 -0
- package/src/components/HtmlBlock.astro +33 -0
- package/src/components/Image.astro +178 -0
- package/src/components/InlineEditor.astro +27 -0
- package/src/components/InlinePortableTextEditor.tsx +1937 -0
- package/src/components/LiveSearch.astro +614 -0
- package/src/components/PortableText.astro +51 -0
- package/src/components/Pullquote.astro +51 -0
- package/src/components/Table.astro +108 -0
- package/src/components/WidgetArea.astro +22 -0
- package/src/components/WidgetRenderer.astro +72 -0
- package/src/components/index.ts +116 -0
- package/src/components/marks/Link.astro +31 -0
- package/src/components/marks/StrikeThrough.astro +7 -0
- package/src/components/marks/Subscript.astro +7 -0
- package/src/components/marks/Superscript.astro +7 -0
- package/src/components/marks/Underline.astro +7 -0
- package/src/components/widgets/Archives.astro +65 -0
- package/src/components/widgets/Categories.astro +35 -0
- package/src/components/widgets/RecentPosts.astro +51 -0
- package/src/components/widgets/Search.astro +18 -0
- package/src/components/widgets/Tags.astro +38 -0
- package/src/ui.ts +75 -0
|
@@ -0,0 +1,137 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Single content item endpoints - injected by Dineway integration
|
|
3
|
+
*
|
|
4
|
+
* GET /_dineway/api/content/{collection}/{id} - Get content
|
|
5
|
+
* PUT /_dineway/api/content/{collection}/{id} - Update content
|
|
6
|
+
* DELETE /_dineway/api/content/{collection}/{id} - Delete content
|
|
7
|
+
*/
|
|
8
|
+
|
|
9
|
+
import { hasPermission, type Permission } from "@dineway-ai/auth";
|
|
10
|
+
import type { APIRoute } from "astro";
|
|
11
|
+
|
|
12
|
+
import { requirePerm, requireOwnerPerm } from "#api/authorize.js";
|
|
13
|
+
import { apiError, mapErrorStatus, unwrapResult } from "#api/error.js";
|
|
14
|
+
import { parseBody, isParseError } from "#api/parse.js";
|
|
15
|
+
import { contentUpdateBody } from "#api/schemas.js";
|
|
16
|
+
|
|
17
|
+
export const prerender = false;
|
|
18
|
+
|
|
19
|
+
export const GET: APIRoute = async ({ params, url, locals }) => {
|
|
20
|
+
const { dineway, user } = locals;
|
|
21
|
+
const denied = requirePerm(user, "content:read");
|
|
22
|
+
if (denied) return denied;
|
|
23
|
+
const collection = params.collection!;
|
|
24
|
+
const id = params.id!;
|
|
25
|
+
const locale = url.searchParams.get("locale") || undefined;
|
|
26
|
+
|
|
27
|
+
if (!dineway?.handleContentGet) {
|
|
28
|
+
return apiError("NOT_CONFIGURED", "Dineway is not initialized", 500);
|
|
29
|
+
}
|
|
30
|
+
|
|
31
|
+
const result = await dineway.handleContentGet(collection, id, locale);
|
|
32
|
+
|
|
33
|
+
return unwrapResult(result);
|
|
34
|
+
};
|
|
35
|
+
|
|
36
|
+
export const PUT: APIRoute = async ({ params, request, locals, cache }) => {
|
|
37
|
+
const { dineway, user } = locals;
|
|
38
|
+
const collection = params.collection!;
|
|
39
|
+
const id = params.id!;
|
|
40
|
+
const body = await parseBody(request, contentUpdateBody);
|
|
41
|
+
if (isParseError(body)) return body;
|
|
42
|
+
|
|
43
|
+
if (!dineway?.handleContentUpdate || !dineway?.handleContentGet) {
|
|
44
|
+
return apiError("NOT_CONFIGURED", "Dineway is not initialized", 500);
|
|
45
|
+
}
|
|
46
|
+
|
|
47
|
+
// Fetch item to check ownership
|
|
48
|
+
const existing = await dineway.handleContentGet(collection, id);
|
|
49
|
+
if (!existing.success) {
|
|
50
|
+
return apiError(
|
|
51
|
+
existing.error?.code ?? "UNKNOWN_ERROR",
|
|
52
|
+
existing.error?.message ?? "Unknown error",
|
|
53
|
+
mapErrorStatus(existing.error?.code),
|
|
54
|
+
);
|
|
55
|
+
}
|
|
56
|
+
|
|
57
|
+
const existingData =
|
|
58
|
+
existing.data && typeof existing.data === "object"
|
|
59
|
+
? // eslint-disable-next-line typescript-eslint(no-unsafe-type-assertion) -- handler returns unknown data; narrowed by typeof check above
|
|
60
|
+
(existing.data as Record<string, unknown>)
|
|
61
|
+
: undefined;
|
|
62
|
+
// Handler returns { item, _rev } — extract the item for ownership and ID resolution
|
|
63
|
+
const existingItem =
|
|
64
|
+
existingData?.item && typeof existingData.item === "object"
|
|
65
|
+
? // eslint-disable-next-line typescript-eslint(no-unsafe-type-assertion) -- narrowed by typeof check above
|
|
66
|
+
(existingData.item as Record<string, unknown>)
|
|
67
|
+
: existingData;
|
|
68
|
+
const authorId = typeof existingItem?.authorId === "string" ? existingItem.authorId : "";
|
|
69
|
+
const editDenied = requireOwnerPerm(user, authorId, "content:edit_own", "content:edit_any");
|
|
70
|
+
if (editDenied) return editDenied;
|
|
71
|
+
|
|
72
|
+
// Use the resolved ID (handles slug → ID resolution)
|
|
73
|
+
const resolvedId = typeof existingItem?.id === "string" ? existingItem.id : id;
|
|
74
|
+
|
|
75
|
+
// Only allow authorId changes if user has content:edit_any permission (editor+)
|
|
76
|
+
const canChangeAuthor =
|
|
77
|
+
body.authorId !== undefined && user && hasPermission(user, "content:edit_any" as Permission);
|
|
78
|
+
const updateBody = canChangeAuthor ? body : { ...body, authorId: undefined };
|
|
79
|
+
|
|
80
|
+
// Pass _rev through for optimistic concurrency validation
|
|
81
|
+
const result = await dineway.handleContentUpdate(collection, resolvedId, {
|
|
82
|
+
...updateBody,
|
|
83
|
+
_rev: body._rev,
|
|
84
|
+
});
|
|
85
|
+
|
|
86
|
+
if (!result.success) return unwrapResult(result);
|
|
87
|
+
|
|
88
|
+
if (cache.enabled) await cache.invalidate({ tags: [collection, resolvedId] });
|
|
89
|
+
|
|
90
|
+
return unwrapResult(result);
|
|
91
|
+
};
|
|
92
|
+
|
|
93
|
+
export const DELETE: APIRoute = async ({ params, locals, cache }) => {
|
|
94
|
+
const { dineway, user } = locals;
|
|
95
|
+
const collection = params.collection!;
|
|
96
|
+
const id = params.id!;
|
|
97
|
+
|
|
98
|
+
if (!dineway?.handleContentDelete || !dineway?.handleContentGet) {
|
|
99
|
+
return apiError("NOT_CONFIGURED", "Dineway is not initialized", 500);
|
|
100
|
+
}
|
|
101
|
+
|
|
102
|
+
// Fetch item to check ownership
|
|
103
|
+
const existing = await dineway.handleContentGet(collection, id);
|
|
104
|
+
if (!existing.success) {
|
|
105
|
+
return apiError(
|
|
106
|
+
existing.error?.code ?? "UNKNOWN_ERROR",
|
|
107
|
+
existing.error?.message ?? "Unknown error",
|
|
108
|
+
mapErrorStatus(existing.error?.code),
|
|
109
|
+
);
|
|
110
|
+
}
|
|
111
|
+
|
|
112
|
+
const deleteData =
|
|
113
|
+
existing.data && typeof existing.data === "object"
|
|
114
|
+
? // eslint-disable-next-line typescript-eslint(no-unsafe-type-assertion) -- handler returns unknown data; narrowed by typeof check above
|
|
115
|
+
(existing.data as Record<string, unknown>)
|
|
116
|
+
: undefined;
|
|
117
|
+
// Handler returns { item, _rev } — extract the item for ownership and ID resolution
|
|
118
|
+
const deleteItem =
|
|
119
|
+
deleteData?.item && typeof deleteData.item === "object"
|
|
120
|
+
? // eslint-disable-next-line typescript-eslint(no-unsafe-type-assertion) -- narrowed by typeof check above
|
|
121
|
+
(deleteData.item as Record<string, unknown>)
|
|
122
|
+
: deleteData;
|
|
123
|
+
const authorId = typeof deleteItem?.authorId === "string" ? deleteItem.authorId : "";
|
|
124
|
+
const deleteDenied = requireOwnerPerm(user, authorId, "content:delete_own", "content:delete_any");
|
|
125
|
+
if (deleteDenied) return deleteDenied;
|
|
126
|
+
|
|
127
|
+
// Use the resolved ID (handles slug → ID resolution)
|
|
128
|
+
const resolvedId = typeof deleteItem?.id === "string" ? deleteItem.id : id;
|
|
129
|
+
|
|
130
|
+
const result = await dineway.handleContentDelete(collection, resolvedId);
|
|
131
|
+
|
|
132
|
+
if (!result.success) return unwrapResult(result);
|
|
133
|
+
|
|
134
|
+
if (cache.enabled) await cache.invalidate({ tags: [collection, resolvedId] });
|
|
135
|
+
|
|
136
|
+
return unwrapResult(result);
|
|
137
|
+
};
|
|
@@ -0,0 +1,59 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Content list and create endpoints - injected by Dineway integration
|
|
3
|
+
*
|
|
4
|
+
* GET /_dineway/api/content/{collection} - List content
|
|
5
|
+
* POST /_dineway/api/content/{collection} - Create content
|
|
6
|
+
*/
|
|
7
|
+
|
|
8
|
+
import type { APIRoute } from "astro";
|
|
9
|
+
|
|
10
|
+
import { requirePerm } from "#api/authorize.js";
|
|
11
|
+
import { apiError, unwrapResult } from "#api/error.js";
|
|
12
|
+
import { parseBody, parseQuery, isParseError } from "#api/parse.js";
|
|
13
|
+
import { contentListQuery, contentCreateBody } from "#api/schemas.js";
|
|
14
|
+
|
|
15
|
+
export const prerender = false;
|
|
16
|
+
|
|
17
|
+
export const GET: APIRoute = async ({ params, url, locals }) => {
|
|
18
|
+
const { dineway, user } = locals;
|
|
19
|
+
const denied = requirePerm(user, "content:read");
|
|
20
|
+
if (denied) return denied;
|
|
21
|
+
const collection = params.collection!;
|
|
22
|
+
const query = parseQuery(url, contentListQuery);
|
|
23
|
+
if (isParseError(query)) return query;
|
|
24
|
+
|
|
25
|
+
if (!dineway?.handleContentList) {
|
|
26
|
+
return apiError("NOT_CONFIGURED", "Dineway is not initialized", 500);
|
|
27
|
+
}
|
|
28
|
+
|
|
29
|
+
const result = await dineway.handleContentList(collection, query);
|
|
30
|
+
|
|
31
|
+
return unwrapResult(result);
|
|
32
|
+
};
|
|
33
|
+
|
|
34
|
+
export const POST: APIRoute = async ({ params, request, locals, cache }) => {
|
|
35
|
+
const { dineway, user } = locals;
|
|
36
|
+
const denied = requirePerm(user, "content:create");
|
|
37
|
+
if (denied) return denied;
|
|
38
|
+
const collection = params.collection!;
|
|
39
|
+
const body = await parseBody(request, contentCreateBody);
|
|
40
|
+
if (isParseError(body)) return body;
|
|
41
|
+
|
|
42
|
+
if (!dineway?.handleContentCreate) {
|
|
43
|
+
return apiError("NOT_CONFIGURED", "Dineway is not initialized", 500);
|
|
44
|
+
}
|
|
45
|
+
|
|
46
|
+
// Auto-set authorId to current user when creating content
|
|
47
|
+
const result = await dineway.handleContentCreate(collection, {
|
|
48
|
+
...body,
|
|
49
|
+
authorId: user?.id,
|
|
50
|
+
locale: body.locale,
|
|
51
|
+
translationOf: body.translationOf,
|
|
52
|
+
});
|
|
53
|
+
|
|
54
|
+
if (!result.success) return unwrapResult(result);
|
|
55
|
+
|
|
56
|
+
if (cache.enabled) await cache.invalidate({ tags: [collection] });
|
|
57
|
+
|
|
58
|
+
return unwrapResult(result, 201);
|
|
59
|
+
};
|
|
@@ -0,0 +1,33 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Trash endpoints for content collection - injected by Dineway integration
|
|
3
|
+
*
|
|
4
|
+
* GET /_dineway/api/content/{collection}/trash - List trashed items
|
|
5
|
+
*/
|
|
6
|
+
|
|
7
|
+
import type { APIRoute } from "astro";
|
|
8
|
+
|
|
9
|
+
import { requirePerm } from "#api/authorize.js";
|
|
10
|
+
import { apiError, unwrapResult } from "#api/error.js";
|
|
11
|
+
import { parseQuery, isParseError } from "#api/parse.js";
|
|
12
|
+
import { contentTrashQuery } from "#api/schemas.js";
|
|
13
|
+
|
|
14
|
+
export const prerender = false;
|
|
15
|
+
|
|
16
|
+
export const GET: APIRoute = async ({ params, url, locals }) => {
|
|
17
|
+
const { dineway, user } = locals;
|
|
18
|
+
const collection = params.collection!;
|
|
19
|
+
|
|
20
|
+
const denied = requirePerm(user, "content:read");
|
|
21
|
+
if (denied) return denied;
|
|
22
|
+
|
|
23
|
+
if (!dineway?.handleContentListTrashed) {
|
|
24
|
+
return apiError("NOT_CONFIGURED", "Dineway is not initialized", 500);
|
|
25
|
+
}
|
|
26
|
+
|
|
27
|
+
const query = parseQuery(url, contentTrashQuery);
|
|
28
|
+
if (isParseError(query)) return query;
|
|
29
|
+
|
|
30
|
+
const result = await dineway.handleContentListTrashed(collection, query);
|
|
31
|
+
|
|
32
|
+
return unwrapResult(result);
|
|
33
|
+
};
|
|
@@ -0,0 +1,32 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Dashboard stats endpoint
|
|
3
|
+
*
|
|
4
|
+
* GET /_dineway/api/dashboard - Collection counts, media/user counts, recent items
|
|
5
|
+
*/
|
|
6
|
+
|
|
7
|
+
import type { APIRoute } from "astro";
|
|
8
|
+
|
|
9
|
+
import { requirePerm } from "#api/authorize.js";
|
|
10
|
+
import { apiError, handleError, unwrapResult } from "#api/error.js";
|
|
11
|
+
import { handleDashboardStats } from "#api/handlers/dashboard.js";
|
|
12
|
+
|
|
13
|
+
export const prerender = false;
|
|
14
|
+
|
|
15
|
+
export const GET: APIRoute = async ({ locals }) => {
|
|
16
|
+
const { dineway, user } = locals;
|
|
17
|
+
|
|
18
|
+
const denied = requirePerm(user, "content:read");
|
|
19
|
+
if (denied) return denied;
|
|
20
|
+
|
|
21
|
+
if (!dineway?.db) {
|
|
22
|
+
return apiError("NOT_CONFIGURED", "Dineway is not initialized", 500);
|
|
23
|
+
}
|
|
24
|
+
|
|
25
|
+
try {
|
|
26
|
+
const result = await handleDashboardStats(dineway.db);
|
|
27
|
+
|
|
28
|
+
return unwrapResult(result);
|
|
29
|
+
} catch (error) {
|
|
30
|
+
return handleError(error, "Failed to load dashboard", "DASHBOARD_ERROR");
|
|
31
|
+
}
|
|
32
|
+
};
|
|
@@ -0,0 +1,36 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* GET /_dineway/api/dev/emails
|
|
3
|
+
* DELETE /_dineway/api/dev/emails
|
|
4
|
+
*
|
|
5
|
+
* Development-only endpoint to view and clear emails captured by
|
|
6
|
+
* the dev console email provider.
|
|
7
|
+
*
|
|
8
|
+
* ONLY available when import.meta.env.DEV is true.
|
|
9
|
+
*
|
|
10
|
+
*/
|
|
11
|
+
|
|
12
|
+
import type { APIRoute } from "astro";
|
|
13
|
+
|
|
14
|
+
export const prerender = false;
|
|
15
|
+
|
|
16
|
+
import { apiError, apiSuccess } from "#api/error.js";
|
|
17
|
+
|
|
18
|
+
import { clearDevEmails, getDevEmails } from "../../../../plugins/email-console.js";
|
|
19
|
+
|
|
20
|
+
export const GET: APIRoute = async () => {
|
|
21
|
+
if (!import.meta.env.DEV) {
|
|
22
|
+
return apiError("FORBIDDEN", "Dev emails endpoint is only available in development mode", 403);
|
|
23
|
+
}
|
|
24
|
+
|
|
25
|
+
const emails = getDevEmails();
|
|
26
|
+
return apiSuccess({ items: emails });
|
|
27
|
+
};
|
|
28
|
+
|
|
29
|
+
export const DELETE: APIRoute = async () => {
|
|
30
|
+
if (!import.meta.env.DEV) {
|
|
31
|
+
return apiError("FORBIDDEN", "Dev emails endpoint is only available in development mode", 403);
|
|
32
|
+
}
|
|
33
|
+
|
|
34
|
+
clearDevEmails();
|
|
35
|
+
return apiSuccess({ success: true });
|
|
36
|
+
};
|
|
@@ -0,0 +1,47 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* URL probe endpoint
|
|
3
|
+
*
|
|
4
|
+
* POST /_dineway/api/import/probe
|
|
5
|
+
*
|
|
6
|
+
* Probes a URL to detect what import source can handle it.
|
|
7
|
+
*/
|
|
8
|
+
|
|
9
|
+
import type { APIRoute } from "astro";
|
|
10
|
+
|
|
11
|
+
import { requirePerm } from "#api/authorize.js";
|
|
12
|
+
import { apiError, apiSuccess, handleError } from "#api/error.js";
|
|
13
|
+
import { isParseError, parseBody } from "#api/parse.js";
|
|
14
|
+
import { importProbeBody } from "#api/schemas.js";
|
|
15
|
+
import { probeUrl, type ProbeResult } from "#import/index.js";
|
|
16
|
+
import { SsrfError } from "#import/ssrf.js";
|
|
17
|
+
|
|
18
|
+
export const prerender = false;
|
|
19
|
+
|
|
20
|
+
export interface ProbeResponse {
|
|
21
|
+
success: boolean;
|
|
22
|
+
result?: ProbeResult;
|
|
23
|
+
error?: { message: string };
|
|
24
|
+
}
|
|
25
|
+
|
|
26
|
+
export const POST: APIRoute = async ({ request, locals }) => {
|
|
27
|
+
const { user } = locals;
|
|
28
|
+
const denied = requirePerm(user, "import:execute");
|
|
29
|
+
if (denied) return denied;
|
|
30
|
+
|
|
31
|
+
try {
|
|
32
|
+
const body = await parseBody(request, importProbeBody);
|
|
33
|
+
if (isParseError(body)) return body;
|
|
34
|
+
|
|
35
|
+
const result = await probeUrl(body.url);
|
|
36
|
+
|
|
37
|
+
return apiSuccess({
|
|
38
|
+
success: true,
|
|
39
|
+
result,
|
|
40
|
+
});
|
|
41
|
+
} catch (error) {
|
|
42
|
+
if (error instanceof SsrfError) {
|
|
43
|
+
return apiError("SSRF_BLOCKED", error.message, 400);
|
|
44
|
+
}
|
|
45
|
+
return handleError(error, "Failed to probe URL", "PROBE_ERROR");
|
|
46
|
+
}
|
|
47
|
+
};
|