@jiggai/kitchen-plugin-marketing 0.2.1

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/dist/index.js ADDED
@@ -0,0 +1,1521 @@
1
+ var __create = Object.create;
2
+ var __defProp = Object.defineProperty;
3
+ var __getOwnPropDesc = Object.getOwnPropertyDescriptor;
4
+ var __getOwnPropNames = Object.getOwnPropertyNames;
5
+ var __getProtoOf = Object.getPrototypeOf;
6
+ var __hasOwnProp = Object.prototype.hasOwnProperty;
7
+ var __esm = (fn, res) => function __init() {
8
+ return fn && (res = (0, fn[__getOwnPropNames(fn)[0]])(fn = 0)), res;
9
+ };
10
+ var __export = (target, all) => {
11
+ for (var name in all)
12
+ __defProp(target, name, { get: all[name], enumerable: true });
13
+ };
14
+ var __copyProps = (to, from, except, desc6) => {
15
+ if (from && typeof from === "object" || typeof from === "function") {
16
+ for (let key of __getOwnPropNames(from))
17
+ if (!__hasOwnProp.call(to, key) && key !== except)
18
+ __defProp(to, key, { get: () => from[key], enumerable: !(desc6 = __getOwnPropDesc(from, key)) || desc6.enumerable });
19
+ }
20
+ return to;
21
+ };
22
+ var __toESM = (mod, isNodeMode, target) => (target = mod != null ? __create(__getProtoOf(mod)) : {}, __copyProps(
23
+ // If the importer is in node compatibility mode or this is not an ESM
24
+ // file that has been converted to a CommonJS file using a Babel-
25
+ // compatible transform (i.e. "__esModule" has not been set), then set
26
+ // "default" to the CommonJS "module.exports" for node compatibility.
27
+ isNodeMode || !mod || !mod.__esModule ? __defProp(target, "default", { value: mod, enumerable: true }) : target,
28
+ mod
29
+ ));
30
+ var __toCommonJS = (mod) => __copyProps(__defProp({}, "__esModule", { value: true }), mod);
31
+
32
+ // src/db/schema.ts
33
+ var schema_exports = {};
34
+ __export(schema_exports, {
35
+ accountMetrics: () => accountMetrics,
36
+ accountMetricsRelations: () => accountMetricsRelations,
37
+ media: () => media,
38
+ postMetrics: () => postMetrics,
39
+ postMetricsRelations: () => postMetricsRelations,
40
+ posts: () => posts,
41
+ postsRelations: () => postsRelations,
42
+ socialAccounts: () => socialAccounts,
43
+ socialAccountsRelations: () => socialAccountsRelations,
44
+ templates: () => templates,
45
+ webhooks: () => webhooks
46
+ });
47
+ var import_sqlite_core, import_drizzle_orm, posts, media, templates, socialAccounts, postMetrics, accountMetrics, webhooks, postsRelations, postMetricsRelations, socialAccountsRelations, accountMetricsRelations;
48
+ var init_schema = __esm({
49
+ "src/db/schema.ts"() {
50
+ import_sqlite_core = require("drizzle-orm/sqlite-core");
51
+ import_drizzle_orm = require("drizzle-orm");
52
+ posts = (0, import_sqlite_core.sqliteTable)("posts", {
53
+ id: (0, import_sqlite_core.text)("id").primaryKey(),
54
+ teamId: (0, import_sqlite_core.text)("team_id").notNull(),
55
+ content: (0, import_sqlite_core.text)("content").notNull(),
56
+ platforms: (0, import_sqlite_core.text)("platforms").notNull(),
57
+ // JSON array
58
+ status: (0, import_sqlite_core.text)("status").notNull(),
59
+ // draft, scheduled, published, failed
60
+ scheduledAt: (0, import_sqlite_core.text)("scheduled_at"),
61
+ // ISO string
62
+ publishedAt: (0, import_sqlite_core.text)("published_at"),
63
+ // ISO string
64
+ tags: (0, import_sqlite_core.text)("tags"),
65
+ // JSON array
66
+ mediaIds: (0, import_sqlite_core.text)("media_ids"),
67
+ // JSON array
68
+ templateId: (0, import_sqlite_core.text)("template_id"),
69
+ createdAt: (0, import_sqlite_core.text)("created_at").notNull(),
70
+ updatedAt: (0, import_sqlite_core.text)("updated_at").notNull(),
71
+ createdBy: (0, import_sqlite_core.text)("created_by").notNull()
72
+ });
73
+ media = (0, import_sqlite_core.sqliteTable)("media", {
74
+ id: (0, import_sqlite_core.text)("id").primaryKey(),
75
+ teamId: (0, import_sqlite_core.text)("team_id").notNull(),
76
+ filename: (0, import_sqlite_core.text)("filename").notNull(),
77
+ originalName: (0, import_sqlite_core.text)("original_name").notNull(),
78
+ mimeType: (0, import_sqlite_core.text)("mime_type").notNull(),
79
+ size: (0, import_sqlite_core.integer)("size").notNull(),
80
+ width: (0, import_sqlite_core.integer)("width"),
81
+ height: (0, import_sqlite_core.integer)("height"),
82
+ alt: (0, import_sqlite_core.text)("alt"),
83
+ tags: (0, import_sqlite_core.text)("tags"),
84
+ // JSON array
85
+ url: (0, import_sqlite_core.text)("url").notNull(),
86
+ thumbnailUrl: (0, import_sqlite_core.text)("thumbnail_url"),
87
+ createdAt: (0, import_sqlite_core.text)("created_at").notNull(),
88
+ createdBy: (0, import_sqlite_core.text)("created_by").notNull()
89
+ });
90
+ templates = (0, import_sqlite_core.sqliteTable)("templates", {
91
+ id: (0, import_sqlite_core.text)("id").primaryKey(),
92
+ teamId: (0, import_sqlite_core.text)("team_id").notNull(),
93
+ name: (0, import_sqlite_core.text)("name").notNull(),
94
+ content: (0, import_sqlite_core.text)("content").notNull(),
95
+ variables: (0, import_sqlite_core.text)("variables"),
96
+ // JSON array of variable definitions
97
+ tags: (0, import_sqlite_core.text)("tags"),
98
+ // JSON array
99
+ createdAt: (0, import_sqlite_core.text)("created_at").notNull(),
100
+ updatedAt: (0, import_sqlite_core.text)("updated_at").notNull(),
101
+ createdBy: (0, import_sqlite_core.text)("created_by").notNull()
102
+ });
103
+ socialAccounts = (0, import_sqlite_core.sqliteTable)("social_accounts", {
104
+ id: (0, import_sqlite_core.text)("id").primaryKey(),
105
+ teamId: (0, import_sqlite_core.text)("team_id").notNull(),
106
+ platform: (0, import_sqlite_core.text)("platform").notNull(),
107
+ // twitter, linkedin, instagram, etc.
108
+ displayName: (0, import_sqlite_core.text)("display_name").notNull(),
109
+ username: (0, import_sqlite_core.text)("username"),
110
+ avatar: (0, import_sqlite_core.text)("avatar"),
111
+ isActive: (0, import_sqlite_core.integer)("is_active", { mode: "boolean" }).notNull().default(true),
112
+ credentials: (0, import_sqlite_core.blob)("credentials").notNull(),
113
+ // Encrypted JSON
114
+ settings: (0, import_sqlite_core.text)("settings"),
115
+ // JSON object
116
+ lastSync: (0, import_sqlite_core.text)("last_sync"),
117
+ createdAt: (0, import_sqlite_core.text)("created_at").notNull(),
118
+ updatedAt: (0, import_sqlite_core.text)("updated_at").notNull()
119
+ });
120
+ postMetrics = (0, import_sqlite_core.sqliteTable)("post_metrics", {
121
+ id: (0, import_sqlite_core.text)("id").primaryKey(),
122
+ postId: (0, import_sqlite_core.text)("post_id").notNull(),
123
+ platform: (0, import_sqlite_core.text)("platform").notNull(),
124
+ impressions: (0, import_sqlite_core.integer)("impressions").default(0),
125
+ likes: (0, import_sqlite_core.integer)("likes").default(0),
126
+ shares: (0, import_sqlite_core.integer)("shares").default(0),
127
+ comments: (0, import_sqlite_core.integer)("comments").default(0),
128
+ clicks: (0, import_sqlite_core.integer)("clicks").default(0),
129
+ engagementRate: (0, import_sqlite_core.text)("engagement_rate"),
130
+ // Stored as string to avoid float precision issues
131
+ syncedAt: (0, import_sqlite_core.text)("synced_at").notNull()
132
+ });
133
+ accountMetrics = (0, import_sqlite_core.sqliteTable)("account_metrics", {
134
+ id: (0, import_sqlite_core.text)("id").primaryKey(),
135
+ accountId: (0, import_sqlite_core.text)("account_id").notNull(),
136
+ date: (0, import_sqlite_core.text)("date").notNull(),
137
+ // YYYY-MM-DD format
138
+ followers: (0, import_sqlite_core.integer)("followers").default(0),
139
+ following: (0, import_sqlite_core.integer)("following").default(0),
140
+ posts: (0, import_sqlite_core.integer)("posts").default(0),
141
+ engagement: (0, import_sqlite_core.integer)("engagement").default(0),
142
+ reach: (0, import_sqlite_core.integer)("reach").default(0),
143
+ syncedAt: (0, import_sqlite_core.text)("synced_at").notNull()
144
+ });
145
+ webhooks = (0, import_sqlite_core.sqliteTable)("webhooks", {
146
+ id: (0, import_sqlite_core.text)("id").primaryKey(),
147
+ teamId: (0, import_sqlite_core.text)("team_id").notNull(),
148
+ url: (0, import_sqlite_core.text)("url").notNull(),
149
+ events: (0, import_sqlite_core.text)("events").notNull(),
150
+ // JSON array
151
+ secret: (0, import_sqlite_core.text)("secret"),
152
+ isActive: (0, import_sqlite_core.integer)("is_active", { mode: "boolean" }).notNull().default(true),
153
+ createdAt: (0, import_sqlite_core.text)("created_at").notNull(),
154
+ lastTriggered: (0, import_sqlite_core.text)("last_triggered")
155
+ });
156
+ postsRelations = (0, import_drizzle_orm.relations)(posts, ({ many }) => ({
157
+ metrics: many(postMetrics)
158
+ }));
159
+ postMetricsRelations = (0, import_drizzle_orm.relations)(postMetrics, ({ one }) => ({
160
+ post: one(posts, {
161
+ fields: [postMetrics.postId],
162
+ references: [posts.id]
163
+ })
164
+ }));
165
+ socialAccountsRelations = (0, import_drizzle_orm.relations)(socialAccounts, ({ many }) => ({
166
+ metrics: many(accountMetrics)
167
+ }));
168
+ accountMetricsRelations = (0, import_drizzle_orm.relations)(accountMetrics, ({ one }) => ({
169
+ account: one(socialAccounts, {
170
+ fields: [accountMetrics.accountId],
171
+ references: [socialAccounts.id]
172
+ })
173
+ }));
174
+ }
175
+ });
176
+
177
+ // src/db/index.ts
178
+ function createDatabase(teamId) {
179
+ const dbPath = process.env.KITCHEN_PLUGIN_DB_PATH || "./data";
180
+ const teamDbFile = `${dbPath}/marketing-${teamId}.db`;
181
+ const sqlite = new import_better_sqlite3.default(teamDbFile);
182
+ const db = (0, import_better_sqlite32.drizzle)(sqlite, { schema: schema_exports });
183
+ return { db, sqlite };
184
+ }
185
+ function encryptCredentials(credentials) {
186
+ const plaintext = JSON.stringify(credentials);
187
+ const hash = (0, import_crypto.createHash)("sha256").update(ENCRYPTION_KEY).digest();
188
+ const cipher = (0, import_crypto.createCipher)("aes-256-cbc", hash);
189
+ let encrypted = cipher.update(plaintext, "utf8", "hex");
190
+ encrypted += cipher.final("hex");
191
+ return Buffer.from(encrypted, "hex");
192
+ }
193
+ function decryptCredentials(encryptedData) {
194
+ const hash = (0, import_crypto.createHash)("sha256").update(ENCRYPTION_KEY).digest();
195
+ const decipher = (0, import_crypto.createDecipher)("aes-256-cbc", hash);
196
+ let decrypted = decipher.update(encryptedData.toString("hex"), "hex", "utf8");
197
+ decrypted += decipher.final("utf8");
198
+ return JSON.parse(decrypted);
199
+ }
200
+ function initializeDatabase(teamId) {
201
+ const { db, sqlite } = createDatabase(teamId);
202
+ try {
203
+ (0, import_migrator.migrate)(db, { migrationsFolder: "./db/migrations" });
204
+ } catch (error) {
205
+ console.warn("Migration warning:", error.message);
206
+ }
207
+ return { db, sqlite };
208
+ }
209
+ var import_better_sqlite3, import_better_sqlite32, import_migrator, import_crypto, ENCRYPTION_KEY;
210
+ var init_db = __esm({
211
+ "src/db/index.ts"() {
212
+ import_better_sqlite3 = __toESM(require("better-sqlite3"));
213
+ import_better_sqlite32 = require("drizzle-orm/better-sqlite3");
214
+ init_schema();
215
+ import_migrator = require("drizzle-orm/better-sqlite3/migrator");
216
+ import_crypto = require("crypto");
217
+ ENCRYPTION_KEY = process.env.KITCHEN_ENCRYPTION_KEY || "fallback-key-change-in-production";
218
+ }
219
+ });
220
+
221
+ // src/api/templates.ts
222
+ var templates_exports = {};
223
+ __export(templates_exports, {
224
+ registerTemplateRoutes: () => registerTemplateRoutes
225
+ });
226
+ function getTeamId(req) {
227
+ return req.headers["x-team-id"] || req.query.teamId;
228
+ }
229
+ function getUserId(req) {
230
+ return req.headers["x-user-id"] || "system";
231
+ }
232
+ function sendError(res, status, error, message, details) {
233
+ const response = { error, message, details };
234
+ res.status(status).json(response);
235
+ }
236
+ function parsePagination(req) {
237
+ const limit = Math.min(parseInt(req.query.limit) || 20, 100);
238
+ const offset = parseInt(req.query.offset) || 0;
239
+ return { limit, offset };
240
+ }
241
+ function registerTemplateRoutes(app) {
242
+ app.get("/templates", async (req, res) => {
243
+ try {
244
+ const teamId = getTeamId(req);
245
+ if (!teamId) return sendError(res, 400, "MISSING_TEAM_ID", "Team ID is required");
246
+ const { db } = initializeDatabase(teamId);
247
+ const { limit, offset } = parsePagination(req);
248
+ const conditions = [(0, import_drizzle_orm2.eq)(templates.teamId, teamId)];
249
+ if (req.query.tag) {
250
+ conditions.push((0, import_drizzle_orm2.like)(templates.tags, `%"${req.query.tag}"%`));
251
+ }
252
+ const templates2 = await db.select().from(templates).where((0, import_drizzle_orm2.and)(...conditions)).orderBy((0, import_drizzle_orm2.desc)(templates.createdAt)).limit(limit).offset(offset);
253
+ const response = templates2.map((template) => ({
254
+ id: template.id,
255
+ name: template.name,
256
+ content: template.content,
257
+ variables: JSON.parse(template.variables || "[]"),
258
+ tags: JSON.parse(template.tags || "[]"),
259
+ createdAt: template.createdAt,
260
+ updatedAt: template.updatedAt,
261
+ createdBy: template.createdBy
262
+ }));
263
+ res.json({ templates: response });
264
+ } catch (error) {
265
+ sendError(res, 500, "DATABASE_ERROR", error.message);
266
+ }
267
+ });
268
+ app.post("/templates", async (req, res) => {
269
+ try {
270
+ const teamId = getTeamId(req);
271
+ const userId = getUserId(req);
272
+ if (!teamId) return sendError(res, 400, "MISSING_TEAM_ID", "Team ID is required");
273
+ const body = req.body;
274
+ if (!body.name || !body.content) {
275
+ return sendError(res, 400, "VALIDATION_ERROR", "Name and content are required");
276
+ }
277
+ const { db } = initializeDatabase(teamId);
278
+ const now = (/* @__PURE__ */ new Date()).toISOString();
279
+ const newTemplate = {
280
+ id: (0, import_crypto2.randomUUID)(),
281
+ teamId,
282
+ name: body.name,
283
+ content: body.content,
284
+ variables: JSON.stringify(body.variables || []),
285
+ tags: JSON.stringify(body.tags || []),
286
+ createdAt: now,
287
+ updatedAt: now,
288
+ createdBy: userId
289
+ };
290
+ await db.insert(templates).values(newTemplate);
291
+ const response = {
292
+ id: newTemplate.id,
293
+ name: newTemplate.name,
294
+ content: newTemplate.content,
295
+ variables: JSON.parse(newTemplate.variables),
296
+ tags: JSON.parse(newTemplate.tags),
297
+ createdAt: newTemplate.createdAt,
298
+ updatedAt: newTemplate.updatedAt,
299
+ createdBy: newTemplate.createdBy
300
+ };
301
+ res.status(201).json(response);
302
+ } catch (error) {
303
+ sendError(res, 500, "DATABASE_ERROR", error.message);
304
+ }
305
+ });
306
+ app.get("/templates/:id", async (req, res) => {
307
+ try {
308
+ const teamId = getTeamId(req);
309
+ if (!teamId) return sendError(res, 400, "MISSING_TEAM_ID", "Team ID is required");
310
+ const { db } = initializeDatabase(teamId);
311
+ const template = await db.select().from(templates).where((0, import_drizzle_orm2.and)(
312
+ (0, import_drizzle_orm2.eq)(templates.id, req.params.id),
313
+ (0, import_drizzle_orm2.eq)(templates.teamId, teamId)
314
+ )).get();
315
+ if (!template) {
316
+ return sendError(res, 404, "TEMPLATE_NOT_FOUND", "Template not found");
317
+ }
318
+ const response = {
319
+ id: template.id,
320
+ name: template.name,
321
+ content: template.content,
322
+ variables: JSON.parse(template.variables || "[]"),
323
+ tags: JSON.parse(template.tags || "[]"),
324
+ createdAt: template.createdAt,
325
+ updatedAt: template.updatedAt,
326
+ createdBy: template.createdBy
327
+ };
328
+ res.json(response);
329
+ } catch (error) {
330
+ sendError(res, 500, "DATABASE_ERROR", error.message);
331
+ }
332
+ });
333
+ app.put("/templates/:id", async (req, res) => {
334
+ try {
335
+ const teamId = getTeamId(req);
336
+ if (!teamId) return sendError(res, 400, "MISSING_TEAM_ID", "Team ID is required");
337
+ const { db } = initializeDatabase(teamId);
338
+ const body = req.body;
339
+ const updateData = {
340
+ updatedAt: (/* @__PURE__ */ new Date()).toISOString()
341
+ };
342
+ if (body.name !== void 0) updateData.name = body.name;
343
+ if (body.content !== void 0) updateData.content = body.content;
344
+ if (body.variables !== void 0) updateData.variables = JSON.stringify(body.variables);
345
+ if (body.tags !== void 0) updateData.tags = JSON.stringify(body.tags);
346
+ const result = await db.update(templates).set(updateData).where((0, import_drizzle_orm2.and)(
347
+ (0, import_drizzle_orm2.eq)(templates.id, req.params.id),
348
+ (0, import_drizzle_orm2.eq)(templates.teamId, teamId)
349
+ ));
350
+ if (result.changes === 0) {
351
+ return sendError(res, 404, "TEMPLATE_NOT_FOUND", "Template not found");
352
+ }
353
+ const updatedTemplate = await db.select().from(templates).where((0, import_drizzle_orm2.eq)(templates.id, req.params.id)).get();
354
+ const response = {
355
+ id: updatedTemplate.id,
356
+ name: updatedTemplate.name,
357
+ content: updatedTemplate.content,
358
+ variables: JSON.parse(updatedTemplate.variables || "[]"),
359
+ tags: JSON.parse(updatedTemplate.tags || "[]"),
360
+ createdAt: updatedTemplate.createdAt,
361
+ updatedAt: updatedTemplate.updatedAt,
362
+ createdBy: updatedTemplate.createdBy
363
+ };
364
+ res.json(response);
365
+ } catch (error) {
366
+ sendError(res, 500, "DATABASE_ERROR", error.message);
367
+ }
368
+ });
369
+ app.delete("/templates/:id", async (req, res) => {
370
+ try {
371
+ const teamId = getTeamId(req);
372
+ if (!teamId) return sendError(res, 400, "MISSING_TEAM_ID", "Team ID is required");
373
+ const { db } = initializeDatabase(teamId);
374
+ const result = await db.delete(templates).where((0, import_drizzle_orm2.and)(
375
+ (0, import_drizzle_orm2.eq)(templates.id, req.params.id),
376
+ (0, import_drizzle_orm2.eq)(templates.teamId, teamId)
377
+ ));
378
+ if (result.changes === 0) {
379
+ return sendError(res, 404, "TEMPLATE_NOT_FOUND", "Template not found");
380
+ }
381
+ res.status(204).send();
382
+ } catch (error) {
383
+ sendError(res, 500, "DATABASE_ERROR", error.message);
384
+ }
385
+ });
386
+ }
387
+ var import_drizzle_orm2, import_crypto2;
388
+ var init_templates = __esm({
389
+ "src/api/templates.ts"() {
390
+ import_drizzle_orm2 = require("drizzle-orm");
391
+ init_db();
392
+ init_schema();
393
+ import_crypto2 = require("crypto");
394
+ }
395
+ });
396
+
397
+ // src/api/social-accounts.ts
398
+ var social_accounts_exports = {};
399
+ __export(social_accounts_exports, {
400
+ registerSocialAccountRoutes: () => registerSocialAccountRoutes
401
+ });
402
+ function getTeamId2(req) {
403
+ return req.headers["x-team-id"] || req.query.teamId;
404
+ }
405
+ function getUserId2(req) {
406
+ return req.headers["x-user-id"] || "system";
407
+ }
408
+ function sendError2(res, status, error, message, details) {
409
+ const response = { error, message, details };
410
+ res.status(status).json(response);
411
+ }
412
+ function registerSocialAccountRoutes(app) {
413
+ app.get("/accounts", async (req, res) => {
414
+ try {
415
+ const teamId = getTeamId2(req);
416
+ if (!teamId) return sendError2(res, 400, "MISSING_TEAM_ID", "Team ID is required");
417
+ const { db } = initializeDatabase(teamId);
418
+ const accounts = await db.select().from(socialAccounts).where((0, import_drizzle_orm3.eq)(socialAccounts.teamId, teamId)).orderBy((0, import_drizzle_orm3.desc)(socialAccounts.createdAt));
419
+ const response = accounts.map((account) => ({
420
+ id: account.id,
421
+ platform: account.platform,
422
+ displayName: account.displayName,
423
+ username: account.username || void 0,
424
+ avatar: account.avatar || void 0,
425
+ isActive: account.isActive,
426
+ settings: JSON.parse(account.settings || "{}"),
427
+ lastSync: account.lastSync || void 0,
428
+ createdAt: account.createdAt,
429
+ updatedAt: account.updatedAt
430
+ // Note: credentials are never returned for security
431
+ }));
432
+ res.json({ accounts: response });
433
+ } catch (error) {
434
+ sendError2(res, 500, "DATABASE_ERROR", error.message);
435
+ }
436
+ });
437
+ app.post("/accounts", async (req, res) => {
438
+ try {
439
+ const teamId = getTeamId2(req);
440
+ const userId = getUserId2(req);
441
+ if (!teamId) return sendError2(res, 400, "MISSING_TEAM_ID", "Team ID is required");
442
+ const body = req.body;
443
+ if (!body.platform || !body.displayName || !body.credentials) {
444
+ return sendError2(res, 400, "VALIDATION_ERROR", "Platform, displayName, and credentials are required");
445
+ }
446
+ const { db } = initializeDatabase(teamId);
447
+ const now = (/* @__PURE__ */ new Date()).toISOString();
448
+ const newAccount = {
449
+ id: (0, import_crypto3.randomUUID)(),
450
+ teamId,
451
+ platform: body.platform,
452
+ displayName: body.displayName,
453
+ username: body.username || null,
454
+ avatar: null,
455
+ isActive: true,
456
+ credentials: encryptCredentials(body.credentials),
457
+ settings: JSON.stringify(body.settings || {}),
458
+ lastSync: null,
459
+ createdAt: now,
460
+ updatedAt: now
461
+ };
462
+ await db.insert(socialAccounts).values(newAccount);
463
+ const response = {
464
+ id: newAccount.id,
465
+ platform: newAccount.platform,
466
+ displayName: newAccount.displayName,
467
+ username: newAccount.username || void 0,
468
+ isActive: newAccount.isActive,
469
+ settings: JSON.parse(newAccount.settings),
470
+ createdAt: newAccount.createdAt,
471
+ updatedAt: newAccount.updatedAt
472
+ };
473
+ res.status(201).json(response);
474
+ } catch (error) {
475
+ sendError2(res, 500, "DATABASE_ERROR", error.message);
476
+ }
477
+ });
478
+ app.get("/accounts/:id", async (req, res) => {
479
+ try {
480
+ const teamId = getTeamId2(req);
481
+ if (!teamId) return sendError2(res, 400, "MISSING_TEAM_ID", "Team ID is required");
482
+ const { db } = initializeDatabase(teamId);
483
+ const account = await db.select().from(socialAccounts).where((0, import_drizzle_orm3.and)(
484
+ (0, import_drizzle_orm3.eq)(socialAccounts.id, req.params.id),
485
+ (0, import_drizzle_orm3.eq)(socialAccounts.teamId, teamId)
486
+ )).get();
487
+ if (!account) {
488
+ return sendError2(res, 404, "ACCOUNT_NOT_FOUND", "Account not found");
489
+ }
490
+ const response = {
491
+ id: account.id,
492
+ platform: account.platform,
493
+ displayName: account.displayName,
494
+ username: account.username || void 0,
495
+ avatar: account.avatar || void 0,
496
+ isActive: account.isActive,
497
+ settings: JSON.parse(account.settings || "{}"),
498
+ lastSync: account.lastSync || void 0,
499
+ createdAt: account.createdAt,
500
+ updatedAt: account.updatedAt
501
+ };
502
+ res.json(response);
503
+ } catch (error) {
504
+ sendError2(res, 500, "DATABASE_ERROR", error.message);
505
+ }
506
+ });
507
+ app.put("/accounts/:id", async (req, res) => {
508
+ try {
509
+ const teamId = getTeamId2(req);
510
+ if (!teamId) return sendError2(res, 400, "MISSING_TEAM_ID", "Team ID is required");
511
+ const { db } = initializeDatabase(teamId);
512
+ const body = req.body;
513
+ const updateData = {
514
+ updatedAt: (/* @__PURE__ */ new Date()).toISOString()
515
+ };
516
+ if (body.displayName !== void 0) updateData.displayName = body.displayName;
517
+ if (body.username !== void 0) updateData.username = body.username;
518
+ if (body.avatar !== void 0) updateData.avatar = body.avatar;
519
+ if (body.isActive !== void 0) updateData.isActive = body.isActive;
520
+ if (body.settings !== void 0) updateData.settings = JSON.stringify(body.settings);
521
+ if (body.credentials !== void 0) updateData.credentials = encryptCredentials(body.credentials);
522
+ const result = await db.update(socialAccounts).set(updateData).where((0, import_drizzle_orm3.and)(
523
+ (0, import_drizzle_orm3.eq)(socialAccounts.id, req.params.id),
524
+ (0, import_drizzle_orm3.eq)(socialAccounts.teamId, teamId)
525
+ ));
526
+ if (result.changes === 0) {
527
+ return sendError2(res, 404, "ACCOUNT_NOT_FOUND", "Account not found");
528
+ }
529
+ res.json({ success: true });
530
+ } catch (error) {
531
+ sendError2(res, 500, "DATABASE_ERROR", error.message);
532
+ }
533
+ });
534
+ app.delete("/accounts/:id", async (req, res) => {
535
+ try {
536
+ const teamId = getTeamId2(req);
537
+ if (!teamId) return sendError2(res, 400, "MISSING_TEAM_ID", "Team ID is required");
538
+ const { db } = initializeDatabase(teamId);
539
+ const result = await db.delete(socialAccounts).where((0, import_drizzle_orm3.and)(
540
+ (0, import_drizzle_orm3.eq)(socialAccounts.id, req.params.id),
541
+ (0, import_drizzle_orm3.eq)(socialAccounts.teamId, teamId)
542
+ ));
543
+ if (result.changes === 0) {
544
+ return sendError2(res, 404, "ACCOUNT_NOT_FOUND", "Account not found");
545
+ }
546
+ await db.delete(accountMetrics).where((0, import_drizzle_orm3.eq)(accountMetrics.accountId, req.params.id));
547
+ res.status(204).send();
548
+ } catch (error) {
549
+ sendError2(res, 500, "DATABASE_ERROR", error.message);
550
+ }
551
+ });
552
+ app.get("/accounts/:id/metrics", async (req, res) => {
553
+ try {
554
+ const teamId = getTeamId2(req);
555
+ if (!teamId) return sendError2(res, 400, "MISSING_TEAM_ID", "Team ID is required");
556
+ const { db } = initializeDatabase(teamId);
557
+ const period = req.query.period || "7d";
558
+ const endDate = /* @__PURE__ */ new Date();
559
+ const startDate = /* @__PURE__ */ new Date();
560
+ const days = parseInt(period.replace("d", "")) || 7;
561
+ startDate.setDate(endDate.getDate() - days);
562
+ const account = await db.select().from(socialAccounts).where((0, import_drizzle_orm3.and)(
563
+ (0, import_drizzle_orm3.eq)(socialAccounts.id, req.params.id),
564
+ (0, import_drizzle_orm3.eq)(socialAccounts.teamId, teamId)
565
+ )).get();
566
+ if (!account) {
567
+ return sendError2(res, 404, "ACCOUNT_NOT_FOUND", "Account not found");
568
+ }
569
+ const metrics = await db.select().from(accountMetrics).where((0, import_drizzle_orm3.and)(
570
+ (0, import_drizzle_orm3.eq)(accountMetrics.accountId, req.params.id)
571
+ // Add date range filtering here when implemented
572
+ )).orderBy((0, import_drizzle_orm3.desc)(accountMetrics.date)).limit(parseInt(period.replace("d", "")) || 7);
573
+ const latestMetric = metrics[0];
574
+ const oldestMetric = metrics[metrics.length - 1];
575
+ const followerGrowth = latestMetric && oldestMetric ? (latestMetric.followers || 0) - (oldestMetric.followers || 0) : 0;
576
+ const totalEngagement = metrics.reduce((sum, m) => sum + (m.engagement || 0), 0);
577
+ const response = {
578
+ account: {
579
+ id: account.id,
580
+ platform: account.platform,
581
+ username: account.username
582
+ },
583
+ period,
584
+ metrics: {
585
+ followerGrowth,
586
+ totalEngagement,
587
+ averageEngagement: metrics.length > 0 ? totalEngagement / metrics.length : 0,
588
+ currentFollowers: latestMetric?.followers || 0,
589
+ currentFollowing: latestMetric?.following || 0
590
+ },
591
+ dailyMetrics: metrics.map((m) => ({
592
+ date: m.date,
593
+ followers: m.followers || 0,
594
+ following: m.following || 0,
595
+ posts: m.posts || 0,
596
+ engagement: m.engagement || 0,
597
+ reach: m.reach || 0
598
+ }))
599
+ };
600
+ res.json(response);
601
+ } catch (error) {
602
+ sendError2(res, 500, "DATABASE_ERROR", error.message);
603
+ }
604
+ });
605
+ }
606
+ var import_drizzle_orm3, import_crypto3;
607
+ var init_social_accounts = __esm({
608
+ "src/api/social-accounts.ts"() {
609
+ import_drizzle_orm3 = require("drizzle-orm");
610
+ init_db();
611
+ init_schema();
612
+ import_crypto3 = require("crypto");
613
+ }
614
+ });
615
+
616
+ // src/api/calendar.ts
617
+ var calendar_exports = {};
618
+ __export(calendar_exports, {
619
+ registerCalendarRoutes: () => registerCalendarRoutes
620
+ });
621
+ function getTeamId3(req) {
622
+ return req.headers["x-team-id"] || req.query.teamId;
623
+ }
624
+ function sendError3(res, status, error, message, details) {
625
+ const response = { error, message, details };
626
+ res.status(status).json(response);
627
+ }
628
+ function formatDate(date) {
629
+ return date.toISOString().split("T")[0];
630
+ }
631
+ function registerCalendarRoutes(app) {
632
+ app.get("/calendar", async (req, res) => {
633
+ try {
634
+ const teamId = getTeamId3(req);
635
+ if (!teamId) return sendError3(res, 400, "MISSING_TEAM_ID", "Team ID is required");
636
+ const { db } = initializeDatabase(teamId);
637
+ const start = req.query.start;
638
+ const end = req.query.end;
639
+ const view = req.query.view || "month";
640
+ if (!start || !end) {
641
+ return sendError3(res, 400, "MISSING_DATES", "Start and end dates are required");
642
+ }
643
+ const posts2 = await db.select().from(posts).where((0, import_drizzle_orm4.and)(
644
+ (0, import_drizzle_orm4.eq)(posts.teamId, teamId),
645
+ (0, import_drizzle_orm4.gte)(posts.scheduledAt, start),
646
+ (0, import_drizzle_orm4.lte)(posts.scheduledAt, end),
647
+ (0, import_drizzle_orm4.eq)(posts.status, "scheduled")
648
+ )).orderBy(posts.scheduledAt);
649
+ const eventsByDate = {};
650
+ const platformCounts = {};
651
+ posts2.forEach((post) => {
652
+ if (!post.scheduledAt) return;
653
+ const date = formatDate(new Date(post.scheduledAt));
654
+ if (!eventsByDate[date]) {
655
+ eventsByDate[date] = [];
656
+ }
657
+ const postResponse = {
658
+ id: post.id,
659
+ content: post.content,
660
+ platforms: JSON.parse(post.platforms || "[]"),
661
+ status: post.status,
662
+ scheduledAt: post.scheduledAt,
663
+ publishedAt: post.publishedAt || void 0,
664
+ tags: JSON.parse(post.tags || "[]"),
665
+ mediaIds: JSON.parse(post.mediaIds || "[]"),
666
+ templateId: post.templateId || void 0,
667
+ createdAt: post.createdAt,
668
+ updatedAt: post.updatedAt,
669
+ createdBy: post.createdBy
670
+ };
671
+ eventsByDate[date].push(postResponse);
672
+ postResponse.platforms.forEach((platform) => {
673
+ platformCounts[platform] = (platformCounts[platform] || 0) + 1;
674
+ });
675
+ });
676
+ const events = Object.entries(eventsByDate).map(([date, posts3]) => ({
677
+ date,
678
+ posts: posts3
679
+ }));
680
+ const response = {
681
+ view,
682
+ period: `${start} to ${end}`,
683
+ events,
684
+ summary: {
685
+ totalScheduled: posts2.length,
686
+ byPlatform: platformCounts
687
+ }
688
+ };
689
+ res.json(response);
690
+ } catch (error) {
691
+ sendError3(res, 500, "DATABASE_ERROR", error.message);
692
+ }
693
+ });
694
+ app.post("/calendar/schedule", async (req, res) => {
695
+ try {
696
+ const teamId = getTeamId3(req);
697
+ if (!teamId) return sendError3(res, 400, "MISSING_TEAM_ID", "Team ID is required");
698
+ const { postId, scheduledAt, platforms } = req.body;
699
+ if (!postId || !scheduledAt) {
700
+ return sendError3(res, 400, "VALIDATION_ERROR", "postId and scheduledAt are required");
701
+ }
702
+ const { db } = initializeDatabase(teamId);
703
+ const updateData = {
704
+ scheduledAt,
705
+ status: "scheduled",
706
+ updatedAt: (/* @__PURE__ */ new Date()).toISOString()
707
+ };
708
+ if (platforms) {
709
+ updateData.platforms = JSON.stringify(platforms);
710
+ }
711
+ const result = await db.update(posts).set(updateData).where((0, import_drizzle_orm4.and)(
712
+ (0, import_drizzle_orm4.eq)(posts.id, postId),
713
+ (0, import_drizzle_orm4.eq)(posts.teamId, teamId)
714
+ ));
715
+ if (result.changes === 0) {
716
+ return sendError3(res, 404, "POST_NOT_FOUND", "Post not found");
717
+ }
718
+ res.json({ success: true, scheduledAt });
719
+ } catch (error) {
720
+ sendError3(res, 500, "DATABASE_ERROR", error.message);
721
+ }
722
+ });
723
+ app.get("/calendar/scheduled", async (req, res) => {
724
+ try {
725
+ const teamId = getTeamId3(req);
726
+ if (!teamId) return sendError3(res, 400, "MISSING_TEAM_ID", "Team ID is required");
727
+ const { db } = initializeDatabase(teamId);
728
+ const posts2 = await db.select().from(posts).where((0, import_drizzle_orm4.and)(
729
+ (0, import_drizzle_orm4.eq)(posts.teamId, teamId),
730
+ (0, import_drizzle_orm4.eq)(posts.status, "scheduled")
731
+ )).orderBy(posts.scheduledAt);
732
+ const response = posts2.map((post) => ({
733
+ id: post.id,
734
+ content: post.content,
735
+ platforms: JSON.parse(post.platforms || "[]"),
736
+ status: post.status,
737
+ scheduledAt: post.scheduledAt || void 0,
738
+ publishedAt: post.publishedAt || void 0,
739
+ tags: JSON.parse(post.tags || "[]"),
740
+ mediaIds: JSON.parse(post.mediaIds || "[]"),
741
+ templateId: post.templateId || void 0,
742
+ createdAt: post.createdAt,
743
+ updatedAt: post.updatedAt,
744
+ createdBy: post.createdBy
745
+ }));
746
+ res.json({ scheduled: response });
747
+ } catch (error) {
748
+ sendError3(res, 500, "DATABASE_ERROR", error.message);
749
+ }
750
+ });
751
+ app.put("/calendar/scheduled/:id", async (req, res) => {
752
+ try {
753
+ const teamId = getTeamId3(req);
754
+ if (!teamId) return sendError3(res, 400, "MISSING_TEAM_ID", "Team ID is required");
755
+ const { scheduledAt, platforms } = req.body;
756
+ if (!scheduledAt) {
757
+ return sendError3(res, 400, "VALIDATION_ERROR", "scheduledAt is required");
758
+ }
759
+ const { db } = initializeDatabase(teamId);
760
+ const updateData = {
761
+ scheduledAt,
762
+ updatedAt: (/* @__PURE__ */ new Date()).toISOString()
763
+ };
764
+ if (platforms) {
765
+ updateData.platforms = JSON.stringify(platforms);
766
+ }
767
+ const result = await db.update(posts).set(updateData).where((0, import_drizzle_orm4.and)(
768
+ (0, import_drizzle_orm4.eq)(posts.id, req.params.id),
769
+ (0, import_drizzle_orm4.eq)(posts.teamId, teamId),
770
+ (0, import_drizzle_orm4.eq)(posts.status, "scheduled")
771
+ ));
772
+ if (result.changes === 0) {
773
+ return sendError3(res, 404, "SCHEDULED_POST_NOT_FOUND", "Scheduled post not found");
774
+ }
775
+ res.json({ success: true, scheduledAt });
776
+ } catch (error) {
777
+ sendError3(res, 500, "DATABASE_ERROR", error.message);
778
+ }
779
+ });
780
+ app.post("/calendar/bulk-schedule", async (req, res) => {
781
+ try {
782
+ const teamId = getTeamId3(req);
783
+ const userId = req.headers["x-user-id"] || "system";
784
+ if (!teamId) return sendError3(res, 400, "MISSING_TEAM_ID", "Team ID is required");
785
+ const { posts: posts2 } = req.body;
786
+ if (!Array.isArray(posts2) || posts2.length === 0) {
787
+ return sendError3(res, 400, "VALIDATION_ERROR", "Posts array is required");
788
+ }
789
+ const { db } = initializeDatabase(teamId);
790
+ const now = (/* @__PURE__ */ new Date()).toISOString();
791
+ const createdPosts = [];
792
+ for (const postData of posts2) {
793
+ if (!postData.content || !postData.scheduledAt || !postData.platforms?.length) {
794
+ continue;
795
+ }
796
+ const newPost = {
797
+ id: require("crypto").randomUUID(),
798
+ teamId,
799
+ content: postData.content,
800
+ platforms: JSON.stringify(postData.platforms),
801
+ status: "scheduled",
802
+ scheduledAt: postData.scheduledAt,
803
+ publishedAt: null,
804
+ tags: JSON.stringify(postData.tags || []),
805
+ mediaIds: JSON.stringify(postData.mediaIds || []),
806
+ templateId: postData.templateId || null,
807
+ createdAt: now,
808
+ updatedAt: now,
809
+ createdBy: userId
810
+ };
811
+ await db.insert(posts).values(newPost);
812
+ createdPosts.push({
813
+ id: newPost.id,
814
+ content: newPost.content,
815
+ platforms: JSON.parse(newPost.platforms),
816
+ status: newPost.status,
817
+ scheduledAt: newPost.scheduledAt || void 0,
818
+ tags: JSON.parse(newPost.tags),
819
+ mediaIds: JSON.parse(newPost.mediaIds),
820
+ templateId: newPost.templateId || void 0,
821
+ createdAt: newPost.createdAt,
822
+ updatedAt: newPost.updatedAt,
823
+ createdBy: newPost.createdBy
824
+ });
825
+ }
826
+ res.status(201).json({
827
+ success: true,
828
+ created: createdPosts.length,
829
+ posts: createdPosts
830
+ });
831
+ } catch (error) {
832
+ sendError3(res, 500, "DATABASE_ERROR", error.message);
833
+ }
834
+ });
835
+ }
836
+ var import_drizzle_orm4;
837
+ var init_calendar = __esm({
838
+ "src/api/calendar.ts"() {
839
+ import_drizzle_orm4 = require("drizzle-orm");
840
+ init_db();
841
+ init_schema();
842
+ }
843
+ });
844
+
845
+ // src/api/webhooks.ts
846
+ var webhooks_exports = {};
847
+ __export(webhooks_exports, {
848
+ registerWebhookRoutes: () => registerWebhookRoutes
849
+ });
850
+ function getTeamId4(req) {
851
+ return req.headers["x-team-id"] || req.query.teamId;
852
+ }
853
+ function sendError4(res, status, error, message, details) {
854
+ const response = { error, message, details };
855
+ res.status(status).json(response);
856
+ }
857
+ function registerWebhookRoutes(app) {
858
+ app.get("/webhooks", async (req, res) => {
859
+ try {
860
+ const teamId = getTeamId4(req);
861
+ if (!teamId) return sendError4(res, 400, "MISSING_TEAM_ID", "Team ID is required");
862
+ const { db } = initializeDatabase(teamId);
863
+ const webhooks2 = await db.select().from(webhooks).where((0, import_drizzle_orm5.eq)(webhooks.teamId, teamId)).orderBy((0, import_drizzle_orm5.desc)(webhooks.createdAt));
864
+ const response = webhooks2.map((webhook) => ({
865
+ id: webhook.id,
866
+ url: webhook.url,
867
+ events: JSON.parse(webhook.events || "[]"),
868
+ isActive: webhook.isActive,
869
+ createdAt: webhook.createdAt,
870
+ lastTriggered: webhook.lastTriggered || void 0
871
+ }));
872
+ res.json({ webhooks: response });
873
+ } catch (error) {
874
+ sendError4(res, 500, "DATABASE_ERROR", error.message);
875
+ }
876
+ });
877
+ app.post("/webhooks", async (req, res) => {
878
+ try {
879
+ const teamId = getTeamId4(req);
880
+ if (!teamId) return sendError4(res, 400, "MISSING_TEAM_ID", "Team ID is required");
881
+ const body = req.body;
882
+ if (!body.url || !body.events?.length) {
883
+ return sendError4(res, 400, "VALIDATION_ERROR", "URL and events are required");
884
+ }
885
+ try {
886
+ new URL(body.url);
887
+ } catch {
888
+ return sendError4(res, 400, "INVALID_URL", "Invalid webhook URL");
889
+ }
890
+ const { db } = initializeDatabase(teamId);
891
+ const now = (/* @__PURE__ */ new Date()).toISOString();
892
+ const newWebhook = {
893
+ id: (0, import_crypto4.randomUUID)(),
894
+ teamId,
895
+ url: body.url,
896
+ events: JSON.stringify(body.events),
897
+ secret: body.secret || null,
898
+ isActive: true,
899
+ createdAt: now,
900
+ lastTriggered: null
901
+ };
902
+ await db.insert(webhooks).values(newWebhook);
903
+ const response = {
904
+ id: newWebhook.id,
905
+ url: newWebhook.url,
906
+ events: JSON.parse(newWebhook.events),
907
+ isActive: newWebhook.isActive,
908
+ createdAt: newWebhook.createdAt
909
+ };
910
+ res.status(201).json(response);
911
+ } catch (error) {
912
+ sendError4(res, 500, "DATABASE_ERROR", error.message);
913
+ }
914
+ });
915
+ app.get("/webhooks/:id", async (req, res) => {
916
+ try {
917
+ const teamId = getTeamId4(req);
918
+ if (!teamId) return sendError4(res, 400, "MISSING_TEAM_ID", "Team ID is required");
919
+ const { db } = initializeDatabase(teamId);
920
+ const webhook = await db.select().from(webhooks).where((0, import_drizzle_orm5.and)(
921
+ (0, import_drizzle_orm5.eq)(webhooks.id, req.params.id),
922
+ (0, import_drizzle_orm5.eq)(webhooks.teamId, teamId)
923
+ )).get();
924
+ if (!webhook) {
925
+ return sendError4(res, 404, "WEBHOOK_NOT_FOUND", "Webhook not found");
926
+ }
927
+ const response = {
928
+ id: webhook.id,
929
+ url: webhook.url,
930
+ events: JSON.parse(webhook.events || "[]"),
931
+ isActive: webhook.isActive,
932
+ createdAt: webhook.createdAt,
933
+ lastTriggered: webhook.lastTriggered || void 0
934
+ };
935
+ res.json(response);
936
+ } catch (error) {
937
+ sendError4(res, 500, "DATABASE_ERROR", error.message);
938
+ }
939
+ });
940
+ app.put("/webhooks/:id", async (req, res) => {
941
+ try {
942
+ const teamId = getTeamId4(req);
943
+ if (!teamId) return sendError4(res, 400, "MISSING_TEAM_ID", "Team ID is required");
944
+ const { db } = initializeDatabase(teamId);
945
+ const body = req.body;
946
+ const updateData = {};
947
+ if (body.url !== void 0) {
948
+ try {
949
+ new URL(body.url);
950
+ updateData.url = body.url;
951
+ } catch {
952
+ return sendError4(res, 400, "INVALID_URL", "Invalid webhook URL");
953
+ }
954
+ }
955
+ if (body.events !== void 0) updateData.events = JSON.stringify(body.events);
956
+ if (body.secret !== void 0) updateData.secret = body.secret;
957
+ if (body.isActive !== void 0) updateData.isActive = body.isActive;
958
+ const result = await db.update(webhooks).set(updateData).where((0, import_drizzle_orm5.and)(
959
+ (0, import_drizzle_orm5.eq)(webhooks.id, req.params.id),
960
+ (0, import_drizzle_orm5.eq)(webhooks.teamId, teamId)
961
+ ));
962
+ if (result.changes === 0) {
963
+ return sendError4(res, 404, "WEBHOOK_NOT_FOUND", "Webhook not found");
964
+ }
965
+ res.json({ success: true });
966
+ } catch (error) {
967
+ sendError4(res, 500, "DATABASE_ERROR", error.message);
968
+ }
969
+ });
970
+ app.delete("/webhooks/:id", async (req, res) => {
971
+ try {
972
+ const teamId = getTeamId4(req);
973
+ if (!teamId) return sendError4(res, 400, "MISSING_TEAM_ID", "Team ID is required");
974
+ const { db } = initializeDatabase(teamId);
975
+ const result = await db.delete(webhooks).where((0, import_drizzle_orm5.and)(
976
+ (0, import_drizzle_orm5.eq)(webhooks.id, req.params.id),
977
+ (0, import_drizzle_orm5.eq)(webhooks.teamId, teamId)
978
+ ));
979
+ if (result.changes === 0) {
980
+ return sendError4(res, 404, "WEBHOOK_NOT_FOUND", "Webhook not found");
981
+ }
982
+ res.status(204).send();
983
+ } catch (error) {
984
+ sendError4(res, 500, "DATABASE_ERROR", error.message);
985
+ }
986
+ });
987
+ app.post("/webhooks/test", async (req, res) => {
988
+ try {
989
+ const teamId = getTeamId4(req);
990
+ if (!teamId) return sendError4(res, 400, "MISSING_TEAM_ID", "Team ID is required");
991
+ const { webhookId, event, data } = req.body;
992
+ if (!webhookId || !event) {
993
+ return sendError4(res, 400, "VALIDATION_ERROR", "webhookId and event are required");
994
+ }
995
+ const { db } = initializeDatabase(teamId);
996
+ const webhook = await db.select().from(webhooks).where((0, import_drizzle_orm5.and)(
997
+ (0, import_drizzle_orm5.eq)(webhooks.id, webhookId),
998
+ (0, import_drizzle_orm5.eq)(webhooks.teamId, teamId),
999
+ (0, import_drizzle_orm5.eq)(webhooks.isActive, true)
1000
+ )).get();
1001
+ if (!webhook) {
1002
+ return sendError4(res, 404, "WEBHOOK_NOT_FOUND", "Active webhook not found");
1003
+ }
1004
+ const events = JSON.parse(webhook.events || "[]");
1005
+ if (!events.includes(event)) {
1006
+ return sendError4(res, 400, "EVENT_NOT_SUBSCRIBED", "Webhook not subscribed to this event");
1007
+ }
1008
+ const payload = {
1009
+ event,
1010
+ timestamp: (/* @__PURE__ */ new Date()).toISOString(),
1011
+ teamId,
1012
+ data: data || { test: true }
1013
+ };
1014
+ try {
1015
+ const response = await fetch(webhook.url, {
1016
+ method: "POST",
1017
+ headers: {
1018
+ "Content-Type": "application/json",
1019
+ "User-Agent": "KitchenPlugin-Marketing/1.0",
1020
+ ...webhook.secret && {
1021
+ "X-Webhook-Signature": require("crypto").createHmac("sha256", webhook.secret).update(JSON.stringify(payload)).digest("hex")
1022
+ }
1023
+ },
1024
+ body: JSON.stringify(payload),
1025
+ signal: AbortSignal.timeout(1e4)
1026
+ });
1027
+ const responseText = await response.text();
1028
+ await db.update(webhooks).set({ lastTriggered: (/* @__PURE__ */ new Date()).toISOString() }).where((0, import_drizzle_orm5.eq)(webhooks.id, webhookId));
1029
+ res.json({
1030
+ success: response.ok,
1031
+ status: response.status,
1032
+ response: responseText,
1033
+ url: webhook.url
1034
+ });
1035
+ } catch (error) {
1036
+ res.json({
1037
+ success: false,
1038
+ error: error.message,
1039
+ url: webhook.url
1040
+ });
1041
+ }
1042
+ } catch (error) {
1043
+ sendError4(res, 500, "WEBHOOK_TEST_ERROR", error.message);
1044
+ }
1045
+ });
1046
+ }
1047
+ var import_drizzle_orm5, import_crypto4;
1048
+ var init_webhooks = __esm({
1049
+ "src/api/webhooks.ts"() {
1050
+ import_drizzle_orm5 = require("drizzle-orm");
1051
+ init_db();
1052
+ init_schema();
1053
+ import_crypto4 = require("crypto");
1054
+ }
1055
+ });
1056
+
1057
+ // src/index.ts
1058
+ var index_exports = {};
1059
+ __export(index_exports, {
1060
+ createDatabase: () => createDatabase,
1061
+ createRoutes: () => createRoutes,
1062
+ decryptCredentials: () => decryptCredentials,
1063
+ encryptCredentials: () => encryptCredentials,
1064
+ initializeDatabase: () => initializeDatabase,
1065
+ pluginMeta: () => pluginMeta,
1066
+ schema: () => schema_exports
1067
+ });
1068
+ module.exports = __toCommonJS(index_exports);
1069
+
1070
+ // src/api/routes.ts
1071
+ var import_drizzle_orm6 = require("drizzle-orm");
1072
+ init_db();
1073
+ init_schema();
1074
+ var import_crypto5 = require("crypto");
1075
+ var import_multer = __toESM(require("multer"));
1076
+ var import_path = __toESM(require("path"));
1077
+ var import_promises = __toESM(require("fs/promises"));
1078
+ var upload = (0, import_multer.default)({
1079
+ dest: "uploads/",
1080
+ limits: {
1081
+ fileSize: 10 * 1024 * 1024
1082
+ // 10MB limit
1083
+ },
1084
+ fileFilter: (req, file, cb) => {
1085
+ const allowedTypes = ["image/jpeg", "image/png", "image/gif", "image/webp", "video/mp4"];
1086
+ if (allowedTypes.includes(file.mimetype)) {
1087
+ cb(null, true);
1088
+ } else {
1089
+ cb(new Error("Invalid file type"));
1090
+ }
1091
+ }
1092
+ });
1093
+ function getTeamId5(req) {
1094
+ return req.headers["x-team-id"] || req.query.teamId;
1095
+ }
1096
+ function getUserId3(req) {
1097
+ return req.headers["x-user-id"] || "system";
1098
+ }
1099
+ function sendError5(res, status, error, message, details) {
1100
+ const response = { error, message, details };
1101
+ res.status(status).json(response);
1102
+ }
1103
+ function parsePagination2(req) {
1104
+ const limit = Math.min(parseInt(req.query.limit) || 20, 100);
1105
+ const offset = parseInt(req.query.offset) || 0;
1106
+ return { limit, offset };
1107
+ }
1108
+ function createRoutes(app) {
1109
+ app.get("/posts", async (req, res) => {
1110
+ try {
1111
+ const teamId = getTeamId5(req);
1112
+ if (!teamId) return sendError5(res, 400, "MISSING_TEAM_ID", "Team ID is required");
1113
+ const { db } = initializeDatabase(teamId);
1114
+ const { limit, offset } = parsePagination2(req);
1115
+ const conditions = [(0, import_drizzle_orm6.eq)(posts.teamId, teamId)];
1116
+ if (req.query.status) {
1117
+ conditions.push((0, import_drizzle_orm6.eq)(posts.status, req.query.status));
1118
+ }
1119
+ if (req.query.platform) {
1120
+ conditions.push((0, import_drizzle_orm6.like)(posts.platforms, `%"${req.query.platform}"%`));
1121
+ }
1122
+ if (req.query.tag) {
1123
+ conditions.push((0, import_drizzle_orm6.like)(posts.tags, `%"${req.query.tag}"%`));
1124
+ }
1125
+ const totalResult = await db.select({ count: import_drizzle_orm6.sql`count(*)` }).from(posts).where((0, import_drizzle_orm6.and)(...conditions));
1126
+ const total = totalResult[0].count;
1127
+ const posts2 = await db.select().from(posts).where((0, import_drizzle_orm6.and)(...conditions)).orderBy((0, import_drizzle_orm6.desc)(posts.createdAt)).limit(limit).offset(offset);
1128
+ const transformedPosts = posts2.map((post) => ({
1129
+ id: post.id,
1130
+ content: post.content,
1131
+ platforms: JSON.parse(post.platforms || "[]"),
1132
+ status: post.status,
1133
+ scheduledAt: post.scheduledAt || void 0,
1134
+ publishedAt: post.publishedAt || void 0,
1135
+ tags: JSON.parse(post.tags || "[]"),
1136
+ mediaIds: JSON.parse(post.mediaIds || "[]"),
1137
+ templateId: post.templateId || void 0,
1138
+ createdAt: post.createdAt,
1139
+ updatedAt: post.updatedAt,
1140
+ createdBy: post.createdBy
1141
+ }));
1142
+ const response = {
1143
+ data: transformedPosts,
1144
+ total,
1145
+ offset,
1146
+ limit,
1147
+ hasMore: offset + limit < total
1148
+ };
1149
+ res.json(response);
1150
+ } catch (error) {
1151
+ sendError5(res, 500, "DATABASE_ERROR", error.message);
1152
+ }
1153
+ });
1154
+ app.post("/posts", async (req, res) => {
1155
+ try {
1156
+ const teamId = getTeamId5(req);
1157
+ const userId = getUserId3(req);
1158
+ if (!teamId) return sendError5(res, 400, "MISSING_TEAM_ID", "Team ID is required");
1159
+ const body = req.body;
1160
+ if (!body.content || !body.platforms?.length) {
1161
+ return sendError5(res, 400, "VALIDATION_ERROR", "Content and platforms are required");
1162
+ }
1163
+ const { db } = initializeDatabase(teamId);
1164
+ const now = (/* @__PURE__ */ new Date()).toISOString();
1165
+ const newPost = {
1166
+ id: (0, import_crypto5.randomUUID)(),
1167
+ teamId,
1168
+ content: body.content,
1169
+ platforms: JSON.stringify(body.platforms),
1170
+ status: body.status || "draft",
1171
+ scheduledAt: body.scheduledAt || null,
1172
+ publishedAt: null,
1173
+ tags: JSON.stringify(body.tags || []),
1174
+ mediaIds: JSON.stringify(body.mediaIds || []),
1175
+ templateId: body.templateId || null,
1176
+ createdAt: now,
1177
+ updatedAt: now,
1178
+ createdBy: userId
1179
+ };
1180
+ await db.insert(posts).values(newPost);
1181
+ const response = {
1182
+ id: newPost.id,
1183
+ content: newPost.content,
1184
+ platforms: JSON.parse(newPost.platforms),
1185
+ status: newPost.status,
1186
+ scheduledAt: newPost.scheduledAt || void 0,
1187
+ publishedAt: void 0,
1188
+ tags: JSON.parse(newPost.tags),
1189
+ mediaIds: JSON.parse(newPost.mediaIds),
1190
+ templateId: newPost.templateId || void 0,
1191
+ createdAt: newPost.createdAt,
1192
+ updatedAt: newPost.updatedAt,
1193
+ createdBy: newPost.createdBy
1194
+ };
1195
+ res.status(201).json(response);
1196
+ } catch (error) {
1197
+ sendError5(res, 500, "DATABASE_ERROR", error.message);
1198
+ }
1199
+ });
1200
+ app.get("/posts/:id", async (req, res) => {
1201
+ try {
1202
+ const teamId = getTeamId5(req);
1203
+ if (!teamId) return sendError5(res, 400, "MISSING_TEAM_ID", "Team ID is required");
1204
+ const { db } = initializeDatabase(teamId);
1205
+ const post = await db.select().from(posts).where((0, import_drizzle_orm6.and)(
1206
+ (0, import_drizzle_orm6.eq)(posts.id, req.params.id),
1207
+ (0, import_drizzle_orm6.eq)(posts.teamId, teamId)
1208
+ )).get();
1209
+ if (!post) {
1210
+ return sendError5(res, 404, "POST_NOT_FOUND", "Post not found");
1211
+ }
1212
+ const metrics = await db.select().from(postMetrics).where((0, import_drizzle_orm6.eq)(postMetrics.postId, post.id));
1213
+ const platformMetrics = {};
1214
+ metrics.forEach((metric) => {
1215
+ platformMetrics[metric.platform] = {
1216
+ impressions: metric.impressions || 0,
1217
+ likes: metric.likes || 0,
1218
+ shares: metric.shares || 0,
1219
+ comments: metric.comments || 0,
1220
+ clicks: metric.clicks || 0,
1221
+ engagementRate: parseFloat(metric.engagementRate || "0")
1222
+ };
1223
+ });
1224
+ const response = {
1225
+ id: post.id,
1226
+ content: post.content,
1227
+ platforms: JSON.parse(post.platforms || "[]"),
1228
+ status: post.status,
1229
+ scheduledAt: post.scheduledAt || void 0,
1230
+ publishedAt: post.publishedAt || void 0,
1231
+ tags: JSON.parse(post.tags || "[]"),
1232
+ mediaIds: JSON.parse(post.mediaIds || "[]"),
1233
+ templateId: post.templateId || void 0,
1234
+ createdAt: post.createdAt,
1235
+ updatedAt: post.updatedAt,
1236
+ createdBy: post.createdBy,
1237
+ metrics: Object.keys(platformMetrics).length > 0 ? platformMetrics : void 0
1238
+ };
1239
+ res.json(response);
1240
+ } catch (error) {
1241
+ sendError5(res, 500, "DATABASE_ERROR", error.message);
1242
+ }
1243
+ });
1244
+ app.put("/posts/:id", async (req, res) => {
1245
+ try {
1246
+ const teamId = getTeamId5(req);
1247
+ if (!teamId) return sendError5(res, 400, "MISSING_TEAM_ID", "Team ID is required");
1248
+ const { db } = initializeDatabase(teamId);
1249
+ const body = req.body;
1250
+ const updateData = {
1251
+ updatedAt: (/* @__PURE__ */ new Date()).toISOString()
1252
+ };
1253
+ if (body.content !== void 0) updateData.content = body.content;
1254
+ if (body.platforms !== void 0) updateData.platforms = JSON.stringify(body.platforms);
1255
+ if (body.status !== void 0) updateData.status = body.status;
1256
+ if (body.scheduledAt !== void 0) updateData.scheduledAt = body.scheduledAt;
1257
+ if (body.tags !== void 0) updateData.tags = JSON.stringify(body.tags);
1258
+ if (body.mediaIds !== void 0) updateData.mediaIds = JSON.stringify(body.mediaIds);
1259
+ const result = await db.update(posts).set(updateData).where((0, import_drizzle_orm6.and)(
1260
+ (0, import_drizzle_orm6.eq)(posts.id, req.params.id),
1261
+ (0, import_drizzle_orm6.eq)(posts.teamId, teamId)
1262
+ ));
1263
+ if (result.changes === 0) {
1264
+ return sendError5(res, 404, "POST_NOT_FOUND", "Post not found");
1265
+ }
1266
+ const updatedPost = await db.select().from(posts).where((0, import_drizzle_orm6.eq)(posts.id, req.params.id)).get();
1267
+ const response = {
1268
+ id: updatedPost.id,
1269
+ content: updatedPost.content,
1270
+ platforms: JSON.parse(updatedPost.platforms || "[]"),
1271
+ status: updatedPost.status,
1272
+ scheduledAt: updatedPost.scheduledAt || void 0,
1273
+ publishedAt: updatedPost.publishedAt || void 0,
1274
+ tags: JSON.parse(updatedPost.tags || "[]"),
1275
+ mediaIds: JSON.parse(updatedPost.mediaIds || "[]"),
1276
+ templateId: updatedPost.templateId || void 0,
1277
+ createdAt: updatedPost.createdAt,
1278
+ updatedAt: updatedPost.updatedAt,
1279
+ createdBy: updatedPost.createdBy
1280
+ };
1281
+ res.json(response);
1282
+ } catch (error) {
1283
+ sendError5(res, 500, "DATABASE_ERROR", error.message);
1284
+ }
1285
+ });
1286
+ app.delete("/posts/:id", async (req, res) => {
1287
+ try {
1288
+ const teamId = getTeamId5(req);
1289
+ if (!teamId) return sendError5(res, 400, "MISSING_TEAM_ID", "Team ID is required");
1290
+ const { db } = initializeDatabase(teamId);
1291
+ const result = await db.delete(posts).where((0, import_drizzle_orm6.and)(
1292
+ (0, import_drizzle_orm6.eq)(posts.id, req.params.id),
1293
+ (0, import_drizzle_orm6.eq)(posts.teamId, teamId)
1294
+ ));
1295
+ if (result.changes === 0) {
1296
+ return sendError5(res, 404, "POST_NOT_FOUND", "Post not found");
1297
+ }
1298
+ await db.delete(postMetrics).where((0, import_drizzle_orm6.eq)(postMetrics.postId, req.params.id));
1299
+ res.status(204).send();
1300
+ } catch (error) {
1301
+ sendError5(res, 500, "DATABASE_ERROR", error.message);
1302
+ }
1303
+ });
1304
+ app.post("/posts/:id/publish", async (req, res) => {
1305
+ try {
1306
+ const teamId = getTeamId5(req);
1307
+ if (!teamId) return sendError5(res, 400, "MISSING_TEAM_ID", "Team ID is required");
1308
+ const { db } = initializeDatabase(teamId);
1309
+ const { platforms } = req.body;
1310
+ const now = (/* @__PURE__ */ new Date()).toISOString();
1311
+ const updateData = {
1312
+ status: "published",
1313
+ publishedAt: now,
1314
+ updatedAt: now
1315
+ };
1316
+ if (platforms) {
1317
+ updateData.platforms = JSON.stringify(platforms);
1318
+ }
1319
+ const result = await db.update(posts).set(updateData).where((0, import_drizzle_orm6.and)(
1320
+ (0, import_drizzle_orm6.eq)(posts.id, req.params.id),
1321
+ (0, import_drizzle_orm6.eq)(posts.teamId, teamId)
1322
+ ));
1323
+ if (result.changes === 0) {
1324
+ return sendError5(res, 404, "POST_NOT_FOUND", "Post not found");
1325
+ }
1326
+ res.json({ success: true, publishedAt: now });
1327
+ } catch (error) {
1328
+ sendError5(res, 500, "DATABASE_ERROR", error.message);
1329
+ }
1330
+ });
1331
+ app.get("/media", async (req, res) => {
1332
+ try {
1333
+ const teamId = getTeamId5(req);
1334
+ if (!teamId) return sendError5(res, 400, "MISSING_TEAM_ID", "Team ID is required");
1335
+ const { db } = initializeDatabase(teamId);
1336
+ const { limit, offset } = parsePagination2(req);
1337
+ const conditions = [(0, import_drizzle_orm6.eq)(media.teamId, teamId)];
1338
+ if (req.query.tag) {
1339
+ conditions.push((0, import_drizzle_orm6.like)(media.tags, `%"${req.query.tag}"%`));
1340
+ }
1341
+ if (req.query.type) {
1342
+ conditions.push((0, import_drizzle_orm6.like)(media.mimeType, `${req.query.type}%`));
1343
+ }
1344
+ const media2 = await db.select().from(media).where((0, import_drizzle_orm6.and)(...conditions)).orderBy((0, import_drizzle_orm6.desc)(media.createdAt)).limit(limit).offset(offset);
1345
+ const response = media2.map((item) => ({
1346
+ id: item.id,
1347
+ filename: item.filename,
1348
+ originalName: item.originalName,
1349
+ mimeType: item.mimeType,
1350
+ size: item.size,
1351
+ width: item.width || void 0,
1352
+ height: item.height || void 0,
1353
+ alt: item.alt || void 0,
1354
+ tags: JSON.parse(item.tags || "[]"),
1355
+ url: item.url,
1356
+ thumbnailUrl: item.thumbnailUrl || void 0,
1357
+ createdAt: item.createdAt,
1358
+ createdBy: item.createdBy
1359
+ }));
1360
+ res.json({ media: response });
1361
+ } catch (error) {
1362
+ sendError5(res, 500, "DATABASE_ERROR", error.message);
1363
+ }
1364
+ });
1365
+ app.post("/media", upload.single("file"), async (req, res) => {
1366
+ try {
1367
+ const teamId = getTeamId5(req);
1368
+ const userId = getUserId3(req);
1369
+ if (!teamId) return sendError5(res, 400, "MISSING_TEAM_ID", "Team ID is required");
1370
+ if (!req.file) {
1371
+ return sendError5(res, 400, "NO_FILE", "File is required");
1372
+ }
1373
+ const { db } = initializeDatabase(teamId);
1374
+ const body = req.body;
1375
+ const mediaId = (0, import_crypto5.randomUUID)();
1376
+ const filename = `${mediaId}${import_path.default.extname(req.file.originalname)}`;
1377
+ const mediaDir = `./uploads/media/${teamId}`;
1378
+ await import_promises.default.mkdir(mediaDir, { recursive: true });
1379
+ const finalPath = import_path.default.join(mediaDir, filename);
1380
+ await import_promises.default.rename(req.file.path, finalPath);
1381
+ const newMedia = {
1382
+ id: mediaId,
1383
+ teamId,
1384
+ filename,
1385
+ originalName: req.file.originalname,
1386
+ mimeType: req.file.mimetype,
1387
+ size: req.file.size,
1388
+ width: null,
1389
+ // TODO: Extract dimensions for images
1390
+ height: null,
1391
+ alt: body.alt || null,
1392
+ tags: JSON.stringify(body.tags || []),
1393
+ url: `/api/plugins/kitchen-plugin-marketing/media/${mediaId}/file`,
1394
+ thumbnailUrl: null,
1395
+ // TODO: Generate thumbnails
1396
+ createdAt: (/* @__PURE__ */ new Date()).toISOString(),
1397
+ createdBy: userId
1398
+ };
1399
+ await db.insert(media).values(newMedia);
1400
+ const response = {
1401
+ id: newMedia.id,
1402
+ filename: newMedia.filename,
1403
+ originalName: newMedia.originalName,
1404
+ mimeType: newMedia.mimeType,
1405
+ size: newMedia.size,
1406
+ alt: newMedia.alt || void 0,
1407
+ tags: JSON.parse(newMedia.tags),
1408
+ url: newMedia.url,
1409
+ createdAt: newMedia.createdAt,
1410
+ createdBy: newMedia.createdBy
1411
+ };
1412
+ res.status(201).json(response);
1413
+ } catch (error) {
1414
+ sendError5(res, 500, "UPLOAD_ERROR", error.message);
1415
+ }
1416
+ });
1417
+ app.get("/media/:id/file", async (req, res) => {
1418
+ try {
1419
+ const teamId = getTeamId5(req);
1420
+ if (!teamId) return sendError5(res, 400, "MISSING_TEAM_ID", "Team ID is required");
1421
+ const { db } = initializeDatabase(teamId);
1422
+ const media2 = await db.select().from(media).where((0, import_drizzle_orm6.and)(
1423
+ (0, import_drizzle_orm6.eq)(media.id, req.params.id),
1424
+ (0, import_drizzle_orm6.eq)(media.teamId, teamId)
1425
+ )).get();
1426
+ if (!media2) {
1427
+ return sendError5(res, 404, "MEDIA_NOT_FOUND", "Media not found");
1428
+ }
1429
+ const filePath = `./uploads/media/${teamId}/${media2.filename}`;
1430
+ res.set("Content-Type", media2.mimeType);
1431
+ res.sendFile(import_path.default.resolve(filePath));
1432
+ } catch (error) {
1433
+ sendError5(res, 500, "FILE_ERROR", error.message);
1434
+ }
1435
+ });
1436
+ app.get("/analytics/overview", async (req, res) => {
1437
+ try {
1438
+ const teamId = getTeamId5(req);
1439
+ if (!teamId) return sendError5(res, 400, "MISSING_TEAM_ID", "Team ID is required");
1440
+ const { db } = initializeDatabase(teamId);
1441
+ const period = req.query.period || "30d";
1442
+ const endDate = /* @__PURE__ */ new Date();
1443
+ const startDate = /* @__PURE__ */ new Date();
1444
+ const days = parseInt(period.replace("d", "")) || 30;
1445
+ startDate.setDate(endDate.getDate() - days);
1446
+ const metrics = await db.select({
1447
+ platform: postMetrics.platform,
1448
+ totalImpressions: import_drizzle_orm6.sql`sum(${postMetrics.impressions})`,
1449
+ totalLikes: import_drizzle_orm6.sql`sum(${postMetrics.likes})`,
1450
+ totalShares: import_drizzle_orm6.sql`sum(${postMetrics.shares})`,
1451
+ totalComments: import_drizzle_orm6.sql`sum(${postMetrics.comments})`,
1452
+ totalClicks: import_drizzle_orm6.sql`sum(${postMetrics.clicks})`,
1453
+ postCount: import_drizzle_orm6.sql`count(distinct ${postMetrics.postId})`
1454
+ }).from(postMetrics).innerJoin(posts, (0, import_drizzle_orm6.eq)(posts.id, postMetrics.postId)).where((0, import_drizzle_orm6.and)(
1455
+ (0, import_drizzle_orm6.eq)(posts.teamId, teamId),
1456
+ (0, import_drizzle_orm6.gte)(posts.publishedAt, startDate.toISOString())
1457
+ )).groupBy(postMetrics.platform);
1458
+ let totalPosts = 0;
1459
+ let totalImpressions = 0;
1460
+ let totalEngagements = 0;
1461
+ let totalClicks = 0;
1462
+ const platformBreakdown = {};
1463
+ metrics.forEach((metric) => {
1464
+ const engagements = (metric.totalLikes || 0) + (metric.totalShares || 0) + (metric.totalComments || 0);
1465
+ totalPosts += metric.postCount || 0;
1466
+ totalImpressions += metric.totalImpressions || 0;
1467
+ totalEngagements += engagements;
1468
+ totalClicks += metric.totalClicks || 0;
1469
+ platformBreakdown[metric.platform] = {
1470
+ posts: metric.postCount || 0,
1471
+ impressions: metric.totalImpressions || 0,
1472
+ engagements
1473
+ };
1474
+ });
1475
+ const response = {
1476
+ period,
1477
+ metrics: {
1478
+ totalPosts,
1479
+ totalImpressions,
1480
+ totalEngagements,
1481
+ totalClicks,
1482
+ engagementRate: totalImpressions > 0 ? totalEngagements / totalImpressions * 100 : 0,
1483
+ averageImpressions: totalPosts > 0 ? totalImpressions / totalPosts : 0
1484
+ },
1485
+ platformBreakdown
1486
+ };
1487
+ res.json(response);
1488
+ } catch (error) {
1489
+ sendError5(res, 500, "DATABASE_ERROR", error.message);
1490
+ }
1491
+ });
1492
+ const { registerTemplateRoutes: registerTemplateRoutes2 } = (init_templates(), __toCommonJS(templates_exports));
1493
+ const { registerSocialAccountRoutes: registerSocialAccountRoutes2 } = (init_social_accounts(), __toCommonJS(social_accounts_exports));
1494
+ const { registerCalendarRoutes: registerCalendarRoutes2 } = (init_calendar(), __toCommonJS(calendar_exports));
1495
+ const { registerWebhookRoutes: registerWebhookRoutes2 } = (init_webhooks(), __toCommonJS(webhooks_exports));
1496
+ registerTemplateRoutes2(app);
1497
+ registerSocialAccountRoutes2(app);
1498
+ registerCalendarRoutes2(app);
1499
+ registerWebhookRoutes2(app);
1500
+ console.log("Marketing plugin API routes registered");
1501
+ }
1502
+
1503
+ // src/index.ts
1504
+ init_db();
1505
+ init_schema();
1506
+ var pluginMeta = {
1507
+ id: "marketing",
1508
+ name: "Marketing Suite",
1509
+ version: "0.2.0",
1510
+ teamTypes: ["marketing-team", "claw-marketing-team"]
1511
+ };
1512
+ // Annotate the CommonJS export names for ESM import in node:
1513
+ 0 && (module.exports = {
1514
+ createDatabase,
1515
+ createRoutes,
1516
+ decryptCredentials,
1517
+ encryptCredentials,
1518
+ initializeDatabase,
1519
+ pluginMeta,
1520
+ schema
1521
+ });