@newcms/database 0.1.1 → 0.2.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.
Files changed (76) hide show
  1. package/dist/index.cjs +1527 -0
  2. package/dist/index.cjs.map +1 -0
  3. package/dist/index.d.cts +2695 -0
  4. package/dist/index.d.ts +2695 -14
  5. package/dist/index.js +1528 -8
  6. package/dist/index.js.map +1 -1
  7. package/package.json +8 -8
  8. package/dist/cache/index.d.ts +0 -3
  9. package/dist/cache/index.d.ts.map +0 -1
  10. package/dist/cache/index.js +0 -2
  11. package/dist/cache/index.js.map +0 -1
  12. package/dist/cache/object-cache.d.ts +0 -139
  13. package/dist/cache/object-cache.d.ts.map +0 -1
  14. package/dist/cache/object-cache.js +0 -321
  15. package/dist/cache/object-cache.js.map +0 -1
  16. package/dist/connection.d.ts +0 -18
  17. package/dist/connection.d.ts.map +0 -1
  18. package/dist/connection.js +0 -32
  19. package/dist/connection.js.map +0 -1
  20. package/dist/index.d.ts.map +0 -1
  21. package/dist/repositories/meta-repository.d.ts +0 -71
  22. package/dist/repositories/meta-repository.d.ts.map +0 -1
  23. package/dist/repositories/meta-repository.js +0 -176
  24. package/dist/repositories/meta-repository.js.map +0 -1
  25. package/dist/repositories/options-repository.d.ts +0 -59
  26. package/dist/repositories/options-repository.d.ts.map +0 -1
  27. package/dist/repositories/options-repository.js +0 -222
  28. package/dist/repositories/options-repository.js.map +0 -1
  29. package/dist/repositories/post-repository.d.ts +0 -121
  30. package/dist/repositories/post-repository.d.ts.map +0 -1
  31. package/dist/repositories/post-repository.js +0 -241
  32. package/dist/repositories/post-repository.js.map +0 -1
  33. package/dist/repositories/revision-repository.d.ts +0 -50
  34. package/dist/repositories/revision-repository.d.ts.map +0 -1
  35. package/dist/repositories/revision-repository.js +0 -149
  36. package/dist/repositories/revision-repository.js.map +0 -1
  37. package/dist/repositories/taxonomy-repository.d.ts +0 -63
  38. package/dist/repositories/taxonomy-repository.d.ts.map +0 -1
  39. package/dist/repositories/taxonomy-repository.js +0 -268
  40. package/dist/repositories/taxonomy-repository.js.map +0 -1
  41. package/dist/schema/comments.d.ts +0 -369
  42. package/dist/schema/comments.d.ts.map +0 -1
  43. package/dist/schema/comments.js +0 -47
  44. package/dist/schema/comments.js.map +0 -1
  45. package/dist/schema/index.d.ts +0 -9
  46. package/dist/schema/index.d.ts.map +0 -1
  47. package/dist/schema/index.js +0 -9
  48. package/dist/schema/index.js.map +0 -1
  49. package/dist/schema/links.d.ts +0 -245
  50. package/dist/schema/links.d.ts.map +0 -1
  51. package/dist/schema/links.js +0 -17
  52. package/dist/schema/links.js.map +0 -1
  53. package/dist/schema/options.d.ts +0 -95
  54. package/dist/schema/options.d.ts.map +0 -1
  55. package/dist/schema/options.js +0 -12
  56. package/dist/schema/options.js.map +0 -1
  57. package/dist/schema/posts.d.ts +0 -509
  58. package/dist/schema/posts.d.ts.map +0 -1
  59. package/dist/schema/posts.js +0 -51
  60. package/dist/schema/posts.js.map +0 -1
  61. package/dist/schema/scheduled-events.d.ts +0 -156
  62. package/dist/schema/scheduled-events.d.ts.map +0 -1
  63. package/dist/schema/scheduled-events.js +0 -22
  64. package/dist/schema/scheduled-events.js.map +0 -1
  65. package/dist/schema/sessions.d.ts +0 -157
  66. package/dist/schema/sessions.d.ts.map +0 -1
  67. package/dist/schema/sessions.js +0 -26
  68. package/dist/schema/sessions.js.map +0 -1
  69. package/dist/schema/terms.d.ts +0 -343
  70. package/dist/schema/terms.d.ts.map +0 -1
  71. package/dist/schema/terms.js +0 -46
  72. package/dist/schema/terms.js.map +0 -1
  73. package/dist/schema/users.d.ts +0 -288
  74. package/dist/schema/users.d.ts.map +0 -1
  75. package/dist/schema/users.js +0 -30
  76. package/dist/schema/users.js.map +0 -1
package/dist/index.cjs ADDED
@@ -0,0 +1,1527 @@
1
+ "use strict";
2
+ var __create = Object.create;
3
+ var __defProp = Object.defineProperty;
4
+ var __getOwnPropDesc = Object.getOwnPropertyDescriptor;
5
+ var __getOwnPropNames = Object.getOwnPropertyNames;
6
+ var __getProtoOf = Object.getPrototypeOf;
7
+ var __hasOwnProp = Object.prototype.hasOwnProperty;
8
+ var __export = (target, all) => {
9
+ for (var name in all)
10
+ __defProp(target, name, { get: all[name], enumerable: true });
11
+ };
12
+ var __copyProps = (to, from, except, desc2) => {
13
+ if (from && typeof from === "object" || typeof from === "function") {
14
+ for (let key of __getOwnPropNames(from))
15
+ if (!__hasOwnProp.call(to, key) && key !== except)
16
+ __defProp(to, key, { get: () => from[key], enumerable: !(desc2 = __getOwnPropDesc(from, key)) || desc2.enumerable });
17
+ }
18
+ return to;
19
+ };
20
+ var __toESM = (mod, isNodeMode, target) => (target = mod != null ? __create(__getProtoOf(mod)) : {}, __copyProps(
21
+ // If the importer is in node compatibility mode or this is not an ESM
22
+ // file that has been converted to a CommonJS file using a Babel-
23
+ // compatible transform (i.e. "__esModule" has not been set), then set
24
+ // "default" to the CommonJS "module.exports" for node compatibility.
25
+ isNodeMode || !mod || !mod.__esModule ? __defProp(target, "default", { value: mod, enumerable: true }) : target,
26
+ mod
27
+ ));
28
+ var __toCommonJS = (mod) => __copyProps(__defProp({}, "__esModule", { value: true }), mod);
29
+
30
+ // src/index.ts
31
+ var index_exports = {};
32
+ __export(index_exports, {
33
+ MetaRepository: () => MetaRepository,
34
+ ObjectCache: () => ObjectCache,
35
+ OptionsRepository: () => OptionsRepository,
36
+ PostRepository: () => PostRepository,
37
+ RevisionRepository: () => RevisionRepository,
38
+ TaxonomyRepository: () => TaxonomyRepository,
39
+ commentmeta: () => commentmeta,
40
+ comments: () => comments,
41
+ createConnection: () => createConnection,
42
+ links: () => links,
43
+ options: () => options,
44
+ postmeta: () => postmeta,
45
+ posts: () => posts,
46
+ scheduledEvents: () => scheduledEvents,
47
+ sessions: () => sessions,
48
+ termRelationships: () => termRelationships,
49
+ termTaxonomy: () => termTaxonomy,
50
+ termmeta: () => termmeta,
51
+ terms: () => terms,
52
+ usermeta: () => usermeta,
53
+ users: () => users
54
+ });
55
+ module.exports = __toCommonJS(index_exports);
56
+
57
+ // src/connection.ts
58
+ var import_postgres_js = require("drizzle-orm/postgres-js");
59
+ var import_postgres = __toESM(require("postgres"), 1);
60
+
61
+ // src/schema/index.ts
62
+ var schema_exports = {};
63
+ __export(schema_exports, {
64
+ commentmeta: () => commentmeta,
65
+ comments: () => comments,
66
+ links: () => links,
67
+ options: () => options,
68
+ postmeta: () => postmeta,
69
+ posts: () => posts,
70
+ scheduledEvents: () => scheduledEvents,
71
+ sessions: () => sessions,
72
+ termRelationships: () => termRelationships,
73
+ termTaxonomy: () => termTaxonomy,
74
+ termmeta: () => termmeta,
75
+ terms: () => terms,
76
+ usermeta: () => usermeta,
77
+ users: () => users
78
+ });
79
+
80
+ // src/schema/posts.ts
81
+ var import_pg_core2 = require("drizzle-orm/pg-core");
82
+
83
+ // src/schema/users.ts
84
+ var import_pg_core = require("drizzle-orm/pg-core");
85
+ var users = (0, import_pg_core.pgTable)(
86
+ "users",
87
+ {
88
+ id: (0, import_pg_core.serial)("id").primaryKey(),
89
+ userLogin: (0, import_pg_core.varchar)("user_login", { length: 60 }).notNull().unique(),
90
+ userPass: (0, import_pg_core.varchar)("user_pass", { length: 255 }).notNull().default(""),
91
+ userNicename: (0, import_pg_core.varchar)("user_nicename", { length: 50 }).notNull().default(""),
92
+ userEmail: (0, import_pg_core.varchar)("user_email", { length: 100 }).notNull().unique(),
93
+ userUrl: (0, import_pg_core.varchar)("user_url", { length: 100 }).notNull().default(""),
94
+ userRegistered: (0, import_pg_core.timestamp)("user_registered", { withTimezone: true }).notNull().defaultNow(),
95
+ userActivationKey: (0, import_pg_core.varchar)("user_activation_key", { length: 255 }).notNull().default(""),
96
+ userStatus: (0, import_pg_core.varchar)("user_status", { length: 20 }).notNull().default("active"),
97
+ displayName: (0, import_pg_core.varchar)("display_name", { length: 250 }).notNull().default("")
98
+ },
99
+ (table) => [
100
+ (0, import_pg_core.index)("idx_user_login").on(table.userLogin),
101
+ (0, import_pg_core.index)("idx_user_nicename").on(table.userNicename),
102
+ (0, import_pg_core.index)("idx_user_email").on(table.userEmail)
103
+ ]
104
+ );
105
+ var usermeta = (0, import_pg_core.pgTable)(
106
+ "usermeta",
107
+ {
108
+ umetaId: (0, import_pg_core.serial)("umeta_id").primaryKey(),
109
+ userId: (0, import_pg_core.serial)("user_id").notNull().references(() => users.id, { onDelete: "cascade" }),
110
+ metaKey: (0, import_pg_core.varchar)("meta_key", { length: 255 }),
111
+ metaValue: (0, import_pg_core.text)("meta_value"),
112
+ metaValueJson: (0, import_pg_core.jsonb)("meta_value_json")
113
+ },
114
+ (table) => [
115
+ (0, import_pg_core.index)("idx_usermeta_user_id").on(table.userId),
116
+ (0, import_pg_core.index)("idx_usermeta_meta_key").on(table.metaKey)
117
+ ]
118
+ );
119
+
120
+ // src/schema/posts.ts
121
+ var posts = (0, import_pg_core2.pgTable)(
122
+ "posts",
123
+ {
124
+ id: (0, import_pg_core2.serial)("id").primaryKey(),
125
+ postAuthor: (0, import_pg_core2.bigint)("post_author", { mode: "number" }).notNull().default(0).references(() => users.id),
126
+ postDate: (0, import_pg_core2.timestamp)("post_date", { withTimezone: true }).notNull().defaultNow(),
127
+ postDateGmt: (0, import_pg_core2.timestamp)("post_date_gmt", { withTimezone: true }).notNull().defaultNow(),
128
+ postContent: (0, import_pg_core2.text)("post_content").notNull().default(""),
129
+ postTitle: (0, import_pg_core2.text)("post_title").notNull().default(""),
130
+ postExcerpt: (0, import_pg_core2.text)("post_excerpt").notNull().default(""),
131
+ postStatus: (0, import_pg_core2.varchar)("post_status", { length: 20 }).notNull().default("publish"),
132
+ commentStatus: (0, import_pg_core2.varchar)("comment_status", { length: 20 }).notNull().default("open"),
133
+ pingStatus: (0, import_pg_core2.varchar)("ping_status", { length: 20 }).notNull().default("open"),
134
+ postPassword: (0, import_pg_core2.varchar)("post_password", { length: 255 }).notNull().default(""),
135
+ postName: (0, import_pg_core2.varchar)("post_name", { length: 200 }).notNull().default(""),
136
+ toPing: (0, import_pg_core2.text)("to_ping").notNull().default(""),
137
+ pinged: (0, import_pg_core2.text)("pinged").notNull().default(""),
138
+ postModified: (0, import_pg_core2.timestamp)("post_modified", { withTimezone: true }).notNull().defaultNow(),
139
+ postModifiedGmt: (0, import_pg_core2.timestamp)("post_modified_gmt", { withTimezone: true }).notNull().defaultNow(),
140
+ postContentFiltered: (0, import_pg_core2.text)("post_content_filtered").notNull().default(""),
141
+ postParent: (0, import_pg_core2.bigint)("post_parent", { mode: "number" }).notNull().default(0),
142
+ guid: (0, import_pg_core2.varchar)("guid", { length: 255 }).notNull().default(""),
143
+ menuOrder: (0, import_pg_core2.bigint)("menu_order", { mode: "number" }).notNull().default(0),
144
+ postType: (0, import_pg_core2.varchar)("post_type", { length: 20 }).notNull().default("post"),
145
+ postMimeType: (0, import_pg_core2.varchar)("post_mime_type", { length: 100 }).notNull().default(""),
146
+ commentCount: (0, import_pg_core2.bigint)("comment_count", { mode: "number" }).notNull().default(0)
147
+ },
148
+ (table) => [
149
+ (0, import_pg_core2.index)("idx_post_name").on(table.postName),
150
+ (0, import_pg_core2.index)("idx_post_type_status_date").on(table.postType, table.postStatus, table.postDate),
151
+ (0, import_pg_core2.index)("idx_post_parent").on(table.postParent),
152
+ (0, import_pg_core2.index)("idx_post_author").on(table.postAuthor)
153
+ ]
154
+ );
155
+ var postmeta = (0, import_pg_core2.pgTable)(
156
+ "postmeta",
157
+ {
158
+ metaId: (0, import_pg_core2.serial)("meta_id").primaryKey(),
159
+ postId: (0, import_pg_core2.bigint)("post_id", { mode: "number" }).notNull().references(() => posts.id, { onDelete: "cascade" }),
160
+ metaKey: (0, import_pg_core2.varchar)("meta_key", { length: 255 }),
161
+ metaValue: (0, import_pg_core2.text)("meta_value"),
162
+ metaValueJson: (0, import_pg_core2.jsonb)("meta_value_json")
163
+ },
164
+ (table) => [
165
+ (0, import_pg_core2.index)("idx_postmeta_post_id").on(table.postId),
166
+ (0, import_pg_core2.index)("idx_postmeta_meta_key").on(table.metaKey),
167
+ (0, import_pg_core2.index)("idx_postmeta_post_key").on(table.postId, table.metaKey)
168
+ ]
169
+ );
170
+
171
+ // src/schema/comments.ts
172
+ var import_pg_core3 = require("drizzle-orm/pg-core");
173
+ var comments = (0, import_pg_core3.pgTable)(
174
+ "comments",
175
+ {
176
+ commentId: (0, import_pg_core3.serial)("comment_id").primaryKey(),
177
+ commentPostId: (0, import_pg_core3.bigint)("comment_post_id", { mode: "number" }).notNull().default(0).references(() => posts.id, { onDelete: "cascade" }),
178
+ commentAuthor: (0, import_pg_core3.text)("comment_author").notNull().default(""),
179
+ commentAuthorEmail: (0, import_pg_core3.varchar)("comment_author_email", { length: 100 }).notNull().default(""),
180
+ commentAuthorUrl: (0, import_pg_core3.varchar)("comment_author_url", { length: 200 }).notNull().default(""),
181
+ commentAuthorIp: (0, import_pg_core3.varchar)("comment_author_ip", { length: 100 }).notNull().default(""),
182
+ commentDate: (0, import_pg_core3.timestamp)("comment_date", { withTimezone: true }).notNull().defaultNow(),
183
+ commentDateGmt: (0, import_pg_core3.timestamp)("comment_date_gmt", { withTimezone: true }).notNull().defaultNow(),
184
+ commentContent: (0, import_pg_core3.text)("comment_content").notNull().default(""),
185
+ commentKarma: (0, import_pg_core3.bigint)("comment_karma", { mode: "number" }).notNull().default(0),
186
+ commentApproved: (0, import_pg_core3.varchar)("comment_approved", { length: 20 }).notNull().default("1"),
187
+ commentAgent: (0, import_pg_core3.varchar)("comment_agent", { length: 255 }).notNull().default(""),
188
+ commentType: (0, import_pg_core3.varchar)("comment_type", { length: 20 }).notNull().default("comment"),
189
+ commentParent: (0, import_pg_core3.bigint)("comment_parent", { mode: "number" }).notNull().default(0),
190
+ userId: (0, import_pg_core3.bigint)("user_id", { mode: "number" }).notNull().default(0).references(() => users.id)
191
+ },
192
+ (table) => [
193
+ (0, import_pg_core3.index)("idx_comment_post_id").on(table.commentPostId),
194
+ (0, import_pg_core3.index)("idx_comment_approved_date_gmt").on(table.commentApproved, table.commentDateGmt),
195
+ (0, import_pg_core3.index)("idx_comment_date_gmt").on(table.commentDateGmt),
196
+ (0, import_pg_core3.index)("idx_comment_parent").on(table.commentParent),
197
+ (0, import_pg_core3.index)("idx_comment_author_email").on(table.commentAuthorEmail)
198
+ ]
199
+ );
200
+ var commentmeta = (0, import_pg_core3.pgTable)(
201
+ "commentmeta",
202
+ {
203
+ metaId: (0, import_pg_core3.serial)("meta_id").primaryKey(),
204
+ commentId: (0, import_pg_core3.bigint)("comment_id", { mode: "number" }).notNull().references(() => comments.commentId, { onDelete: "cascade" }),
205
+ metaKey: (0, import_pg_core3.varchar)("meta_key", { length: 255 }),
206
+ metaValue: (0, import_pg_core3.text)("meta_value"),
207
+ metaValueJson: (0, import_pg_core3.jsonb)("meta_value_json")
208
+ },
209
+ (table) => [
210
+ (0, import_pg_core3.index)("idx_commentmeta_comment_id").on(table.commentId),
211
+ (0, import_pg_core3.index)("idx_commentmeta_meta_key").on(table.metaKey)
212
+ ]
213
+ );
214
+
215
+ // src/schema/terms.ts
216
+ var import_pg_core4 = require("drizzle-orm/pg-core");
217
+ var terms = (0, import_pg_core4.pgTable)(
218
+ "terms",
219
+ {
220
+ termId: (0, import_pg_core4.serial)("term_id").primaryKey(),
221
+ name: (0, import_pg_core4.varchar)("name", { length: 200 }).notNull().default(""),
222
+ slug: (0, import_pg_core4.varchar)("slug", { length: 200 }).notNull().default(""),
223
+ termGroup: (0, import_pg_core4.bigint)("term_group", { mode: "number" }).notNull().default(0)
224
+ },
225
+ (table) => [(0, import_pg_core4.index)("idx_term_slug").on(table.slug), (0, import_pg_core4.index)("idx_term_name").on(table.name)]
226
+ );
227
+ var termTaxonomy = (0, import_pg_core4.pgTable)(
228
+ "term_taxonomy",
229
+ {
230
+ termTaxonomyId: (0, import_pg_core4.serial)("term_taxonomy_id").primaryKey(),
231
+ termId: (0, import_pg_core4.bigint)("term_id", { mode: "number" }).notNull().references(() => terms.termId, { onDelete: "cascade" }),
232
+ taxonomy: (0, import_pg_core4.varchar)("taxonomy", { length: 32 }).notNull().default(""),
233
+ description: (0, import_pg_core4.text)("description").notNull().default(""),
234
+ parent: (0, import_pg_core4.bigint)("parent", { mode: "number" }).notNull().default(0),
235
+ count: (0, import_pg_core4.bigint)("count", { mode: "number" }).notNull().default(0)
236
+ },
237
+ (table) => [
238
+ (0, import_pg_core4.uniqueIndex)("idx_term_id_taxonomy").on(table.termId, table.taxonomy),
239
+ (0, import_pg_core4.index)("idx_taxonomy").on(table.taxonomy)
240
+ ]
241
+ );
242
+ var termRelationships = (0, import_pg_core4.pgTable)(
243
+ "term_relationships",
244
+ {
245
+ objectId: (0, import_pg_core4.bigint)("object_id", { mode: "number" }).notNull().references(() => posts.id, { onDelete: "cascade" }),
246
+ termTaxonomyId: (0, import_pg_core4.bigint)("term_taxonomy_id", { mode: "number" }).notNull().references(() => termTaxonomy.termTaxonomyId, { onDelete: "cascade" }),
247
+ termOrder: (0, import_pg_core4.bigint)("term_order", { mode: "number" }).notNull().default(0)
248
+ },
249
+ (table) => [
250
+ (0, import_pg_core4.primaryKey)({ columns: [table.objectId, table.termTaxonomyId] }),
251
+ (0, import_pg_core4.index)("idx_term_taxonomy_id").on(table.termTaxonomyId)
252
+ ]
253
+ );
254
+ var termmeta = (0, import_pg_core4.pgTable)(
255
+ "termmeta",
256
+ {
257
+ metaId: (0, import_pg_core4.serial)("meta_id").primaryKey(),
258
+ termId: (0, import_pg_core4.bigint)("term_id", { mode: "number" }).notNull().references(() => terms.termId, { onDelete: "cascade" }),
259
+ metaKey: (0, import_pg_core4.varchar)("meta_key", { length: 255 }),
260
+ metaValue: (0, import_pg_core4.text)("meta_value"),
261
+ metaValueJson: (0, import_pg_core4.jsonb)("meta_value_json")
262
+ },
263
+ (table) => [
264
+ (0, import_pg_core4.index)("idx_termmeta_term_id").on(table.termId),
265
+ (0, import_pg_core4.index)("idx_termmeta_meta_key").on(table.metaKey)
266
+ ]
267
+ );
268
+
269
+ // src/schema/options.ts
270
+ var import_pg_core5 = require("drizzle-orm/pg-core");
271
+ var options = (0, import_pg_core5.pgTable)(
272
+ "options",
273
+ {
274
+ optionId: (0, import_pg_core5.serial)("option_id").primaryKey(),
275
+ optionName: (0, import_pg_core5.varchar)("option_name", { length: 191 }).notNull().unique(),
276
+ optionValue: (0, import_pg_core5.text)("option_value").notNull().default(""),
277
+ optionValueJson: (0, import_pg_core5.jsonb)("option_value_json"),
278
+ autoload: (0, import_pg_core5.boolean)("autoload").notNull().default(true)
279
+ },
280
+ (table) => [
281
+ (0, import_pg_core5.uniqueIndex)("idx_option_name").on(table.optionName),
282
+ (0, import_pg_core5.index)("idx_autoload").on(table.autoload)
283
+ ]
284
+ );
285
+
286
+ // src/schema/links.ts
287
+ var import_pg_core6 = require("drizzle-orm/pg-core");
288
+ var links = (0, import_pg_core6.pgTable)(
289
+ "links",
290
+ {
291
+ linkId: (0, import_pg_core6.serial)("link_id").primaryKey(),
292
+ linkUrl: (0, import_pg_core6.varchar)("link_url", { length: 255 }).notNull().default(""),
293
+ linkName: (0, import_pg_core6.varchar)("link_name", { length: 255 }).notNull().default(""),
294
+ linkImage: (0, import_pg_core6.varchar)("link_image", { length: 255 }).notNull().default(""),
295
+ linkTarget: (0, import_pg_core6.varchar)("link_target", { length: 25 }).notNull().default(""),
296
+ linkDescription: (0, import_pg_core6.varchar)("link_description", { length: 255 }).notNull().default(""),
297
+ linkVisible: (0, import_pg_core6.varchar)("link_visible", { length: 20 }).notNull().default("Y"),
298
+ linkOwner: (0, import_pg_core6.bigint)("link_owner", { mode: "number" }).notNull().default(1),
299
+ linkRating: (0, import_pg_core6.bigint)("link_rating", { mode: "number" }).notNull().default(0),
300
+ linkUpdated: (0, import_pg_core6.timestamp)("link_updated", { withTimezone: true }).notNull().defaultNow(),
301
+ linkRel: (0, import_pg_core6.varchar)("link_rel", { length: 255 }).notNull().default(""),
302
+ linkNotes: (0, import_pg_core6.text)("link_notes").notNull().default(""),
303
+ linkRss: (0, import_pg_core6.varchar)("link_rss", { length: 255 }).notNull().default("")
304
+ },
305
+ (table) => [(0, import_pg_core6.index)("idx_link_visible").on(table.linkVisible)]
306
+ );
307
+
308
+ // src/schema/sessions.ts
309
+ var import_pg_core7 = require("drizzle-orm/pg-core");
310
+ var sessions = (0, import_pg_core7.pgTable)(
311
+ "sessions",
312
+ {
313
+ id: (0, import_pg_core7.serial)("id").primaryKey(),
314
+ userId: (0, import_pg_core7.bigint)("user_id", { mode: "number" }).notNull().references(() => users.id, { onDelete: "cascade" }),
315
+ tokenHash: (0, import_pg_core7.varchar)("token_hash", { length: 255 }).notNull().unique(),
316
+ createdAt: (0, import_pg_core7.timestamp)("created_at", { withTimezone: true }).notNull().defaultNow(),
317
+ expiresAt: (0, import_pg_core7.timestamp)("expires_at", { withTimezone: true }).notNull(),
318
+ ip: (0, import_pg_core7.varchar)("ip", { length: 45 }).notNull().default(""),
319
+ userAgent: (0, import_pg_core7.varchar)("user_agent", { length: 500 }).notNull().default(""),
320
+ data: (0, import_pg_core7.jsonb)("data")
321
+ },
322
+ (table) => [
323
+ (0, import_pg_core7.index)("idx_session_user_id").on(table.userId),
324
+ (0, import_pg_core7.index)("idx_session_token_hash").on(table.tokenHash),
325
+ (0, import_pg_core7.index)("idx_session_expires_at").on(table.expiresAt)
326
+ ]
327
+ );
328
+
329
+ // src/schema/scheduled-events.ts
330
+ var import_pg_core8 = require("drizzle-orm/pg-core");
331
+ var scheduledEvents = (0, import_pg_core8.pgTable)(
332
+ "scheduled_events",
333
+ {
334
+ id: (0, import_pg_core8.serial)("id").primaryKey(),
335
+ hook: (0, import_pg_core8.varchar)("hook", { length: 255 }).notNull(),
336
+ args: (0, import_pg_core8.jsonb)("args").notNull().default("[]"),
337
+ schedule: (0, import_pg_core8.varchar)("schedule", { length: 50 }),
338
+ intervalSeconds: (0, import_pg_core8.bigint)("interval_seconds", { mode: "number" }),
339
+ nextRunAt: (0, import_pg_core8.timestamp)("next_run_at", { withTimezone: true }).notNull(),
340
+ createdAt: (0, import_pg_core8.timestamp)("created_at", { withTimezone: true }).notNull().defaultNow(),
341
+ status: (0, import_pg_core8.varchar)("status", { length: 20 }).notNull().default("pending")
342
+ },
343
+ (table) => [
344
+ (0, import_pg_core8.index)("idx_scheduled_hook").on(table.hook),
345
+ (0, import_pg_core8.index)("idx_scheduled_next_run").on(table.nextRunAt),
346
+ (0, import_pg_core8.index)("idx_scheduled_status").on(table.status)
347
+ ]
348
+ );
349
+
350
+ // src/connection.ts
351
+ function getConfigFromEnv() {
352
+ const password = process.env["DB_PASSWORD"];
353
+ if (!password) {
354
+ throw new Error(
355
+ "DB_PASSWORD environment variable is required. Set it in your .env file or environment."
356
+ );
357
+ }
358
+ return {
359
+ host: process.env["DB_HOST"] ?? "localhost",
360
+ port: parseInt(process.env["DB_PORT"] ?? "5432", 10),
361
+ database: process.env["DB_NAME"] ?? "newcms",
362
+ user: process.env["DB_USER"] ?? "newcms",
363
+ password,
364
+ maxConnections: parseInt(process.env["DB_MAX_CONNECTIONS"] ?? "10", 10)
365
+ };
366
+ }
367
+ function createConnection(config) {
368
+ const cfg = config ?? getConfigFromEnv();
369
+ const client = (0, import_postgres.default)({
370
+ host: cfg.host,
371
+ port: cfg.port,
372
+ database: cfg.database,
373
+ user: cfg.user,
374
+ password: cfg.password,
375
+ max: cfg.maxConnections ?? 10
376
+ });
377
+ const db = (0, import_postgres_js.drizzle)(client, { schema: schema_exports });
378
+ return { db, client };
379
+ }
380
+
381
+ // src/cache/object-cache.ts
382
+ var import_ioredis = __toESM(require("ioredis"), 1);
383
+ var ObjectCache = class {
384
+ redis;
385
+ siteId = 1;
386
+ keyPrefix;
387
+ defaultTtl;
388
+ /** Groups that are shared across all sites (multisite) */
389
+ globalGroups = /* @__PURE__ */ new Set();
390
+ /** Per-group TTL overrides (in seconds) */
391
+ groupTtl = /* @__PURE__ */ new Map();
392
+ /** Local in-memory cache for the current request (non-persistent) */
393
+ localCache = /* @__PURE__ */ new Map();
394
+ constructor(config) {
395
+ this.redis = new import_ioredis.default({
396
+ host: config.host,
397
+ port: config.port,
398
+ lazyConnect: true,
399
+ maxRetriesPerRequest: 3
400
+ });
401
+ this.keyPrefix = config.keyPrefix ?? "cache";
402
+ this.defaultTtl = config.defaultTtl ?? 0;
403
+ }
404
+ async connect() {
405
+ await this.redis.connect();
406
+ }
407
+ async disconnect() {
408
+ await this.redis.quit();
409
+ }
410
+ /**
411
+ * Set the current site ID (for multisite per-site cache isolation).
412
+ */
413
+ setSiteId(siteId) {
414
+ this.siteId = siteId;
415
+ }
416
+ /**
417
+ * Register groups as global (shared across sites in multisite).
418
+ */
419
+ addGlobalGroups(groups) {
420
+ for (const group of groups) {
421
+ this.globalGroups.add(group);
422
+ }
423
+ }
424
+ /**
425
+ * Set TTL for a specific cache group.
426
+ */
427
+ setGroupTtl(group, ttlSeconds) {
428
+ this.groupTtl.set(group, ttlSeconds);
429
+ }
430
+ /**
431
+ * Build the Redis key for a cache entry.
432
+ */
433
+ buildKey(key, group = "default") {
434
+ if (this.globalGroups.has(group)) {
435
+ return `${this.keyPrefix}:global:${group}:${key}`;
436
+ }
437
+ return `${this.keyPrefix}:site:${this.siteId}:${group}:${key}`;
438
+ }
439
+ /**
440
+ * Build a local cache key (in-memory, for current request).
441
+ */
442
+ buildLocalKey(key, group = "default") {
443
+ if (this.globalGroups.has(group)) {
444
+ return `global:${group}:${key}`;
445
+ }
446
+ return `site:${this.siteId}:${group}:${key}`;
447
+ }
448
+ /**
449
+ * Get TTL for a group in seconds.
450
+ */
451
+ getTtl(group) {
452
+ return this.groupTtl.get(group) ?? this.defaultTtl;
453
+ }
454
+ /**
455
+ * Get a cached value.
456
+ *
457
+ * @returns The cached value, or undefined if not found
458
+ */
459
+ async get(key, group = "default") {
460
+ const localKey = this.buildLocalKey(key, group);
461
+ if (this.localCache.has(localKey)) {
462
+ return this.localCache.get(localKey);
463
+ }
464
+ const redisKey = this.buildKey(key, group);
465
+ const raw = await this.redis.get(redisKey);
466
+ if (raw === null) return void 0;
467
+ try {
468
+ const value = JSON.parse(raw);
469
+ this.localCache.set(localKey, value);
470
+ return value;
471
+ } catch {
472
+ return raw;
473
+ }
474
+ }
475
+ /**
476
+ * Set a cached value.
477
+ *
478
+ * @param key - Cache key
479
+ * @param value - Value to cache (will be JSON serialized)
480
+ * @param group - Cache group
481
+ * @param ttl - TTL in seconds (overrides group default). 0 = no expiry.
482
+ * @returns true on success
483
+ */
484
+ async set(key, value, group = "default", ttl) {
485
+ const redisKey = this.buildKey(key, group);
486
+ const serialized = JSON.stringify(value);
487
+ const effectiveTtl = ttl ?? this.getTtl(group);
488
+ if (effectiveTtl > 0) {
489
+ await this.redis.setex(redisKey, effectiveTtl, serialized);
490
+ } else {
491
+ await this.redis.set(redisKey, serialized);
492
+ }
493
+ const localKey = this.buildLocalKey(key, group);
494
+ this.localCache.set(localKey, value);
495
+ return true;
496
+ }
497
+ /**
498
+ * Add a cached value only if it doesn't already exist.
499
+ *
500
+ * @returns true if the value was added, false if key already exists
501
+ */
502
+ async add(key, value, group = "default", ttl) {
503
+ const redisKey = this.buildKey(key, group);
504
+ const serialized = JSON.stringify(value);
505
+ const effectiveTtl = ttl ?? this.getTtl(group);
506
+ let result;
507
+ if (effectiveTtl > 0) {
508
+ result = await this.redis.set(redisKey, serialized, "EX", effectiveTtl, "NX");
509
+ } else {
510
+ result = await this.redis.set(redisKey, serialized, "NX");
511
+ }
512
+ if (result === "OK") {
513
+ const localKey = this.buildLocalKey(key, group);
514
+ this.localCache.set(localKey, value);
515
+ return true;
516
+ }
517
+ return false;
518
+ }
519
+ /**
520
+ * Delete a cached value.
521
+ *
522
+ * @returns true if the key existed and was deleted
523
+ */
524
+ async delete(key, group = "default") {
525
+ const redisKey = this.buildKey(key, group);
526
+ const count = await this.redis.del(redisKey);
527
+ const localKey = this.buildLocalKey(key, group);
528
+ this.localCache.delete(localKey);
529
+ return count > 0;
530
+ }
531
+ /**
532
+ * Increment a numeric cached value.
533
+ *
534
+ * @returns The new value, or false if key doesn't exist
535
+ */
536
+ async incr(key, group = "default", offset = 1) {
537
+ const redisKey = this.buildKey(key, group);
538
+ const keyExists = await this.redis.exists(redisKey);
539
+ if (!keyExists) return false;
540
+ const current = await this.get(key, group);
541
+ if (current === void 0 || typeof current !== "number") return false;
542
+ const newValue = current + offset;
543
+ await this.set(key, newValue, group);
544
+ return newValue;
545
+ }
546
+ /**
547
+ * Decrement a numeric cached value.
548
+ *
549
+ * @returns The new value, or false if key doesn't exist
550
+ */
551
+ async decr(key, group = "default", offset = 1) {
552
+ return this.incr(key, group, -offset);
553
+ }
554
+ /**
555
+ * Get multiple cached values at once.
556
+ *
557
+ * @returns Map of key -> value (missing keys are not included)
558
+ */
559
+ async getMultiple(keys, group = "default") {
560
+ const result = /* @__PURE__ */ new Map();
561
+ if (keys.length === 0) return result;
562
+ const redisKeys = keys.map((k) => this.buildKey(k, group));
563
+ const values = await this.redis.mget(...redisKeys);
564
+ for (let i = 0; i < keys.length; i++) {
565
+ const raw = values[i];
566
+ if (raw !== null) {
567
+ try {
568
+ const value = JSON.parse(raw);
569
+ result.set(keys[i], value);
570
+ const localKey = this.buildLocalKey(keys[i], group);
571
+ this.localCache.set(localKey, value);
572
+ } catch {
573
+ result.set(keys[i], raw);
574
+ }
575
+ }
576
+ }
577
+ return result;
578
+ }
579
+ /**
580
+ * Set multiple cached values at once.
581
+ */
582
+ async setMultiple(entries, group = "default", ttl) {
583
+ const items = entries instanceof Map ? entries : new Map(Object.entries(entries));
584
+ if (items.size === 0) return true;
585
+ const effectiveTtl = ttl ?? this.getTtl(group);
586
+ const pipeline = this.redis.pipeline();
587
+ for (const [key, value] of items) {
588
+ const redisKey = this.buildKey(key, group);
589
+ const serialized = JSON.stringify(value);
590
+ if (effectiveTtl > 0) {
591
+ pipeline.setex(redisKey, effectiveTtl, serialized);
592
+ } else {
593
+ pipeline.set(redisKey, serialized);
594
+ }
595
+ const localKey = this.buildLocalKey(key, group);
596
+ this.localCache.set(localKey, value);
597
+ }
598
+ await pipeline.exec();
599
+ return true;
600
+ }
601
+ /**
602
+ * Flush all keys in a specific group using SCAN + pipeline DEL.
603
+ *
604
+ * @returns Number of keys deleted
605
+ */
606
+ async flushGroup(group) {
607
+ const pattern = this.globalGroups.has(group) ? `${this.keyPrefix}:global:${group}:*` : `${this.keyPrefix}:site:${this.siteId}:${group}:*`;
608
+ let deleted = 0;
609
+ let cursor = "0";
610
+ do {
611
+ const [nextCursor, keys] = await this.redis.scan(cursor, "MATCH", pattern, "COUNT", 100);
612
+ cursor = nextCursor;
613
+ if (keys.length > 0) {
614
+ const pipeline = this.redis.pipeline();
615
+ for (const key of keys) {
616
+ pipeline.del(key);
617
+ }
618
+ await pipeline.exec();
619
+ deleted += keys.length;
620
+ }
621
+ } while (cursor !== "0");
622
+ for (const localKey of this.localCache.keys()) {
623
+ if (localKey.startsWith(`${group}:`)) {
624
+ this.localCache.delete(localKey);
625
+ }
626
+ }
627
+ return deleted;
628
+ }
629
+ /**
630
+ * Flush all cached data (all groups, all sites).
631
+ * Uses SCAN + DEL to only clear cache keys (not other Redis data).
632
+ *
633
+ * @returns Number of keys deleted
634
+ */
635
+ async flushAll() {
636
+ const pattern = `${this.keyPrefix}:*`;
637
+ let deleted = 0;
638
+ let cursor = "0";
639
+ do {
640
+ const [nextCursor, keys] = await this.redis.scan(cursor, "MATCH", pattern, "COUNT", 100);
641
+ cursor = nextCursor;
642
+ if (keys.length > 0) {
643
+ const pipeline = this.redis.pipeline();
644
+ for (const key of keys) {
645
+ pipeline.del(key);
646
+ }
647
+ await pipeline.exec();
648
+ deleted += keys.length;
649
+ }
650
+ } while (cursor !== "0");
651
+ this.localCache.clear();
652
+ return deleted;
653
+ }
654
+ /**
655
+ * Clear only the local in-memory cache (for request boundary cleanup).
656
+ */
657
+ clearLocalCache() {
658
+ this.localCache.clear();
659
+ }
660
+ /**
661
+ * Check if a key exists in cache.
662
+ */
663
+ async exists(key, group = "default") {
664
+ const localKey = this.buildLocalKey(key, group);
665
+ if (this.localCache.has(localKey)) return true;
666
+ const redisKey = this.buildKey(key, group);
667
+ return await this.redis.exists(redisKey) === 1;
668
+ }
669
+ /**
670
+ * Get the underlying Redis instance (for advanced operations).
671
+ */
672
+ getRedis() {
673
+ return this.redis;
674
+ }
675
+ };
676
+
677
+ // src/repositories/options-repository.ts
678
+ var import_drizzle_orm = require("drizzle-orm");
679
+ var CACHE_GROUP = "options";
680
+ var AUTOLOAD_CACHE_KEY = "__autoloaded";
681
+ var NOT_FOUND_GROUP = "options_nf";
682
+ var OptionsRepository = class {
683
+ constructor(db, cache) {
684
+ this.db = db;
685
+ this.cache = cache;
686
+ }
687
+ db;
688
+ cache;
689
+ /**
690
+ * Get an option value.
691
+ *
692
+ * Lookup order:
693
+ * 1. Redis cache (group "options")
694
+ * 2. "Not found" cache (avoids repeated DB queries for missing keys)
695
+ * 3. Database
696
+ */
697
+ async getOption(name, defaultValue) {
698
+ const cached = await this.cache.get(name, CACHE_GROUP);
699
+ if (cached !== void 0) return cached;
700
+ const isNotFound = await this.cache.get(name, NOT_FOUND_GROUP);
701
+ if (isNotFound !== void 0) return defaultValue;
702
+ const rows = await this.db.select().from(options).where((0, import_drizzle_orm.eq)(options.optionName, name)).limit(1);
703
+ if (rows.length === 0) {
704
+ await this.cache.set(name, true, NOT_FOUND_GROUP, 3600);
705
+ return defaultValue;
706
+ }
707
+ const row = rows[0];
708
+ const value = this.deserializeValue(row);
709
+ await this.cache.set(name, value, CACHE_GROUP);
710
+ return value;
711
+ }
712
+ /**
713
+ * Add a new option. Fails if option already exists.
714
+ *
715
+ * @returns true if the option was created
716
+ */
717
+ async addOption(name, value, autoload = true) {
718
+ const existing = await this.db.select({ optionId: options.optionId }).from(options).where((0, import_drizzle_orm.eq)(options.optionName, name)).limit(1);
719
+ if (existing.length > 0) return false;
720
+ const { textValue, jsonValue } = this.serializeValue(value);
721
+ await this.db.insert(options).values({
722
+ optionName: name,
723
+ optionValue: textValue,
724
+ optionValueJson: jsonValue,
725
+ autoload
726
+ });
727
+ await this.cache.set(name, value, CACHE_GROUP);
728
+ await this.cache.delete(name, NOT_FOUND_GROUP);
729
+ if (autoload) {
730
+ await this.cache.delete(AUTOLOAD_CACHE_KEY, CACHE_GROUP);
731
+ }
732
+ return true;
733
+ }
734
+ /**
735
+ * Update an existing option, or create it if it doesn't exist.
736
+ *
737
+ * @returns true if the value was changed
738
+ */
739
+ async updateOption(name, value, autoload) {
740
+ const { textValue, jsonValue } = this.serializeValue(value);
741
+ const existing = await this.db.select().from(options).where((0, import_drizzle_orm.eq)(options.optionName, name)).limit(1);
742
+ if (existing.length === 0) {
743
+ return this.addOption(name, value, autoload ?? true);
744
+ }
745
+ const row = existing[0];
746
+ if (row.optionValue === textValue && autoload === void 0) {
747
+ return false;
748
+ }
749
+ const updateData = {
750
+ optionValue: textValue,
751
+ optionValueJson: jsonValue
752
+ };
753
+ if (autoload !== void 0) {
754
+ updateData["autoload"] = autoload;
755
+ }
756
+ await this.db.update(options).set(updateData).where((0, import_drizzle_orm.eq)(options.optionName, name));
757
+ await this.cache.set(name, value, CACHE_GROUP);
758
+ await this.cache.delete(name, NOT_FOUND_GROUP);
759
+ await this.cache.delete(AUTOLOAD_CACHE_KEY, CACHE_GROUP);
760
+ return true;
761
+ }
762
+ /**
763
+ * Delete an option.
764
+ *
765
+ * @returns true if the option existed and was deleted
766
+ */
767
+ async deleteOption(name) {
768
+ const result = await this.db.delete(options).where((0, import_drizzle_orm.eq)(options.optionName, name)).returning({ optionId: options.optionId });
769
+ if (result.length === 0) return false;
770
+ await this.cache.delete(name, CACHE_GROUP);
771
+ await this.cache.delete(name, NOT_FOUND_GROUP);
772
+ await this.cache.delete(AUTOLOAD_CACHE_KEY, CACHE_GROUP);
773
+ return true;
774
+ }
775
+ /**
776
+ * Load all autoloaded options into cache at once.
777
+ * Called during bootstrap to pre-warm the cache.
778
+ */
779
+ async loadAutoloadedOptions() {
780
+ const cached = await this.cache.get(
781
+ AUTOLOAD_CACHE_KEY,
782
+ CACHE_GROUP
783
+ );
784
+ if (cached) {
785
+ const result2 = new Map(Object.entries(cached));
786
+ for (const [key, value] of result2) {
787
+ await this.cache.set(key, value, CACHE_GROUP);
788
+ }
789
+ return result2;
790
+ }
791
+ const rows = await this.db.select().from(options).where((0, import_drizzle_orm.eq)(options.autoload, true));
792
+ const result = /* @__PURE__ */ new Map();
793
+ const autoloadMap = {};
794
+ for (const row of rows) {
795
+ const value = this.deserializeValue(row);
796
+ result.set(row.optionName, value);
797
+ autoloadMap[row.optionName] = value;
798
+ await this.cache.set(row.optionName, value, CACHE_GROUP);
799
+ }
800
+ await this.cache.set(AUTOLOAD_CACHE_KEY, autoloadMap, CACHE_GROUP);
801
+ return result;
802
+ }
803
+ /**
804
+ * Serialize a value for storage.
805
+ * Complex types (objects, arrays) are stored in both text and JSONB columns.
806
+ */
807
+ serializeValue(value) {
808
+ if (value === null || value === void 0) {
809
+ return { textValue: "", jsonValue: null };
810
+ }
811
+ if (typeof value === "string") {
812
+ try {
813
+ const parsed = JSON.parse(value);
814
+ if (typeof parsed === "object" && parsed !== null) {
815
+ return { textValue: value, jsonValue: parsed };
816
+ }
817
+ } catch {
818
+ }
819
+ return { textValue: value, jsonValue: null };
820
+ }
821
+ if (typeof value === "number" || typeof value === "boolean") {
822
+ return { textValue: String(value), jsonValue: null };
823
+ }
824
+ const textValue = JSON.stringify(value);
825
+ return { textValue, jsonValue: value };
826
+ }
827
+ /**
828
+ * Deserialize a value from the database row.
829
+ * Prefers JSONB column when available (already parsed).
830
+ */
831
+ deserializeValue(row) {
832
+ if (row.optionValueJson !== null && row.optionValueJson !== void 0) {
833
+ return row.optionValueJson;
834
+ }
835
+ try {
836
+ return JSON.parse(row.optionValue);
837
+ } catch {
838
+ return row.optionValue;
839
+ }
840
+ }
841
+ };
842
+
843
+ // src/repositories/post-repository.ts
844
+ var import_drizzle_orm3 = require("drizzle-orm");
845
+
846
+ // src/repositories/meta-repository.ts
847
+ var import_drizzle_orm2 = require("drizzle-orm");
848
+ var MetaRepository = class {
849
+ constructor(db, table, columns, colNames) {
850
+ this.db = db;
851
+ this.table = table;
852
+ this.columns = columns;
853
+ this.colNames = colNames;
854
+ }
855
+ db;
856
+ table;
857
+ columns;
858
+ colNames;
859
+ async get(objectId, key) {
860
+ const rows = await this.db.select().from(this.table).where((0, import_drizzle_orm2.and)((0, import_drizzle_orm2.eq)(this.columns.objectId, objectId), (0, import_drizzle_orm2.eq)(this.columns.metaKey, key))).limit(1);
861
+ if (rows.length === 0) return void 0;
862
+ return this.deserialize(this.toMetaEntry(rows[0]));
863
+ }
864
+ async getAll(objectId, key) {
865
+ const rows = await this.db.select().from(this.table).where((0, import_drizzle_orm2.and)((0, import_drizzle_orm2.eq)(this.columns.objectId, objectId), (0, import_drizzle_orm2.eq)(this.columns.metaKey, key)));
866
+ return rows.map((r) => this.deserialize(this.toMetaEntry(r)));
867
+ }
868
+ async getAllForObject(objectId) {
869
+ const rows = await this.db.select().from(this.table).where((0, import_drizzle_orm2.eq)(this.columns.objectId, objectId));
870
+ const result = /* @__PURE__ */ new Map();
871
+ for (const row of rows) {
872
+ const entry = this.toMetaEntry(row);
873
+ const key = entry.metaKey ?? "";
874
+ const values = result.get(key) ?? [];
875
+ values.push(this.deserialize(entry));
876
+ result.set(key, values);
877
+ }
878
+ return result;
879
+ }
880
+ async batchLoad(objectIds) {
881
+ if (objectIds.length === 0) return /* @__PURE__ */ new Map();
882
+ const rows = await this.db.select().from(this.table).where((0, import_drizzle_orm2.inArray)(this.columns.objectId, objectIds));
883
+ const result = /* @__PURE__ */ new Map();
884
+ for (const row of rows) {
885
+ const rawRow = row;
886
+ const entry = this.toMetaEntry(rawRow);
887
+ if (!result.has(entry.objectId)) {
888
+ result.set(entry.objectId, /* @__PURE__ */ new Map());
889
+ }
890
+ const objectMeta = result.get(entry.objectId);
891
+ const key = entry.metaKey ?? "";
892
+ const values = objectMeta.get(key) ?? [];
893
+ values.push(this.deserialize(entry));
894
+ objectMeta.set(key, values);
895
+ }
896
+ return result;
897
+ }
898
+ async add(objectId, key, value) {
899
+ const { textValue, jsonValue } = this.serialize(value);
900
+ const jsonStr = jsonValue !== null ? JSON.stringify(jsonValue) : null;
901
+ const s = this.colNames.sql;
902
+ const t = this.colNames.table;
903
+ const rows = await this.db.execute(import_drizzle_orm2.sql`
904
+ INSERT INTO ${import_drizzle_orm2.sql.raw(`"${t}"`)} (${import_drizzle_orm2.sql.raw(`"${s.objectId}"`)}, ${import_drizzle_orm2.sql.raw(`"${s.metaKey}"`)}, ${import_drizzle_orm2.sql.raw(`"${s.metaValue}"`)}, ${import_drizzle_orm2.sql.raw(`"${s.metaValueJson}"`)})
905
+ VALUES (${objectId}, ${key}, ${textValue}, ${jsonStr}::jsonb)
906
+ RETURNING ${import_drizzle_orm2.sql.raw(`"${s.metaId}"`)}
907
+ `);
908
+ const returnedRows = rows;
909
+ return returnedRows[0][s.metaId];
910
+ }
911
+ async update(objectId, key, value) {
912
+ const { textValue, jsonValue } = this.serialize(value);
913
+ const existing = await this.db.select({ metaId: this.columns.metaId }).from(this.table).where((0, import_drizzle_orm2.and)((0, import_drizzle_orm2.eq)(this.columns.objectId, objectId), (0, import_drizzle_orm2.eq)(this.columns.metaKey, key))).limit(1);
914
+ if (existing.length === 0) {
915
+ await this.add(objectId, key, value);
916
+ return true;
917
+ }
918
+ const metaId = existing[0].metaId;
919
+ const jsonStr = jsonValue !== null ? JSON.stringify(jsonValue) : null;
920
+ const s = this.colNames.sql;
921
+ const t = this.colNames.table;
922
+ await this.db.execute(import_drizzle_orm2.sql`
923
+ UPDATE ${import_drizzle_orm2.sql.raw(`"${t}"`)}
924
+ SET ${import_drizzle_orm2.sql.raw(`"${s.metaValue}"`)} = ${textValue}, ${import_drizzle_orm2.sql.raw(`"${s.metaValueJson}"`)} = ${jsonStr}::jsonb
925
+ WHERE ${import_drizzle_orm2.sql.raw(`"${s.metaId}"`)} = ${metaId}
926
+ `);
927
+ return true;
928
+ }
929
+ async delete(objectId, key, value) {
930
+ if (value !== void 0) {
931
+ const { textValue } = this.serialize(value);
932
+ const result2 = await this.db.delete(this.table).where(
933
+ (0, import_drizzle_orm2.and)(
934
+ (0, import_drizzle_orm2.eq)(this.columns.objectId, objectId),
935
+ (0, import_drizzle_orm2.eq)(this.columns.metaKey, key),
936
+ (0, import_drizzle_orm2.eq)(this.columns.metaValue, textValue)
937
+ )
938
+ ).returning({ metaId: this.columns.metaId });
939
+ return result2.length;
940
+ }
941
+ const result = await this.db.delete(this.table).where((0, import_drizzle_orm2.and)((0, import_drizzle_orm2.eq)(this.columns.objectId, objectId), (0, import_drizzle_orm2.eq)(this.columns.metaKey, key))).returning({ metaId: this.columns.metaId });
942
+ return result.length;
943
+ }
944
+ async deleteAllForObject(objectId) {
945
+ const result = await this.db.delete(this.table).where((0, import_drizzle_orm2.eq)(this.columns.objectId, objectId)).returning({ metaId: this.columns.metaId });
946
+ return result.length;
947
+ }
948
+ /**
949
+ * Convert a raw DB row to MetaEntry using column name mapping.
950
+ */
951
+ toMetaEntry(row) {
952
+ const ts = this.colNames.ts;
953
+ return {
954
+ metaId: row[ts.metaId],
955
+ objectId: row[ts.objectId],
956
+ metaKey: row[ts.metaKey],
957
+ metaValue: row[ts.metaValue],
958
+ metaValueJson: row[ts.metaValueJson]
959
+ };
960
+ }
961
+ serialize(value) {
962
+ if (value === null || value === void 0) {
963
+ return { textValue: "", jsonValue: null };
964
+ }
965
+ if (typeof value === "string") {
966
+ try {
967
+ const parsed = JSON.parse(value);
968
+ if (typeof parsed === "object" && parsed !== null) {
969
+ return { textValue: value, jsonValue: parsed };
970
+ }
971
+ } catch {
972
+ }
973
+ return { textValue: value, jsonValue: null };
974
+ }
975
+ if (typeof value === "number" || typeof value === "boolean") {
976
+ return { textValue: String(value), jsonValue: null };
977
+ }
978
+ const textValue = JSON.stringify(value);
979
+ return { textValue, jsonValue: value };
980
+ }
981
+ deserialize(entry) {
982
+ if (entry.metaValueJson !== null && entry.metaValueJson !== void 0) {
983
+ return entry.metaValueJson;
984
+ }
985
+ if (entry.metaValue === null) return "";
986
+ try {
987
+ return JSON.parse(entry.metaValue);
988
+ } catch {
989
+ return entry.metaValue;
990
+ }
991
+ }
992
+ };
993
+
994
+ // src/repositories/post-repository.ts
995
+ var PostRepository = class {
996
+ constructor(db) {
997
+ this.db = db;
998
+ const metaCols = {
999
+ metaId: postmeta.metaId,
1000
+ objectId: postmeta.postId,
1001
+ metaKey: postmeta.metaKey,
1002
+ metaValue: postmeta.metaValue,
1003
+ metaValueJson: postmeta.metaValueJson
1004
+ };
1005
+ const colNames = {
1006
+ table: "postmeta",
1007
+ sql: { metaId: "meta_id", objectId: "post_id", metaKey: "meta_key", metaValue: "meta_value", metaValueJson: "meta_value_json" },
1008
+ ts: { metaId: "metaId", objectId: "postId", metaKey: "metaKey", metaValue: "metaValue", metaValueJson: "metaValueJson" }
1009
+ };
1010
+ this.meta = new MetaRepository(db, postmeta, metaCols, colNames);
1011
+ }
1012
+ db;
1013
+ meta;
1014
+ /**
1015
+ * Create a new post.
1016
+ */
1017
+ async create(input) {
1018
+ const postName = input.postName || this.generateSlug(input.postTitle);
1019
+ const uniqueSlug = await this.ensureUniqueSlug(
1020
+ postName,
1021
+ input.postType ?? "post"
1022
+ );
1023
+ const now = /* @__PURE__ */ new Date();
1024
+ const [row] = await this.db.insert(posts).values({
1025
+ postAuthor: input.postAuthor,
1026
+ postTitle: input.postTitle,
1027
+ postContent: input.postContent ?? "",
1028
+ postExcerpt: input.postExcerpt ?? "",
1029
+ postStatus: input.postStatus ?? "draft",
1030
+ postName: uniqueSlug,
1031
+ postType: input.postType ?? "post",
1032
+ postParent: input.postParent ?? 0,
1033
+ postPassword: input.postPassword ?? "",
1034
+ commentStatus: input.commentStatus ?? "open",
1035
+ pingStatus: input.pingStatus ?? "open",
1036
+ postMimeType: input.postMimeType ?? "",
1037
+ menuOrder: input.menuOrder ?? 0,
1038
+ guid: input.guid ?? "",
1039
+ postDate: now,
1040
+ postDateGmt: now,
1041
+ postModified: now,
1042
+ postModifiedGmt: now
1043
+ }).returning();
1044
+ return row;
1045
+ }
1046
+ /**
1047
+ * Get a post by ID.
1048
+ */
1049
+ async getById(id) {
1050
+ const rows = await this.db.select().from(posts).where((0, import_drizzle_orm3.eq)(posts.id, id)).limit(1);
1051
+ return rows[0];
1052
+ }
1053
+ /**
1054
+ * Get a post by slug and type.
1055
+ */
1056
+ async getBySlug(slug, postType = "post") {
1057
+ const rows = await this.db.select().from(posts).where((0, import_drizzle_orm3.and)((0, import_drizzle_orm3.eq)(posts.postName, slug), (0, import_drizzle_orm3.eq)(posts.postType, postType))).limit(1);
1058
+ return rows[0];
1059
+ }
1060
+ /**
1061
+ * Update a post. Returns the updated row or undefined if not found.
1062
+ */
1063
+ async update(id, input) {
1064
+ const existing = await this.getById(id);
1065
+ if (!existing) return void 0;
1066
+ const now = /* @__PURE__ */ new Date();
1067
+ const updateData = {
1068
+ postModified: now,
1069
+ postModifiedGmt: now
1070
+ };
1071
+ if (input.postTitle !== void 0) updateData["postTitle"] = input.postTitle;
1072
+ if (input.postContent !== void 0) updateData["postContent"] = input.postContent;
1073
+ if (input.postExcerpt !== void 0) updateData["postExcerpt"] = input.postExcerpt;
1074
+ if (input.postStatus !== void 0) updateData["postStatus"] = input.postStatus;
1075
+ if (input.postType !== void 0) updateData["postType"] = input.postType;
1076
+ if (input.postParent !== void 0) updateData["postParent"] = input.postParent;
1077
+ if (input.postPassword !== void 0) updateData["postPassword"] = input.postPassword;
1078
+ if (input.commentStatus !== void 0) updateData["commentStatus"] = input.commentStatus;
1079
+ if (input.pingStatus !== void 0) updateData["pingStatus"] = input.pingStatus;
1080
+ if (input.menuOrder !== void 0) updateData["menuOrder"] = input.menuOrder;
1081
+ if (input.postName !== void 0) {
1082
+ updateData["postName"] = await this.ensureUniqueSlug(
1083
+ input.postName,
1084
+ input.postType ?? existing.postType,
1085
+ id
1086
+ );
1087
+ }
1088
+ const [row] = await this.db.update(posts).set(updateData).where((0, import_drizzle_orm3.eq)(posts.id, id)).returning();
1089
+ return row;
1090
+ }
1091
+ /**
1092
+ * Trash a post (move to trash status, preserving original status in meta).
1093
+ */
1094
+ async trash(id) {
1095
+ const existing = await this.getById(id);
1096
+ if (!existing) return void 0;
1097
+ if (existing.postStatus === "trash") return existing;
1098
+ await this.meta.update(id, "_trash_meta_status", existing.postStatus);
1099
+ return this.update(id, { postStatus: "trash" });
1100
+ }
1101
+ /**
1102
+ * Restore a trashed post to its original status.
1103
+ */
1104
+ async untrash(id) {
1105
+ const existing = await this.getById(id);
1106
+ if (!existing || existing.postStatus !== "trash") return existing;
1107
+ const originalStatus = await this.meta.get(id, "_trash_meta_status");
1108
+ await this.meta.delete(id, "_trash_meta_status");
1109
+ return this.update(id, { postStatus: originalStatus ?? "draft" });
1110
+ }
1111
+ /**
1112
+ * Permanently delete a post and all its metadata.
1113
+ */
1114
+ async deletePermanently(id) {
1115
+ await this.meta.deleteAllForObject(id);
1116
+ const result = await this.db.delete(posts).where((0, import_drizzle_orm3.eq)(posts.id, id)).returning({ id: posts.id });
1117
+ return result.length > 0;
1118
+ }
1119
+ /**
1120
+ * Get sticky post IDs.
1121
+ */
1122
+ async getStickyIds() {
1123
+ const rows = await this.db.select({ postId: postmeta.postId }).from(postmeta).where((0, import_drizzle_orm3.and)((0, import_drizzle_orm3.eq)(postmeta.metaKey, "_sticky"), (0, import_drizzle_orm3.eq)(postmeta.metaValue, "1")));
1124
+ return rows.map((r) => r.postId);
1125
+ }
1126
+ /**
1127
+ * Set a post as sticky or not.
1128
+ */
1129
+ async setSticky(id, sticky) {
1130
+ if (sticky) {
1131
+ await this.meta.update(id, "_sticky", "1");
1132
+ } else {
1133
+ await this.meta.delete(id, "_sticky");
1134
+ }
1135
+ }
1136
+ /**
1137
+ * Check if a post is sticky.
1138
+ */
1139
+ async isSticky(id) {
1140
+ const value = await this.meta.get(id, "_sticky");
1141
+ return value === "1" || value === 1;
1142
+ }
1143
+ /**
1144
+ * Count posts by type and status.
1145
+ */
1146
+ async countByStatus(postType = "post") {
1147
+ const rows = await this.db.select({
1148
+ status: posts.postStatus,
1149
+ count: import_drizzle_orm3.sql`count(*)::int`
1150
+ }).from(posts).where((0, import_drizzle_orm3.eq)(posts.postType, postType)).groupBy(posts.postStatus);
1151
+ const result = {};
1152
+ for (const row of rows) {
1153
+ result[row.status] = row.count;
1154
+ }
1155
+ return result;
1156
+ }
1157
+ /**
1158
+ * Generate a URL-safe slug from a title.
1159
+ */
1160
+ generateSlug(title) {
1161
+ return title.toLowerCase().normalize("NFD").replace(/[\u0300-\u036f]/g, "").replace(/[^a-z0-9_\s-]/g, "").replace(/\s+/g, "-").replace(/-+/g, "-").replace(/^-|-$/g, "").substring(0, 200);
1162
+ }
1163
+ /**
1164
+ * Ensure a slug is unique within a post type.
1165
+ * Appends -2, -3, etc. if needed.
1166
+ */
1167
+ async ensureUniqueSlug(slug, postType, excludeId) {
1168
+ let candidate = slug;
1169
+ let suffix = 2;
1170
+ while (true) {
1171
+ const conditions = [(0, import_drizzle_orm3.eq)(posts.postName, candidate), (0, import_drizzle_orm3.eq)(posts.postType, postType)];
1172
+ if (excludeId !== void 0) {
1173
+ conditions.push(import_drizzle_orm3.sql`${posts.id} != ${excludeId}`);
1174
+ }
1175
+ const existing = await this.db.select({ id: posts.id }).from(posts).where((0, import_drizzle_orm3.and)(...conditions)).limit(1);
1176
+ if (existing.length === 0) return candidate;
1177
+ candidate = `${slug}-${suffix}`;
1178
+ suffix++;
1179
+ }
1180
+ }
1181
+ };
1182
+
1183
+ // src/repositories/taxonomy-repository.ts
1184
+ var import_drizzle_orm4 = require("drizzle-orm");
1185
+ var TaxonomyRepository = class {
1186
+ constructor(db) {
1187
+ this.db = db;
1188
+ const metaCols = {
1189
+ metaId: termmeta.metaId,
1190
+ objectId: termmeta.termId,
1191
+ metaKey: termmeta.metaKey,
1192
+ metaValue: termmeta.metaValue,
1193
+ metaValueJson: termmeta.metaValueJson
1194
+ };
1195
+ const colNames = {
1196
+ table: "termmeta",
1197
+ sql: { metaId: "meta_id", objectId: "term_id", metaKey: "meta_key", metaValue: "meta_value", metaValueJson: "meta_value_json" },
1198
+ ts: { metaId: "metaId", objectId: "termId", metaKey: "metaKey", metaValue: "metaValue", metaValueJson: "metaValueJson" }
1199
+ };
1200
+ this.meta = new MetaRepository(db, termmeta, metaCols, colNames);
1201
+ }
1202
+ db;
1203
+ meta;
1204
+ /**
1205
+ * Create a new term in a taxonomy.
1206
+ */
1207
+ async createTerm(input) {
1208
+ const slug = input.slug || this.generateSlug(input.name);
1209
+ const uniqueSlug = await this.ensureUniqueSlug(slug);
1210
+ const [term] = await this.db.insert(terms).values({
1211
+ name: input.name,
1212
+ slug: uniqueSlug
1213
+ }).returning();
1214
+ const [tt] = await this.db.insert(termTaxonomy).values({
1215
+ termId: term.termId,
1216
+ taxonomy: input.taxonomy,
1217
+ description: input.description ?? "",
1218
+ parent: input.parent ?? 0,
1219
+ count: 0
1220
+ }).returning();
1221
+ return {
1222
+ termId: term.termId,
1223
+ name: term.name,
1224
+ slug: term.slug,
1225
+ termGroup: term.termGroup,
1226
+ termTaxonomyId: tt.termTaxonomyId,
1227
+ taxonomy: tt.taxonomy,
1228
+ description: tt.description,
1229
+ parent: tt.parent,
1230
+ count: tt.count
1231
+ };
1232
+ }
1233
+ /**
1234
+ * Get a term by ID and taxonomy.
1235
+ */
1236
+ async getTermById(termId, taxonomy) {
1237
+ const rows = await this.db.select({
1238
+ termId: terms.termId,
1239
+ name: terms.name,
1240
+ slug: terms.slug,
1241
+ termGroup: terms.termGroup,
1242
+ termTaxonomyId: termTaxonomy.termTaxonomyId,
1243
+ taxonomy: termTaxonomy.taxonomy,
1244
+ description: termTaxonomy.description,
1245
+ parent: termTaxonomy.parent,
1246
+ count: termTaxonomy.count
1247
+ }).from(terms).innerJoin(termTaxonomy, (0, import_drizzle_orm4.eq)(terms.termId, termTaxonomy.termId)).where((0, import_drizzle_orm4.and)((0, import_drizzle_orm4.eq)(terms.termId, termId), (0, import_drizzle_orm4.eq)(termTaxonomy.taxonomy, taxonomy))).limit(1);
1248
+ return rows[0];
1249
+ }
1250
+ /**
1251
+ * Get a term by slug and taxonomy.
1252
+ */
1253
+ async getTermBySlug(slug, taxonomy) {
1254
+ const rows = await this.db.select({
1255
+ termId: terms.termId,
1256
+ name: terms.name,
1257
+ slug: terms.slug,
1258
+ termGroup: terms.termGroup,
1259
+ termTaxonomyId: termTaxonomy.termTaxonomyId,
1260
+ taxonomy: termTaxonomy.taxonomy,
1261
+ description: termTaxonomy.description,
1262
+ parent: termTaxonomy.parent,
1263
+ count: termTaxonomy.count
1264
+ }).from(terms).innerJoin(termTaxonomy, (0, import_drizzle_orm4.eq)(terms.termId, termTaxonomy.termId)).where((0, import_drizzle_orm4.and)((0, import_drizzle_orm4.eq)(terms.slug, slug), (0, import_drizzle_orm4.eq)(termTaxonomy.taxonomy, taxonomy))).limit(1);
1265
+ return rows[0];
1266
+ }
1267
+ /**
1268
+ * Get all terms in a taxonomy.
1269
+ */
1270
+ async getTerms(taxonomy, parentId) {
1271
+ const conditions = [(0, import_drizzle_orm4.eq)(termTaxonomy.taxonomy, taxonomy)];
1272
+ if (parentId !== void 0) {
1273
+ conditions.push((0, import_drizzle_orm4.eq)(termTaxonomy.parent, parentId));
1274
+ }
1275
+ const rows = await this.db.select({
1276
+ termId: terms.termId,
1277
+ name: terms.name,
1278
+ slug: terms.slug,
1279
+ termGroup: terms.termGroup,
1280
+ termTaxonomyId: termTaxonomy.termTaxonomyId,
1281
+ taxonomy: termTaxonomy.taxonomy,
1282
+ description: termTaxonomy.description,
1283
+ parent: termTaxonomy.parent,
1284
+ count: termTaxonomy.count
1285
+ }).from(terms).innerJoin(termTaxonomy, (0, import_drizzle_orm4.eq)(terms.termId, termTaxonomy.termId)).where((0, import_drizzle_orm4.and)(...conditions)).orderBy(terms.name);
1286
+ return rows;
1287
+ }
1288
+ /**
1289
+ * Assign terms to an object (post).
1290
+ */
1291
+ async setObjectTerms(objectId, termTaxonomyIds) {
1292
+ const existingTtIds = termTaxonomyIds.length > 0 ? await this.db.select({ taxonomy: termTaxonomy.taxonomy }).from(termTaxonomy).where((0, import_drizzle_orm4.inArray)(termTaxonomy.termTaxonomyId, termTaxonomyIds)) : [];
1293
+ const taxonomies = [...new Set(existingTtIds.map((r) => r.taxonomy))];
1294
+ if (taxonomies.length > 0) {
1295
+ const allTtIds = await this.db.select({ termTaxonomyId: termTaxonomy.termTaxonomyId }).from(termTaxonomy).where((0, import_drizzle_orm4.inArray)(termTaxonomy.taxonomy, taxonomies));
1296
+ const allTtIdValues = allTtIds.map((r) => r.termTaxonomyId);
1297
+ if (allTtIdValues.length > 0) {
1298
+ await this.db.delete(termRelationships).where(
1299
+ (0, import_drizzle_orm4.and)(
1300
+ (0, import_drizzle_orm4.eq)(termRelationships.objectId, objectId),
1301
+ (0, import_drizzle_orm4.inArray)(termRelationships.termTaxonomyId, allTtIdValues)
1302
+ )
1303
+ );
1304
+ }
1305
+ }
1306
+ if (termTaxonomyIds.length > 0) {
1307
+ await this.db.insert(termRelationships).values(
1308
+ termTaxonomyIds.map((ttId, i) => ({
1309
+ objectId,
1310
+ termTaxonomyId: ttId,
1311
+ termOrder: i
1312
+ }))
1313
+ ).onConflictDoNothing();
1314
+ }
1315
+ await this.recountTerms(termTaxonomyIds);
1316
+ }
1317
+ /**
1318
+ * Get terms assigned to an object.
1319
+ */
1320
+ async getObjectTerms(objectId, taxonomy) {
1321
+ const conditions = [(0, import_drizzle_orm4.eq)(termRelationships.objectId, objectId)];
1322
+ if (taxonomy) {
1323
+ conditions.push((0, import_drizzle_orm4.eq)(termTaxonomy.taxonomy, taxonomy));
1324
+ }
1325
+ const rows = await this.db.select({
1326
+ termId: terms.termId,
1327
+ name: terms.name,
1328
+ slug: terms.slug,
1329
+ termGroup: terms.termGroup,
1330
+ termTaxonomyId: termTaxonomy.termTaxonomyId,
1331
+ taxonomy: termTaxonomy.taxonomy,
1332
+ description: termTaxonomy.description,
1333
+ parent: termTaxonomy.parent,
1334
+ count: termTaxonomy.count
1335
+ }).from(termRelationships).innerJoin(
1336
+ termTaxonomy,
1337
+ (0, import_drizzle_orm4.eq)(termRelationships.termTaxonomyId, termTaxonomy.termTaxonomyId)
1338
+ ).innerJoin(terms, (0, import_drizzle_orm4.eq)(termTaxonomy.termId, terms.termId)).where((0, import_drizzle_orm4.and)(...conditions)).orderBy(termRelationships.termOrder);
1339
+ return rows;
1340
+ }
1341
+ /**
1342
+ * Delete a term and all its relationships.
1343
+ */
1344
+ async deleteTerm(termId, taxonomy) {
1345
+ const term = await this.getTermById(termId, taxonomy);
1346
+ if (!term) return false;
1347
+ await this.db.delete(termRelationships).where((0, import_drizzle_orm4.eq)(termRelationships.termTaxonomyId, term.termTaxonomyId));
1348
+ await this.db.delete(termTaxonomy).where((0, import_drizzle_orm4.eq)(termTaxonomy.termTaxonomyId, term.termTaxonomyId));
1349
+ const otherUsages = await this.db.select({ termTaxonomyId: termTaxonomy.termTaxonomyId }).from(termTaxonomy).where((0, import_drizzle_orm4.eq)(termTaxonomy.termId, termId)).limit(1);
1350
+ if (otherUsages.length === 0) {
1351
+ await this.db.delete(terms).where((0, import_drizzle_orm4.eq)(terms.termId, termId));
1352
+ }
1353
+ await this.meta.deleteAllForObject(termId);
1354
+ return true;
1355
+ }
1356
+ /**
1357
+ * Recount the number of objects assigned to terms.
1358
+ */
1359
+ async recountTerms(termTaxonomyIds) {
1360
+ for (const ttId of termTaxonomyIds) {
1361
+ const [result] = await this.db.select({ count: import_drizzle_orm4.sql`count(*)::int` }).from(termRelationships).where((0, import_drizzle_orm4.eq)(termRelationships.termTaxonomyId, ttId));
1362
+ await this.db.update(termTaxonomy).set({ count: result.count }).where((0, import_drizzle_orm4.eq)(termTaxonomy.termTaxonomyId, ttId));
1363
+ }
1364
+ }
1365
+ generateSlug(name) {
1366
+ return name.toLowerCase().normalize("NFD").replace(/[\u0300-\u036f]/g, "").replace(/[^a-z0-9_\s-]/g, "").replace(/\s+/g, "-").replace(/-+/g, "-").replace(/^-|-$/g, "").substring(0, 200);
1367
+ }
1368
+ async ensureUniqueSlug(slug, excludeId) {
1369
+ let candidate = slug;
1370
+ let suffix = 2;
1371
+ while (true) {
1372
+ const conditions = [(0, import_drizzle_orm4.eq)(terms.slug, candidate)];
1373
+ if (excludeId !== void 0) {
1374
+ conditions.push(import_drizzle_orm4.sql`${terms.termId} != ${excludeId}`);
1375
+ }
1376
+ const existing = await this.db.select({ termId: terms.termId }).from(terms).where((0, import_drizzle_orm4.and)(...conditions)).limit(1);
1377
+ if (existing.length === 0) return candidate;
1378
+ candidate = `${slug}-${suffix}`;
1379
+ suffix++;
1380
+ }
1381
+ }
1382
+ };
1383
+
1384
+ // src/repositories/revision-repository.ts
1385
+ var import_drizzle_orm5 = require("drizzle-orm");
1386
+ var REVISION_FIELDS = [
1387
+ "postTitle",
1388
+ "postContent",
1389
+ "postExcerpt"
1390
+ ];
1391
+ var RevisionRepository = class {
1392
+ constructor(db) {
1393
+ this.db = db;
1394
+ }
1395
+ db;
1396
+ /**
1397
+ * Create a revision snapshot of a post.
1398
+ * Returns undefined if nothing changed since the last revision.
1399
+ *
1400
+ * @param post - The current state of the post (before or after update)
1401
+ * @param authorId - The user who made the change
1402
+ */
1403
+ async createRevision(post, authorId) {
1404
+ const lastRevision = await this.getLatest(post.id);
1405
+ if (lastRevision && !this.hasChanges(post, lastRevision)) {
1406
+ return void 0;
1407
+ }
1408
+ const now = /* @__PURE__ */ new Date();
1409
+ const [revision] = await this.db.insert(posts).values({
1410
+ postAuthor: authorId,
1411
+ postDate: now,
1412
+ postDateGmt: now,
1413
+ postModified: now,
1414
+ postModifiedGmt: now,
1415
+ postTitle: post.postTitle,
1416
+ postContent: post.postContent,
1417
+ postExcerpt: post.postExcerpt,
1418
+ postStatus: "inherit",
1419
+ postName: `${post.id}-revision-v1`,
1420
+ postType: "revision",
1421
+ postParent: post.id
1422
+ }).returning();
1423
+ return revision;
1424
+ }
1425
+ /**
1426
+ * Get all revisions for a post, newest first.
1427
+ */
1428
+ async getRevisions(postId, limit) {
1429
+ let query = this.db.select().from(posts).where((0, import_drizzle_orm5.and)((0, import_drizzle_orm5.eq)(posts.postParent, postId), (0, import_drizzle_orm5.eq)(posts.postType, "revision"))).orderBy((0, import_drizzle_orm5.desc)(posts.postDate)).$dynamic();
1430
+ if (limit !== void 0) {
1431
+ query = query.limit(limit);
1432
+ }
1433
+ return await query;
1434
+ }
1435
+ /**
1436
+ * Get the most recent revision for a post.
1437
+ */
1438
+ async getLatest(postId) {
1439
+ const rows = await this.getRevisions(postId, 1);
1440
+ return rows[0];
1441
+ }
1442
+ /**
1443
+ * Get a specific revision by ID.
1444
+ */
1445
+ async getById(revisionId) {
1446
+ const rows = await this.db.select().from(posts).where((0, import_drizzle_orm5.and)((0, import_drizzle_orm5.eq)(posts.id, revisionId), (0, import_drizzle_orm5.eq)(posts.postType, "revision"))).limit(1);
1447
+ return rows[0];
1448
+ }
1449
+ /**
1450
+ * Restore a post to a specific revision.
1451
+ * Returns the updated post.
1452
+ */
1453
+ async restore(postId, revisionId) {
1454
+ const revision = await this.getById(revisionId);
1455
+ if (!revision || revision.postParent !== postId) return void 0;
1456
+ const now = /* @__PURE__ */ new Date();
1457
+ const [updated] = await this.db.update(posts).set({
1458
+ postTitle: revision.postTitle,
1459
+ postContent: revision.postContent,
1460
+ postExcerpt: revision.postExcerpt,
1461
+ postModified: now,
1462
+ postModifiedGmt: now
1463
+ }).where((0, import_drizzle_orm5.eq)(posts.id, postId)).returning();
1464
+ return updated;
1465
+ }
1466
+ /**
1467
+ * Delete old revisions beyond the keep limit.
1468
+ */
1469
+ async cleanup(postId, keepCount) {
1470
+ const revisions = await this.getRevisions(postId);
1471
+ if (revisions.length <= keepCount) return 0;
1472
+ const toDelete = revisions.slice(keepCount);
1473
+ const idsToDelete = toDelete.map((r) => r.id);
1474
+ if (idsToDelete.length === 0) return 0;
1475
+ const result = await this.db.delete(posts).where(
1476
+ (0, import_drizzle_orm5.and)(
1477
+ import_drizzle_orm5.sql`${posts.id} IN (${import_drizzle_orm5.sql.join(
1478
+ idsToDelete.map((id) => import_drizzle_orm5.sql`${id}`),
1479
+ import_drizzle_orm5.sql`, `
1480
+ )})`,
1481
+ (0, import_drizzle_orm5.eq)(posts.postType, "revision")
1482
+ )
1483
+ ).returning({ id: posts.id });
1484
+ return result.length;
1485
+ }
1486
+ /**
1487
+ * Count revisions for a post.
1488
+ */
1489
+ async count(postId) {
1490
+ const [result] = await this.db.select({ count: import_drizzle_orm5.sql`count(*)::int` }).from(posts).where((0, import_drizzle_orm5.and)((0, import_drizzle_orm5.eq)(posts.postParent, postId), (0, import_drizzle_orm5.eq)(posts.postType, "revision")));
1491
+ return result.count;
1492
+ }
1493
+ /**
1494
+ * Check if any tracked field changed between two post states.
1495
+ */
1496
+ hasChanges(current, previous) {
1497
+ for (const field of REVISION_FIELDS) {
1498
+ if (current[field] !== previous[field]) return true;
1499
+ }
1500
+ return false;
1501
+ }
1502
+ };
1503
+ // Annotate the CommonJS export names for ESM import in node:
1504
+ 0 && (module.exports = {
1505
+ MetaRepository,
1506
+ ObjectCache,
1507
+ OptionsRepository,
1508
+ PostRepository,
1509
+ RevisionRepository,
1510
+ TaxonomyRepository,
1511
+ commentmeta,
1512
+ comments,
1513
+ createConnection,
1514
+ links,
1515
+ options,
1516
+ postmeta,
1517
+ posts,
1518
+ scheduledEvents,
1519
+ sessions,
1520
+ termRelationships,
1521
+ termTaxonomy,
1522
+ termmeta,
1523
+ terms,
1524
+ usermeta,
1525
+ users
1526
+ });
1527
+ //# sourceMappingURL=index.cjs.map