@we8/cms 0.1.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +78 -0
- package/dist/auth/auth.d.ts +87 -0
- package/dist/auth/auth.d.ts.map +1 -0
- package/dist/auth/auth.js +90 -0
- package/dist/auth/auth.js.map +1 -0
- package/dist/auth/routes.admin.d.ts +22 -0
- package/dist/auth/routes.admin.d.ts.map +1 -0
- package/dist/auth/routes.admin.js +106 -0
- package/dist/auth/routes.admin.js.map +1 -0
- package/dist/auth/schema.d.ts +1395 -0
- package/dist/auth/schema.d.ts.map +1 -0
- package/dist/auth/schema.js +76 -0
- package/dist/auth/schema.js.map +1 -0
- package/dist/env.d.ts +64 -0
- package/dist/env.d.ts.map +1 -0
- package/dist/env.js +48 -0
- package/dist/env.js.map +1 -0
- package/dist/index.d.ts +22 -0
- package/dist/index.d.ts.map +1 -0
- package/dist/index.js +170 -0
- package/dist/index.js.map +1 -0
- package/dist/keys/middleware.d.ts +54 -0
- package/dist/keys/middleware.d.ts.map +1 -0
- package/dist/keys/middleware.js +84 -0
- package/dist/keys/middleware.js.map +1 -0
- package/dist/keys/routes.admin.d.ts +16 -0
- package/dist/keys/routes.admin.d.ts.map +1 -0
- package/dist/keys/routes.admin.js +34 -0
- package/dist/keys/routes.admin.js.map +1 -0
- package/dist/keys/service.d.ts +36 -0
- package/dist/keys/service.d.ts.map +1 -0
- package/dist/keys/service.js +120 -0
- package/dist/keys/service.js.map +1 -0
- package/dist/lib/bots.d.ts +24 -0
- package/dist/lib/bots.d.ts.map +1 -0
- package/dist/lib/bots.js +79 -0
- package/dist/lib/bots.js.map +1 -0
- package/dist/lib/email.d.ts +62 -0
- package/dist/lib/email.d.ts.map +1 -0
- package/dist/lib/email.js +64 -0
- package/dist/lib/email.js.map +1 -0
- package/dist/lib/errors.d.ts +12 -0
- package/dist/lib/errors.d.ts.map +1 -0
- package/dist/lib/errors.js +23 -0
- package/dist/lib/errors.js.map +1 -0
- package/dist/lib/notify.d.ts +20 -0
- package/dist/lib/notify.d.ts.map +1 -0
- package/dist/lib/notify.js +60 -0
- package/dist/lib/notify.js.map +1 -0
- package/dist/lib/retention.d.ts +15 -0
- package/dist/lib/retention.d.ts.map +1 -0
- package/dist/lib/retention.js +40 -0
- package/dist/lib/retention.js.map +1 -0
- package/dist/lib/sanitize.d.ts +14 -0
- package/dist/lib/sanitize.d.ts.map +1 -0
- package/dist/lib/sanitize.js +145 -0
- package/dist/lib/sanitize.js.map +1 -0
- package/dist/lib/turnstile.d.ts +7 -0
- package/dist/lib/turnstile.d.ts.map +1 -0
- package/dist/lib/turnstile.js +32 -0
- package/dist/lib/turnstile.js.map +1 -0
- package/dist/lib/validate.d.ts +11 -0
- package/dist/lib/validate.d.ts.map +1 -0
- package/dist/lib/validate.js +22 -0
- package/dist/lib/validate.js.map +1 -0
- package/dist/lib/word-count.d.ts +7 -0
- package/dist/lib/word-count.d.ts.map +1 -0
- package/dist/lib/word-count.js +14 -0
- package/dist/lib/word-count.js.map +1 -0
- package/dist/middleware/auth.d.ts +46 -0
- package/dist/middleware/auth.d.ts.map +1 -0
- package/dist/middleware/auth.js +60 -0
- package/dist/middleware/auth.js.map +1 -0
- package/dist/middleware/cors.d.ts +33 -0
- package/dist/middleware/cors.d.ts.map +1 -0
- package/dist/middleware/cors.js +55 -0
- package/dist/middleware/cors.js.map +1 -0
- package/dist/middleware/module-gate.d.ts +11 -0
- package/dist/middleware/module-gate.d.ts.map +1 -0
- package/dist/middleware/module-gate.js +18 -0
- package/dist/middleware/module-gate.js.map +1 -0
- package/dist/middleware/rate-limit.d.ts +13 -0
- package/dist/middleware/rate-limit.d.ts.map +1 -0
- package/dist/middleware/rate-limit.js +30 -0
- package/dist/middleware/rate-limit.js.map +1 -0
- package/dist/middleware/request-id.d.ts +8 -0
- package/dist/middleware/request-id.d.ts.map +1 -0
- package/dist/middleware/request-id.js +11 -0
- package/dist/middleware/request-id.js.map +1 -0
- package/dist/modules/aeo/checks.d.ts +41 -0
- package/dist/modules/aeo/checks.d.ts.map +1 -0
- package/dist/modules/aeo/checks.js +127 -0
- package/dist/modules/aeo/checks.js.map +1 -0
- package/dist/modules/aeo/llms.d.ts +24 -0
- package/dist/modules/aeo/llms.d.ts.map +1 -0
- package/dist/modules/aeo/llms.js +92 -0
- package/dist/modules/aeo/llms.js.map +1 -0
- package/dist/modules/aeo/routes.admin.d.ts +12 -0
- package/dist/modules/aeo/routes.admin.d.ts.map +1 -0
- package/dist/modules/aeo/routes.admin.js +37 -0
- package/dist/modules/aeo/routes.admin.js.map +1 -0
- package/dist/modules/analytics/db.d.ts +24 -0
- package/dist/modules/analytics/db.d.ts.map +1 -0
- package/dist/modules/analytics/db.js +24 -0
- package/dist/modules/analytics/db.js.map +1 -0
- package/dist/modules/analytics/routes.admin.d.ts +6 -0
- package/dist/modules/analytics/routes.admin.d.ts.map +1 -0
- package/dist/modules/analytics/routes.admin.js +21 -0
- package/dist/modules/analytics/routes.admin.js.map +1 -0
- package/dist/modules/analytics/routes.public.d.ts +6 -0
- package/dist/modules/analytics/routes.public.d.ts.map +1 -0
- package/dist/modules/analytics/routes.public.js +33 -0
- package/dist/modules/analytics/routes.public.js.map +1 -0
- package/dist/modules/analytics/service.d.ts +16 -0
- package/dist/modules/analytics/service.d.ts.map +1 -0
- package/dist/modules/analytics/service.js +148 -0
- package/dist/modules/analytics/service.js.map +1 -0
- package/dist/modules/authors/routes.admin.d.ts +6 -0
- package/dist/modules/authors/routes.admin.d.ts.map +1 -0
- package/dist/modules/authors/routes.admin.js +29 -0
- package/dist/modules/authors/routes.admin.js.map +1 -0
- package/dist/modules/authors/routes.public.d.ts +6 -0
- package/dist/modules/authors/routes.public.d.ts.map +1 -0
- package/dist/modules/authors/routes.public.js +11 -0
- package/dist/modules/authors/routes.public.js.map +1 -0
- package/dist/modules/authors/service.d.ts +26 -0
- package/dist/modules/authors/service.d.ts.map +1 -0
- package/dist/modules/authors/service.js +116 -0
- package/dist/modules/authors/service.js.map +1 -0
- package/dist/modules/content/db.d.ts +127 -0
- package/dist/modules/content/db.d.ts.map +1 -0
- package/dist/modules/content/db.js +203 -0
- package/dist/modules/content/db.js.map +1 -0
- package/dist/modules/content/publish.d.ts +38 -0
- package/dist/modules/content/publish.d.ts.map +1 -0
- package/dist/modules/content/publish.js +184 -0
- package/dist/modules/content/publish.js.map +1 -0
- package/dist/modules/content/routes.admin.d.ts +8 -0
- package/dist/modules/content/routes.admin.d.ts.map +1 -0
- package/dist/modules/content/routes.admin.js +122 -0
- package/dist/modules/content/routes.admin.js.map +1 -0
- package/dist/modules/content/routes.public.d.ts +6 -0
- package/dist/modules/content/routes.public.d.ts.map +1 -0
- package/dist/modules/content/routes.public.js +56 -0
- package/dist/modules/content/routes.public.js.map +1 -0
- package/dist/modules/content/service.d.ts +137 -0
- package/dist/modules/content/service.d.ts.map +1 -0
- package/dist/modules/content/service.js +348 -0
- package/dist/modules/content/service.js.map +1 -0
- package/dist/modules/forms/db.d.ts +42 -0
- package/dist/modules/forms/db.d.ts.map +1 -0
- package/dist/modules/forms/db.js +62 -0
- package/dist/modules/forms/db.js.map +1 -0
- package/dist/modules/forms/forms-routes.admin.d.ts +6 -0
- package/dist/modules/forms/forms-routes.admin.d.ts.map +1 -0
- package/dist/modules/forms/forms-routes.admin.js +37 -0
- package/dist/modules/forms/forms-routes.admin.js.map +1 -0
- package/dist/modules/forms/forms-service.d.ts +18 -0
- package/dist/modules/forms/forms-service.d.ts.map +1 -0
- package/dist/modules/forms/forms-service.js +121 -0
- package/dist/modules/forms/forms-service.js.map +1 -0
- package/dist/modules/forms/routes.public.d.ts +6 -0
- package/dist/modules/forms/routes.public.d.ts.map +1 -0
- package/dist/modules/forms/routes.public.js +41 -0
- package/dist/modules/forms/routes.public.js.map +1 -0
- package/dist/modules/forms/submissions-routes.admin.d.ts +6 -0
- package/dist/modules/forms/submissions-routes.admin.d.ts.map +1 -0
- package/dist/modules/forms/submissions-routes.admin.js +46 -0
- package/dist/modules/forms/submissions-routes.admin.js.map +1 -0
- package/dist/modules/forms/submissions-service.d.ts +45 -0
- package/dist/modules/forms/submissions-service.d.ts.map +1 -0
- package/dist/modules/forms/submissions-service.js +174 -0
- package/dist/modules/forms/submissions-service.js.map +1 -0
- package/dist/modules/media/db.d.ts +15 -0
- package/dist/modules/media/db.d.ts.map +1 -0
- package/dist/modules/media/db.js +24 -0
- package/dist/modules/media/db.js.map +1 -0
- package/dist/modules/media/routes.admin.d.ts +6 -0
- package/dist/modules/media/routes.admin.d.ts.map +1 -0
- package/dist/modules/media/routes.admin.js +30 -0
- package/dist/modules/media/routes.admin.js.map +1 -0
- package/dist/modules/media/routes.public.d.ts +6 -0
- package/dist/modules/media/routes.public.d.ts.map +1 -0
- package/dist/modules/media/routes.public.js +35 -0
- package/dist/modules/media/routes.public.js.map +1 -0
- package/dist/modules/media/service.d.ts +32 -0
- package/dist/modules/media/service.d.ts.map +1 -0
- package/dist/modules/media/service.js +99 -0
- package/dist/modules/media/service.js.map +1 -0
- package/dist/modules/openapi/spec.d.ts +21 -0
- package/dist/modules/openapi/spec.d.ts.map +1 -0
- package/dist/modules/openapi/spec.js +468 -0
- package/dist/modules/openapi/spec.js.map +1 -0
- package/dist/modules/seo/jsonld.d.ts +25 -0
- package/dist/modules/seo/jsonld.d.ts.map +1 -0
- package/dist/modules/seo/jsonld.js +67 -0
- package/dist/modules/seo/jsonld.js.map +1 -0
- package/dist/modules/seo/routes.public.d.ts +6 -0
- package/dist/modules/seo/routes.public.d.ts.map +1 -0
- package/dist/modules/seo/routes.public.js +39 -0
- package/dist/modules/seo/routes.public.js.map +1 -0
- package/dist/modules/seo/sitemap.d.ts +3 -0
- package/dist/modules/seo/sitemap.d.ts.map +1 -0
- package/dist/modules/seo/sitemap.js +39 -0
- package/dist/modules/seo/sitemap.js.map +1 -0
- package/dist/modules/settings/routes.admin.d.ts +12 -0
- package/dist/modules/settings/routes.admin.d.ts.map +1 -0
- package/dist/modules/settings/routes.admin.js +27 -0
- package/dist/modules/settings/routes.admin.js.map +1 -0
- package/dist/modules/site-documents/routes.admin.d.ts +10 -0
- package/dist/modules/site-documents/routes.admin.d.ts.map +1 -0
- package/dist/modules/site-documents/routes.admin.js +29 -0
- package/dist/modules/site-documents/routes.admin.js.map +1 -0
- package/dist/modules/site-documents/routes.public.d.ts +6 -0
- package/dist/modules/site-documents/routes.public.d.ts.map +1 -0
- package/dist/modules/site-documents/routes.public.js +16 -0
- package/dist/modules/site-documents/routes.public.js.map +1 -0
- package/dist/modules/site-documents/service.d.ts +11 -0
- package/dist/modules/site-documents/service.d.ts.map +1 -0
- package/dist/modules/site-documents/service.js +42 -0
- package/dist/modules/site-documents/service.js.map +1 -0
- package/dist/modules/webhooks/dispatch.d.ts +14 -0
- package/dist/modules/webhooks/dispatch.d.ts.map +1 -0
- package/dist/modules/webhooks/dispatch.js +84 -0
- package/dist/modules/webhooks/dispatch.js.map +1 -0
- package/dist/shared/constants.d.ts +79 -0
- package/dist/shared/constants.d.ts.map +1 -0
- package/dist/shared/constants.js +89 -0
- package/dist/shared/constants.js.map +1 -0
- package/dist/shared/envelope.d.ts +37 -0
- package/dist/shared/envelope.d.ts.map +1 -0
- package/dist/shared/envelope.js +46 -0
- package/dist/shared/envelope.js.map +1 -0
- package/dist/shared/hash.d.ts +2 -0
- package/dist/shared/hash.d.ts.map +1 -0
- package/dist/shared/hash.js +8 -0
- package/dist/shared/hash.js.map +1 -0
- package/dist/shared/index.d.ts +13 -0
- package/dist/shared/index.d.ts.map +1 -0
- package/dist/shared/index.js +13 -0
- package/dist/shared/index.js.map +1 -0
- package/dist/shared/schemas/aeo.d.ts +182 -0
- package/dist/shared/schemas/aeo.d.ts.map +1 -0
- package/dist/shared/schemas/aeo.js +43 -0
- package/dist/shared/schemas/aeo.js.map +1 -0
- package/dist/shared/schemas/analytics.d.ts +277 -0
- package/dist/shared/schemas/analytics.d.ts.map +1 -0
- package/dist/shared/schemas/analytics.js +74 -0
- package/dist/shared/schemas/analytics.js.map +1 -0
- package/dist/shared/schemas/api-key.d.ts +77 -0
- package/dist/shared/schemas/api-key.d.ts.map +1 -0
- package/dist/shared/schemas/api-key.js +27 -0
- package/dist/shared/schemas/api-key.js.map +1 -0
- package/dist/shared/schemas/author.d.ts +147 -0
- package/dist/shared/schemas/author.d.ts.map +1 -0
- package/dist/shared/schemas/author.js +27 -0
- package/dist/shared/schemas/author.js.map +1 -0
- package/dist/shared/schemas/form.d.ts +341 -0
- package/dist/shared/schemas/form.d.ts.map +1 -0
- package/dist/shared/schemas/form.js +117 -0
- package/dist/shared/schemas/form.js.map +1 -0
- package/dist/shared/schemas/index.d.ts +12 -0
- package/dist/shared/schemas/index.d.ts.map +1 -0
- package/dist/shared/schemas/index.js +12 -0
- package/dist/shared/schemas/index.js.map +1 -0
- package/dist/shared/schemas/media.d.ts +42 -0
- package/dist/shared/schemas/media.d.ts.map +1 -0
- package/dist/shared/schemas/media.js +16 -0
- package/dist/shared/schemas/media.js.map +1 -0
- package/dist/shared/schemas/pagination.d.ts +34 -0
- package/dist/shared/schemas/pagination.d.ts.map +1 -0
- package/dist/shared/schemas/pagination.js +21 -0
- package/dist/shared/schemas/pagination.js.map +1 -0
- package/dist/shared/schemas/post.d.ts +862 -0
- package/dist/shared/schemas/post.d.ts.map +1 -0
- package/dist/shared/schemas/post.js +187 -0
- package/dist/shared/schemas/post.js.map +1 -0
- package/dist/shared/schemas/settings.d.ts +839 -0
- package/dist/shared/schemas/settings.d.ts.map +1 -0
- package/dist/shared/schemas/settings.js +202 -0
- package/dist/shared/schemas/settings.js.map +1 -0
- package/dist/shared/schemas/site-document.d.ts +38 -0
- package/dist/shared/schemas/site-document.d.ts.map +1 -0
- package/dist/shared/schemas/site-document.js +21 -0
- package/dist/shared/schemas/site-document.js.map +1 -0
- package/dist/shared/schemas/webhook.d.ts +39 -0
- package/dist/shared/schemas/webhook.d.ts.map +1 -0
- package/dist/shared/schemas/webhook.js +20 -0
- package/dist/shared/schemas/webhook.js.map +1 -0
- package/dist/spa.d.ts +9 -0
- package/dist/spa.d.ts.map +1 -0
- package/dist/spa.js +57 -0
- package/dist/spa.js.map +1 -0
- package/migrations/0001_settings.sql +39 -0
- package/migrations/0002_content.sql +135 -0
- package/migrations/0003_forms.sql +35 -0
- package/migrations/0004_analytics.sql +42 -0
- package/migrations/0005_media.sql +17 -0
- package/migrations/0006_site_documents.sql +18 -0
- package/migrations/0007_auth.sql +81 -0
- package/migrations/0008_api_keys.sql +20 -0
- package/package.json +68 -0
- package/scripts/bundle-admin.mjs +54 -0
- package/seed/local.sql +63 -0
|
@@ -0,0 +1,42 @@
|
|
|
1
|
+
-- 0004: the visit and consent logs. High volume and read only in aggregate,
|
|
2
|
+
-- so INTEGER AUTOINCREMENT ids like the other operational tables.
|
|
3
|
+
--
|
|
4
|
+
-- user_agent_class is the 0.1 AEO addition: `is_bot` alone answers "was this a
|
|
5
|
+
-- human", which throws away the distinction AEO is judged on. The class column
|
|
6
|
+
-- keeps an answer engine's crawler separate from a search crawler, a social
|
|
7
|
+
-- unfurler, and an SEO tool, so crawler activity can be read as a signal.
|
|
8
|
+
|
|
9
|
+
CREATE TABLE page_visits (
|
|
10
|
+
id INTEGER PRIMARY KEY AUTOINCREMENT,
|
|
11
|
+
visited_at TEXT NOT NULL DEFAULT (datetime('now')),
|
|
12
|
+
pathname TEXT NOT NULL,
|
|
13
|
+
referrer TEXT,
|
|
14
|
+
country TEXT,
|
|
15
|
+
ip_hash TEXT,
|
|
16
|
+
user_agent TEXT,
|
|
17
|
+
is_bot INTEGER NOT NULL DEFAULT 0,
|
|
18
|
+
bot_name TEXT,
|
|
19
|
+
bot_score INTEGER,
|
|
20
|
+
user_agent_class TEXT NOT NULL DEFAULT 'human',
|
|
21
|
+
session_id TEXT
|
|
22
|
+
);
|
|
23
|
+
|
|
24
|
+
CREATE INDEX idx_page_visits_visited_at ON page_visits (visited_at DESC);
|
|
25
|
+
CREATE INDEX idx_page_visits_pathname ON page_visits (pathname);
|
|
26
|
+
CREATE INDEX idx_page_visits_is_bot ON page_visits (is_bot);
|
|
27
|
+
CREATE INDEX idx_page_visits_country ON page_visits (country);
|
|
28
|
+
CREATE INDEX idx_page_visits_ua_class ON page_visits (user_agent_class);
|
|
29
|
+
|
|
30
|
+
CREATE TABLE consent_records (
|
|
31
|
+
id INTEGER PRIMARY KEY AUTOINCREMENT,
|
|
32
|
+
recorded_at TEXT NOT NULL DEFAULT (datetime('now')),
|
|
33
|
+
session_id TEXT NOT NULL,
|
|
34
|
+
ip_hash TEXT,
|
|
35
|
+
decision TEXT NOT NULL CHECK (decision IN ('accepted', 'partial', 'declined')),
|
|
36
|
+
analytics INTEGER NOT NULL DEFAULT 0,
|
|
37
|
+
performance INTEGER NOT NULL DEFAULT 0,
|
|
38
|
+
user_agent TEXT
|
|
39
|
+
);
|
|
40
|
+
|
|
41
|
+
CREATE INDEX idx_consent_records_recorded_at ON consent_records (recorded_at DESC);
|
|
42
|
+
CREATE INDEX idx_consent_records_decision ON consent_records (decision);
|
|
@@ -0,0 +1,17 @@
|
|
|
1
|
+
-- 0005: media metadata. The bytes live in the R2 bucket bound as MEDIA; this
|
|
2
|
+
-- table is the admin-visible record of what is in it. r2_key is unique because
|
|
3
|
+
-- it is the object's address and doubles as the public serve path.
|
|
4
|
+
|
|
5
|
+
CREATE TABLE media_assets (
|
|
6
|
+
id TEXT PRIMARY KEY,
|
|
7
|
+
r2_key TEXT NOT NULL UNIQUE,
|
|
8
|
+
filename TEXT NOT NULL,
|
|
9
|
+
content_type TEXT NOT NULL,
|
|
10
|
+
size INTEGER NOT NULL,
|
|
11
|
+
width INTEGER,
|
|
12
|
+
height INTEGER,
|
|
13
|
+
alt TEXT,
|
|
14
|
+
created_at TEXT NOT NULL DEFAULT (datetime('now'))
|
|
15
|
+
);
|
|
16
|
+
|
|
17
|
+
CREATE INDEX idx_media_assets_created_at ON media_assets (created_at DESC);
|
|
@@ -0,0 +1,18 @@
|
|
|
1
|
+
-- 0006: site documents, the small author-written texts served at the site
|
|
2
|
+
-- root. `kind` is the primary key: a fixed vocabulary, one row per kind,
|
|
3
|
+
-- upserted on write. An absent row means "never written", which is the same
|
|
4
|
+
-- meaning as empty content, so no rows are seeded here.
|
|
5
|
+
--
|
|
6
|
+
-- The llms-txt row is also the manual override for the generated /llms.txt:
|
|
7
|
+
-- when it has content, that content is served verbatim instead of the
|
|
8
|
+
-- generated document.
|
|
9
|
+
--
|
|
10
|
+
-- answer_summary is the 0.1 AEO field, the document-level counterpart of a
|
|
11
|
+
-- post's answer summary.
|
|
12
|
+
|
|
13
|
+
CREATE TABLE site_documents (
|
|
14
|
+
kind TEXT PRIMARY KEY,
|
|
15
|
+
content TEXT NOT NULL DEFAULT '',
|
|
16
|
+
answer_summary TEXT,
|
|
17
|
+
updated_at TEXT
|
|
18
|
+
);
|
|
@@ -0,0 +1,81 @@
|
|
|
1
|
+
-- 0007: the embedded Better Auth schema, as a plain migration under this
|
|
2
|
+
-- package's own numbering rather than ORM migration tooling. Additive only.
|
|
3
|
+
--
|
|
4
|
+
-- Canonical source of the field list: Better Auth's own model definitions for
|
|
5
|
+
-- the four core tables. No auth plugin is enabled, so there are no plugin
|
|
6
|
+
-- columns here and nothing unused: `role` is this package's own additional
|
|
7
|
+
-- field, carrying 'owner' or 'member'. A Drizzle mirror of these exact columns
|
|
8
|
+
-- lives at src/auth/schema.ts so the Drizzle adapter can build typed queries;
|
|
9
|
+
-- the two are kept in lockstep by hand. To regenerate a reference schema after
|
|
10
|
+
-- a Better Auth version bump, run the CLI against the auth config:
|
|
11
|
+
-- npx @better-auth/cli@latest generate --config src/auth/auth.ts
|
|
12
|
+
--
|
|
13
|
+
-- Column-type decisions: the Drizzle adapter passes native Date and boolean
|
|
14
|
+
-- values straight through, so date fields are INTEGER unix-second timestamps
|
|
15
|
+
-- (Drizzle `mode: 'timestamp'`) and boolean fields are INTEGER 0/1 (Drizzle
|
|
16
|
+
-- `mode: 'boolean'`). Ids are Better Auth's own generated TEXT strings. Column
|
|
17
|
+
-- names are Better Auth's default camelCase, so they intentionally differ from
|
|
18
|
+
-- the snake_case convention of this package's own tables: these four are owned
|
|
19
|
+
-- end to end by the library.
|
|
20
|
+
|
|
21
|
+
CREATE TABLE user (
|
|
22
|
+
id TEXT PRIMARY KEY,
|
|
23
|
+
name TEXT NOT NULL,
|
|
24
|
+
email TEXT NOT NULL UNIQUE,
|
|
25
|
+
emailVerified INTEGER NOT NULL DEFAULT 0,
|
|
26
|
+
image TEXT,
|
|
27
|
+
createdAt INTEGER NOT NULL,
|
|
28
|
+
updatedAt INTEGER NOT NULL,
|
|
29
|
+
-- The site role: 'owner' for the first user created, 'member' for everyone
|
|
30
|
+
-- after. Assigned server-side on user creation and never writable through
|
|
31
|
+
-- the auth API, so a member cannot promote themselves.
|
|
32
|
+
role TEXT
|
|
33
|
+
);
|
|
34
|
+
|
|
35
|
+
CREATE TABLE session (
|
|
36
|
+
id TEXT PRIMARY KEY,
|
|
37
|
+
expiresAt INTEGER NOT NULL,
|
|
38
|
+
token TEXT NOT NULL UNIQUE,
|
|
39
|
+
createdAt INTEGER NOT NULL,
|
|
40
|
+
updatedAt INTEGER NOT NULL,
|
|
41
|
+
ipAddress TEXT,
|
|
42
|
+
userAgent TEXT,
|
|
43
|
+
userId TEXT NOT NULL REFERENCES user (id) ON DELETE CASCADE
|
|
44
|
+
);
|
|
45
|
+
|
|
46
|
+
CREATE INDEX idx_session_user ON session (userId);
|
|
47
|
+
|
|
48
|
+
CREATE TABLE account (
|
|
49
|
+
id TEXT PRIMARY KEY,
|
|
50
|
+
-- Who vouches for this identity. For an email and password login it is the
|
|
51
|
+
-- local credential issuer; for a future social login it is that provider.
|
|
52
|
+
-- (issuer, accountId) is the identity's unique key.
|
|
53
|
+
issuer TEXT NOT NULL,
|
|
54
|
+
accountId TEXT NOT NULL,
|
|
55
|
+
providerId TEXT NOT NULL,
|
|
56
|
+
userId TEXT NOT NULL REFERENCES user (id) ON DELETE CASCADE,
|
|
57
|
+
accessToken TEXT,
|
|
58
|
+
refreshToken TEXT,
|
|
59
|
+
idToken TEXT,
|
|
60
|
+
accessTokenExpiresAt INTEGER,
|
|
61
|
+
refreshTokenExpiresAt INTEGER,
|
|
62
|
+
scope TEXT,
|
|
63
|
+
-- The password hash for the email and password credential account.
|
|
64
|
+
password TEXT,
|
|
65
|
+
createdAt INTEGER NOT NULL,
|
|
66
|
+
updatedAt INTEGER NOT NULL
|
|
67
|
+
);
|
|
68
|
+
|
|
69
|
+
CREATE INDEX idx_account_user ON account (userId);
|
|
70
|
+
CREATE UNIQUE INDEX idx_account_issuer_account ON account (issuer, accountId);
|
|
71
|
+
|
|
72
|
+
CREATE TABLE verification (
|
|
73
|
+
id TEXT PRIMARY KEY,
|
|
74
|
+
identifier TEXT NOT NULL,
|
|
75
|
+
value TEXT NOT NULL,
|
|
76
|
+
expiresAt INTEGER NOT NULL,
|
|
77
|
+
createdAt INTEGER NOT NULL,
|
|
78
|
+
updatedAt INTEGER NOT NULL
|
|
79
|
+
);
|
|
80
|
+
|
|
81
|
+
CREATE INDEX idx_verification_identifier ON verification (identifier);
|
|
@@ -0,0 +1,20 @@
|
|
|
1
|
+
-- 0008: public API keys, validated inside this worker.
|
|
2
|
+
--
|
|
3
|
+
-- Only the SHA-256 hash of a key is stored, so the table is not a credential
|
|
4
|
+
-- store: a database dump does not yield usable keys. `prefix` is the
|
|
5
|
+
-- non-secret leading fragment (e.g. `pk_live_a1b2c3d4`) kept purely so a key
|
|
6
|
+
-- list is readable. key_hash is unique because a presented key is resolved by
|
|
7
|
+
-- hash on the public request path, and last_used_at is advisory only.
|
|
8
|
+
|
|
9
|
+
CREATE TABLE api_keys (
|
|
10
|
+
id TEXT PRIMARY KEY,
|
|
11
|
+
kind TEXT NOT NULL CHECK (kind IN ('pk', 'sk')),
|
|
12
|
+
prefix TEXT NOT NULL,
|
|
13
|
+
key_hash TEXT NOT NULL UNIQUE,
|
|
14
|
+
label TEXT,
|
|
15
|
+
created_at TEXT NOT NULL DEFAULT (datetime('now')),
|
|
16
|
+
last_used_at TEXT,
|
|
17
|
+
revoked_at TEXT
|
|
18
|
+
);
|
|
19
|
+
|
|
20
|
+
CREATE INDEX idx_api_keys_created ON api_keys (created_at DESC);
|
package/package.json
ADDED
|
@@ -0,0 +1,68 @@
|
|
|
1
|
+
{
|
|
2
|
+
"name": "@we8/cms",
|
|
3
|
+
"version": "0.1.0",
|
|
4
|
+
"license": "MIT",
|
|
5
|
+
"repository": {
|
|
6
|
+
"type": "git",
|
|
7
|
+
"url": "git+https://github.com/reveriext/we8-package.git",
|
|
8
|
+
"directory": "packages/cms"
|
|
9
|
+
},
|
|
10
|
+
"homepage": "https://github.com/reveriext/we8-package/tree/main/packages/cms#readme",
|
|
11
|
+
"bugs": "https://github.com/reveriext/we8-package/issues",
|
|
12
|
+
"type": "module",
|
|
13
|
+
"description": "The core we8 headless CMS: content, forms, analytics, media, and SEO modules behind a single-site /v1 API with embedded auth.",
|
|
14
|
+
"keywords": [
|
|
15
|
+
"we8",
|
|
16
|
+
"cms",
|
|
17
|
+
"headless-cms",
|
|
18
|
+
"cloudflare-workers",
|
|
19
|
+
"hono",
|
|
20
|
+
"self-hosted",
|
|
21
|
+
"aeo",
|
|
22
|
+
"seo"
|
|
23
|
+
],
|
|
24
|
+
"main": "./dist/index.js",
|
|
25
|
+
"types": "./dist/index.d.ts",
|
|
26
|
+
"exports": {
|
|
27
|
+
".": {
|
|
28
|
+
"types": "./dist/index.d.ts",
|
|
29
|
+
"default": "./dist/index.js"
|
|
30
|
+
}
|
|
31
|
+
},
|
|
32
|
+
"files": [
|
|
33
|
+
"dist",
|
|
34
|
+
"migrations",
|
|
35
|
+
"scripts",
|
|
36
|
+
"seed",
|
|
37
|
+
"README.md"
|
|
38
|
+
],
|
|
39
|
+
"sideEffects": false,
|
|
40
|
+
"scripts": {
|
|
41
|
+
"build": "tsc -p tsconfig.build.json",
|
|
42
|
+
"typecheck": "tsc -p tsconfig.json",
|
|
43
|
+
"test": "vitest run",
|
|
44
|
+
"dev": "wrangler dev",
|
|
45
|
+
"db:migrate": "wrangler d1 migrations apply DB --local",
|
|
46
|
+
"db:seed": "wrangler d1 execute DB --local --file=./seed/local.sql",
|
|
47
|
+
"admin:bundle": "node scripts/bundle-admin.mjs",
|
|
48
|
+
"prepack": "npm run build"
|
|
49
|
+
},
|
|
50
|
+
"publishConfig": {
|
|
51
|
+
"access": "public"
|
|
52
|
+
},
|
|
53
|
+
"dependencies": {
|
|
54
|
+
"better-auth": "^1.7.1",
|
|
55
|
+
"drizzle-orm": "^0.45.2",
|
|
56
|
+
"hono": "^4.12.27",
|
|
57
|
+
"zod": "^3.24.1"
|
|
58
|
+
},
|
|
59
|
+
"devDependencies": {
|
|
60
|
+
"@cloudflare/vitest-pool-workers": "^0.18.0",
|
|
61
|
+
"@cloudflare/workers-types": "^5.20260705.1",
|
|
62
|
+
"vitest": "^4.1.9",
|
|
63
|
+
"wrangler": "^4.107.0"
|
|
64
|
+
},
|
|
65
|
+
"engines": {
|
|
66
|
+
"node": ">=20"
|
|
67
|
+
}
|
|
68
|
+
}
|
|
@@ -0,0 +1,54 @@
|
|
|
1
|
+
// Copies the built admin portal into this worker's static-asset directory.
|
|
2
|
+
//
|
|
3
|
+
// A tiny node script rather than a shell one-liner, so it behaves the same on
|
|
4
|
+
// every platform a self-hoster might run it from, and so the failure when the
|
|
5
|
+
// portal has not been built yet says what to do about it.
|
|
6
|
+
|
|
7
|
+
import { cp, mkdir, readdir, rm, stat } from 'node:fs/promises';
|
|
8
|
+
import { dirname, join } from 'node:path';
|
|
9
|
+
import { fileURLToPath } from 'node:url';
|
|
10
|
+
|
|
11
|
+
const here = dirname(fileURLToPath(import.meta.url));
|
|
12
|
+
|
|
13
|
+
// In this workspace the defaults point at the sibling admin package. A
|
|
14
|
+
// scaffolded project passes its own paths instead:
|
|
15
|
+
// node node_modules/@we8/cms/scripts/bundle-admin.mjs \
|
|
16
|
+
// --source node_modules/@we8/admin-app/dist --target public
|
|
17
|
+
/** @param {string} flag */
|
|
18
|
+
function argValue(flag) {
|
|
19
|
+
const at = process.argv.indexOf(flag);
|
|
20
|
+
return at !== -1 && process.argv[at + 1] ? process.argv[at + 1] : null;
|
|
21
|
+
}
|
|
22
|
+
const source = argValue('--source') ?? join(here, '..', '..', 'admin', 'dist');
|
|
23
|
+
const target = argValue('--target') ?? join(here, '..', 'public');
|
|
24
|
+
const keepName = '.gitkeep';
|
|
25
|
+
|
|
26
|
+
async function main() {
|
|
27
|
+
try {
|
|
28
|
+
const info = await stat(source);
|
|
29
|
+
if (!info.isDirectory()) throw new Error('not a directory');
|
|
30
|
+
} catch {
|
|
31
|
+
console.error(
|
|
32
|
+
`No admin build at ${source}.\nRun "npm run build --workspace @we8/admin-app" first, or deploy without this step to run API-only.`,
|
|
33
|
+
);
|
|
34
|
+
process.exitCode = 1;
|
|
35
|
+
return;
|
|
36
|
+
}
|
|
37
|
+
|
|
38
|
+
await mkdir(target, { recursive: true });
|
|
39
|
+
|
|
40
|
+
// Clear everything but the placeholder, so a stale bundle's hashed files do
|
|
41
|
+
// not accumulate in the deployed asset set release after release.
|
|
42
|
+
for (const entry of await readdir(target)) {
|
|
43
|
+
if (entry === keepName) continue;
|
|
44
|
+
await rm(join(target, entry), { recursive: true, force: true });
|
|
45
|
+
}
|
|
46
|
+
|
|
47
|
+
// The placeholder is skipped by the clear above and absent from the source,
|
|
48
|
+
// so it survives every bundle and the directory stays tracked in git.
|
|
49
|
+
await cp(source, target, { recursive: true });
|
|
50
|
+
|
|
51
|
+
console.log(`Bundled the admin portal from ${source} into ${target}.`);
|
|
52
|
+
}
|
|
53
|
+
|
|
54
|
+
await main();
|
package/seed/local.sql
ADDED
|
@@ -0,0 +1,63 @@
|
|
|
1
|
+
-- Local development seed. Never run this against a real deployment: the two
|
|
2
|
+
-- API keys below are published in this file, so they are public knowledge.
|
|
3
|
+
--
|
|
4
|
+
-- Settings keys are camelCase, matching the field names in
|
|
5
|
+
-- src/shared/schemas/settings.ts directly.
|
|
6
|
+
|
|
7
|
+
INSERT INTO site_settings (key, value) VALUES
|
|
8
|
+
('allowedOrigins', '["http://localhost:4321","http://localhost:8787"]'),
|
|
9
|
+
('modules', '{"content":true,"forms":true,"analytics":true,"media":true,"seo":true}'),
|
|
10
|
+
('webhooks', '[]'),
|
|
11
|
+
('notifyEmails', '[]'),
|
|
12
|
+
('retentionDays', '{"visits":90,"consent":365}'),
|
|
13
|
+
('turnstile', '{"enabled":false}'),
|
|
14
|
+
('postsPathPrefix', '"/insights"'),
|
|
15
|
+
('publisher', '{"name":"Example Site"}'),
|
|
16
|
+
('seo', '{"defaultTitle":"Example Site","titleTemplate":"%s | Example Site","metaDescription":"A we8 package development site.","discourageSearchEngines":false}'),
|
|
17
|
+
('aeo', '{"siteSummary":"Example Site is a development site for the we8 package, used to exercise the CMS API locally.","llmsTxtEnabled":true,"llmsTxtMaxPosts":100}');
|
|
18
|
+
|
|
19
|
+
-- One author, credited on the seeded posts.
|
|
20
|
+
INSERT INTO authors (id, slug, name, type, role_title, bio, links) VALUES
|
|
21
|
+
('author-sample', 'sam-rivers', 'Sam Rivers', 'team', 'Editor', 'Writes the sample content that ships with the we8 package development seed.', '[]');
|
|
22
|
+
|
|
23
|
+
-- A published post, complete with the AEO fields, so /v1/posts, the sitemap,
|
|
24
|
+
-- and /llms.txt all have something real to return on a fresh database.
|
|
25
|
+
INSERT INTO posts (id, slug, type, title, excerpt, content, category, tags, status, answer_summary, question_heading, current_version_id, current_version_number, word_count, published_at) VALUES
|
|
26
|
+
('post-hello', 'hello-we8', 'blog', 'Hello from the we8 package',
|
|
27
|
+
'A first post so a fresh local install has something to serve.',
|
|
28
|
+
'<p>This post ships with the development seed. Edit or delete it once your own content lands.</p>',
|
|
29
|
+
'Guides', '["welcome","getting-started"]', 'published',
|
|
30
|
+
'The we8 package is a self-hostable website backend: a headless CMS, an admin portal, an API client, and an Astro integration, deployed on your own account.',
|
|
31
|
+
'What is the we8 package?',
|
|
32
|
+
'version-hello-1', 1, 18, datetime('now'));
|
|
33
|
+
|
|
34
|
+
INSERT INTO post_versions (id, post_id, version, title, excerpt, content, category, tags, answer_summary, question_heading, author_ids, word_count, note) VALUES
|
|
35
|
+
('version-hello-1', 'post-hello', 1, 'Hello from the we8 package',
|
|
36
|
+
'A first post so a fresh local install has something to serve.',
|
|
37
|
+
'<p>This post ships with the development seed. Edit or delete it once your own content lands.</p>',
|
|
38
|
+
'Guides', '["welcome","getting-started"]',
|
|
39
|
+
'The we8 package is a self-hostable website backend: a headless CMS, an admin portal, an API client, and an Astro integration, deployed on your own account.',
|
|
40
|
+
'What is the we8 package?',
|
|
41
|
+
'["author-sample"]', 18, 'seeded');
|
|
42
|
+
|
|
43
|
+
INSERT INTO post_authors (post_id, author_id, position) VALUES ('post-hello', 'author-sample', 0);
|
|
44
|
+
|
|
45
|
+
-- A never-published draft, so the admin has both states to look at and the AEO
|
|
46
|
+
-- check has a piece of content with real findings on it.
|
|
47
|
+
INSERT INTO posts (id, slug, type, title, content, tags, status) VALUES
|
|
48
|
+
('post-draft', 'a-draft-in-progress', 'article', 'A draft in progress',
|
|
49
|
+
'<p>Unpublished. The AEO check reports this one as missing a description, an answer summary, and a place in the sitemap.</p>',
|
|
50
|
+
'[]', 'draft');
|
|
51
|
+
|
|
52
|
+
-- The contact form every starter template posts to.
|
|
53
|
+
INSERT INTO forms (id, form_key, name, type, settings, updated_at) VALUES
|
|
54
|
+
('form-contact', 'contact', 'Contact', 'contact', '{"turnstileEnabled":false,"honeypotField":"website"}', datetime('now'));
|
|
55
|
+
|
|
56
|
+
-- Development API keys. The stored value is the SHA-256 of the secret, exactly
|
|
57
|
+
-- as a minted key is stored; the plaintext is in the comment because this seed
|
|
58
|
+
-- exists to make local curl calls possible.
|
|
59
|
+
-- publishable: pk_live_000000000000000000000000000000000000000000000000
|
|
60
|
+
-- secret: sk_live_111111111111111111111111111111111111111111111111
|
|
61
|
+
INSERT INTO api_keys (id, kind, prefix, key_hash, label) VALUES
|
|
62
|
+
('key-dev-pk', 'pk', 'pk_live_00000000', '53ffa4f3d7ef56f30213fc0c933a79477df3ea269c384fb6676ec21ce93fe867', 'local development (publishable)'),
|
|
63
|
+
('key-dev-sk', 'sk', 'sk_live_11111111', '5c11f32033bc37c58021740fd2a50a305d8dc52c5c52b4237962cfca20aa21b0', 'local development (secret)');
|