@endora-commerce/mod-blog 0.100.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/LICENSE +21 -0
- package/README.md +62 -0
- package/dist/admin/api/blog-client.d.ts +70 -0
- package/dist/admin/api/blog-client.d.ts.map +1 -0
- package/dist/admin/api/blog-client.js +137 -0
- package/dist/admin/api/blog-client.js.map +1 -0
- package/dist/admin/components/CategoryTreeNode.d.ts +25 -0
- package/dist/admin/components/CategoryTreeNode.d.ts.map +1 -0
- package/dist/admin/components/CategoryTreeNode.js +14 -0
- package/dist/admin/components/CategoryTreeNode.js.map +1 -0
- package/dist/admin/components/PostStatusBadge.d.ts +7 -0
- package/dist/admin/components/PostStatusBadge.d.ts.map +1 -0
- package/dist/admin/components/PostStatusBadge.js +16 -0
- package/dist/admin/components/PostStatusBadge.js.map +1 -0
- package/dist/admin/components/RelatedPostsPicker.d.ts +11 -0
- package/dist/admin/components/RelatedPostsPicker.d.ts.map +1 -0
- package/dist/admin/components/RelatedPostsPicker.js +77 -0
- package/dist/admin/components/RelatedPostsPicker.js.map +1 -0
- package/dist/admin/components/RelatedProductsPicker.d.ts +9 -0
- package/dist/admin/components/RelatedProductsPicker.d.ts.map +1 -0
- package/dist/admin/components/RelatedProductsPicker.js +66 -0
- package/dist/admin/components/RelatedProductsPicker.js.map +1 -0
- package/dist/admin/components/TagPicker.d.ts +9 -0
- package/dist/admin/components/TagPicker.d.ts.map +1 -0
- package/dist/admin/components/TagPicker.js +66 -0
- package/dist/admin/components/TagPicker.js.map +1 -0
- package/dist/admin/index.d.ts +33 -0
- package/dist/admin/index.d.ts.map +1 -0
- package/dist/admin/index.js +114 -0
- package/dist/admin/index.js.map +1 -0
- package/dist/admin/pages/BlogCategoryEditor.d.ts +9 -0
- package/dist/admin/pages/BlogCategoryEditor.d.ts.map +1 -0
- package/dist/admin/pages/BlogCategoryEditor.js +196 -0
- package/dist/admin/pages/BlogCategoryEditor.js.map +1 -0
- package/dist/admin/pages/BlogCategoryTreePage.d.ts +9 -0
- package/dist/admin/pages/BlogCategoryTreePage.d.ts.map +1 -0
- package/dist/admin/pages/BlogCategoryTreePage.js +122 -0
- package/dist/admin/pages/BlogCategoryTreePage.js.map +1 -0
- package/dist/admin/pages/BlogPostEditor.d.ts +9 -0
- package/dist/admin/pages/BlogPostEditor.d.ts.map +1 -0
- package/dist/admin/pages/BlogPostEditor.js +314 -0
- package/dist/admin/pages/BlogPostEditor.js.map +1 -0
- package/dist/admin/pages/BlogPostListPage.d.ts +9 -0
- package/dist/admin/pages/BlogPostListPage.d.ts.map +1 -0
- package/dist/admin/pages/BlogPostListPage.js +75 -0
- package/dist/admin/pages/BlogPostListPage.js.map +1 -0
- package/dist/admin/pages/BlogTagListPage.d.ts +9 -0
- package/dist/admin/pages/BlogTagListPage.d.ts.map +1 -0
- package/dist/admin/pages/BlogTagListPage.js +145 -0
- package/dist/admin/pages/BlogTagListPage.js.map +1 -0
- package/dist/backend/entities/blog-category-language.entity.d.ts +11 -0
- package/dist/backend/entities/blog-category-language.entity.d.ts.map +1 -0
- package/dist/backend/entities/blog-category-language.entity.js +35 -0
- package/dist/backend/entities/blog-category-language.entity.js.map +1 -0
- package/dist/backend/entities/blog-category-sales-channel.entity.d.ts +17 -0
- package/dist/backend/entities/blog-category-sales-channel.entity.d.ts.map +1 -0
- package/dist/backend/entities/blog-category-sales-channel.entity.js +48 -0
- package/dist/backend/entities/blog-category-sales-channel.entity.js.map +1 -0
- package/dist/backend/entities/blog-category.entity.d.ts +32 -0
- package/dist/backend/entities/blog-category.entity.d.ts.map +1 -0
- package/dist/backend/entities/blog-category.entity.js +113 -0
- package/dist/backend/entities/blog-category.entity.js.map +1 -0
- package/dist/backend/entities/blog-post-category.entity.d.ts +10 -0
- package/dist/backend/entities/blog-post-category.entity.d.ts.map +1 -0
- package/dist/backend/entities/blog-post-category.entity.js +34 -0
- package/dist/backend/entities/blog-post-category.entity.js.map +1 -0
- package/dist/backend/entities/blog-post-language.entity.d.ts +9 -0
- package/dist/backend/entities/blog-post-language.entity.d.ts.map +1 -0
- package/dist/backend/entities/blog-post-language.entity.js +33 -0
- package/dist/backend/entities/blog-post-language.entity.js.map +1 -0
- package/dist/backend/entities/blog-post-related-post.entity.d.ts +15 -0
- package/dist/backend/entities/blog-post-related-post.entity.d.ts.map +1 -0
- package/dist/backend/entities/blog-post-related-post.entity.js +42 -0
- package/dist/backend/entities/blog-post-related-post.entity.js.map +1 -0
- package/dist/backend/entities/blog-post-related-product.entity.d.ts +14 -0
- package/dist/backend/entities/blog-post-related-product.entity.d.ts.map +1 -0
- package/dist/backend/entities/blog-post-related-product.entity.js +41 -0
- package/dist/backend/entities/blog-post-related-product.entity.js.map +1 -0
- package/dist/backend/entities/blog-post-sales-channel.entity.d.ts +16 -0
- package/dist/backend/entities/blog-post-sales-channel.entity.d.ts.map +1 -0
- package/dist/backend/entities/blog-post-sales-channel.entity.js +47 -0
- package/dist/backend/entities/blog-post-sales-channel.entity.js.map +1 -0
- package/dist/backend/entities/blog-post-tag.entity.d.ts +14 -0
- package/dist/backend/entities/blog-post-tag.entity.d.ts.map +1 -0
- package/dist/backend/entities/blog-post-tag.entity.js +41 -0
- package/dist/backend/entities/blog-post-tag.entity.js.map +1 -0
- package/dist/backend/entities/blog-post.entity.d.ts +31 -0
- package/dist/backend/entities/blog-post.entity.d.ts.map +1 -0
- package/dist/backend/entities/blog-post.entity.js +106 -0
- package/dist/backend/entities/blog-post.entity.js.map +1 -0
- package/dist/backend/entities/blog-tag.entity.d.ts +18 -0
- package/dist/backend/entities/blog-tag.entity.d.ts.map +1 -0
- package/dist/backend/entities/blog-tag.entity.js +66 -0
- package/dist/backend/entities/blog-tag.entity.js.map +1 -0
- package/dist/backend/index.d.ts +100 -0
- package/dist/backend/index.d.ts.map +1 -0
- package/dist/backend/index.js +182 -0
- package/dist/backend/index.js.map +1 -0
- package/dist/backend/routes.admin.d.ts +12 -0
- package/dist/backend/routes.admin.d.ts.map +1 -0
- package/dist/backend/routes.admin.js +148 -0
- package/dist/backend/routes.admin.js.map +1 -0
- package/dist/backend/routes.storefront.d.ts +6 -0
- package/dist/backend/routes.storefront.d.ts.map +1 -0
- package/dist/backend/routes.storefront.js +72 -0
- package/dist/backend/routes.storefront.js.map +1 -0
- package/dist/backend/services/blog-asset-references.d.ts +4 -0
- package/dist/backend/services/blog-asset-references.d.ts.map +1 -0
- package/dist/backend/services/blog-asset-references.js +79 -0
- package/dist/backend/services/blog-asset-references.js.map +1 -0
- package/dist/backend/services/blog-cache.d.ts +55 -0
- package/dist/backend/services/blog-cache.d.ts.map +1 -0
- package/dist/backend/services/blog-cache.js +111 -0
- package/dist/backend/services/blog-cache.js.map +1 -0
- package/dist/backend/services/blog-category-service.d.ts +53 -0
- package/dist/backend/services/blog-category-service.d.ts.map +1 -0
- package/dist/backend/services/blog-category-service.js +446 -0
- package/dist/backend/services/blog-category-service.js.map +1 -0
- package/dist/backend/services/blog-language-reference.d.ts +18 -0
- package/dist/backend/services/blog-language-reference.d.ts.map +1 -0
- package/dist/backend/services/blog-language-reference.js +43 -0
- package/dist/backend/services/blog-language-reference.js.map +1 -0
- package/dist/backend/services/blog-post-service.d.ts +79 -0
- package/dist/backend/services/blog-post-service.d.ts.map +1 -0
- package/dist/backend/services/blog-post-service.js +539 -0
- package/dist/backend/services/blog-post-service.js.map +1 -0
- package/dist/backend/services/blog-settings-resolver.d.ts +36 -0
- package/dist/backend/services/blog-settings-resolver.d.ts.map +1 -0
- package/dist/backend/services/blog-settings-resolver.js +68 -0
- package/dist/backend/services/blog-settings-resolver.js.map +1 -0
- package/dist/backend/services/blog-slug-collision.d.ts +35 -0
- package/dist/backend/services/blog-slug-collision.d.ts.map +1 -0
- package/dist/backend/services/blog-slug-collision.js +84 -0
- package/dist/backend/services/blog-slug-collision.js.map +1 -0
- package/dist/backend/services/blog-storefront-resolver.d.ts +107 -0
- package/dist/backend/services/blog-storefront-resolver.d.ts.map +1 -0
- package/dist/backend/services/blog-storefront-resolver.js +492 -0
- package/dist/backend/services/blog-storefront-resolver.js.map +1 -0
- package/dist/backend/services/blog-tag-service.d.ts +45 -0
- package/dist/backend/services/blog-tag-service.d.ts.map +1 -0
- package/dist/backend/services/blog-tag-service.js +198 -0
- package/dist/backend/services/blog-tag-service.js.map +1 -0
- package/dist/backend/services/seed-default-category.d.ts +25 -0
- package/dist/backend/services/seed-default-category.d.ts.map +1 -0
- package/dist/backend/services/seed-default-category.js +48 -0
- package/dist/backend/services/seed-default-category.js.map +1 -0
- package/dist/backend/services/seed-roles.d.ts +41 -0
- package/dist/backend/services/seed-roles.d.ts.map +1 -0
- package/dist/backend/services/seed-roles.js +98 -0
- package/dist/backend/services/seed-roles.js.map +1 -0
- package/dist/manifest.d.ts +226 -0
- package/dist/manifest.d.ts.map +1 -0
- package/dist/manifest.js +236 -0
- package/dist/manifest.js.map +1 -0
- package/dist/migrations/20260506T081055_blog_init.d.ts +33 -0
- package/dist/migrations/20260506T081055_blog_init.d.ts.map +1 -0
- package/dist/migrations/20260506T081055_blog_init.js +260 -0
- package/dist/migrations/20260506T081055_blog_init.js.map +1 -0
- package/dist/migrations/20260903T101744_blog_namespace_block_names.d.ts +6 -0
- package/dist/migrations/20260903T101744_blog_namespace_block_names.d.ts.map +1 -0
- package/dist/migrations/20260903T101744_blog_namespace_block_names.js +58 -0
- package/dist/migrations/20260903T101744_blog_namespace_block_names.js.map +1 -0
- package/dist/migrations/index.d.ts +34 -0
- package/dist/migrations/index.d.ts.map +1 -0
- package/dist/migrations/index.js +37 -0
- package/dist/migrations/index.js.map +1 -0
- package/docs/blog/index.md +199 -0
- package/i18n/en.json +166 -0
- package/i18n/pl.json +166 -0
- package/package.json +108 -0
- package/tailwind.css +14 -0
|
@@ -0,0 +1,182 @@
|
|
|
1
|
+
import { effectiveState, lazyPort } from '@endora-commerce/platform/kernel';
|
|
2
|
+
import { BlogCacheService } from './services/blog-cache.js';
|
|
3
|
+
import { BlogSettingsResolver, } from './services/blog-settings-resolver.js';
|
|
4
|
+
import { BlogCategoryService } from './services/blog-category-service.js';
|
|
5
|
+
import { BlogPostService } from './services/blog-post-service.js';
|
|
6
|
+
import { BlogTagService } from './services/blog-tag-service.js';
|
|
7
|
+
import { BlogStorefrontResolver, } from './services/blog-storefront-resolver.js';
|
|
8
|
+
import { registerBlogAssetReferences } from './services/blog-asset-references.js';
|
|
9
|
+
import { seedDefaultCategory } from './services/seed-default-category.js';
|
|
10
|
+
import { seedBlogRoles } from './services/seed-roles.js';
|
|
11
|
+
import { registerBlogAdminRoutes } from './routes.admin.js';
|
|
12
|
+
import { registerBlogStorefrontRoutes } from './routes.storefront.js';
|
|
13
|
+
import { registerBlogLanguageReferences } from './services/blog-language-reference.js';
|
|
14
|
+
import { BlogCategory } from './entities/blog-category.entity.js';
|
|
15
|
+
import { BlogCategoryLanguage } from './entities/blog-category-language.entity.js';
|
|
16
|
+
import { BlogCategorySalesChannel } from './entities/blog-category-sales-channel.entity.js';
|
|
17
|
+
import { BlogPost } from './entities/blog-post.entity.js';
|
|
18
|
+
import { BlogPostCategory } from './entities/blog-post-category.entity.js';
|
|
19
|
+
import { BlogPostLanguage } from './entities/blog-post-language.entity.js';
|
|
20
|
+
import { BlogPostRelatedPost } from './entities/blog-post-related-post.entity.js';
|
|
21
|
+
import { BlogPostRelatedProduct } from './entities/blog-post-related-product.entity.js';
|
|
22
|
+
import { BlogPostSalesChannel } from './entities/blog-post-sales-channel.entity.js';
|
|
23
|
+
import { BlogPostTag } from './entities/blog-post-tag.entity.js';
|
|
24
|
+
import { BlogTag } from './entities/blog-tag.entity.js';
|
|
25
|
+
export function registerModule(ctx) {
|
|
26
|
+
ctx.di.register({
|
|
27
|
+
// Singletons, matching what the composition root constructed once at boot.
|
|
28
|
+
// They take `emFactory` rather than an `EntityManager`, so a single
|
|
29
|
+
// instance is correct in every request and every job: the fork happens per
|
|
30
|
+
// call and the tenant filter reads the ambient context at query time.
|
|
31
|
+
blogCacheService: ctx
|
|
32
|
+
.asFunction(({ redis }) => redis ? new BlogCacheService(redis, {}) : undefined)
|
|
33
|
+
.singleton(),
|
|
34
|
+
blogSettingsResolver: ctx
|
|
35
|
+
.asFunction(() => new BlogSettingsResolver(lazyPort(ctx, 'settingsReadPort')))
|
|
36
|
+
.singleton(),
|
|
37
|
+
blogPostService: ctx
|
|
38
|
+
.asFunction(({ emFactory, blogCacheService }) => new BlogPostService(emFactory, blogCacheService, lazyPort(ctx, 'dictionaryValidator')))
|
|
39
|
+
.singleton(),
|
|
40
|
+
blogCategoryService: ctx
|
|
41
|
+
.asFunction(({ emFactory, blogCacheService }) => new BlogCategoryService(emFactory, blogCacheService, lazyPort(ctx, 'dictionaryValidator')))
|
|
42
|
+
.singleton(),
|
|
43
|
+
blogTagService: ctx
|
|
44
|
+
.asFunction(({ emFactory, blogCacheService }) => new BlogTagService(emFactory, blogCacheService))
|
|
45
|
+
.singleton(),
|
|
46
|
+
blogStorefrontResolver: ctx
|
|
47
|
+
.asFunction(({ emFactory, blogSettingsResolver, blogStorefrontDeps, blogCacheService }) => new BlogStorefrontResolver(emFactory, blogSettingsResolver, blogStorefrontDeps ?? {}, blogCacheService))
|
|
48
|
+
.singleton(),
|
|
49
|
+
});
|
|
50
|
+
ctx.routes(async (app) => {
|
|
51
|
+
const { blogPostService, blogCategoryService, blogTagService, requireAdmin } = ctx.cradle();
|
|
52
|
+
await registerBlogAdminRoutes(app, {
|
|
53
|
+
postService: blogPostService,
|
|
54
|
+
categoryService: blogCategoryService,
|
|
55
|
+
tagService: blogTagService,
|
|
56
|
+
...(requireAdmin ? { requireAdmin } : {}),
|
|
57
|
+
});
|
|
58
|
+
});
|
|
59
|
+
ctx.routes(async (app) => {
|
|
60
|
+
const { blogStorefrontResolver } = ctx.cradle();
|
|
61
|
+
await registerBlogStorefrontRoutes(app, { storefrontResolver: blogStorefrontResolver });
|
|
62
|
+
});
|
|
63
|
+
// R9 — a `blog.*` settings write wipes the storefront blog cache, so the next
|
|
64
|
+
// read picks up the new value.
|
|
65
|
+
ctx.subscribe('settings.value_changed', async (payload) => {
|
|
66
|
+
const code = payload?.settingCode;
|
|
67
|
+
if (code === undefined || !code.startsWith('blog.'))
|
|
68
|
+
return;
|
|
69
|
+
await ctx.cradle().blogCacheService?.invalidateAll();
|
|
70
|
+
});
|
|
71
|
+
/**
|
|
72
|
+
* The two asset-reference edges, contributed **unprobed** (D-68).
|
|
73
|
+
*
|
|
74
|
+
* Registered before any blog write can happen, so the Library's soft-delete
|
|
75
|
+
* path sees them from the first request on — and it keeps seeing them while
|
|
76
|
+
* `blog` is switched off, deliberately. `assets_library` consults the registry
|
|
77
|
+
* to refuse deleting an asset something still points at, and a deactivated
|
|
78
|
+
* module's posts and categories still embed assets: probing here would let an
|
|
79
|
+
* operator delete an asset a deactivated post references, and the damage would
|
|
80
|
+
* only surface as a broken image when `blog` comes back on. Off is meant to be
|
|
81
|
+
* non-destructive and reversible (Constitution XVII), which is why the
|
|
82
|
+
* registry's own enumeration policy is `honoured` rather than `skip` for these
|
|
83
|
+
* descriptors — a scanner is integrity, not a surface.
|
|
84
|
+
*
|
|
85
|
+
* A second hook rather than a line in the one below, because the two answer
|
|
86
|
+
* different questions: this one must run whatever the module's state, that one
|
|
87
|
+
* must not run while it is off. `product_feeds/backend.ts` is the shipped
|
|
88
|
+
* example of the same pair.
|
|
89
|
+
*/
|
|
90
|
+
ctx.onBoot(() => {
|
|
91
|
+
const { assetReferenceRegistry, emFactory } = ctx.cradle();
|
|
92
|
+
registerBlogAssetReferences(assetReferenceRegistry, emFactory);
|
|
93
|
+
});
|
|
94
|
+
// Idempotent boot reconcilers (R11 / R8): on a rerun they preserve every
|
|
95
|
+
// admin edit and only fill in what is missing.
|
|
96
|
+
ctx.onBoot(async () => {
|
|
97
|
+
// Presence is decided here — first, and outside anything that could catch it
|
|
98
|
+
// (issue #146, D-68). These two seeds write rows: a category and two roles.
|
|
99
|
+
// A switched-off module writing at every boot is "behaves as if never
|
|
100
|
+
// installed" failing, and a boot hook has no caller to answer, so the
|
|
101
|
+
// question is asked rather than thrown. `runBootHooks` re-throws as
|
|
102
|
+
// `ModuleCompositionError`, which `index.ts` turns into `process.exit(1)`.
|
|
103
|
+
if (!effectiveState.isPresent('blog'))
|
|
104
|
+
return;
|
|
105
|
+
const { emFactory } = ctx.cradle();
|
|
106
|
+
await seedDefaultCategory(emFactory);
|
|
107
|
+
// Two ports into `admin_roles`, and they are different kinds of seam.
|
|
108
|
+
//
|
|
109
|
+
// `adminRolePort` is a **call**: it is where the two role rows are written
|
|
110
|
+
// since feature 075 drained this module's cross-module-import shard, in
|
|
111
|
+
// place of three raw SQL statements against `admin_roles`' own table. It is
|
|
112
|
+
// gated, so the seam fails closed — but `admin_roles` declares itself
|
|
113
|
+
// non-deactivatable, so the state that gate answers "no" in is one an
|
|
114
|
+
// operator cannot reach: the only way this composition runs without it is a
|
|
115
|
+
// deployment that never shipped it, and `composeModules` refuses that
|
|
116
|
+
// before the first module registers. Resolving it here rather than in a
|
|
117
|
+
// factory keeps it lazy, so composition asks the gate nothing.
|
|
118
|
+
//
|
|
119
|
+
// `systemRoleCodePort` is `admin_roles`' ungated contribution registry, so
|
|
120
|
+
// resolving it asks no gate at all — the probe above is this module's own
|
|
121
|
+
// answer about its own seeds, not a question about either seam's owner.
|
|
122
|
+
await seedBlogRoles(lazyPort(ctx, 'adminRolePort'), lazyPort(ctx, 'systemRoleCodePort'));
|
|
123
|
+
});
|
|
124
|
+
/**
|
|
125
|
+
* This module's rows carry a language code, so it answers "who still points at
|
|
126
|
+
* this language?" about its own tables (feature 077, D-87), where the owner used
|
|
127
|
+
* to count them with SQL naming this module's tables.
|
|
128
|
+
*
|
|
129
|
+
* A **contribution** hook: it pushes an inert descriptor into `languageReferenceRegistry`,
|
|
130
|
+
* an ungated registry, and carries no presence probe (D-62/D-68). Probing
|
|
131
|
+
* would be wrong in the dangerous direction — a switched-off module still owns
|
|
132
|
+
* the rows, so its language must still refuse the delete, which is the
|
|
133
|
+
* enumeration policy the registry states.
|
|
134
|
+
*/
|
|
135
|
+
ctx.onBoot(() => {
|
|
136
|
+
registerBlogLanguageReferences(lazyPort(ctx, 'languageReferenceRegistry'), ctx.cradle().emFactory);
|
|
137
|
+
});
|
|
138
|
+
}
|
|
139
|
+
/**
|
|
140
|
+
* The module's persisted entity classes, on the `./backend` subpath, as one
|
|
141
|
+
* array and **no named class export** (D-168).
|
|
142
|
+
*
|
|
143
|
+
* This is the shape the platform already reads, in two places: the boot-time
|
|
144
|
+
* loader (`src/packages/package-runtime.ts`, `exported['entities']`) and the
|
|
145
|
+
* static declaration reader (`scripts/lib/package-declarations.ts`), which is
|
|
146
|
+
* the third source of the `table→owner` map and the package pass of
|
|
147
|
+
* `check-entity-tenant-classification`. Until D-168 this file published eleven
|
|
148
|
+
* `export *` lines instead, which satisfied only the committed host registry —
|
|
149
|
+
* the one path that stops being taken the day this module is *installed*
|
|
150
|
+
* rather than linked, at which point the loader read `undefined`, returned
|
|
151
|
+
* `[]`, and registered zero entities without a word.
|
|
152
|
+
*
|
|
153
|
+
* The absence of a named export is the load-bearing half. With it,
|
|
154
|
+
* `import type { BlogPost } from '@endora-commerce/mod-blog/backend'` compiles
|
|
155
|
+
* in any consumer — ours, a deployment's, a stranger's — and only a check whose
|
|
156
|
+
* population is *this* repository could ever object. Without it, that import is
|
|
157
|
+
* TS2305 in the consumer's own tree, which is Principle I holding by
|
|
158
|
+
* construction. Nothing legitimate is lost: D-32 already forbids an ORM
|
|
159
|
+
* relation from another module into these classes, and every other cross-module
|
|
160
|
+
* read goes through a contract type. An `EntityClassLike[]` is a value the
|
|
161
|
+
* host's ORM registers and nothing else can usefully name.
|
|
162
|
+
*
|
|
163
|
+
* Identity matters more here than anywhere else in the package: MikroORM keys
|
|
164
|
+
* its metadata on the class, so a consumer that reached these files by a second
|
|
165
|
+
* specifier would register a second `BlogPost` and lose one of them at
|
|
166
|
+
* discovery (D-160.6, measured). One array behind one declared subpath is the
|
|
167
|
+
* only way in.
|
|
168
|
+
*/
|
|
169
|
+
export const entities = [
|
|
170
|
+
BlogCategory,
|
|
171
|
+
BlogCategoryLanguage,
|
|
172
|
+
BlogCategorySalesChannel,
|
|
173
|
+
BlogPost,
|
|
174
|
+
BlogPostCategory,
|
|
175
|
+
BlogPostLanguage,
|
|
176
|
+
BlogPostRelatedPost,
|
|
177
|
+
BlogPostRelatedProduct,
|
|
178
|
+
BlogPostSalesChannel,
|
|
179
|
+
BlogPostTag,
|
|
180
|
+
BlogTag,
|
|
181
|
+
];
|
|
182
|
+
//# sourceMappingURL=index.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"index.js","sourceRoot":"","sources":["../../src/backend/index.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1,12 @@
|
|
|
1
|
+
import type { FastifyInstance } from 'fastify';
|
|
2
|
+
import type { BlogCategoryService } from './services/blog-category-service.js';
|
|
3
|
+
import type { BlogPostService } from './services/blog-post-service.js';
|
|
4
|
+
import type { BlogTagService } from './services/blog-tag-service.js';
|
|
5
|
+
import type { RequireAdminFactory } from '@endora-commerce/platform/kernel';
|
|
6
|
+
export declare function registerBlogAdminRoutes(app: FastifyInstance, deps: {
|
|
7
|
+
postService: BlogPostService;
|
|
8
|
+
categoryService: BlogCategoryService;
|
|
9
|
+
tagService: BlogTagService;
|
|
10
|
+
requireAdmin?: RequireAdminFactory;
|
|
11
|
+
}): Promise<void>;
|
|
12
|
+
//# sourceMappingURL=routes.admin.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"routes.admin.d.ts","sourceRoot":"","sources":["../../src/backend/routes.admin.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,eAAe,EAAE,MAAM,SAAS,CAAC;AAgB/C,OAAO,KAAK,EAAE,mBAAmB,EAAE,MAAM,qCAAqC,CAAC;AAC/E,OAAO,KAAK,EAAE,eAAe,EAAE,MAAM,iCAAiC,CAAC;AACvE,OAAO,KAAK,EAAE,cAAc,EAAE,MAAM,gCAAgC,CAAC;AACrE,OAAO,KAAK,EAAE,mBAAmB,EAAE,MAAM,kCAAkC,CAAC;AA2C5E,wBAAsB,uBAAuB,CAC3C,GAAG,EAAE,eAAe,EACpB,IAAI,EAAE;IACJ,WAAW,EAAE,eAAe,CAAC;IAC7B,eAAe,EAAE,mBAAmB,CAAC;IACrC,UAAU,EAAE,cAAc,CAAC;IAC3B,YAAY,CAAC,EAAE,mBAAmB,CAAC;CACpC,GACA,OAAO,CAAC,IAAI,CAAC,CA6Of"}
|
|
@@ -0,0 +1,148 @@
|
|
|
1
|
+
import { createBlogCategoryRequestSchema, createBlogPostRequestSchema, createBlogTagRequestSchema, patchBlogCategoryRequestSchema, patchBlogPostRequestSchema, patchBlogTagRequestSchema, putBlogCategoryDescriptionRequestSchema, putBlogCategoryTreeMovesRequestSchema, putBlogPostContentRequestSchema, setBlogPostRelatedPostsRequestSchema, setBlogPostRelatedProductsRequestSchema, setBlogPostTagsRequestSchema, } from '@endora-commerce/contracts';
|
|
2
|
+
import { z } from 'zod';
|
|
3
|
+
const versionOnlySchema = z.object({ version: z.number().int() });
|
|
4
|
+
const versionQuerySchema = z.object({
|
|
5
|
+
version: z.coerce.number().int().optional(),
|
|
6
|
+
});
|
|
7
|
+
/**
|
|
8
|
+
* DELETE doesn't carry a body (Fetch API limitation in some browsers),
|
|
9
|
+
* so the admin client can pass version as a query parameter. The backend
|
|
10
|
+
* accepts either form: body wins when present, query is the fallback.
|
|
11
|
+
*/
|
|
12
|
+
function readDeleteVersion(body, query) {
|
|
13
|
+
if (body && typeof body === 'object') {
|
|
14
|
+
const bv = body.version;
|
|
15
|
+
if (typeof bv === 'number')
|
|
16
|
+
return bv;
|
|
17
|
+
}
|
|
18
|
+
const q = versionQuerySchema.safeParse(query ?? {});
|
|
19
|
+
if (q.success)
|
|
20
|
+
return q.data.version;
|
|
21
|
+
return undefined;
|
|
22
|
+
}
|
|
23
|
+
const listFiltersSchema = z.object({
|
|
24
|
+
q: z.string().optional(),
|
|
25
|
+
status: z.enum(['draft', 'published', 'archived']).optional(),
|
|
26
|
+
salesChannelId: z.string().uuid().optional(),
|
|
27
|
+
categoryId: z.string().uuid().optional(),
|
|
28
|
+
tagId: z.string().uuid().optional(),
|
|
29
|
+
language: z.string().min(2).optional(),
|
|
30
|
+
page: z.coerce.number().int().positive().optional(),
|
|
31
|
+
perPage: z.coerce.number().int().positive().max(100).optional(),
|
|
32
|
+
});
|
|
33
|
+
const tagListFiltersSchema = z.object({
|
|
34
|
+
q: z.string().optional(),
|
|
35
|
+
page: z.coerce.number().int().positive().optional(),
|
|
36
|
+
perPage: z.coerce.number().int().positive().max(100).optional(),
|
|
37
|
+
});
|
|
38
|
+
export async function registerBlogAdminRoutes(app, deps) {
|
|
39
|
+
const requireRead = deps.requireAdmin?.('blog.read') ?? (async () => { });
|
|
40
|
+
const requireWrite = deps.requireAdmin?.('blog.write') ?? (async () => { });
|
|
41
|
+
// ── Posts ──────────────────────────────────────────────────────────
|
|
42
|
+
app.get('/api/v1/admin/blog/posts', { preHandler: requireRead }, async (request) => {
|
|
43
|
+
const filters = listFiltersSchema.parse(request.query ?? {});
|
|
44
|
+
return deps.postService.list(filters);
|
|
45
|
+
});
|
|
46
|
+
app.post('/api/v1/admin/blog/posts', { preHandler: requireWrite }, async (request, reply) => {
|
|
47
|
+
const body = createBlogPostRequestSchema.parse(request.body);
|
|
48
|
+
const created = await deps.postService.create(body);
|
|
49
|
+
return reply.code(201).send({ data: created });
|
|
50
|
+
});
|
|
51
|
+
app.get('/api/v1/admin/blog/posts/:id', { preHandler: requireRead }, async (request) => ({ data: await deps.postService.getById(request.params.id) }));
|
|
52
|
+
app.patch('/api/v1/admin/blog/posts/:id', { preHandler: requireWrite }, async (request) => {
|
|
53
|
+
const body = patchBlogPostRequestSchema.parse(request.body);
|
|
54
|
+
return { data: await deps.postService.patch(request.params.id, body) };
|
|
55
|
+
});
|
|
56
|
+
app.put('/api/v1/admin/blog/posts/:id/content', { preHandler: requireWrite }, async (request) => {
|
|
57
|
+
const body = putBlogPostContentRequestSchema.parse(request.body);
|
|
58
|
+
return { data: await deps.postService.setContent(request.params.id, body) };
|
|
59
|
+
});
|
|
60
|
+
app.put('/api/v1/admin/blog/posts/:id/tags', { preHandler: requireWrite }, async (request) => {
|
|
61
|
+
const body = setBlogPostTagsRequestSchema.parse(request.body);
|
|
62
|
+
return {
|
|
63
|
+
data: await deps.postService.setTags(request.params.id, body.tagIds, body.version),
|
|
64
|
+
};
|
|
65
|
+
});
|
|
66
|
+
app.put('/api/v1/admin/blog/posts/:id/related-posts', { preHandler: requireWrite }, async (request) => {
|
|
67
|
+
const body = setBlogPostRelatedPostsRequestSchema.parse(request.body);
|
|
68
|
+
return {
|
|
69
|
+
data: await deps.postService.setRelatedPosts(request.params.id, body.relatedPostIds, body.version),
|
|
70
|
+
};
|
|
71
|
+
});
|
|
72
|
+
app.put('/api/v1/admin/blog/posts/:id/related-products', { preHandler: requireWrite }, async (request) => {
|
|
73
|
+
const body = setBlogPostRelatedProductsRequestSchema.parse(request.body);
|
|
74
|
+
return {
|
|
75
|
+
data: await deps.postService.setRelatedProducts(request.params.id, body.productIds, body.version),
|
|
76
|
+
};
|
|
77
|
+
});
|
|
78
|
+
app.post('/api/v1/admin/blog/posts/:id/publish', { preHandler: requireWrite }, async (request) => {
|
|
79
|
+
const body = versionOnlySchema.parse(request.body ?? {});
|
|
80
|
+
return { data: await deps.postService.publish(request.params.id, body.version) };
|
|
81
|
+
});
|
|
82
|
+
app.post('/api/v1/admin/blog/posts/:id/unpublish', { preHandler: requireWrite }, async (request) => {
|
|
83
|
+
const body = versionOnlySchema.parse(request.body ?? {});
|
|
84
|
+
return { data: await deps.postService.unpublish(request.params.id, body.version) };
|
|
85
|
+
});
|
|
86
|
+
app.post('/api/v1/admin/blog/posts/:id/archive', { preHandler: requireWrite }, async (request) => {
|
|
87
|
+
const body = versionOnlySchema.parse(request.body ?? {});
|
|
88
|
+
return { data: await deps.postService.archive(request.params.id, body.version) };
|
|
89
|
+
});
|
|
90
|
+
app.delete('/api/v1/admin/blog/posts/:id', { preHandler: requireWrite }, async (request, reply) => {
|
|
91
|
+
const version = readDeleteVersion(request.body, request.query) ??
|
|
92
|
+
versionOnlySchema.parse(request.body ?? { version: 0 }).version;
|
|
93
|
+
const result = await deps.postService.softDelete(request.params.id, version);
|
|
94
|
+
return reply.code(200).send({ data: result });
|
|
95
|
+
});
|
|
96
|
+
app.get('/api/v1/admin/blog/posts/:id/inbound-references', { preHandler: requireRead }, async (request) => ({
|
|
97
|
+
data: await deps.postService.getInboundReferences(request.params.id),
|
|
98
|
+
}));
|
|
99
|
+
// ── Categories ─────────────────────────────────────────────────────
|
|
100
|
+
app.get('/api/v1/admin/blog/categories', { preHandler: requireRead }, async () => deps.categoryService.getTree());
|
|
101
|
+
app.get('/api/v1/admin/blog/categories/:id', { preHandler: requireRead }, async (request) => ({ data: await deps.categoryService.getById(request.params.id) }));
|
|
102
|
+
app.post('/api/v1/admin/blog/categories', { preHandler: requireWrite }, async (request, reply) => {
|
|
103
|
+
const body = createBlogCategoryRequestSchema.parse(request.body);
|
|
104
|
+
const created = await deps.categoryService.create(body);
|
|
105
|
+
return reply.code(201).send({ data: created });
|
|
106
|
+
});
|
|
107
|
+
app.patch('/api/v1/admin/blog/categories/:id', { preHandler: requireWrite }, async (request) => {
|
|
108
|
+
const body = patchBlogCategoryRequestSchema.parse(request.body);
|
|
109
|
+
return { data: await deps.categoryService.patch(request.params.id, body) };
|
|
110
|
+
});
|
|
111
|
+
app.put('/api/v1/admin/blog/categories/:id/description', { preHandler: requireWrite }, async (request) => {
|
|
112
|
+
const body = putBlogCategoryDescriptionRequestSchema.parse(request.body);
|
|
113
|
+
return { data: await deps.categoryService.setDescription(request.params.id, body) };
|
|
114
|
+
});
|
|
115
|
+
app.put('/api/v1/admin/blog/categories/tree', { preHandler: requireWrite }, async (request) => {
|
|
116
|
+
const body = putBlogCategoryTreeMovesRequestSchema.parse(request.body);
|
|
117
|
+
return await deps.categoryService.applyTreeMoves(body.moves);
|
|
118
|
+
});
|
|
119
|
+
app.delete('/api/v1/admin/blog/categories/:id', { preHandler: requireWrite }, async (request, reply) => {
|
|
120
|
+
const version = readDeleteVersion(request.body, request.query);
|
|
121
|
+
await deps.categoryService.softDelete(request.params.id, version);
|
|
122
|
+
return reply.code(204).send();
|
|
123
|
+
});
|
|
124
|
+
// ── Tags ───────────────────────────────────────────────────────────
|
|
125
|
+
app.get('/api/v1/admin/blog/tags', { preHandler: requireRead }, async (request) => {
|
|
126
|
+
const filters = tagListFiltersSchema.parse(request.query ?? {});
|
|
127
|
+
return deps.tagService.list(filters);
|
|
128
|
+
});
|
|
129
|
+
app.get('/api/v1/admin/blog/tags/:id', { preHandler: requireRead }, async (request) => ({ data: await deps.tagService.getById(request.params.id) }));
|
|
130
|
+
app.post('/api/v1/admin/blog/tags', { preHandler: requireWrite }, async (request, reply) => {
|
|
131
|
+
const body = createBlogTagRequestSchema.parse(request.body);
|
|
132
|
+
const created = await deps.tagService.create(body);
|
|
133
|
+
return reply.code(201).send({ data: created });
|
|
134
|
+
});
|
|
135
|
+
app.patch('/api/v1/admin/blog/tags/:id', { preHandler: requireWrite }, async (request) => {
|
|
136
|
+
const body = patchBlogTagRequestSchema.parse(request.body);
|
|
137
|
+
return { data: await deps.tagService.patch(request.params.id, body) };
|
|
138
|
+
});
|
|
139
|
+
app.delete('/api/v1/admin/blog/tags/:id', { preHandler: requireWrite }, async (request, reply) => {
|
|
140
|
+
const version = readDeleteVersion(request.body, request.query);
|
|
141
|
+
await deps.tagService.softDelete(request.params.id, version);
|
|
142
|
+
return reply.code(204).send();
|
|
143
|
+
});
|
|
144
|
+
app.get('/api/v1/admin/blog/tags/:id/inbound-references', { preHandler: requireRead }, async (request) => ({
|
|
145
|
+
data: await deps.tagService.getInboundReferences(request.params.id),
|
|
146
|
+
}));
|
|
147
|
+
}
|
|
148
|
+
//# sourceMappingURL=routes.admin.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"routes.admin.js","sourceRoot":"","sources":["../../src/backend/routes.admin.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1,6 @@
|
|
|
1
|
+
import type { FastifyInstance } from 'fastify';
|
|
2
|
+
import type { BlogStorefrontResolver } from './services/blog-storefront-resolver.js';
|
|
3
|
+
export declare function registerBlogStorefrontRoutes(app: FastifyInstance, deps: {
|
|
4
|
+
storefrontResolver: BlogStorefrontResolver;
|
|
5
|
+
}): Promise<void>;
|
|
6
|
+
//# sourceMappingURL=routes.storefront.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"routes.storefront.d.ts","sourceRoot":"","sources":["../../src/backend/routes.storefront.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,eAAe,EAAkB,MAAM,SAAS,CAAC;AAK/D,OAAO,KAAK,EAAE,sBAAsB,EAAE,MAAM,wCAAwC,CAAC;AAYrF,wBAAsB,4BAA4B,CAChD,GAAG,EAAE,eAAe,EACpB,IAAI,EAAE;IAAE,kBAAkB,EAAE,sBAAsB,CAAA;CAAE,GACnD,OAAO,CAAC,IAAI,CAAC,CAgDf"}
|
|
@@ -0,0 +1,72 @@
|
|
|
1
|
+
import { ERROR_CODES } from '@endora-commerce/contracts';
|
|
2
|
+
import { z } from 'zod';
|
|
3
|
+
import { HttpError } from '@endora-commerce/platform/http';
|
|
4
|
+
import { getResolvedChannel } from '@endora-commerce/platform/kernel';
|
|
5
|
+
const bySlugQuerySchema = z.object({
|
|
6
|
+
slug: z.string().min(1).max(160),
|
|
7
|
+
page: z.coerce.number().int().positive().optional(),
|
|
8
|
+
});
|
|
9
|
+
const tagByCodeQuerySchema = z.object({
|
|
10
|
+
code: z.string().min(1).max(64),
|
|
11
|
+
page: z.coerce.number().int().positive().optional(),
|
|
12
|
+
});
|
|
13
|
+
export async function registerBlogStorefrontRoutes(app, deps) {
|
|
14
|
+
app.get('/api/v1/blog/by-channel', async (request) => {
|
|
15
|
+
const { language } = readContext(request);
|
|
16
|
+
const resolved = await deps.storefrontResolver.getIndex({
|
|
17
|
+
resolvedChannel: resolvedChannel(request),
|
|
18
|
+
...(language !== undefined ? { language } : {}),
|
|
19
|
+
});
|
|
20
|
+
if (!resolved) {
|
|
21
|
+
throw new HttpError(404, ERROR_CODES.BLOG_DISABLED, 'Blog is disabled or not configured.');
|
|
22
|
+
}
|
|
23
|
+
return { data: resolved };
|
|
24
|
+
});
|
|
25
|
+
app.get('/api/v1/blog/by-slug', async (request) => {
|
|
26
|
+
const query = bySlugQuerySchema.parse(request.query ?? {});
|
|
27
|
+
const { language } = readContext(request);
|
|
28
|
+
const resolved = await deps.storefrontResolver.getBySlug(query.slug, {
|
|
29
|
+
resolvedChannel: resolvedChannel(request),
|
|
30
|
+
...(language !== undefined ? { language } : {}),
|
|
31
|
+
...(query.page !== undefined ? { page: query.page } : {}),
|
|
32
|
+
});
|
|
33
|
+
if (!resolved) {
|
|
34
|
+
throw new HttpError(404, ERROR_CODES.BLOG_POST_NOT_FOUND, 'No blog Post or Category at that slug, or the blog is disabled in this scope.');
|
|
35
|
+
}
|
|
36
|
+
return { data: resolved };
|
|
37
|
+
});
|
|
38
|
+
app.get('/api/v1/blog/tag-by-code', async (request) => {
|
|
39
|
+
const query = tagByCodeQuerySchema.parse(request.query ?? {});
|
|
40
|
+
const { language } = readContext(request);
|
|
41
|
+
const resolved = await deps.storefrontResolver.getTagByCode(query.code, {
|
|
42
|
+
resolvedChannel: resolvedChannel(request),
|
|
43
|
+
...(language !== undefined ? { language } : {}),
|
|
44
|
+
...(query.page !== undefined ? { page: query.page } : {}),
|
|
45
|
+
});
|
|
46
|
+
if (!resolved) {
|
|
47
|
+
throw new HttpError(404, ERROR_CODES.BLOG_TAG_NOT_FOUND, 'No blog Tag at that code, or the blog is disabled in this scope.');
|
|
48
|
+
}
|
|
49
|
+
return { data: resolved };
|
|
50
|
+
});
|
|
51
|
+
}
|
|
52
|
+
function readContext(request) {
|
|
53
|
+
const headers = request.headers;
|
|
54
|
+
const language = readHeader(headers['x-blog-language']) ??
|
|
55
|
+
readHeader(headers['accept-language'])?.split(',')[0]?.trim();
|
|
56
|
+
return { language };
|
|
57
|
+
}
|
|
58
|
+
/**
|
|
59
|
+
* Read the sales channel already resolved by the sales-channel resolver
|
|
60
|
+
* middleware for this request. Feature 053: routes no longer re-parse the
|
|
61
|
+
* `x-sales-channel` header nor re-query `sales_channels`.
|
|
62
|
+
*/
|
|
63
|
+
function resolvedChannel(request) {
|
|
64
|
+
const ch = getResolvedChannel(request);
|
|
65
|
+
return { id: ch.id, code: ch.code, defaultLanguage: ch.defaultLanguage };
|
|
66
|
+
}
|
|
67
|
+
function readHeader(value) {
|
|
68
|
+
if (Array.isArray(value))
|
|
69
|
+
return value[0];
|
|
70
|
+
return value;
|
|
71
|
+
}
|
|
72
|
+
//# sourceMappingURL=routes.storefront.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"routes.storefront.js","sourceRoot":"","sources":["../../src/backend/routes.storefront.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1,4 @@
|
|
|
1
|
+
import type { EntityManager } from '@mikro-orm/postgresql';
|
|
2
|
+
import type { AssetReferenceRegistryPort } from '@endora-commerce/contracts';
|
|
3
|
+
export declare function registerBlogAssetReferences(registry: AssetReferenceRegistryPort, emFactory: () => EntityManager): void;
|
|
4
|
+
//# sourceMappingURL=blog-asset-references.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"blog-asset-references.d.ts","sourceRoot":"","sources":["../../../src/backend/services/blog-asset-references.ts"],"names":[],"mappings":"AAcA,OAAO,KAAK,EAAE,aAAa,EAAE,MAAM,uBAAuB,CAAC;AAC3D,OAAO,KAAK,EAGV,0BAA0B,EAC3B,MAAM,4BAA4B,CAAC;AAEpC,wBAAgB,2BAA2B,CACzC,QAAQ,EAAE,0BAA0B,EACpC,SAAS,EAAE,MAAM,aAAa,GAC7B,IAAI,CAGN"}
|
|
@@ -0,0 +1,79 @@
|
|
|
1
|
+
// Blog → AssetReferenceRegistry descriptor — feature 016 / T018.
|
|
2
|
+
//
|
|
3
|
+
// Registers two reference edges with the Library Asset reference registry
|
|
4
|
+
// so the Library's soft-delete path (feature 013 / FR-030) blocks deletion
|
|
5
|
+
// of any asset still pointed at by:
|
|
6
|
+
//
|
|
7
|
+
// - blog_categories.main_image_asset_id (column-level reference)
|
|
8
|
+
// - jsonb references inside blog_posts.content or
|
|
9
|
+
// blog_categories.description (Page Builder asset embeds)
|
|
10
|
+
//
|
|
11
|
+
// The jsonb edge uses `jsonb_path_exists` driven by the GIN index
|
|
12
|
+
// `idx_blog_posts_content_refs` and the matching index on
|
|
13
|
+
// `blog_categories.description` (created via the GIN's content path).
|
|
14
|
+
export function registerBlogAssetReferences(registry, emFactory) {
|
|
15
|
+
registry.register(blogMainImageReferenceDescriptor(emFactory));
|
|
16
|
+
registry.register(blogContentTreeReferenceDescriptor(emFactory));
|
|
17
|
+
}
|
|
18
|
+
function blogMainImageReferenceDescriptor(emFactory) {
|
|
19
|
+
return {
|
|
20
|
+
ownerModuleId: 'blog',
|
|
21
|
+
async findReferences(assetIds) {
|
|
22
|
+
if (assetIds.length === 0)
|
|
23
|
+
return [];
|
|
24
|
+
const em = emFactory();
|
|
25
|
+
const placeholders = assetIds.map(() => '?').join(', ');
|
|
26
|
+
const rows = (await em.execute(`select id::text as id, slug
|
|
27
|
+
from blog_categories
|
|
28
|
+
where main_image_asset_id in (${placeholders})
|
|
29
|
+
and deleted_at is null`, [...assetIds]));
|
|
30
|
+
return rows.map((r) => ({
|
|
31
|
+
kind: 'blog_category_main_image',
|
|
32
|
+
entityId: r.id,
|
|
33
|
+
label: `Blog category "${r.slug}"`,
|
|
34
|
+
}));
|
|
35
|
+
},
|
|
36
|
+
};
|
|
37
|
+
}
|
|
38
|
+
function blogContentTreeReferenceDescriptor(emFactory) {
|
|
39
|
+
return {
|
|
40
|
+
ownerModuleId: 'blog',
|
|
41
|
+
async findReferences(assetIds) {
|
|
42
|
+
if (assetIds.length === 0)
|
|
43
|
+
return [];
|
|
44
|
+
const em = emFactory();
|
|
45
|
+
const out = [];
|
|
46
|
+
for (const aidRaw of assetIds) {
|
|
47
|
+
// The asset id is a UUID; this regex is a defensive pre-filter to
|
|
48
|
+
// keep the literal-injected jsonpath safe (the same idiom feature
|
|
49
|
+
// 014's CMS asset-references uses).
|
|
50
|
+
const aid = aidRaw.replace(/[^0-9a-fA-F-]/g, '');
|
|
51
|
+
const path = `'$.** ? (@ == "${aid}")'::jsonpath`;
|
|
52
|
+
const rows = (await em.execute(`select id::text as id, slug, 'blog_post' as kind
|
|
53
|
+
from blog_posts
|
|
54
|
+
where deleted_at is null
|
|
55
|
+
and jsonb_path_exists(content, ${path})
|
|
56
|
+
union all
|
|
57
|
+
select id::text as id, slug, 'blog_category' as kind
|
|
58
|
+
from blog_categories
|
|
59
|
+
where deleted_at is null
|
|
60
|
+
and description is not null
|
|
61
|
+
and jsonb_path_exists(description, ${path})`));
|
|
62
|
+
for (const r of rows) {
|
|
63
|
+
const label = r.kind === 'blog_post'
|
|
64
|
+
? `Blog post "${r.slug}"`
|
|
65
|
+
: `Blog category description "${r.slug}"`;
|
|
66
|
+
out.push({
|
|
67
|
+
kind: r.kind === 'blog_post'
|
|
68
|
+
? 'blog_post_content'
|
|
69
|
+
: 'blog_category_description',
|
|
70
|
+
entityId: r.id,
|
|
71
|
+
label,
|
|
72
|
+
});
|
|
73
|
+
}
|
|
74
|
+
}
|
|
75
|
+
return out;
|
|
76
|
+
},
|
|
77
|
+
};
|
|
78
|
+
}
|
|
79
|
+
//# sourceMappingURL=blog-asset-references.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"blog-asset-references.js","sourceRoot":"","sources":["../../../src/backend/services/blog-asset-references.ts"],"names":[],"mappings":"AAAA,iEAAiE;AACjE,EAAE;AACF,0EAA0E;AAC1E,2EAA2E;AAC3E,oCAAoC;AACpC,EAAE;AACF,sEAAsE;AACtE,oDAAoD;AACpD,8DAA8D;AAC9D,EAAE;AACF,kEAAkE;AAClE,0DAA0D;AAC1D,sEAAsE;AAStE,MAAM,UAAU,2BAA2B,CACzC,QAAoC,EACpC,SAA8B;IAE9B,QAAQ,CAAC,QAAQ,CAAC,gCAAgC,CAAC,SAAS,CAAC,CAAC,CAAC;IAC/D,QAAQ,CAAC,QAAQ,CAAC,kCAAkC,CAAC,SAAS,CAAC,CAAC,CAAC;AACnE,CAAC;AAED,SAAS,gCAAgC,CACvC,SAA8B;IAE9B,OAAO;QACL,aAAa,EAAE,MAAM;QACrB,KAAK,CAAC,cAAc,CAAC,QAAkB;YACrC,IAAI,QAAQ,CAAC,MAAM,KAAK,CAAC;gBAAE,OAAO,EAAE,CAAC;YACrC,MAAM,EAAE,GAAG,SAAS,EAAE,CAAC;YACvB,MAAM,YAAY,GAAG,QAAQ,CAAC,GAAG,CAAC,GAAG,EAAE,CAAC,GAAG,CAAC,CAAC,IAAI,CAAC,IAAI,CAAC,CAAC;YACxD,MAAM,IAAI,GAAG,CAAC,MAAM,EAAE,CAAC,OAAO,CAC5B;;0CAEkC,YAAY;mCACnB,EAC3B,CAAC,GAAG,QAAQ,CAAC,CACd,CAAwC,CAAC;YAC1C,OAAO,IAAI,CAAC,GAAG,CAAC,CAAC,CAAC,EAAE,EAAE,CAAC,CAAC;gBACtB,IAAI,EAAE,0BAA0B;gBAChC,QAAQ,EAAE,CAAC,CAAC,EAAE;gBACd,KAAK,EAAE,kBAAkB,CAAC,CAAC,IAAI,GAAG;aACnC,CAAC,CAAC,CAAC;QACN,CAAC;KACF,CAAC;AACJ,CAAC;AAED,SAAS,kCAAkC,CACzC,SAA8B;IAE9B,OAAO;QACL,aAAa,EAAE,MAAM;QACrB,KAAK,CAAC,cAAc,CAAC,QAAkB;YACrC,IAAI,QAAQ,CAAC,MAAM,KAAK,CAAC;gBAAE,OAAO,EAAE,CAAC;YACrC,MAAM,EAAE,GAAG,SAAS,EAAE,CAAC;YACvB,MAAM,GAAG,GAAqB,EAAE,CAAC;YACjC,KAAK,MAAM,MAAM,IAAI,QAAQ,EAAE,CAAC;gBAC9B,kEAAkE;gBAClE,kEAAkE;gBAClE,oCAAoC;gBACpC,MAAM,GAAG,GAAG,MAAM,CAAC,OAAO,CAAC,gBAAgB,EAAE,EAAE,CAAC,CAAC;gBACjD,MAAM,IAAI,GAAG,kBAAkB,GAAG,eAAe,CAAC;gBAElD,MAAM,IAAI,GAAG,CAAC,MAAM,EAAE,CAAC,OAAO,CAC5B;;;+CAGqC,IAAI;;;;;;mDAMA,IAAI,GAAG,CACjD,CAAsD,CAAC;gBAExD,KAAK,MAAM,CAAC,IAAI,IAAI,EAAE,CAAC;oBACrB,MAAM,KAAK,GACT,CAAC,CAAC,IAAI,KAAK,WAAW;wBACpB,CAAC,CAAC,cAAc,CAAC,CAAC,IAAI,GAAG;wBACzB,CAAC,CAAC,8BAA8B,CAAC,CAAC,IAAI,GAAG,CAAC;oBAC9C,GAAG,CAAC,IAAI,CAAC;wBACP,IAAI,EACF,CAAC,CAAC,IAAI,KAAK,WAAW;4BACpB,CAAC,CAAC,mBAAmB;4BACrB,CAAC,CAAC,2BAA2B;wBACjC,QAAQ,EAAE,CAAC,CAAC,EAAE;wBACd,KAAK;qBACN,CAAC,CAAC;gBACL,CAAC;YACH,CAAC;YACD,OAAO,GAAG,CAAC;QACb,CAAC;KACF,CAAC;AACJ,CAAC"}
|
|
@@ -0,0 +1,55 @@
|
|
|
1
|
+
import type { Redis } from 'ioredis';
|
|
2
|
+
/**
|
|
3
|
+
* Storefront read-through cache for the Blog module — feature 016 / T020.
|
|
4
|
+
*
|
|
5
|
+
* Mirrors feature 014's `CmsCache` and feature 015's `MegamenuCache` shape
|
|
6
|
+
* exactly: same key-prefix scheme, same default TTL, same SCAN-based
|
|
7
|
+
* coarse invalidation. Keys live under `blog:v1:<channelCode>:<language>`.
|
|
8
|
+
*
|
|
9
|
+
* Per `research.md` § R9 the cache holds four kinds of entry:
|
|
10
|
+
*
|
|
11
|
+
* blog:v1:<channel>:<language>:index
|
|
12
|
+
* blog:v1:<channel>:<language>:category:<slug>:p<page>
|
|
13
|
+
* blog:v1:<channel>:<language>:post:<slug>
|
|
14
|
+
* blog:v1:<channel>:<language>:tag:<code>:p<page>
|
|
15
|
+
*
|
|
16
|
+
* Invalidation is per-write (publishing a Post invalidates that post's
|
|
17
|
+
* key, every category page that contained it, every tag page that
|
|
18
|
+
* contained it, and the index for every channel the post is in). Settings
|
|
19
|
+
* writes invalidate the whole channel keyspace via `invalidateChannel`.
|
|
20
|
+
*/
|
|
21
|
+
export declare const BLOG_CACHE_KEY_PREFIX = "blog:v1:";
|
|
22
|
+
export declare const BLOG_CACHE_DEFAULT_TTL_SECONDS: number;
|
|
23
|
+
export interface BlogCacheOptions {
|
|
24
|
+
ttlSeconds?: number;
|
|
25
|
+
/** When false, get/set are short-circuit no-ops (useful for tests). */
|
|
26
|
+
enabled?: boolean;
|
|
27
|
+
}
|
|
28
|
+
export declare class BlogCacheService {
|
|
29
|
+
private readonly redis;
|
|
30
|
+
private readonly ttlSeconds;
|
|
31
|
+
private readonly enabled;
|
|
32
|
+
constructor(redis: Redis, options?: BlogCacheOptions);
|
|
33
|
+
static composeIndexKey(channelCode: string, language: string): string;
|
|
34
|
+
static composeCategoryKey(channelCode: string, language: string, slug: string, page: number): string;
|
|
35
|
+
static composePostKey(channelCode: string, language: string, slug: string): string;
|
|
36
|
+
static composeTagKey(channelCode: string, language: string, code: string, page: number): string;
|
|
37
|
+
get<T>(key: string): Promise<T | null>;
|
|
38
|
+
set<T>(key: string, payload: T): Promise<void>;
|
|
39
|
+
/** Drop one key (used after the post-by-slug write). */
|
|
40
|
+
invalidateKey(key: string): Promise<void>;
|
|
41
|
+
/** Drop every key under a channel + language scope. */
|
|
42
|
+
invalidateScope(channelCode: string, language: string): Promise<void>;
|
|
43
|
+
/** Drop every key under a channel (covers every language). Used on settings writes. */
|
|
44
|
+
invalidateChannel(channelCode: string): Promise<void>;
|
|
45
|
+
/** Drop the entire blog keyspace. Used by tests and by global config changes. */
|
|
46
|
+
invalidateAll(): Promise<void>;
|
|
47
|
+
/** Drop every entry that mentions a specific category slug across every language of a channel. */
|
|
48
|
+
invalidateCategory(channelCode: string, slug: string): Promise<void>;
|
|
49
|
+
/** Drop every entry that mentions a specific post slug across every language of a channel. */
|
|
50
|
+
invalidatePost(channelCode: string, slug: string): Promise<void>;
|
|
51
|
+
/** Drop every entry that mentions a specific tag code across every language of a channel. */
|
|
52
|
+
invalidateTag(channelCode: string, code: string): Promise<void>;
|
|
53
|
+
private scanDelete;
|
|
54
|
+
}
|
|
55
|
+
//# sourceMappingURL=blog-cache.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"blog-cache.d.ts","sourceRoot":"","sources":["../../../src/backend/services/blog-cache.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,KAAK,EAAE,MAAM,SAAS,CAAC;AAErC;;;;;;;;;;;;;;;;;;GAkBG;AAEH,eAAO,MAAM,qBAAqB,aAAa,CAAC;AAChD,eAAO,MAAM,8BAA8B,QAAS,CAAC;AAErD,MAAM,WAAW,gBAAgB;IAC/B,UAAU,CAAC,EAAE,MAAM,CAAC;IACpB,uEAAuE;IACvE,OAAO,CAAC,EAAE,OAAO,CAAC;CACnB;AAMD,qBAAa,gBAAgB;IAIf,OAAO,CAAC,QAAQ,CAAC,KAAK;IAHlC,OAAO,CAAC,QAAQ,CAAC,UAAU,CAAS;IACpC,OAAO,CAAC,QAAQ,CAAC,OAAO,CAAU;gBAEL,KAAK,EAAE,KAAK,EAAE,OAAO,GAAE,gBAAqB;IAKzE,MAAM,CAAC,eAAe,CAAC,WAAW,EAAE,MAAM,EAAE,QAAQ,EAAE,MAAM,GAAG,MAAM;IAIrE,MAAM,CAAC,kBAAkB,CACvB,WAAW,EAAE,MAAM,EACnB,QAAQ,EAAE,MAAM,EAChB,IAAI,EAAE,MAAM,EACZ,IAAI,EAAE,MAAM,GACX,MAAM;IAIT,MAAM,CAAC,cAAc,CAAC,WAAW,EAAE,MAAM,EAAE,QAAQ,EAAE,MAAM,EAAE,IAAI,EAAE,MAAM,GAAG,MAAM;IAIlF,MAAM,CAAC,aAAa,CAClB,WAAW,EAAE,MAAM,EACnB,QAAQ,EAAE,MAAM,EAChB,IAAI,EAAE,MAAM,EACZ,IAAI,EAAE,MAAM,GACX,MAAM;IAIH,GAAG,CAAC,CAAC,EAAE,GAAG,EAAE,MAAM,GAAG,OAAO,CAAC,CAAC,GAAG,IAAI,CAAC;IAYtC,GAAG,CAAC,CAAC,EAAE,GAAG,EAAE,MAAM,EAAE,OAAO,EAAE,CAAC,GAAG,OAAO,CAAC,IAAI,CAAC;IAKpD,wDAAwD;IAClD,aAAa,CAAC,GAAG,EAAE,MAAM,GAAG,OAAO,CAAC,IAAI,CAAC;IAK/C,uDAAuD;IACjD,eAAe,CAAC,WAAW,EAAE,MAAM,EAAE,QAAQ,EAAE,MAAM,GAAG,OAAO,CAAC,IAAI,CAAC;IAI3E,uFAAuF;IACjF,iBAAiB,CAAC,WAAW,EAAE,MAAM,GAAG,OAAO,CAAC,IAAI,CAAC;IAI3D,iFAAiF;IAC3E,aAAa,IAAI,OAAO,CAAC,IAAI,CAAC;IAIpC,kGAAkG;IAC5F,kBAAkB,CAAC,WAAW,EAAE,MAAM,EAAE,IAAI,EAAE,MAAM,GAAG,OAAO,CAAC,IAAI,CAAC;IAI1E,8FAA8F;IACxF,cAAc,CAAC,WAAW,EAAE,MAAM,EAAE,IAAI,EAAE,MAAM,GAAG,OAAO,CAAC,IAAI,CAAC;IAQtE,6FAA6F;IACvF,aAAa,CAAC,WAAW,EAAE,MAAM,EAAE,IAAI,EAAE,MAAM,GAAG,OAAO,CAAC,IAAI,CAAC;YAIvD,UAAU;CASzB"}
|