@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 @@
|
|
|
1
|
+
{"version":3,"file":"schema.d.ts","sourceRoot":"","sources":["../../src/auth/schema.ts"],"names":[],"mappings":"AAEA;;;;;;;;;;;;;;;;;;GAkBG;AAEH,eAAO,MAAM,IAAI;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;EAYf,CAAC;AAEH,eAAO,MAAM,OAAO;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;EAWlB,CAAC;AAEH,eAAO,MAAM,OAAO;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;EAmBlB,CAAC;AAEH,eAAO,MAAM,YAAY;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;EAOvB,CAAC;AAEH,oEAAoE;AACpE,eAAO,MAAM,UAAU;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;CAA2C,CAAC"}
|
|
@@ -0,0 +1,76 @@
|
|
|
1
|
+
import { sqliteTable, text, integer } from 'drizzle-orm/sqlite-core';
|
|
2
|
+
/**
|
|
3
|
+
* The Better Auth table shape, expressed as Drizzle SQLite tables.
|
|
4
|
+
*
|
|
5
|
+
* This is NOT a second source of truth for the schema: the physical tables are
|
|
6
|
+
* created by migrations/0007_auth.sql, and these objects only describe those
|
|
7
|
+
* exact columns so the Better Auth Drizzle adapter can build typed queries
|
|
8
|
+
* against them. The two are kept in lockstep by hand.
|
|
9
|
+
*
|
|
10
|
+
* Column types follow from how the adapter behaves: it passes native Date and
|
|
11
|
+
* boolean values through to Drizzle rather than pre-serializing them, so date
|
|
12
|
+
* fields are `integer({ mode: 'timestamp' })` (epoch seconds in, Date out) and
|
|
13
|
+
* boolean fields are `integer({ mode: 'boolean' })` (0/1 in, boolean out).
|
|
14
|
+
* Everything else is text, including ids, which are Better Auth's own
|
|
15
|
+
* generated strings.
|
|
16
|
+
*
|
|
17
|
+
* The object KEYS are Better Auth model names (singular), because the adapter
|
|
18
|
+
* resolves a column as `schema[model][field]`; the string passed to each column
|
|
19
|
+
* helper is the physical SQL column name, kept identical to the field name.
|
|
20
|
+
*/
|
|
21
|
+
export const user = sqliteTable('user', {
|
|
22
|
+
id: text('id').primaryKey(),
|
|
23
|
+
name: text('name').notNull(),
|
|
24
|
+
email: text('email').notNull().unique(),
|
|
25
|
+
emailVerified: integer('emailVerified', { mode: 'boolean' }).notNull().default(false),
|
|
26
|
+
image: text('image'),
|
|
27
|
+
createdAt: integer('createdAt', { mode: 'timestamp' }).notNull(),
|
|
28
|
+
updatedAt: integer('updatedAt', { mode: 'timestamp' }).notNull(),
|
|
29
|
+
// This package's own additional field: 'owner' or 'member'. Declared with
|
|
30
|
+
// input: false in the auth config, so it is assigned server-side on creation
|
|
31
|
+
// and unreachable from the account-update endpoint.
|
|
32
|
+
role: text('role'),
|
|
33
|
+
});
|
|
34
|
+
export const session = sqliteTable('session', {
|
|
35
|
+
id: text('id').primaryKey(),
|
|
36
|
+
expiresAt: integer('expiresAt', { mode: 'timestamp' }).notNull(),
|
|
37
|
+
token: text('token').notNull().unique(),
|
|
38
|
+
createdAt: integer('createdAt', { mode: 'timestamp' }).notNull(),
|
|
39
|
+
updatedAt: integer('updatedAt', { mode: 'timestamp' }).notNull(),
|
|
40
|
+
ipAddress: text('ipAddress'),
|
|
41
|
+
userAgent: text('userAgent'),
|
|
42
|
+
userId: text('userId')
|
|
43
|
+
.notNull()
|
|
44
|
+
.references(() => user.id, { onDelete: 'cascade' }),
|
|
45
|
+
});
|
|
46
|
+
export const account = sqliteTable('account', {
|
|
47
|
+
id: text('id').primaryKey(),
|
|
48
|
+
// Who vouches for this identity: the local credential issuer for an email
|
|
49
|
+
// and password login. (issuer, accountId) is the identity's unique key.
|
|
50
|
+
issuer: text('issuer').notNull(),
|
|
51
|
+
accountId: text('accountId').notNull(),
|
|
52
|
+
providerId: text('providerId').notNull(),
|
|
53
|
+
userId: text('userId')
|
|
54
|
+
.notNull()
|
|
55
|
+
.references(() => user.id, { onDelete: 'cascade' }),
|
|
56
|
+
accessToken: text('accessToken'),
|
|
57
|
+
refreshToken: text('refreshToken'),
|
|
58
|
+
idToken: text('idToken'),
|
|
59
|
+
accessTokenExpiresAt: integer('accessTokenExpiresAt', { mode: 'timestamp' }),
|
|
60
|
+
refreshTokenExpiresAt: integer('refreshTokenExpiresAt', { mode: 'timestamp' }),
|
|
61
|
+
scope: text('scope'),
|
|
62
|
+
password: text('password'),
|
|
63
|
+
createdAt: integer('createdAt', { mode: 'timestamp' }).notNull(),
|
|
64
|
+
updatedAt: integer('updatedAt', { mode: 'timestamp' }).notNull(),
|
|
65
|
+
});
|
|
66
|
+
export const verification = sqliteTable('verification', {
|
|
67
|
+
id: text('id').primaryKey(),
|
|
68
|
+
identifier: text('identifier').notNull(),
|
|
69
|
+
value: text('value').notNull(),
|
|
70
|
+
expiresAt: integer('expiresAt', { mode: 'timestamp' }).notNull(),
|
|
71
|
+
createdAt: integer('createdAt', { mode: 'timestamp' }).notNull(),
|
|
72
|
+
updatedAt: integer('updatedAt', { mode: 'timestamp' }).notNull(),
|
|
73
|
+
});
|
|
74
|
+
/** The single object handed to `drizzleAdapter(db, { schema })`. */
|
|
75
|
+
export const authSchema = { user, session, account, verification };
|
|
76
|
+
//# sourceMappingURL=schema.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"schema.js","sourceRoot":"","sources":["../../src/auth/schema.ts"],"names":[],"mappings":"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"}
|
package/dist/env.d.ts
ADDED
|
@@ -0,0 +1,64 @@
|
|
|
1
|
+
import { type SiteSettings, type SiteSettingsUpdateInput } from './shared/index.js';
|
|
2
|
+
/**
|
|
3
|
+
* Everything this worker consumes from its environment. One site, one
|
|
4
|
+
* database, one bucket: there is no tenant id, no dispatch namespace, and no
|
|
5
|
+
* control plane, because there is nothing above this worker to belong to.
|
|
6
|
+
*/
|
|
7
|
+
export interface Bindings {
|
|
8
|
+
/** The site's D1 database. Content, forms, analytics, auth, and keys all live here. */
|
|
9
|
+
DB: D1Database;
|
|
10
|
+
/** The site's R2 bucket, holding uploaded media bytes. */
|
|
11
|
+
MEDIA: R2Bucket;
|
|
12
|
+
/**
|
|
13
|
+
* The built admin portal, served from this same worker. Optional: a headless
|
|
14
|
+
* install deploys with an empty assets directory and runs API-only, and the
|
|
15
|
+
* SPA fallback in src/spa.ts stands down when there is nothing behind this.
|
|
16
|
+
*/
|
|
17
|
+
ASSETS?: Fetcher;
|
|
18
|
+
/** The public origin of the site this CMS backs, e.g. `https://example.com`. */
|
|
19
|
+
SITE_URL: string;
|
|
20
|
+
/** The version string reported by /v1/health. Set from the package version at deploy time. */
|
|
21
|
+
CMS_VERSION: string;
|
|
22
|
+
/**
|
|
23
|
+
* The secret Better Auth signs sessions with. A deployment MUST set this;
|
|
24
|
+
* `wrangler secret put BETTER_AUTH_SECRET` in production, `.dev.vars`
|
|
25
|
+
* locally. Sign-in is refused when it is missing rather than falling back to
|
|
26
|
+
* a default, because a predictable session secret is a forged session.
|
|
27
|
+
*/
|
|
28
|
+
BETTER_AUTH_SECRET?: string;
|
|
29
|
+
/**
|
|
30
|
+
* The origin Better Auth builds its own URLs from and trusts as an origin.
|
|
31
|
+
* Defaults to SITE_URL, which is correct when the CMS and the site share an
|
|
32
|
+
* origin; set it when the admin lives somewhere else.
|
|
33
|
+
*/
|
|
34
|
+
AUTH_URL?: string;
|
|
35
|
+
/** Optional. Only enforced for forms with settings.turnstileEnabled. */
|
|
36
|
+
TURNSTILE_SECRET?: string;
|
|
37
|
+
/**
|
|
38
|
+
* Which EmailSender to resolve: `console` logs the message, anything else
|
|
39
|
+
* (including unset) drops it. The Cloudflare pack supplies a real sender.
|
|
40
|
+
*/
|
|
41
|
+
EMAIL_MODE?: string;
|
|
42
|
+
/** The from-address a real sender uses. Carried here so the seam is configured in one place. */
|
|
43
|
+
EMAIL_FROM?: string;
|
|
44
|
+
}
|
|
45
|
+
/**
|
|
46
|
+
* Loads site settings from the site_settings key/value table, validated and
|
|
47
|
+
* defaulted through siteSettingsSchema, cached in memory for 60s per isolate.
|
|
48
|
+
* Every module reads its configuration through this one function, so a fresh
|
|
49
|
+
* database with no settings rows still yields a fully-formed settings object.
|
|
50
|
+
*/
|
|
51
|
+
export declare function getSettings(db: D1Database, now?: number): Promise<SiteSettings>;
|
|
52
|
+
/**
|
|
53
|
+
* Persists a partial settings update. Shallow-merges onto the current settings
|
|
54
|
+
* (each top-level key is one site_settings row, so a changed `modules` or
|
|
55
|
+
* `webhooks` value replaces that whole row; this matches the read side, which
|
|
56
|
+
* reassembles the full object one row per key), re-validates the merged result
|
|
57
|
+
* through the same schema `getSettings` uses, then writes every key back and
|
|
58
|
+
* refreshes the in-isolate cache immediately so a follow-up read in the same
|
|
59
|
+
* request never sees stale data for the rest of the 60s TTL.
|
|
60
|
+
*/
|
|
61
|
+
export declare function setSettings(db: D1Database, patch: SiteSettingsUpdateInput, now?: number): Promise<SiteSettings>;
|
|
62
|
+
/** Test-only: clears the module-scope cache between test cases. */
|
|
63
|
+
export declare function clearSettingsCacheForTests(): void;
|
|
64
|
+
//# sourceMappingURL=env.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"env.d.ts","sourceRoot":"","sources":["../src/env.ts"],"names":[],"mappings":"AAAA,OAAO,EAAsB,KAAK,YAAY,EAAE,KAAK,uBAAuB,EAAE,MAAM,mBAAmB,CAAC;AAExG;;;;GAIG;AACH,MAAM,WAAW,QAAQ;IACvB,uFAAuF;IACvF,EAAE,EAAE,UAAU,CAAC;IACf,0DAA0D;IAC1D,KAAK,EAAE,QAAQ,CAAC;IAChB;;;;OAIG;IACH,MAAM,CAAC,EAAE,OAAO,CAAC;IACjB,gFAAgF;IAChF,QAAQ,EAAE,MAAM,CAAC;IACjB,8FAA8F;IAC9F,WAAW,EAAE,MAAM,CAAC;IACpB;;;;;OAKG;IACH,kBAAkB,CAAC,EAAE,MAAM,CAAC;IAC5B;;;;OAIG;IACH,QAAQ,CAAC,EAAE,MAAM,CAAC;IAClB,wEAAwE;IACxE,gBAAgB,CAAC,EAAE,MAAM,CAAC;IAC1B;;;OAGG;IACH,UAAU,CAAC,EAAE,MAAM,CAAC;IACpB,gGAAgG;IAChG,UAAU,CAAC,EAAE,MAAM,CAAC;CACrB;AAiBD;;;;;GAKG;AACH,wBAAsB,WAAW,CAAC,EAAE,EAAE,UAAU,EAAE,GAAG,GAAE,MAAmB,GAAG,OAAO,CAAC,YAAY,CAAC,CAiBjG;AAED;;;;;;;;GAQG;AACH,wBAAsB,WAAW,CAC/B,EAAE,EAAE,UAAU,EACd,KAAK,EAAE,uBAAuB,EAC9B,GAAG,GAAE,MAAmB,GACvB,OAAO,CAAC,YAAY,CAAC,CAcvB;AAED,mEAAmE;AACnE,wBAAgB,0BAA0B,IAAI,IAAI,CAEjD"}
|
package/dist/env.js
ADDED
|
@@ -0,0 +1,48 @@
|
|
|
1
|
+
import { siteSettingsSchema } from './shared/index.js';
|
|
2
|
+
const SETTINGS_CACHE_TTL_MS = 60_000;
|
|
3
|
+
/** Per-isolate cache; module-scope state is the standard Workers pattern for this. */
|
|
4
|
+
let cache = null;
|
|
5
|
+
/**
|
|
6
|
+
* Loads site settings from the site_settings key/value table, validated and
|
|
7
|
+
* defaulted through siteSettingsSchema, cached in memory for 60s per isolate.
|
|
8
|
+
* Every module reads its configuration through this one function, so a fresh
|
|
9
|
+
* database with no settings rows still yields a fully-formed settings object.
|
|
10
|
+
*/
|
|
11
|
+
export async function getSettings(db, now = Date.now()) {
|
|
12
|
+
if (cache && cache.expiresAt > now) {
|
|
13
|
+
return cache.value;
|
|
14
|
+
}
|
|
15
|
+
const { results } = await db
|
|
16
|
+
.prepare('SELECT key, value FROM site_settings')
|
|
17
|
+
.all();
|
|
18
|
+
const raw = {};
|
|
19
|
+
for (const row of results) {
|
|
20
|
+
raw[row.key] = JSON.parse(row.value);
|
|
21
|
+
}
|
|
22
|
+
const value = siteSettingsSchema.parse(raw);
|
|
23
|
+
cache = { value, expiresAt: now + SETTINGS_CACHE_TTL_MS };
|
|
24
|
+
return value;
|
|
25
|
+
}
|
|
26
|
+
/**
|
|
27
|
+
* Persists a partial settings update. Shallow-merges onto the current settings
|
|
28
|
+
* (each top-level key is one site_settings row, so a changed `modules` or
|
|
29
|
+
* `webhooks` value replaces that whole row; this matches the read side, which
|
|
30
|
+
* reassembles the full object one row per key), re-validates the merged result
|
|
31
|
+
* through the same schema `getSettings` uses, then writes every key back and
|
|
32
|
+
* refreshes the in-isolate cache immediately so a follow-up read in the same
|
|
33
|
+
* request never sees stale data for the rest of the 60s TTL.
|
|
34
|
+
*/
|
|
35
|
+
export async function setSettings(db, patch, now = Date.now()) {
|
|
36
|
+
const current = await getSettings(db, now);
|
|
37
|
+
const merged = siteSettingsSchema.parse({ ...current, ...patch });
|
|
38
|
+
await db.batch(Object.entries(merged).map(([key, value]) => db
|
|
39
|
+
.prepare('INSERT OR REPLACE INTO site_settings (key, value) VALUES (?1, ?2)')
|
|
40
|
+
.bind(key, JSON.stringify(value))));
|
|
41
|
+
cache = { value: merged, expiresAt: now + SETTINGS_CACHE_TTL_MS };
|
|
42
|
+
return merged;
|
|
43
|
+
}
|
|
44
|
+
/** Test-only: clears the module-scope cache between test cases. */
|
|
45
|
+
export function clearSettingsCacheForTests() {
|
|
46
|
+
cache = null;
|
|
47
|
+
}
|
|
48
|
+
//# sourceMappingURL=env.js.map
|
package/dist/env.js.map
ADDED
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"env.js","sourceRoot":"","sources":["../src/env.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,kBAAkB,EAAmD,MAAM,mBAAmB,CAAC;AAmDxG,MAAM,qBAAqB,GAAG,MAAM,CAAC;AAErC,sFAAsF;AACtF,IAAI,KAAK,GAA8B,IAAI,CAAC;AAO5C;;;;;GAKG;AACH,MAAM,CAAC,KAAK,UAAU,WAAW,CAAC,EAAc,EAAE,MAAc,IAAI,CAAC,GAAG,EAAE;IACxE,IAAI,KAAK,IAAI,KAAK,CAAC,SAAS,GAAG,GAAG,EAAE,CAAC;QACnC,OAAO,KAAK,CAAC,KAAK,CAAC;IACrB,CAAC;IAED,MAAM,EAAE,OAAO,EAAE,GAAG,MAAM,EAAE;SACzB,OAAO,CAAC,sCAAsC,CAAC;SAC/C,GAAG,EAAkB,CAAC;IAEzB,MAAM,GAAG,GAA4B,EAAE,CAAC;IACxC,KAAK,MAAM,GAAG,IAAI,OAAO,EAAE,CAAC;QAC1B,GAAG,CAAC,GAAG,CAAC,GAAG,CAAC,GAAG,IAAI,CAAC,KAAK,CAAC,GAAG,CAAC,KAAK,CAAC,CAAC;IACvC,CAAC;IAED,MAAM,KAAK,GAAG,kBAAkB,CAAC,KAAK,CAAC,GAAG,CAAC,CAAC;IAC5C,KAAK,GAAG,EAAE,KAAK,EAAE,SAAS,EAAE,GAAG,GAAG,qBAAqB,EAAE,CAAC;IAC1D,OAAO,KAAK,CAAC;AACf,CAAC;AAED;;;;;;;;GAQG;AACH,MAAM,CAAC,KAAK,UAAU,WAAW,CAC/B,EAAc,EACd,KAA8B,EAC9B,MAAc,IAAI,CAAC,GAAG,EAAE;IAExB,MAAM,OAAO,GAAG,MAAM,WAAW,CAAC,EAAE,EAAE,GAAG,CAAC,CAAC;IAC3C,MAAM,MAAM,GAAG,kBAAkB,CAAC,KAAK,CAAC,EAAE,GAAG,OAAO,EAAE,GAAG,KAAK,EAAE,CAAC,CAAC;IAElE,MAAM,EAAE,CAAC,KAAK,CACZ,MAAM,CAAC,OAAO,CAAC,MAAM,CAAC,CAAC,GAAG,CAAC,CAAC,CAAC,GAAG,EAAE,KAAK,CAAC,EAAE,EAAE,CAC1C,EAAE;SACC,OAAO,CAAC,mEAAmE,CAAC;SAC5E,IAAI,CAAC,GAAG,EAAE,IAAI,CAAC,SAAS,CAAC,KAAK,CAAC,CAAC,CACpC,CACF,CAAC;IAEF,KAAK,GAAG,EAAE,KAAK,EAAE,MAAM,EAAE,SAAS,EAAE,GAAG,GAAG,qBAAqB,EAAE,CAAC;IAClE,OAAO,MAAM,CAAC;AAChB,CAAC;AAED,mEAAmE;AACnE,MAAM,UAAU,0BAA0B;IACxC,KAAK,GAAG,IAAI,CAAC;AACf,CAAC"}
|
package/dist/index.d.ts
ADDED
|
@@ -0,0 +1,22 @@
|
|
|
1
|
+
import { Hono } from 'hono';
|
|
2
|
+
import { type Bindings } from './env.js';
|
|
3
|
+
import { type KeyVariables } from './keys/middleware.js';
|
|
4
|
+
import { type AuthVariables } from './middleware/auth.js';
|
|
5
|
+
import { type RequestIdVariables } from './middleware/request-id.js';
|
|
6
|
+
/**
|
|
7
|
+
* The email seam, re-exported so a composed worker can plug a pack's sender in
|
|
8
|
+
* without reaching into the package's internals. A scaffolded project calls
|
|
9
|
+
* `registerEmailSender(cloudflareEmailSender)` at module scope and is done.
|
|
10
|
+
*/
|
|
11
|
+
export { registerEmailSender, type EmailMessage, type EmailSender, type EmailSenderFactory, } from './lib/email.js';
|
|
12
|
+
type Variables = RequestIdVariables & AuthVariables & KeyVariables;
|
|
13
|
+
export declare const app: Hono<{
|
|
14
|
+
Bindings: Bindings;
|
|
15
|
+
Variables: Variables;
|
|
16
|
+
}, import("hono/types").BlankSchema, "/">;
|
|
17
|
+
declare const _default: {
|
|
18
|
+
fetch: (request: Request, env?: {} | Bindings | undefined, executionCtx?: import("hono").ExecutionContext) => Response | Promise<Response>;
|
|
19
|
+
scheduled(_controller: ScheduledController, env: Bindings, _ctx: ExecutionContext<unknown>): Promise<void>;
|
|
20
|
+
};
|
|
21
|
+
export default _default;
|
|
22
|
+
//# sourceMappingURL=index.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,IAAI,EAAE,MAAM,MAAM,CAAC;AAK5B,OAAO,EAAe,KAAK,QAAQ,EAAE,MAAM,UAAU,CAAC;AAItD,OAAO,EAAiB,KAAK,YAAY,EAAE,MAAM,sBAAsB,CAAC;AACxE,OAAO,EAAe,KAAK,aAAa,EAAE,MAAM,sBAAsB,CAAC;AAGvE,OAAO,EAAa,KAAK,kBAAkB,EAAE,MAAM,4BAA4B,CAAC;AAqBhF;;;;GAIG;AACH,OAAO,EACL,mBAAmB,EACnB,KAAK,YAAY,EACjB,KAAK,WAAW,EAChB,KAAK,kBAAkB,GACxB,MAAM,gBAAgB,CAAC;AAExB,KAAK,SAAS,GAAG,kBAAkB,GAAG,aAAa,GAAG,YAAY,CAAC;AAKnE,eAAO,MAAM,GAAG;cAAwB,QAAQ;eAAa,SAAS;yCAAK,CAAC;;;;;AA+I5E,wBASsC"}
|
package/dist/index.js
ADDED
|
@@ -0,0 +1,170 @@
|
|
|
1
|
+
import { Hono } from 'hono';
|
|
2
|
+
import { createMiddleware } from 'hono/factory';
|
|
3
|
+
import { ok } from './shared/index.js';
|
|
4
|
+
import { AUTH_BASE_PATH, createAuth, isBootstrapOpen } from './auth/auth.js';
|
|
5
|
+
import { usersAdminRoutes } from './auth/routes.admin.js';
|
|
6
|
+
import { getSettings } from './env.js';
|
|
7
|
+
import { HttpError, errorBoundary, notFoundHandler } from './lib/errors.js';
|
|
8
|
+
import { runRetentionCleanup } from './lib/retention.js';
|
|
9
|
+
import { keysAdminRoutes } from './keys/routes.admin.js';
|
|
10
|
+
import { publicApiAuth } from './keys/middleware.js';
|
|
11
|
+
import { sessionAuth } from './middleware/auth.js';
|
|
12
|
+
import { corsMiddleware } from './middleware/cors.js';
|
|
13
|
+
import { moduleGate } from './middleware/module-gate.js';
|
|
14
|
+
import { requestId } from './middleware/request-id.js';
|
|
15
|
+
import { aeoAdminRoutes } from './modules/aeo/routes.admin.js';
|
|
16
|
+
import { resolveLlmsTxt } from './modules/aeo/llms.js';
|
|
17
|
+
import { analyticsAdminRoutes } from './modules/analytics/routes.admin.js';
|
|
18
|
+
import { analyticsPublicRoutes } from './modules/analytics/routes.public.js';
|
|
19
|
+
import { authorsAdminRoutes } from './modules/authors/routes.admin.js';
|
|
20
|
+
import { authorsPublicRoutes } from './modules/authors/routes.public.js';
|
|
21
|
+
import { contentAdminRoutes } from './modules/content/routes.admin.js';
|
|
22
|
+
import { contentPublicRoutes } from './modules/content/routes.public.js';
|
|
23
|
+
import { formsAdminRoutes } from './modules/forms/forms-routes.admin.js';
|
|
24
|
+
import { formsPublicRoutes } from './modules/forms/routes.public.js';
|
|
25
|
+
import { submissionsAdminRoutes } from './modules/forms/submissions-routes.admin.js';
|
|
26
|
+
import { mediaAdminRoutes } from './modules/media/routes.admin.js';
|
|
27
|
+
import { mediaPublicRoutes } from './modules/media/routes.public.js';
|
|
28
|
+
import { buildOpenApiSpec } from './modules/openapi/spec.js';
|
|
29
|
+
import { seoPublicRoutes } from './modules/seo/routes.public.js';
|
|
30
|
+
import { serveSpaShell } from './spa.js';
|
|
31
|
+
import { settingsAdminRoutes } from './modules/settings/routes.admin.js';
|
|
32
|
+
import { siteDocumentsAdminRoutes } from './modules/site-documents/routes.admin.js';
|
|
33
|
+
import { siteDocumentsPublicRoutes } from './modules/site-documents/routes.public.js';
|
|
34
|
+
/**
|
|
35
|
+
* The email seam, re-exported so a composed worker can plug a pack's sender in
|
|
36
|
+
* without reaching into the package's internals. A scaffolded project calls
|
|
37
|
+
* `registerEmailSender(cloudflareEmailSender)` at module scope and is done.
|
|
38
|
+
*/
|
|
39
|
+
export { registerEmailSender, } from './lib/email.js';
|
|
40
|
+
// Named export as well as default, so tests can call app.request(...) directly:
|
|
41
|
+
// the default export is the plain {fetch, scheduled} object Cloudflare's module
|
|
42
|
+
// Worker format expects, which has no .request() of its own.
|
|
43
|
+
export const app = new Hono();
|
|
44
|
+
app.onError(errorBoundary);
|
|
45
|
+
/**
|
|
46
|
+
* Nothing matched a route. When an admin bundle is bound as static assets,
|
|
47
|
+
* a document request for one of its client-side routes gets the SPA shell;
|
|
48
|
+
* everything else, including every API path, keeps the envelope 404 it has
|
|
49
|
+
* always had. See src/spa.ts for why the fallback is this narrow.
|
|
50
|
+
*/
|
|
51
|
+
app.notFound(async (c) => (await serveSpaShell(c.req.raw, c.env)) ?? notFoundHandler(c));
|
|
52
|
+
app.use('*', requestId);
|
|
53
|
+
// ---------------------------------------------------------------------------
|
|
54
|
+
// Embedded auth
|
|
55
|
+
// ---------------------------------------------------------------------------
|
|
56
|
+
/**
|
|
57
|
+
* Public sign-up is open exactly once, to create the first user, who becomes
|
|
58
|
+
* the owner. After that this closes and further accounts are created by the
|
|
59
|
+
* owner through /v1/admin/users.
|
|
60
|
+
*
|
|
61
|
+
* Gating at the HTTP layer rather than through the library's own disableSignUp
|
|
62
|
+
* is deliberate: the flag is static, the condition is not, and the owner's
|
|
63
|
+
* account-creation route needs the same underlying sign-up path to stay open
|
|
64
|
+
* server-side. One rule, applied where the request arrives.
|
|
65
|
+
*/
|
|
66
|
+
const bootstrapGate = createMiddleware(async (c, next) => {
|
|
67
|
+
if (!(await isBootstrapOpen(c.env.DB))) {
|
|
68
|
+
throw new HttpError('forbidden', 'sign-up is closed; ask an owner for an account');
|
|
69
|
+
}
|
|
70
|
+
await next();
|
|
71
|
+
});
|
|
72
|
+
app.use(`${AUTH_BASE_PATH}/*`, corsMiddleware('admin'));
|
|
73
|
+
app.use(`${AUTH_BASE_PATH}/sign-up/*`, bootstrapGate);
|
|
74
|
+
app.all(`${AUTH_BASE_PATH}/*`, async (c) => {
|
|
75
|
+
if (!c.env.BETTER_AUTH_SECRET) {
|
|
76
|
+
throw new HttpError('internal', 'BETTER_AUTH_SECRET is not configured');
|
|
77
|
+
}
|
|
78
|
+
return createAuth(c.env).handler(c.req.raw);
|
|
79
|
+
});
|
|
80
|
+
// ---------------------------------------------------------------------------
|
|
81
|
+
// Gates
|
|
82
|
+
// ---------------------------------------------------------------------------
|
|
83
|
+
app.use('/v1/*', publicApiAuth);
|
|
84
|
+
app.use('/v1/admin/*', corsMiddleware('admin'), sessionAuth);
|
|
85
|
+
// ---------------------------------------------------------------------------
|
|
86
|
+
// Meta
|
|
87
|
+
// ---------------------------------------------------------------------------
|
|
88
|
+
app.use('/v1/health', corsMiddleware('publicRead'));
|
|
89
|
+
app.get('/v1/health', async (c) => {
|
|
90
|
+
const settings = await getSettings(c.env.DB);
|
|
91
|
+
return c.json(ok({ cmsVersion: c.env.CMS_VERSION, modules: settings.modules }));
|
|
92
|
+
});
|
|
93
|
+
// Self-describing API: keyless, so any developer can read the contract before
|
|
94
|
+
// they have a key. Not module-gated either; it documents whatever is enabled
|
|
95
|
+
// and is cheap and static.
|
|
96
|
+
app.use('/v1/openapi.json', corsMiddleware('publicRead'));
|
|
97
|
+
app.get('/v1/openapi.json', (c) => c.json(buildOpenApiSpec(c.env.SITE_URL)));
|
|
98
|
+
/**
|
|
99
|
+
* The AEO document, at the root path answer engines actually look for. Served
|
|
100
|
+
* from the authored site document when there is one, otherwise generated from
|
|
101
|
+
* settings and published content; 404 when a site has turned it off, because
|
|
102
|
+
* an empty file would claim the site has nothing to say.
|
|
103
|
+
*/
|
|
104
|
+
app.use('/llms.txt', corsMiddleware('publicRead'));
|
|
105
|
+
app.get('/llms.txt', async (c) => {
|
|
106
|
+
const body = await resolveLlmsTxt(c.env.DB, c.env.SITE_URL);
|
|
107
|
+
if (body === null)
|
|
108
|
+
throw new HttpError('not_found', 'not found');
|
|
109
|
+
return c.body(body, 200, {
|
|
110
|
+
'Content-Type': 'text/plain; charset=UTF-8',
|
|
111
|
+
'Cache-Control': 'public, max-age=900',
|
|
112
|
+
});
|
|
113
|
+
});
|
|
114
|
+
// ---------------------------------------------------------------------------
|
|
115
|
+
// Module gates
|
|
116
|
+
// ---------------------------------------------------------------------------
|
|
117
|
+
// Authors gate on the content flag: a byline is part of content, and there is
|
|
118
|
+
// no separate authors module. Admin routes get the same gate as their public
|
|
119
|
+
// counterpart, since a module turned off entirely has no reason to leave its
|
|
120
|
+
// management API reachable.
|
|
121
|
+
app.use('/v1/posts/*', moduleGate('content'));
|
|
122
|
+
app.use('/v1/authors/*', moduleGate('content'));
|
|
123
|
+
app.use('/v1/admin/posts/*', moduleGate('content'));
|
|
124
|
+
app.use('/v1/admin/authors/*', moduleGate('content'));
|
|
125
|
+
app.use('/v1/sitemap.xml', moduleGate('seo'));
|
|
126
|
+
app.use('/v1/forms/*', moduleGate('forms'));
|
|
127
|
+
app.use('/v1/admin/forms/*', moduleGate('forms'));
|
|
128
|
+
app.use('/v1/admin/submissions/*', moduleGate('forms'));
|
|
129
|
+
app.use('/v1/events/*', moduleGate('analytics'));
|
|
130
|
+
app.use('/v1/admin/visits', moduleGate('analytics'));
|
|
131
|
+
app.use('/v1/admin/visits/stats', moduleGate('analytics'));
|
|
132
|
+
app.use('/v1/admin/consent/stats', moduleGate('analytics'));
|
|
133
|
+
app.use('/v1/media/*', moduleGate('media'));
|
|
134
|
+
app.use('/v1/admin/media/*', moduleGate('media'));
|
|
135
|
+
// ---------------------------------------------------------------------------
|
|
136
|
+
// Routes
|
|
137
|
+
// ---------------------------------------------------------------------------
|
|
138
|
+
app.route('/v1/posts', contentPublicRoutes);
|
|
139
|
+
app.route('/v1/authors', authorsPublicRoutes);
|
|
140
|
+
app.route('/v1/admin/posts', contentAdminRoutes);
|
|
141
|
+
app.route('/v1/admin/authors', authorsAdminRoutes);
|
|
142
|
+
app.route('/v1', seoPublicRoutes);
|
|
143
|
+
app.route('/v1/forms', formsPublicRoutes);
|
|
144
|
+
app.route('/v1/admin/forms', formsAdminRoutes);
|
|
145
|
+
app.route('/v1/admin/submissions', submissionsAdminRoutes);
|
|
146
|
+
app.route('/v1/events', analyticsPublicRoutes);
|
|
147
|
+
// Bare /v1/admin, not /v1/admin/analytics: these endpoints are /visits,
|
|
148
|
+
// /visits/stats, and /consent/stats with no module-name segment. app.route only
|
|
149
|
+
// prepends this prefix to the router's own sub-paths, so it cannot swallow the
|
|
150
|
+
// other /v1/admin mounts around it.
|
|
151
|
+
app.route('/v1/admin', analyticsAdminRoutes);
|
|
152
|
+
app.route('/v1/media', mediaPublicRoutes);
|
|
153
|
+
app.route('/v1/admin/media', mediaAdminRoutes);
|
|
154
|
+
app.route('/v1/admin/settings', settingsAdminRoutes);
|
|
155
|
+
app.route('/v1/documents', siteDocumentsPublicRoutes);
|
|
156
|
+
app.route('/v1/admin/documents', siteDocumentsAdminRoutes);
|
|
157
|
+
app.route('/v1/admin/aeo', aeoAdminRoutes);
|
|
158
|
+
app.route('/v1/admin/keys', keysAdminRoutes);
|
|
159
|
+
app.route('/v1/admin/users', usersAdminRoutes);
|
|
160
|
+
export default {
|
|
161
|
+
fetch: app.fetch,
|
|
162
|
+
// The daily retention sweep. The schedule is configured in wrangler.jsonc's
|
|
163
|
+
// triggers.crons.
|
|
164
|
+
async scheduled(_controller, env, _ctx) {
|
|
165
|
+
const settings = await getSettings(env.DB);
|
|
166
|
+
const result = await runRetentionCleanup(env.DB, settings.retentionDays);
|
|
167
|
+
console.log(`[retention] cleanup complete: ${JSON.stringify(result)}`);
|
|
168
|
+
},
|
|
169
|
+
};
|
|
170
|
+
//# sourceMappingURL=index.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"index.js","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1,54 @@
|
|
|
1
|
+
import { type ApiKeyKind } from '../shared/index.js';
|
|
2
|
+
import type { Bindings } from '../env.js';
|
|
3
|
+
export type KeyVariables = {
|
|
4
|
+
/** The kind of key this public request presented, once one has been validated. */
|
|
5
|
+
keyKind: ApiKeyKind;
|
|
6
|
+
};
|
|
7
|
+
/**
|
|
8
|
+
* Key validation for the public API, done inside this worker.
|
|
9
|
+
*
|
|
10
|
+
* In managed we8 the dispatch router validates the key before a request ever
|
|
11
|
+
* reaches a tenant, and the engine simply trusts what arrives. Standalone,
|
|
12
|
+
* this worker IS the front door, so the same pk/sk dialect is resolved here:
|
|
13
|
+
* the presented secret is hashed and looked up, an unknown or revoked key is
|
|
14
|
+
* a 401, and the resolved kind is put on the context for anything that cares.
|
|
15
|
+
*
|
|
16
|
+
* A handful of routes are deliberately keyless (see KEYLESS_PUBLIC_ROUTES in
|
|
17
|
+
* src/index.ts) and never mount this.
|
|
18
|
+
*/
|
|
19
|
+
export declare const publicKeyAuth: import("hono").MiddlewareHandler<{
|
|
20
|
+
Bindings: Bindings;
|
|
21
|
+
Variables: KeyVariables;
|
|
22
|
+
}, string, {}, Response>;
|
|
23
|
+
/**
|
|
24
|
+
* The public routes that need no key.
|
|
25
|
+
*
|
|
26
|
+
* Each one is keyless because its reader cannot hold a key. A crawler fetching
|
|
27
|
+
* the sitemap has no credential to present; an image in published HTML cannot
|
|
28
|
+
* carry a rotating secret without every historical page breaking on the next
|
|
29
|
+
* rotation; health and the OpenAPI document exist to be discovered before
|
|
30
|
+
* anyone has a key at all.
|
|
31
|
+
*
|
|
32
|
+
* Treat the media exemption as irreversible: once keyless media URLs are in
|
|
33
|
+
* published content, re-gating them breaks that content permanently.
|
|
34
|
+
*/
|
|
35
|
+
export declare function isKeylessPublicRoute(method: string, pathname: string): boolean;
|
|
36
|
+
/**
|
|
37
|
+
* The gate mounted across /v1/*. Admin routes fall through untouched: they are
|
|
38
|
+
* gated by session instead, and an API key presented on one is refused
|
|
39
|
+
* outright (see middleware/auth.ts).
|
|
40
|
+
*/
|
|
41
|
+
export declare const publicApiAuth: import("hono").MiddlewareHandler<{
|
|
42
|
+
Bindings: Bindings;
|
|
43
|
+
Variables: KeyVariables;
|
|
44
|
+
}, string, {}, Response>;
|
|
45
|
+
/**
|
|
46
|
+
* Narrows an already-validated public request to a secret key. A publishable
|
|
47
|
+
* key travels in browser code by design, so anything a `pk_` holder must not
|
|
48
|
+
* be able to do mounts this behind publicKeyAuth.
|
|
49
|
+
*/
|
|
50
|
+
export declare const requireSecretKey: import("hono").MiddlewareHandler<{
|
|
51
|
+
Bindings: Bindings;
|
|
52
|
+
Variables: KeyVariables;
|
|
53
|
+
}, string, {}, Response>;
|
|
54
|
+
//# sourceMappingURL=middleware.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"middleware.d.ts","sourceRoot":"","sources":["../../src/keys/middleware.ts"],"names":[],"mappings":"AACA,OAAO,EAAa,KAAK,UAAU,EAAE,MAAM,oBAAoB,CAAC;AAChE,OAAO,KAAK,EAAE,QAAQ,EAAE,MAAM,WAAW,CAAC;AAI1C,MAAM,MAAM,YAAY,GAAG;IACzB,kFAAkF;IAClF,OAAO,EAAE,UAAU,CAAC;CACrB,CAAC;AAEF;;;;;;;;;;;GAWG;AACH,eAAO,MAAM,aAAa;cAAgC,QAAQ;eAAa,YAAY;wBAe1F,CAAC;AAEF;;;;;;;;;;;GAWG;AACH,wBAAgB,oBAAoB,CAAC,MAAM,EAAE,MAAM,EAAE,QAAQ,EAAE,MAAM,GAAG,OAAO,CAO9E;AAED;;;;GAIG;AACH,eAAO,MAAM,aAAa;cAAgC,QAAQ;eAAa,YAAY;wBAa1F,CAAC;AAEF;;;;GAIG;AACH,eAAO,MAAM,gBAAgB;cAAgC,QAAQ;eAAa,YAAY;wBAO7F,CAAC"}
|
|
@@ -0,0 +1,84 @@
|
|
|
1
|
+
import { createMiddleware } from 'hono/factory';
|
|
2
|
+
import { sha256Hex } from '../shared/index.js';
|
|
3
|
+
import { HttpError } from '../lib/errors.js';
|
|
4
|
+
import { extractApiKey, lookupApiKeyByHash } from './service.js';
|
|
5
|
+
/**
|
|
6
|
+
* Key validation for the public API, done inside this worker.
|
|
7
|
+
*
|
|
8
|
+
* In managed we8 the dispatch router validates the key before a request ever
|
|
9
|
+
* reaches a tenant, and the engine simply trusts what arrives. Standalone,
|
|
10
|
+
* this worker IS the front door, so the same pk/sk dialect is resolved here:
|
|
11
|
+
* the presented secret is hashed and looked up, an unknown or revoked key is
|
|
12
|
+
* a 401, and the resolved kind is put on the context for anything that cares.
|
|
13
|
+
*
|
|
14
|
+
* A handful of routes are deliberately keyless (see KEYLESS_PUBLIC_ROUTES in
|
|
15
|
+
* src/index.ts) and never mount this.
|
|
16
|
+
*/
|
|
17
|
+
export const publicKeyAuth = createMiddleware(async (c, next) => {
|
|
18
|
+
const presented = extractApiKey(c);
|
|
19
|
+
if (!presented) {
|
|
20
|
+
throw new HttpError('unauthorized', 'missing API key');
|
|
21
|
+
}
|
|
22
|
+
const resolved = await lookupApiKeyByHash(c.env.DB, await sha256Hex(presented));
|
|
23
|
+
if (!resolved || resolved.revoked) {
|
|
24
|
+
throw new HttpError('unauthorized', 'unknown or revoked API key');
|
|
25
|
+
}
|
|
26
|
+
c.set('keyKind', resolved.kind);
|
|
27
|
+
await next();
|
|
28
|
+
});
|
|
29
|
+
/**
|
|
30
|
+
* The public routes that need no key.
|
|
31
|
+
*
|
|
32
|
+
* Each one is keyless because its reader cannot hold a key. A crawler fetching
|
|
33
|
+
* the sitemap has no credential to present; an image in published HTML cannot
|
|
34
|
+
* carry a rotating secret without every historical page breaking on the next
|
|
35
|
+
* rotation; health and the OpenAPI document exist to be discovered before
|
|
36
|
+
* anyone has a key at all.
|
|
37
|
+
*
|
|
38
|
+
* Treat the media exemption as irreversible: once keyless media URLs are in
|
|
39
|
+
* published content, re-gating them breaks that content permanently.
|
|
40
|
+
*/
|
|
41
|
+
export function isKeylessPublicRoute(method, pathname) {
|
|
42
|
+
const isRead = method === 'GET' || method === 'HEAD';
|
|
43
|
+
if (!isRead)
|
|
44
|
+
return false;
|
|
45
|
+
if (pathname === '/v1/health')
|
|
46
|
+
return true;
|
|
47
|
+
if (pathname === '/v1/openapi.json')
|
|
48
|
+
return true;
|
|
49
|
+
if (pathname === '/v1/sitemap.xml')
|
|
50
|
+
return true;
|
|
51
|
+
return pathname.startsWith('/v1/media/');
|
|
52
|
+
}
|
|
53
|
+
/**
|
|
54
|
+
* The gate mounted across /v1/*. Admin routes fall through untouched: they are
|
|
55
|
+
* gated by session instead, and an API key presented on one is refused
|
|
56
|
+
* outright (see middleware/auth.ts).
|
|
57
|
+
*/
|
|
58
|
+
export const publicApiAuth = createMiddleware(async (c, next) => {
|
|
59
|
+
// A CORS preflight can never present the key it is asking permission to
|
|
60
|
+
// send: the browser strips custom headers and credentials from OPTIONS.
|
|
61
|
+
// Demanding one here would 401 every cross-origin browser call before
|
|
62
|
+
// route-level CORS could answer, so the preflight passes through and the
|
|
63
|
+
// key check runs on the real request that follows it.
|
|
64
|
+
if (c.req.method === 'OPTIONS')
|
|
65
|
+
return next();
|
|
66
|
+
const pathname = new URL(c.req.url).pathname;
|
|
67
|
+
if (pathname.startsWith('/v1/admin'))
|
|
68
|
+
return next();
|
|
69
|
+
if (isKeylessPublicRoute(c.req.method, pathname))
|
|
70
|
+
return next();
|
|
71
|
+
return publicKeyAuth(c, next);
|
|
72
|
+
});
|
|
73
|
+
/**
|
|
74
|
+
* Narrows an already-validated public request to a secret key. A publishable
|
|
75
|
+
* key travels in browser code by design, so anything a `pk_` holder must not
|
|
76
|
+
* be able to do mounts this behind publicKeyAuth.
|
|
77
|
+
*/
|
|
78
|
+
export const requireSecretKey = createMiddleware(async (c, next) => {
|
|
79
|
+
if (c.get('keyKind') !== 'sk') {
|
|
80
|
+
throw new HttpError('forbidden', 'this endpoint requires a secret key');
|
|
81
|
+
}
|
|
82
|
+
await next();
|
|
83
|
+
});
|
|
84
|
+
//# sourceMappingURL=middleware.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"middleware.js","sourceRoot":"","sources":["../../src/keys/middleware.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,gBAAgB,EAAE,MAAM,cAAc,CAAC;AAChD,OAAO,EAAE,SAAS,EAAmB,MAAM,oBAAoB,CAAC;AAEhE,OAAO,EAAE,SAAS,EAAE,MAAM,kBAAkB,CAAC;AAC7C,OAAO,EAAE,aAAa,EAAE,kBAAkB,EAAE,MAAM,cAAc,CAAC;AAOjE;;;;;;;;;;;GAWG;AACH,MAAM,CAAC,MAAM,aAAa,GAAG,gBAAgB,CAC3C,KAAK,EAAE,CAAC,EAAE,IAAI,EAAE,EAAE;IAChB,MAAM,SAAS,GAAG,aAAa,CAAC,CAAC,CAAC,CAAC;IACnC,IAAI,CAAC,SAAS,EAAE,CAAC;QACf,MAAM,IAAI,SAAS,CAAC,cAAc,EAAE,iBAAiB,CAAC,CAAC;IACzD,CAAC;IAED,MAAM,QAAQ,GAAG,MAAM,kBAAkB,CAAC,CAAC,CAAC,GAAG,CAAC,EAAE,EAAE,MAAM,SAAS,CAAC,SAAS,CAAC,CAAC,CAAC;IAChF,IAAI,CAAC,QAAQ,IAAI,QAAQ,CAAC,OAAO,EAAE,CAAC;QAClC,MAAM,IAAI,SAAS,CAAC,cAAc,EAAE,4BAA4B,CAAC,CAAC;IACpE,CAAC;IAED,CAAC,CAAC,GAAG,CAAC,SAAS,EAAE,QAAQ,CAAC,IAAI,CAAC,CAAC;IAChC,MAAM,IAAI,EAAE,CAAC;AACf,CAAC,CACF,CAAC;AAEF;;;;;;;;;;;GAWG;AACH,MAAM,UAAU,oBAAoB,CAAC,MAAc,EAAE,QAAgB;IACnE,MAAM,MAAM,GAAG,MAAM,KAAK,KAAK,IAAI,MAAM,KAAK,MAAM,CAAC;IACrD,IAAI,CAAC,MAAM;QAAE,OAAO,KAAK,CAAC;IAC1B,IAAI,QAAQ,KAAK,YAAY;QAAE,OAAO,IAAI,CAAC;IAC3C,IAAI,QAAQ,KAAK,kBAAkB;QAAE,OAAO,IAAI,CAAC;IACjD,IAAI,QAAQ,KAAK,iBAAiB;QAAE,OAAO,IAAI,CAAC;IAChD,OAAO,QAAQ,CAAC,UAAU,CAAC,YAAY,CAAC,CAAC;AAC3C,CAAC;AAED;;;;GAIG;AACH,MAAM,CAAC,MAAM,aAAa,GAAG,gBAAgB,CAC3C,KAAK,EAAE,CAAC,EAAE,IAAI,EAAE,EAAE;IAChB,wEAAwE;IACxE,wEAAwE;IACxE,sEAAsE;IACtE,yEAAyE;IACzE,sDAAsD;IACtD,IAAI,CAAC,CAAC,GAAG,CAAC,MAAM,KAAK,SAAS;QAAE,OAAO,IAAI,EAAE,CAAC;IAC9C,MAAM,QAAQ,GAAG,IAAI,GAAG,CAAC,CAAC,CAAC,GAAG,CAAC,GAAG,CAAC,CAAC,QAAQ,CAAC;IAC7C,IAAI,QAAQ,CAAC,UAAU,CAAC,WAAW,CAAC;QAAE,OAAO,IAAI,EAAE,CAAC;IACpD,IAAI,oBAAoB,CAAC,CAAC,CAAC,GAAG,CAAC,MAAM,EAAE,QAAQ,CAAC;QAAE,OAAO,IAAI,EAAE,CAAC;IAChE,OAAO,aAAa,CAAC,CAAC,EAAE,IAAI,CAAC,CAAC;AAChC,CAAC,CACF,CAAC;AAEF;;;;GAIG;AACH,MAAM,CAAC,MAAM,gBAAgB,GAAG,gBAAgB,CAC9C,KAAK,EAAE,CAAC,EAAE,IAAI,EAAE,EAAE;IAChB,IAAI,CAAC,CAAC,GAAG,CAAC,SAAS,CAAC,KAAK,IAAI,EAAE,CAAC;QAC9B,MAAM,IAAI,SAAS,CAAC,WAAW,EAAE,qCAAqC,CAAC,CAAC;IAC1E,CAAC;IACD,MAAM,IAAI,EAAE,CAAC;AACf,CAAC,CACF,CAAC"}
|
|
@@ -0,0 +1,16 @@
|
|
|
1
|
+
import { Hono } from 'hono';
|
|
2
|
+
import type { Bindings } from '../env.js';
|
|
3
|
+
import { type AuthVariables } from '../middleware/auth.js';
|
|
4
|
+
/**
|
|
5
|
+
* API key management, owner-only.
|
|
6
|
+
*
|
|
7
|
+
* A key is site-wide credentials, and a secret key is a standing grant to
|
|
8
|
+
* whoever holds it, so minting and revoking sit with the owner rather than
|
|
9
|
+
* with every editor. The list is safe to read but stays behind the same gate:
|
|
10
|
+
* splitting the two would only mean two rules to remember.
|
|
11
|
+
*/
|
|
12
|
+
export declare const keysAdminRoutes: Hono<{
|
|
13
|
+
Bindings: Bindings;
|
|
14
|
+
Variables: AuthVariables;
|
|
15
|
+
}, import("hono/types").BlankSchema, "/">;
|
|
16
|
+
//# sourceMappingURL=routes.admin.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"routes.admin.d.ts","sourceRoot":"","sources":["../../src/keys/routes.admin.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,IAAI,EAAE,MAAM,MAAM,CAAC;AAE5B,OAAO,KAAK,EAAE,QAAQ,EAAE,MAAM,WAAW,CAAC;AAE1C,OAAO,EAAgB,KAAK,aAAa,EAAE,MAAM,uBAAuB,CAAC;AAGzE;;;;;;;GAOG;AACH,eAAO,MAAM,eAAe;cAAwB,QAAQ;eAAa,aAAa;yCAAK,CAAC"}
|
|
@@ -0,0 +1,34 @@
|
|
|
1
|
+
import { Hono } from 'hono';
|
|
2
|
+
import { apiKeyCreateInputSchema, ok } from '../shared/index.js';
|
|
3
|
+
import { parseOrThrow } from '../lib/validate.js';
|
|
4
|
+
import { requireOwner } from '../middleware/auth.js';
|
|
5
|
+
import { createApiKey, listApiKeys, revokeApiKey } from './service.js';
|
|
6
|
+
/**
|
|
7
|
+
* API key management, owner-only.
|
|
8
|
+
*
|
|
9
|
+
* A key is site-wide credentials, and a secret key is a standing grant to
|
|
10
|
+
* whoever holds it, so minting and revoking sit with the owner rather than
|
|
11
|
+
* with every editor. The list is safe to read but stays behind the same gate:
|
|
12
|
+
* splitting the two would only mean two rules to remember.
|
|
13
|
+
*/
|
|
14
|
+
export const keysAdminRoutes = new Hono();
|
|
15
|
+
keysAdminRoutes.use('*', requireOwner);
|
|
16
|
+
keysAdminRoutes.get('/', async (c) => {
|
|
17
|
+
const items = await listApiKeys(c.env.DB);
|
|
18
|
+
return c.json(ok({ items }));
|
|
19
|
+
});
|
|
20
|
+
/**
|
|
21
|
+
* The one response in this API that carries a secret. The plaintext exists
|
|
22
|
+
* here and nowhere else, ever again, so the admin must show it once and say
|
|
23
|
+
* so; every later read returns the prefix only.
|
|
24
|
+
*/
|
|
25
|
+
keysAdminRoutes.post('/', async (c) => {
|
|
26
|
+
const input = parseOrThrow(apiKeyCreateInputSchema, await c.req.json());
|
|
27
|
+
const key = await createApiKey(c.env.DB, input.kind, input.label);
|
|
28
|
+
return c.json(ok({ key }), 201);
|
|
29
|
+
});
|
|
30
|
+
keysAdminRoutes.delete('/:id', async (c) => {
|
|
31
|
+
const key = await revokeApiKey(c.env.DB, c.req.param('id'));
|
|
32
|
+
return c.json(ok({ key }));
|
|
33
|
+
});
|
|
34
|
+
//# sourceMappingURL=routes.admin.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"routes.admin.js","sourceRoot":"","sources":["../../src/keys/routes.admin.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,IAAI,EAAE,MAAM,MAAM,CAAC;AAC5B,OAAO,EAAE,uBAAuB,EAAE,EAAE,EAAE,MAAM,oBAAoB,CAAC;AAEjE,OAAO,EAAE,YAAY,EAAE,MAAM,oBAAoB,CAAC;AAClD,OAAO,EAAE,YAAY,EAAsB,MAAM,uBAAuB,CAAC;AACzE,OAAO,EAAE,YAAY,EAAE,WAAW,EAAE,YAAY,EAAE,MAAM,cAAc,CAAC;AAEvE;;;;;;;GAOG;AACH,MAAM,CAAC,MAAM,eAAe,GAAG,IAAI,IAAI,EAAoD,CAAC;AAE5F,eAAe,CAAC,GAAG,CAAC,GAAG,EAAE,YAAY,CAAC,CAAC;AAEvC,eAAe,CAAC,GAAG,CAAC,GAAG,EAAE,KAAK,EAAE,CAAC,EAAE,EAAE;IACnC,MAAM,KAAK,GAAG,MAAM,WAAW,CAAC,CAAC,CAAC,GAAG,CAAC,EAAE,CAAC,CAAC;IAC1C,OAAO,CAAC,CAAC,IAAI,CAAC,EAAE,CAAC,EAAE,KAAK,EAAE,CAAC,CAAC,CAAC;AAC/B,CAAC,CAAC,CAAC;AAEH;;;;GAIG;AACH,eAAe,CAAC,IAAI,CAAC,GAAG,EAAE,KAAK,EAAE,CAAC,EAAE,EAAE;IACpC,MAAM,KAAK,GAAG,YAAY,CAAC,uBAAuB,EAAE,MAAM,CAAC,CAAC,GAAG,CAAC,IAAI,EAAE,CAAC,CAAC;IACxE,MAAM,GAAG,GAAG,MAAM,YAAY,CAAC,CAAC,CAAC,GAAG,CAAC,EAAE,EAAE,KAAK,CAAC,IAAI,EAAE,KAAK,CAAC,KAAK,CAAC,CAAC;IAClE,OAAO,CAAC,CAAC,IAAI,CAAC,EAAE,CAAC,EAAE,GAAG,EAAE,CAAC,EAAE,GAAG,CAAC,CAAC;AAClC,CAAC,CAAC,CAAC;AAEH,eAAe,CAAC,MAAM,CAAC,MAAM,EAAE,KAAK,EAAE,CAAC,EAAE,EAAE;IACzC,MAAM,GAAG,GAAG,MAAM,YAAY,CAAC,CAAC,CAAC,GAAG,CAAC,EAAE,EAAE,CAAC,CAAC,GAAG,CAAC,KAAK,CAAC,IAAI,CAAC,CAAC,CAAC;IAC5D,OAAO,CAAC,CAAC,IAAI,CAAC,EAAE,CAAC,EAAE,GAAG,EAAE,CAAC,CAAC,CAAC;AAC7B,CAAC,CAAC,CAAC"}
|