@btst/stack 1.2.2 → 1.3.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.
Files changed (32) hide show
  1. package/dist/packages/better-stack/src/plugins/blog/api/plugin.cjs +101 -120
  2. package/dist/packages/better-stack/src/plugins/blog/api/plugin.mjs +101 -120
  3. package/dist/packages/better-stack/src/plugins/blog/client/components/pages/post-page.internal.cjs +1 -1
  4. package/dist/packages/better-stack/src/plugins/blog/client/components/pages/post-page.internal.mjs +1 -1
  5. package/dist/packages/better-stack/src/plugins/blog/client/components/shared/on-this-page.cjs +1 -1
  6. package/dist/packages/better-stack/src/plugins/blog/client/components/shared/on-this-page.mjs +1 -1
  7. package/dist/packages/better-stack/src/plugins/blog/client/components/shared/recent-posts-carousel.cjs +2 -2
  8. package/dist/packages/better-stack/src/plugins/blog/client/components/shared/recent-posts-carousel.mjs +2 -2
  9. package/dist/packages/better-stack/src/plugins/blog/db.cjs +12 -2
  10. package/dist/packages/better-stack/src/plugins/blog/db.mjs +12 -2
  11. package/dist/plugins/blog/api/index.d.cts +1 -1
  12. package/dist/plugins/blog/api/index.d.mts +1 -1
  13. package/dist/plugins/blog/api/index.d.ts +1 -1
  14. package/dist/plugins/blog/client/hooks/index.d.cts +3 -3
  15. package/dist/plugins/blog/client/hooks/index.d.mts +3 -3
  16. package/dist/plugins/blog/client/hooks/index.d.ts +3 -3
  17. package/dist/plugins/blog/client/index.d.cts +1 -1
  18. package/dist/plugins/blog/client/index.d.mts +1 -1
  19. package/dist/plugins/blog/client/index.d.ts +1 -1
  20. package/dist/plugins/blog/query-keys.d.cts +6 -6
  21. package/dist/plugins/blog/query-keys.d.mts +6 -6
  22. package/dist/plugins/blog/query-keys.d.ts +6 -6
  23. package/package.json +3 -3
  24. package/src/plugins/blog/api/plugin.ts +122 -147
  25. package/src/plugins/blog/client/components/pages/post-page.internal.tsx +1 -1
  26. package/src/plugins/blog/client/components/shared/on-this-page.tsx +1 -1
  27. package/src/plugins/blog/client/components/shared/recent-posts-carousel.tsx +2 -2
  28. package/src/plugins/blog/db.ts +10 -0
  29. package/src/plugins/blog/types.ts +7 -0
  30. package/dist/shared/{stack.Cr2JoQdo.d.cts → stack.CbuN2zVV.d.cts} +3 -3
  31. package/dist/shared/{stack.Cr2JoQdo.d.mts → stack.CbuN2zVV.d.mts} +3 -3
  32. package/dist/shared/{stack.Cr2JoQdo.d.ts → stack.CbuN2zVV.d.ts} +3 -3
@@ -26,53 +26,7 @@ const blogBackendPlugin = (hooks) => api.defineBackendPlugin({
26
26
  name: "blog",
27
27
  dbPlugin: db.blogSchema,
28
28
  routes: (adapter) => {
29
- const createTagCache = () => {
30
- let cache = null;
31
- return {
32
- getAllTags: async () => {
33
- if (!cache) {
34
- cache = await adapter.findMany({
35
- model: "tag"
36
- });
37
- }
38
- return cache;
39
- },
40
- invalidate: () => {
41
- cache = null;
42
- },
43
- addTag: (tag) => {
44
- if (cache) {
45
- cache.push(tag);
46
- }
47
- }
48
- };
49
- };
50
- const createPostTagCache = () => {
51
- let cache = null;
52
- const getAllPostTags = async () => {
53
- if (!cache) {
54
- cache = await adapter.findMany({
55
- model: "postTag"
56
- });
57
- }
58
- return cache;
59
- };
60
- return {
61
- getAllPostTags,
62
- invalidate: () => {
63
- cache = null;
64
- },
65
- getByTagId: async (tagId) => {
66
- const allPostTags = await getAllPostTags();
67
- return allPostTags.filter((pt) => pt.tagId === tagId);
68
- },
69
- getByPostId: async (postId) => {
70
- const allPostTags = await getAllPostTags();
71
- return allPostTags.filter((pt) => pt.postId === postId);
72
- }
73
- };
74
- };
75
- const findOrCreateTags = async (tagInputs, tagCache) => {
29
+ const findOrCreateTags = async (tagInputs) => {
76
30
  if (tagInputs.length === 0) return [];
77
31
  const normalizeTagName = (name) => {
78
32
  return name.trim();
@@ -95,7 +49,9 @@ const blogBackendPlugin = (hooks) => api.defineBackendPlugin({
95
49
  if (tagsToFindOrCreate.length === 0) {
96
50
  return tagsWithIds;
97
51
  }
98
- const allTags = await tagCache.getAllTags();
52
+ const allTags = await adapter.findMany({
53
+ model: "tag"
54
+ });
99
55
  const tagMapBySlug = /* @__PURE__ */ new Map();
100
56
  for (const tag of allTags) {
101
57
  tagMapBySlug.set(tag.slug, tag);
@@ -128,33 +84,9 @@ const blogBackendPlugin = (hooks) => api.defineBackendPlugin({
128
84
  }
129
85
  });
130
86
  createdTags.push(newTag);
131
- tagCache.addTag(newTag);
132
87
  }
133
88
  return [...tagsWithIds, ...foundTags, ...createdTags];
134
89
  };
135
- const loadTagsForPosts = async (postIds, tagCache, postTagCache) => {
136
- if (postIds.length === 0) return /* @__PURE__ */ new Map();
137
- const allPostTags = await postTagCache.getAllPostTags();
138
- const relevantPostTags = allPostTags.filter(
139
- (pt) => postIds.includes(pt.postId)
140
- );
141
- const tagIds = [...new Set(relevantPostTags.map((pt) => pt.tagId))];
142
- if (tagIds.length === 0) return /* @__PURE__ */ new Map();
143
- const allTags = await tagCache.getAllTags();
144
- const tagMap = /* @__PURE__ */ new Map();
145
- for (const tag of allTags) {
146
- tagMap.set(tag.id, tag);
147
- }
148
- const postTagsMap = /* @__PURE__ */ new Map();
149
- for (const postTag of relevantPostTags) {
150
- const tag = tagMap.get(postTag.tagId);
151
- if (tag) {
152
- const existing = postTagsMap.get(postTag.postId) || [];
153
- postTagsMap.set(postTag.postId, [...existing, { ...tag }]);
154
- }
155
- }
156
- return postTagsMap;
157
- };
158
90
  const listPosts = api.createEndpoint(
159
91
  "/posts",
160
92
  {
@@ -164,8 +96,6 @@ const blogBackendPlugin = (hooks) => api.defineBackendPlugin({
164
96
  async (ctx) => {
165
97
  const { query, headers } = ctx;
166
98
  const context = { query, headers };
167
- const tagCache = createTagCache();
168
- const postTagCache = createPostTagCache();
169
99
  try {
170
100
  if (hooks?.onBeforeListPosts) {
171
101
  const canList = await hooks.onBeforeListPosts(query, context);
@@ -177,12 +107,29 @@ const blogBackendPlugin = (hooks) => api.defineBackendPlugin({
177
107
  }
178
108
  let tagFilterPostIds = null;
179
109
  if (query.tagSlug) {
180
- const allTags = await tagCache.getAllTags();
181
- const tag = allTags.find((t) => t.slug === query.tagSlug);
110
+ const tag = await adapter.findOne({
111
+ model: "tag",
112
+ where: [
113
+ {
114
+ field: "slug",
115
+ value: query.tagSlug,
116
+ operator: "eq"
117
+ }
118
+ ]
119
+ });
182
120
  if (!tag) {
183
121
  return [];
184
122
  }
185
- const postTags = await postTagCache.getByTagId(tag.id);
123
+ const postTags = await adapter.findMany({
124
+ model: "postTag",
125
+ where: [
126
+ {
127
+ field: "tagId",
128
+ value: tag.id,
129
+ operator: "eq"
130
+ }
131
+ ]
132
+ });
186
133
  tagFilterPostIds = new Set(postTags.map((pt) => pt.postId));
187
134
  if (tagFilterPostIds.size === 0) {
188
135
  return [];
@@ -211,17 +158,39 @@ const blogBackendPlugin = (hooks) => api.defineBackendPlugin({
211
158
  sortBy: {
212
159
  field: "createdAt",
213
160
  direction: "desc"
161
+ },
162
+ join: {
163
+ postTag: true
214
164
  }
215
165
  });
216
- const postTagsMap = await loadTagsForPosts(
217
- posts.map((post) => post.id),
218
- tagCache,
219
- postTagCache
220
- );
221
- let result = posts.map((post) => ({
222
- ...post,
223
- tags: postTagsMap.get(post.id) || []
224
- }));
166
+ const tagIds = /* @__PURE__ */ new Set();
167
+ for (const post of posts) {
168
+ if (post.postTag) {
169
+ for (const pt of post.postTag) {
170
+ tagIds.add(pt.tagId);
171
+ }
172
+ }
173
+ }
174
+ const tags = tagIds.size > 0 ? await adapter.findMany({
175
+ model: "tag"
176
+ }) : [];
177
+ const tagMap = /* @__PURE__ */ new Map();
178
+ for (const tag of tags) {
179
+ if (tagIds.has(tag.id)) {
180
+ tagMap.set(tag.id, tag);
181
+ }
182
+ }
183
+ let result = posts.map((post) => {
184
+ const postTags = (post.postTag || []).map((pt) => {
185
+ const tag = tagMap.get(pt.tagId);
186
+ return tag ? { ...tag } : void 0;
187
+ }).filter((tag) => tag !== void 0);
188
+ const { postTag: _, ...postWithoutJoin } = post;
189
+ return {
190
+ ...postWithoutJoin,
191
+ tags: postTags
192
+ };
193
+ });
225
194
  if (tagFilterPostIds) {
226
195
  result = result.filter((post) => tagFilterPostIds.has(post.id));
227
196
  }
@@ -262,7 +231,6 @@ const blogBackendPlugin = (hooks) => api.defineBackendPlugin({
262
231
  body: ctx.body,
263
232
  headers: ctx.headers
264
233
  };
265
- const tagCache = createTagCache();
266
234
  try {
267
235
  if (hooks?.onBeforeCreatePost) {
268
236
  const canCreate = await hooks.onBeforeCreatePost(
@@ -288,7 +256,7 @@ const blogBackendPlugin = (hooks) => api.defineBackendPlugin({
288
256
  }
289
257
  });
290
258
  if (tagNames.length > 0) {
291
- const createdTags = await findOrCreateTags(tagNames, tagCache);
259
+ const createdTags = await findOrCreateTags(tagNames);
292
260
  await adapter.transaction(async (tx) => {
293
261
  for (const tag of createdTags) {
294
262
  await tx.create({
@@ -328,7 +296,6 @@ const blogBackendPlugin = (hooks) => api.defineBackendPlugin({
328
296
  params: ctx.params,
329
297
  headers: ctx.headers
330
298
  };
331
- const tagCache = createTagCache();
332
299
  try {
333
300
  if (hooks?.onBeforeUpdatePost) {
334
301
  const canUpdate = await hooks.onBeforeUpdatePost(
@@ -386,7 +353,7 @@ const blogBackendPlugin = (hooks) => api.defineBackendPlugin({
386
353
  });
387
354
  }
388
355
  if (tagNames.length > 0) {
389
- const createdTags = await findOrCreateTags(tagNames, tagCache);
356
+ const createdTags = await findOrCreateTags(tagNames);
390
357
  for (const tag of createdTags) {
391
358
  await tx.create({
392
359
  model: "postTag",
@@ -436,15 +403,9 @@ const blogBackendPlugin = (hooks) => api.defineBackendPlugin({
436
403
  });
437
404
  }
438
405
  }
439
- await adapter.transaction(async (tx) => {
440
- await tx.delete({
441
- model: "postTag",
442
- where: [{ field: "postId", value: ctx.params.id }]
443
- });
444
- await tx.delete({
445
- model: "post",
446
- where: [{ field: "id", value: ctx.params.id }]
447
- });
406
+ await adapter.delete({
407
+ model: "post",
408
+ where: [{ field: "id", value: ctx.params.id }]
448
409
  });
449
410
  if (hooks?.onPostDeleted) {
450
411
  await hooks.onPostDeleted(ctx.params.id, context);
@@ -467,8 +428,6 @@ const blogBackendPlugin = (hooks) => api.defineBackendPlugin({
467
428
  async (ctx) => {
468
429
  const { query, headers } = ctx;
469
430
  const context = { query, headers };
470
- const tagCache = createTagCache();
471
- const postTagCache = createPostTagCache();
472
431
  try {
473
432
  if (hooks?.onBeforeListPosts) {
474
433
  const canList = await hooks.onBeforeListPosts(
@@ -482,7 +441,7 @@ const blogBackendPlugin = (hooks) => api.defineBackendPlugin({
482
441
  }
483
442
  }
484
443
  const date = query.date;
485
- const previousPost = await adapter.findMany({
444
+ const previousPosts = await adapter.findMany({
486
445
  model: "post",
487
446
  limit: 1,
488
447
  where: [
@@ -500,9 +459,12 @@ const blogBackendPlugin = (hooks) => api.defineBackendPlugin({
500
459
  sortBy: {
501
460
  field: "createdAt",
502
461
  direction: "desc"
462
+ },
463
+ join: {
464
+ postTag: true
503
465
  }
504
466
  });
505
- const nextPost = await adapter.findMany({
467
+ const nextPosts = await adapter.findMany({
506
468
  model: "post",
507
469
  limit: 1,
508
470
  where: [
@@ -520,26 +482,45 @@ const blogBackendPlugin = (hooks) => api.defineBackendPlugin({
520
482
  sortBy: {
521
483
  field: "createdAt",
522
484
  direction: "asc"
485
+ },
486
+ join: {
487
+ postTag: true
523
488
  }
524
489
  });
525
- const postIds = [
526
- ...previousPost?.[0] ? [previousPost[0].id] : [],
527
- ...nextPost?.[0] ? [nextPost[0].id] : []
528
- ];
529
- const postTagsMap = await loadTagsForPosts(
530
- postIds,
531
- tagCache,
532
- postTagCache
533
- );
490
+ const tagIds = /* @__PURE__ */ new Set();
491
+ const allPosts = [...previousPosts, ...nextPosts];
492
+ for (const post of allPosts) {
493
+ if (post.postTag) {
494
+ for (const pt of post.postTag) {
495
+ tagIds.add(pt.tagId);
496
+ }
497
+ }
498
+ }
499
+ const tagMap = /* @__PURE__ */ new Map();
500
+ if (tagIds.size > 0) {
501
+ const tags = await adapter.findMany({
502
+ model: "tag"
503
+ });
504
+ for (const tag of tags) {
505
+ if (tagIds.has(tag.id)) {
506
+ tagMap.set(tag.id, tag);
507
+ }
508
+ }
509
+ }
510
+ const mapPostWithTags = (post) => {
511
+ const tags = (post.postTag || []).map((pt) => {
512
+ const tag = tagMap.get(pt.tagId);
513
+ return tag ? { ...tag } : void 0;
514
+ }).filter((tag) => tag !== void 0);
515
+ const { postTag: _, ...postWithoutJoin } = post;
516
+ return {
517
+ ...postWithoutJoin,
518
+ tags
519
+ };
520
+ };
534
521
  return {
535
- previous: previousPost?.[0] ? {
536
- ...previousPost[0],
537
- tags: postTagsMap.get(previousPost[0].id) || []
538
- } : null,
539
- next: nextPost?.[0] ? {
540
- ...nextPost[0],
541
- tags: postTagsMap.get(nextPost[0].id) || []
542
- } : null
522
+ previous: previousPosts[0] ? mapPostWithTags(previousPosts[0]) : null,
523
+ next: nextPosts[0] ? mapPostWithTags(nextPosts[0]) : null
543
524
  };
544
525
  } catch (error) {
545
526
  if (hooks?.onListPostsError) {
@@ -24,53 +24,7 @@ const blogBackendPlugin = (hooks) => defineBackendPlugin({
24
24
  name: "blog",
25
25
  dbPlugin: blogSchema,
26
26
  routes: (adapter) => {
27
- const createTagCache = () => {
28
- let cache = null;
29
- return {
30
- getAllTags: async () => {
31
- if (!cache) {
32
- cache = await adapter.findMany({
33
- model: "tag"
34
- });
35
- }
36
- return cache;
37
- },
38
- invalidate: () => {
39
- cache = null;
40
- },
41
- addTag: (tag) => {
42
- if (cache) {
43
- cache.push(tag);
44
- }
45
- }
46
- };
47
- };
48
- const createPostTagCache = () => {
49
- let cache = null;
50
- const getAllPostTags = async () => {
51
- if (!cache) {
52
- cache = await adapter.findMany({
53
- model: "postTag"
54
- });
55
- }
56
- return cache;
57
- };
58
- return {
59
- getAllPostTags,
60
- invalidate: () => {
61
- cache = null;
62
- },
63
- getByTagId: async (tagId) => {
64
- const allPostTags = await getAllPostTags();
65
- return allPostTags.filter((pt) => pt.tagId === tagId);
66
- },
67
- getByPostId: async (postId) => {
68
- const allPostTags = await getAllPostTags();
69
- return allPostTags.filter((pt) => pt.postId === postId);
70
- }
71
- };
72
- };
73
- const findOrCreateTags = async (tagInputs, tagCache) => {
27
+ const findOrCreateTags = async (tagInputs) => {
74
28
  if (tagInputs.length === 0) return [];
75
29
  const normalizeTagName = (name) => {
76
30
  return name.trim();
@@ -93,7 +47,9 @@ const blogBackendPlugin = (hooks) => defineBackendPlugin({
93
47
  if (tagsToFindOrCreate.length === 0) {
94
48
  return tagsWithIds;
95
49
  }
96
- const allTags = await tagCache.getAllTags();
50
+ const allTags = await adapter.findMany({
51
+ model: "tag"
52
+ });
97
53
  const tagMapBySlug = /* @__PURE__ */ new Map();
98
54
  for (const tag of allTags) {
99
55
  tagMapBySlug.set(tag.slug, tag);
@@ -126,33 +82,9 @@ const blogBackendPlugin = (hooks) => defineBackendPlugin({
126
82
  }
127
83
  });
128
84
  createdTags.push(newTag);
129
- tagCache.addTag(newTag);
130
85
  }
131
86
  return [...tagsWithIds, ...foundTags, ...createdTags];
132
87
  };
133
- const loadTagsForPosts = async (postIds, tagCache, postTagCache) => {
134
- if (postIds.length === 0) return /* @__PURE__ */ new Map();
135
- const allPostTags = await postTagCache.getAllPostTags();
136
- const relevantPostTags = allPostTags.filter(
137
- (pt) => postIds.includes(pt.postId)
138
- );
139
- const tagIds = [...new Set(relevantPostTags.map((pt) => pt.tagId))];
140
- if (tagIds.length === 0) return /* @__PURE__ */ new Map();
141
- const allTags = await tagCache.getAllTags();
142
- const tagMap = /* @__PURE__ */ new Map();
143
- for (const tag of allTags) {
144
- tagMap.set(tag.id, tag);
145
- }
146
- const postTagsMap = /* @__PURE__ */ new Map();
147
- for (const postTag of relevantPostTags) {
148
- const tag = tagMap.get(postTag.tagId);
149
- if (tag) {
150
- const existing = postTagsMap.get(postTag.postId) || [];
151
- postTagsMap.set(postTag.postId, [...existing, { ...tag }]);
152
- }
153
- }
154
- return postTagsMap;
155
- };
156
88
  const listPosts = createEndpoint(
157
89
  "/posts",
158
90
  {
@@ -162,8 +94,6 @@ const blogBackendPlugin = (hooks) => defineBackendPlugin({
162
94
  async (ctx) => {
163
95
  const { query, headers } = ctx;
164
96
  const context = { query, headers };
165
- const tagCache = createTagCache();
166
- const postTagCache = createPostTagCache();
167
97
  try {
168
98
  if (hooks?.onBeforeListPosts) {
169
99
  const canList = await hooks.onBeforeListPosts(query, context);
@@ -175,12 +105,29 @@ const blogBackendPlugin = (hooks) => defineBackendPlugin({
175
105
  }
176
106
  let tagFilterPostIds = null;
177
107
  if (query.tagSlug) {
178
- const allTags = await tagCache.getAllTags();
179
- const tag = allTags.find((t) => t.slug === query.tagSlug);
108
+ const tag = await adapter.findOne({
109
+ model: "tag",
110
+ where: [
111
+ {
112
+ field: "slug",
113
+ value: query.tagSlug,
114
+ operator: "eq"
115
+ }
116
+ ]
117
+ });
180
118
  if (!tag) {
181
119
  return [];
182
120
  }
183
- const postTags = await postTagCache.getByTagId(tag.id);
121
+ const postTags = await adapter.findMany({
122
+ model: "postTag",
123
+ where: [
124
+ {
125
+ field: "tagId",
126
+ value: tag.id,
127
+ operator: "eq"
128
+ }
129
+ ]
130
+ });
184
131
  tagFilterPostIds = new Set(postTags.map((pt) => pt.postId));
185
132
  if (tagFilterPostIds.size === 0) {
186
133
  return [];
@@ -209,17 +156,39 @@ const blogBackendPlugin = (hooks) => defineBackendPlugin({
209
156
  sortBy: {
210
157
  field: "createdAt",
211
158
  direction: "desc"
159
+ },
160
+ join: {
161
+ postTag: true
212
162
  }
213
163
  });
214
- const postTagsMap = await loadTagsForPosts(
215
- posts.map((post) => post.id),
216
- tagCache,
217
- postTagCache
218
- );
219
- let result = posts.map((post) => ({
220
- ...post,
221
- tags: postTagsMap.get(post.id) || []
222
- }));
164
+ const tagIds = /* @__PURE__ */ new Set();
165
+ for (const post of posts) {
166
+ if (post.postTag) {
167
+ for (const pt of post.postTag) {
168
+ tagIds.add(pt.tagId);
169
+ }
170
+ }
171
+ }
172
+ const tags = tagIds.size > 0 ? await adapter.findMany({
173
+ model: "tag"
174
+ }) : [];
175
+ const tagMap = /* @__PURE__ */ new Map();
176
+ for (const tag of tags) {
177
+ if (tagIds.has(tag.id)) {
178
+ tagMap.set(tag.id, tag);
179
+ }
180
+ }
181
+ let result = posts.map((post) => {
182
+ const postTags = (post.postTag || []).map((pt) => {
183
+ const tag = tagMap.get(pt.tagId);
184
+ return tag ? { ...tag } : void 0;
185
+ }).filter((tag) => tag !== void 0);
186
+ const { postTag: _, ...postWithoutJoin } = post;
187
+ return {
188
+ ...postWithoutJoin,
189
+ tags: postTags
190
+ };
191
+ });
223
192
  if (tagFilterPostIds) {
224
193
  result = result.filter((post) => tagFilterPostIds.has(post.id));
225
194
  }
@@ -260,7 +229,6 @@ const blogBackendPlugin = (hooks) => defineBackendPlugin({
260
229
  body: ctx.body,
261
230
  headers: ctx.headers
262
231
  };
263
- const tagCache = createTagCache();
264
232
  try {
265
233
  if (hooks?.onBeforeCreatePost) {
266
234
  const canCreate = await hooks.onBeforeCreatePost(
@@ -286,7 +254,7 @@ const blogBackendPlugin = (hooks) => defineBackendPlugin({
286
254
  }
287
255
  });
288
256
  if (tagNames.length > 0) {
289
- const createdTags = await findOrCreateTags(tagNames, tagCache);
257
+ const createdTags = await findOrCreateTags(tagNames);
290
258
  await adapter.transaction(async (tx) => {
291
259
  for (const tag of createdTags) {
292
260
  await tx.create({
@@ -326,7 +294,6 @@ const blogBackendPlugin = (hooks) => defineBackendPlugin({
326
294
  params: ctx.params,
327
295
  headers: ctx.headers
328
296
  };
329
- const tagCache = createTagCache();
330
297
  try {
331
298
  if (hooks?.onBeforeUpdatePost) {
332
299
  const canUpdate = await hooks.onBeforeUpdatePost(
@@ -384,7 +351,7 @@ const blogBackendPlugin = (hooks) => defineBackendPlugin({
384
351
  });
385
352
  }
386
353
  if (tagNames.length > 0) {
387
- const createdTags = await findOrCreateTags(tagNames, tagCache);
354
+ const createdTags = await findOrCreateTags(tagNames);
388
355
  for (const tag of createdTags) {
389
356
  await tx.create({
390
357
  model: "postTag",
@@ -434,15 +401,9 @@ const blogBackendPlugin = (hooks) => defineBackendPlugin({
434
401
  });
435
402
  }
436
403
  }
437
- await adapter.transaction(async (tx) => {
438
- await tx.delete({
439
- model: "postTag",
440
- where: [{ field: "postId", value: ctx.params.id }]
441
- });
442
- await tx.delete({
443
- model: "post",
444
- where: [{ field: "id", value: ctx.params.id }]
445
- });
404
+ await adapter.delete({
405
+ model: "post",
406
+ where: [{ field: "id", value: ctx.params.id }]
446
407
  });
447
408
  if (hooks?.onPostDeleted) {
448
409
  await hooks.onPostDeleted(ctx.params.id, context);
@@ -465,8 +426,6 @@ const blogBackendPlugin = (hooks) => defineBackendPlugin({
465
426
  async (ctx) => {
466
427
  const { query, headers } = ctx;
467
428
  const context = { query, headers };
468
- const tagCache = createTagCache();
469
- const postTagCache = createPostTagCache();
470
429
  try {
471
430
  if (hooks?.onBeforeListPosts) {
472
431
  const canList = await hooks.onBeforeListPosts(
@@ -480,7 +439,7 @@ const blogBackendPlugin = (hooks) => defineBackendPlugin({
480
439
  }
481
440
  }
482
441
  const date = query.date;
483
- const previousPost = await adapter.findMany({
442
+ const previousPosts = await adapter.findMany({
484
443
  model: "post",
485
444
  limit: 1,
486
445
  where: [
@@ -498,9 +457,12 @@ const blogBackendPlugin = (hooks) => defineBackendPlugin({
498
457
  sortBy: {
499
458
  field: "createdAt",
500
459
  direction: "desc"
460
+ },
461
+ join: {
462
+ postTag: true
501
463
  }
502
464
  });
503
- const nextPost = await adapter.findMany({
465
+ const nextPosts = await adapter.findMany({
504
466
  model: "post",
505
467
  limit: 1,
506
468
  where: [
@@ -518,26 +480,45 @@ const blogBackendPlugin = (hooks) => defineBackendPlugin({
518
480
  sortBy: {
519
481
  field: "createdAt",
520
482
  direction: "asc"
483
+ },
484
+ join: {
485
+ postTag: true
521
486
  }
522
487
  });
523
- const postIds = [
524
- ...previousPost?.[0] ? [previousPost[0].id] : [],
525
- ...nextPost?.[0] ? [nextPost[0].id] : []
526
- ];
527
- const postTagsMap = await loadTagsForPosts(
528
- postIds,
529
- tagCache,
530
- postTagCache
531
- );
488
+ const tagIds = /* @__PURE__ */ new Set();
489
+ const allPosts = [...previousPosts, ...nextPosts];
490
+ for (const post of allPosts) {
491
+ if (post.postTag) {
492
+ for (const pt of post.postTag) {
493
+ tagIds.add(pt.tagId);
494
+ }
495
+ }
496
+ }
497
+ const tagMap = /* @__PURE__ */ new Map();
498
+ if (tagIds.size > 0) {
499
+ const tags = await adapter.findMany({
500
+ model: "tag"
501
+ });
502
+ for (const tag of tags) {
503
+ if (tagIds.has(tag.id)) {
504
+ tagMap.set(tag.id, tag);
505
+ }
506
+ }
507
+ }
508
+ const mapPostWithTags = (post) => {
509
+ const tags = (post.postTag || []).map((pt) => {
510
+ const tag = tagMap.get(pt.tagId);
511
+ return tag ? { ...tag } : void 0;
512
+ }).filter((tag) => tag !== void 0);
513
+ const { postTag: _, ...postWithoutJoin } = post;
514
+ return {
515
+ ...postWithoutJoin,
516
+ tags
517
+ };
518
+ };
532
519
  return {
533
- previous: previousPost?.[0] ? {
534
- ...previousPost[0],
535
- tags: postTagsMap.get(previousPost[0].id) || []
536
- } : null,
537
- next: nextPost?.[0] ? {
538
- ...nextPost[0],
539
- tags: postTagsMap.get(nextPost[0].id) || []
540
- } : null
520
+ previous: previousPosts[0] ? mapPostWithTags(previousPosts[0]) : null,
521
+ next: nextPosts[0] ? mapPostWithTags(nextPosts[0]) : null
541
522
  };
542
523
  } catch (error) {
543
524
  if (hooks?.onListPostsError) {
@@ -51,7 +51,7 @@ function PostPage({ slug }) {
51
51
  if (!slug || !post) {
52
52
  return /* @__PURE__ */ jsxRuntime.jsx(pageWrapper.PageWrapper, { children: /* @__PURE__ */ jsxRuntime.jsx(emptyList.EmptyList, { message: localization.BLOG_PAGE_NOT_FOUND_DESCRIPTION }) });
53
53
  }
54
- return /* @__PURE__ */ jsxRuntime.jsx(pageWrapper.PageWrapper, { className: "gap-0 px-4 lg:px-4 py-0 pb-18", testId: "post-page", children: /* @__PURE__ */ jsxRuntime.jsxs("div", { className: "flex items-start w-full", children: [
54
+ return /* @__PURE__ */ jsxRuntime.jsx(pageWrapper.PageWrapper, { className: "gap-0 px-4 lg:px-2 py-0 pb-18", testId: "post-page", children: /* @__PURE__ */ jsxRuntime.jsxs("div", { className: "flex items-start w-full", children: [
55
55
  /* @__PURE__ */ jsxRuntime.jsx("div", { className: "w-44 shrink-0 hidden xl:flex mr-auto" }),
56
56
  /* @__PURE__ */ jsxRuntime.jsxs("div", { className: "flex flex-col items-center flex-1 mx-auto w-full max-w-4xl min-w-0", children: [
57
57
  /* @__PURE__ */ jsxRuntime.jsx(onThisPage.OnThisPageSelect, { markdown: post.content }),
@@ -49,7 +49,7 @@ function PostPage({ slug }) {
49
49
  if (!slug || !post) {
50
50
  return /* @__PURE__ */ jsx(PageWrapper, { children: /* @__PURE__ */ jsx(EmptyList, { message: localization.BLOG_PAGE_NOT_FOUND_DESCRIPTION }) });
51
51
  }
52
- return /* @__PURE__ */ jsx(PageWrapper, { className: "gap-0 px-4 lg:px-4 py-0 pb-18", testId: "post-page", children: /* @__PURE__ */ jsxs("div", { className: "flex items-start w-full", children: [
52
+ return /* @__PURE__ */ jsx(PageWrapper, { className: "gap-0 px-4 lg:px-2 py-0 pb-18", testId: "post-page", children: /* @__PURE__ */ jsxs("div", { className: "flex items-start w-full", children: [
53
53
  /* @__PURE__ */ jsx("div", { className: "w-44 shrink-0 hidden xl:flex mr-auto" }),
54
54
  /* @__PURE__ */ jsxs("div", { className: "flex flex-col items-center flex-1 mx-auto w-full max-w-4xl min-w-0", children: [
55
55
  /* @__PURE__ */ jsx(OnThisPageSelect, { markdown: post.content }),