@beechcms/api 0.4.3 → 0.6.0-preview.1
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/assets/dashboard/Searching.svg +1 -0
- package/assets/dashboard/assets/index-BSjk0Sx9.js +634 -0
- package/assets/dashboard/assets/index-kRCYVN2B.css +1 -0
- package/assets/dashboard/index.html +2 -2
- package/assets/dashboard/noResult.svg +43 -0
- package/assets/dashboard/working.svg +1 -0
- package/migrations/0000_v040_base.sql +27 -0
- package/migrations/0030_test_seeds.sql +125 -0
- package/package.json +14 -9
- package/src/auth/{in-memory-hash-provider.ts → __fixtures__/in-memory-hash-provider.ts} +4 -0
- package/src/auth/{static-token-service.ts → __fixtures__/static-token-service.ts} +4 -0
- package/src/auth/bcrypt-hash-provider.ts +6 -2
- package/src/auth/constants.ts +4 -0
- package/src/auth/generate-refresh-token.test.ts +8 -4
- package/src/auth/hash-provider.test.ts +14 -5
- package/src/auth/jose-token-service.ts +7 -0
- package/src/auth/jwt-claims-passthrough.test.ts +87 -0
- package/src/auth/login.test.ts +9 -1
- package/src/auth/login.ts +5 -1
- package/src/auth/refresh.ts +7 -1
- package/src/auth/token-service.test.ts +9 -1
- package/src/factory.ts +37 -16
- package/src/features/automations/__tests__/action-executors.test.ts +59 -72
- package/src/features/automations/__tests__/automation-runner.test.ts +4 -0
- package/src/features/automations/__tests__/automation-runner.utils.test.ts +4 -0
- package/src/features/automations/__tests__/automations.handler.test.ts +7 -3
- package/src/features/automations/__tests__/automations.repository.test.ts +4 -0
- package/src/features/automations/__tests__/automations.schema.test.ts +92 -2
- package/src/features/automations/__tests__/context-resolver.test.ts +4 -0
- package/src/features/automations/__tests__/cron-runner.test.ts +11 -7
- package/src/features/automations/__tests__/cron-runner.utils.test.ts +4 -0
- package/src/features/automations/__tests__/set-variable.executor.test.ts +77 -0
- package/src/features/automations/__tests__/template-grammar.test.ts +4 -0
- package/src/features/automations/__tests__/webhook.executor.test.ts +142 -0
- package/src/features/automations/__tests__/when-evaluator.test.ts +4 -0
- package/src/features/automations/__tests__/when-pushdown.test.ts +5 -1
- package/src/features/automations/action-executors/create-entry.executor.ts +4 -0
- package/src/features/automations/action-executors/edit-field.executor.ts +4 -0
- package/src/features/automations/action-executors/index.ts +5 -1
- package/src/features/automations/action-executors/send-mail.executor.ts +13 -2
- package/src/features/automations/action-executors/set-variable.executor.ts +15 -2
- package/src/features/automations/action-executors/webhook.executor.ts +55 -13
- package/src/features/automations/automation-runner.ts +4 -0
- package/src/features/automations/automation-runner.utils.ts +4 -0
- package/src/features/automations/automations.handler.ts +4 -0
- package/src/features/automations/automations.schema.ts +19 -2
- package/src/features/automations/context-resolver.ts +4 -0
- package/src/features/automations/cron-runner.ts +4 -0
- package/src/features/automations/cron-runner.utils.ts +4 -0
- package/src/features/automations/filter-translation.ts +4 -0
- package/src/features/automations/index.ts +4 -0
- package/src/features/automations/template-grammar.ts +4 -0
- package/src/features/automations/var-access-resolver.ts +4 -0
- package/src/features/automations/when-evaluator.ts +4 -0
- package/src/features/automations/when-pushdown.ts +4 -0
- package/src/features/backrefs/__tests__/backrefs.handler.test.ts +359 -0
- package/src/features/backrefs/backrefs.handler.ts +168 -0
- package/src/features/backrefs/d1-backref.repository.ts +84 -0
- package/src/features/backrefs/index.ts +5 -0
- package/src/features/content/constants.ts +6 -0
- package/src/features/content/handlers/bulk.handler.ts +185 -0
- package/src/features/content/handlers/create.ts +19 -55
- package/src/features/content/handlers/delete.ts +12 -37
- package/src/features/content/handlers/facets.ts +4 -0
- package/src/features/content/handlers/get.ts +4 -0
- package/src/features/content/handlers/helpers.test.ts +180 -0
- package/src/features/content/handlers/helpers.ts +93 -0
- package/src/features/content/handlers/list.ts +105 -19
- package/src/features/content/handlers/update.ts +19 -64
- package/src/features/content/index.ts +6 -0
- package/src/features/draft/draft.handler.ts +33 -8
- package/src/features/draft/draft.middleware.ts +4 -0
- package/src/features/draft/index.ts +4 -0
- package/src/features/email/email.provider.ts +4 -0
- package/src/features/email/email.service.ts +50 -45
- package/src/features/email/email.types.ts +12 -1
- package/src/features/email/index.ts +4 -0
- package/src/features/email/providers/resend.ts +4 -0
- package/src/features/email/providers/smtp.ts +55 -0
- package/src/features/email/templates/automation-mail.ts +4 -0
- package/src/features/email/templates/password-changed.ts +4 -0
- package/src/features/email/templates/password-reset.ts +4 -0
- package/src/features/email/templates/shell.ts +4 -0
- package/src/features/notifications/index.ts +4 -0
- package/src/features/notifications/notifications.handler.ts +4 -0
- package/src/features/password-reset/index.ts +5 -1
- package/src/features/password-reset/request.ts +12 -2
- package/src/features/password-reset/reset.ts +12 -2
- package/src/features/rotate-field/index.ts +4 -0
- package/src/features/rotate-field/rotate-field.handler.ts +4 -0
- package/src/features/rotate-field/rotate-field.schema.ts +4 -0
- package/src/features/schema/schema.handler.ts +118 -3
- package/src/features/seeds/index.ts +5 -0
- package/src/features/seeds/seeds.handler.test.ts +632 -0
- package/src/features/seeds/seeds.handler.ts +693 -0
- package/src/features/settings/__tests__/settings.handler.test.ts +555 -0
- package/src/features/settings/settings.handler.ts +98 -8
- package/src/features/setup/index.ts +124 -11
- package/src/features/stats/index.ts +4 -0
- package/src/features/stats/stats.handler.ts +11 -21
- package/src/features/webhooks/index.ts +63 -0
- package/src/index.ts +28 -19
- package/src/media-utils.ts +4 -0
- package/src/middleware/auth-providers.middleware.ts +13 -0
- package/src/middleware/observability.middleware.ts +21 -3
- package/src/middleware/rate-limit.middleware.ts +4 -0
- package/src/middleware/repository.middleware.ts +25 -2
- package/src/middleware/seed-registry.middleware.test.ts +97 -0
- package/src/middleware/seed-registry.middleware.ts +21 -0
- package/src/middleware/storage.middleware.ts +4 -0
- package/src/middleware.ts +5 -7
- package/src/public/access-policy.ts +4 -0
- package/src/public/api-key-middleware.ts +4 -0
- package/src/public/cache-utils.ts +38 -34
- package/src/public/entry-projection.ts +46 -42
- package/src/public/idempotency.ts +23 -19
- package/src/public/index.ts +4 -0
- package/src/public/problem-details.ts +71 -0
- package/src/public/public-add.ts +4 -0
- package/src/public/public-edit.ts +4 -0
- package/src/public/public-errors.ts +4 -0
- package/src/public/public-read.ts +4 -0
- package/src/public/public-routes.ts +4 -0
- package/src/public/query-builder.test.ts +4 -0
- package/src/public/query-builder.ts +4 -0
- package/src/public/rate-limit-middleware.ts +4 -0
- package/src/public/read-list.ts +54 -50
- package/src/public/read-single.ts +48 -44
- package/src/public/response-builder.ts +4 -0
- package/src/public/sanitize.ts +4 -0
- package/src/public/slug-utils.ts +4 -0
- package/src/rate-limit/cloudflare-rate-limiter.test.ts +4 -0
- package/src/rate-limit/cloudflare-rate-limiter.ts +4 -0
- package/src/rate-limit/in-memory-rate-limiter.test.ts +4 -0
- package/src/rate-limit/in-memory-rate-limiter.ts +4 -0
- package/src/rate-limit/no-op-rate-limiter.test.ts +4 -0
- package/src/rate-limit/no-op-rate-limiter.ts +4 -0
- package/src/search-utils.test.ts +4 -0
- package/src/search-utils.ts +5 -1
- package/src/search.ts +5 -1
- package/src/shared/apply-policies.test.ts +4 -0
- package/src/shared/apply-policies.ts +4 -0
- package/src/shared/automations.repository.d1.ts +4 -0
- package/src/shared/background-notification-service.test.ts +4 -0
- package/src/shared/background-notification-service.ts +4 -0
- package/src/shared/base.repository.d1.ts +4 -0
- package/src/shared/content-utils.test.ts +4 -0
- package/src/shared/content-utils.ts +4 -0
- package/src/shared/content.repository.d1.test.ts +147 -1
- package/src/shared/content.repository.d1.ts +535 -66
- package/src/shared/d1-activity-log.repository.test.ts +4 -0
- package/src/shared/d1-activity-log.repository.ts +4 -0
- package/src/shared/d1-activity-logger.test.ts +4 -0
- package/src/shared/d1-activity-logger.ts +4 -0
- package/src/shared/d1-analytics.repository.test.ts +4 -0
- package/src/shared/d1-analytics.repository.ts +4 -0
- package/src/shared/d1-content-scan.repository.test.ts +9 -5
- package/src/shared/d1-content-scan.repository.ts +15 -7
- package/src/shared/d1-notification.repository.test.ts +4 -0
- package/src/shared/d1-notification.repository.ts +4 -0
- package/src/shared/d1-password-reset-token.repository.test.ts +4 -0
- package/src/shared/d1-password-reset-token.repository.ts +4 -0
- package/src/shared/d1-search.repository.test.ts +4 -0
- package/src/shared/d1-search.repository.ts +4 -0
- package/src/shared/d1-session.repository.test.ts +4 -0
- package/src/shared/d1-session.repository.ts +4 -0
- package/src/shared/d1-setup-checklist.repository.ts +36 -0
- package/src/shared/d1-user.repository.test.ts +8 -4
- package/src/shared/d1-user.repository.ts +15 -5
- package/src/shared/d1-widget.repository.test.ts +4 -0
- package/src/shared/d1-widget.repository.ts +4 -0
- package/src/shared/demo-data-sql.ts +54 -0
- package/src/shared/demo-data.repository.d1.ts +20 -0
- package/src/shared/execution-context-scheduler.ts +4 -0
- package/src/shared/fixed-clock.ts +4 -0
- package/src/shared/fts-sync.ts +4 -0
- package/src/shared/idempotency.repository.d1.test.ts +4 -0
- package/src/shared/idempotency.repository.d1.ts +4 -0
- package/src/shared/in-memory-activity-logger.ts +4 -0
- package/src/shared/in-memory-notification-service.ts +4 -0
- package/src/shared/in-memory-seed.repository.ts +51 -0
- package/src/shared/media.repository.d1.test.ts +4 -0
- package/src/shared/media.repository.d1.ts +4 -0
- package/src/shared/qstash-notification-service.test.ts +67 -0
- package/src/shared/qstash-notification-service.ts +55 -0
- package/src/shared/query-utils.ts +4 -0
- package/src/shared/request-utils.ts +4 -0
- package/src/shared/schema-mutator.d1.ts +64 -0
- package/src/shared/seed-layout.repository.d1.test.ts +114 -0
- package/src/shared/seed-layout.repository.d1.ts +62 -0
- package/src/shared/seed-registry-cache.test.ts +68 -0
- package/src/shared/seed-registry-cache.ts +49 -0
- package/src/shared/seed.repository.d1.test.ts +143 -0
- package/src/shared/seed.repository.d1.ts +98 -0
- package/src/shared/sequential-id-generator.ts +11 -0
- package/src/shared/site-settings.repository.d1.ts +53 -0
- package/src/shared/storage/factory.ts +16 -15
- package/src/shared/storage/s3-bucket.ts +34 -2
- package/src/shared/storage-utils.ts +4 -0
- package/src/shared/system-stats.repository.d1.test.ts +4 -0
- package/src/shared/system-stats.repository.d1.ts +5 -1
- package/src/types.ts +23 -3
- package/src/upload.ts +134 -123
- package/src/widget.ts +6 -2
- package/assets/dashboard/assets/index-BKWnlvnV.css +0 -1
- package/assets/dashboard/assets/index-BMkd1Irh.js +0 -629
- package/src/shared/storage/r2-binding-bucket.ts +0 -81
|
@@ -1,3 +1,7 @@
|
|
|
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
|
+
|
|
1
5
|
import { describe, it, expect, vi } from 'vitest'
|
|
2
6
|
import { D1ActivityLogRepository } from './d1-activity-log.repository'
|
|
3
7
|
|
|
@@ -1,3 +1,7 @@
|
|
|
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
|
+
|
|
1
5
|
import { describe, it, expect, vi } from 'vitest'
|
|
2
6
|
import { D1ActivityLogger } from './d1-activity-logger'
|
|
3
7
|
import type { ActivityLogEntry } from '@beechcms/core'
|
|
@@ -1,3 +1,7 @@
|
|
|
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
|
+
|
|
1
5
|
/// <reference types="@cloudflare/workers-types" />
|
|
2
6
|
import type { IActivityLogger, ActivityLogEntry, IClock, IIdGenerator } from '@beechcms/core'
|
|
3
7
|
|
|
@@ -1,3 +1,7 @@
|
|
|
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
|
+
|
|
1
5
|
import { describe, it, expect, vi } from 'vitest'
|
|
2
6
|
import { D1AnalyticsRepository } from './d1-analytics.repository'
|
|
3
7
|
import { FixedClock } from './fixed-clock'
|
|
@@ -1,3 +1,7 @@
|
|
|
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
|
+
|
|
1
5
|
/// <reference types="@cloudflare/workers-types" />
|
|
2
6
|
import type { IAnalyticsRepository, AnalyticsMetric, IClock } from '@beechcms/core'
|
|
3
7
|
|
|
@@ -1,3 +1,7 @@
|
|
|
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
|
+
|
|
1
5
|
import { describe, it, expect, vi } from 'vitest'
|
|
2
6
|
import type { Seed } from '@beechcms/core'
|
|
3
7
|
import { D1ContentScanRepository } from './d1-content-scan.repository'
|
|
@@ -25,7 +29,7 @@ describe('D1ContentScanRepository', () => {
|
|
|
25
29
|
label: 'Post',
|
|
26
30
|
displayNameAlias: 'title',
|
|
27
31
|
branches: [
|
|
28
|
-
{ alias: 'title', type: 'text', label: 'Title' },
|
|
32
|
+
{ id: 'br_01', alias: 'title', type: 'text', label: 'Title' },
|
|
29
33
|
],
|
|
30
34
|
}
|
|
31
35
|
const result = await repo.getReferencedMediaKeys([seedWithoutFile])
|
|
@@ -45,9 +49,9 @@ describe('D1ContentScanRepository', () => {
|
|
|
45
49
|
label: 'Article',
|
|
46
50
|
displayNameAlias: 'title',
|
|
47
51
|
branches: [
|
|
48
|
-
{ alias: 'title', type: 'text', label: 'Title' },
|
|
49
|
-
{ alias: 'cover', type: 'file', label: 'Cover' },
|
|
50
|
-
{ alias: 'gallery', type: 'file', label: 'Gallery' },
|
|
52
|
+
{ id: 'br_01', alias: 'title', type: 'text', label: 'Title' },
|
|
53
|
+
{ id: 'br_02', alias: 'cover', type: 'file', label: 'Cover' },
|
|
54
|
+
{ id: 'br_03', alias: 'gallery', type: 'file', label: 'Gallery' },
|
|
51
55
|
],
|
|
52
56
|
}
|
|
53
57
|
|
|
@@ -66,7 +70,7 @@ describe('D1ContentScanRepository', () => {
|
|
|
66
70
|
label: 'Article',
|
|
67
71
|
displayNameAlias: 'title',
|
|
68
72
|
branches: [
|
|
69
|
-
{ alias: 'cover', type: 'file', label: 'Cover' },
|
|
73
|
+
{ id: 'br_01', alias: 'cover', type: 'file', label: 'Cover' },
|
|
70
74
|
],
|
|
71
75
|
}
|
|
72
76
|
|
|
@@ -1,3 +1,7 @@
|
|
|
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
|
+
|
|
1
5
|
import type { D1Database } from '@cloudflare/workers-types'
|
|
2
6
|
import type { IContentScanRepository, Seed } from '@beechcms/core'
|
|
3
7
|
|
|
@@ -12,15 +16,19 @@ export class D1ContentScanRepository implements IContentScanRepository {
|
|
|
12
16
|
if (mediaFields.length === 0) continue
|
|
13
17
|
|
|
14
18
|
const mediaColumns = mediaFields.map(field => field.alias).join(', ')
|
|
15
|
-
|
|
16
|
-
|
|
17
|
-
|
|
19
|
+
try {
|
|
20
|
+
const contentData = await this.db.prepare(
|
|
21
|
+
`SELECT ${mediaColumns} FROM content_${seed.slug}`
|
|
22
|
+
).all<Record<string, string | null>>()
|
|
18
23
|
|
|
19
|
-
|
|
20
|
-
|
|
21
|
-
|
|
22
|
-
|
|
24
|
+
for (const contentRow of contentData.results ?? []) {
|
|
25
|
+
const rowContentString = Object.values(contentRow).filter(Boolean).join(' ')
|
|
26
|
+
for (const keyMatch of rowContentString.matchAll(/\/api\/media\/([^"'\s\\,}\]]+)/g)) {
|
|
27
|
+
referencedMediaKeys.add(decodeURIComponent(keyMatch[1]))
|
|
28
|
+
}
|
|
23
29
|
}
|
|
30
|
+
} catch {
|
|
31
|
+
// Table not yet created (seed:load not run) — skip this seed gracefully
|
|
24
32
|
}
|
|
25
33
|
}
|
|
26
34
|
|
|
@@ -1,3 +1,7 @@
|
|
|
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
|
+
|
|
1
5
|
import { describe, it, expect, vi } from 'vitest'
|
|
2
6
|
import { D1NotificationRepository } from './d1-notification.repository'
|
|
3
7
|
import { FixedClock } from './fixed-clock'
|
|
@@ -1,3 +1,7 @@
|
|
|
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
|
+
|
|
1
5
|
import { describe, it, expect, vi } from 'vitest'
|
|
2
6
|
import { D1PasswordResetTokenRepository } from './d1-password-reset-token.repository'
|
|
3
7
|
|
|
@@ -1,3 +1,7 @@
|
|
|
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
|
+
|
|
1
5
|
/// <reference types="@cloudflare/workers-types" />
|
|
2
6
|
import type { IPasswordResetTokenRepository, NewPasswordResetToken, ValidatedResetToken, IIdGenerator } from '@beechcms/core'
|
|
3
7
|
|
|
@@ -1,3 +1,7 @@
|
|
|
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
|
+
|
|
1
5
|
import { describe, it, expect, vi } from 'vitest'
|
|
2
6
|
import type { Seed } from '@beechcms/core'
|
|
3
7
|
import { D1SearchRepository } from './d1-search.repository'
|
|
@@ -1,3 +1,7 @@
|
|
|
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
|
+
|
|
1
5
|
import { describe, it, expect, vi } from 'vitest'
|
|
2
6
|
import { D1SessionRepository } from './d1-session.repository'
|
|
3
7
|
import { FixedClock } from './fixed-clock'
|
|
@@ -1,3 +1,7 @@
|
|
|
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
|
+
|
|
1
5
|
/// <reference types="@cloudflare/workers-types" />
|
|
2
6
|
import type { ISessionRepository, NewRefreshToken, RefreshTokenRecord, ActiveSessionSummary, IClock } from '@beechcms/core'
|
|
3
7
|
|
|
@@ -0,0 +1,36 @@
|
|
|
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
|
+
|
|
7
|
+
export interface ISetupChecklistRepository {
|
|
8
|
+
getExistingTableNames(): Promise<Set<string>>
|
|
9
|
+
countAdmins(): Promise<number>
|
|
10
|
+
countEntriesInSeed(slug: string): Promise<number>
|
|
11
|
+
}
|
|
12
|
+
|
|
13
|
+
export class D1SetupChecklistRepository implements ISetupChecklistRepository {
|
|
14
|
+
constructor(private readonly db: D1Database) {}
|
|
15
|
+
|
|
16
|
+
async getExistingTableNames(): Promise<Set<string>> {
|
|
17
|
+
const result = await this.db
|
|
18
|
+
.prepare(`SELECT name FROM sqlite_master WHERE type='table'`)
|
|
19
|
+
.all<{ name: string }>()
|
|
20
|
+
return new Set((result.results ?? []).map(row => row.name))
|
|
21
|
+
}
|
|
22
|
+
|
|
23
|
+
async countAdmins(): Promise<number> {
|
|
24
|
+
const result = await this.db
|
|
25
|
+
.prepare(`SELECT COUNT(*) as count FROM users WHERE role = 'admin'`)
|
|
26
|
+
.first<{ count: number }>()
|
|
27
|
+
return result?.count ?? 0
|
|
28
|
+
}
|
|
29
|
+
|
|
30
|
+
async countEntriesInSeed(slug: string): Promise<number> {
|
|
31
|
+
const result = await this.db
|
|
32
|
+
.prepare(`SELECT COUNT(*) as count FROM content_${slug}`)
|
|
33
|
+
.first<{ count: number }>()
|
|
34
|
+
return result?.count ?? 0
|
|
35
|
+
}
|
|
36
|
+
}
|
|
@@ -1,3 +1,7 @@
|
|
|
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
|
+
|
|
1
5
|
import { describe, it, expect, vi } from 'vitest'
|
|
2
6
|
import { D1UserRepository } from './d1-user.repository'
|
|
3
7
|
|
|
@@ -79,17 +83,17 @@ describe('D1UserRepository', () => {
|
|
|
79
83
|
it('calls prepare with an INSERT INTO users statement', async () => {
|
|
80
84
|
const { db, prepareMock } = makeMockDb()
|
|
81
85
|
await new D1UserRepository(db).create({
|
|
82
|
-
id: 'u1', email: 'a@b.com', passwordHash: 'hash', role: 'admin', name: 'Test',
|
|
86
|
+
id: 'u1', email: 'a@b.com', passwordHash: 'hash', role: 'admin', name: 'Test', surname: null,
|
|
83
87
|
})
|
|
84
88
|
expect(prepareMock).toHaveBeenCalledWith(expect.stringContaining('INSERT INTO users'))
|
|
85
89
|
})
|
|
86
90
|
|
|
87
|
-
it('binds id, email, passwordHash, role, name in the correct order', async () => {
|
|
91
|
+
it('binds id, email, passwordHash, role, name, surname in the correct order', async () => {
|
|
88
92
|
const { db, bindMock } = makeMockDb()
|
|
89
93
|
await new D1UserRepository(db).create({
|
|
90
|
-
id: 'u1', email: 'a@b.com', passwordHash: 'hash', role: 'admin', name: 'Test',
|
|
94
|
+
id: 'u1', email: 'a@b.com', passwordHash: 'hash', role: 'admin', name: 'Test', surname: null,
|
|
91
95
|
})
|
|
92
|
-
expect(bindMock).toHaveBeenCalledWith('u1', 'a@b.com', 'hash', 'admin', 'Test')
|
|
96
|
+
expect(bindMock).toHaveBeenCalledWith('u1', 'a@b.com', 'hash', 'admin', 'Test', null)
|
|
93
97
|
})
|
|
94
98
|
})
|
|
95
99
|
|
|
@@ -1,3 +1,7 @@
|
|
|
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
|
+
|
|
1
5
|
/// <reference types="@cloudflare/workers-types" />
|
|
2
6
|
import type { IUserRepository, UserRecord, NewUserInput } from '@beechcms/core'
|
|
3
7
|
|
|
@@ -5,6 +9,7 @@ type UserRow = {
|
|
|
5
9
|
id: string
|
|
6
10
|
email: string
|
|
7
11
|
name: string | null
|
|
12
|
+
surname: string | null
|
|
8
13
|
password_hash: string
|
|
9
14
|
role: string
|
|
10
15
|
avatar_url: string | null
|
|
@@ -16,6 +21,7 @@ function rowToRecord(row: UserRow): UserRecord {
|
|
|
16
21
|
id: row.id,
|
|
17
22
|
email: row.email,
|
|
18
23
|
name: row.name,
|
|
24
|
+
surname: row.surname,
|
|
19
25
|
passwordHash: row.password_hash,
|
|
20
26
|
role: row.role,
|
|
21
27
|
avatarUrl: row.avatar_url,
|
|
@@ -35,7 +41,7 @@ export class D1UserRepository implements IUserRepository {
|
|
|
35
41
|
|
|
36
42
|
async findById(userId: string): Promise<UserRecord | null> {
|
|
37
43
|
const row = await this.db
|
|
38
|
-
.prepare('SELECT id, email, name, password_hash, role, avatar_url, notification_prefs FROM users WHERE id = ? LIMIT 1')
|
|
44
|
+
.prepare('SELECT id, email, name, surname, password_hash, role, avatar_url, notification_prefs FROM users WHERE id = ? LIMIT 1')
|
|
39
45
|
.bind(userId)
|
|
40
46
|
.first<UserRow>()
|
|
41
47
|
return row ? rowToRecord(row) : null
|
|
@@ -43,7 +49,7 @@ export class D1UserRepository implements IUserRepository {
|
|
|
43
49
|
|
|
44
50
|
async findByEmail(email: string): Promise<UserRecord | null> {
|
|
45
51
|
const row = await this.db
|
|
46
|
-
.prepare('SELECT id, email, name, password_hash, role, avatar_url, notification_prefs FROM users WHERE email = ? LIMIT 1')
|
|
52
|
+
.prepare('SELECT id, email, name, surname, password_hash, role, avatar_url, notification_prefs FROM users WHERE email = ? LIMIT 1')
|
|
47
53
|
.bind(email)
|
|
48
54
|
.first<UserRow>()
|
|
49
55
|
return row ? rowToRecord(row) : null
|
|
@@ -51,12 +57,12 @@ export class D1UserRepository implements IUserRepository {
|
|
|
51
57
|
|
|
52
58
|
async create(user: NewUserInput): Promise<void> {
|
|
53
59
|
await this.db
|
|
54
|
-
.prepare('INSERT INTO users (id, email, password_hash, role, name) VALUES (?, ?, ?, ?, ?)')
|
|
55
|
-
.bind(user.id, user.email, user.passwordHash, user.role, user.name)
|
|
60
|
+
.prepare('INSERT INTO users (id, email, password_hash, role, name, surname) VALUES (?, ?, ?, ?, ?, ?)')
|
|
61
|
+
.bind(user.id, user.email, user.passwordHash, user.role, user.name, user.surname)
|
|
56
62
|
.run()
|
|
57
63
|
}
|
|
58
64
|
|
|
59
|
-
async updateProfile(userId: string, fields: { name?: string; email?: string }): Promise<void> {
|
|
65
|
+
async updateProfile(userId: string, fields: { name?: string; surname?: string; email?: string }): Promise<void> {
|
|
60
66
|
const columnAssignments: string[] = []
|
|
61
67
|
const boundValues: unknown[] = []
|
|
62
68
|
|
|
@@ -64,6 +70,10 @@ export class D1UserRepository implements IUserRepository {
|
|
|
64
70
|
columnAssignments.push('name = ?')
|
|
65
71
|
boundValues.push(fields.name)
|
|
66
72
|
}
|
|
73
|
+
if (fields.surname !== undefined) {
|
|
74
|
+
columnAssignments.push('surname = ?')
|
|
75
|
+
boundValues.push(fields.surname)
|
|
76
|
+
}
|
|
67
77
|
if (fields.email !== undefined) {
|
|
68
78
|
columnAssignments.push('email = ?')
|
|
69
79
|
boundValues.push(fields.email)
|
|
@@ -1,3 +1,7 @@
|
|
|
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
|
+
|
|
1
5
|
import { describe, it, expect, vi } from 'vitest'
|
|
2
6
|
import type { Seed } from '@beechcms/core'
|
|
3
7
|
import { D1WidgetRepository } from './d1-widget.repository'
|
|
@@ -0,0 +1,54 @@
|
|
|
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
|
+
// Compiled-in demo dataset. Workers have no runtime FS so the SQL from
|
|
6
|
+
// migrations/0028_v040_seed_data.sql is bundled here as a string constant.
|
|
7
|
+
export const DEMO_DATA_SQL = `
|
|
8
|
+
INSERT OR IGNORE INTO content_team (id, slug, status, name, role, bio, photo, linkedIn, active, metaTitle, metaDescription, created_at, updated_at) VALUES
|
|
9
|
+
('tm-0001', 'flavio-de-musso', 'published', 'Flavio De Musso', 'Founder & Principal Engineer', 'Progetta architetture moderne per CMS headless e prodotti digitali edge-native.', 'https://images.unsplash.com/photo-1507003211169-0a1dd7228f2d?w=400&q=80', 'https://www.linkedin.com/in/flaviodemusso', 1, 'Flavio De Musso', 'Founder e creatore di Beech CMS.', unixepoch(), unixepoch()),
|
|
10
|
+
('tm-0002', 'laura-rossi', 'published', 'Laura Rossi', 'Product Designer', 'Cura la UX della dashboard e dei workflow editoriali. Specializzata in design system a scala.', 'https://images.unsplash.com/photo-1494790108377-be9c29b29330?w=400&q=80', 'https://www.linkedin.com/in/', 1, 'Laura Rossi – Designer', 'UX designer focalizzata su strumenti per content team.', unixepoch(), unixepoch()),
|
|
11
|
+
('tm-0003', 'marco-bianchi', 'published', 'Marco Bianchi', 'Frontend Engineer', 'Sviluppa i field renderer React e il registry della UI. Appassionato di performance web.', 'https://images.unsplash.com/photo-1500648767791-00dcc994a43e?w=400&q=80', 'https://www.linkedin.com/in/', 1, 'Marco Bianchi – Engineer', 'Sviluppatore frontend specializzato in React e UX.', unixepoch(), unixepoch()),
|
|
12
|
+
('tm-0004', 'giulia-verdi', 'published', 'Giulia Verdi', 'Developer Relations', 'Aiuta i team a integrare Beech CMS nelle loro pipeline di sviluppo. Developer Advocate.', 'https://images.unsplash.com/photo-1438761681033-6461ffad8d80?w=400&q=80', 'https://www.linkedin.com/in/', 1, 'Giulia Verdi – DevRel', 'Developer advocate per la community Beech.', unixepoch(), unixepoch()),
|
|
13
|
+
('tm-0005', 'andrea-neri', 'published', 'Andrea Neri', 'Support Specialist', 'Supporto di primo livello per clienti enterprise e gestione della knowledge base.', 'https://images.unsplash.com/photo-1472099645785-5658abf4ff4e?w=400&q=80', 'https://www.linkedin.com/in/', 1, 'Andrea Neri – Support', 'Supporto tecnico e customer success.', unixepoch(), unixepoch());
|
|
14
|
+
|
|
15
|
+
INSERT OR IGNORE INTO content_prodotti (id, slug, status, name, price, stock, active, coverImage, images, description, metaTitle, metaDescription, created_at, updated_at) VALUES
|
|
16
|
+
('prd-0001', 'beech-starter', 'published', 'Beech Starter', 490, 50, 1, 'https://images.unsplash.com/photo-1496181133206-80ce9b88a853?w=800&q=80', '[]', '<p>Piano entry-level per piccoli siti e landing page. Include il Botanical Engine, la dashboard, e 1GB di storage R2.</p>', 'Beech Starter', 'Piano starter per progetti piccoli e medi.', unixepoch(), unixepoch()),
|
|
17
|
+
('prd-0002', 'beech-pro', 'published', 'Beech Pro', 1290, 30, 1, 'https://images.unsplash.com/photo-1499951360447-b19be8fe80f5?w=800&q=80', '[]', '<p>Tutte le feature avanzate per team strutturati: draft workflow, analytics per-seed, FTS5 full-text search, 10GB storage R2.</p>', 'Beech Pro', 'Piano professionale per agenzie e team marketing.', unixepoch(), unixepoch()),
|
|
18
|
+
('prd-0003', 'beech-enterprise', 'published', 'Beech Enterprise', 3990, 10, 1, 'https://images.unsplash.com/photo-1522071820081-009f0129c71c?w=800&q=80', '[]', '<p>Funzionalità enterprise, audit log, SLA garantito, multi-ambiente staging/production, e storage R2 illimitato.</p>', 'Beech Enterprise', 'Soluzione enterprise per grandi organizzazioni.', unixepoch(), unixepoch()),
|
|
19
|
+
('prd-0004', 'implementazione-custom', 'published', 'Implementazione custom', 15000, 3, 1, 'https://images.unsplash.com/photo-1593642532744-d377ab507dc8?w=800&q=80', '[]', '<p>Servizio di implementazione su misura di Beech CMS: analisi dei requisiti, definizione dei Seed, deploy su Cloudflare, formazione team.</p>', 'Implementazione custom Beech', 'Servizio di onboarding e integrazione personalizzata.', unixepoch(), unixepoch()),
|
|
20
|
+
('prd-0005', 'workshop-botanical-engine', 'published', 'Workshop Botanical Engine', 990, 20, 1, 'https://images.unsplash.com/photo-1561070791-2526d30994b5?w=800&q=80', '[]', '<p>Workshop avanzato sul Botanical Engine e sul registry dei seed. Impara a definire Seed ottimali e a usare beech seed:load per deployare schemi.</p>', 'Workshop Botanical Engine', 'Formazione per team tecnici su Beech CMS.', unixepoch(), unixepoch());
|
|
21
|
+
|
|
22
|
+
INSERT OR IGNORE INTO content_articoli (id, slug, status, title, publishedAt, coverImage, tags, body, metaTitle, metaDescription, created_at, updated_at) VALUES
|
|
23
|
+
('art-0001', 'benvenuto-nel-blog', 'published', 'Benvenuto nel blog Beech', 1736467200, 'https://images.unsplash.com/photo-1633356122544-f134324a6cee?w=800&q=80', '["news","annuncio"]', '<p>Scopri come Beech CMS gestisce contenuti schema-driven con tabelle SQL dedicate per ogni tipo di contenuto.</p><h3>Architettura moderna</h3><p>Beech v0.4.0 elimina il JSON blob e usa colonne reali per ogni Branch del Seed. Il risultato è performance migliorate e query native SQLite.</p>', 'Benvenuto nel blog Beech', 'Introduzione al CMS headless schema-driven.', unixepoch(), unixepoch()),
|
|
24
|
+
('art-0002', 'roadmap-2026', 'published', 'Roadmap prodotto 2026', 1738713600, 'https://images.unsplash.com/photo-1557804506-669a67965ba0?w=800&q=80', '["release","aggiornamento"]', '<p>Tutte le novità in arrivo per Beech CMS nel 2026: Doctype Architecture, CLI seed:load, FTS5 per-seed, e molto altro.</p><h3>Fase 1 — Core</h3><p>Il Botanical Engine diventa un compilatore di schema che genera DDL SQL dalla definizione TypeScript dei Seed.</p>', 'Roadmap Beech CMS 2026', 'Piano di sviluppo delle funzionalità per il 2026.', unixepoch(), unixepoch()),
|
|
25
|
+
('art-0003', 'migrare-da-wordpress', 'published', 'Migrare da WordPress a Beech', 1740182400, 'https://images.unsplash.com/photo-1542831371-29b0f74f9713?w=800&q=80', '["guida","cms"]', '<p>Guida pratica per migrare contenuti da WordPress a Beech CMS senza downtime. Esporta, trasforma e importa usando la Public API.</p><h3>Step 1: Esporta da WordPress</h3><p>Usa il plugin WP All Export per ottenere CSV o JSON dai post. Poi mappali alle colonne del tuo Seed.</p>', 'Migrazione da WordPress a Beech', 'Strategie per migrare contenuti in sicurezza.', unixepoch(), unixepoch()),
|
|
26
|
+
('art-0004', 'pattern-registry-ui', 'published', 'Il Pattern Registry della UI', 1740873600, 'https://images.unsplash.com/photo-1561070791-2526d30994b5?w=800&q=80', '["tutorial","guida"]', '<p>Come il registry dei field renderer semplifica la dashboard: ogni Branch type ha un renderer React dedicato, registrato centralmente e richiamato automaticamente.</p>', 'Pattern Registry UI Beech', 'Architettura dei componenti field-driven.', unixepoch(), unixepoch()),
|
|
27
|
+
('art-0005', 'edge-first-architecture', 'published', 'Architettura edge-first con Cloudflare', 1741132800, 'https://images.unsplash.com/photo-1558494949-ef010cbdcc31?w=800&q=80', '["news","aggiornamento"]', '<p>Perché Beech nasce per l''edge: latenza minima, zero cold start, D1 SQLite replicato globalmente su Cloudflare. Il CMS arriva dove si trovano gli utenti.</p>', 'Architettura edge-first', 'Vantaggi di un CMS progettato per l''edge.', unixepoch(), unixepoch());
|
|
28
|
+
|
|
29
|
+
INSERT OR IGNORE INTO content_testimonianze (id, slug, status, author, company, quote, rating, date, photo, active, metaTitle, metaDescription, created_at, updated_at) VALUES
|
|
30
|
+
('tes-0001', 'acme-corp', 'published', 'Chiara Conti', 'Acme Corp', 'Con Beech CMS abbiamo ridotto del 60% il tempo di pubblicazione dei contenuti.', 5, 1737331200, 'https://images.unsplash.com/photo-1573497019940-1c28c88b4f3e?w=400&q=80', 1, 'Caso studio Acme', 'Come Acme ha accelerato i workflow editoriali.', unixepoch(), unixepoch()),
|
|
31
|
+
('tes-0002', 'studio-x', 'published', 'Luca Ferri', 'Studio X', 'La flessibilità degli schema ci ha permesso di iterare velocemente sul design del sito.', 4, 1738195200, 'https://images.unsplash.com/photo-1560250097-0b93528c311a?w=400&q=80', 1, 'Testimonianza Studio X', 'Feedback di un''agenzia digital sul CMS.', unixepoch(), unixepoch()),
|
|
32
|
+
('tes-0003', 'media-hub', 'published', 'Sara Galli', 'MediaHub', 'Finalmente un CMS pensato per il contenuto, non per il database. Team felicissimo.', 5, 1739404800, 'https://images.unsplash.com/photo-1580489944761-15a19d654956?w=400&q=80', 1, 'Testimonianza MediaHub', 'Perché i content team amano Beech.', unixepoch(), unixepoch()),
|
|
33
|
+
('tes-0004', 'shop-co', 'published', 'Davide Rizzi', 'ShopCo', 'Gestire landing e pagine prodotto è diventato molto più semplice. Alta raccomandazione.', 4, 1740268800, 'https://images.unsplash.com/photo-1507003211169-0a1dd7228f2d?w=400&q=80', 1, 'Testimonianza ShopCo', 'Beech CMS per e-commerce moderni.', unixepoch(), unixepoch()),
|
|
34
|
+
('tes-0005', 'fit-tech', 'published', 'Elena Santi', 'FitTech Inc', 'La dashboard è così intuitiva che il team marketing la usa senza training.', 5, 1741046400, 'https://images.unsplash.com/photo-1573497019940-1c28c88b4f3e?w=400&q=80', 1, 'Testimonianza FitTech', 'Esperienza di un team marketing su Beech CMS.', unixepoch(), unixepoch());
|
|
35
|
+
|
|
36
|
+
INSERT OR IGNORE INTO content_pagine (id, slug, status, title, coverImage, body, metaTitle, metaDescription, created_at, updated_at) VALUES
|
|
37
|
+
('pag-0001', 'home', 'published', 'Homepage', 'https://images.unsplash.com/photo-1517694712202-14dd9538aa97?w=1200&q=80', '<h1>Beech CMS</h1><p>Il CMS schema-driven per l''era edge. Definisci i tuoi Seed in TypeScript, deploya su Cloudflare, e inizia a pubblicare.</p>', 'Beech CMS - Homepage', 'CMS moderno schema-driven per deployment edge.', unixepoch(), unixepoch()),
|
|
38
|
+
('pag-0002', 'il-prodotto', 'published', 'Il prodotto', 'https://images.unsplash.com/photo-1551288049-bebda4e38f71?w=1200&q=80', '<h1>Perché Beech</h1><p>Architettura ibrida con tabelle SQL dedicate per Seed, Botanical Engine come compilatore di schema, e CLI per il deploy.</p>', 'Perché scegliere Beech', 'Scopri le funzionalità chiave di Beech CMS.', unixepoch(), unixepoch()),
|
|
39
|
+
('pag-0003', 'casi-studio', 'published', 'Casi studio', 'https://images.unsplash.com/photo-1552664730-d307ca884978?w=1200&q=80', '<h1>Storie di successo</h1><p>Come i team usano Beech ogni giorno per pubblicare contenuti velocemente con la dashboard schema-driven.</p>', 'Casi studio Beech', 'Raccolta di case study su Beech CMS.', unixepoch(), unixepoch()),
|
|
40
|
+
('pag-0004', 'pricing', 'published', 'Pricing', 'https://images.unsplash.com/photo-1554224155-6726b3ff858f?w=1200&q=80', '<h1>Piani e prezzi</h1><p>Scegli il piano adatto al tuo team: Starter, Pro o Enterprise. Tutti includono il Botanical Engine e la dashboard.</p>', 'Pricing Beech CMS', 'Confronta i piani Starter, Pro ed Enterprise.', unixepoch(), unixepoch()),
|
|
41
|
+
('pag-0005', 'contatti', 'published', 'Contatti', 'https://images.unsplash.com/photo-1423666639041-f56000c27a9a?w=1200&q=80', '<h1>Parliamo del tuo progetto</h1><p>Compila il form per una demo gratuita. Il team risponde entro 24 ore lavorative.</p>', 'Contatta Beech', 'Richiedi una demo o una consulenza su Beech CMS.', unixepoch(), unixepoch());
|
|
42
|
+
|
|
43
|
+
INSERT OR IGNORE INTO content_clienti (id, slug, status, name, email, passwordHash, tier, phone, internalNote, registeredAt, active, created_at, updated_at) VALUES
|
|
44
|
+
('clt-0001', 'marco-rossi', 'published', 'Marco Rossi', 'marco.rossi@acmecorp.it', '5e884898da28047151d0e56f8dc6292773603d0d6aabbdd62a11ef721d1542d8', 'enterprise', '+39 02 1234 5678', 'Cliente storico. Sconto applicato del 20% su rinnovo annuale.', 1710460800, 1, unixepoch(), unixepoch()),
|
|
45
|
+
('clt-0002', 'laura-bianchi', 'published', 'Laura Bianchi', 'laura.bianchi@studiox.io', '8d969eef6ecad3c29a3a629280e686cf0c3f5d5a86aff3ca12020c923adc6c92', 'pro', '+39 06 9876 5432', 'Contattare prima del rinnovo per upsell a enterprise.', 1736294400, 1, unixepoch(), unixepoch()),
|
|
46
|
+
('clt-0003', 'davide-ferrari', 'published', 'Davide Ferrari', 'davide@mediahub.eu', '1c8bfe8f801d79745c4631d09fff36c82aa37fc4cce4fc946683d7b336b63032', 'starter', '+39 011 4567 890', 'Ha richiesto supporto per migrazione da WordPress.', 1750550400, 1, unixepoch(), unixepoch()),
|
|
47
|
+
('clt-0004', 'giulia-verdi', 'published', 'Giulia Verdi', 'giulia.verdi@personal.me', '6ca13d52ca70c883e0f0bb101e425a89e8624de51db2d2392593af6a84118090', 'free', '+39 081 3210 987', 'Account free scaduto. Inviare offerta upgrade.', 1756771200, 0, unixepoch(), unixepoch()),
|
|
48
|
+
('clt-0005', 'sofia-costa', 'published', 'Sofia Costa', 'sofia.costa@fittech.com', '65e84be33532fb784c48129675f9eff3a682b27168c0ea744b2cf58ee02337c5', 'pro', NULL, NULL, 1769731200, 1, unixepoch(), unixepoch());
|
|
49
|
+
|
|
50
|
+
INSERT OR IGNORE INTO content_messaggi (id, slug, status, name, email, subject, message, read, created_at, updated_at) VALUES
|
|
51
|
+
('msg-0001', 'msg-demo-1', 'published', 'Riccardo Esposito', 'riccardo@example.com', 'Richiesta demo Beech Pro', '<p>Buongiorno, siamo un''agenzia di 8 persone e vorremmo valutare Beech Pro per i nostri clienti. Possiamo fissare una call la prossima settimana?</p>', 0, unixepoch(), unixepoch()),
|
|
52
|
+
('msg-0002', 'msg-demo-2', 'published', 'Anna Marchetti', 'anna@startup.io', 'Domanda su FTS5 e ricerca full-text', '<p>Ciao team! Sto valutando Beech per un progetto di knowledge base. La ricerca full-text FTS5 funziona anche sulla versione Starter? Grazie.</p>', 1, unixepoch(), unixepoch()),
|
|
53
|
+
('msg-0003', 'msg-demo-3', 'published', 'Francesco Lombardi', 'f.lombardi@enterprise.it', 'Beech Enterprise — SLA e uptime', '<p>Siamo interessati al piano Enterprise. Quali SLA garantite? Abbiamo bisogno di 99.9% uptime per un''applicazione mission-critical.</p>', 0, unixepoch(), unixepoch());
|
|
54
|
+
`
|
|
@@ -0,0 +1,20 @@
|
|
|
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 { IDemoDataRepository } from '@beechcms/core'
|
|
7
|
+
import { DEMO_DATA_SQL } from './demo-data-sql'
|
|
8
|
+
|
|
9
|
+
export class D1DemoDataRepository implements IDemoDataRepository {
|
|
10
|
+
constructor(private readonly db: D1Database) {}
|
|
11
|
+
|
|
12
|
+
async loadDemoData(): Promise<void> {
|
|
13
|
+
const statements = DEMO_DATA_SQL
|
|
14
|
+
.split(';')
|
|
15
|
+
.map(s => s.trim())
|
|
16
|
+
.filter(s => s.length > 0)
|
|
17
|
+
.map(s => this.db.prepare(s))
|
|
18
|
+
await this.db.batch(statements)
|
|
19
|
+
}
|
|
20
|
+
}
|
|
@@ -1,3 +1,7 @@
|
|
|
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
|
+
|
|
1
5
|
import type { IScheduler } from '@beechcms/core'
|
|
2
6
|
|
|
3
7
|
export class ExecutionContextScheduler implements IScheduler {
|
package/src/shared/fts-sync.ts
CHANGED
|
@@ -1,3 +1,7 @@
|
|
|
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
|
+
|
|
1
5
|
// v0.4.0: FTS sync handled automatically by SQL triggers (generateFtsTriggers).
|
|
2
6
|
// syncFts/deleteFts eliminated. This file kept as empty module to avoid import errors
|
|
3
7
|
// during the Phase 4 → Phase 6 transition.
|
|
@@ -1,3 +1,7 @@
|
|
|
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
|
+
|
|
1
5
|
import { describe, it, expect, vi } from 'vitest'
|
|
2
6
|
import { D1IdempotencyRepository } from './idempotency.repository.d1'
|
|
3
7
|
|
|
@@ -1,3 +1,7 @@
|
|
|
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
|
+
|
|
1
5
|
import { IdempotencyRepository, IdempotencyRecord } from '@beechcms/core'
|
|
2
6
|
import { BaseD1Repository } from './base.repository.d1.js'
|
|
3
7
|
|
|
@@ -0,0 +1,51 @@
|
|
|
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 { ISeedRepository, Seed, SeedRecord } from '@beechcms/core'
|
|
6
|
+
|
|
7
|
+
/**
|
|
8
|
+
* In-memory ISeedRepository for testing and for the config.seeds back-compat shim.
|
|
9
|
+
* Returns a fixed seed list with a static version token.
|
|
10
|
+
*/
|
|
11
|
+
export class InMemorySeedRepository implements ISeedRepository {
|
|
12
|
+
private readonly seeds: Seed[]
|
|
13
|
+
private version = 1
|
|
14
|
+
|
|
15
|
+
constructor(seeds: Seed[]) {
|
|
16
|
+
this.seeds = seeds.filter(s => s && typeof s === 'object' && 'slug' in s)
|
|
17
|
+
}
|
|
18
|
+
|
|
19
|
+
async listActive(): Promise<Seed[]> {
|
|
20
|
+
return this.seeds
|
|
21
|
+
}
|
|
22
|
+
|
|
23
|
+
async listAll(): Promise<SeedRecord[]> {
|
|
24
|
+
return this.seeds.map(s => ({
|
|
25
|
+
slug: s.slug,
|
|
26
|
+
definition: s,
|
|
27
|
+
status: 'active' as const,
|
|
28
|
+
source: 'code' as const,
|
|
29
|
+
createdAt: 0,
|
|
30
|
+
updatedAt: 0,
|
|
31
|
+
}))
|
|
32
|
+
}
|
|
33
|
+
|
|
34
|
+
async get(slug: string): Promise<SeedRecord | null> {
|
|
35
|
+
const s = this.seeds.find(s => s.slug === slug)
|
|
36
|
+
if (!s) return null
|
|
37
|
+
return { slug: s.slug, definition: s, status: 'active', source: 'code', createdAt: 0, updatedAt: 0 }
|
|
38
|
+
}
|
|
39
|
+
|
|
40
|
+
async upsert(): Promise<void> {}
|
|
41
|
+
async softDelete(): Promise<void> {}
|
|
42
|
+
async hardDelete(): Promise<void> {}
|
|
43
|
+
|
|
44
|
+
async getRegistryVersion(): Promise<number> {
|
|
45
|
+
return this.version
|
|
46
|
+
}
|
|
47
|
+
|
|
48
|
+
async bumpRegistryVersion(): Promise<number> {
|
|
49
|
+
return ++this.version
|
|
50
|
+
}
|
|
51
|
+
}
|
|
@@ -1,3 +1,7 @@
|
|
|
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
|
+
|
|
1
5
|
import { describe, it, expect, vi } from 'vitest'
|
|
2
6
|
import { D1MediaRepository } from './media.repository.d1'
|
|
3
7
|
|