@btst/stack 2.11.1 → 2.11.3

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 (28) hide show
  1. package/dist/packages/stack/src/plugins/blog/api/mutations.cjs +170 -0
  2. package/dist/packages/stack/src/plugins/blog/api/mutations.mjs +166 -0
  3. package/dist/packages/stack/src/plugins/blog/api/plugin.cjs +34 -157
  4. package/dist/packages/stack/src/plugins/blog/api/plugin.mjs +40 -163
  5. package/dist/plugins/blog/api/index.cjs +4 -0
  6. package/dist/plugins/blog/api/index.d.cts +1 -1
  7. package/dist/plugins/blog/api/index.d.mts +1 -1
  8. package/dist/plugins/blog/api/index.d.ts +1 -1
  9. package/dist/plugins/blog/api/index.mjs +1 -0
  10. package/dist/plugins/blog/query-keys.d.cts +1 -1
  11. package/dist/plugins/blog/query-keys.d.mts +1 -1
  12. package/dist/plugins/blog/query-keys.d.ts +1 -1
  13. package/dist/plugins/kanban/api/index.d.cts +1 -1
  14. package/dist/plugins/kanban/api/index.d.mts +1 -1
  15. package/dist/plugins/kanban/api/index.d.ts +1 -1
  16. package/dist/plugins/kanban/query-keys.d.cts +1 -1
  17. package/dist/plugins/kanban/query-keys.d.mts +1 -1
  18. package/dist/plugins/kanban/query-keys.d.ts +1 -1
  19. package/dist/shared/{stack.qta0-CPq.d.ts → stack.BQSy-NDc.d.ts} +85 -2
  20. package/dist/shared/{stack.DvMUCTTl.d.mts → stack.CLrGRIj0.d.mts} +85 -2
  21. package/dist/shared/{stack.DEW8EtFu.d.cts → stack.CntKf20s.d.cts} +85 -2
  22. package/package.json +4 -4
  23. package/src/plugins/blog/api/index.ts +7 -0
  24. package/src/plugins/blog/api/mutations.ts +287 -0
  25. package/src/plugins/blog/api/plugin.ts +43 -184
  26. package/dist/shared/{stack.BvCR4-9H.d.ts → stack.CMbX8Q5C.d.ts} +13 -13
  27. package/dist/shared/{stack.CWxAl9K3.d.mts → stack.Dj04W2c3.d.mts} +13 -13
  28. package/dist/shared/{stack.BOokfhZD.d.cts → stack.eq5eg1yt.d.cts} +13 -13
@@ -4,6 +4,7 @@ import { blogSchema } from '../db.mjs';
4
4
  import { slugify } from '../utils.mjs';
5
5
  import { createPostSchema, updatePostSchema } from '../schemas.mjs';
6
6
  import { getAllTags, getPostBySlug, getAllPosts } from './getters.mjs';
7
+ import { deletePost, updatePost, createPost } from './mutations.mjs';
7
8
  import { BLOG_QUERY_KEYS } from './query-key-defs.mjs';
8
9
  import { serializePost, serializeTag } from './serializers.mjs';
9
10
  import { runHookWithShim } from '../../utils.mjs';
@@ -79,70 +80,13 @@ const blogBackendPlugin = (hooks) => defineBackendPlugin({
79
80
  getAllPosts: (params) => getAllPosts(adapter, params),
80
81
  getPostBySlug: (slug) => getPostBySlug(adapter, slug),
81
82
  getAllTags: () => getAllTags(adapter),
82
- prefetchForRoute: createBlogPrefetchForRoute(adapter)
83
+ prefetchForRoute: createBlogPrefetchForRoute(adapter),
84
+ // Mutations
85
+ createPost: (input) => createPost(adapter, input),
86
+ updatePost: (id, input) => updatePost(adapter, id, input),
87
+ deletePost: (id) => deletePost(adapter, id)
83
88
  }),
84
89
  routes: (adapter) => {
85
- const findOrCreateTags = async (tagInputs) => {
86
- if (tagInputs.length === 0) return [];
87
- const normalizeTagName = (name) => {
88
- return name.trim();
89
- };
90
- const tagsWithIds = [];
91
- const tagsToFindOrCreate = [];
92
- for (const tagInput of tagInputs) {
93
- if ("id" in tagInput && tagInput.id) {
94
- tagsWithIds.push({
95
- id: tagInput.id,
96
- name: normalizeTagName(tagInput.name),
97
- slug: tagInput.slug,
98
- createdAt: /* @__PURE__ */ new Date(),
99
- updatedAt: /* @__PURE__ */ new Date()
100
- });
101
- } else {
102
- tagsToFindOrCreate.push({ name: normalizeTagName(tagInput.name) });
103
- }
104
- }
105
- if (tagsToFindOrCreate.length === 0) {
106
- return tagsWithIds;
107
- }
108
- const allTags = await adapter.findMany({
109
- model: "tag"
110
- });
111
- const tagMapBySlug = /* @__PURE__ */ new Map();
112
- for (const tag of allTags) {
113
- tagMapBySlug.set(tag.slug, tag);
114
- }
115
- const tagSlugs = tagsToFindOrCreate.map((tag) => slugify(tag.name));
116
- const foundTags = [];
117
- for (const slug of tagSlugs) {
118
- const tag = tagMapBySlug.get(slug);
119
- if (tag) {
120
- foundTags.push(tag);
121
- }
122
- }
123
- const existingSlugs = /* @__PURE__ */ new Set([
124
- ...tagsWithIds.map((tag) => tag.slug),
125
- ...foundTags.map((tag) => tag.slug)
126
- ]);
127
- const tagsToCreate = tagsToFindOrCreate.filter(
128
- (tag) => !existingSlugs.has(slugify(tag.name))
129
- );
130
- const createdTags = [];
131
- for (const tag of tagsToCreate) {
132
- const normalizedName = normalizeTagName(tag.name);
133
- const newTag = await adapter.create({
134
- model: "tag",
135
- data: {
136
- name: normalizedName,
137
- slug: slugify(normalizedName),
138
- createdAt: /* @__PURE__ */ new Date(),
139
- updatedAt: /* @__PURE__ */ new Date()
140
- }
141
- });
142
- createdTags.push(newTag);
143
- }
144
- return [...tagsWithIds, ...foundTags, ...createdTags];
145
- };
146
90
  const listPosts = createEndpoint(
147
91
  "/posts",
148
92
  {
@@ -173,7 +117,7 @@ const blogBackendPlugin = (hooks) => defineBackendPlugin({
173
117
  }
174
118
  }
175
119
  );
176
- const createPost = createEndpoint(
120
+ const createPost$1 = createEndpoint(
177
121
  "/posts",
178
122
  {
179
123
  method: "POST",
@@ -192,41 +136,26 @@ const blogBackendPlugin = (hooks) => defineBackendPlugin({
192
136
  "Unauthorized: Cannot create post"
193
137
  );
194
138
  }
195
- const { tags, ...postData } = ctx.body;
196
- const tagNames = tags || [];
197
- const slug = slugify(postData.slug || postData.title);
139
+ const {
140
+ tags,
141
+ slug: rawSlug,
142
+ createdAt: _ca,
143
+ updatedAt: _ua,
144
+ ...postData
145
+ } = ctx.body;
146
+ const slug = slugify(rawSlug || postData.title);
198
147
  if (!slug) {
199
148
  throw ctx.error(400, {
200
149
  message: "Invalid slug: must contain at least one alphanumeric character"
201
150
  });
202
151
  }
203
- const newPost = await adapter.create({
204
- model: "post",
205
- data: {
206
- ...postData,
207
- slug,
208
- tags: [],
209
- createdAt: /* @__PURE__ */ new Date(),
210
- updatedAt: /* @__PURE__ */ new Date()
211
- }
152
+ const newPost = await createPost(adapter, {
153
+ ...postData,
154
+ slug,
155
+ tags: tags ?? [],
156
+ createdAt: /* @__PURE__ */ new Date(),
157
+ updatedAt: /* @__PURE__ */ new Date()
212
158
  });
213
- if (tagNames.length > 0) {
214
- const createdTags = await findOrCreateTags(tagNames);
215
- await adapter.transaction(async (tx) => {
216
- for (const tag of createdTags) {
217
- await tx.create({
218
- model: "postTag",
219
- data: {
220
- postId: newPost.id,
221
- tagId: tag.id
222
- }
223
- });
224
- }
225
- });
226
- newPost.tags = createdTags.map((tag) => ({ ...tag }));
227
- } else {
228
- newPost.tags = [];
229
- }
230
159
  if (hooks?.onPostCreated) {
231
160
  await hooks.onPostCreated(newPost, context);
232
161
  }
@@ -239,7 +168,7 @@ const blogBackendPlugin = (hooks) => defineBackendPlugin({
239
168
  }
240
169
  }
241
170
  );
242
- const updatePost = createEndpoint(
171
+ const updatePost$1 = createEndpoint(
243
172
  "/posts/:id",
244
173
  {
245
174
  method: "PUT",
@@ -259,76 +188,27 @@ const blogBackendPlugin = (hooks) => defineBackendPlugin({
259
188
  "Unauthorized: Cannot update post"
260
189
  );
261
190
  }
262
- const { tags, slug: rawSlug, ...restPostData } = ctx.body;
263
- const tagNames = tags || [];
191
+ const {
192
+ tags,
193
+ slug: rawSlug,
194
+ createdAt: _ca,
195
+ updatedAt: _ua,
196
+ ...restPostData
197
+ } = ctx.body;
264
198
  const slugified = rawSlug ? slugify(rawSlug) : void 0;
265
199
  if (rawSlug && !slugified) {
266
200
  throw ctx.error(400, {
267
201
  message: "Invalid slug: must contain at least one alphanumeric character"
268
202
  });
269
203
  }
270
- const postData = {
204
+ const updated = await updatePost(adapter, ctx.params.id, {
271
205
  ...restPostData,
272
- ...slugified ? { slug: slugified } : {}
273
- };
274
- const updated = await adapter.transaction(async (tx) => {
275
- const existingPostTags = await tx.findMany({
276
- model: "postTag",
277
- where: [
278
- {
279
- field: "postId",
280
- value: ctx.params.id,
281
- operator: "eq"
282
- }
283
- ]
284
- });
285
- const updatedPost = await tx.update({
286
- model: "post",
287
- where: [{ field: "id", value: ctx.params.id }],
288
- update: {
289
- ...postData,
290
- updatedAt: /* @__PURE__ */ new Date()
291
- }
292
- });
293
- if (!updatedPost) {
294
- throw ctx.error(404, {
295
- message: "Post not found"
296
- });
297
- }
298
- for (const postTag of existingPostTags) {
299
- await tx.delete({
300
- model: "postTag",
301
- where: [
302
- {
303
- field: "postId",
304
- value: postTag.postId,
305
- operator: "eq"
306
- },
307
- {
308
- field: "tagId",
309
- value: postTag.tagId,
310
- operator: "eq"
311
- }
312
- ]
313
- });
314
- }
315
- if (tagNames.length > 0) {
316
- const createdTags = await findOrCreateTags(tagNames);
317
- for (const tag of createdTags) {
318
- await tx.create({
319
- model: "postTag",
320
- data: {
321
- postId: ctx.params.id,
322
- tagId: tag.id
323
- }
324
- });
325
- }
326
- updatedPost.tags = createdTags.map((tag) => ({ ...tag }));
327
- } else {
328
- updatedPost.tags = [];
329
- }
330
- return updatedPost;
206
+ ...slugified ? { slug: slugified } : {},
207
+ tags: tags ?? []
331
208
  });
209
+ if (!updated) {
210
+ throw ctx.error(404, { message: "Post not found" });
211
+ }
332
212
  if (hooks?.onPostUpdated) {
333
213
  await hooks.onPostUpdated(updated, context);
334
214
  }
@@ -341,7 +221,7 @@ const blogBackendPlugin = (hooks) => defineBackendPlugin({
341
221
  }
342
222
  }
343
223
  );
344
- const deletePost = createEndpoint(
224
+ const deletePost$1 = createEndpoint(
345
225
  "/posts/:id",
346
226
  {
347
227
  method: "DELETE"
@@ -359,10 +239,7 @@ const blogBackendPlugin = (hooks) => defineBackendPlugin({
359
239
  "Unauthorized: Cannot delete post"
360
240
  );
361
241
  }
362
- await adapter.delete({
363
- model: "post",
364
- where: [{ field: "id", value: ctx.params.id }]
365
- });
242
+ await deletePost(adapter, ctx.params.id);
366
243
  if (hooks?.onPostDeleted) {
367
244
  await hooks.onPostDeleted(ctx.params.id, context);
368
245
  }
@@ -493,9 +370,9 @@ const blogBackendPlugin = (hooks) => defineBackendPlugin({
493
370
  );
494
371
  return {
495
372
  listPosts,
496
- createPost,
497
- updatePost,
498
- deletePost,
373
+ createPost: createPost$1,
374
+ updatePost: updatePost$1,
375
+ deletePost: deletePost$1,
499
376
  getNextPreviousPosts,
500
377
  listTags
501
378
  };
@@ -2,6 +2,7 @@
2
2
 
3
3
  const plugin = require('../../../packages/stack/src/plugins/blog/api/plugin.cjs');
4
4
  const getters = require('../../../packages/stack/src/plugins/blog/api/getters.cjs');
5
+ const mutations = require('../../../packages/stack/src/plugins/blog/api/mutations.cjs');
5
6
  const serializers = require('../../../packages/stack/src/plugins/blog/api/serializers.cjs');
6
7
  const queryKeyDefs = require('../../../packages/stack/src/plugins/blog/api/query-key-defs.cjs');
7
8
  const plugins_blog_queryKeys = require('../query-keys.cjs');
@@ -14,6 +15,9 @@ exports.blogBackendPlugin = plugin.blogBackendPlugin;
14
15
  exports.getAllPosts = getters.getAllPosts;
15
16
  exports.getAllTags = getters.getAllTags;
16
17
  exports.getPostBySlug = getters.getPostBySlug;
18
+ exports.createPost = mutations.createPost;
19
+ exports.deletePost = mutations.deletePost;
20
+ exports.updatePost = mutations.updatePost;
17
21
  exports.serializePost = serializers.serializePost;
18
22
  exports.serializeTag = serializers.serializeTag;
19
23
  exports.BLOG_QUERY_KEYS = queryKeyDefs.BLOG_QUERY_KEYS;
@@ -1,4 +1,4 @@
1
- export { B as BLOG_QUERY_KEYS, h as BlogApiContext, k as BlogApiRouter, i as BlogBackendHooks, e as BlogRouteKey, N as NextPreviousPostsQuerySchema, P as PostListParams, f as PostListQuerySchema, c as PostListResult, j as blogBackendPlugin, d as createBlogQueryKeys, g as getAllPosts, b as getAllTags, a as getPostBySlug } from '../../../shared/stack.DEW8EtFu.cjs';
1
+ export { B as BLOG_QUERY_KEYS, j as BlogApiContext, m as BlogApiRouter, k as BlogBackendHooks, h as BlogRouteKey, C as CreatePostInput, N as NextPreviousPostsQuerySchema, P as PostListParams, i as PostListQuerySchema, c as PostListResult, U as UpdatePostInput, l as blogBackendPlugin, f as createBlogQueryKeys, d as createPost, e as deletePost, g as getAllPosts, b as getAllTags, a as getPostBySlug, u as updatePost } from '../../../shared/stack.CntKf20s.cjs';
2
2
  import { P as Post, T as Tag, S as SerializedPost, a as SerializedTag } from '../../../shared/stack.Sod_PZhB.cjs';
3
3
  import '@tanstack/react-query';
4
4
  import '@btst/stack/plugins/client';
@@ -1,4 +1,4 @@
1
- export { B as BLOG_QUERY_KEYS, h as BlogApiContext, k as BlogApiRouter, i as BlogBackendHooks, e as BlogRouteKey, N as NextPreviousPostsQuerySchema, P as PostListParams, f as PostListQuerySchema, c as PostListResult, j as blogBackendPlugin, d as createBlogQueryKeys, g as getAllPosts, b as getAllTags, a as getPostBySlug } from '../../../shared/stack.DvMUCTTl.mjs';
1
+ export { B as BLOG_QUERY_KEYS, j as BlogApiContext, m as BlogApiRouter, k as BlogBackendHooks, h as BlogRouteKey, C as CreatePostInput, N as NextPreviousPostsQuerySchema, P as PostListParams, i as PostListQuerySchema, c as PostListResult, U as UpdatePostInput, l as blogBackendPlugin, f as createBlogQueryKeys, d as createPost, e as deletePost, g as getAllPosts, b as getAllTags, a as getPostBySlug, u as updatePost } from '../../../shared/stack.CLrGRIj0.mjs';
2
2
  import { P as Post, T as Tag, S as SerializedPost, a as SerializedTag } from '../../../shared/stack.Sod_PZhB.mjs';
3
3
  import '@tanstack/react-query';
4
4
  import '@btst/stack/plugins/client';
@@ -1,4 +1,4 @@
1
- export { B as BLOG_QUERY_KEYS, h as BlogApiContext, k as BlogApiRouter, i as BlogBackendHooks, e as BlogRouteKey, N as NextPreviousPostsQuerySchema, P as PostListParams, f as PostListQuerySchema, c as PostListResult, j as blogBackendPlugin, d as createBlogQueryKeys, g as getAllPosts, b as getAllTags, a as getPostBySlug } from '../../../shared/stack.qta0-CPq.js';
1
+ export { B as BLOG_QUERY_KEYS, j as BlogApiContext, m as BlogApiRouter, k as BlogBackendHooks, h as BlogRouteKey, C as CreatePostInput, N as NextPreviousPostsQuerySchema, P as PostListParams, i as PostListQuerySchema, c as PostListResult, U as UpdatePostInput, l as blogBackendPlugin, f as createBlogQueryKeys, d as createPost, e as deletePost, g as getAllPosts, b as getAllTags, a as getPostBySlug, u as updatePost } from '../../../shared/stack.BQSy-NDc.js';
2
2
  import { P as Post, T as Tag, S as SerializedPost, a as SerializedTag } from '../../../shared/stack.Sod_PZhB.js';
3
3
  import '@tanstack/react-query';
4
4
  import '@btst/stack/plugins/client';
@@ -1,5 +1,6 @@
1
1
  export { NextPreviousPostsQuerySchema, PostListQuerySchema, blogBackendPlugin } from '../../../packages/stack/src/plugins/blog/api/plugin.mjs';
2
2
  export { getAllPosts, getAllTags, getPostBySlug } from '../../../packages/stack/src/plugins/blog/api/getters.mjs';
3
+ export { createPost, deletePost, updatePost } from '../../../packages/stack/src/plugins/blog/api/mutations.mjs';
3
4
  export { serializePost, serializeTag } from '../../../packages/stack/src/plugins/blog/api/serializers.mjs';
4
5
  export { BLOG_QUERY_KEYS } from '../../../packages/stack/src/plugins/blog/api/query-key-defs.mjs';
5
6
  export { createBlogQueryKeys } from '../query-keys.mjs';
@@ -1,5 +1,5 @@
1
1
  import '@tanstack/react-query';
2
- export { d as createBlogQueryKeys } from '../../shared/stack.DEW8EtFu.cjs';
2
+ export { f as createBlogQueryKeys } from '../../shared/stack.CntKf20s.cjs';
3
3
  import '@btst/stack/plugins/client';
4
4
  import '../../shared/stack.Sod_PZhB.cjs';
5
5
  import '@btst/stack/plugins/api';
@@ -1,5 +1,5 @@
1
1
  import '@tanstack/react-query';
2
- export { d as createBlogQueryKeys } from '../../shared/stack.DvMUCTTl.mjs';
2
+ export { f as createBlogQueryKeys } from '../../shared/stack.CLrGRIj0.mjs';
3
3
  import '@btst/stack/plugins/client';
4
4
  import '../../shared/stack.Sod_PZhB.mjs';
5
5
  import '@btst/stack/plugins/api';
@@ -1,5 +1,5 @@
1
1
  import '@tanstack/react-query';
2
- export { d as createBlogQueryKeys } from '../../shared/stack.qta0-CPq.js';
2
+ export { f as createBlogQueryKeys } from '../../shared/stack.BQSy-NDc.js';
3
3
  import '@btst/stack/plugins/client';
4
4
  import '../../shared/stack.Sod_PZhB.js';
5
5
  import '@btst/stack/plugins/api';
@@ -1,4 +1,4 @@
1
- export { B as BoardListResult, C as CreateKanbanTaskInput, i as KANBAN_QUERY_KEYS, b as KanbanApiContext, K as KanbanApiRouter, c as KanbanBackendHooks, a as KanbanRouteKey, e as createKanbanTask, f as findOrCreateKanbanBoard, g as getAllBoards, d as getBoardById, h as getKanbanColumnsByBoardId, k as kanbanBackendPlugin } from '../../../shared/stack.BOokfhZD.cjs';
1
+ export { B as BoardListResult, C as CreateKanbanTaskInput, i as KANBAN_QUERY_KEYS, b as KanbanApiContext, K as KanbanApiRouter, c as KanbanBackendHooks, a as KanbanRouteKey, e as createKanbanTask, f as findOrCreateKanbanBoard, g as getAllBoards, d as getBoardById, h as getKanbanColumnsByBoardId, k as kanbanBackendPlugin } from '../../../shared/stack.eq5eg1yt.cjs';
2
2
  import { B as BoardWithColumns, S as SerializedBoardWithColumns, C as ColumnWithTasks, a as SerializedColumn, T as Task, b as SerializedTask } from '../../../shared/stack.DJaKVY7v.cjs';
3
3
  import '@btst/stack/plugins/api';
4
4
  import '@btst/db';
@@ -1,4 +1,4 @@
1
- export { B as BoardListResult, C as CreateKanbanTaskInput, i as KANBAN_QUERY_KEYS, b as KanbanApiContext, K as KanbanApiRouter, c as KanbanBackendHooks, a as KanbanRouteKey, e as createKanbanTask, f as findOrCreateKanbanBoard, g as getAllBoards, d as getBoardById, h as getKanbanColumnsByBoardId, k as kanbanBackendPlugin } from '../../../shared/stack.CWxAl9K3.mjs';
1
+ export { B as BoardListResult, C as CreateKanbanTaskInput, i as KANBAN_QUERY_KEYS, b as KanbanApiContext, K as KanbanApiRouter, c as KanbanBackendHooks, a as KanbanRouteKey, e as createKanbanTask, f as findOrCreateKanbanBoard, g as getAllBoards, d as getBoardById, h as getKanbanColumnsByBoardId, k as kanbanBackendPlugin } from '../../../shared/stack.Dj04W2c3.mjs';
2
2
  import { B as BoardWithColumns, S as SerializedBoardWithColumns, C as ColumnWithTasks, a as SerializedColumn, T as Task, b as SerializedTask } from '../../../shared/stack.DJaKVY7v.mjs';
3
3
  import '@btst/stack/plugins/api';
4
4
  import '@btst/db';
@@ -1,4 +1,4 @@
1
- export { B as BoardListResult, C as CreateKanbanTaskInput, i as KANBAN_QUERY_KEYS, b as KanbanApiContext, K as KanbanApiRouter, c as KanbanBackendHooks, a as KanbanRouteKey, e as createKanbanTask, f as findOrCreateKanbanBoard, g as getAllBoards, d as getBoardById, h as getKanbanColumnsByBoardId, k as kanbanBackendPlugin } from '../../../shared/stack.BvCR4-9H.js';
1
+ export { B as BoardListResult, C as CreateKanbanTaskInput, i as KANBAN_QUERY_KEYS, b as KanbanApiContext, K as KanbanApiRouter, c as KanbanBackendHooks, a as KanbanRouteKey, e as createKanbanTask, f as findOrCreateKanbanBoard, g as getAllBoards, d as getBoardById, h as getKanbanColumnsByBoardId, k as kanbanBackendPlugin } from '../../../shared/stack.CMbX8Q5C.js';
2
2
  import { B as BoardWithColumns, S as SerializedBoardWithColumns, C as ColumnWithTasks, a as SerializedColumn, T as Task, b as SerializedTask } from '../../../shared/stack.DJaKVY7v.js';
3
3
  import '@btst/stack/plugins/api';
4
4
  import '@btst/db';
@@ -1,5 +1,5 @@
1
1
  import * as _tanstack_react_query from '@tanstack/react-query';
2
- import { K as KanbanApiRouter, j as BoardsListDiscriminator } from '../../shared/stack.BOokfhZD.cjs';
2
+ import { K as KanbanApiRouter, j as BoardsListDiscriminator } from '../../shared/stack.eq5eg1yt.cjs';
3
3
  import { createApiClient } from '@btst/stack/plugins/client';
4
4
  import { S as SerializedBoardWithColumns } from '../../shared/stack.DJaKVY7v.cjs';
5
5
  import '@btst/stack/plugins/api';
@@ -1,5 +1,5 @@
1
1
  import * as _tanstack_react_query from '@tanstack/react-query';
2
- import { K as KanbanApiRouter, j as BoardsListDiscriminator } from '../../shared/stack.CWxAl9K3.mjs';
2
+ import { K as KanbanApiRouter, j as BoardsListDiscriminator } from '../../shared/stack.Dj04W2c3.mjs';
3
3
  import { createApiClient } from '@btst/stack/plugins/client';
4
4
  import { S as SerializedBoardWithColumns } from '../../shared/stack.DJaKVY7v.mjs';
5
5
  import '@btst/stack/plugins/api';
@@ -1,5 +1,5 @@
1
1
  import * as _tanstack_react_query from '@tanstack/react-query';
2
- import { K as KanbanApiRouter, j as BoardsListDiscriminator } from '../../shared/stack.BvCR4-9H.js';
2
+ import { K as KanbanApiRouter, j as BoardsListDiscriminator } from '../../shared/stack.CMbX8Q5C.js';
3
3
  import { createApiClient } from '@btst/stack/plugins/client';
4
4
  import { S as SerializedBoardWithColumns } from '../../shared/stack.DJaKVY7v.js';
5
5
  import '@btst/stack/plugins/api';
@@ -67,6 +67,86 @@ declare function getPostBySlug(adapter: DBAdapter, slug: string): Promise<(Post
67
67
  */
68
68
  declare function getAllTags(adapter: DBAdapter): Promise<Tag[]>;
69
69
 
70
+ type TagInput = {
71
+ name: string;
72
+ } | {
73
+ id: string;
74
+ name: string;
75
+ slug: string;
76
+ };
77
+ /**
78
+ * Input for creating a new blog post.
79
+ * `slug` must already be slugified by the caller.
80
+ */
81
+ interface CreatePostInput {
82
+ title: string;
83
+ content: string;
84
+ excerpt: string;
85
+ /** Pre-slugified URL slug — use {@link slugify} before passing. */
86
+ slug: string;
87
+ image?: string;
88
+ published?: boolean;
89
+ publishedAt?: Date;
90
+ createdAt?: Date;
91
+ updatedAt?: Date;
92
+ tags?: TagInput[];
93
+ }
94
+ /**
95
+ * Input for updating an existing blog post.
96
+ * If `slug` is provided it must already be slugified by the caller.
97
+ */
98
+ interface UpdatePostInput {
99
+ title?: string;
100
+ content?: string;
101
+ excerpt?: string;
102
+ /** Pre-slugified URL slug — use {@link slugify} before passing. */
103
+ slug?: string;
104
+ image?: string;
105
+ published?: boolean;
106
+ publishedAt?: Date;
107
+ createdAt?: Date;
108
+ updatedAt?: Date;
109
+ tags?: TagInput[];
110
+ }
111
+ /**
112
+ * Create a new blog post with optional tag associations.
113
+ * Pure DB function — no hooks, no HTTP context. Safe for server-side and SSG use.
114
+ *
115
+ * @remarks **Security:** Authorization hooks (e.g. `onBeforeCreatePost`) are NOT
116
+ * called. The caller is responsible for any access-control checks before
117
+ * invoking this function.
118
+ *
119
+ * @param adapter - The database adapter
120
+ * @param input - Post data; `slug` must be pre-slugified
121
+ */
122
+ declare function createPost(adapter: DBAdapter, input: CreatePostInput): Promise<Post>;
123
+ /**
124
+ * Update an existing blog post and reconcile its tag associations.
125
+ * Returns `null` if no post with the given `id` exists.
126
+ * Pure DB function — no hooks, no HTTP context. Safe for server-side use.
127
+ *
128
+ * @remarks **Security:** Authorization hooks (e.g. `onBeforeUpdatePost`) are NOT
129
+ * called. The caller is responsible for any access-control checks before
130
+ * invoking this function.
131
+ *
132
+ * @param adapter - The database adapter
133
+ * @param id - The post ID to update
134
+ * @param input - Partial post data to apply; `slug` must be pre-slugified if provided
135
+ */
136
+ declare function updatePost(adapter: DBAdapter, id: string, input: UpdatePostInput): Promise<Post | null>;
137
+ /**
138
+ * Delete a blog post by ID.
139
+ * Pure DB function — no hooks, no HTTP context. Safe for server-side use.
140
+ *
141
+ * @remarks **Security:** Authorization hooks (e.g. `onBeforeDeletePost`) are NOT
142
+ * called. The caller is responsible for any access-control checks before
143
+ * invoking this function.
144
+ *
145
+ * @param adapter - The database adapter
146
+ * @param id - The post ID to delete
147
+ */
148
+ declare function deletePost(adapter: DBAdapter, id: string): Promise<void>;
149
+
70
150
  /**
71
151
  * Route keys for the blog plugin — matches the keys returned by
72
152
  * `stackClient.router.getRoute(path).routeKey`.
@@ -366,6 +446,9 @@ declare const blogBackendPlugin: (hooks?: BlogBackendHooks) => _btst_stack_plugi
366
446
  }) | null>;
367
447
  getAllTags: () => Promise<Tag[]>;
368
448
  prefetchForRoute: BlogPrefetchForRoute;
449
+ createPost: (input: CreatePostInput) => Promise<Post>;
450
+ updatePost: (id: string, input: UpdatePostInput) => Promise<Post | null>;
451
+ deletePost: (id: string) => Promise<void>;
369
452
  }>;
370
453
  type BlogApiRouter = ReturnType<ReturnType<typeof blogBackendPlugin>["routes"]>;
371
454
 
@@ -476,5 +559,5 @@ declare function createBlogQueryKeys(client: ReturnType<typeof createApiClient<B
476
559
  };
477
560
  };
478
561
 
479
- export { BLOG_QUERY_KEYS as B, NextPreviousPostsQuerySchema as N, getPostBySlug as a, getAllTags as b, createBlogQueryKeys as d, PostListQuerySchema as f, getAllPosts as g, blogBackendPlugin as j };
480
- export type { PostListParams as P, PostListResult as c, BlogRouteKey as e, BlogApiContext as h, BlogBackendHooks as i, BlogApiRouter as k };
562
+ export { BLOG_QUERY_KEYS as B, NextPreviousPostsQuerySchema as N, getPostBySlug as a, getAllTags as b, createPost as d, deletePost as e, createBlogQueryKeys as f, getAllPosts as g, PostListQuerySchema as i, blogBackendPlugin as l, updatePost as u };
563
+ export type { CreatePostInput as C, PostListParams as P, UpdatePostInput as U, PostListResult as c, BlogRouteKey as h, BlogApiContext as j, BlogBackendHooks as k, BlogApiRouter as m };
@@ -67,6 +67,86 @@ declare function getPostBySlug(adapter: DBAdapter, slug: string): Promise<(Post
67
67
  */
68
68
  declare function getAllTags(adapter: DBAdapter): Promise<Tag[]>;
69
69
 
70
+ type TagInput = {
71
+ name: string;
72
+ } | {
73
+ id: string;
74
+ name: string;
75
+ slug: string;
76
+ };
77
+ /**
78
+ * Input for creating a new blog post.
79
+ * `slug` must already be slugified by the caller.
80
+ */
81
+ interface CreatePostInput {
82
+ title: string;
83
+ content: string;
84
+ excerpt: string;
85
+ /** Pre-slugified URL slug — use {@link slugify} before passing. */
86
+ slug: string;
87
+ image?: string;
88
+ published?: boolean;
89
+ publishedAt?: Date;
90
+ createdAt?: Date;
91
+ updatedAt?: Date;
92
+ tags?: TagInput[];
93
+ }
94
+ /**
95
+ * Input for updating an existing blog post.
96
+ * If `slug` is provided it must already be slugified by the caller.
97
+ */
98
+ interface UpdatePostInput {
99
+ title?: string;
100
+ content?: string;
101
+ excerpt?: string;
102
+ /** Pre-slugified URL slug — use {@link slugify} before passing. */
103
+ slug?: string;
104
+ image?: string;
105
+ published?: boolean;
106
+ publishedAt?: Date;
107
+ createdAt?: Date;
108
+ updatedAt?: Date;
109
+ tags?: TagInput[];
110
+ }
111
+ /**
112
+ * Create a new blog post with optional tag associations.
113
+ * Pure DB function — no hooks, no HTTP context. Safe for server-side and SSG use.
114
+ *
115
+ * @remarks **Security:** Authorization hooks (e.g. `onBeforeCreatePost`) are NOT
116
+ * called. The caller is responsible for any access-control checks before
117
+ * invoking this function.
118
+ *
119
+ * @param adapter - The database adapter
120
+ * @param input - Post data; `slug` must be pre-slugified
121
+ */
122
+ declare function createPost(adapter: DBAdapter, input: CreatePostInput): Promise<Post>;
123
+ /**
124
+ * Update an existing blog post and reconcile its tag associations.
125
+ * Returns `null` if no post with the given `id` exists.
126
+ * Pure DB function — no hooks, no HTTP context. Safe for server-side use.
127
+ *
128
+ * @remarks **Security:** Authorization hooks (e.g. `onBeforeUpdatePost`) are NOT
129
+ * called. The caller is responsible for any access-control checks before
130
+ * invoking this function.
131
+ *
132
+ * @param adapter - The database adapter
133
+ * @param id - The post ID to update
134
+ * @param input - Partial post data to apply; `slug` must be pre-slugified if provided
135
+ */
136
+ declare function updatePost(adapter: DBAdapter, id: string, input: UpdatePostInput): Promise<Post | null>;
137
+ /**
138
+ * Delete a blog post by ID.
139
+ * Pure DB function — no hooks, no HTTP context. Safe for server-side use.
140
+ *
141
+ * @remarks **Security:** Authorization hooks (e.g. `onBeforeDeletePost`) are NOT
142
+ * called. The caller is responsible for any access-control checks before
143
+ * invoking this function.
144
+ *
145
+ * @param adapter - The database adapter
146
+ * @param id - The post ID to delete
147
+ */
148
+ declare function deletePost(adapter: DBAdapter, id: string): Promise<void>;
149
+
70
150
  /**
71
151
  * Route keys for the blog plugin — matches the keys returned by
72
152
  * `stackClient.router.getRoute(path).routeKey`.
@@ -366,6 +446,9 @@ declare const blogBackendPlugin: (hooks?: BlogBackendHooks) => _btst_stack_plugi
366
446
  }) | null>;
367
447
  getAllTags: () => Promise<Tag[]>;
368
448
  prefetchForRoute: BlogPrefetchForRoute;
449
+ createPost: (input: CreatePostInput) => Promise<Post>;
450
+ updatePost: (id: string, input: UpdatePostInput) => Promise<Post | null>;
451
+ deletePost: (id: string) => Promise<void>;
369
452
  }>;
370
453
  type BlogApiRouter = ReturnType<ReturnType<typeof blogBackendPlugin>["routes"]>;
371
454
 
@@ -476,5 +559,5 @@ declare function createBlogQueryKeys(client: ReturnType<typeof createApiClient<B
476
559
  };
477
560
  };
478
561
 
479
- export { BLOG_QUERY_KEYS as B, NextPreviousPostsQuerySchema as N, getPostBySlug as a, getAllTags as b, createBlogQueryKeys as d, PostListQuerySchema as f, getAllPosts as g, blogBackendPlugin as j };
480
- export type { PostListParams as P, PostListResult as c, BlogRouteKey as e, BlogApiContext as h, BlogBackendHooks as i, BlogApiRouter as k };
562
+ export { BLOG_QUERY_KEYS as B, NextPreviousPostsQuerySchema as N, getPostBySlug as a, getAllTags as b, createPost as d, deletePost as e, createBlogQueryKeys as f, getAllPosts as g, PostListQuerySchema as i, blogBackendPlugin as l, updatePost as u };
563
+ export type { CreatePostInput as C, PostListParams as P, UpdatePostInput as U, PostListResult as c, BlogRouteKey as h, BlogApiContext as j, BlogBackendHooks as k, BlogApiRouter as m };