@btst/stack 1.2.1 → 1.3.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/dist/packages/better-stack/src/plugins/blog/api/plugin.cjs +117 -137
- package/dist/packages/better-stack/src/plugins/blog/api/plugin.mjs +117 -137
- package/dist/packages/better-stack/src/plugins/blog/client/plugin.cjs +10 -0
- package/dist/packages/better-stack/src/plugins/blog/client/plugin.mjs +10 -0
- package/dist/packages/better-stack/src/plugins/blog/db.cjs +12 -2
- package/dist/packages/better-stack/src/plugins/blog/db.mjs +12 -2
- package/dist/plugins/blog/api/index.d.cts +1 -1
- package/dist/plugins/blog/api/index.d.mts +1 -1
- package/dist/plugins/blog/api/index.d.ts +1 -1
- package/dist/plugins/blog/client/hooks/index.d.cts +2 -2
- package/dist/plugins/blog/client/hooks/index.d.mts +2 -2
- package/dist/plugins/blog/client/hooks/index.d.ts +2 -2
- package/dist/plugins/blog/client/index.d.cts +1 -1
- package/dist/plugins/blog/client/index.d.mts +1 -1
- package/dist/plugins/blog/client/index.d.ts +1 -1
- package/dist/plugins/blog/query-keys.d.cts +5 -5
- package/dist/plugins/blog/query-keys.d.mts +5 -5
- package/dist/plugins/blog/query-keys.d.ts +5 -5
- package/package.json +3 -3
- package/src/plugins/blog/api/plugin.ts +139 -190
- package/src/plugins/blog/client/plugin.tsx +12 -0
- package/src/plugins/blog/db.ts +10 -0
- package/src/plugins/blog/types.ts +7 -0
- package/dist/shared/{stack.Cr2JoQdo.d.cts → stack.DLhzx1-D.d.cts} +2 -2
- package/dist/shared/{stack.Cr2JoQdo.d.mts → stack.DLhzx1-D.d.mts} +2 -2
- package/dist/shared/{stack.Cr2JoQdo.d.ts → stack.DLhzx1-D.d.ts} +2 -2
|
@@ -26,53 +26,7 @@ const blogBackendPlugin = (hooks) => api.defineBackendPlugin({
|
|
|
26
26
|
name: "blog",
|
|
27
27
|
dbPlugin: db.blogSchema,
|
|
28
28
|
routes: (adapter) => {
|
|
29
|
-
const
|
|
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
|
|
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
|
|
181
|
-
|
|
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
|
|
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,36 @@ const blogBackendPlugin = (hooks) => api.defineBackendPlugin({
|
|
|
211
158
|
sortBy: {
|
|
212
159
|
field: "createdAt",
|
|
213
160
|
direction: "desc"
|
|
161
|
+
},
|
|
162
|
+
join: {
|
|
163
|
+
postTag: true
|
|
164
|
+
}
|
|
165
|
+
});
|
|
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
|
+
}
|
|
214
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) => tagMap.get(pt.tagId)).filter((tag) => tag !== void 0);
|
|
185
|
+
const { postTag: _, ...postWithoutJoin } = post;
|
|
186
|
+
return {
|
|
187
|
+
...postWithoutJoin,
|
|
188
|
+
tags: postTags
|
|
189
|
+
};
|
|
215
190
|
});
|
|
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
|
-
}));
|
|
225
191
|
if (tagFilterPostIds) {
|
|
226
192
|
result = result.filter((post) => tagFilterPostIds.has(post.id));
|
|
227
193
|
}
|
|
@@ -262,7 +228,6 @@ const blogBackendPlugin = (hooks) => api.defineBackendPlugin({
|
|
|
262
228
|
body: ctx.body,
|
|
263
229
|
headers: ctx.headers
|
|
264
230
|
};
|
|
265
|
-
const tagCache = createTagCache();
|
|
266
231
|
try {
|
|
267
232
|
if (hooks?.onBeforeCreatePost) {
|
|
268
233
|
const canCreate = await hooks.onBeforeCreatePost(
|
|
@@ -288,7 +253,7 @@ const blogBackendPlugin = (hooks) => api.defineBackendPlugin({
|
|
|
288
253
|
}
|
|
289
254
|
});
|
|
290
255
|
if (tagNames.length > 0) {
|
|
291
|
-
const createdTags = await findOrCreateTags(tagNames
|
|
256
|
+
const createdTags = await findOrCreateTags(tagNames);
|
|
292
257
|
await adapter.transaction(async (tx) => {
|
|
293
258
|
for (const tag of createdTags) {
|
|
294
259
|
await tx.create({
|
|
@@ -328,7 +293,6 @@ const blogBackendPlugin = (hooks) => api.defineBackendPlugin({
|
|
|
328
293
|
params: ctx.params,
|
|
329
294
|
headers: ctx.headers
|
|
330
295
|
};
|
|
331
|
-
const tagCache = createTagCache();
|
|
332
296
|
try {
|
|
333
297
|
if (hooks?.onBeforeUpdatePost) {
|
|
334
298
|
const canUpdate = await hooks.onBeforeUpdatePost(
|
|
@@ -386,7 +350,7 @@ const blogBackendPlugin = (hooks) => api.defineBackendPlugin({
|
|
|
386
350
|
});
|
|
387
351
|
}
|
|
388
352
|
if (tagNames.length > 0) {
|
|
389
|
-
const createdTags = await findOrCreateTags(tagNames
|
|
353
|
+
const createdTags = await findOrCreateTags(tagNames);
|
|
390
354
|
for (const tag of createdTags) {
|
|
391
355
|
await tx.create({
|
|
392
356
|
model: "postTag",
|
|
@@ -436,15 +400,9 @@ const blogBackendPlugin = (hooks) => api.defineBackendPlugin({
|
|
|
436
400
|
});
|
|
437
401
|
}
|
|
438
402
|
}
|
|
439
|
-
await adapter.
|
|
440
|
-
|
|
441
|
-
|
|
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
|
-
});
|
|
403
|
+
await adapter.delete({
|
|
404
|
+
model: "post",
|
|
405
|
+
where: [{ field: "id", value: ctx.params.id }]
|
|
448
406
|
});
|
|
449
407
|
if (hooks?.onPostDeleted) {
|
|
450
408
|
await hooks.onPostDeleted(ctx.params.id, context);
|
|
@@ -467,8 +425,6 @@ const blogBackendPlugin = (hooks) => api.defineBackendPlugin({
|
|
|
467
425
|
async (ctx) => {
|
|
468
426
|
const { query, headers } = ctx;
|
|
469
427
|
const context = { query, headers };
|
|
470
|
-
const tagCache = createTagCache();
|
|
471
|
-
const postTagCache = createPostTagCache();
|
|
472
428
|
try {
|
|
473
429
|
if (hooks?.onBeforeListPosts) {
|
|
474
430
|
const canList = await hooks.onBeforeListPosts(
|
|
@@ -482,12 +438,15 @@ const blogBackendPlugin = (hooks) => api.defineBackendPlugin({
|
|
|
482
438
|
}
|
|
483
439
|
}
|
|
484
440
|
const date = query.date;
|
|
485
|
-
const
|
|
486
|
-
const WINDOW_SIZE = 100;
|
|
487
|
-
const allPosts = await adapter.findMany({
|
|
441
|
+
const previousPosts = await adapter.findMany({
|
|
488
442
|
model: "post",
|
|
489
|
-
limit:
|
|
443
|
+
limit: 1,
|
|
490
444
|
where: [
|
|
445
|
+
{
|
|
446
|
+
field: "createdAt",
|
|
447
|
+
value: date,
|
|
448
|
+
operator: "lt"
|
|
449
|
+
},
|
|
491
450
|
{
|
|
492
451
|
field: "published",
|
|
493
452
|
value: true,
|
|
@@ -497,44 +456,65 @@ const blogBackendPlugin = (hooks) => api.defineBackendPlugin({
|
|
|
497
456
|
sortBy: {
|
|
498
457
|
field: "createdAt",
|
|
499
458
|
direction: "desc"
|
|
459
|
+
},
|
|
460
|
+
join: {
|
|
461
|
+
postTag: true
|
|
500
462
|
}
|
|
501
463
|
});
|
|
502
|
-
const
|
|
503
|
-
|
|
504
|
-
|
|
505
|
-
|
|
464
|
+
const nextPosts = await adapter.findMany({
|
|
465
|
+
model: "post",
|
|
466
|
+
limit: 1,
|
|
467
|
+
where: [
|
|
468
|
+
{
|
|
469
|
+
field: "createdAt",
|
|
470
|
+
value: date,
|
|
471
|
+
operator: "gt"
|
|
472
|
+
},
|
|
473
|
+
{
|
|
474
|
+
field: "published",
|
|
475
|
+
value: true,
|
|
476
|
+
operator: "eq"
|
|
477
|
+
}
|
|
478
|
+
],
|
|
479
|
+
sortBy: {
|
|
480
|
+
field: "createdAt",
|
|
481
|
+
direction: "asc"
|
|
482
|
+
},
|
|
483
|
+
join: {
|
|
484
|
+
postTag: true
|
|
485
|
+
}
|
|
506
486
|
});
|
|
507
|
-
|
|
508
|
-
|
|
509
|
-
for (
|
|
510
|
-
|
|
511
|
-
|
|
512
|
-
|
|
513
|
-
|
|
514
|
-
|
|
515
|
-
|
|
516
|
-
|
|
517
|
-
|
|
487
|
+
const tagIds = /* @__PURE__ */ new Set();
|
|
488
|
+
const allPosts = [...previousPosts, ...nextPosts];
|
|
489
|
+
for (const post of allPosts) {
|
|
490
|
+
if (post.postTag) {
|
|
491
|
+
for (const pt of post.postTag) {
|
|
492
|
+
tagIds.add(pt.tagId);
|
|
493
|
+
}
|
|
494
|
+
}
|
|
495
|
+
}
|
|
496
|
+
const tagMap = /* @__PURE__ */ new Map();
|
|
497
|
+
if (tagIds.size > 0) {
|
|
498
|
+
const tags = await adapter.findMany({
|
|
499
|
+
model: "tag"
|
|
500
|
+
});
|
|
501
|
+
for (const tag of tags) {
|
|
502
|
+
if (tagIds.has(tag.id)) {
|
|
503
|
+
tagMap.set(tag.id, tag);
|
|
504
|
+
}
|
|
518
505
|
}
|
|
519
506
|
}
|
|
520
|
-
const
|
|
521
|
-
|
|
522
|
-
...
|
|
523
|
-
|
|
524
|
-
|
|
525
|
-
|
|
526
|
-
|
|
527
|
-
|
|
528
|
-
);
|
|
507
|
+
const mapPostWithTags = (post) => {
|
|
508
|
+
const tags = (post.postTag || []).map((pt) => tagMap.get(pt.tagId)).filter((tag) => tag !== void 0);
|
|
509
|
+
const { postTag: _, ...postWithoutJoin } = post;
|
|
510
|
+
return {
|
|
511
|
+
...postWithoutJoin,
|
|
512
|
+
tags
|
|
513
|
+
};
|
|
514
|
+
};
|
|
529
515
|
return {
|
|
530
|
-
previous:
|
|
531
|
-
|
|
532
|
-
tags: postTagsMap.get(previousPost.id) || []
|
|
533
|
-
} : null,
|
|
534
|
-
next: nextPost ? {
|
|
535
|
-
...nextPost,
|
|
536
|
-
tags: postTagsMap.get(nextPost.id) || []
|
|
537
|
-
} : null
|
|
516
|
+
previous: previousPosts[0] ? mapPostWithTags(previousPosts[0]) : null,
|
|
517
|
+
next: nextPosts[0] ? mapPostWithTags(nextPosts[0]) : null
|
|
538
518
|
};
|
|
539
519
|
} catch (error) {
|
|
540
520
|
if (hooks?.onListPostsError) {
|