@ekrist1/vulse 0.1.6-alpha.3 → 0.1.7-alpha.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/dist/cli/migrate.d.ts.map +1 -1
- package/dist/cli/migrate.js +3 -4
- package/dist/cli/setup.d.ts.map +1 -1
- package/dist/cli/setup.js +11 -10
- package/dist/core/blueprints/compile.d.ts +1 -1
- package/dist/core/blueprints/compile.d.ts.map +1 -1
- package/dist/core/blueprints/compile.js +3 -3
- package/dist/core/blueprints/mutations.js +2 -2
- package/dist/core/forms/rate-limit.d.ts +1 -1
- package/dist/core/forms/rate-limit.d.ts.map +1 -1
- package/dist/core/forms/rate-limit.js +3 -3
- package/dist/core/forms/unique.d.ts +1 -1
- package/dist/core/forms/unique.d.ts.map +1 -1
- package/dist/core/forms/unique.js +4 -4
- package/dist/core/globals/compile.d.ts +1 -1
- package/dist/core/globals/compile.d.ts.map +1 -1
- package/dist/core/globals/compile.js +2 -2
- package/dist/core/globals/definition.d.ts +1 -1
- package/dist/core/globals/definition.d.ts.map +1 -1
- package/dist/core/globals/definition.js +3 -3
- package/dist/core/repos/globals.js +3 -3
- package/dist/core/sha256.d.ts +3 -0
- package/dist/core/sha256.d.ts.map +1 -0
- package/dist/core/sha256.js +9 -0
- package/dist/integration/index.js +1 -1
- package/dist/integration/install-hook.d.ts.map +1 -1
- package/dist/integration/install-hook.js +6 -4
- package/dist/integration/wrangler-config.d.ts +12 -0
- package/dist/integration/wrangler-config.d.ts.map +1 -0
- package/dist/integration/wrangler-config.js +97 -0
- package/dist/integration/wrangler-patch.d.ts +1 -0
- package/dist/integration/wrangler-patch.d.ts.map +1 -1
- package/dist/integration/wrangler-patch.js +2 -1
- package/dist/server/routes/form-submit.js +1 -1
- package/dist/version.d.ts +1 -1
- package/dist/version.js +1 -1
- package/package.json +11 -3
- package/src/admin/assets/logo-mark.svg +5 -0
- package/src/admin/client/active-locale.ts +17 -0
- package/src/admin/client/api.ts +21 -0
- package/src/admin/client/form-from-zod.ts +7 -0
- package/src/admin/client/live-preview-enabled.ts +5 -0
- package/src/admin/components/AdminShell.astro +45 -0
- package/src/admin/components/AuthSettings.vue +60 -0
- package/src/admin/components/BlockEditor.vue +53 -0
- package/src/admin/components/BlueprintEditor.vue +1783 -0
- package/src/admin/components/CollectionKindIcon.vue +26 -0
- package/src/admin/components/CollectionTree.vue +220 -0
- package/src/admin/components/EntryEditorWithPreview.vue +130 -0
- package/src/admin/components/EntryForm.vue +411 -0
- package/src/admin/components/EntryList.vue +121 -0
- package/src/admin/components/EntryStatusBadge.vue +24 -0
- package/src/admin/components/FormEditor.vue +233 -0
- package/src/admin/components/FormList.vue +54 -0
- package/src/admin/components/GlobalSetEditor.vue +272 -0
- package/src/admin/components/GlobalSetList.vue +55 -0
- package/src/admin/components/LivePreviewPanel.vue +171 -0
- package/src/admin/components/LoginForm.vue +53 -0
- package/src/admin/components/MediaLibrary.vue +106 -0
- package/src/admin/components/MediaPicker.vue +49 -0
- package/src/admin/components/RevisionDiff.vue +11 -0
- package/src/admin/components/RevisionList.vue +134 -0
- package/src/admin/components/SeoFields.vue +113 -0
- package/src/admin/components/SetEditor.vue +137 -0
- package/src/admin/components/SetList.vue +32 -0
- package/src/admin/components/SettingsForm.vue +189 -0
- package/src/admin/components/SideNav.vue +152 -0
- package/src/admin/components/SubmissionDetail.vue +45 -0
- package/src/admin/components/SubmissionList.vue +89 -0
- package/src/admin/components/ToastHost.vue +33 -0
- package/src/admin/components/TreeRow.vue +163 -0
- package/src/admin/components/UserEditor.vue +186 -0
- package/src/admin/components/UserList.vue +46 -0
- package/src/admin/components/blocks/BlockItem.vue +32 -0
- package/src/admin/components/blocks/BlockToolbar.vue +12 -0
- package/src/admin/components/blocks/edit/CodeEdit.vue +18 -0
- package/src/admin/components/blocks/edit/EmbedEdit.vue +14 -0
- package/src/admin/components/blocks/edit/HeadingEdit.vue +19 -0
- package/src/admin/components/blocks/edit/ImageEdit.vue +40 -0
- package/src/admin/components/blocks/edit/ListEdit.vue +36 -0
- package/src/admin/components/blocks/edit/ParagraphEdit.vue +14 -0
- package/src/admin/components/blocks/edit/QuoteEdit.vue +18 -0
- package/src/admin/components/fields/BlocksField.vue +123 -0
- package/src/admin/components/fields/BlocksSetsPicker.vue +59 -0
- package/src/admin/components/fields/BoolField.vue +10 -0
- package/src/admin/components/fields/DateField.vue +22 -0
- package/src/admin/components/fields/EntriesField.vue +153 -0
- package/src/admin/components/fields/EntryField.vue +138 -0
- package/src/admin/components/fields/EnumField.vue +81 -0
- package/src/admin/components/fields/FieldRenderer.vue +87 -0
- package/src/admin/components/fields/GridField.vue +173 -0
- package/src/admin/components/fields/LinkField.vue +219 -0
- package/src/admin/components/fields/MediaField.vue +69 -0
- package/src/admin/components/fields/NumberField.vue +12 -0
- package/src/admin/components/fields/ObjectField.vue +18 -0
- package/src/admin/components/fields/RefField.vue +170 -0
- package/src/admin/components/fields/RepeaterField.vue +27 -0
- package/src/admin/components/fields/ReplicatorField.vue +121 -0
- package/src/admin/components/fields/TextField.vue +11 -0
- package/src/admin/components/fields/TextareaField.vue +11 -0
- package/src/admin/components/fields/VulseAccordionGroupNodeView.vue +82 -0
- package/src/admin/components/fields/VulseAccordionNodeView.vue +128 -0
- package/src/admin/components/fields/VulseCalloutNodeView.vue +81 -0
- package/src/admin/components/fields/VulseIframeNodeView.vue +112 -0
- package/src/admin/components/fields/VulseSetNodeView.vue +68 -0
- package/src/admin/components/fields/VulseVideoNodeView.vue +104 -0
- package/src/admin/components/fields/blocks-editor-extensions.ts +26 -0
- package/src/admin/components/fields/emoji-extension.ts +54 -0
- package/src/admin/components/fields/link-extension.ts +48 -0
- package/src/admin/components/fields/set-node-utils.ts +115 -0
- package/src/admin/components/fields/url-utils.ts +85 -0
- package/src/admin/components/fields/vulse-accordion-extension.ts +64 -0
- package/src/admin/components/fields/vulse-accordion-group-extension.ts +49 -0
- package/src/admin/components/fields/vulse-callout-extension.ts +53 -0
- package/src/admin/components/fields/vulse-iframe-extension.ts +96 -0
- package/src/admin/components/fields/vulse-set-extension.ts +66 -0
- package/src/admin/components/fields/vulse-video-extension.ts +65 -0
- package/src/admin/composables/toast.ts +35 -0
- package/src/admin/composables/useEntrySearch.ts +112 -0
- package/src/admin/composables/useSets.ts +31 -0
- package/src/admin/pages/collections/[name]/[id]/revisions.astro +27 -0
- package/src/admin/pages/collections/[name]/[id].astro +90 -0
- package/src/admin/pages/collections/[name]/index.astro +31 -0
- package/src/admin/pages/collections/[name]/new.astro +38 -0
- package/src/admin/pages/forms/[handle]/submissions/[id].astro +9 -0
- package/src/admin/pages/forms/[handle]/submissions/index.astro +9 -0
- package/src/admin/pages/forms/[handle].astro +9 -0
- package/src/admin/pages/forms/index.astro +7 -0
- package/src/admin/pages/forms/new.astro +7 -0
- package/src/admin/pages/index.astro +36 -0
- package/src/admin/pages/login.astro +14 -0
- package/src/admin/pages/media.astro +8 -0
- package/src/admin/pages/schema/[handle].astro +10 -0
- package/src/admin/pages/schema/new.astro +9 -0
- package/src/admin/pages/settings/auth.astro +9 -0
- package/src/admin/pages/settings/globals/[handle].astro +9 -0
- package/src/admin/pages/settings/globals/index.astro +7 -0
- package/src/admin/pages/settings/globals/new.astro +7 -0
- package/src/admin/pages/settings/index.astro +8 -0
- package/src/admin/pages/settings/sets/[handle].astro +9 -0
- package/src/admin/pages/settings/sets/index.astro +7 -0
- package/src/admin/pages/settings/sets/new.astro +7 -0
- package/src/admin/pages/users/[id].astro +10 -0
- package/src/admin/pages/users/index.astro +8 -0
- package/src/admin/styles/admin.css +166 -0
- package/src/core/access.ts +9 -0
- package/src/core/blocks/schema.ts +66 -0
- package/src/core/blueprints/code-to-definition.ts +156 -0
- package/src/core/blueprints/compile.ts +176 -0
- package/src/core/blueprints/define.ts +12 -0
- package/src/core/blueprints/definition.ts +185 -0
- package/src/core/blueprints/load.ts +144 -0
- package/src/core/blueprints/mutations.ts +236 -0
- package/src/core/blueprints/preview-path.ts +33 -0
- package/src/core/blueprints/reflect-fields.ts +305 -0
- package/src/core/blueprints/registry.ts +14 -0
- package/src/core/blueprints/seed.ts +20 -0
- package/src/core/blueprints/select-helpers.ts +30 -0
- package/src/core/blueprints/seo.ts +180 -0
- package/src/core/blueprints/types.ts +59 -0
- package/src/core/blueprints/zod-helpers.ts +86 -0
- package/src/core/db.ts +11 -0
- package/src/core/errors.ts +34 -0
- package/src/core/forms/compile.ts +84 -0
- package/src/core/forms/definition.ts +102 -0
- package/src/core/forms/rate-limit.ts +52 -0
- package/src/core/forms/unique.ts +38 -0
- package/src/core/globals/compile.ts +35 -0
- package/src/core/globals/definition.ts +27 -0
- package/src/core/locales.ts +45 -0
- package/src/core/migrations.ts +48 -0
- package/src/core/parse-content.ts +85 -0
- package/src/core/plugins/definition.ts +150 -0
- package/src/core/preview-content.ts +21 -0
- package/src/core/repos/entries.ts +504 -0
- package/src/core/repos/forms.ts +270 -0
- package/src/core/repos/globals.ts +179 -0
- package/src/core/repos/media.ts +106 -0
- package/src/core/repos/preview-sessions.ts +108 -0
- package/src/core/repos/revisions.ts +60 -0
- package/src/core/repos/settings.ts +23 -0
- package/src/core/schema.ts +244 -0
- package/src/core/sets/compile.ts +12 -0
- package/src/core/sets/definition.ts +10 -0
- package/src/core/sets/service.ts +82 -0
- package/src/core/sets/validate-tree.ts +57 -0
- package/src/core/sha256.ts +10 -0
- package/src/core/slug.ts +30 -0
- package/src/scaffold/collection-write.ts +83 -0
- package/src/scaffold/collection.ts +277 -0
- package/src/server/assets/live-preview-bridge.content.ts +2 -0
- package/src/server/assets/live-preview-bridge.js +535 -0
- package/src/server/better-auth.ts +82 -0
- package/src/server/cf-images.ts +34 -0
- package/src/server/cron.ts +37 -0
- package/src/server/email.ts +17 -0
- package/src/server/endpoints/api-auth.ts +10 -0
- package/src/server/endpoints/api-vulse-blueprints.ts +23 -0
- package/src/server/endpoints/api-vulse-entries-locales.ts +12 -0
- package/src/server/endpoints/api-vulse-entries-move.ts +7 -0
- package/src/server/endpoints/api-vulse-entries-publish.ts +7 -0
- package/src/server/endpoints/api-vulse-entries-tree.ts +7 -0
- package/src/server/endpoints/api-vulse-entries.ts +23 -0
- package/src/server/endpoints/api-vulse-form-handle.ts +30 -0
- package/src/server/endpoints/api-vulse-form-public.ts +7 -0
- package/src/server/endpoints/api-vulse-form-submit.ts +7 -0
- package/src/server/endpoints/api-vulse-form-upload.ts +7 -0
- package/src/server/endpoints/api-vulse-forms.ts +12 -0
- package/src/server/endpoints/api-vulse-globals-handle.ts +20 -0
- package/src/server/endpoints/api-vulse-globals-public-handle.ts +7 -0
- package/src/server/endpoints/api-vulse-globals-public.ts +7 -0
- package/src/server/endpoints/api-vulse-globals-value.ts +8 -0
- package/src/server/endpoints/api-vulse-globals.ts +12 -0
- package/src/server/endpoints/api-vulse-media-file.ts +7 -0
- package/src/server/endpoints/api-vulse-media-id.ts +12 -0
- package/src/server/endpoints/api-vulse-media.ts +12 -0
- package/src/server/endpoints/api-vulse-preview-bridge.ts +11 -0
- package/src/server/endpoints/api-vulse-preview-sessions-id.ts +10 -0
- package/src/server/endpoints/api-vulse-preview-sessions.ts +7 -0
- package/src/server/endpoints/api-vulse-preview-start.ts +7 -0
- package/src/server/endpoints/api-vulse-preview-stop.ts +7 -0
- package/src/server/endpoints/api-vulse-revisions-restore.ts +7 -0
- package/src/server/endpoints/api-vulse-revisions.ts +7 -0
- package/src/server/endpoints/api-vulse-search.ts +7 -0
- package/src/server/endpoints/api-vulse-sets.ts +23 -0
- package/src/server/endpoints/api-vulse-settings.ts +12 -0
- package/src/server/endpoints/api-vulse-users-id.ts +12 -0
- package/src/server/endpoints/api-vulse-users-reset-password.ts +7 -0
- package/src/server/endpoints/api-vulse-users-role.ts +9 -0
- package/src/server/endpoints/api-vulse-users.ts +7 -0
- package/src/server/endpoints/with-runtime.ts +11 -0
- package/src/server/env.ts +23 -0
- package/src/server/envelope.ts +21 -0
- package/src/server/forms/email.ts +11 -0
- package/src/server/forms/process-submission.ts +95 -0
- package/src/server/forms/queue.ts +25 -0
- package/src/server/forms/templates.ts +24 -0
- package/src/server/forms/webhook.ts +19 -0
- package/src/server/handler.ts +66 -0
- package/src/server/image-probe.ts +35 -0
- package/src/server/loader.ts +54 -0
- package/src/server/plugins.ts +214 -0
- package/src/server/preview.ts +25 -0
- package/src/server/r2.ts +13 -0
- package/src/server/routes/blueprints.ts +62 -0
- package/src/server/routes/entries.ts +255 -0
- package/src/server/routes/form-submit.ts +168 -0
- package/src/server/routes/form-upload.ts +100 -0
- package/src/server/routes/forms.ts +88 -0
- package/src/server/routes/globals-public.ts +30 -0
- package/src/server/routes/globals.ts +93 -0
- package/src/server/routes/media.ts +145 -0
- package/src/server/routes/preview-sessions.ts +76 -0
- package/src/server/routes/preview.ts +36 -0
- package/src/server/routes/revisions.ts +29 -0
- package/src/server/routes/search.ts +31 -0
- package/src/server/routes/sets.ts +40 -0
- package/src/server/routes/settings.ts +24 -0
- package/src/server/routes/users.ts +127 -0
- package/src/server/runtime.ts +99 -0
- package/src/server/sdk/collections.ts +98 -0
- package/src/server/sdk/index.ts +25 -0
- package/src/server/sdk/media.ts +11 -0
- package/src/server/sdk/search.ts +90 -0
|
@@ -0,0 +1,17 @@
|
|
|
1
|
+
export interface EmailEnv {
|
|
2
|
+
EMAIL_FROM?: string
|
|
3
|
+
EMAIL_API_TOKEN?: string
|
|
4
|
+
}
|
|
5
|
+
|
|
6
|
+
export async function sendEmail(
|
|
7
|
+
env: EmailEnv,
|
|
8
|
+
input: { to: string; subject: string; body: string },
|
|
9
|
+
): Promise<'sent' | 'logged'> {
|
|
10
|
+
if (!env.EMAIL_FROM || !env.EMAIL_API_TOKEN) {
|
|
11
|
+
console.log(`[vulse-email] to=${input.to} subject=${input.subject}\n${input.body}`)
|
|
12
|
+
return 'logged'
|
|
13
|
+
}
|
|
14
|
+
// Placeholder: real Email Workers integration documented in README.
|
|
15
|
+
console.log(`[vulse-email] to=${input.to} subject=${input.subject}`)
|
|
16
|
+
return 'sent'
|
|
17
|
+
}
|
|
@@ -0,0 +1,10 @@
|
|
|
1
|
+
import type { APIRoute } from 'astro'
|
|
2
|
+
import { withRuntime } from './with-runtime.js'
|
|
3
|
+
|
|
4
|
+
export const ALL: APIRoute = async ({ request }) => {
|
|
5
|
+
const rt = await withRuntime(request)
|
|
6
|
+
return rt.auth.handler(request)
|
|
7
|
+
}
|
|
8
|
+
|
|
9
|
+
export const GET = ALL
|
|
10
|
+
export const POST = ALL
|
|
@@ -0,0 +1,23 @@
|
|
|
1
|
+
import type { APIRoute } from 'astro'
|
|
2
|
+
import { withRuntime } from './with-runtime.js'
|
|
3
|
+
|
|
4
|
+
export const GET: APIRoute = async ({ params, request }) => {
|
|
5
|
+
const rt = await withRuntime(request)
|
|
6
|
+
if (params.handle) return rt.routes.blueprints.get(request, params as Record<string, string>)
|
|
7
|
+
return rt.routes.blueprints.list(request)
|
|
8
|
+
}
|
|
9
|
+
|
|
10
|
+
export const POST: APIRoute = async ({ request }) => {
|
|
11
|
+
const rt = await withRuntime(request)
|
|
12
|
+
return rt.routes.blueprints.create(request)
|
|
13
|
+
}
|
|
14
|
+
|
|
15
|
+
export const PATCH: APIRoute = async ({ params, request }) => {
|
|
16
|
+
const rt = await withRuntime(request)
|
|
17
|
+
return rt.routes.blueprints.update(request, params as Record<string, string>)
|
|
18
|
+
}
|
|
19
|
+
|
|
20
|
+
export const DELETE: APIRoute = async ({ params, request }) => {
|
|
21
|
+
const rt = await withRuntime(request)
|
|
22
|
+
return rt.routes.blueprints.delete(request, params as Record<string, string>)
|
|
23
|
+
}
|
|
@@ -0,0 +1,12 @@
|
|
|
1
|
+
import type { APIRoute } from 'astro'
|
|
2
|
+
import { withRuntime } from './with-runtime.js'
|
|
3
|
+
|
|
4
|
+
export const GET: APIRoute = async ({ params, request }) => {
|
|
5
|
+
const rt = await withRuntime(request)
|
|
6
|
+
return rt.routes.entries.listLocales(request, params as Record<string, string>)
|
|
7
|
+
}
|
|
8
|
+
|
|
9
|
+
export const POST: APIRoute = async ({ params, request }) => {
|
|
10
|
+
const rt = await withRuntime(request)
|
|
11
|
+
return rt.routes.entries.createLocale(request, params as Record<string, string>)
|
|
12
|
+
}
|
|
@@ -0,0 +1,7 @@
|
|
|
1
|
+
import type { APIRoute } from 'astro'
|
|
2
|
+
import { withRuntime } from './with-runtime.js'
|
|
3
|
+
|
|
4
|
+
export const PATCH: APIRoute = async ({ params, request }) => {
|
|
5
|
+
const rt = await withRuntime(request)
|
|
6
|
+
return rt.routes.entries.move(request, params as Record<string, string>)
|
|
7
|
+
}
|
|
@@ -0,0 +1,7 @@
|
|
|
1
|
+
import type { APIRoute } from 'astro'
|
|
2
|
+
import { withRuntime } from './with-runtime.js'
|
|
3
|
+
|
|
4
|
+
export const POST: APIRoute = async ({ params, request }) => {
|
|
5
|
+
const rt = await withRuntime(request)
|
|
6
|
+
return rt.routes.entries.publish(request, params as Record<string, string>)
|
|
7
|
+
}
|
|
@@ -0,0 +1,7 @@
|
|
|
1
|
+
import type { APIRoute } from 'astro'
|
|
2
|
+
import { withRuntime } from './with-runtime.js'
|
|
3
|
+
|
|
4
|
+
export const GET: APIRoute = async ({ params, request }) => {
|
|
5
|
+
const rt = await withRuntime(request)
|
|
6
|
+
return rt.routes.entries.tree(request, params as Record<string, string>)
|
|
7
|
+
}
|
|
@@ -0,0 +1,23 @@
|
|
|
1
|
+
import type { APIRoute } from 'astro'
|
|
2
|
+
import { withRuntime } from './with-runtime.js'
|
|
3
|
+
|
|
4
|
+
export const GET: APIRoute = async ({ params, request }) => {
|
|
5
|
+
const rt = await withRuntime(request)
|
|
6
|
+
if (params.id) return rt.routes.entries.findById(request, params as Record<string, string>)
|
|
7
|
+
return rt.routes.entries.list(request, params as Record<string, string>)
|
|
8
|
+
}
|
|
9
|
+
|
|
10
|
+
export const POST: APIRoute = async ({ params, request }) => {
|
|
11
|
+
const rt = await withRuntime(request)
|
|
12
|
+
return rt.routes.entries.create(request, params as Record<string, string>)
|
|
13
|
+
}
|
|
14
|
+
|
|
15
|
+
export const PUT: APIRoute = async ({ params, request }) => {
|
|
16
|
+
const rt = await withRuntime(request)
|
|
17
|
+
return rt.routes.entries.update(request, params as Record<string, string>)
|
|
18
|
+
}
|
|
19
|
+
|
|
20
|
+
export const DELETE: APIRoute = async ({ params, request }) => {
|
|
21
|
+
const rt = await withRuntime(request)
|
|
22
|
+
return rt.routes.entries.delete(request, params as Record<string, string>)
|
|
23
|
+
}
|
|
@@ -0,0 +1,30 @@
|
|
|
1
|
+
import type { APIRoute } from 'astro'
|
|
2
|
+
import { withRuntime } from './with-runtime.js'
|
|
3
|
+
|
|
4
|
+
export const GET: APIRoute = async ({ params, request }) => {
|
|
5
|
+
const rt = await withRuntime(request)
|
|
6
|
+
if (params.id) return rt.routes.forms.getSubmission(request, params as Record<string, string>)
|
|
7
|
+
if (params.handle && request.url.includes('/submissions')) {
|
|
8
|
+
return rt.routes.forms.listSubmissions(request, params as Record<string, string>)
|
|
9
|
+
}
|
|
10
|
+
return rt.routes.forms.get(request, params as Record<string, string>)
|
|
11
|
+
}
|
|
12
|
+
|
|
13
|
+
export const PUT: APIRoute = async ({ params, request }) => {
|
|
14
|
+
const rt = await withRuntime(request)
|
|
15
|
+
return rt.routes.forms.update(request, params as Record<string, string>)
|
|
16
|
+
}
|
|
17
|
+
|
|
18
|
+
export const DELETE: APIRoute = async ({ params, request }) => {
|
|
19
|
+
const rt = await withRuntime(request)
|
|
20
|
+
if (params.id) return rt.routes.forms.deleteSubmission(request, params as Record<string, string>)
|
|
21
|
+
return rt.routes.forms.delete(request, params as Record<string, string>)
|
|
22
|
+
}
|
|
23
|
+
|
|
24
|
+
export const POST: APIRoute = async ({ params, request }) => {
|
|
25
|
+
const rt = await withRuntime(request)
|
|
26
|
+
if (request.url.includes('/submissions/delete')) {
|
|
27
|
+
return rt.routes.forms.bulkDeleteSubmissions(request, params as Record<string, string>)
|
|
28
|
+
}
|
|
29
|
+
return new Response('Not found', { status: 404 })
|
|
30
|
+
}
|
|
@@ -0,0 +1,7 @@
|
|
|
1
|
+
import type { APIRoute } from 'astro'
|
|
2
|
+
import { withRuntime } from './with-runtime.js'
|
|
3
|
+
|
|
4
|
+
export const GET: APIRoute = async ({ params, request }) => {
|
|
5
|
+
const rt = await withRuntime(request)
|
|
6
|
+
return rt.routes.formSubmit.public(request, params as Record<string, string>)
|
|
7
|
+
}
|
|
@@ -0,0 +1,7 @@
|
|
|
1
|
+
import type { APIRoute } from 'astro'
|
|
2
|
+
import { withRuntime } from './with-runtime.js'
|
|
3
|
+
|
|
4
|
+
export const POST: APIRoute = async ({ params, request }) => {
|
|
5
|
+
const rt = await withRuntime(request)
|
|
6
|
+
return rt.routes.formSubmit.submit(request, params as Record<string, string>)
|
|
7
|
+
}
|
|
@@ -0,0 +1,7 @@
|
|
|
1
|
+
import type { APIRoute } from 'astro'
|
|
2
|
+
import { withRuntime } from './with-runtime.js'
|
|
3
|
+
|
|
4
|
+
export const POST: APIRoute = async ({ params, request }) => {
|
|
5
|
+
const rt = await withRuntime(request)
|
|
6
|
+
return rt.routes.formUpload.upload(request, params as Record<string, string>)
|
|
7
|
+
}
|
|
@@ -0,0 +1,12 @@
|
|
|
1
|
+
import type { APIRoute } from 'astro'
|
|
2
|
+
import { withRuntime } from './with-runtime.js'
|
|
3
|
+
|
|
4
|
+
export const GET: APIRoute = async ({ request }) => {
|
|
5
|
+
const rt = await withRuntime(request)
|
|
6
|
+
return rt.routes.forms.list(request)
|
|
7
|
+
}
|
|
8
|
+
|
|
9
|
+
export const POST: APIRoute = async ({ request }) => {
|
|
10
|
+
const rt = await withRuntime(request)
|
|
11
|
+
return rt.routes.forms.create(request)
|
|
12
|
+
}
|
|
@@ -0,0 +1,20 @@
|
|
|
1
|
+
import type { APIRoute } from 'astro'
|
|
2
|
+
import { withRuntime } from './with-runtime.js'
|
|
3
|
+
|
|
4
|
+
export const GET: APIRoute = async ({ params, request }) => {
|
|
5
|
+
const rt = await withRuntime(request)
|
|
6
|
+
if (!params.handle) return new Response('Not found', { status: 404 })
|
|
7
|
+
return rt.routes.globals.get(request, params as Record<string, string>)
|
|
8
|
+
}
|
|
9
|
+
|
|
10
|
+
export const PUT: APIRoute = async ({ params, request }) => {
|
|
11
|
+
const rt = await withRuntime(request)
|
|
12
|
+
if (!params.handle) return new Response('Not found', { status: 404 })
|
|
13
|
+
return rt.routes.globals.update(request, params as Record<string, string>)
|
|
14
|
+
}
|
|
15
|
+
|
|
16
|
+
export const DELETE: APIRoute = async ({ params, request }) => {
|
|
17
|
+
const rt = await withRuntime(request)
|
|
18
|
+
if (!params.handle) return new Response('Not found', { status: 404 })
|
|
19
|
+
return rt.routes.globals.delete(request, params as Record<string, string>)
|
|
20
|
+
}
|
|
@@ -0,0 +1,7 @@
|
|
|
1
|
+
import type { APIRoute } from 'astro'
|
|
2
|
+
import { withRuntime } from './with-runtime.js'
|
|
3
|
+
|
|
4
|
+
export const GET: APIRoute = async ({ params, request }) => {
|
|
5
|
+
const rt = await withRuntime(request)
|
|
6
|
+
return rt.routes.globalsPublic.get(request, params as Record<string, string>)
|
|
7
|
+
}
|
|
@@ -0,0 +1,8 @@
|
|
|
1
|
+
import type { APIRoute } from 'astro'
|
|
2
|
+
import { withRuntime } from './with-runtime.js'
|
|
3
|
+
|
|
4
|
+
export const PUT: APIRoute = async ({ params, request }) => {
|
|
5
|
+
const rt = await withRuntime(request)
|
|
6
|
+
if (!params.handle) return new Response('Not found', { status: 404 })
|
|
7
|
+
return rt.routes.globals.updateValue(request, params as Record<string, string>)
|
|
8
|
+
}
|
|
@@ -0,0 +1,12 @@
|
|
|
1
|
+
import type { APIRoute } from 'astro'
|
|
2
|
+
import { withRuntime } from './with-runtime.js'
|
|
3
|
+
|
|
4
|
+
export const GET: APIRoute = async ({ request }) => {
|
|
5
|
+
const rt = await withRuntime(request)
|
|
6
|
+
return rt.routes.globals.list(request)
|
|
7
|
+
}
|
|
8
|
+
|
|
9
|
+
export const POST: APIRoute = async ({ request }) => {
|
|
10
|
+
const rt = await withRuntime(request)
|
|
11
|
+
return rt.routes.globals.create(request)
|
|
12
|
+
}
|
|
@@ -0,0 +1,7 @@
|
|
|
1
|
+
import type { APIRoute } from 'astro'
|
|
2
|
+
import { withRuntime } from './with-runtime.js'
|
|
3
|
+
|
|
4
|
+
export const GET: APIRoute = async ({ params, request }) => {
|
|
5
|
+
const rt = await withRuntime(request)
|
|
6
|
+
return rt.routes.media.file(request, params as Record<string, string>)
|
|
7
|
+
}
|
|
@@ -0,0 +1,12 @@
|
|
|
1
|
+
import type { APIRoute } from 'astro'
|
|
2
|
+
import { withRuntime } from './with-runtime.js'
|
|
3
|
+
|
|
4
|
+
export const DELETE: APIRoute = async ({ params, request }) => {
|
|
5
|
+
const rt = await withRuntime(request)
|
|
6
|
+
return rt.routes.media.delete(request, params as Record<string, string>)
|
|
7
|
+
}
|
|
8
|
+
|
|
9
|
+
export const PATCH: APIRoute = async ({ params, request }) => {
|
|
10
|
+
const rt = await withRuntime(request)
|
|
11
|
+
return rt.routes.media.updateAlt(request, params as Record<string, string>)
|
|
12
|
+
}
|
|
@@ -0,0 +1,12 @@
|
|
|
1
|
+
import type { APIRoute } from 'astro'
|
|
2
|
+
import { withRuntime } from './with-runtime.js'
|
|
3
|
+
|
|
4
|
+
export const GET: APIRoute = async ({ request }) => {
|
|
5
|
+
const rt = await withRuntime(request)
|
|
6
|
+
return rt.routes.media.list(request)
|
|
7
|
+
}
|
|
8
|
+
|
|
9
|
+
export const POST: APIRoute = async ({ request }) => {
|
|
10
|
+
const rt = await withRuntime(request)
|
|
11
|
+
return rt.routes.media.upload(request)
|
|
12
|
+
}
|
|
@@ -0,0 +1,11 @@
|
|
|
1
|
+
import type { APIRoute } from 'astro'
|
|
2
|
+
import { livePreviewBridgeSource } from '../assets/live-preview-bridge.content.js'
|
|
3
|
+
|
|
4
|
+
export const GET: APIRoute = async () => {
|
|
5
|
+
return new Response(livePreviewBridgeSource, {
|
|
6
|
+
headers: {
|
|
7
|
+
'Content-Type': 'application/javascript; charset=utf-8',
|
|
8
|
+
'Cache-Control': 'public, max-age=3600',
|
|
9
|
+
},
|
|
10
|
+
})
|
|
11
|
+
}
|
|
@@ -0,0 +1,10 @@
|
|
|
1
|
+
import type { APIRoute } from 'astro'
|
|
2
|
+
import { withRuntime } from './with-runtime.js'
|
|
3
|
+
|
|
4
|
+
export const ALL: APIRoute = async ({ request, params }) => {
|
|
5
|
+
const rt = await withRuntime(request)
|
|
6
|
+
const id = params.id!
|
|
7
|
+
if (request.method === 'PUT') return rt.routes.previewSessions.update(request, { id })
|
|
8
|
+
if (request.method === 'DELETE') return rt.routes.previewSessions.remove(request, { id })
|
|
9
|
+
return new Response('Method Not Allowed', { status: 405 })
|
|
10
|
+
}
|
|
@@ -0,0 +1,7 @@
|
|
|
1
|
+
import type { APIRoute } from 'astro'
|
|
2
|
+
import { withRuntime } from './with-runtime.js'
|
|
3
|
+
|
|
4
|
+
export const POST: APIRoute = async ({ params, request }) => {
|
|
5
|
+
const rt = await withRuntime(request)
|
|
6
|
+
return rt.routes.revisions.restore(request, params as Record<string, string>)
|
|
7
|
+
}
|
|
@@ -0,0 +1,7 @@
|
|
|
1
|
+
import type { APIRoute } from 'astro'
|
|
2
|
+
import { withRuntime } from './with-runtime.js'
|
|
3
|
+
|
|
4
|
+
export const GET: APIRoute = async ({ params, request }) => {
|
|
5
|
+
const rt = await withRuntime(request)
|
|
6
|
+
return rt.routes.revisions.list(request, params as Record<string, string>)
|
|
7
|
+
}
|
|
@@ -0,0 +1,23 @@
|
|
|
1
|
+
import type { APIRoute } from 'astro'
|
|
2
|
+
import { withRuntime } from './with-runtime.js'
|
|
3
|
+
|
|
4
|
+
export const GET: APIRoute = async ({ params, request }) => {
|
|
5
|
+
const rt = await withRuntime(request)
|
|
6
|
+
if (params.handle) return rt.routes.sets.get(request, params as Record<string, string>)
|
|
7
|
+
return rt.routes.sets.list(request)
|
|
8
|
+
}
|
|
9
|
+
|
|
10
|
+
export const POST: APIRoute = async ({ request }) => {
|
|
11
|
+
const rt = await withRuntime(request)
|
|
12
|
+
return rt.routes.sets.create(request)
|
|
13
|
+
}
|
|
14
|
+
|
|
15
|
+
export const PATCH: APIRoute = async ({ params, request }) => {
|
|
16
|
+
const rt = await withRuntime(request)
|
|
17
|
+
return rt.routes.sets.update(request, params as Record<string, string>)
|
|
18
|
+
}
|
|
19
|
+
|
|
20
|
+
export const DELETE: APIRoute = async ({ params, request }) => {
|
|
21
|
+
const rt = await withRuntime(request)
|
|
22
|
+
return rt.routes.sets.delete(request, params as Record<string, string>)
|
|
23
|
+
}
|
|
@@ -0,0 +1,12 @@
|
|
|
1
|
+
import type { APIRoute } from 'astro'
|
|
2
|
+
import { withRuntime } from './with-runtime.js'
|
|
3
|
+
|
|
4
|
+
export const GET: APIRoute = async ({ request }) => {
|
|
5
|
+
const rt = await withRuntime(request)
|
|
6
|
+
return rt.routes.settings.list(request)
|
|
7
|
+
}
|
|
8
|
+
|
|
9
|
+
export const PUT: APIRoute = async ({ params, request }) => {
|
|
10
|
+
const rt = await withRuntime(request)
|
|
11
|
+
return rt.routes.settings.set(request, params as Record<string, string>)
|
|
12
|
+
}
|
|
@@ -0,0 +1,12 @@
|
|
|
1
|
+
import type { APIRoute } from 'astro'
|
|
2
|
+
import { withRuntime } from './with-runtime.js'
|
|
3
|
+
|
|
4
|
+
export const GET: APIRoute = async ({ params, request }) => {
|
|
5
|
+
const rt = await withRuntime(request)
|
|
6
|
+
return rt.routes.users.get(request, params as Record<string, string>)
|
|
7
|
+
}
|
|
8
|
+
|
|
9
|
+
export const PATCH: APIRoute = async ({ params, request }) => {
|
|
10
|
+
const rt = await withRuntime(request)
|
|
11
|
+
return rt.routes.users.update(request, params as Record<string, string>)
|
|
12
|
+
}
|
|
@@ -0,0 +1,7 @@
|
|
|
1
|
+
import type { APIRoute } from 'astro'
|
|
2
|
+
import { withRuntime } from './with-runtime.js'
|
|
3
|
+
|
|
4
|
+
export const POST: APIRoute = async ({ params, request }) => {
|
|
5
|
+
const rt = await withRuntime(request)
|
|
6
|
+
return rt.routes.users.resetPassword(request, params as Record<string, string>)
|
|
7
|
+
}
|
|
@@ -0,0 +1,9 @@
|
|
|
1
|
+
import type { APIRoute } from 'astro'
|
|
2
|
+
import { withRuntime } from './with-runtime.js'
|
|
3
|
+
|
|
4
|
+
export const POST: APIRoute = async ({ params, request }) => {
|
|
5
|
+
const rt = await withRuntime(request)
|
|
6
|
+
return rt.routes.users.setRole(request, params as Record<string, string>)
|
|
7
|
+
}
|
|
8
|
+
|
|
9
|
+
export const PUT: APIRoute = POST
|
|
@@ -0,0 +1,11 @@
|
|
|
1
|
+
import { getRuntimeEnv } from '../env.js'
|
|
2
|
+
import { createDb } from '../../core/db.js'
|
|
3
|
+
import { registryForRequest } from '../../core/blueprints/load.js'
|
|
4
|
+
import { getRuntime } from '../runtime.js'
|
|
5
|
+
|
|
6
|
+
export async function withRuntime(request: Request) {
|
|
7
|
+
const env = getRuntimeEnv()
|
|
8
|
+
const db = createDb(env.DB)
|
|
9
|
+
const registry = await registryForRequest(db)
|
|
10
|
+
return getRuntime(env, registry, new URL(request.url).origin)
|
|
11
|
+
}
|
|
@@ -0,0 +1,23 @@
|
|
|
1
|
+
import { env as cfEnv } from 'cloudflare:workers'
|
|
2
|
+
|
|
3
|
+
export interface RuntimeEnv {
|
|
4
|
+
DB: D1Database
|
|
5
|
+
BUCKET?: R2Bucket
|
|
6
|
+
FORM_QUEUE?: Queue
|
|
7
|
+
BETTER_AUTH_SECRET: string
|
|
8
|
+
BETTER_AUTH_URL?: string
|
|
9
|
+
VULSE_PREVIEW_SECRET?: string
|
|
10
|
+
/** When `"true"`, enables public sign-up (overrides DB setting). Useful for local playgrounds. */
|
|
11
|
+
VULSE_ALLOW_MEMBER_SIGNUP?: string
|
|
12
|
+
CF_IMAGES_ACCOUNT_HASH?: string
|
|
13
|
+
CF_IMAGES_TOKEN?: string
|
|
14
|
+
EMAIL_FROM?: string
|
|
15
|
+
EMAIL_API_TOKEN?: string
|
|
16
|
+
}
|
|
17
|
+
|
|
18
|
+
export function getRuntimeEnv(): RuntimeEnv {
|
|
19
|
+
const env = cfEnv as RuntimeEnv
|
|
20
|
+
if (!env.DB) throw new Error('Vulse: D1 binding "DB" is missing. Add it to wrangler.toml.')
|
|
21
|
+
if (!env.BETTER_AUTH_SECRET) throw new Error('Vulse: BETTER_AUTH_SECRET missing from wrangler.toml [vars].')
|
|
22
|
+
return env
|
|
23
|
+
}
|
|
@@ -0,0 +1,21 @@
|
|
|
1
|
+
import { VulseError } from '../core/errors.js'
|
|
2
|
+
|
|
3
|
+
export interface OkEnvelope<T> { ok: true; data: T }
|
|
4
|
+
export interface FailEnvelope { ok: false; error: { code: string; message: string; details?: unknown } }
|
|
5
|
+
|
|
6
|
+
export function ok<T>(data: T, init?: ResponseInit): Response {
|
|
7
|
+
return Response.json({ ok: true, data } satisfies OkEnvelope<T>, init)
|
|
8
|
+
}
|
|
9
|
+
|
|
10
|
+
export function fail(err: unknown): Response {
|
|
11
|
+
if (VulseError.isVulseError(err)) {
|
|
12
|
+
return Response.json({
|
|
13
|
+
ok: false,
|
|
14
|
+
error: { code: err.code, message: err.message, ...(err.details ? { details: err.details } : {}) },
|
|
15
|
+
} satisfies FailEnvelope, { status: err.status })
|
|
16
|
+
}
|
|
17
|
+
console.error('[vulse] internal error:', err)
|
|
18
|
+
return Response.json({
|
|
19
|
+
ok: false, error: { code: 'INTERNAL', message: 'Internal server error' },
|
|
20
|
+
} satisfies FailEnvelope, { status: 500 })
|
|
21
|
+
}
|
|
@@ -0,0 +1,11 @@
|
|
|
1
|
+
import { sendEmail, type EmailEnv } from '../email.js'
|
|
2
|
+
|
|
3
|
+
export type FormEmailEnv = EmailEnv
|
|
4
|
+
|
|
5
|
+
export async function sendFormEmail(
|
|
6
|
+
env: FormEmailEnv,
|
|
7
|
+
input: { to: string; subject: string; body: string },
|
|
8
|
+
): Promise<void> {
|
|
9
|
+
const result = await sendEmail(env, input)
|
|
10
|
+
if (result === 'logged') throw new Error('email_not_configured')
|
|
11
|
+
}
|
|
@@ -0,0 +1,95 @@
|
|
|
1
|
+
import { createDb } from '../../core/db.js'
|
|
2
|
+
import { FormsRepo, SubmissionsRepo } from '../../core/repos/forms.js'
|
|
3
|
+
import { renderTemplate } from './templates.js'
|
|
4
|
+
import { sendFormEmail } from './email.js'
|
|
5
|
+
import { sendFormWebhook } from './webhook.js'
|
|
6
|
+
import type { FormProcessMessage } from './queue.js'
|
|
7
|
+
import type { FormEmailEnv } from './email.js'
|
|
8
|
+
import { runFormAfterProcessHooks, runFormBeforeProcessHooks } from '../plugins.js'
|
|
9
|
+
|
|
10
|
+
export interface ProcessEnv extends FormEmailEnv {
|
|
11
|
+
DB: D1Database
|
|
12
|
+
}
|
|
13
|
+
|
|
14
|
+
export async function processSubmission(env: ProcessEnv, submissionId: string): Promise<void> {
|
|
15
|
+
const db = createDb(env.DB)
|
|
16
|
+
const forms = new FormsRepo(db)
|
|
17
|
+
const submissions = new SubmissionsRepo(db)
|
|
18
|
+
const submission = await submissions.findById(submissionId)
|
|
19
|
+
if (!submission) return
|
|
20
|
+
|
|
21
|
+
const formRow = await forms.findByHandle(submission.formHandle)
|
|
22
|
+
if (!formRow) {
|
|
23
|
+
await submissions.updateStatus(submissionId, 'failed', 'form_not_found')
|
|
24
|
+
return
|
|
25
|
+
}
|
|
26
|
+
|
|
27
|
+
const def = formRow.definition
|
|
28
|
+
const ctx = { form: def, submission, payload: submission.payload }
|
|
29
|
+
|
|
30
|
+
try {
|
|
31
|
+
await runFormBeforeProcessHooks(ctx, env as unknown as Record<string, unknown>)
|
|
32
|
+
|
|
33
|
+
const notifyEmails = def.settings.notifyEmails ?? []
|
|
34
|
+
for (const email of notifyEmails) {
|
|
35
|
+
const body = renderTemplate(
|
|
36
|
+
'New submission for {{form.label}}\n\n{{email}}',
|
|
37
|
+
ctx,
|
|
38
|
+
)
|
|
39
|
+
await sendFormEmail(env, { to: email, subject: `New ${def.label} submission`, body })
|
|
40
|
+
}
|
|
41
|
+
|
|
42
|
+
for (const action of def.actions) {
|
|
43
|
+
if (action.type === 'notify') {
|
|
44
|
+
for (const email of action.emails) {
|
|
45
|
+
const body = renderTemplate(action.template ?? 'New submission', ctx)
|
|
46
|
+
await sendFormEmail(env, { to: email, subject: `New ${def.label} submission`, body })
|
|
47
|
+
}
|
|
48
|
+
}
|
|
49
|
+
if (action.type === 'confirmation') {
|
|
50
|
+
const to = submission.payload[action.toField]
|
|
51
|
+
if (to && String(to).length > 0) {
|
|
52
|
+
await sendFormEmail(env, {
|
|
53
|
+
to: String(to),
|
|
54
|
+
subject: renderTemplate(action.subject, ctx),
|
|
55
|
+
body: renderTemplate(action.bodyTemplate, ctx),
|
|
56
|
+
})
|
|
57
|
+
}
|
|
58
|
+
}
|
|
59
|
+
if (action.type === 'webhook') {
|
|
60
|
+
await sendFormWebhook(action.url, { form: def, submission, payload: submission.payload }, action.headers ?? {})
|
|
61
|
+
}
|
|
62
|
+
}
|
|
63
|
+
|
|
64
|
+
const conf = def.settings.confirmationEmail
|
|
65
|
+
if (conf?.enabled && conf.toField) {
|
|
66
|
+
const to = submission.payload[conf.toField]
|
|
67
|
+
if (to && String(to).length > 0) {
|
|
68
|
+
await sendFormEmail(env, {
|
|
69
|
+
to: String(to),
|
|
70
|
+
subject: renderTemplate(conf.subject, ctx),
|
|
71
|
+
body: renderTemplate(conf.bodyTemplate, ctx),
|
|
72
|
+
})
|
|
73
|
+
}
|
|
74
|
+
}
|
|
75
|
+
|
|
76
|
+
await runFormAfterProcessHooks(ctx, env as unknown as Record<string, unknown>)
|
|
77
|
+
|
|
78
|
+
await submissions.updateStatus(submissionId, 'processed')
|
|
79
|
+
} catch (err) {
|
|
80
|
+
const message = err instanceof Error ? err.message : 'process_failed'
|
|
81
|
+
await submissions.updateStatus(submissionId, 'failed', message)
|
|
82
|
+
}
|
|
83
|
+
}
|
|
84
|
+
|
|
85
|
+
export async function vulseFormQueue(
|
|
86
|
+
batch: MessageBatch<FormProcessMessage>,
|
|
87
|
+
env: ProcessEnv,
|
|
88
|
+
): Promise<void> {
|
|
89
|
+
for (const msg of batch.messages) {
|
|
90
|
+
if (msg.body.type === 'process_submission') {
|
|
91
|
+
await processSubmission(env, msg.body.submissionId)
|
|
92
|
+
}
|
|
93
|
+
msg.ack()
|
|
94
|
+
}
|
|
95
|
+
}
|
|
@@ -0,0 +1,25 @@
|
|
|
1
|
+
export interface FormProcessMessage {
|
|
2
|
+
type: 'process_submission'
|
|
3
|
+
submissionId: string
|
|
4
|
+
}
|
|
5
|
+
|
|
6
|
+
const pending = new Set<string>()
|
|
7
|
+
|
|
8
|
+
export async function enqueueFormProcess(queue: Queue | undefined, submissionId: string): Promise<void> {
|
|
9
|
+
const msg: FormProcessMessage = { type: 'process_submission', submissionId }
|
|
10
|
+
if (queue) {
|
|
11
|
+
await queue.send(msg)
|
|
12
|
+
return
|
|
13
|
+
}
|
|
14
|
+
pending.add(submissionId)
|
|
15
|
+
}
|
|
16
|
+
|
|
17
|
+
export function drainPendingProcess(): string[] {
|
|
18
|
+
const ids = [...pending]
|
|
19
|
+
pending.clear()
|
|
20
|
+
return ids
|
|
21
|
+
}
|
|
22
|
+
|
|
23
|
+
export function __testResetPending(): void {
|
|
24
|
+
pending.clear()
|
|
25
|
+
}
|