@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
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"migrate.d.ts","sourceRoot":"","sources":["../../src/cli/migrate.ts"],"names":[],"mappings":"
|
|
1
|
+
{"version":3,"file":"migrate.d.ts","sourceRoot":"","sources":["../../src/cli/migrate.ts"],"names":[],"mappings":"AAGA,MAAM,WAAW,cAAc;IAAG,MAAM,CAAC,EAAE,OAAO,CAAA;CAAE;AAEpD,wBAAsB,UAAU,CAAC,IAAI,EAAE,cAAc,GAAG,OAAO,CAAC,IAAI,CAAC,CAMpE"}
|
package/dist/cli/migrate.js
CHANGED
|
@@ -1,10 +1,9 @@
|
|
|
1
|
-
import { join, dirname } from 'node:path';
|
|
2
|
-
import { fileURLToPath } from 'node:url';
|
|
3
1
|
import { execSync } from 'node:child_process';
|
|
4
|
-
|
|
2
|
+
import { ensureWranglerConfig } from '../integration/wrangler-config.js';
|
|
5
3
|
export async function runMigrate(opts) {
|
|
4
|
+
const file = await ensureWranglerConfig(process.cwd());
|
|
6
5
|
const flag = opts.remote ? '--remote' : '--local';
|
|
7
6
|
const cmd = `wrangler d1 migrations apply DB ${flag}`;
|
|
8
|
-
console.log(`> ${cmd}`);
|
|
7
|
+
console.log(`> ${cmd} (migrations: node_modules/@ekrist1/vulse/migrations via ${file})`);
|
|
9
8
|
execSync(cmd, { stdio: 'inherit' });
|
|
10
9
|
}
|
package/dist/cli/setup.d.ts.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"setup.d.ts","sourceRoot":"","sources":["../../src/cli/setup.ts"],"names":[],"mappings":"AAUA,MAAM,WAAW,YAAY;IAC3B,GAAG,CAAC,EAAE,OAAO,CAAA;IACb,KAAK,CAAC,EAAE,MAAM,CAAA;IACd,QAAQ,CAAC,EAAE,MAAM,CAAA;IACjB,WAAW,CAAC,EAAE,OAAO,CAAA;IACrB,QAAQ,CAAC,EAAE,OAAO,CAAA;IAClB,GAAG,CAAC,EAAE,MAAM,CAAA;CACb;AAiBD,6EAA6E;AAC7E,wBAAgB,cAAc,IAAI,MAAM,CAEvC;AAED;;;;GAIG;AACH,wBAAgB,aAAa,CAAC,IAAI,EAAE,MAAM,EAAE,EAAE,EAAE,MAAM,GAAG,MAAM,CAM9D;AAED;;;;;GAKG;AACH,wBAAgB,YAAY,CAAC,QAAQ,EAAE,MAAM,EAAE,IAAI,EAAE,MAAM,CAAC,MAAM,EAAE,MAAM,CAAC,GAAG,MAAM,CAgBnF;AAED,mEAAmE;AACnE,wBAAgB,gBAAgB,CAAC,QAAQ,EAAE,MAAM,EAAE,KAAK,SAAc,GAAG,MAAM,CAK9E;AAuCD,sEAAsE;AACtE,wBAAgB,eAAe,CAAC,MAAM,EAAE,MAAM,GAAG,MAAM,GAAG,IAAI,CAG7D;AAED,wBAAsB,QAAQ,CAAC,IAAI,GAAE,YAAiB,GAAG,OAAO,CAAC,IAAI,CAAC,
|
|
1
|
+
{"version":3,"file":"setup.d.ts","sourceRoot":"","sources":["../../src/cli/setup.ts"],"names":[],"mappings":"AAUA,MAAM,WAAW,YAAY;IAC3B,GAAG,CAAC,EAAE,OAAO,CAAA;IACb,KAAK,CAAC,EAAE,MAAM,CAAA;IACd,QAAQ,CAAC,EAAE,MAAM,CAAA;IACjB,WAAW,CAAC,EAAE,OAAO,CAAA;IACrB,QAAQ,CAAC,EAAE,OAAO,CAAA;IAClB,GAAG,CAAC,EAAE,MAAM,CAAA;CACb;AAiBD,6EAA6E;AAC7E,wBAAgB,cAAc,IAAI,MAAM,CAEvC;AAED;;;;GAIG;AACH,wBAAgB,aAAa,CAAC,IAAI,EAAE,MAAM,EAAE,EAAE,EAAE,MAAM,GAAG,MAAM,CAM9D;AAED;;;;;GAKG;AACH,wBAAgB,YAAY,CAAC,QAAQ,EAAE,MAAM,EAAE,IAAI,EAAE,MAAM,CAAC,MAAM,EAAE,MAAM,CAAC,GAAG,MAAM,CAgBnF;AAED,mEAAmE;AACnE,wBAAgB,gBAAgB,CAAC,QAAQ,EAAE,MAAM,EAAE,KAAK,SAAc,GAAG,MAAM,CAK9E;AAuCD,sEAAsE;AACtE,wBAAgB,eAAe,CAAC,MAAM,EAAE,MAAM,GAAG,MAAM,GAAG,IAAI,CAG7D;AAED,wBAAsB,QAAQ,CAAC,IAAI,GAAE,YAAiB,GAAG,OAAO,CAAC,IAAI,CAAC,CAuJrE"}
|
package/dist/cli/setup.js
CHANGED
|
@@ -4,7 +4,7 @@ import { randomBytes } from 'node:crypto';
|
|
|
4
4
|
import { execSync } from 'node:child_process';
|
|
5
5
|
import { createInterface } from 'node:readline/promises';
|
|
6
6
|
import { stdin, stdout } from 'node:process';
|
|
7
|
-
import {
|
|
7
|
+
import { patchWranglerConfig, findWranglerConfig } from '../integration/wrangler-config.js';
|
|
8
8
|
import { runMigrate } from './migrate.js';
|
|
9
9
|
import { runSeedAdmin } from './seed-admin.js';
|
|
10
10
|
const DEV_VARS_FILE = '.dev.vars';
|
|
@@ -117,7 +117,7 @@ export async function runSetup(opts = {}) {
|
|
|
117
117
|
try {
|
|
118
118
|
stdout.write(`\nVulse setup — local development\n\n`);
|
|
119
119
|
stdout.write(`This wizard will update:\n`);
|
|
120
|
-
stdout.write(` •
|
|
120
|
+
stdout.write(` • wrangler config (D1 + R2 bindings)\n`);
|
|
121
121
|
stdout.write(` • ${DEV_VARS_FILE} (local secrets — gitignored)\n`);
|
|
122
122
|
stdout.write(` • ${GITIGNORE_FILE} (adds ${DEV_VARS_FILE})\n\n`);
|
|
123
123
|
if (!(await prompter.confirm('Continue?', true))) {
|
|
@@ -126,10 +126,11 @@ export async function runSetup(opts = {}) {
|
|
|
126
126
|
}
|
|
127
127
|
// --- Step 1: D1 ---
|
|
128
128
|
stdout.write(`\nStep 1/3 — Cloudflare D1 (database)\n`);
|
|
129
|
-
const
|
|
130
|
-
|
|
129
|
+
const wranglerFile = (await findWranglerConfig(cwd)) ?? WRANGLER_FILE;
|
|
130
|
+
const wranglerPath = join(cwd, wranglerFile);
|
|
131
|
+
let wranglerConfig = await readIfExists(wranglerPath);
|
|
131
132
|
const d1Name = await prompter.ask(' D1 database name', 'vulse-db');
|
|
132
|
-
|
|
133
|
+
wranglerConfig = patchWranglerConfig(wranglerConfig, wranglerFile, { d1Name, r2Bucket: 'vulse-media' });
|
|
133
134
|
let databaseId = await prompter.ask(' D1 database_id (leave blank to create one now)', '');
|
|
134
135
|
if (!databaseId) {
|
|
135
136
|
if (await prompter.confirm(` Run \`wrangler d1 create ${d1Name}\`?`, true)) {
|
|
@@ -152,11 +153,11 @@ export async function runSetup(opts = {}) {
|
|
|
152
153
|
}
|
|
153
154
|
}
|
|
154
155
|
if (databaseId)
|
|
155
|
-
|
|
156
|
+
wranglerConfig = setDatabaseId(wranglerConfig, databaseId);
|
|
156
157
|
// --- Step 2: R2 ---
|
|
157
158
|
stdout.write(`\nStep 2/3 — Cloudflare R2 (media storage)\n`);
|
|
158
159
|
const r2Bucket = await prompter.ask(' R2 bucket name', 'vulse-media');
|
|
159
|
-
|
|
160
|
+
wranglerConfig = patchWranglerConfig(wranglerConfig, wranglerFile, { d1Name, r2Bucket });
|
|
160
161
|
if (await prompter.confirm(` Run \`wrangler r2 bucket create ${r2Bucket}\`?`, true)) {
|
|
161
162
|
const result = tryRun(`wrangler r2 bucket create ${r2Bucket}`);
|
|
162
163
|
if (result.ok) {
|
|
@@ -170,8 +171,8 @@ export async function runSetup(opts = {}) {
|
|
|
170
171
|
stdout.write(` Continuing — you can create it later.\n`);
|
|
171
172
|
}
|
|
172
173
|
}
|
|
173
|
-
await writeFile(wranglerPath,
|
|
174
|
-
stdout.write(` ✓ wrote ${
|
|
174
|
+
await writeFile(wranglerPath, wranglerConfig, 'utf8');
|
|
175
|
+
stdout.write(` ✓ wrote ${wranglerFile}\n`);
|
|
175
176
|
// --- Step 3: Secrets + .dev.vars ---
|
|
176
177
|
stdout.write(`\nStep 3/3 — Secrets\n`);
|
|
177
178
|
const devVarsPath = join(cwd, DEV_VARS_FILE);
|
|
@@ -198,7 +199,7 @@ export async function runSetup(opts = {}) {
|
|
|
198
199
|
}
|
|
199
200
|
// Warn if wrangler.toml still has the placeholder BETTER_AUTH_SECRET — .dev.vars
|
|
200
201
|
// overrides it in dev, but the placeholder is misleading.
|
|
201
|
-
if (
|
|
202
|
+
if (wranglerConfig.includes(PLACEHOLDER_AUTH_SECRET)) {
|
|
202
203
|
stdout.write(` ℹ ${WRANGLER_FILE} still contains the placeholder BETTER_AUTH_SECRET in [vars].\n` +
|
|
203
204
|
` ${DEV_VARS_FILE} takes precedence in dev — you can remove the [vars] line.\n`);
|
|
204
205
|
}
|
|
@@ -6,5 +6,5 @@ export interface CompileBlueprintOptions {
|
|
|
6
6
|
}
|
|
7
7
|
export declare function compileBlueprintSchema(def: BlueprintDefinition, options?: CompileBlueprintOptions): z.ZodObject<z.ZodRawShape>;
|
|
8
8
|
export declare function compileFieldObject(fields: NestedFieldDefinition[]): z.ZodObject<z.ZodRawShape>;
|
|
9
|
-
export declare function hashDefinition(def: BlueprintDefinition): string
|
|
9
|
+
export declare function hashDefinition(def: BlueprintDefinition): Promise<string>;
|
|
10
10
|
//# sourceMappingURL=compile.d.ts.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"compile.d.ts","sourceRoot":"","sources":["../../../src/core/blueprints/compile.ts"],"names":[],"mappings":"
|
|
1
|
+
{"version":3,"file":"compile.d.ts","sourceRoot":"","sources":["../../../src/core/blueprints/compile.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,CAAC,EAAE,MAAM,WAAW,CAAA;AAE7B,OAAO,KAAK,EAAE,WAAW,EAAE,MAAM,oBAAoB,CAAA;AAErD,OAAO,KAAK,EACV,mBAAmB,EAEnB,qBAAqB,EAEtB,MAAM,iBAAiB,CAAA;AAKxB,MAAM,WAAW,uBAAuB;IACtC,IAAI,CAAC,EAAE,GAAG,CAAC,MAAM,EAAE,WAAW,CAAC,CAAA;CAChC;AAED,wBAAgB,sBAAsB,CACpC,GAAG,EAAE,mBAAmB,EACxB,OAAO,GAAE,uBAA4B,GACpC,CAAC,CAAC,SAAS,CAAC,CAAC,CAAC,WAAW,CAAC,CAS5B;AAqHD,wBAAgB,kBAAkB,CAAC,MAAM,EAAE,qBAAqB,EAAE,GAAG,CAAC,CAAC,SAAS,CAAC,CAAC,CAAC,WAAW,CAAC,CAM9F;AAED,wBAAsB,cAAc,CAAC,GAAG,EAAE,mBAAmB,GAAG,OAAO,CAAC,MAAM,CAAC,CAoB9E"}
|
|
@@ -1,5 +1,5 @@
|
|
|
1
|
-
import { createHash } from 'node:crypto';
|
|
2
1
|
import { z } from 'astro/zod';
|
|
2
|
+
import { sha256Hex } from '../sha256.js';
|
|
3
3
|
import { validateSetNodes } from '../sets/validate-tree.js';
|
|
4
4
|
import { LinkValueSchema } from './definition.js';
|
|
5
5
|
import { seoZodSchema } from './seo.js';
|
|
@@ -130,7 +130,7 @@ export function compileFieldObject(fields) {
|
|
|
130
130
|
}
|
|
131
131
|
return z.object(shape);
|
|
132
132
|
}
|
|
133
|
-
export function hashDefinition(def) {
|
|
133
|
+
export async function hashDefinition(def) {
|
|
134
134
|
const canonical = JSON.stringify({
|
|
135
135
|
handle: def.handle,
|
|
136
136
|
label: def.label,
|
|
@@ -149,5 +149,5 @@ export function hashDefinition(def) {
|
|
|
149
149
|
validation: f.validation ?? null,
|
|
150
150
|
})),
|
|
151
151
|
});
|
|
152
|
-
return
|
|
152
|
+
return sha256Hex(canonical);
|
|
153
153
|
}
|
|
@@ -10,7 +10,7 @@ export async function createBlueprint(db, input) {
|
|
|
10
10
|
handle: def.handle,
|
|
11
11
|
label: def.label,
|
|
12
12
|
definition: def,
|
|
13
|
-
blueprintHash: hashDefinition(def),
|
|
13
|
+
blueprintHash: await hashDefinition(def),
|
|
14
14
|
singleton: def.singleton,
|
|
15
15
|
tree: def.tree === true,
|
|
16
16
|
drafts: def.drafts === true,
|
|
@@ -64,7 +64,7 @@ export async function updateBlueprint(db, handle, input) {
|
|
|
64
64
|
await db.update(vulseCollections).set({
|
|
65
65
|
label: canonical.label,
|
|
66
66
|
definition: canonical,
|
|
67
|
-
blueprintHash: hashDefinition(canonical),
|
|
67
|
+
blueprintHash: await hashDefinition(canonical),
|
|
68
68
|
singleton: canonical.singleton,
|
|
69
69
|
tree: canonical.tree === true,
|
|
70
70
|
drafts: canonical.drafts === true,
|
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
import type { VulseDb } from '../db.js';
|
|
2
|
-
export declare function hashIp(ip: string): string
|
|
2
|
+
export declare function hashIp(ip: string): Promise<string>;
|
|
3
3
|
export declare function checkRateLimit(db: VulseDb, formHandle: string, ipHash: string, opts?: {
|
|
4
4
|
maxPerIp: number;
|
|
5
5
|
windowSec: number;
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"rate-limit.d.ts","sourceRoot":"","sources":["../../../src/core/forms/rate-limit.ts"],"names":[],"mappings":"AAEA,OAAO,KAAK,EAAE,OAAO,EAAE,MAAM,UAAU,CAAA;AAGvC,
|
|
1
|
+
{"version":3,"file":"rate-limit.d.ts","sourceRoot":"","sources":["../../../src/core/forms/rate-limit.ts"],"names":[],"mappings":"AAEA,OAAO,KAAK,EAAE,OAAO,EAAE,MAAM,UAAU,CAAA;AAGvC,wBAAsB,MAAM,CAAC,EAAE,EAAE,MAAM,GAAG,OAAO,CAAC,MAAM,CAAC,CAExD;AAED,wBAAsB,cAAc,CAClC,EAAE,EAAE,OAAO,EACX,UAAU,EAAE,MAAM,EAClB,MAAM,EAAE,MAAM,EACd,IAAI,GAAE;IAAE,QAAQ,EAAE,MAAM,CAAC;IAAC,SAAS,EAAE,MAAM,CAAA;CAAsC,GAChF,OAAO,CAAC;IAAE,OAAO,EAAE,OAAO,CAAC;IAAC,aAAa,CAAC,EAAE,MAAM,CAAA;CAAE,CAAC,CAqCvD"}
|
|
@@ -1,8 +1,8 @@
|
|
|
1
|
-
import {
|
|
1
|
+
import { sha256Hex } from '../sha256.js';
|
|
2
2
|
import { eq, and, lt } from 'drizzle-orm';
|
|
3
3
|
import { vulseFormRateLimits } from '../schema.js';
|
|
4
|
-
export function hashIp(ip) {
|
|
5
|
-
return
|
|
4
|
+
export async function hashIp(ip) {
|
|
5
|
+
return sha256Hex(ip);
|
|
6
6
|
}
|
|
7
7
|
export async function checkRateLimit(db, formHandle, ipHash, opts = { maxPerIp: 10, windowSec: 3600 }) {
|
|
8
8
|
const windowMs = opts.windowSec * 1000;
|
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
import type { VulseDb } from '../db.js';
|
|
2
2
|
export declare function normalizeUniqueValue(value: unknown): string;
|
|
3
|
-
export declare function hashUniqueValue(value: unknown): string
|
|
3
|
+
export declare function hashUniqueValue(value: unknown): Promise<string>;
|
|
4
4
|
export declare function insertUniqueValues(db: VulseDb, formHandle: string, submissionId: string, fields: Record<string, unknown>, uniqueFieldNames: string[]): Promise<void>;
|
|
5
5
|
//# sourceMappingURL=unique.d.ts.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"unique.d.ts","sourceRoot":"","sources":["../../../src/core/forms/unique.ts"],"names":[],"mappings":"AACA,OAAO,KAAK,EAAE,OAAO,EAAE,MAAM,UAAU,CAAA;AAIvC,wBAAgB,oBAAoB,CAAC,KAAK,EAAE,OAAO,GAAG,MAAM,CAE3D;AAED,
|
|
1
|
+
{"version":3,"file":"unique.d.ts","sourceRoot":"","sources":["../../../src/core/forms/unique.ts"],"names":[],"mappings":"AACA,OAAO,KAAK,EAAE,OAAO,EAAE,MAAM,UAAU,CAAA;AAIvC,wBAAgB,oBAAoB,CAAC,KAAK,EAAE,OAAO,GAAG,MAAM,CAE3D;AAED,wBAAsB,eAAe,CAAC,KAAK,EAAE,OAAO,GAAG,OAAO,CAAC,MAAM,CAAC,CAErE;AAED,wBAAsB,kBAAkB,CACtC,EAAE,EAAE,OAAO,EACX,UAAU,EAAE,MAAM,EAClB,YAAY,EAAE,MAAM,EACpB,MAAM,EAAE,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,EAC/B,gBAAgB,EAAE,MAAM,EAAE,GACzB,OAAO,CAAC,IAAI,CAAC,CAkBf"}
|
|
@@ -1,11 +1,11 @@
|
|
|
1
|
-
import {
|
|
1
|
+
import { sha256Hex } from '../sha256.js';
|
|
2
2
|
import { vulseFormUniqueValues } from '../schema.js';
|
|
3
3
|
import { ConflictError } from '../errors.js';
|
|
4
4
|
export function normalizeUniqueValue(value) {
|
|
5
5
|
return String(value).trim().toLowerCase();
|
|
6
6
|
}
|
|
7
|
-
export function hashUniqueValue(value) {
|
|
8
|
-
return
|
|
7
|
+
export async function hashUniqueValue(value) {
|
|
8
|
+
return sha256Hex(normalizeUniqueValue(value));
|
|
9
9
|
}
|
|
10
10
|
export async function insertUniqueValues(db, formHandle, submissionId, fields, uniqueFieldNames) {
|
|
11
11
|
const now = new Date();
|
|
@@ -13,7 +13,7 @@ export async function insertUniqueValues(db, formHandle, submissionId, fields, u
|
|
|
13
13
|
const value = fields[name];
|
|
14
14
|
if (value === undefined || value === null || value === '')
|
|
15
15
|
continue;
|
|
16
|
-
const valueHash = hashUniqueValue(value);
|
|
16
|
+
const valueHash = await hashUniqueValue(value);
|
|
17
17
|
try {
|
|
18
18
|
await db.insert(vulseFormUniqueValues).values({
|
|
19
19
|
formHandle,
|
|
@@ -9,5 +9,5 @@ export interface CompiledGlobalSet {
|
|
|
9
9
|
schema: z.ZodObject<z.ZodRawShape>;
|
|
10
10
|
hash: string;
|
|
11
11
|
}
|
|
12
|
-
export declare function compileGlobalSet(def: GlobalSetDefinition, sets?: Map<string, CompiledSet>): CompiledGlobalSet
|
|
12
|
+
export declare function compileGlobalSet(def: GlobalSetDefinition, sets?: Map<string, CompiledSet>): Promise<CompiledGlobalSet>;
|
|
13
13
|
//# sourceMappingURL=compile.d.ts.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"compile.d.ts","sourceRoot":"","sources":["../../../src/core/globals/compile.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,CAAC,EAAE,MAAM,WAAW,CAAA;AAElC,OAAO,KAAK,EAAE,WAAW,EAAE,MAAM,oBAAoB,CAAA;AACrD,OAAO,KAAK,EAAE,eAAe,EAAE,MAAM,6BAA6B,CAAA;AAClE,OAAO,EAAE,KAAK,mBAAmB,EAA2B,MAAM,iBAAiB,CAAA;AAEnF,MAAM,WAAW,iBAAiB;IAChC,MAAM,EAAE,MAAM,CAAA;IACd,KAAK,EAAE,MAAM,CAAA;IACb,MAAM,EAAE,eAAe,EAAE,CAAA;IACzB,MAAM,EAAE,CAAC,CAAC,SAAS,CAAC,CAAC,CAAC,WAAW,CAAC,CAAA;IAClC,IAAI,EAAE,MAAM,CAAA;CACb;AAED,
|
|
1
|
+
{"version":3,"file":"compile.d.ts","sourceRoot":"","sources":["../../../src/core/globals/compile.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,CAAC,EAAE,MAAM,WAAW,CAAA;AAElC,OAAO,KAAK,EAAE,WAAW,EAAE,MAAM,oBAAoB,CAAA;AACrD,OAAO,KAAK,EAAE,eAAe,EAAE,MAAM,6BAA6B,CAAA;AAClE,OAAO,EAAE,KAAK,mBAAmB,EAA2B,MAAM,iBAAiB,CAAA;AAEnF,MAAM,WAAW,iBAAiB;IAChC,MAAM,EAAE,MAAM,CAAA;IACd,KAAK,EAAE,MAAM,CAAA;IACb,MAAM,EAAE,eAAe,EAAE,CAAA;IACzB,MAAM,EAAE,CAAC,CAAC,SAAS,CAAC,CAAC,CAAC,WAAW,CAAC,CAAA;IAClC,IAAI,EAAE,MAAM,CAAA;CACb;AAED,wBAAsB,gBAAgB,CACpC,GAAG,EAAE,mBAAmB,EACxB,IAAI,CAAC,EAAE,GAAG,CAAC,MAAM,EAAE,WAAW,CAAC,GAC9B,OAAO,CAAC,iBAAiB,CAAC,CAiB5B"}
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
import { compileBlueprintSchema } from '../blueprints/compile.js';
|
|
2
2
|
import { hashGlobalSetDefinition } from './definition.js';
|
|
3
|
-
export function compileGlobalSet(def, sets) {
|
|
3
|
+
export async function compileGlobalSet(def, sets) {
|
|
4
4
|
const options = sets ? { sets } : {};
|
|
5
5
|
return {
|
|
6
6
|
handle: def.handle,
|
|
@@ -12,6 +12,6 @@ export function compileGlobalSet(def, sets) {
|
|
|
12
12
|
singleton: true,
|
|
13
13
|
fields: def.fields,
|
|
14
14
|
}, options),
|
|
15
|
-
hash: hashGlobalSetDefinition(def),
|
|
15
|
+
hash: await hashGlobalSetDefinition(def),
|
|
16
16
|
};
|
|
17
17
|
}
|
|
@@ -157,5 +157,5 @@ export declare const GlobalSetDefinitionSchema: z.ZodObject<{
|
|
|
157
157
|
}, z.core.$strip>>>;
|
|
158
158
|
}, z.core.$strip>;
|
|
159
159
|
export type GlobalSetDefinition = z.infer<typeof GlobalSetDefinitionSchema>;
|
|
160
|
-
export declare function hashGlobalSetDefinition(def: GlobalSetDefinition): string
|
|
160
|
+
export declare function hashGlobalSetDefinition(def: GlobalSetDefinition): Promise<string>;
|
|
161
161
|
//# sourceMappingURL=definition.d.ts.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"definition.d.ts","sourceRoot":"","sources":["../../../src/core/globals/definition.ts"],"names":[],"mappings":"
|
|
1
|
+
{"version":3,"file":"definition.d.ts","sourceRoot":"","sources":["../../../src/core/globals/definition.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,CAAC,EAAE,MAAM,WAAW,CAAA;AAI7B,eAAO,MAAM,yBAAyB;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;iBAIpC,CAAA;AAEF,MAAM,MAAM,mBAAmB,GAAG,CAAC,CAAC,KAAK,CAAC,OAAO,yBAAyB,CAAC,CAAA;AAE3E,wBAAsB,uBAAuB,CAAC,GAAG,EAAE,mBAAmB,GAAG,OAAO,CAAC,MAAM,CAAC,CAcvF"}
|
|
@@ -1,12 +1,12 @@
|
|
|
1
|
-
import { createHash } from 'node:crypto';
|
|
2
1
|
import { z } from 'astro/zod';
|
|
2
|
+
import { sha256Hex } from '../sha256.js';
|
|
3
3
|
import { FieldDefinitionSchema } from '../blueprints/definition.js';
|
|
4
4
|
export const GlobalSetDefinitionSchema = z.object({
|
|
5
5
|
handle: z.string().regex(/^[a-z][a-z0-9_-]*$/),
|
|
6
6
|
label: z.string().min(1),
|
|
7
7
|
fields: z.array(FieldDefinitionSchema).default([]),
|
|
8
8
|
});
|
|
9
|
-
export function hashGlobalSetDefinition(def) {
|
|
9
|
+
export async function hashGlobalSetDefinition(def) {
|
|
10
10
|
const canonical = JSON.stringify({
|
|
11
11
|
handle: def.handle,
|
|
12
12
|
label: def.label,
|
|
@@ -19,5 +19,5 @@ export function hashGlobalSetDefinition(def) {
|
|
|
19
19
|
validation: f.validation ?? null,
|
|
20
20
|
})),
|
|
21
21
|
});
|
|
22
|
-
return
|
|
22
|
+
return sha256Hex(canonical);
|
|
23
23
|
}
|
|
@@ -44,7 +44,7 @@ export class GlobalsRepo {
|
|
|
44
44
|
if (existing)
|
|
45
45
|
throw new ConflictError(`global set already exists: ${def.handle}`);
|
|
46
46
|
const now = new Date();
|
|
47
|
-
const hash = hashGlobalSetDefinition(def);
|
|
47
|
+
const hash = await hashGlobalSetDefinition(def);
|
|
48
48
|
await this.db.insert(vulseGlobalSets).values({
|
|
49
49
|
handle: def.handle,
|
|
50
50
|
label: def.label,
|
|
@@ -78,7 +78,7 @@ export class GlobalsRepo {
|
|
|
78
78
|
await this.db.update(vulseGlobalSets).set({
|
|
79
79
|
label: def.label,
|
|
80
80
|
definition: def,
|
|
81
|
-
blueprintHash: hashGlobalSetDefinition(def),
|
|
81
|
+
blueprintHash: await hashGlobalSetDefinition(def),
|
|
82
82
|
updatedAt: new Date(),
|
|
83
83
|
}).where(eq(vulseGlobalSets.handle, handle));
|
|
84
84
|
const row = await this.findSetByHandle(handle);
|
|
@@ -104,7 +104,7 @@ export class GlobalsRepo {
|
|
|
104
104
|
if (!set)
|
|
105
105
|
throw new NotFoundError('global set not found');
|
|
106
106
|
const sets = await loadCompiledSets(this.db);
|
|
107
|
-
const compiled = compileGlobalSet(set.definition, sets);
|
|
107
|
+
const compiled = await compileGlobalSet(set.definition, sets);
|
|
108
108
|
const result = compiled.schema.safeParse(input);
|
|
109
109
|
if (!result.success) {
|
|
110
110
|
throw new ValidationError('Invalid global value', { issues: result.error.issues });
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"sha256.d.ts","sourceRoot":"","sources":["../../src/core/sha256.ts"],"names":[],"mappings":"AAIA,wDAAwD;AACxD,wBAAsB,SAAS,CAAC,KAAK,EAAE,MAAM,GAAG,OAAO,CAAC,MAAM,CAAC,CAI9D"}
|
|
@@ -0,0 +1,9 @@
|
|
|
1
|
+
function bytesToHex(bytes) {
|
|
2
|
+
return Array.from(bytes, (byte) => byte.toString(16).padStart(2, '0')).join('');
|
|
3
|
+
}
|
|
4
|
+
/** Workers-safe SHA-256 hex digest (no node:crypto). */
|
|
5
|
+
export async function sha256Hex(input) {
|
|
6
|
+
const data = new TextEncoder().encode(input);
|
|
7
|
+
const hash = await crypto.subtle.digest('SHA-256', data);
|
|
8
|
+
return bytesToHex(new Uint8Array(hash));
|
|
9
|
+
}
|
|
@@ -50,7 +50,7 @@ export default function vulse(opts = {}) {
|
|
|
50
50
|
ssr: {
|
|
51
51
|
// Bundle vulse in-process for Cloudflare's module runner; avoid
|
|
52
52
|
// noExternal: true — it pulls native dev deps (tailwind oxide, babel) into SSR.
|
|
53
|
-
noExternal: ['@ekrist1/vulse'],
|
|
53
|
+
noExternal: ['@ekrist1/vulse', '@astrojs/vue'],
|
|
54
54
|
optimizeDeps: {
|
|
55
55
|
exclude: [...OPTIMIZE_DEPS_EXCLUDE],
|
|
56
56
|
},
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"install-hook.d.ts","sourceRoot":"","sources":["../../src/integration/install-hook.ts"],"names":[],"mappings":"AAsCA,wBAAsB,cAAc,CAAC,GAAG,EAAE,MAAM,GAAG,OAAO,CAAC,IAAI,CAAC,
|
|
1
|
+
{"version":3,"file":"install-hook.d.ts","sourceRoot":"","sources":["../../src/integration/install-hook.ts"],"names":[],"mappings":"AAsCA,wBAAsB,cAAc,CAAC,GAAG,EAAE,MAAM,GAAG,OAAO,CAAC,IAAI,CAAC,CAqC/D"}
|
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
import { readFile, writeFile, mkdir, access } from 'node:fs/promises';
|
|
2
2
|
import { join } from 'node:path';
|
|
3
3
|
import { VULSE_PACKAGE } from '../package-name.js';
|
|
4
|
-
import {
|
|
4
|
+
import { ensureWranglerConfig, patchWranglerConfig, findWranglerConfig } from './wrangler-config.js';
|
|
5
5
|
const STARTER_BLUEPRINT = `import { defineCollection, z } from '${VULSE_PACKAGE}'
|
|
6
6
|
|
|
7
7
|
export default defineCollection({
|
|
@@ -39,9 +39,10 @@ async function fileExists(path) {
|
|
|
39
39
|
}
|
|
40
40
|
}
|
|
41
41
|
export async function runInstallHook(cwd) {
|
|
42
|
-
const
|
|
42
|
+
const wranglerFile = await findWranglerConfig(cwd);
|
|
43
|
+
const wranglerPath = join(cwd, wranglerFile ?? 'wrangler.toml');
|
|
43
44
|
const existing = (await fileExists(wranglerPath)) ? await readFile(wranglerPath, 'utf8') : '';
|
|
44
|
-
const patched =
|
|
45
|
+
const patched = patchWranglerConfig(existing, wranglerFile ?? 'wrangler.toml', { d1Name: 'vulse-db', r2Bucket: 'vulse-media' });
|
|
45
46
|
if (patched !== existing)
|
|
46
47
|
await writeFile(wranglerPath, patched, 'utf8');
|
|
47
48
|
const collectionsDir = join(cwd, 'src/vulse/collections');
|
|
@@ -63,9 +64,10 @@ export async function runInstallHook(cwd) {
|
|
|
63
64
|
✅ Vulse installed.
|
|
64
65
|
|
|
65
66
|
One-time setup (copy/paste):
|
|
67
|
+
pnpm add @astrojs/vue vue # required at project root for the admin UI renderer
|
|
66
68
|
wrangler d1 create vulse-db
|
|
67
69
|
wrangler r2 bucket create vulse-media
|
|
68
|
-
# Paste the returned database_id into wrangler
|
|
70
|
+
# Paste the returned database_id into your wrangler config (search for TODO_PASTE_ID).
|
|
69
71
|
npx vulse migrate
|
|
70
72
|
npx vulse seed:admin --email you@example.com
|
|
71
73
|
|
|
@@ -0,0 +1,12 @@
|
|
|
1
|
+
import { type PatchOptions } from './wrangler-patch.js';
|
|
2
|
+
declare const WRANGLER_FILES: readonly ["wrangler.jsonc", "wrangler.toml", "wrangler.json"];
|
|
3
|
+
export type WranglerConfigFile = (typeof WRANGLER_FILES)[number];
|
|
4
|
+
/** Prefer the wrangler file Astro/Cloudflare already created. */
|
|
5
|
+
export declare function findWranglerConfig(cwd: string): Promise<WranglerConfigFile | null>;
|
|
6
|
+
export declare function isJsonWranglerConfig(file: WranglerConfigFile): boolean;
|
|
7
|
+
export declare function patchWranglerJsonc(input: string, opts?: PatchOptions): string;
|
|
8
|
+
export declare function patchWranglerConfig(input: string, file: WranglerConfigFile, opts?: PatchOptions): string;
|
|
9
|
+
/** Ensure the active wrangler config points migrations at the bundled package SQL. */
|
|
10
|
+
export declare function ensureWranglerConfig(cwd: string, opts?: PatchOptions): Promise<WranglerConfigFile>;
|
|
11
|
+
export {};
|
|
12
|
+
//# sourceMappingURL=wrangler-config.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"wrangler-config.d.ts","sourceRoot":"","sources":["../../src/integration/wrangler-config.ts"],"names":[],"mappings":"AAEA,OAAO,EAA2C,KAAK,YAAY,EAAE,MAAM,qBAAqB,CAAA;AAEhG,QAAA,MAAM,cAAc,+DAAgE,CAAA;AAGpF,MAAM,MAAM,kBAAkB,GAAG,CAAC,OAAO,cAAc,CAAC,CAAC,MAAM,CAAC,CAAA;AAMhE,iEAAiE;AACjE,wBAAsB,kBAAkB,CAAC,GAAG,EAAE,MAAM,GAAG,OAAO,CAAC,kBAAkB,GAAG,IAAI,CAAC,CAKxF;AAED,wBAAgB,oBAAoB,CAAC,IAAI,EAAE,kBAAkB,GAAG,OAAO,CAEtE;AAED,wBAAgB,kBAAkB,CAAC,KAAK,EAAE,MAAM,EAAE,IAAI,GAAE,YAA4B,GAAG,MAAM,CAyD5F;AAED,wBAAgB,mBAAmB,CACjC,KAAK,EAAE,MAAM,EACb,IAAI,EAAE,kBAAkB,EACxB,IAAI,GAAE,YAA4B,GACjC,MAAM,CAmBR;AAED,sFAAsF;AACtF,wBAAsB,oBAAoB,CACxC,GAAG,EAAE,MAAM,EACX,IAAI,GAAE,YAA4B,GACjC,OAAO,CAAC,kBAAkB,CAAC,CAQ7B"}
|
|
@@ -0,0 +1,97 @@
|
|
|
1
|
+
import { access, readFile, writeFile } from 'node:fs/promises';
|
|
2
|
+
import { join } from 'node:path';
|
|
3
|
+
import { patchWranglerToml, VULSE_MIGRATIONS_DIR } from './wrangler-patch.js';
|
|
4
|
+
const WRANGLER_FILES = ['wrangler.jsonc', 'wrangler.toml', 'wrangler.json'];
|
|
5
|
+
const DEFAULT_PATCH = { d1Name: 'vulse-db', r2Bucket: 'vulse-media' };
|
|
6
|
+
async function fileExists(path) {
|
|
7
|
+
try {
|
|
8
|
+
await access(path);
|
|
9
|
+
return true;
|
|
10
|
+
}
|
|
11
|
+
catch {
|
|
12
|
+
return false;
|
|
13
|
+
}
|
|
14
|
+
}
|
|
15
|
+
/** Prefer the wrangler file Astro/Cloudflare already created. */
|
|
16
|
+
export async function findWranglerConfig(cwd) {
|
|
17
|
+
for (const file of WRANGLER_FILES) {
|
|
18
|
+
if (await fileExists(join(cwd, file)))
|
|
19
|
+
return file;
|
|
20
|
+
}
|
|
21
|
+
return null;
|
|
22
|
+
}
|
|
23
|
+
export function isJsonWranglerConfig(file) {
|
|
24
|
+
return file === 'wrangler.jsonc' || file === 'wrangler.json';
|
|
25
|
+
}
|
|
26
|
+
export function patchWranglerJsonc(input, opts = DEFAULT_PATCH) {
|
|
27
|
+
const D1_MARKER = '// vulse:d1';
|
|
28
|
+
const R2_MARKER = '// vulse:r2';
|
|
29
|
+
let out = input.trimEnd();
|
|
30
|
+
if (!out.endsWith('\n'))
|
|
31
|
+
out += '\n';
|
|
32
|
+
if (!out.includes(D1_MARKER)) {
|
|
33
|
+
if (/["']binding["']\s*:\s*["']DB["']/.test(out) && !out.includes('migrations_dir')) {
|
|
34
|
+
out = out.replace(/("binding"\s*:\s*"DB"[\s\S]*?)(}\s*,?\s*(?=\]|,|\n\s*}))/, (match, prefix, suffix) => {
|
|
35
|
+
if (prefix.includes('migrations_dir'))
|
|
36
|
+
return match;
|
|
37
|
+
const sep = prefix.trimEnd().endsWith(',') ? '\n ' : ',\n ';
|
|
38
|
+
return `${prefix}${sep}"migrations_dir": "${VULSE_MIGRATIONS_DIR}"${suffix}`;
|
|
39
|
+
});
|
|
40
|
+
}
|
|
41
|
+
else if (!out.includes('"d1_databases"')) {
|
|
42
|
+
const d1Block = ` ${D1_MARKER}
|
|
43
|
+
"d1_databases": [
|
|
44
|
+
{
|
|
45
|
+
"binding": "DB",
|
|
46
|
+
"database_name": "${opts.d1Name}",
|
|
47
|
+
"database_id": "TODO_PASTE_ID_FROM_WRANGLER_OUTPUT",
|
|
48
|
+
"migrations_dir": "${VULSE_MIGRATIONS_DIR}"
|
|
49
|
+
}
|
|
50
|
+
],`;
|
|
51
|
+
out = out.replace(/\}\s*$/, `${d1Block}\n}\n`);
|
|
52
|
+
}
|
|
53
|
+
}
|
|
54
|
+
if (!out.includes(R2_MARKER) && !out.includes('"r2_buckets"')) {
|
|
55
|
+
const r2Block = ` ${R2_MARKER}
|
|
56
|
+
"r2_buckets": [
|
|
57
|
+
{
|
|
58
|
+
"binding": "BUCKET",
|
|
59
|
+
"bucket_name": "${opts.r2Bucket}"
|
|
60
|
+
}
|
|
61
|
+
],`;
|
|
62
|
+
out = out.replace(/\}\s*$/, `${r2Block}\n}\n`);
|
|
63
|
+
}
|
|
64
|
+
if (!out.includes('nodejs_compat')) {
|
|
65
|
+
if (out.includes('"compatibility_flags"')) {
|
|
66
|
+
out = out.replace(/"compatibility_flags"\s*:\s*\[(.*?)\]/s, (match, flags) => flags.includes('nodejs_compat') ? match : `"compatibility_flags": [${flags.trim()}${flags.trim() ? ', ' : ''}"nodejs_compat"]`);
|
|
67
|
+
}
|
|
68
|
+
else if (out.includes('"compatibility_date"')) {
|
|
69
|
+
out = out.replace(/"compatibility_date"\s*:\s*"[^"]*"/, (m) => `${m},\n "compatibility_flags": ["nodejs_compat"]`);
|
|
70
|
+
}
|
|
71
|
+
}
|
|
72
|
+
return out;
|
|
73
|
+
}
|
|
74
|
+
export function patchWranglerConfig(input, file, opts = DEFAULT_PATCH) {
|
|
75
|
+
const patched = isJsonWranglerConfig(file) ? patchWranglerJsonc(input, opts) : patchWranglerToml(input, opts);
|
|
76
|
+
if (patched.includes('migrations_dir'))
|
|
77
|
+
return patched;
|
|
78
|
+
// Cloudflare scaffold may already define D1 without migrations_dir (no vulse marker).
|
|
79
|
+
if (file.endsWith('.toml') && patched.includes('binding = "DB"') && !patched.includes('migrations_dir')) {
|
|
80
|
+
if (patched.includes('database_id = ')) {
|
|
81
|
+
return patched.replace(/(database_id = "[^"]*")/, `$1\nmigrations_dir = "${VULSE_MIGRATIONS_DIR}"`);
|
|
82
|
+
}
|
|
83
|
+
return patched.replace(/(binding = "DB"[^\n]*\n)/, `$1migrations_dir = "${VULSE_MIGRATIONS_DIR}"\n`);
|
|
84
|
+
}
|
|
85
|
+
return patched;
|
|
86
|
+
}
|
|
87
|
+
/** Ensure the active wrangler config points migrations at the bundled package SQL. */
|
|
88
|
+
export async function ensureWranglerConfig(cwd, opts = DEFAULT_PATCH) {
|
|
89
|
+
const existing = await findWranglerConfig(cwd);
|
|
90
|
+
const file = existing ?? 'wrangler.toml';
|
|
91
|
+
const path = join(cwd, file);
|
|
92
|
+
const before = existing ? await readFile(path, 'utf8') : '';
|
|
93
|
+
const after = patchWranglerConfig(before, file, opts);
|
|
94
|
+
if (after !== before)
|
|
95
|
+
await writeFile(path, after, 'utf8');
|
|
96
|
+
return file;
|
|
97
|
+
}
|
|
@@ -2,5 +2,6 @@ export interface PatchOptions {
|
|
|
2
2
|
d1Name: string;
|
|
3
3
|
r2Bucket: string;
|
|
4
4
|
}
|
|
5
|
+
export declare const VULSE_MIGRATIONS_DIR = "node_modules/@ekrist1/vulse/migrations";
|
|
5
6
|
export declare function patchWranglerToml(input: string, opts: PatchOptions): string;
|
|
6
7
|
//# sourceMappingURL=wrangler-patch.d.ts.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"wrangler-patch.d.ts","sourceRoot":"","sources":["../../src/integration/wrangler-patch.ts"],"names":[],"mappings":"AAEA,MAAM,WAAW,YAAY;IAC3B,MAAM,EAAE,MAAM,CAAA;IACd,QAAQ,EAAE,MAAM,CAAA;CACjB;
|
|
1
|
+
{"version":3,"file":"wrangler-patch.d.ts","sourceRoot":"","sources":["../../src/integration/wrangler-patch.ts"],"names":[],"mappings":"AAEA,MAAM,WAAW,YAAY;IAC3B,MAAM,EAAE,MAAM,CAAA;IACd,QAAQ,EAAE,MAAM,CAAA;CACjB;AAED,eAAO,MAAM,oBAAoB,2CAA6C,CAAA;AAK9E,wBAAgB,iBAAiB,CAAC,KAAK,EAAE,MAAM,EAAE,IAAI,EAAE,YAAY,GAAG,MAAM,CAe3E"}
|
|
@@ -1,4 +1,5 @@
|
|
|
1
1
|
import { VULSE_PACKAGE } from '../package-name.js';
|
|
2
|
+
export const VULSE_MIGRATIONS_DIR = `node_modules/${VULSE_PACKAGE}/migrations`;
|
|
2
3
|
const D1_MARKER = '# vulse:d1';
|
|
3
4
|
const R2_MARKER = '# vulse:r2';
|
|
4
5
|
export function patchWranglerToml(input, opts) {
|
|
@@ -6,7 +7,7 @@ export function patchWranglerToml(input, opts) {
|
|
|
6
7
|
const hasR2 = input.includes(R2_MARKER);
|
|
7
8
|
let out = input;
|
|
8
9
|
if (!hasD1) {
|
|
9
|
-
out += `\n${D1_MARKER}\n[[d1_databases]]\nbinding = "DB"\ndatabase_name = "${opts.d1Name}"\ndatabase_id = "TODO_PASTE_ID_FROM_WRANGLER_OUTPUT"\nmigrations_dir = "
|
|
10
|
+
out += `\n${D1_MARKER}\n[[d1_databases]]\nbinding = "DB"\ndatabase_name = "${opts.d1Name}"\ndatabase_id = "TODO_PASTE_ID_FROM_WRANGLER_OUTPUT"\nmigrations_dir = "${VULSE_MIGRATIONS_DIR}"\n`;
|
|
10
11
|
}
|
|
11
12
|
if (!hasR2) {
|
|
12
13
|
out += `\n${R2_MARKER}\n[[r2_buckets]]\nbinding = "BUCKET"\nbucket_name = "${opts.r2Bucket}"\n`;
|
|
@@ -80,7 +80,7 @@ export function formSubmitRoutes(db, options = {}) {
|
|
|
80
80
|
});
|
|
81
81
|
}
|
|
82
82
|
const rate = def.settings.rateLimit ?? { maxPerIp: 10, windowSec: 3600 };
|
|
83
|
-
const rl = await checkRateLimit(db, handle, hashIp(ip), rate);
|
|
83
|
+
const rl = await checkRateLimit(db, handle, await hashIp(ip), rate);
|
|
84
84
|
if (!rl.allowed) {
|
|
85
85
|
return new Response(JSON.stringify({
|
|
86
86
|
ok: false,
|
package/dist/version.d.ts
CHANGED
|
@@ -1,2 +1,2 @@
|
|
|
1
|
-
export declare const VULSE_VERSION = "0.1.
|
|
1
|
+
export declare const VULSE_VERSION = "0.1.7-alpha.4";
|
|
2
2
|
//# sourceMappingURL=version.d.ts.map
|
package/dist/version.js
CHANGED
|
@@ -1,2 +1,2 @@
|
|
|
1
1
|
// Generated by sync-version — do not edit
|
|
2
|
-
export const VULSE_VERSION = "0.1.
|
|
2
|
+
export const VULSE_VERSION = "0.1.7-alpha.4";
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@ekrist1/vulse",
|
|
3
|
-
"version": "0.1.
|
|
3
|
+
"version": "0.1.7-alpha.4",
|
|
4
4
|
"description": "Astro-native headless CMS for Cloudflare (D1, R2, Workers)",
|
|
5
5
|
"license": "MIT",
|
|
6
6
|
"repository": {
|
|
@@ -72,6 +72,10 @@
|
|
|
72
72
|
"files": [
|
|
73
73
|
"dist",
|
|
74
74
|
"migrations",
|
|
75
|
+
"src/admin",
|
|
76
|
+
"src/core",
|
|
77
|
+
"src/server",
|
|
78
|
+
"src/scaffold",
|
|
75
79
|
"src/client",
|
|
76
80
|
"LICENSE",
|
|
77
81
|
"README.md"
|
|
@@ -90,6 +94,7 @@
|
|
|
90
94
|
},
|
|
91
95
|
"dependencies": {
|
|
92
96
|
"@astrojs/vue": "^6.0.1",
|
|
97
|
+
"@tailwindcss/vite": "^4.3.0",
|
|
93
98
|
"@tiptap/core": "^2.8.0",
|
|
94
99
|
"@tiptap/pm": "^2.8.0",
|
|
95
100
|
"@tiptap/starter-kit": "^2.8.0",
|
|
@@ -101,28 +106,31 @@
|
|
|
101
106
|
"jose": "^6.2.3",
|
|
102
107
|
"morphdom": "^2.7.8",
|
|
103
108
|
"nanoid": "^5.0.0",
|
|
109
|
+
"tailwindcss": "^4",
|
|
104
110
|
"vue": "^3.5.34"
|
|
105
111
|
},
|
|
106
112
|
"devDependencies": {
|
|
107
113
|
"@cloudflare/vitest-pool-workers": "^0.6.0",
|
|
108
114
|
"@cloudflare/workers-types": "^4.20240320.0",
|
|
109
|
-
"@tailwindcss/vite": "^4.3.0",
|
|
110
115
|
"@types/diff": "^8.0.0",
|
|
111
116
|
"@types/node": "^22.0.0",
|
|
112
117
|
"astro": "^6.3.7",
|
|
113
118
|
"drizzle-kit": "^0.31.10",
|
|
114
119
|
"esbuild": "^0.25.12",
|
|
115
|
-
"tailwindcss": "^4",
|
|
116
120
|
"typescript": "^5.6.0",
|
|
117
121
|
"vite": "^7.3.0",
|
|
118
122
|
"vitest": "^2.1.0",
|
|
119
123
|
"wrangler": "^4.94.0"
|
|
120
124
|
},
|
|
121
125
|
"peerDependencies": {
|
|
126
|
+
"@astrojs/vue": "^6.0.0",
|
|
122
127
|
"astro": "^6.3.0",
|
|
123
128
|
"vue": "^3.5.0"
|
|
124
129
|
},
|
|
125
130
|
"peerDependenciesMeta": {
|
|
131
|
+
"@astrojs/vue": {
|
|
132
|
+
"optional": false
|
|
133
|
+
},
|
|
126
134
|
"vue": {
|
|
127
135
|
"optional": false
|
|
128
136
|
}
|
|
@@ -0,0 +1,5 @@
|
|
|
1
|
+
<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 120 120" role="img" aria-label="Vulse">
|
|
2
|
+
<rect x="0" y="0" width="120" height="120" rx="24" fill="#0B0B0C"></rect>
|
|
3
|
+
<path d="M30 36 L60 92 L90 36" stroke="#FAFAF7" stroke-width="11" stroke-linecap="round" stroke-linejoin="round" fill="none"></path>
|
|
4
|
+
<circle cx="60" cy="92" r="6" fill="#FF5B2E"></circle>
|
|
5
|
+
</svg>
|