@beechcms/api 0.4.0-preview.12 → 0.4.0-preview.13

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.
Files changed (85) hide show
  1. package/assets/dashboard/BeechLogo.svg +18 -18
  2. package/assets/dashboard/BeechLogoLIght.svg +48 -48
  3. package/assets/dashboard/assets/index-CewtCjom.css +1 -0
  4. package/assets/dashboard/assets/{index-CTSuGxlX.js → index-FQ6JhvRH.js} +99 -99
  5. package/assets/dashboard/beechLogoDark.svg +48 -48
  6. package/assets/dashboard/index.html +18 -18
  7. package/assets/dashboard/sol.svg +3 -3
  8. package/assets/dashboard/undraw_enter_nwx3.svg +36 -36
  9. package/migrations/0000_v040_base.sql +213 -213
  10. package/package.json +2 -2
  11. package/src/auth/constants.ts +10 -10
  12. package/src/auth/login.ts +91 -91
  13. package/src/auth/refresh.ts +127 -127
  14. package/src/factory.ts +347 -325
  15. package/src/features/content/constants.ts +10 -10
  16. package/src/features/content/handlers/create.ts +153 -163
  17. package/src/features/content/handlers/delete.ts +76 -85
  18. package/src/features/content/handlers/facets.ts +45 -45
  19. package/src/features/content/handlers/get.ts +116 -116
  20. package/src/features/content/handlers/list.ts +88 -88
  21. package/src/features/content/handlers/update.ts +207 -216
  22. package/src/features/content/index.ts +20 -20
  23. package/src/features/draft/draft.handler.ts +272 -272
  24. package/src/features/draft/index.ts +1 -1
  25. package/src/features/email/email.provider.ts +38 -38
  26. package/src/features/email/email.service.ts +80 -80
  27. package/src/features/email/email.types.ts +98 -98
  28. package/src/features/email/index.ts +28 -28
  29. package/src/features/email/providers/resend.ts +63 -63
  30. package/src/features/email/templates/password-changed.ts +59 -59
  31. package/src/features/email/templates/password-reset.ts +64 -64
  32. package/src/features/email/templates/shell.ts +92 -93
  33. package/src/features/notifications/index.ts +1 -1
  34. package/src/features/notifications/notifications.handler.ts +130 -88
  35. package/src/features/password-reset/index.ts +15 -15
  36. package/src/features/password-reset/request.ts +106 -88
  37. package/src/features/password-reset/reset.ts +128 -110
  38. package/src/features/rotate-field/index.ts +1 -1
  39. package/src/features/rotate-field/rotate-field.handler.ts +132 -82
  40. package/src/features/rotate-field/rotate-field.schema.ts +13 -9
  41. package/src/features/schema/schema.handler.ts +16 -16
  42. package/src/features/settings/settings.handler.ts +414 -267
  43. package/src/features/setup/index.ts +96 -59
  44. package/src/features/stats/index.ts +1 -1
  45. package/src/features/stats/stats.handler.ts +458 -395
  46. package/src/index.ts +24 -24
  47. package/src/media-utils.ts +78 -78
  48. package/src/middleware/repository.middleware.ts +24 -18
  49. package/src/middleware/storage.middleware.ts +21 -0
  50. package/src/middleware.ts +67 -67
  51. package/src/public/access-policy.ts +23 -23
  52. package/src/public/api-key-middleware.ts +53 -53
  53. package/src/public/index.ts +12 -12
  54. package/src/public/problem-details.ts +48 -42
  55. package/src/public/public-add.ts +166 -166
  56. package/src/public/public-edit.ts +158 -158
  57. package/src/public/public-errors.ts +15 -15
  58. package/src/public/public-read.ts +216 -216
  59. package/src/public/public-routes.ts +84 -31
  60. package/src/public/query-builder.ts +152 -152
  61. package/src/public/rate-limit-middleware.ts +42 -42
  62. package/src/public/response-builder.ts +26 -26
  63. package/src/public/sanitize.ts +65 -65
  64. package/src/public/slug-utils.ts +14 -14
  65. package/src/search-utils.ts +192 -192
  66. package/src/search.ts +72 -72
  67. package/src/shared/activity-logger.ts +79 -79
  68. package/src/shared/apply-policies.ts +63 -63
  69. package/src/shared/base.repository.d1.ts +28 -28
  70. package/src/shared/content-utils.ts +82 -108
  71. package/src/shared/content.repository.d1.ts +382 -382
  72. package/src/shared/fts-sync.ts +4 -4
  73. package/src/shared/idempotency.repository.d1.ts +56 -45
  74. package/src/shared/media.repository.d1.ts +64 -0
  75. package/src/shared/notification-service.ts +56 -56
  76. package/src/shared/query-utils.ts +137 -137
  77. package/src/shared/storage/factory.ts +40 -0
  78. package/src/shared/storage/r2-binding-bucket.ts +81 -0
  79. package/src/shared/storage/s3-bucket.ts +163 -0
  80. package/src/shared/storage-utils.ts +36 -36
  81. package/src/shared/system-stats.repository.d1.ts +44 -0
  82. package/src/types.ts +46 -41
  83. package/src/upload.ts +179 -331
  84. package/src/widget.ts +349 -349
  85. package/assets/dashboard/assets/index-ye3325L9.css +0 -1
@@ -1,59 +1,59 @@
1
- import type { EmailLocale } from '../email.types'
2
- import { buildEmailShell } from './shell'
3
-
4
- /**
5
- * Testi localizzati per la notifica di sicurezza "password modificata".
6
- *
7
- * ─── AGGIUNGERE UNA NUOVA LINGUA ─────────────────────────────────────────────
8
- * Vedi le istruzioni in `templates/password-reset.ts`.
9
- * ─────────────────────────────────────────────────────────────────────────────
10
- */
11
- const COPY: Record<EmailLocale, {
12
- subject: string
13
- title: string
14
- body: string
15
- warning: string
16
- footer: string
17
- }> = {
18
- en: {
19
- subject: 'Your Beech CMS password has been changed',
20
- title: 'Your password has been changed',
21
- body: 'Your Beech CMS account password was successfully changed. If you made this change, no action is needed.',
22
- warning:
23
- 'If you did not make this change, your account may be compromised. Contact your administrator immediately.',
24
- footer: 'This is an automated security notification. Do not reply to this email.',
25
- },
26
- it: {
27
- subject: 'La tua password Beech CMS è stata modificata',
28
- title: 'La tua password è stata modificata',
29
- body: 'La password del tuo account Beech CMS è stata modificata con successo. Se hai effettuato tu questa modifica, non devi fare nulla.',
30
- warning:
31
- 'Se non hai effettuato tu questa modifica, il tuo account potrebbe essere compromesso. Contatta immediatamente il tuo amministratore.',
32
- footer: 'Questa è una notifica di sicurezza automatica. Non rispondere a questa email.',
33
- },
34
- }
35
-
36
- /**
37
- * Costruisce l'email di notifica "password modificata".
38
- *
39
- * Questa email non ha un pulsante CTA — è una pura notifica di sicurezza.
40
- * Il blocco `warning` (testo rosso) avvisa l'utente di agire se non è
41
- * stato lui a modificare la password.
42
- *
43
- * @param locale - Lingua per oggetto e corpo dell'email.
44
- * @returns Oggetto con `subject` (stringa) e `html` (documento HTML completo).
45
- */
46
- export function buildPasswordChangedEmail(
47
- locale: EmailLocale,
48
- ): { subject: string; html: string } {
49
- const c = COPY[locale]
50
- return {
51
- subject: c.subject,
52
- html: buildEmailShell(locale, {
53
- title: c.title,
54
- body: c.body,
55
- warning: c.warning,
56
- footer: c.footer,
57
- }),
58
- }
59
- }
1
+ import type { EmailLocale } from '../email.types'
2
+ import { buildEmailShell } from './shell'
3
+
4
+ /**
5
+ * Localized texts for the "password changed" security notification.
6
+ *
7
+ * ─── ADDING A NEW LANGUAGE ──────────────────────────────────────────────────
8
+ * See instructions in `templates/password-reset.ts`.
9
+ * ─────────────────────────────────────────────────────────────────────────────
10
+ */
11
+ const COPY: Record<EmailLocale, {
12
+ subject: string
13
+ title: string
14
+ body: string
15
+ warning: string
16
+ footer: string
17
+ }> = {
18
+ en: {
19
+ subject: 'Your Beech CMS password has been changed',
20
+ title: 'Your password has been changed',
21
+ body: 'Your Beech CMS account password was successfully changed. If you made this change, no action is needed.',
22
+ warning:
23
+ 'If you did not make this change, your account may be compromised. Contact your administrator immediately.',
24
+ footer: 'This is an automated security notification. Do not reply to this email.',
25
+ },
26
+ it: {
27
+ subject: 'La tua password Beech CMS è stata modificata',
28
+ title: 'La tua password è stata modificata',
29
+ body: 'La password del tuo account Beech CMS è stata modificata con successo. Se hai effettuato tu questa modifica, non devi fare nulla.',
30
+ warning:
31
+ 'Se non hai effettuato tu questa modifica, il tuo account potrebbe essere compromesso. Contatta immediatamente il tuo amministratore.',
32
+ footer: 'Questa è una notifica di sicurezza automatica. Non rispondere a questa email.',
33
+ },
34
+ }
35
+
36
+ /**
37
+ * Builds the "password changed" notification email.
38
+ *
39
+ * This email does not have a CTA button it is a pure security notification.
40
+ * The `warning` block (red text) warns the user to take action if they
41
+ * were not the one who changed the password.
42
+ *
43
+ * @param locale - Language for the email subject and body.
44
+ * @returns Object with `subject` (string) and `html` (complete HTML document).
45
+ */
46
+ export function buildPasswordChangedEmail(
47
+ locale: EmailLocale,
48
+ ): { subject: string; html: string } {
49
+ const c = COPY[locale]
50
+ return {
51
+ subject: c.subject,
52
+ html: buildEmailShell(locale, {
53
+ title: c.title,
54
+ body: c.body,
55
+ warning: c.warning,
56
+ footer: c.footer,
57
+ }),
58
+ }
59
+ }
@@ -1,64 +1,64 @@
1
- import type { EmailLocale } from '../email.types'
2
- import { buildEmailShell } from './shell'
3
-
4
- /**
5
- * Testi localizzati per l'email di reset password.
6
- *
7
- * ─── AGGIUNGERE UNA NUOVA LINGUA ─────────────────────────────────────────────
8
- * 1. Aggiungi il codice ISO in `SUPPORTED_EMAIL_LOCALES` (email.types.ts).
9
- * 2. Aggiungi una chiave corrispondente in questo oggetto con tutti i campi.
10
- * TypeScript segnala immediatamente le chiavi mancanti grazie a
11
- * `Record<EmailLocale, …>`.
12
- * ─────────────────────────────────────────────────────────────────────────────
13
- */
14
- const COPY: Record<EmailLocale, {
15
- subject: string
16
- title: string
17
- body: string
18
- ctaLabel: string
19
- footer: string
20
- }> = {
21
- en: {
22
- subject: 'Reset your Beech CMS password',
23
- title: 'Reset your password',
24
- body: 'You requested a password reset for your Beech CMS account. Click the button below to set a new password. This link expires in 30 minutes.',
25
- ctaLabel: 'Reset password',
26
- footer: "If you didn't request this, you can safely ignore this email.",
27
- },
28
- it: {
29
- subject: 'Reimposta la tua password Beech CMS',
30
- title: 'Reimposta la tua password',
31
- body: 'Hai richiesto il reset della password per il tuo account Beech CMS. Clicca il pulsante qui sotto per impostare una nuova password. Questo link scade tra 30 minuti.',
32
- ctaLabel: 'Reimposta password',
33
- footer: 'Se non hai richiesto questo, puoi ignorare questa email in tutta sicurezza.',
34
- },
35
- }
36
-
37
- /**
38
- * Costruisce l'email con il link di reset password.
39
- *
40
- * Compone il contenuto localizzato con il layout base (`buildEmailShell`)
41
- * iniettando il pulsante CTA che punta all'URL di reset.
42
- *
43
- * @param resetUrl - URL completo con il token in chiaro, es.
44
- * `https://dashboard.beechcms.dev/reset-password?token=<uuid>`.
45
- * Viene incorporato direttamente nel pulsante CTA — non sanificare
46
- * ulteriormente: il token è un UUID generato internamente.
47
- * @param locale - Lingua per oggetto e corpo dell'email.
48
- * @returns Oggetto con `subject` (stringa) e `html` (documento HTML completo).
49
- */
50
- export function buildPasswordResetEmail(
51
- resetUrl: string,
52
- locale: EmailLocale,
53
- ): { subject: string; html: string } {
54
- const c = COPY[locale]
55
- return {
56
- subject: c.subject,
57
- html: buildEmailShell(locale, {
58
- title: c.title,
59
- body: c.body,
60
- cta: { label: c.ctaLabel, href: resetUrl },
61
- footer: c.footer,
62
- }),
63
- }
64
- }
1
+ import type { EmailLocale } from '../email.types'
2
+ import { buildEmailShell } from './shell'
3
+
4
+ /**
5
+ * Localized texts for the password reset email.
6
+ *
7
+ * ─── ADDING A NEW LANGUAGE ──────────────────────────────────────────────────
8
+ * 1. Add the ISO code in `SUPPORTED_EMAIL_LOCALES` (`email.types.ts`).
9
+ * 2. Add a corresponding key in this object with all fields.
10
+ * TypeScript immediately reports missing keys thanks to
11
+ * `Record<EmailLocale, …>`.
12
+ * ─────────────────────────────────────────────────────────────────────────────
13
+ */
14
+ const COPY: Record<EmailLocale, {
15
+ subject: string
16
+ title: string
17
+ body: string
18
+ ctaLabel: string
19
+ footer: string
20
+ }> = {
21
+ en: {
22
+ subject: 'Reset your Beech CMS password',
23
+ title: 'Reset your password',
24
+ body: 'You requested a password reset for your Beech CMS account. Click the button below to set a new password. This link expires in 30 minutes.',
25
+ ctaLabel: 'Reset password',
26
+ footer: "If you didn't request this, you can safely ignore this email.",
27
+ },
28
+ it: {
29
+ subject: 'Reimposta la tua password Beech CMS',
30
+ title: 'Reimposta la tua password',
31
+ body: 'Hai richiesto il reset della password per il tuo account Beech CMS. Clicca il pulsante qui sotto per impostare una nuova password. Questo link scade tra 30 minuti.',
32
+ ctaLabel: 'Reimposta password',
33
+ footer: 'Se non hai richiesto questo, puoi ignorare questa email in tutta sicurezza.',
34
+ },
35
+ }
36
+
37
+ /**
38
+ * Builds the email with the password reset link.
39
+ *
40
+ * Composes the localized content with the base layout (`buildEmailShell`)
41
+ * injecting the CTA button pointing to the reset URL.
42
+ *
43
+ * @param resetUrl - Complete URL with the token in plain text, e.g.
44
+ * `https://dashboard.beechcms.dev/reset-password?token=<uuid>`.
45
+ * It is directly embedded in the CTA button do not sanitize
46
+ * further: the token is an internally generated UUID.
47
+ * @param locale - Language for the email subject and body.
48
+ * @returns Object with `subject` (string) and `html` (complete HTML document).
49
+ */
50
+ export function buildPasswordResetEmail(
51
+ resetUrl: string,
52
+ locale: EmailLocale,
53
+ ): { subject: string; html: string } {
54
+ const c = COPY[locale]
55
+ return {
56
+ subject: c.subject,
57
+ html: buildEmailShell(locale, {
58
+ title: c.title,
59
+ body: c.body,
60
+ cta: { label: c.ctaLabel, href: resetUrl },
61
+ footer: c.footer,
62
+ }),
63
+ }
64
+ }
@@ -1,93 +1,92 @@
1
- import type { EmailLocale } from '../email.types'
2
-
3
- /**
4
- * Slot di contenuto che ogni template deve fornire per comporre un'email completa.
5
- * Ogni slot corrisponde a un blocco visivo nel layout della card email.
6
- */
7
- export interface EmailShellSlots {
8
- /**
9
- * Heading H2 mostrato in cima alla card. Mantienilo sotto ~50 caratteri
10
- * per garantire una buona leggibilità su client mobile.
11
- */
12
- title: string
13
-
14
- /**
15
- * Testo principale del corpo. Renderizzato come paragrafo.
16
- * È ammesso HTML inline sicuro (es. `<strong>`, `<a href="...">`),
17
- * ma evita elementi block (`<p>`, `<div>`) che potrebbero rompere
18
- * la struttura del layout in client email rigidi (Outlook, Gmail).
19
- */
20
- body: string
21
-
22
- /**
23
- * Pulsante call-to-action opzionale, renderizzato come link-button scuro.
24
- * Ometti per email di sola notifica che non richiedono azione da parte dell'utente.
25
- */
26
- cta?: { label: string; href: string }
27
-
28
- /**
29
- * Paragrafo di avviso opzionale. Renderizzato in rosso (#ef4444) per attirare
30
- * l'attenzione. Usalo per avvisi di sicurezza
31
- * ("se non sei stato tu, agisci immediatamente").
32
- */
33
- warning?: string
34
-
35
- /**
36
- * Testo piccolo grigio in fondo alla card.
37
- * Usato per note del tipo "notifica automatica, non rispondere".
38
- */
39
- footer: string
40
- }
41
-
42
- /**
43
- * Costruisce il layout HTML base condiviso da tutte le email transazionali
44
- * di Beech CMS.
45
- *
46
- * ─── FONTE UNICA DI VERITÀ PER IL BRANDING ───────────────────────────────────
47
- * Modificare questa funzione cambia l'aspetto visivo di TUTTE le email
48
- * in uscita contemporaneamente:
49
- * - colore di sfondo e della card
50
- * - stile del bordo e del border-radius
51
- * - scala tipografica e spaziatura
52
- * - stile del pulsante CTA
53
- *
54
- * Per cambiare il testo o la struttura di una email specifica, modifica invece
55
- * il file template corrispondente (`templates/password-reset.ts`, ecc.).
56
- * ─────────────────────────────────────────────────────────────────────────────
57
- *
58
- * @param locale - Usato per l'attributo `lang` del tag `<html>`.
59
- * @param slots - Blocchi di contenuto iniettati nel layout.
60
- * @returns Un documento HTML completo e self-contained pronto per l'invio.
61
- */
62
- export function buildEmailShell(locale: EmailLocale, slots: EmailShellSlots): string {
63
- const ctaBlock = slots.cta
64
- ? `<a href="${slots.cta.href}"
65
- style="display:inline-block;background:#111;color:#fff;padding:12px 24px;
66
- border-radius:6px;text-decoration:none;font-size:15px;font-weight:500;
67
- margin-bottom:24px">
68
- ${slots.cta.label}
69
- </a>`
70
- : ''
71
-
72
- const warningBlock = slots.warning
73
- ? `<p style="margin:0 0 24px;color:#ef4444;font-size:15px;line-height:1.5;font-weight:500">
74
- ${slots.warning}
75
- </p>`
76
- : ''
77
-
78
- return `<!DOCTYPE html>
79
- <html lang="${locale}">
80
- <head>
81
- <meta charset="UTF-8">
82
- <meta name="viewport" content="width=device-width,initial-scale=1">
83
- </head>
84
- <body style="font-family:sans-serif;background:#f9f9f9;margin:0;padding:32px">
85
- <div style="max-width:480px;margin:0 auto;background:#fff;border-radius:8px;
86
- padding:32px;border:1px solid #e5e5e5">
87
- <h2 style="margin:0 0 16px;font-size:20px;color:#111">${slots.title}</h2>
88
- <p style="margin:0 0 24px;color:#555;font-size:15px;line-height:1.5">${slots.body}</p>
89
- ${ctaBlock}${warningBlock}<p style="margin:0;color:#999;font-size:13px">${slots.footer}</p>
90
- </div>
91
- </body>
92
- </html>`
93
- }
1
+ import type { EmailLocale } from '../email.types'
2
+
3
+ /**
4
+ * Content slots that every template must provide to compose a complete email.
5
+ * Each slot corresponds to a visual block in the email card layout.
6
+ */
7
+ export interface EmailShellSlots {
8
+ /**
9
+ * H2 heading shown at the top of the card. Keep it under ~50 characters
10
+ * to ensure good readability on mobile clients.
11
+ */
12
+ title: string
13
+
14
+ /**
15
+ * Main body text. Rendered as a paragraph.
16
+ * Safe inline HTML is allowed (e.g., `<strong>`, `<a href="...">`),
17
+ * but avoid block elements (`<p>`, `<div>`) that could break
18
+ * the layout structure in rigid email clients (Outlook, Gmail).
19
+ */
20
+ body: string
21
+
22
+ /**
23
+ * Optional call-to-action button, rendered as a dark link-button.
24
+ * Omit for notification-only emails that do not require user action.
25
+ */
26
+ cta?: { label: string; href: string }
27
+
28
+ /**
29
+ * Optional warning paragraph. Rendered in red (#ef4444) to attract
30
+ * attention. Use it for security alerts
31
+ * ("if it wasn't you, act immediately").
32
+ */
33
+ warning?: string
34
+
35
+ /**
36
+ * Small gray text at the bottom of the card.
37
+ * Used for notes like "automated notification, do not reply".
38
+ */
39
+ footer: string
40
+ }
41
+
42
+ /**
43
+ * Builds the base HTML layout shared by all Beech CMS transactional emails.
44
+ *
45
+ * ─── SINGLE SOURCE OF TRUTH FOR BRANDING ─────────────────────────────────────
46
+ * Modifying this function changes the visual appearance of ALL outgoing emails
47
+ * simultaneously:
48
+ * - background and card color
49
+ * - border style and border-radius
50
+ * - typographic scale and spacing
51
+ * - CTA button style
52
+ *
53
+ * To change the text or structure of a specific email, instead modify
54
+ * the corresponding template file (`templates/password-reset.ts`, etc.).
55
+ * ─────────────────────────────────────────────────────────────────────────────
56
+ *
57
+ * @param locale - Used for the `lang` attribute of the `<html>` tag.
58
+ * @param slots - Content blocks injected into the layout.
59
+ * @returns A complete and self-contained HTML document ready to be sent.
60
+ */
61
+ export function buildEmailShell(locale: EmailLocale, slots: EmailShellSlots): string {
62
+ const ctaBlock = slots.cta
63
+ ? `<a href="${slots.cta.href}"
64
+ style="display:inline-block;background:#111;color:#fff;padding:12px 24px;
65
+ border-radius:6px;text-decoration:none;font-size:15px;font-weight:500;
66
+ margin-bottom:24px">
67
+ ${slots.cta.label}
68
+ </a>`
69
+ : ''
70
+
71
+ const warningBlock = slots.warning
72
+ ? `<p style="margin:0 0 24px;color:#ef4444;font-size:15px;line-height:1.5;font-weight:500">
73
+ ${slots.warning}
74
+ </p>`
75
+ : ''
76
+
77
+ return `<!DOCTYPE html>
78
+ <html lang="${locale}">
79
+ <head>
80
+ <meta charset="UTF-8">
81
+ <meta name="viewport" content="width=device-width,initial-scale=1">
82
+ </head>
83
+ <body style="font-family:sans-serif;background:#f9f9f9;margin:0;padding:32px">
84
+ <div style="max-width:480px;margin:0 auto;background:#fff;border-radius:8px;
85
+ padding:32px;border:1px solid #e5e5e5">
86
+ <h2 style="margin:0 0 16px;font-size:20px;color:#111">${slots.title}</h2>
87
+ <p style="margin:0 0 24px;color:#555;font-size:15px;line-height:1.5">${slots.body}</p>
88
+ ${ctaBlock}${warningBlock}<p style="margin:0;color:#999;font-size:13px">${slots.footer}</p>
89
+ </div>
90
+ </body>
91
+ </html>`
92
+ }
@@ -1 +1 @@
1
- export { notificationsApp } from './notifications.handler'
1
+ export { notificationsApp } from './notifications.handler'