@beechcms/api 0.6.0-preview.2 → 0.6.0-preview.4
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +4 -4
- package/assets/dashboard/BeechLogo.svg +18 -18
- package/assets/dashboard/BeechLogoLIght.svg +48 -48
- package/assets/dashboard/assets/chart-BwlCt-IA.js +39 -0
- package/assets/dashboard/assets/geist-cyrillic-ext-wght-normal-DjL33-gN.woff2 +0 -0
- package/assets/dashboard/assets/geist-cyrillic-wght-normal-BEAKL7Jp.woff2 +0 -0
- package/assets/dashboard/assets/geist-latin-ext-wght-normal-DC-KSUi6.woff2 +0 -0
- package/assets/dashboard/assets/geist-latin-wght-normal-BgDaEnEv.woff2 +0 -0
- package/assets/dashboard/assets/geist-vietnamese-wght-normal-6IgcOCM7.woff2 +0 -0
- package/assets/dashboard/assets/index-BcVN-DNy.js +642 -0
- package/assets/dashboard/assets/index-Cf1yRCqG.css +1 -0
- package/assets/dashboard/assets/lora-cyrillic-ext-wght-normal-YcVxMP-u.woff2 +0 -0
- package/assets/dashboard/assets/lora-cyrillic-wght-normal-UWPuZLjM.woff2 +0 -0
- package/assets/dashboard/assets/lora-latin-ext-wght-normal-C2Wlntb9.woff2 +0 -0
- package/assets/dashboard/assets/lora-latin-wght-normal-BiLcIKcI.woff2 +0 -0
- package/assets/dashboard/assets/lora-math-wght-normal-sOy7rEfW.woff2 +0 -0
- package/assets/dashboard/assets/lora-symbols-wght-normal-DQ5VrUkH.woff2 +0 -0
- package/assets/dashboard/assets/lora-vietnamese-wght-normal-CfJ7gtf3.woff2 +0 -0
- package/assets/dashboard/assets/pie-chart-recharts-BMWpjFzf.js +1 -0
- package/assets/dashboard/assets/timeseries-chart-recharts-8_GwAFR0.js +1 -0
- package/assets/dashboard/beechLogoDark.svg +48 -48
- package/assets/dashboard/index.html +18 -18
- package/assets/dashboard/noResult.svg +42 -42
- package/assets/dashboard/sol.svg +3 -3
- package/assets/dashboard/undraw_enter_nwx3.svg +36 -36
- package/dist/auth/__fixtures__/in-memory-hash-provider.d.ts +5 -0
- package/dist/auth/__fixtures__/static-token-service.d.ts +6 -0
- package/dist/auth/bcrypt-hash-provider.d.ts +8 -0
- package/dist/auth/constants.d.ts +10 -0
- package/dist/auth/jose-token-service.d.ts +14 -0
- package/dist/auth/login.d.ts +32 -0
- package/dist/auth/refresh.d.ts +1 -0
- package/dist/factory.d.ts +45 -0
- package/dist/features/automations/action-executors/create-entry.executor.d.ts +7 -0
- package/dist/features/automations/action-executors/edit-field.executor.d.ts +7 -0
- package/dist/features/automations/action-executors/index.d.ts +13 -0
- package/dist/features/automations/action-executors/send-mail.executor.d.ts +7 -0
- package/dist/features/automations/action-executors/set-variable.executor.d.ts +15 -0
- package/dist/features/automations/action-executors/webhook.executor.d.ts +7 -0
- package/dist/features/automations/automation-runner.d.ts +13 -0
- package/dist/features/automations/automation-runner.utils.d.ts +3 -0
- package/dist/features/automations/automations.handler.d.ts +7 -0
- package/dist/features/automations/automations.schema.d.ts +191 -0
- package/dist/features/automations/context-resolver.d.ts +8 -0
- package/dist/features/automations/cron-runner.d.ts +9 -0
- package/dist/features/automations/cron-runner.utils.d.ts +1 -0
- package/dist/features/automations/filter-translation.d.ts +9 -0
- package/dist/features/automations/index.d.ts +7 -0
- package/dist/features/automations/template-grammar.d.ts +73 -0
- package/dist/features/automations/var-access-resolver.d.ts +6 -0
- package/dist/features/automations/when-evaluator.d.ts +3 -0
- package/dist/features/automations/when-pushdown.d.ts +2 -0
- package/dist/features/backrefs/backrefs.handler.d.ts +3 -0
- package/dist/features/backrefs/d1-backref.repository.d.ts +17 -0
- package/dist/features/backrefs/index.d.ts +1 -0
- package/dist/features/content/constants.d.ts +12 -0
- package/dist/features/content/handlers/bulk.handler.d.ts +3 -0
- package/dist/features/content/handlers/create.d.ts +3 -0
- package/dist/features/content/handlers/delete.d.ts +3 -0
- package/dist/features/content/handlers/facets.d.ts +3 -0
- package/dist/features/content/handlers/get.d.ts +4 -0
- package/dist/features/content/handlers/helpers.d.ts +12 -0
- package/dist/features/content/handlers/list.d.ts +3 -0
- package/dist/features/content/handlers/update.d.ts +3 -0
- package/dist/features/content/index.d.ts +4 -0
- package/dist/features/dashboard-layout/dashboard-layout.handler.d.ts +7 -0
- package/dist/features/dashboard-layout/index.d.ts +1 -0
- package/dist/features/draft/draft.handler.d.ts +4 -0
- package/dist/features/draft/draft.middleware.d.ts +9 -0
- package/dist/features/draft/index.d.ts +1 -0
- package/{src/features/email/email.provider.ts → dist/features/email/email.provider.d.ts} +19 -24
- package/dist/features/email/email.service.d.ts +13 -0
- package/dist/features/email/email.types.d.ts +94 -0
- package/{src/features/email/index.ts → dist/features/email/index.d.ts} +3 -16
- package/dist/features/email/providers/resend.d.ts +36 -0
- package/dist/features/email/providers/smtp.d.ts +11 -0
- package/dist/features/email/templates/automation-mail.d.ts +8 -0
- package/dist/features/email/templates/password-changed.d.ts +15 -0
- package/dist/features/email/templates/password-reset.d.ts +18 -0
- package/dist/features/email/templates/shell.d.ts +58 -0
- package/dist/features/notifications/index.d.ts +1 -0
- package/dist/features/notifications/notifications.handler.d.ts +15 -0
- package/dist/features/password-reset/index.d.ts +6 -0
- package/dist/features/password-reset/request.d.ts +10 -0
- package/dist/features/password-reset/reset.d.ts +9 -0
- package/dist/features/rotate-field/index.d.ts +1 -0
- package/dist/features/rotate-field/rotate-field.handler.d.ts +7 -0
- package/dist/features/rotate-field/rotate-field.schema.d.ts +11 -0
- package/dist/features/schema/schema.handler.d.ts +7 -0
- package/dist/features/seeds/index.d.ts +1 -0
- package/dist/features/seeds/seeds.handler.d.ts +6 -0
- package/dist/features/settings/settings.handler.d.ts +7 -0
- package/dist/features/setup/index.d.ts +7 -0
- package/dist/features/stats/index.d.ts +1 -0
- package/dist/features/stats/stats.handler.d.ts +7 -0
- package/dist/features/webhooks/index.d.ts +3 -0
- package/dist/index.d.ts +7 -0
- package/dist/index.js +9732 -0
- package/dist/media-utils.d.ts +25 -0
- package/dist/middleware/auth-providers.middleware.d.ts +8 -0
- package/dist/middleware/observability.middleware.d.ts +20 -0
- package/dist/middleware/queue.middleware.d.ts +11 -0
- package/dist/middleware/rate-limit.middleware.d.ts +9 -0
- package/dist/middleware/repository.middleware.d.ts +34 -0
- package/dist/middleware/seed-registry.middleware.d.ts +10 -0
- package/dist/middleware/storage.middleware.d.ts +7 -0
- package/dist/middleware.d.ts +11 -0
- package/dist/public/access-policy.d.ts +12 -0
- package/dist/public/api-key-middleware.d.ts +6 -0
- package/dist/public/cache-utils.d.ts +10 -0
- package/dist/public/entry-projection.d.ts +2 -0
- package/dist/public/idempotency.d.ts +9 -0
- package/dist/public/index.d.ts +11 -0
- package/dist/public/problem-details.d.ts +31 -0
- package/dist/public/public-add.d.ts +3 -0
- package/dist/public/public-edit.d.ts +5 -0
- package/dist/public/public-errors.d.ts +13 -0
- package/dist/public/public-read.d.ts +3 -0
- package/dist/public/public-routes.d.ts +3 -0
- package/dist/public/query-builder.d.ts +28 -0
- package/dist/public/rate-limit-middleware.d.ts +3 -0
- package/dist/public/read-list.d.ts +26 -0
- package/dist/public/read-single.d.ts +22 -0
- package/dist/public/response-builder.d.ts +22 -0
- package/dist/public/sanitize.d.ts +23 -0
- package/{src/public/slug-utils.ts → dist/public/slug-utils.d.ts} +3 -10
- package/dist/rate-limit/cloudflare-rate-limiter.d.ts +6 -0
- package/dist/rate-limit/in-memory-rate-limiter.d.ts +7 -0
- package/dist/rate-limit/no-op-rate-limiter.d.ts +4 -0
- package/dist/search-utils.d.ts +54 -0
- package/dist/search.d.ts +6 -0
- package/dist/shared/apply-policies.d.ts +10 -0
- package/dist/shared/automations.repository.d1.d.ts +12 -0
- package/dist/shared/background-notification-service.d.ts +18 -0
- package/dist/shared/base.repository.d1.d.ts +18 -0
- package/dist/shared/cloudflare-queue-service.d.ts +11 -0
- package/dist/shared/content-utils.d.ts +21 -0
- package/dist/shared/content.repository.d1.d.ts +68 -0
- package/dist/shared/d1-activity-log.repository.d.ts +13 -0
- package/dist/shared/d1-activity-logger.d.ts +20 -0
- package/dist/shared/d1-analytics.repository.d.ts +20 -0
- package/dist/shared/d1-content-scan.repository.d.ts +7 -0
- package/dist/shared/d1-notification.repository.d.ts +17 -0
- package/dist/shared/d1-password-reset-token.repository.d.ts +10 -0
- package/dist/shared/d1-search.repository.d.ts +14 -0
- package/dist/shared/d1-session.repository.d.ts +12 -0
- package/dist/shared/d1-setup-checklist.repository.d.ts +12 -0
- package/dist/shared/d1-user.repository.d.ts +18 -0
- package/dist/shared/d1-widget.repository.d.ts +31 -0
- package/dist/shared/dashboard-layout.repository.d1.d.ts +9 -0
- package/dist/shared/demo-data-sql.d.ts +1 -0
- package/dist/shared/demo-data.repository.d1.d.ts +6 -0
- package/dist/shared/execution-context-scheduler.d.ts +6 -0
- package/dist/shared/fixed-clock.d.ts +13 -0
- package/dist/shared/fts-sync.d.ts +1 -0
- package/dist/shared/idempotency.repository.d1.d.ts +16 -0
- package/dist/shared/in-memory-activity-logger.d.ts +11 -0
- package/dist/shared/in-memory-notification-service.d.ts +11 -0
- package/dist/shared/in-memory-queue-service.d.ts +16 -0
- package/dist/shared/in-memory-seed.repository.d.ts +18 -0
- package/dist/shared/media.repository.d1.d.ts +35 -0
- package/dist/shared/qstash-notification-service.d.ts +18 -0
- package/dist/shared/query-utils.d.ts +36 -0
- package/dist/shared/queue-consumer.d.ts +9 -0
- package/dist/shared/request-utils.d.ts +13 -0
- package/dist/shared/schema-mutator.d1.d.ts +12 -0
- package/dist/shared/seed-layout.repository.d1.d.ts +9 -0
- package/dist/shared/seed-registry-cache.d.ts +12 -0
- package/dist/shared/seed.repository.d1.d.ts +13 -0
- package/dist/shared/sequential-id-generator.d.ts +13 -0
- package/dist/shared/site-settings.repository.d1.d.ts +7 -0
- package/dist/shared/storage/factory.d.ts +8 -0
- package/dist/shared/storage/s3-bucket.d.ts +43 -0
- package/dist/shared/storage-utils.d.ts +7 -0
- package/dist/shared/system-stats.repository.d1.d.ts +25 -0
- package/dist/types.d.ts +87 -0
- package/dist/upload.d.ts +16 -0
- package/dist/widget.d.ts +7 -0
- package/migrations/0000_v040_base.sql +265 -265
- package/migrations/0029_automations.sql +14 -14
- package/migrations/0030_test_seeds.sql +125 -125
- package/package.json +28 -18
- package/assets/dashboard/assets/chart-BrJFdsGZ.js +0 -39
- package/assets/dashboard/assets/index-CIaoMxuB.css +0 -1
- package/assets/dashboard/assets/index-wTKgygsg.js +0 -636
- package/assets/dashboard/assets/pie-chart-recharts-BEaE1FOE.js +0 -1
- package/assets/dashboard/assets/timeseries-chart-recharts-DmWM6imF.js +0 -1
- package/src/auth/__fixtures__/in-memory-hash-provider.ts +0 -17
- package/src/auth/__fixtures__/static-token-service.ts +0 -22
- package/src/auth/bcrypt-hash-provider.ts +0 -24
- package/src/auth/constants.ts +0 -14
- package/src/auth/generate-refresh-token.test.ts +0 -23
- package/src/auth/hash-provider.test.ts +0 -55
- package/src/auth/jose-token-service.ts +0 -62
- package/src/auth/jwt-claims-passthrough.test.ts +0 -87
- package/src/auth/login.test.ts +0 -100
- package/src/auth/login.ts +0 -78
- package/src/auth/refresh.ts +0 -11
- package/src/auth/token-service.test.ts +0 -90
- package/src/factory.ts +0 -370
- package/src/features/automations/__tests__/action-executors.test.ts +0 -255
- package/src/features/automations/__tests__/automation-runner.test.ts +0 -196
- package/src/features/automations/__tests__/automation-runner.utils.test.ts +0 -60
- package/src/features/automations/__tests__/automations.handler.test.ts +0 -264
- package/src/features/automations/__tests__/automations.repository.test.ts +0 -163
- package/src/features/automations/__tests__/automations.schema.test.ts +0 -224
- package/src/features/automations/__tests__/context-resolver.test.ts +0 -126
- package/src/features/automations/__tests__/cron-runner.test.ts +0 -267
- package/src/features/automations/__tests__/cron-runner.utils.test.ts +0 -144
- package/src/features/automations/__tests__/set-variable.executor.test.ts +0 -383
- package/src/features/automations/__tests__/template-grammar.test.ts +0 -308
- package/src/features/automations/__tests__/webhook.executor.test.ts +0 -142
- package/src/features/automations/__tests__/when-evaluator.test.ts +0 -274
- package/src/features/automations/__tests__/when-pushdown.test.ts +0 -281
- package/src/features/automations/action-executors/create-entry.executor.ts +0 -27
- package/src/features/automations/action-executors/edit-field.executor.ts +0 -26
- package/src/features/automations/action-executors/index.ts +0 -37
- package/src/features/automations/action-executors/send-mail.executor.ts +0 -53
- package/src/features/automations/action-executors/set-variable.executor.ts +0 -159
- package/src/features/automations/action-executors/webhook.executor.ts +0 -67
- package/src/features/automations/automation-runner.ts +0 -85
- package/src/features/automations/automation-runner.utils.ts +0 -47
- package/src/features/automations/automations.handler.ts +0 -197
- package/src/features/automations/automations.schema.ts +0 -177
- package/src/features/automations/context-resolver.ts +0 -152
- package/src/features/automations/cron-runner.ts +0 -140
- package/src/features/automations/cron-runner.utils.ts +0 -44
- package/src/features/automations/filter-translation.ts +0 -46
- package/src/features/automations/index.ts +0 -16
- package/src/features/automations/template-grammar.ts +0 -245
- package/src/features/automations/var-access-resolver.ts +0 -140
- package/src/features/automations/when-evaluator.ts +0 -87
- package/src/features/automations/when-pushdown.ts +0 -57
- package/src/features/backrefs/__tests__/backrefs.handler.test.ts +0 -359
- package/src/features/backrefs/backrefs.handler.ts +0 -168
- package/src/features/backrefs/d1-backref.repository.ts +0 -84
- package/src/features/backrefs/index.ts +0 -5
- package/src/features/content/constants.ts +0 -16
- package/src/features/content/handlers/bulk.handler.ts +0 -185
- package/src/features/content/handlers/create.ts +0 -129
- package/src/features/content/handlers/delete.ts +0 -62
- package/src/features/content/handlers/facets.ts +0 -49
- package/src/features/content/handlers/get.ts +0 -120
- package/src/features/content/handlers/helpers.test.ts +0 -180
- package/src/features/content/handlers/helpers.ts +0 -93
- package/src/features/content/handlers/list.ts +0 -174
- package/src/features/content/handlers/update.ts +0 -174
- package/src/features/content/index.ts +0 -26
- package/src/features/dashboard-layout/__tests__/dashboard-layout.handler.test.ts +0 -388
- package/src/features/dashboard-layout/dashboard-layout.handler.ts +0 -206
- package/src/features/dashboard-layout/index.ts +0 -5
- package/src/features/draft/draft.handler.ts +0 -195
- package/src/features/draft/draft.middleware.ts +0 -66
- package/src/features/draft/index.ts +0 -5
- package/src/features/email/email.service.ts +0 -98
- package/src/features/email/email.types.ts +0 -119
- package/src/features/email/providers/resend.ts +0 -67
- package/src/features/email/providers/smtp.ts +0 -55
- package/src/features/email/templates/automation-mail.ts +0 -19
- package/src/features/email/templates/password-changed.ts +0 -63
- package/src/features/email/templates/password-reset.ts +0 -68
- package/src/features/email/templates/shell.ts +0 -96
- package/src/features/notifications/index.ts +0 -5
- package/src/features/notifications/notifications.handler.ts +0 -105
- package/src/features/password-reset/index.ts +0 -19
- package/src/features/password-reset/request.ts +0 -92
- package/src/features/password-reset/reset.ts +0 -102
- package/src/features/rotate-field/index.ts +0 -5
- package/src/features/rotate-field/rotate-field.handler.ts +0 -132
- package/src/features/rotate-field/rotate-field.schema.ts +0 -17
- package/src/features/schema/schema.handler.ts +0 -131
- package/src/features/seeds/index.ts +0 -5
- package/src/features/seeds/seeds.handler.test.ts +0 -1199
- package/src/features/seeds/seeds.handler.ts +0 -558
- package/src/features/settings/__tests__/settings.handler.test.ts +0 -555
- package/src/features/settings/settings.handler.ts +0 -392
- package/src/features/setup/index.ts +0 -288
- package/src/features/stats/index.ts +0 -5
- package/src/features/stats/stats.handler.ts +0 -420
- package/src/features/webhooks/index.ts +0 -63
- package/src/index.ts +0 -65
- package/src/media-utils.ts +0 -82
- package/src/middleware/auth-providers.middleware.test.ts +0 -85
- package/src/middleware/auth-providers.middleware.ts +0 -45
- package/src/middleware/observability.middleware.test.ts +0 -93
- package/src/middleware/observability.middleware.ts +0 -70
- package/src/middleware/rate-limit.middleware.ts +0 -45
- package/src/middleware/repository.middleware.ts +0 -117
- package/src/middleware/seed-registry.middleware.test.ts +0 -97
- package/src/middleware/seed-registry.middleware.ts +0 -21
- package/src/middleware/storage.middleware.ts +0 -25
- package/src/middleware.ts +0 -45
- package/src/public/access-policy.ts +0 -27
- package/src/public/api-key-middleware.ts +0 -57
- package/src/public/cache-utils.ts +0 -38
- package/src/public/entry-projection.ts +0 -46
- package/src/public/idempotency.ts +0 -23
- package/src/public/index.ts +0 -16
- package/src/public/problem-details.ts +0 -124
- package/src/public/public-add.ts +0 -114
- package/src/public/public-edit.ts +0 -163
- package/src/public/public-errors.ts +0 -19
- package/src/public/public-read.ts +0 -63
- package/src/public/public-routes.ts +0 -88
- package/src/public/query-builder.test.ts +0 -224
- package/src/public/query-builder.ts +0 -156
- package/src/public/rate-limit-middleware.ts +0 -34
- package/src/public/read-list.ts +0 -54
- package/src/public/read-single.ts +0 -48
- package/src/public/response-builder.ts +0 -30
- package/src/public/sanitize.ts +0 -69
- package/src/rate-limit/cloudflare-rate-limiter.test.ts +0 -30
- package/src/rate-limit/cloudflare-rate-limiter.ts +0 -15
- package/src/rate-limit/in-memory-rate-limiter.test.ts +0 -37
- package/src/rate-limit/in-memory-rate-limiter.ts +0 -17
- package/src/rate-limit/no-op-rate-limiter.test.ts +0 -22
- package/src/rate-limit/no-op-rate-limiter.ts +0 -11
- package/src/search-utils.test.ts +0 -211
- package/src/search-utils.ts +0 -213
- package/src/search.ts +0 -65
- package/src/shared/apply-policies.test.ts +0 -81
- package/src/shared/apply-policies.ts +0 -67
- package/src/shared/automations.repository.d1.ts +0 -150
- package/src/shared/background-notification-service.test.ts +0 -62
- package/src/shared/background-notification-service.ts +0 -52
- package/src/shared/base.repository.d1.ts +0 -32
- package/src/shared/content-utils.test.ts +0 -165
- package/src/shared/content-utils.ts +0 -86
- package/src/shared/content.repository.d1.test.ts +0 -507
- package/src/shared/content.repository.d1.ts +0 -851
- package/src/shared/d1-activity-log.repository.test.ts +0 -140
- package/src/shared/d1-activity-log.repository.ts +0 -105
- package/src/shared/d1-activity-logger.test.ts +0 -86
- package/src/shared/d1-activity-logger.ts +0 -67
- package/src/shared/d1-analytics.repository.test.ts +0 -78
- package/src/shared/d1-analytics.repository.ts +0 -85
- package/src/shared/d1-content-scan.repository.test.ts +0 -80
- package/src/shared/d1-content-scan.repository.ts +0 -37
- package/src/shared/d1-notification.repository.test.ts +0 -128
- package/src/shared/d1-notification.repository.ts +0 -118
- package/src/shared/d1-password-reset-token.repository.test.ts +0 -81
- package/src/shared/d1-password-reset-token.repository.ts +0 -56
- package/src/shared/d1-search.repository.test.ts +0 -87
- package/src/shared/d1-search.repository.ts +0 -88
- package/src/shared/d1-session.repository.test.ts +0 -125
- package/src/shared/d1-session.repository.ts +0 -102
- package/src/shared/d1-setup-checklist.repository.ts +0 -36
- package/src/shared/d1-user.repository.test.ts +0 -151
- package/src/shared/d1-user.repository.ts +0 -119
- package/src/shared/d1-widget.repository.test.ts +0 -267
- package/src/shared/d1-widget.repository.ts +0 -385
- package/src/shared/dashboard-layout.repository.d1.test.ts +0 -135
- package/src/shared/dashboard-layout.repository.d1.ts +0 -58
- package/src/shared/demo-data-sql.ts +0 -216
- package/src/shared/demo-data.repository.d1.ts +0 -20
- package/src/shared/execution-context-scheduler.ts +0 -13
- package/src/shared/fixed-clock.ts +0 -25
- package/src/shared/fts-sync.ts +0 -8
- package/src/shared/idempotency.repository.d1.test.ts +0 -83
- package/src/shared/idempotency.repository.d1.ts +0 -60
- package/src/shared/in-memory-activity-logger.ts +0 -19
- package/src/shared/in-memory-notification-service.ts +0 -19
- package/src/shared/in-memory-seed.repository.ts +0 -58
- package/src/shared/media.repository.d1.test.ts +0 -107
- package/src/shared/media.repository.d1.ts +0 -68
- package/src/shared/qstash-notification-service.test.ts +0 -67
- package/src/shared/qstash-notification-service.ts +0 -55
- package/src/shared/query-utils.ts +0 -141
- package/src/shared/request-utils.ts +0 -26
- package/src/shared/schema-mutator.d1.test.ts +0 -142
- package/src/shared/schema-mutator.d1.ts +0 -64
- package/src/shared/seed-layout.repository.d1.test.ts +0 -114
- package/src/shared/seed-layout.repository.d1.ts +0 -62
- package/src/shared/seed-registry-cache.test.ts +0 -68
- package/src/shared/seed-registry-cache.ts +0 -49
- package/src/shared/seed.repository.d1.test.ts +0 -143
- package/src/shared/seed.repository.d1.ts +0 -98
- package/src/shared/sequential-id-generator.ts +0 -33
- package/src/shared/site-settings.repository.d1.ts +0 -53
- package/src/shared/storage/factory.ts +0 -41
- package/src/shared/storage/s3-bucket.ts +0 -195
- package/src/shared/storage-utils.ts +0 -40
- package/src/shared/system-stats.repository.d1.test.ts +0 -58
- package/src/shared/system-stats.repository.d1.ts +0 -48
- package/src/types.ts +0 -90
- package/src/upload.ts +0 -198
- package/src/widget.test.ts +0 -85
- package/src/widget.ts +0 -251
|
@@ -1,85 +0,0 @@
|
|
|
1
|
-
// SPDX-License-Identifier: BUSL-1.1
|
|
2
|
-
// Copyright (c) 2024–2026 Flavio De Musso. All rights reserved.
|
|
3
|
-
// See LICENSE in the repository root for license terms.
|
|
4
|
-
|
|
5
|
-
import { describe, it, expect, vi } from 'vitest'
|
|
6
|
-
import { Hono } from 'hono'
|
|
7
|
-
import { authProvidersMiddleware } from './auth-providers.middleware'
|
|
8
|
-
|
|
9
|
-
describe('authProvidersMiddleware', () => {
|
|
10
|
-
it('throws an error if ENV is production and JWT_SECRET is the development default', async () => {
|
|
11
|
-
const app = new Hono()
|
|
12
|
-
app.use('*', authProvidersMiddleware())
|
|
13
|
-
app.get('/test', (c) => c.text('ok'))
|
|
14
|
-
|
|
15
|
-
const env = {
|
|
16
|
-
ENV: 'production',
|
|
17
|
-
JWT_SECRET: 'sviluppo-secret-cambiami-almeno-32-byte-per-sicurezza-hono',
|
|
18
|
-
}
|
|
19
|
-
|
|
20
|
-
// Since throwing in Hono middleware returns an unhandled exception or 500 error,
|
|
21
|
-
// let's run app.request and inspect if the error is thrown. Hono's default errorHandler
|
|
22
|
-
// catches it, or we can add a custom error handler to catch it.
|
|
23
|
-
let thrownError: Error | null = null
|
|
24
|
-
app.onError((err) => {
|
|
25
|
-
thrownError = err
|
|
26
|
-
return Hono.prototype.json({ error: err.message }, 500)
|
|
27
|
-
})
|
|
28
|
-
|
|
29
|
-
const res = await app.request('/test', undefined, env)
|
|
30
|
-
expect(res.status).toBe(500)
|
|
31
|
-
expect(thrownError).not.toBeNull()
|
|
32
|
-
expect(thrownError!.message).toContain('JWT_SECRET non configurato')
|
|
33
|
-
})
|
|
34
|
-
|
|
35
|
-
it('injects hashProvider and tokenService when configuration is correct', async () => {
|
|
36
|
-
const app = new Hono()
|
|
37
|
-
app.use('*', authProvidersMiddleware())
|
|
38
|
-
app.get('/test', (c) => {
|
|
39
|
-
const hash = c.get('hashProvider' as never)
|
|
40
|
-
const token = c.get('tokenService' as never)
|
|
41
|
-
return c.json({
|
|
42
|
-
hasHash: !!hash,
|
|
43
|
-
hasToken: !!token,
|
|
44
|
-
})
|
|
45
|
-
})
|
|
46
|
-
|
|
47
|
-
const env = {
|
|
48
|
-
ENV: 'development',
|
|
49
|
-
JWT_SECRET: 'custom-secret-key-that-is-secure-enough',
|
|
50
|
-
JWT_ISSUER: 'issuer',
|
|
51
|
-
JWT_AUDIENCE: 'audience',
|
|
52
|
-
}
|
|
53
|
-
|
|
54
|
-
const res = await app.request('/test', undefined, env)
|
|
55
|
-
expect(res.status).toBe(200)
|
|
56
|
-
const body = await res.json() as any
|
|
57
|
-
expect(body.hasHash).toBe(true)
|
|
58
|
-
expect(body.hasToken).toBe(true)
|
|
59
|
-
})
|
|
60
|
-
|
|
61
|
-
it('respects overrides when provided', async () => {
|
|
62
|
-
const app = new Hono()
|
|
63
|
-
const mockHash = { hash: vi.fn(), verify: vi.fn() }
|
|
64
|
-
const mockToken = { sign: vi.fn(), verify: vi.fn() }
|
|
65
|
-
|
|
66
|
-
app.use('*', authProvidersMiddleware({
|
|
67
|
-
hashProvider: mockHash as any,
|
|
68
|
-
tokenService: mockToken as any,
|
|
69
|
-
}))
|
|
70
|
-
|
|
71
|
-
app.get('/test', (c) => {
|
|
72
|
-
const hash = c.get('hashProvider' as never)
|
|
73
|
-
const token = c.get('tokenService' as never)
|
|
74
|
-
return c.json({
|
|
75
|
-
hashIsOverridden: hash === mockHash,
|
|
76
|
-
tokenIsOverridden: token === mockToken,
|
|
77
|
-
})
|
|
78
|
-
})
|
|
79
|
-
|
|
80
|
-
const res = await app.request('/test')
|
|
81
|
-
const body = await res.json() as any
|
|
82
|
-
expect(body.hashIsOverridden).toBe(true)
|
|
83
|
-
expect(body.tokenIsOverridden).toBe(true)
|
|
84
|
-
})
|
|
85
|
-
})
|
|
@@ -1,45 +0,0 @@
|
|
|
1
|
-
// SPDX-License-Identifier: BUSL-1.1
|
|
2
|
-
// Copyright (c) 2024–2026 Flavio De Musso. All rights reserved.
|
|
3
|
-
// See LICENSE in the repository root for license terms.
|
|
4
|
-
|
|
5
|
-
import { createMiddleware } from 'hono/factory'
|
|
6
|
-
import type { IHashProvider, ITokenService, IClock } from '@beechcms/core'
|
|
7
|
-
import { SystemClock } from '@beechcms/core'
|
|
8
|
-
import type { AppEnv } from '../types'
|
|
9
|
-
import { BcryptHashProvider } from '../auth/bcrypt-hash-provider'
|
|
10
|
-
import { JoseTokenService } from '../auth/jose-token-service'
|
|
11
|
-
|
|
12
|
-
export interface AuthProviderOverrides {
|
|
13
|
-
hashProvider?: IHashProvider
|
|
14
|
-
tokenService?: ITokenService
|
|
15
|
-
clock?: IClock
|
|
16
|
-
}
|
|
17
|
-
|
|
18
|
-
// Valore di default presente in .dev.vars.example: mai accettabile in produzione.
|
|
19
|
-
const DEV_JWT_SECRET = 'sviluppo-secret-cambiami-almeno-32-byte-per-sicurezza-hono'
|
|
20
|
-
|
|
21
|
-
export const authProvidersMiddleware = (overrides?: AuthProviderOverrides) => {
|
|
22
|
-
return createMiddleware<AppEnv>(async (context, next) => {
|
|
23
|
-
if (context.env.ENV === 'production' && context.env.JWT_SECRET === DEV_JWT_SECRET) {
|
|
24
|
-
throw new Error(
|
|
25
|
-
'JWT_SECRET non configurato: in produzione impostare un segreto univoco con `wrangler secret put JWT_SECRET`',
|
|
26
|
-
)
|
|
27
|
-
}
|
|
28
|
-
|
|
29
|
-
const resolvedClock = overrides?.clock ?? SystemClock
|
|
30
|
-
const hashProvider = overrides?.hashProvider ?? new BcryptHashProvider()
|
|
31
|
-
const tokenService = overrides?.tokenService ?? new JoseTokenService(
|
|
32
|
-
context.env.JWT_SECRET,
|
|
33
|
-
{
|
|
34
|
-
issuer: context.env.JWT_ISSUER,
|
|
35
|
-
audience: context.env.JWT_AUDIENCE,
|
|
36
|
-
},
|
|
37
|
-
resolvedClock,
|
|
38
|
-
)
|
|
39
|
-
|
|
40
|
-
context.set('hashProvider', hashProvider)
|
|
41
|
-
context.set('tokenService', tokenService)
|
|
42
|
-
|
|
43
|
-
await next()
|
|
44
|
-
})
|
|
45
|
-
}
|
|
@@ -1,93 +0,0 @@
|
|
|
1
|
-
// SPDX-License-Identifier: BUSL-1.1
|
|
2
|
-
// Copyright (c) 2024–2026 Flavio De Musso. All rights reserved.
|
|
3
|
-
// See LICENSE in the repository root for license terms.
|
|
4
|
-
|
|
5
|
-
import { describe, it, expect, vi } from 'vitest'
|
|
6
|
-
import { Hono } from 'hono'
|
|
7
|
-
import { observabilityMiddleware } from './observability.middleware'
|
|
8
|
-
import type { IClock, IIdGenerator } from '@beechcms/core'
|
|
9
|
-
|
|
10
|
-
describe('observabilityMiddleware', () => {
|
|
11
|
-
it('injects default activityLogger and background notification service when no overrides are given', async () => {
|
|
12
|
-
const app = new Hono()
|
|
13
|
-
|
|
14
|
-
app.use('*', async (c, next) => {
|
|
15
|
-
c.set('notificationRepository' as never, {} as any)
|
|
16
|
-
await next()
|
|
17
|
-
})
|
|
18
|
-
|
|
19
|
-
app.use('*', observabilityMiddleware())
|
|
20
|
-
|
|
21
|
-
app.get('/test', (c) => {
|
|
22
|
-
const logger = c.get('activityLogger' as never)
|
|
23
|
-
const notifications = c.get('notificationService' as never)
|
|
24
|
-
return c.json({
|
|
25
|
-
hasLogger: !!logger,
|
|
26
|
-
hasNotifications: !!notifications,
|
|
27
|
-
})
|
|
28
|
-
})
|
|
29
|
-
|
|
30
|
-
const executionCtx = {
|
|
31
|
-
waitUntil: vi.fn(),
|
|
32
|
-
passThroughOnException: vi.fn(),
|
|
33
|
-
}
|
|
34
|
-
|
|
35
|
-
// Mock env with DB
|
|
36
|
-
const res = await app.request('/test', undefined, { DB: {} }, executionCtx)
|
|
37
|
-
const body = await res.json() as any
|
|
38
|
-
expect(body.hasLogger).toBe(true)
|
|
39
|
-
expect(body.hasNotifications).toBe(true)
|
|
40
|
-
})
|
|
41
|
-
|
|
42
|
-
it('respects overrides when provided', async () => {
|
|
43
|
-
const app = new Hono()
|
|
44
|
-
|
|
45
|
-
const mockLogger = { log: vi.fn() }
|
|
46
|
-
const mockNotifications = { send: vi.fn() }
|
|
47
|
-
const mockClock: IClock = { now: () => 12345 }
|
|
48
|
-
const mockIdGen: IIdGenerator = { nextId: () => 'custom-id' }
|
|
49
|
-
|
|
50
|
-
app.use('*', observabilityMiddleware({
|
|
51
|
-
activityLogger: mockLogger as any,
|
|
52
|
-
notificationService: mockNotifications as any,
|
|
53
|
-
clock: mockClock,
|
|
54
|
-
idGenerator: mockIdGen,
|
|
55
|
-
}))
|
|
56
|
-
|
|
57
|
-
app.get('/test', (c) => {
|
|
58
|
-
const logger = c.get('activityLogger' as never)
|
|
59
|
-
const notifications = c.get('notificationService' as never)
|
|
60
|
-
return c.json({
|
|
61
|
-
loggerIsOverridden: logger === mockLogger,
|
|
62
|
-
notificationsAreOverridden: notifications === mockNotifications,
|
|
63
|
-
})
|
|
64
|
-
})
|
|
65
|
-
|
|
66
|
-
const res = await app.request('/test')
|
|
67
|
-
const body = await res.json() as any
|
|
68
|
-
expect(body.loggerIsOverridden).toBe(true)
|
|
69
|
-
expect(body.notificationsAreOverridden).toBe(true)
|
|
70
|
-
})
|
|
71
|
-
|
|
72
|
-
it('uses QStashNotificationService when QSTASH_TOKEN and APP_URL are in Env', async () => {
|
|
73
|
-
const app = new Hono()
|
|
74
|
-
app.use('*', observabilityMiddleware())
|
|
75
|
-
|
|
76
|
-
app.get('/test', (c) => {
|
|
77
|
-
const notifications = c.get('notificationService' as never) as any
|
|
78
|
-
return c.json({
|
|
79
|
-
type: notifications?.constructor?.name,
|
|
80
|
-
})
|
|
81
|
-
})
|
|
82
|
-
|
|
83
|
-
const env = {
|
|
84
|
-
QSTASH_TOKEN: 'token',
|
|
85
|
-
APP_URL: 'https://my-app.com',
|
|
86
|
-
DB: {},
|
|
87
|
-
}
|
|
88
|
-
|
|
89
|
-
const res = await app.request('/test', undefined, env)
|
|
90
|
-
const body = await res.json() as any
|
|
91
|
-
expect(body.type).toBe('QStashNotificationService')
|
|
92
|
-
})
|
|
93
|
-
})
|
|
@@ -1,70 +0,0 @@
|
|
|
1
|
-
// SPDX-License-Identifier: BUSL-1.1
|
|
2
|
-
// Copyright (c) 2024–2026 Flavio De Musso. All rights reserved.
|
|
3
|
-
// See LICENSE in the repository root for license terms.
|
|
4
|
-
|
|
5
|
-
import { createMiddleware } from 'hono/factory'
|
|
6
|
-
import type { IActivityLogger, INotificationService, IClock, IIdGenerator } from '@beechcms/core'
|
|
7
|
-
import { SystemClock, SystemIdGenerator } from '@beechcms/core'
|
|
8
|
-
import type { AppEnv } from '../types'
|
|
9
|
-
import { D1ActivityLogger } from '../shared/d1-activity-logger'
|
|
10
|
-
import { BackgroundNotificationService } from '../shared/background-notification-service'
|
|
11
|
-
import { QStashNotificationService } from '../shared/qstash-notification-service'
|
|
12
|
-
|
|
13
|
-
export interface ObservabilityOverrides {
|
|
14
|
-
activityLogger?: IActivityLogger
|
|
15
|
-
notificationService?: INotificationService
|
|
16
|
-
clock?: IClock
|
|
17
|
-
idGenerator?: IIdGenerator
|
|
18
|
-
}
|
|
19
|
-
|
|
20
|
-
/**
|
|
21
|
-
* Observability middleware.
|
|
22
|
-
*
|
|
23
|
-
* Injects the activity logger and the notification service into the Hono
|
|
24
|
-
* context. Both depend on `executionCtx.waitUntil` to fire-and-forget their
|
|
25
|
-
* persistence work in production. The notification service additionally
|
|
26
|
-
* depends on the notification repository — `repositoryMiddleware` MUST run
|
|
27
|
-
* before this middleware in the factory pipeline.
|
|
28
|
-
*
|
|
29
|
-
* Tests can pass their own implementations via `overrides` to bypass D1.
|
|
30
|
-
*/
|
|
31
|
-
export const observabilityMiddleware = (overrides?: ObservabilityOverrides) => {
|
|
32
|
-
return createMiddleware<AppEnv>(async (context, next) => {
|
|
33
|
-
let scheduleBackgroundTask: ((task: Promise<unknown>) => void) | undefined
|
|
34
|
-
try {
|
|
35
|
-
const executionContext = context.executionCtx
|
|
36
|
-
scheduleBackgroundTask = executionContext.waitUntil.bind(executionContext)
|
|
37
|
-
} catch {
|
|
38
|
-
scheduleBackgroundTask = undefined
|
|
39
|
-
}
|
|
40
|
-
|
|
41
|
-
const resolvedClock = overrides?.clock ?? SystemClock
|
|
42
|
-
const resolvedIdGenerator = overrides?.idGenerator ?? SystemIdGenerator
|
|
43
|
-
|
|
44
|
-
const activityLogger =
|
|
45
|
-
overrides?.activityLogger ??
|
|
46
|
-
new D1ActivityLogger(context.env.DB, resolvedClock, resolvedIdGenerator, scheduleBackgroundTask)
|
|
47
|
-
|
|
48
|
-
let notificationService: INotificationService
|
|
49
|
-
if (overrides?.notificationService) {
|
|
50
|
-
notificationService = overrides.notificationService
|
|
51
|
-
} else if (context.env.QSTASH_TOKEN && (context.env.QSTASH_CALLBACK_URL || context.env.APP_URL)) {
|
|
52
|
-
notificationService = new QStashNotificationService(
|
|
53
|
-
context.env.QSTASH_TOKEN,
|
|
54
|
-
(context.env.QSTASH_CALLBACK_URL ?? context.env.APP_URL) as string,
|
|
55
|
-
scheduleBackgroundTask,
|
|
56
|
-
context.env.QSTASH_URL
|
|
57
|
-
)
|
|
58
|
-
} else {
|
|
59
|
-
notificationService = new BackgroundNotificationService(
|
|
60
|
-
context.get('notificationRepository'),
|
|
61
|
-
scheduleBackgroundTask
|
|
62
|
-
)
|
|
63
|
-
}
|
|
64
|
-
|
|
65
|
-
context.set('activityLogger', activityLogger)
|
|
66
|
-
context.set('notificationService', notificationService)
|
|
67
|
-
|
|
68
|
-
await next()
|
|
69
|
-
})
|
|
70
|
-
}
|
|
@@ -1,45 +0,0 @@
|
|
|
1
|
-
// SPDX-License-Identifier: BUSL-1.1
|
|
2
|
-
// Copyright (c) 2024–2026 Flavio De Musso. All rights reserved.
|
|
3
|
-
// See LICENSE in the repository root for license terms.
|
|
4
|
-
|
|
5
|
-
/// <reference types="@cloudflare/workers-types" />
|
|
6
|
-
import { createMiddleware } from 'hono/factory'
|
|
7
|
-
import type { IRateLimiter } from '@beechcms/core'
|
|
8
|
-
import type { AppEnv, Env } from '../types'
|
|
9
|
-
import { CloudflareRateLimiter } from '../rate-limit/cloudflare-rate-limiter'
|
|
10
|
-
import { NoOpRateLimiter } from '../rate-limit/no-op-rate-limiter'
|
|
11
|
-
|
|
12
|
-
export type RateLimiterName =
|
|
13
|
-
| 'login'
|
|
14
|
-
| 'tokenRefresh'
|
|
15
|
-
| 'forgotPassword'
|
|
16
|
-
| 'resetPassword'
|
|
17
|
-
| 'publicApiRead'
|
|
18
|
-
| 'publicApiWrite'
|
|
19
|
-
|
|
20
|
-
export interface IRateLimiterRegistry {
|
|
21
|
-
getLimiter(name: RateLimiterName): IRateLimiter
|
|
22
|
-
}
|
|
23
|
-
|
|
24
|
-
const NO_OP = new NoOpRateLimiter()
|
|
25
|
-
|
|
26
|
-
function buildDefaultRegistry(env: Env): IRateLimiterRegistry {
|
|
27
|
-
const limiters: Record<RateLimiterName, IRateLimiter> = {
|
|
28
|
-
login: env.LOGIN_RATE_LIMITER ? new CloudflareRateLimiter(env.LOGIN_RATE_LIMITER) : NO_OP,
|
|
29
|
-
tokenRefresh: env.REFRESH_RATE_LIMITER ? new CloudflareRateLimiter(env.REFRESH_RATE_LIMITER) : NO_OP,
|
|
30
|
-
forgotPassword: env.FORGOT_PASSWORD_RATE_LIMITER ? new CloudflareRateLimiter(env.FORGOT_PASSWORD_RATE_LIMITER) : NO_OP,
|
|
31
|
-
resetPassword: env.RESET_PASSWORD_RATE_LIMITER ? new CloudflareRateLimiter(env.RESET_PASSWORD_RATE_LIMITER) : NO_OP,
|
|
32
|
-
publicApiRead: env.PUBLIC_READ_RATE_LIMITER ? new CloudflareRateLimiter(env.PUBLIC_READ_RATE_LIMITER) : NO_OP,
|
|
33
|
-
publicApiWrite: env.PUBLIC_WRITE_RATE_LIMITER ? new CloudflareRateLimiter(env.PUBLIC_WRITE_RATE_LIMITER) : NO_OP,
|
|
34
|
-
}
|
|
35
|
-
|
|
36
|
-
return { getLimiter: (name) => limiters[name] }
|
|
37
|
-
}
|
|
38
|
-
|
|
39
|
-
export const rateLimiterMiddleware = (overrides?: { registry?: IRateLimiterRegistry }) => {
|
|
40
|
-
return createMiddleware<AppEnv>(async (context, next) => {
|
|
41
|
-
const registry = overrides?.registry ?? buildDefaultRegistry(context.env)
|
|
42
|
-
context.set('rateLimiters', registry)
|
|
43
|
-
await next()
|
|
44
|
-
})
|
|
45
|
-
}
|
|
@@ -1,117 +0,0 @@
|
|
|
1
|
-
// SPDX-License-Identifier: BUSL-1.1
|
|
2
|
-
// Copyright (c) 2024–2026 Flavio De Musso. All rights reserved.
|
|
3
|
-
// See LICENSE in the repository root for license terms.
|
|
4
|
-
|
|
5
|
-
import { createMiddleware } from 'hono/factory'
|
|
6
|
-
import type { Context } from 'hono'
|
|
7
|
-
import { D1ContentRepository } from '../shared/content.repository.d1'
|
|
8
|
-
import { D1IdempotencyRepository } from '../shared/idempotency.repository.d1'
|
|
9
|
-
import { D1MediaRepository } from '../shared/media.repository.d1'
|
|
10
|
-
import { D1SystemStatsRepository } from '../shared/system-stats.repository.d1'
|
|
11
|
-
import { D1UserRepository } from '../shared/d1-user.repository'
|
|
12
|
-
import { D1SessionRepository } from '../shared/d1-session.repository'
|
|
13
|
-
import { D1PasswordResetTokenRepository } from '../shared/d1-password-reset-token.repository'
|
|
14
|
-
import { D1ActivityLogRepository } from '../shared/d1-activity-log.repository'
|
|
15
|
-
import { D1NotificationRepository } from '../shared/d1-notification.repository'
|
|
16
|
-
import { D1WidgetRepository } from '../shared/d1-widget.repository'
|
|
17
|
-
import { D1SearchRepository } from '../shared/d1-search.repository'
|
|
18
|
-
import { D1AnalyticsRepository } from '../shared/d1-analytics.repository'
|
|
19
|
-
import { D1ContentScanRepository } from '../shared/d1-content-scan.repository'
|
|
20
|
-
import { D1SiteSettingsRepository } from '../shared/site-settings.repository.d1'
|
|
21
|
-
import { D1DemoDataRepository } from '../shared/demo-data.repository.d1'
|
|
22
|
-
import { D1SetupChecklistRepository } from '../shared/d1-setup-checklist.repository'
|
|
23
|
-
import { D1SeedLayoutRepository } from '../shared/seed-layout.repository.d1'
|
|
24
|
-
import { D1DashboardLayoutRepository } from '../shared/dashboard-layout.repository.d1'
|
|
25
|
-
import { D1SeedRepository } from '../shared/seed.repository.d1'
|
|
26
|
-
import { D1SchemaMutator } from '../shared/schema-mutator.d1'
|
|
27
|
-
import { SystemClock, SystemIdGenerator } from '@beechcms/core'
|
|
28
|
-
import type { ContentRepository, IdempotencyRepository, MediaRepository, SystemStatsRepository, IUserRepository, ISessionRepository, IPasswordResetTokenRepository, IActivityLogRepository, INotificationRepository, IWidgetRepository, ISearchRepository, IAnalyticsRepository, IContentScanRepository, IClock, IIdGenerator, IAutomationRunner, IAutomationRepository, IScheduler, ISiteSettingsRepository, IDemoDataRepository, ISeedLayoutRepository, ISeedRepository, ISchemaMutator, IDashboardLayoutRepository } from '@beechcms/core'
|
|
29
|
-
import { NoOpScheduler } from '@beechcms/core'
|
|
30
|
-
import { AutomationRunner } from '../features/automations'
|
|
31
|
-
import { D1AutomationRepository } from '../shared/automations.repository.d1'
|
|
32
|
-
import { ExecutionContextScheduler } from '../shared/execution-context-scheduler'
|
|
33
|
-
import type { Env, Variables } from '../types'
|
|
34
|
-
|
|
35
|
-
interface RepositoryOverrides {
|
|
36
|
-
repository?: ContentRepository
|
|
37
|
-
idempotencyRepository?: IdempotencyRepository
|
|
38
|
-
mediaRepository?: MediaRepository
|
|
39
|
-
systemStatsRepository?: SystemStatsRepository
|
|
40
|
-
userRepository?: IUserRepository
|
|
41
|
-
sessionRepository?: ISessionRepository
|
|
42
|
-
passwordResetTokenRepository?: IPasswordResetTokenRepository
|
|
43
|
-
activityLogRepository?: IActivityLogRepository
|
|
44
|
-
notificationRepository?: INotificationRepository
|
|
45
|
-
widgetRepository?: IWidgetRepository
|
|
46
|
-
searchRepository?: ISearchRepository
|
|
47
|
-
analyticsRepository?: IAnalyticsRepository
|
|
48
|
-
contentScanRepository?: IContentScanRepository
|
|
49
|
-
clock?: IClock
|
|
50
|
-
idGenerator?: IIdGenerator
|
|
51
|
-
automationRepository?: IAutomationRepository
|
|
52
|
-
automationRunner?: IAutomationRunner
|
|
53
|
-
scheduler?: IScheduler
|
|
54
|
-
siteSettingsRepository?: ISiteSettingsRepository
|
|
55
|
-
demoDataRepository?: IDemoDataRepository
|
|
56
|
-
seedLayoutRepository?: ISeedLayoutRepository
|
|
57
|
-
seedRepository?: ISeedRepository
|
|
58
|
-
schemaMutator?: ISchemaMutator
|
|
59
|
-
dashboardLayoutRepository?: IDashboardLayoutRepository
|
|
60
|
-
}
|
|
61
|
-
|
|
62
|
-
function buildScheduler(context: Context): IScheduler {
|
|
63
|
-
try {
|
|
64
|
-
return new ExecutionContextScheduler(context.executionCtx)
|
|
65
|
-
} catch {
|
|
66
|
-
return new NoOpScheduler()
|
|
67
|
-
}
|
|
68
|
-
}
|
|
69
|
-
|
|
70
|
-
export const repositoryMiddleware = (overrides?: RepositoryOverrides) => {
|
|
71
|
-
return createMiddleware<{ Bindings: Env; Variables: Variables }>(async (context, next) => {
|
|
72
|
-
const resolvedClock = overrides?.clock ?? SystemClock
|
|
73
|
-
const resolvedIdGenerator = overrides?.idGenerator ?? SystemIdGenerator
|
|
74
|
-
const database = context.env.DB
|
|
75
|
-
|
|
76
|
-
context.set('repository', overrides?.repository ?? new D1ContentRepository(database))
|
|
77
|
-
context.set('idempotencyRepository', overrides?.idempotencyRepository ?? new D1IdempotencyRepository(database))
|
|
78
|
-
context.set('mediaRepository', overrides?.mediaRepository ?? new D1MediaRepository(database))
|
|
79
|
-
context.set('systemStatsRepository', overrides?.systemStatsRepository ?? new D1SystemStatsRepository(database))
|
|
80
|
-
context.set('userRepository', overrides?.userRepository ?? new D1UserRepository(database))
|
|
81
|
-
context.set('sessionRepository', overrides?.sessionRepository ?? new D1SessionRepository(database, resolvedClock))
|
|
82
|
-
context.set('passwordResetTokenRepository', overrides?.passwordResetTokenRepository ?? new D1PasswordResetTokenRepository(database, resolvedIdGenerator))
|
|
83
|
-
context.set('activityLogRepository', overrides?.activityLogRepository ?? new D1ActivityLogRepository(database))
|
|
84
|
-
context.set('notificationRepository', overrides?.notificationRepository ?? new D1NotificationRepository(database, resolvedClock, resolvedIdGenerator))
|
|
85
|
-
context.set('widgetRepository', overrides?.widgetRepository ?? new D1WidgetRepository(database))
|
|
86
|
-
context.set('searchRepository', overrides?.searchRepository ?? new D1SearchRepository(database))
|
|
87
|
-
context.set('analyticsRepository', overrides?.analyticsRepository ?? new D1AnalyticsRepository(database, resolvedClock))
|
|
88
|
-
context.set('contentScanRepository', overrides?.contentScanRepository ?? new D1ContentScanRepository(database))
|
|
89
|
-
context.set('clock', resolvedClock)
|
|
90
|
-
context.set('idGenerator', resolvedIdGenerator)
|
|
91
|
-
const automationRepository = overrides?.automationRepository
|
|
92
|
-
?? new D1AutomationRepository(database)
|
|
93
|
-
|
|
94
|
-
context.set('automationRepository', automationRepository)
|
|
95
|
-
// getSeed is set later by seedRegistryMiddleware — capture context by closure so the
|
|
96
|
-
// runner reads the live value at call time, not at middleware creation time.
|
|
97
|
-
context.set(
|
|
98
|
-
'automationRunner',
|
|
99
|
-
overrides?.automationRunner ?? new AutomationRunner({
|
|
100
|
-
automationRepository,
|
|
101
|
-
contentRepository: context.get('repository'),
|
|
102
|
-
getSeed: (slug: string) => context.get('getSeed')?.(slug) ?? null,
|
|
103
|
-
idGenerator: resolvedIdGenerator,
|
|
104
|
-
env: context.env as unknown as Record<string, string | undefined>,
|
|
105
|
-
}),
|
|
106
|
-
)
|
|
107
|
-
context.set('scheduler', overrides?.scheduler ?? buildScheduler(context))
|
|
108
|
-
context.set('siteSettingsRepository', overrides?.siteSettingsRepository ?? new D1SiteSettingsRepository(database))
|
|
109
|
-
context.set('demoDataRepository', overrides?.demoDataRepository ?? new D1DemoDataRepository(database))
|
|
110
|
-
context.set('setupChecklistRepository', new D1SetupChecklistRepository(database))
|
|
111
|
-
context.set('seedLayoutRepository', overrides?.seedLayoutRepository ?? new D1SeedLayoutRepository(database))
|
|
112
|
-
context.set('seedRepository', overrides?.seedRepository ?? new D1SeedRepository(database))
|
|
113
|
-
context.set('schemaMutator', overrides?.schemaMutator ?? new D1SchemaMutator(database))
|
|
114
|
-
context.set('dashboardLayoutRepository', overrides?.dashboardLayoutRepository ?? new D1DashboardLayoutRepository(database))
|
|
115
|
-
await next()
|
|
116
|
-
})
|
|
117
|
-
}
|
|
@@ -1,97 +0,0 @@
|
|
|
1
|
-
// SPDX-License-Identifier: BUSL-1.1
|
|
2
|
-
// Copyright (c) 2024–2026 Flavio De Musso. All rights reserved.
|
|
3
|
-
// See LICENSE in the repository root for license terms.
|
|
4
|
-
|
|
5
|
-
import { describe, it, expect, beforeEach, vi } from 'vitest'
|
|
6
|
-
import { Hono } from 'hono'
|
|
7
|
-
import { seedRegistryMiddleware } from './seed-registry.middleware'
|
|
8
|
-
import { __resetSeedRegistryCache } from '../shared/seed-registry-cache'
|
|
9
|
-
import type { ISeedRepository, Seed } from '@beechcms/core'
|
|
10
|
-
|
|
11
|
-
const mockSeed: Seed = {
|
|
12
|
-
slug: 'posts',
|
|
13
|
-
label: 'Posts',
|
|
14
|
-
displayNameAlias: 'title',
|
|
15
|
-
branches: [{ id: 'br_01', alias: 'title', label: 'Title', type: 'text' }],
|
|
16
|
-
}
|
|
17
|
-
|
|
18
|
-
function makeRepo(seeds: Seed[] = [mockSeed]): ISeedRepository {
|
|
19
|
-
return {
|
|
20
|
-
listActive: vi.fn().mockResolvedValue(seeds),
|
|
21
|
-
listAll: vi.fn().mockResolvedValue([]),
|
|
22
|
-
get: vi.fn().mockResolvedValue(null),
|
|
23
|
-
upsert: vi.fn().mockResolvedValue(undefined),
|
|
24
|
-
softDelete: vi.fn().mockResolvedValue(undefined),
|
|
25
|
-
getRegistryVersion: vi.fn().mockResolvedValue(1),
|
|
26
|
-
bumpRegistryVersion: vi.fn().mockResolvedValue(2),
|
|
27
|
-
}
|
|
28
|
-
}
|
|
29
|
-
|
|
30
|
-
describe('seedRegistryMiddleware', () => {
|
|
31
|
-
beforeEach(() => __resetSeedRegistryCache())
|
|
32
|
-
|
|
33
|
-
it('injects seedRegistry, getSeed, and backrefMap into context', async () => {
|
|
34
|
-
const app = new Hono()
|
|
35
|
-
const repo = makeRepo()
|
|
36
|
-
|
|
37
|
-
app.use('*', async (c, next) => {
|
|
38
|
-
c.set('seedRepository' as never, repo)
|
|
39
|
-
await next()
|
|
40
|
-
})
|
|
41
|
-
app.use('*', seedRegistryMiddleware())
|
|
42
|
-
app.get('/test', (c) => {
|
|
43
|
-
const registry = c.get('seedRegistry' as never) as any
|
|
44
|
-
const getSeed = c.get('getSeed' as never) as any
|
|
45
|
-
const backrefMap = c.get('backrefMap' as never) as any
|
|
46
|
-
return c.json({
|
|
47
|
-
hasRegistry: !!registry,
|
|
48
|
-
hasSeed: !!getSeed('posts'),
|
|
49
|
-
hasBackrefMap: !!backrefMap,
|
|
50
|
-
})
|
|
51
|
-
})
|
|
52
|
-
|
|
53
|
-
const res = await app.request('/test')
|
|
54
|
-
const body = await res.json() as any
|
|
55
|
-
expect(body.hasRegistry).toBe(true)
|
|
56
|
-
expect(body.hasSeed).toBe(true)
|
|
57
|
-
expect(body.hasBackrefMap).toBe(true)
|
|
58
|
-
})
|
|
59
|
-
|
|
60
|
-
it('getSeed returns null for unknown slug', async () => {
|
|
61
|
-
const app = new Hono()
|
|
62
|
-
const repo = makeRepo()
|
|
63
|
-
|
|
64
|
-
app.use('*', async (c, next) => {
|
|
65
|
-
c.set('seedRepository' as never, repo)
|
|
66
|
-
await next()
|
|
67
|
-
})
|
|
68
|
-
app.use('*', seedRegistryMiddleware())
|
|
69
|
-
app.get('/test', (c) => {
|
|
70
|
-
const getSeed = c.get('getSeed' as never) as any
|
|
71
|
-
return c.json({ result: getSeed('no-such-slug') })
|
|
72
|
-
})
|
|
73
|
-
|
|
74
|
-
const res = await app.request('/test')
|
|
75
|
-
const body = await res.json() as any
|
|
76
|
-
expect(body.result).toBeNull()
|
|
77
|
-
})
|
|
78
|
-
|
|
79
|
-
it('empty seed list yields empty registry without crashing', async () => {
|
|
80
|
-
const app = new Hono()
|
|
81
|
-
const repo = makeRepo([])
|
|
82
|
-
|
|
83
|
-
app.use('*', async (c, next) => {
|
|
84
|
-
c.set('seedRepository' as never, repo)
|
|
85
|
-
await next()
|
|
86
|
-
})
|
|
87
|
-
app.use('*', seedRegistryMiddleware())
|
|
88
|
-
app.get('/test', (c) => {
|
|
89
|
-
const registry = c.get('seedRegistry' as never) as any
|
|
90
|
-
return c.json({ count: registry.all().length })
|
|
91
|
-
})
|
|
92
|
-
|
|
93
|
-
const res = await app.request('/test')
|
|
94
|
-
const body = await res.json() as any
|
|
95
|
-
expect(body.count).toBe(0)
|
|
96
|
-
})
|
|
97
|
-
})
|
|
@@ -1,21 +0,0 @@
|
|
|
1
|
-
// SPDX-License-Identifier: BUSL-1.1
|
|
2
|
-
// Copyright (c) 2024–2026 Flavio De Musso. All rights reserved.
|
|
3
|
-
// See LICENSE in the repository root for license terms.
|
|
4
|
-
|
|
5
|
-
import { createMiddleware } from 'hono/factory'
|
|
6
|
-
import type { Env, Variables } from '../types'
|
|
7
|
-
import { getHydratedRegistry } from '../shared/seed-registry-cache'
|
|
8
|
-
|
|
9
|
-
/**
|
|
10
|
-
* Hydrates the seed registry from D1 and injects seedRegistry, getSeed, and backrefMap
|
|
11
|
-
* into the context. Must run AFTER repositoryMiddleware (needs seedRepository) and
|
|
12
|
-
* BEFORE any handler that reads the registry.
|
|
13
|
-
*/
|
|
14
|
-
export const seedRegistryMiddleware = () =>
|
|
15
|
-
createMiddleware<{ Bindings: Env; Variables: Variables }>(async (context, next) => {
|
|
16
|
-
const { registry, backrefMap } = await getHydratedRegistry(context.get('seedRepository'))
|
|
17
|
-
context.set('seedRegistry', registry)
|
|
18
|
-
context.set('getSeed', (slug: string) => registry.get(slug))
|
|
19
|
-
context.set('backrefMap', backrefMap)
|
|
20
|
-
await next()
|
|
21
|
-
})
|
|
@@ -1,25 +0,0 @@
|
|
|
1
|
-
// SPDX-License-Identifier: BUSL-1.1
|
|
2
|
-
// Copyright (c) 2024–2026 Flavio De Musso. All rights reserved.
|
|
3
|
-
// See LICENSE in the repository root for license terms.
|
|
4
|
-
|
|
5
|
-
import { createMiddleware } from 'hono/factory'
|
|
6
|
-
import { BeechBucket } from '@beechcms/core'
|
|
7
|
-
import { AppEnv } from '../types'
|
|
8
|
-
import { createBucketProvider } from '../shared/storage/factory'
|
|
9
|
-
|
|
10
|
-
interface StorageOverrides {
|
|
11
|
-
bucket?: BeechBucket
|
|
12
|
-
}
|
|
13
|
-
|
|
14
|
-
export const storageMiddleware = (overrides?: StorageOverrides) => {
|
|
15
|
-
return createMiddleware<AppEnv>(async (context, next) => {
|
|
16
|
-
if (overrides?.bucket) {
|
|
17
|
-
context.set('bucket', overrides.bucket)
|
|
18
|
-
} else {
|
|
19
|
-
// Determine base URL for getUrl() only if we need to create the provider
|
|
20
|
-
const baseUrl = context.env.MEDIA_BASE_URL?.trim().replace(/\/$/, '') || new URL(context.req.url).origin
|
|
21
|
-
context.set('bucket', createBucketProvider(context.env, baseUrl))
|
|
22
|
-
}
|
|
23
|
-
await next()
|
|
24
|
-
})
|
|
25
|
-
}
|
package/src/middleware.ts
DELETED
|
@@ -1,45 +0,0 @@
|
|
|
1
|
-
// SPDX-License-Identifier: BUSL-1.1
|
|
2
|
-
// Copyright (c) 2024–2026 Flavio De Musso. All rights reserved.
|
|
3
|
-
// See LICENSE in the repository root for license terms.
|
|
4
|
-
|
|
5
|
-
/// <reference types="@cloudflare/workers-types" />
|
|
6
|
-
import type { Context, Next } from 'hono'
|
|
7
|
-
import { HTTPException } from 'hono/http-exception'
|
|
8
|
-
import type { Env, Variables } from './types'
|
|
9
|
-
|
|
10
|
-
const UNAUTHORIZED_JSON = JSON.stringify({ error: 'Unauthorized' })
|
|
11
|
-
|
|
12
|
-
function unauthorizedResponse() {
|
|
13
|
-
return new Response(UNAUTHORIZED_JSON, {
|
|
14
|
-
status: 401,
|
|
15
|
-
headers: { 'Content-Type': 'application/json' },
|
|
16
|
-
})
|
|
17
|
-
}
|
|
18
|
-
|
|
19
|
-
/**
|
|
20
|
-
* JWT authentication middleware. Reads the Bearer token from the Authorization
|
|
21
|
-
* header and delegates verification to the ITokenService injected in context.
|
|
22
|
-
* Returns 401 on any missing or invalid token; never exposes failure details.
|
|
23
|
-
*/
|
|
24
|
-
export function authMiddleware() {
|
|
25
|
-
return async (c: Context<{ Bindings: Env; Variables: Variables }>, next: Next): Promise<Response | void> => {
|
|
26
|
-
const authHeader = c.req.header('Authorization')
|
|
27
|
-
if (!authHeader?.startsWith('Bearer ')) {
|
|
28
|
-
throw new HTTPException(401, { res: unauthorizedResponse() })
|
|
29
|
-
}
|
|
30
|
-
|
|
31
|
-
const token = authHeader.slice(7)
|
|
32
|
-
if (!token) {
|
|
33
|
-
throw new HTTPException(401, { res: unauthorizedResponse() })
|
|
34
|
-
}
|
|
35
|
-
|
|
36
|
-
const claims = await c.get('tokenService').verify(token)
|
|
37
|
-
|
|
38
|
-
if (!claims) {
|
|
39
|
-
throw new HTTPException(401, { res: unauthorizedResponse() })
|
|
40
|
-
}
|
|
41
|
-
|
|
42
|
-
c.set('jwtPayload', claims)
|
|
43
|
-
await next()
|
|
44
|
-
}
|
|
45
|
-
}
|
|
@@ -1,27 +0,0 @@
|
|
|
1
|
-
// SPDX-License-Identifier: BUSL-1.1
|
|
2
|
-
// Copyright (c) 2024–2026 Flavio De Musso. All rights reserved.
|
|
3
|
-
// See LICENSE in the repository root for license terms.
|
|
4
|
-
|
|
5
|
-
import type { Seed } from '@beechcms/core'
|
|
6
|
-
|
|
7
|
-
export type PublicOperation = 'read' | 'add' | 'edit'
|
|
8
|
-
|
|
9
|
-
function isAllowed(seed: Seed, operation: PublicOperation): boolean {
|
|
10
|
-
if (operation === 'read') return seed.allowPublicRead === true
|
|
11
|
-
if (operation === 'add') return seed.allowPublicPost === true
|
|
12
|
-
return seed.allowPublicEdit === true
|
|
13
|
-
}
|
|
14
|
-
|
|
15
|
-
export function checkPublicOperation(seed: Seed, operation: PublicOperation) {
|
|
16
|
-
if (isAllowed(seed, operation)) {
|
|
17
|
-
return { ok: true } as const
|
|
18
|
-
}
|
|
19
|
-
|
|
20
|
-
return {
|
|
21
|
-
ok: false,
|
|
22
|
-
error: {
|
|
23
|
-
error: 'Forbidden',
|
|
24
|
-
message: `Public ${operation.toUpperCase()} is not allowed for content type '${seed.slug}'.`,
|
|
25
|
-
},
|
|
26
|
-
} as const
|
|
27
|
-
}
|