@bernierllc/content-management-suite 0.4.2 → 0.6.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/dist/index.js CHANGED
@@ -1,4 +1,3 @@
1
- "use client";
2
1
  "use strict";
3
2
  var __create = Object.create;
4
3
  var __defProp = Object.defineProperty;
@@ -31,73 +30,36 @@ var __toCommonJS = (mod) => __copyProps(__defProp({}, "__esModule", { value: tru
31
30
  // src/index.ts
32
31
  var src_exports = {};
33
32
  __export(src_exports, {
34
- AudioContentTypeManager: () => import_content_type_audio2.AudioContentTypeManager,
33
+ AudioContentTypeManager: () => import_content_type_audio.AudioContentTypeManager,
35
34
  AutosaveManager: () => import_content_autosave_manager.AutosaveManager,
35
+ ConflictError: () => ConflictError,
36
36
  ContentManagementConfigSchema: () => ContentManagementConfigSchema,
37
- ContentManagementSuiteConflictError: () => ContentManagementSuiteConflictError,
38
- ContentManagementSuiteError: () => ContentManagementSuiteError,
39
- ContentManagementSuiteForbiddenError: () => ContentManagementSuiteForbiddenError,
40
- ContentManagementSuiteInternalError: () => ContentManagementSuiteInternalError,
41
- ContentManagementSuiteNotFoundError: () => ContentManagementSuiteNotFoundError,
42
- ContentManagementSuiteUnauthorizedError: () => ContentManagementSuiteUnauthorizedError,
43
- ContentManagementSuiteValidationError: () => ContentManagementSuiteValidationError,
37
+ ContentManagementError: () => ContentManagementError,
44
38
  ContentSoftDelete: () => import_content_soft_delete.ContentSoftDelete,
45
- ContentTypeRegistry: () => import_content_type_registry2.ContentTypeRegistry,
39
+ ContentTypeRegistry: () => import_content_type_registry.ContentTypeRegistry,
46
40
  EditorialWorkflowEngine: () => import_content_editorial_workflow.EditorialWorkflowEngine,
47
- ImageContentType: () => import_content_type_image2.ImageContentType,
48
- StageActionButtons: () => import_content_workflow_ui2.StageActionButtons,
49
- TextContentType: () => import_content_type_text2.TextContentType,
50
- VideoContentType: () => import_content_type_video2.VideoContentType,
51
- WorkflowAdminConfig: () => import_content_workflow_ui2.WorkflowAdminConfig,
41
+ ForbiddenError: () => ForbiddenError,
42
+ ImageContentType: () => import_content_type_image.ImageContentType,
43
+ InternalError: () => InternalError,
44
+ NotFoundError: () => NotFoundError,
45
+ TextContentType: () => import_content_type_text.TextContentType,
46
+ UnauthorizedError: () => UnauthorizedError,
47
+ ValidationError: () => ValidationError,
48
+ VideoContentType: () => import_content_type_video.VideoContentType,
52
49
  WorkflowBuilder: () => import_content_editorial_workflow.WorkflowBuilder,
53
50
  WorkflowFactory: () => import_content_editorial_workflow.WorkflowFactory,
54
- WorkflowStepper: () => import_content_workflow_ui2.WorkflowStepper,
55
51
  WorkflowTemplates: () => import_content_editorial_workflow.WorkflowTemplates,
56
- WorkflowTimeline: () => import_content_workflow_ui2.WorkflowTimeline,
57
52
  createContentManagementSuite: () => createContentManagementSuite
58
53
  });
59
54
  module.exports = __toCommonJS(src_exports);
60
55
 
61
- // src/types.ts
56
+ // src/content-management-suite.ts
57
+ var import_events = require("events");
58
+
59
+ // src/config.ts
62
60
  var import_zod = require("zod");
63
61
  var ContentManagementConfigSchema = import_zod.z.object({
64
- // Server Configuration
65
- server: import_zod.z.object({
66
- port: import_zod.z.number().default(3e3),
67
- host: import_zod.z.string().default("localhost"),
68
- cors: import_zod.z.object({
69
- origin: import_zod.z.union([import_zod.z.string(), import_zod.z.array(import_zod.z.string())]).default("*"),
70
- credentials: import_zod.z.boolean().default(true)
71
- }).default({}),
72
- security: import_zod.z.object({
73
- helmet: import_zod.z.boolean().default(true),
74
- rateLimit: import_zod.z.object({
75
- enabled: import_zod.z.boolean().default(true),
76
- windowMs: import_zod.z.number().default(15 * 60 * 1e3),
77
- // 15 minutes
78
- max: import_zod.z.number().default(100)
79
- // limit each IP to 100 requests per windowMs
80
- }).default({})
81
- }).default({})
82
- }).default({}),
83
- // Database Configuration
84
- database: import_zod.z.object({
85
- type: import_zod.z.enum(["sqlite", "postgresql", "mysql", "mongodb"]).default("sqlite"),
86
- url: import_zod.z.string().optional(),
87
- host: import_zod.z.string().default("localhost"),
88
- port: import_zod.z.number().optional(),
89
- name: import_zod.z.string().default("content_management"),
90
- username: import_zod.z.string().optional(),
91
- password: import_zod.z.string().optional(),
92
- ssl: import_zod.z.boolean().default(false),
93
- pool: import_zod.z.object({
94
- min: import_zod.z.number().default(2),
95
- max: import_zod.z.number().default(10)
96
- }).default({})
97
- }).default({}),
98
- // Content Configuration
99
62
  content: import_zod.z.object({
100
- // Default editorial workflow
101
63
  defaultWorkflow: import_zod.z.object({
102
64
  id: import_zod.z.string().default("standard"),
103
65
  name: import_zod.z.string().default("Standard Workflow"),
@@ -111,24 +73,8 @@ var ContentManagementConfigSchema = import_zod.z.object({
111
73
  description: import_zod.z.string().optional(),
112
74
  permissions: import_zod.z.array(import_zod.z.string()).default([])
113
75
  })).default([
114
- {
115
- id: "write",
116
- name: "Write",
117
- order: 1,
118
- isPublishStage: false,
119
- allowsScheduling: false,
120
- description: "Write content",
121
- permissions: ["content.edit"]
122
- },
123
- {
124
- id: "publish",
125
- name: "Publish",
126
- order: 2,
127
- isPublishStage: true,
128
- allowsScheduling: true,
129
- description: "Publish content",
130
- permissions: ["content.publish"]
131
- }
76
+ { id: "write", name: "Write", order: 1, isPublishStage: false, allowsScheduling: false, description: "Write content", permissions: ["content.edit"] },
77
+ { id: "publish", name: "Publish", order: 2, isPublishStage: true, allowsScheduling: true, description: "Publish content", permissions: ["content.publish"] }
132
78
  ]),
133
79
  transitions: import_zod.z.array(import_zod.z.object({
134
80
  id: import_zod.z.string(),
@@ -137,34 +83,23 @@ var ContentManagementConfigSchema = import_zod.z.object({
137
83
  description: import_zod.z.string().optional(),
138
84
  permissions: import_zod.z.array(import_zod.z.string()).default([])
139
85
  })).default([
140
- {
141
- id: "write-to-publish",
142
- from: "write",
143
- to: "publish",
144
- description: "Move from write to publish",
145
- permissions: ["content.publish"]
146
- }
86
+ { id: "write-to-publish", from: "write", to: "publish", description: "Move from write to publish", permissions: ["content.publish"] }
147
87
  ])
148
88
  }).default({}),
149
- // Content types
150
89
  contentTypes: import_zod.z.array(import_zod.z.string()).default(["text", "image", "audio", "video"]),
151
- // Auto-save configuration
152
90
  autoSave: import_zod.z.object({
153
91
  enabled: import_zod.z.boolean().default(true),
154
92
  debounceMs: import_zod.z.number().default(1e3),
155
93
  maxRetries: import_zod.z.number().default(3),
156
94
  backoffMs: import_zod.z.number().default(1e3)
157
95
  }).default({}),
158
- // Soft delete configuration
159
96
  softDelete: import_zod.z.object({
160
97
  enabled: import_zod.z.boolean().default(true),
161
98
  showDeletedToUsers: import_zod.z.boolean().default(false),
162
99
  retentionDays: import_zod.z.number().default(30)
163
100
  }).default({}),
164
- // File upload configuration
165
101
  upload: import_zod.z.object({
166
102
  maxFileSize: import_zod.z.number().default(104857600),
167
- // 100MB
168
103
  allowedTypes: import_zod.z.array(import_zod.z.string()).default([
169
104
  "image/jpeg",
170
105
  "image/png",
@@ -178,893 +113,542 @@ var ContentManagementConfigSchema = import_zod.z.object({
178
113
  "video/ogg"
179
114
  ]),
180
115
  storage: import_zod.z.object({
181
- type: import_zod.z.enum(["local", "s3", "gcs", "azure"]).default("local"),
116
+ type: import_zod.z.enum(["local", "s3"]).default("local"),
182
117
  path: import_zod.z.string().default("./uploads"),
183
118
  bucket: import_zod.z.string().optional(),
184
- region: import_zod.z.string().optional(),
185
- accessKey: import_zod.z.string().optional(),
186
- secretKey: import_zod.z.string().optional()
187
- }).default({})
119
+ region: import_zod.z.string().optional()
120
+ }).default({}).optional()
188
121
  }).default({})
189
122
  }).default({}),
190
- // UI Configuration
191
- ui: import_zod.z.object({
192
- theme: import_zod.z.object({
193
- mode: import_zod.z.enum(["light", "dark", "auto"]).default("auto"),
194
- primaryColor: import_zod.z.string().default("#007bff"),
195
- secondaryColor: import_zod.z.string().default("#6c757d"),
196
- accentColor: import_zod.z.string().default("#17a2b8")
197
- }).default({}),
198
- editor: import_zod.z.object({
199
- showToolbar: import_zod.z.boolean().default(true),
200
- showStatusBar: import_zod.z.boolean().default(true),
201
- showWordCount: import_zod.z.boolean().default(true),
202
- showCharacterCount: import_zod.z.boolean().default(true),
203
- autoSave: import_zod.z.boolean().default(true),
204
- placeholder: import_zod.z.string().default("Start writing your content...")
205
- }).default({}),
206
- list: import_zod.z.object({
207
- defaultView: import_zod.z.enum(["table", "list", "grid", "kanban"]).default("table"),
208
- pageSize: import_zod.z.number().default(20),
209
- showSearch: import_zod.z.boolean().default(true),
210
- showFilters: import_zod.z.boolean().default(true),
211
- showSorting: import_zod.z.boolean().default(true),
212
- showPagination: import_zod.z.boolean().default(true)
123
+ database: import_zod.z.object({
124
+ type: import_zod.z.enum(["sqlite", "postgresql", "mysql", "mongodb"]).default("sqlite"),
125
+ url: import_zod.z.string().optional(),
126
+ host: import_zod.z.string().default("localhost"),
127
+ port: import_zod.z.number().optional(),
128
+ name: import_zod.z.string().default("content_management"),
129
+ username: import_zod.z.string().optional(),
130
+ password: import_zod.z.string().optional(),
131
+ ssl: import_zod.z.boolean().default(false),
132
+ pool: import_zod.z.object({
133
+ min: import_zod.z.number().default(2),
134
+ max: import_zod.z.number().default(10),
135
+ idleTimeoutMs: import_zod.z.number().optional()
213
136
  }).default({})
214
137
  }).default({}),
215
- // Integration Configuration
216
138
  integrations: import_zod.z.object({
217
139
  neverAdmin: import_zod.z.object({
218
140
  enabled: import_zod.z.boolean().default(false),
219
- url: import_zod.z.string().optional(),
220
- apiKey: import_zod.z.string().optional(),
221
- syncInterval: import_zod.z.number().default(3e5)
222
- // 5 minutes
141
+ endpoint: import_zod.z.string().optional()
223
142
  }).default({}),
224
143
  neverHub: import_zod.z.object({
225
144
  enabled: import_zod.z.boolean().default(false),
226
- url: import_zod.z.string().optional(),
227
- apiKey: import_zod.z.string().optional(),
228
- packageDiscovery: import_zod.z.boolean().default(true)
145
+ endpoint: import_zod.z.string().optional()
229
146
  }).default({}),
230
147
  analytics: import_zod.z.object({
231
148
  enabled: import_zod.z.boolean().default(false),
232
- provider: import_zod.z.enum(["google", "mixpanel", "amplitude", "custom"]).optional(),
233
- trackingId: import_zod.z.string().optional(),
234
- config: import_zod.z.record(import_zod.z.any()).default({})
149
+ provider: import_zod.z.string().optional()
235
150
  }).default({})
236
151
  }).default({}),
237
- // Security Configuration
238
152
  security: import_zod.z.object({
239
- jwt: import_zod.z.object({
240
- secret: import_zod.z.string().default("your-secret-key"),
241
- expiresIn: import_zod.z.string().default("24h"),
242
- issuer: import_zod.z.string().default("content-management-suite")
243
- }).default({}),
244
153
  permissions: import_zod.z.object({
245
154
  enabled: import_zod.z.boolean().default(true),
246
- defaultRole: import_zod.z.string().default("user"),
247
- roles: import_zod.z.array(import_zod.z.object({
248
- name: import_zod.z.string(),
249
- permissions: import_zod.z.array(import_zod.z.string()),
250
- description: import_zod.z.string().optional()
251
- })).default([
252
- {
253
- name: "admin",
254
- permissions: ["*"],
255
- description: "Full administrative access"
256
- },
257
- {
258
- name: "editor",
259
- permissions: ["content.edit", "content.publish", "content.schedule"],
260
- description: "Content editing and publishing"
261
- },
262
- {
263
- name: "author",
264
- permissions: ["content.edit"],
265
- description: "Content creation and editing"
266
- },
267
- {
268
- name: "user",
269
- permissions: ["content.view"],
270
- description: "Content viewing only"
271
- }
272
- ])
273
- }).default({})
155
+ defaultRole: import_zod.z.string().default("user")
156
+ }).default({}),
157
+ roles: import_zod.z.array(import_zod.z.object({
158
+ name: import_zod.z.string(),
159
+ permissions: import_zod.z.array(import_zod.z.string()),
160
+ description: import_zod.z.string().optional()
161
+ })).default([
162
+ { name: "admin", permissions: ["*"], description: "Full administrative access" },
163
+ { name: "editor", permissions: ["content.edit", "content.publish", "content.schedule"], description: "Content editing and publishing" },
164
+ { name: "author", permissions: ["content.edit"], description: "Content creation and editing" },
165
+ { name: "user", permissions: ["content.view"], description: "Content viewing only" }
166
+ ])
274
167
  }).default({}),
275
- // Logging Configuration
276
168
  logging: import_zod.z.object({
277
- level: import_zod.z.enum(["error", "warn", "info", "debug"]).default("info"),
278
- format: import_zod.z.enum(["json", "text"]).default("json"),
279
- file: import_zod.z.object({
280
- enabled: import_zod.z.boolean().default(true),
281
- path: import_zod.z.string().default("./logs"),
282
- maxSize: import_zod.z.string().default("10MB"),
283
- maxFiles: import_zod.z.number().default(5)
284
- }).default({}),
285
- console: import_zod.z.object({
286
- enabled: import_zod.z.boolean().default(true),
287
- colorize: import_zod.z.boolean().default(true)
288
- }).default({})
169
+ level: import_zod.z.enum(["error", "warn", "info", "debug"]).default("info")
289
170
  }).default({}),
290
- // Performance Configuration
291
171
  performance: import_zod.z.object({
292
172
  cache: import_zod.z.object({
293
173
  enabled: import_zod.z.boolean().default(true),
294
174
  ttl: import_zod.z.number().default(300),
295
- // 5 minutes
296
175
  maxSize: import_zod.z.number().default(1e3)
297
- }).default({}),
298
- compression: import_zod.z.object({
299
- enabled: import_zod.z.boolean().default(true),
300
- level: import_zod.z.number().min(1).max(9).default(6)
301
- }).default({}),
302
- rateLimit: import_zod.z.object({
303
- enabled: import_zod.z.boolean().default(true),
304
- windowMs: import_zod.z.number().default(15 * 60 * 1e3),
305
- // 15 minutes
306
- max: import_zod.z.number().default(100)
307
176
  }).default({})
308
177
  }).default({})
309
178
  });
310
- var ContentManagementSuiteError = class extends Error {
311
- constructor(message, code, statusCode = 500, details) {
179
+
180
+ // src/errors.ts
181
+ var ContentManagementError = class extends Error {
182
+ constructor(message, options) {
312
183
  super(message);
313
- this.name = "ContentManagementSuiteError";
314
- this.code = code;
315
- this.statusCode = statusCode;
316
- this.details = details;
184
+ if (options?.cause !== void 0) {
185
+ this.cause = options.cause;
186
+ }
187
+ this.name = this.constructor.name;
188
+ this.code = options?.code ?? "CONTENT_MANAGEMENT_ERROR";
189
+ if (options?.details !== void 0) {
190
+ this.details = options.details;
191
+ }
317
192
  }
318
193
  };
319
- var ContentManagementSuiteValidationError = class extends ContentManagementSuiteError {
320
- constructor(message, details) {
321
- super(message, "VALIDATION_ERROR", 400, details);
322
- this.name = "ContentManagementSuiteValidationError";
194
+ var ValidationError = class extends ContentManagementError {
195
+ constructor(message, options) {
196
+ super(message, { ...options, code: "VALIDATION_ERROR" });
323
197
  }
324
198
  };
325
- var ContentManagementSuiteNotFoundError = class extends ContentManagementSuiteError {
326
- constructor(message, details) {
327
- super(message, "NOT_FOUND", 404, details);
328
- this.name = "ContentManagementSuiteNotFoundError";
199
+ var NotFoundError = class extends ContentManagementError {
200
+ constructor(message, options) {
201
+ super(message, { ...options, code: "NOT_FOUND" });
329
202
  }
330
203
  };
331
- var ContentManagementSuiteUnauthorizedError = class extends ContentManagementSuiteError {
332
- constructor(message, details) {
333
- super(message, "UNAUTHORIZED", 401, details);
334
- this.name = "ContentManagementSuiteUnauthorizedError";
204
+ var UnauthorizedError = class extends ContentManagementError {
205
+ constructor(message, options) {
206
+ super(message, { ...options, code: "UNAUTHORIZED" });
335
207
  }
336
208
  };
337
- var ContentManagementSuiteForbiddenError = class extends ContentManagementSuiteError {
338
- constructor(message, details) {
339
- super(message, "FORBIDDEN", 403, details);
340
- this.name = "ContentManagementSuiteForbiddenError";
209
+ var ForbiddenError = class extends ContentManagementError {
210
+ constructor(message, options) {
211
+ super(message, { ...options, code: "FORBIDDEN" });
341
212
  }
342
213
  };
343
- var ContentManagementSuiteConflictError = class extends ContentManagementSuiteError {
344
- constructor(message, details) {
345
- super(message, "CONFLICT", 409, details);
346
- this.name = "ContentManagementSuiteConflictError";
214
+ var ConflictError = class extends ContentManagementError {
215
+ constructor(message, options) {
216
+ super(message, { ...options, code: "CONFLICT" });
347
217
  }
348
218
  };
349
- var ContentManagementSuiteInternalError = class extends ContentManagementSuiteError {
350
- constructor(message, details) {
351
- super(message, "INTERNAL_ERROR", 500, details);
352
- this.name = "ContentManagementSuiteInternalError";
219
+ var InternalError = class extends ContentManagementError {
220
+ constructor(message, options) {
221
+ super(message, { ...options, code: "INTERNAL_ERROR" });
353
222
  }
354
223
  };
355
224
 
356
- // src/index.ts
357
- var import_content_workflow_ui2 = require("@bernierllc/content-workflow-ui");
358
- var import_content_type_text2 = require("@bernierllc/content-type-text");
359
- var import_content_type_image2 = require("@bernierllc/content-type-image");
360
- var import_content_type_audio2 = require("@bernierllc/content-type-audio");
361
- var import_content_type_video2 = require("@bernierllc/content-type-video");
362
- var import_content_type_registry2 = require("@bernierllc/content-type-registry");
363
- var import_content_editorial_workflow = require("@bernierllc/content-editorial-workflow");
364
- var import_content_autosave_manager = require("@bernierllc/content-autosave-manager");
365
- var import_content_soft_delete = require("@bernierllc/content-soft-delete");
366
-
367
- // src/content-management-suite.ts
368
- var import_events = require("events");
369
- var import_express = __toESM(require("express"));
370
- var import_cors = __toESM(require("cors"));
371
- var import_helmet = __toESM(require("helmet"));
372
- var import_morgan = __toESM(require("morgan"));
373
- var import_compression = __toESM(require("compression"));
374
- var import_uuid = require("uuid");
375
- var import_content_type_registry = require("@bernierllc/content-type-registry");
376
- var import_content_type_text = require("@bernierllc/content-type-text");
377
- var import_content_type_image = require("@bernierllc/content-type-image");
378
- var import_content_type_audio = require("@bernierllc/content-type-audio");
379
- var import_content_type_video = require("@bernierllc/content-type-video");
380
- var import_content_workflow_ui = require("@bernierllc/content-workflow-ui");
381
- var ContentManagementSuiteImpl = class extends import_events.EventEmitter {
382
- constructor(options = {}) {
383
- super();
384
- // Stub until @bernierllc/content-editor-service is published
385
- this.autosaveManager = null;
386
- this.softDelete = null;
387
- this.workflowEngine = null;
388
- // Content Types
389
- this.contentTypes = /* @__PURE__ */ new Map();
390
- // Plugins and Middleware
391
- this.plugins = /* @__PURE__ */ new Map();
392
- this.middleware = [];
393
- this.hooks = /* @__PURE__ */ new Map();
394
- // State
395
- this.isStarted = false;
396
- this.isStopped = false;
397
- this.httpServer = null;
398
- this.options = options;
399
- this.config = this.loadConfiguration();
400
- this.contentTypeRegistry = new import_content_type_registry.ContentTypeRegistry();
401
- this.configManager = this.createConfigManagerStub();
402
- this.workflowService = this.createWorkflowServiceStub();
403
- this.editorService = this.createEditorServiceStub();
404
- this.workflow = {
405
- stepper: import_content_workflow_ui.WorkflowStepper,
406
- actions: import_content_workflow_ui.StageActionButtons,
407
- timeline: import_content_workflow_ui.WorkflowTimeline,
408
- admin: import_content_workflow_ui.WorkflowAdminConfig
225
+ // src/namespaces/content.ts
226
+ var crypto = __toESM(require("crypto"));
227
+ var ContentNamespaceImpl = class {
228
+ constructor(emitter) {
229
+ this.store = /* @__PURE__ */ new Map();
230
+ this.emitter = emitter;
231
+ }
232
+ async create(input) {
233
+ const item = {
234
+ id: crypto.randomUUID(),
235
+ type: input.type,
236
+ data: { ...input.data },
237
+ status: "draft",
238
+ createdAt: (/* @__PURE__ */ new Date()).toISOString()
409
239
  };
410
- this.server = (0, import_express.default)();
411
- this.setupMiddleware();
412
- this.setupRoutes();
413
- this.editor = this.createEditorStub();
414
- this.list = this.createListStub();
415
- this.registerDefaultContentTypes();
416
- if (options.plugins) {
417
- options.plugins.forEach((plugin) => this.registerPlugin(plugin));
418
- }
419
- }
420
- // Stub creators for services not yet published
421
- createConfigManagerStub() {
422
- return {
423
- getConfig: () => this.config,
424
- updateConfig: async (config) => {
425
- this.config = { ...this.config, ...config };
426
- },
427
- start: async () => {
428
- },
429
- stop: async () => {
430
- }
240
+ this.store.set(item.id, item);
241
+ this.emitter.emit("content:created", item);
242
+ return item;
243
+ }
244
+ async get(id) {
245
+ const item = this.store.get(id);
246
+ if (!item) {
247
+ throw new NotFoundError(`Content item not found: ${id}`);
248
+ }
249
+ return item;
250
+ }
251
+ async list(filters) {
252
+ let items = Array.from(this.store.values());
253
+ if (filters?.type) {
254
+ items = items.filter((item) => item.type === filters.type);
255
+ }
256
+ if (filters?.status) {
257
+ items = items.filter((item) => item.status === filters.status);
258
+ }
259
+ const total = items.length;
260
+ const page = filters?.page ?? 1;
261
+ const limit = filters?.limit ?? items.length;
262
+ const start = (page - 1) * limit;
263
+ const paged = items.slice(start, start + limit);
264
+ return { items: paged, total, page, limit };
265
+ }
266
+ async update(id, input) {
267
+ const existing = this.store.get(id);
268
+ if (!existing) {
269
+ throw new NotFoundError(`Content item not found: ${id}`);
270
+ }
271
+ const updated = {
272
+ ...existing,
273
+ data: { ...existing.data, ...input.data },
274
+ updatedAt: (/* @__PURE__ */ new Date()).toISOString()
431
275
  };
432
- }
433
- createWorkflowServiceStub() {
434
- return {
435
- listWorkflows: async () => [],
436
- getWorkflow: async (id) => ({ id, name: "Default Workflow" }),
437
- createWorkflow: async (data) => ({ id: (0, import_uuid.v4)(), ...data }),
438
- updateWorkflow: async (id, data) => ({ id, ...data }),
439
- deleteWorkflow: async (_id) => {
440
- },
441
- publishContent: async (id) => ({ id, status: "published" }),
442
- scheduleContent: async (id, date) => ({ id, scheduledFor: date }),
443
- unpublishContent: async (id) => ({ id, status: "draft" }),
444
- start: async () => {
445
- },
446
- stop: async () => {
447
- }
276
+ this.store.set(id, updated);
277
+ this.emitter.emit("content:updated", updated);
278
+ return updated;
279
+ }
280
+ async delete(id) {
281
+ if (!this.store.has(id)) {
282
+ throw new NotFoundError(`Content item not found: ${id}`);
283
+ }
284
+ this.store.delete(id);
285
+ this.emitter.emit("content:deleted", { id });
286
+ }
287
+ async publish(id) {
288
+ const existing = this.store.get(id);
289
+ if (!existing) {
290
+ throw new NotFoundError(`Content item not found: ${id}`);
291
+ }
292
+ const published = {
293
+ ...existing,
294
+ status: "published",
295
+ publishedAt: (/* @__PURE__ */ new Date()).toISOString(),
296
+ updatedAt: (/* @__PURE__ */ new Date()).toISOString()
448
297
  };
449
- }
450
- createEditorServiceStub() {
451
- const contentStore = /* @__PURE__ */ new Map();
452
- return {
453
- listContent: async (_filters) => ({ items: Array.from(contentStore.values()), total: contentStore.size }),
454
- getContent: async (id) => contentStore.get(id) || null,
455
- createContent: async (type, data) => {
456
- const content = { id: (0, import_uuid.v4)(), type, ...data, createdAt: (/* @__PURE__ */ new Date()).toISOString() };
457
- contentStore.set(content.id, content);
458
- return content;
459
- },
460
- updateContent: async (id, data) => {
461
- const existing = contentStore.get(id);
462
- if (!existing)
463
- throw new Error("Content not found");
464
- const updated = { ...existing, ...data, updatedAt: (/* @__PURE__ */ new Date()).toISOString() };
465
- contentStore.set(id, updated);
466
- return updated;
467
- },
468
- deleteContent: async (id, _soft) => {
469
- contentStore.delete(id);
470
- },
471
- start: async () => {
472
- },
473
- stop: async () => {
474
- }
298
+ this.store.set(id, published);
299
+ this.emitter.emit("content:published", published);
300
+ return published;
301
+ }
302
+ async unpublish(id) {
303
+ const existing = this.store.get(id);
304
+ if (!existing) {
305
+ throw new NotFoundError(`Content item not found: ${id}`);
306
+ }
307
+ const unpublished = {
308
+ ...existing,
309
+ status: "draft",
310
+ updatedAt: (/* @__PURE__ */ new Date()).toISOString()
475
311
  };
476
- }
477
- // Stub for editor interface (until @bernierllc/content-editor-ui is published)
478
- createEditorStub() {
479
- return {
480
- render: () => null,
481
- getValue: () => "",
482
- setValue: (_value) => {
483
- },
484
- focus: () => {
485
- },
486
- blur: () => {
487
- },
488
- on: (_event, _callback) => {
489
- },
490
- off: (_event, _callback) => {
491
- }
312
+ this.store.set(id, unpublished);
313
+ this.emitter.emit("content:unpublished", unpublished);
314
+ return unpublished;
315
+ }
316
+ async schedule(id, date) {
317
+ const existing = this.store.get(id);
318
+ if (!existing) {
319
+ throw new NotFoundError(`Content item not found: ${id}`);
320
+ }
321
+ const scheduled = {
322
+ ...existing,
323
+ scheduledFor: date,
324
+ updatedAt: (/* @__PURE__ */ new Date()).toISOString()
492
325
  };
493
- }
494
- // Stub for list interface (until @bernierllc/content-list-ui is published)
495
- createListStub() {
496
- return {
497
- render: () => null,
498
- getItems: () => [],
499
- setItems: (_items) => {
500
- },
501
- getSelectedItems: () => [],
502
- setSelectedItems: (_items) => {
503
- },
504
- on: (_event, _callback) => {
505
- },
506
- off: (_event, _callback) => {
507
- }
508
- };
509
- }
510
- loadConfiguration() {
511
- try {
512
- if (this.options.config) {
513
- return ContentManagementConfigSchema.parse(this.options.config);
514
- }
515
- const config = this.configManager?.getConfig() || {};
516
- return ContentManagementConfigSchema.parse(config);
517
- } catch (error) {
518
- console.error("Failed to load configuration:", error);
519
- return ContentManagementConfigSchema.parse({});
520
- }
521
- }
522
- setupMiddleware() {
523
- if (this.config.server.security.helmet) {
524
- this.server.use((0, import_helmet.default)());
525
- }
526
- this.server.use((0, import_cors.default)(this.config.server.cors));
527
- if (this.config.performance.compression.enabled) {
528
- this.server.use((0, import_compression.default)({
529
- level: this.config.performance.compression.level
530
- }));
531
- }
532
- if (this.options.logger) {
533
- this.server.use((0, import_morgan.default)("combined", {
534
- stream: {
535
- write: (message) => {
536
- this.options.logger?.info(message.trim());
537
- }
538
- }
539
- }));
540
- }
541
- this.server.use(import_express.default.json({ limit: "10mb" }));
542
- this.server.use(import_express.default.urlencoded({ extended: true, limit: "10mb" }));
543
- this.middleware.sort((a, b) => (a.order || 0) - (b.order || 0)).forEach((middleware) => {
544
- this.server.use(middleware.handler);
545
- });
546
- }
547
- setupRoutes() {
548
- this.server.get("/health", (req, res) => {
549
- res.json({
550
- status: "healthy",
551
- timestamp: (/* @__PURE__ */ new Date()).toISOString(),
552
- version: "0.1.0",
553
- uptime: process.uptime()
554
- });
326
+ this.store.set(id, scheduled);
327
+ this.emitter.emit("content:scheduled", { item: scheduled, date });
328
+ return scheduled;
329
+ }
330
+ async search(query, options) {
331
+ const lowerQuery = query.toLowerCase();
332
+ let items = Array.from(this.store.values()).filter((item) => {
333
+ return Object.values(item.data).some(
334
+ (value) => typeof value === "string" && value.toLowerCase().includes(lowerQuery)
335
+ );
555
336
  });
556
- this.server.use("/api", this.createAPIRoutes());
557
- this.server.use("/admin", this.createAdminRoutes());
558
- this.server.use("/static", import_express.default.static("public"));
559
- this.server.use(this.errorHandler.bind(this));
560
- }
561
- createAPIRoutes() {
562
- const router = import_express.default.Router();
563
- router.get("/content", this.getContentList.bind(this));
564
- router.get("/content/:id", this.getContent.bind(this));
565
- router.post("/content", this.createContent.bind(this));
566
- router.put("/content/:id", this.updateContent.bind(this));
567
- router.delete("/content/:id", this.deleteContent.bind(this));
568
- router.post("/content/:id/publish", this.publishContent.bind(this));
569
- router.post("/content/:id/schedule", this.scheduleContent.bind(this));
570
- router.post("/content/:id/unpublish", this.unpublishContent.bind(this));
571
- router.get("/workflows", this.getWorkflows.bind(this));
572
- router.get("/workflows/:id", this.getWorkflow.bind(this));
573
- router.post("/workflows", this.createWorkflow.bind(this));
574
- router.put("/workflows/:id", this.updateWorkflow.bind(this));
575
- router.delete("/workflows/:id", this.deleteWorkflow.bind(this));
576
- router.get("/content-types", this.getContentTypes.bind(this));
577
- router.get("/content-types/:id", this.handleGetContentType.bind(this));
578
- router.post("/content-types", this.createContentType.bind(this));
579
- router.put("/content-types/:id", this.updateContentType.bind(this));
580
- router.delete("/content-types/:id", this.deleteContentType.bind(this));
581
- router.get("/config", this.handleGetConfig.bind(this));
582
- router.put("/config", this.handleUpdateConfig.bind(this));
583
- router.get("/users", this.getUsers.bind(this));
584
- router.get("/users/:id", this.getUser.bind(this));
585
- router.post("/users", this.createUser.bind(this));
586
- router.put("/users/:id", this.updateUser.bind(this));
587
- router.delete("/users/:id", this.deleteUser.bind(this));
588
- return router;
589
- }
590
- createAdminRoutes() {
591
- const router = import_express.default.Router();
592
- router.get("/", (req, res) => {
593
- res.json({
594
- message: "Content Management Suite Admin",
595
- version: "0.1.0",
596
- endpoints: [
597
- "/workflows",
598
- "/content-types",
599
- "/config",
600
- "/users"
601
- ]
602
- });
603
- });
604
- router.get("/workflows", this.getWorkflows.bind(this));
605
- router.post("/workflows", this.createWorkflow.bind(this));
606
- router.put("/workflows/:id", this.updateWorkflow.bind(this));
607
- router.delete("/workflows/:id", this.deleteWorkflow.bind(this));
608
- router.get("/content-types", this.getContentTypes.bind(this));
609
- router.post("/content-types", this.createContentType.bind(this));
610
- router.put("/content-types/:id", this.updateContentType.bind(this));
611
- router.delete("/content-types/:id", this.deleteContentType.bind(this));
612
- router.get("/config", this.handleGetConfig.bind(this));
613
- router.put("/config", this.handleUpdateConfig.bind(this));
614
- return router;
615
- }
616
- errorHandler(error, _req, res, _next) {
617
- this.emit("error", error);
618
- if (error instanceof ContentManagementSuiteError) {
619
- res.status(error.statusCode).json({
620
- error: {
621
- code: error.code,
622
- message: error.message,
623
- details: error.details
624
- }
625
- });
626
- } else {
627
- res.status(500).json({
628
- error: {
629
- code: "INTERNAL_ERROR",
630
- message: "An unexpected error occurred",
631
- details: process.env.NODE_ENV === "development" ? error.message : void 0
632
- }
633
- });
634
- }
635
- }
636
- registerDefaultContentTypes() {
637
- this.contentTypes.set("text", import_content_type_text.TextContentType);
638
- this.contentTypes.set("image", import_content_type_image.ImageContentType);
639
- this.contentTypes.set("audio", import_content_type_audio.AudioContentTypeManager);
640
- this.contentTypes.set("video", import_content_type_video.VideoContentType);
641
- }
642
- // Public API Methods
643
- async start() {
644
- if (this.isStarted) {
645
- throw new ContentManagementSuiteError("Suite is already started", "ALREADY_STARTED");
337
+ if (options?.type) {
338
+ items = items.filter((item) => item.type === options.type);
646
339
  }
647
- try {
648
- await this.configManager.start();
649
- await this.workflowService.start();
650
- await this.editorService.start();
651
- const port = this.config.server.port;
652
- const host = this.config.server.host;
653
- return new Promise((resolve, reject) => {
654
- this.httpServer = this.server.listen(port, host, () => {
655
- console.log(`Content Management Suite started on http://${host}:${port}`);
656
- this.isStarted = true;
657
- this.emit("started");
658
- resolve();
659
- });
660
- this.httpServer.on("error", (err) => {
661
- this.emit("error", err);
662
- reject(new ContentManagementSuiteInternalError("Failed to start server", err));
663
- });
664
- });
665
- } catch (error) {
666
- this.emit("error", error);
667
- throw new ContentManagementSuiteInternalError("Failed to start suite", error);
340
+ if (options?.status) {
341
+ items = items.filter((item) => item.status === options.status);
668
342
  }
343
+ const total = items.length;
344
+ const page = options?.page ?? 1;
345
+ const limit = options?.limit ?? items.length;
346
+ const start = (page - 1) * limit;
347
+ const paged = items.slice(start, start + limit);
348
+ return { items: paged, total, page, limit };
669
349
  }
670
- async stop() {
671
- if (this.isStopped) {
672
- throw new ContentManagementSuiteError("Suite is already stopped", "ALREADY_STOPPED");
673
- }
674
- try {
675
- await this.configManager.stop();
676
- await this.workflowService.stop();
677
- await this.editorService.stop();
678
- if (this.httpServer) {
679
- return new Promise((resolve) => {
680
- this.httpServer.close(() => {
681
- console.log("Content Management Suite stopped");
682
- this.isStopped = true;
683
- this.emit("stopped");
684
- resolve();
685
- });
686
- });
687
- }
688
- this.isStopped = true;
689
- } catch (error) {
690
- this.emit("error", error);
691
- throw new ContentManagementSuiteInternalError("Failed to stop suite", error);
692
- }
693
- }
694
- getConfig() {
695
- return this.config;
350
+ };
351
+
352
+ // src/namespaces/content-types.ts
353
+ var ContentTypesNamespaceImpl = class {
354
+ constructor() {
355
+ this.store = /* @__PURE__ */ new Map();
696
356
  }
697
- async updateConfig(config) {
698
- try {
699
- const newConfig = ContentManagementConfigSchema.parse({
700
- ...this.config,
701
- ...config
702
- });
703
- this.config = newConfig;
704
- await this.configManager.updateConfig(newConfig);
705
- this.emit("config:updated", newConfig);
706
- } catch (error) {
707
- throw new ContentManagementSuiteValidationError("Invalid configuration", error);
357
+ register(contentType) {
358
+ const id = contentType.id ?? contentType.name;
359
+ if (!id) {
360
+ throw new Error("Content type must have an id or name");
708
361
  }
362
+ this.store.set(id, contentType);
709
363
  }
710
- registerContentType(contentType) {
711
- const id = contentType?.id || contentType?.name || "unknown";
712
- this.contentTypes.set(id, contentType);
713
- this.emit("contentType:registered", contentType);
714
- }
715
- unregisterContentType(contentTypeId) {
716
- if (!this.contentTypes.has(contentTypeId)) {
717
- throw new ContentManagementSuiteNotFoundError("Content type not found");
364
+ unregister(id) {
365
+ if (!this.store.has(id)) {
366
+ throw new NotFoundError(`Content type not found: ${id}`);
718
367
  }
719
- this.contentTypes.delete(contentTypeId);
720
- this.emit("contentType:unregistered", contentTypeId);
368
+ this.store.delete(id);
721
369
  }
722
- getContentType(contentTypeId) {
723
- const contentType = this.contentTypes.get(contentTypeId);
724
- if (!contentType) {
725
- throw new ContentManagementSuiteNotFoundError("Content type not found");
370
+ get(id) {
371
+ const contentType = this.store.get(id);
372
+ if (contentType === void 0) {
373
+ throw new NotFoundError(`Content type not found: ${id}`);
726
374
  }
727
- return contentType;
375
+ return { id, contentType };
728
376
  }
729
- listContentTypes() {
730
- return Array.from(this.contentTypes.entries()).map(([id, contentType]) => ({
377
+ list() {
378
+ return Array.from(this.store.entries()).map(([id, contentType]) => ({
731
379
  id,
732
- contentType,
733
- ...contentType
380
+ contentType
734
381
  }));
735
382
  }
736
- // Plugin Management
737
- registerPlugin(plugin) {
738
- if (this.plugins.has(plugin.name)) {
739
- throw new ContentManagementSuiteConflictError("Plugin already registered");
740
- }
741
- this.plugins.set(plugin.name, plugin);
742
- plugin.install(this);
743
- this.emit("plugin:registered", plugin);
744
- }
745
- unregisterPlugin(pluginName) {
746
- const plugin = this.plugins.get(pluginName);
747
- if (!plugin) {
748
- throw new ContentManagementSuiteNotFoundError("Plugin not found");
749
- }
750
- plugin.uninstall(this);
751
- this.plugins.delete(pluginName);
752
- this.emit("plugin:unregistered", pluginName);
753
- }
754
- // Middleware Management
755
- addMiddleware(middleware) {
756
- this.middleware.push(middleware);
757
- this.emit("middleware:added", middleware);
758
- }
759
- removeMiddleware(middlewareName) {
760
- const index = this.middleware.findIndex((m) => m.name === middlewareName);
761
- if (index === -1) {
762
- throw new ContentManagementSuiteNotFoundError("Middleware not found");
763
- }
764
- this.middleware.splice(index, 1);
765
- this.emit("middleware:removed", middlewareName);
383
+ };
384
+
385
+ // src/namespaces/workflows.ts
386
+ var crypto2 = __toESM(require("crypto"));
387
+ var WorkflowsNamespaceImpl = class {
388
+ constructor() {
389
+ this.store = /* @__PURE__ */ new Map();
390
+ }
391
+ async create(input) {
392
+ const workflow = {
393
+ id: crypto2.randomUUID(),
394
+ name: input.name,
395
+ ...input.description !== void 0 ? { description: input.description } : {},
396
+ ...input.stages !== void 0 ? { stages: input.stages } : {},
397
+ ...input.transitions !== void 0 ? { transitions: input.transitions } : {}
398
+ };
399
+ this.store.set(workflow.id, workflow);
400
+ return workflow;
766
401
  }
767
- // Hook Management
768
- addHook(hook) {
769
- if (!this.hooks.has(hook.name)) {
770
- this.hooks.set(hook.name, []);
402
+ async get(id) {
403
+ const workflow = this.store.get(id);
404
+ if (!workflow) {
405
+ throw new NotFoundError(`Workflow not found: ${id}`);
771
406
  }
772
- this.hooks.get(hook.name).push(hook);
773
- this.hooks.get(hook.name).sort((a, b) => (a.priority || 0) - (b.priority || 0));
774
- this.emit("hook:added", hook);
407
+ return workflow;
775
408
  }
776
- removeHook(hookName, handler) {
777
- const hooks = this.hooks.get(hookName);
778
- if (!hooks) {
779
- throw new ContentManagementSuiteNotFoundError("Hook not found");
780
- }
781
- if (handler) {
782
- const index = hooks.findIndex((h) => h.handler === handler);
783
- if (index === -1) {
784
- throw new ContentManagementSuiteNotFoundError("Hook handler not found");
785
- }
786
- hooks.splice(index, 1);
787
- } else {
788
- this.hooks.delete(hookName);
789
- }
790
- this.emit("hook:removed", hookName);
409
+ async list() {
410
+ return Array.from(this.store.values());
791
411
  }
792
- // API Route Handlers
793
- async getContentList(req, res) {
794
- try {
795
- const { type, status, page = 1, limit = 20 } = req.query;
796
- const filters = { type, status, page: parseInt(page), limit: parseInt(limit) };
797
- const content = await this.editorService.listContent(filters);
798
- res.json(content);
799
- } catch (error) {
800
- throw new ContentManagementSuiteInternalError("Failed to get content list", error);
412
+ async update(id, input) {
413
+ const existing = this.store.get(id);
414
+ if (!existing) {
415
+ throw new NotFoundError(`Workflow not found: ${id}`);
801
416
  }
417
+ const updated = { ...existing, ...input };
418
+ this.store.set(id, updated);
419
+ return updated;
802
420
  }
803
- async getContent(req, res) {
804
- try {
805
- const { id } = req.params;
806
- const content = await this.editorService.getContent(id);
807
- res.json(content);
808
- } catch (error) {
809
- throw new ContentManagementSuiteNotFoundError("Content not found", error);
421
+ async delete(id) {
422
+ if (!this.store.has(id)) {
423
+ throw new NotFoundError(`Workflow not found: ${id}`);
810
424
  }
425
+ this.store.delete(id);
811
426
  }
812
- async createContent(req, res) {
813
- try {
814
- const { type, data } = req.body;
815
- const content = await this.editorService.createContent(type, data);
816
- this.emit("content:created", content);
817
- res.status(201).json(content);
818
- } catch (error) {
819
- throw new ContentManagementSuiteInternalError("Failed to create content", error);
820
- }
821
- }
822
- async updateContent(req, res) {
823
- try {
824
- const { id } = req.params;
825
- const { data } = req.body;
826
- const content = await this.editorService.updateContent(id, data);
827
- this.emit("content:updated", content);
828
- res.json(content);
829
- } catch (error) {
830
- throw new ContentManagementSuiteInternalError("Failed to update content", error);
831
- }
427
+ };
428
+
429
+ // src/namespaces/users.ts
430
+ var crypto3 = __toESM(require("crypto"));
431
+ var UsersNamespaceImpl = class {
432
+ constructor(emitter) {
433
+ this.store = /* @__PURE__ */ new Map();
434
+ this.emitter = emitter;
435
+ }
436
+ async create(input) {
437
+ const user = {
438
+ id: crypto3.randomUUID(),
439
+ name: input.name,
440
+ ...input.email !== void 0 ? { email: input.email } : {},
441
+ ...input.role !== void 0 ? { role: input.role } : {},
442
+ createdAt: (/* @__PURE__ */ new Date()).toISOString()
443
+ };
444
+ this.store.set(user.id, user);
445
+ this.emitter.emit("user:created", user);
446
+ return user;
447
+ }
448
+ async get(id) {
449
+ const user = this.store.get(id);
450
+ if (!user) {
451
+ throw new NotFoundError(`User not found: ${id}`);
452
+ }
453
+ return user;
454
+ }
455
+ async list() {
456
+ const items = Array.from(this.store.values());
457
+ return { items, total: items.length };
458
+ }
459
+ async update(id, input) {
460
+ const existing = this.store.get(id);
461
+ if (!existing) {
462
+ throw new NotFoundError(`User not found: ${id}`);
463
+ }
464
+ const updated = {
465
+ ...existing,
466
+ ...input,
467
+ updatedAt: (/* @__PURE__ */ new Date()).toISOString()
468
+ };
469
+ this.store.set(id, updated);
470
+ this.emitter.emit("user:updated", updated);
471
+ return updated;
832
472
  }
833
- async deleteContent(req, res) {
834
- try {
835
- const { id } = req.params;
836
- const { soft = true } = req.query;
837
- await this.editorService.deleteContent(id, soft === "true");
838
- this.emit("content:deleted", { id });
839
- res.status(204).send();
840
- } catch (error) {
841
- throw new ContentManagementSuiteInternalError("Failed to delete content", error);
473
+ async delete(id) {
474
+ if (!this.store.has(id)) {
475
+ throw new NotFoundError(`User not found: ${id}`);
842
476
  }
477
+ this.store.delete(id);
478
+ this.emitter.emit("user:deleted", { id });
843
479
  }
844
- async publishContent(req, res) {
845
- try {
846
- const { id } = req.params;
847
- const content = await this.workflowService.publishContent(id);
848
- this.emit("content:published", content);
849
- res.json(content);
850
- } catch (error) {
851
- throw new ContentManagementSuiteInternalError("Failed to publish content", error);
852
- }
480
+ };
481
+ var PermissionsNamespaceImpl = class {
482
+ constructor() {
483
+ this.store = /* @__PURE__ */ new Map();
853
484
  }
854
- async scheduleContent(req, res) {
855
- try {
856
- const { id } = req.params;
857
- const { date } = req.body;
858
- const content = await this.workflowService.scheduleContent(id, new Date(date));
859
- this.emit("content:scheduled", content, new Date(date));
860
- res.json(content);
861
- } catch (error) {
862
- throw new ContentManagementSuiteInternalError("Failed to schedule content", error);
863
- }
485
+ async check(userId, permission) {
486
+ const perms = this.store.get(userId);
487
+ return perms?.has(permission) ?? false;
864
488
  }
865
- async unpublishContent(req, res) {
866
- try {
867
- const { id } = req.params;
868
- const content = await this.workflowService.unpublishContent(id);
869
- res.json(content);
870
- } catch (error) {
871
- throw new ContentManagementSuiteInternalError("Failed to unpublish content", error);
489
+ async grant(userId, permission) {
490
+ let perms = this.store.get(userId);
491
+ if (!perms) {
492
+ perms = /* @__PURE__ */ new Set();
493
+ this.store.set(userId, perms);
872
494
  }
495
+ perms.add(permission);
873
496
  }
874
- async getWorkflows(req, res) {
875
- try {
876
- const workflows = await this.workflowService.listWorkflows();
877
- res.json(workflows);
878
- } catch (error) {
879
- throw new ContentManagementSuiteInternalError("Failed to get workflows", error);
497
+ async revoke(userId, permission) {
498
+ const perms = this.store.get(userId);
499
+ if (perms) {
500
+ perms.delete(permission);
880
501
  }
881
502
  }
882
- async getWorkflow(req, res) {
883
- try {
884
- const { id } = req.params;
885
- const workflow = await this.workflowService.getWorkflow(id);
886
- res.json(workflow);
887
- } catch (error) {
888
- throw new ContentManagementSuiteNotFoundError("Workflow not found", error);
503
+ };
504
+
505
+ // src/namespaces/config.ts
506
+ function deepMerge(target, source) {
507
+ const result = { ...target };
508
+ for (const key of Object.keys(source)) {
509
+ const sourceVal = source[key];
510
+ const targetVal = result[key];
511
+ if (sourceVal !== null && sourceVal !== void 0 && typeof sourceVal === "object" && !Array.isArray(sourceVal) && targetVal !== null && targetVal !== void 0 && typeof targetVal === "object" && !Array.isArray(targetVal)) {
512
+ result[key] = deepMerge(
513
+ targetVal,
514
+ sourceVal
515
+ );
516
+ } else {
517
+ result[key] = sourceVal;
889
518
  }
890
519
  }
891
- async createWorkflow(req, res) {
892
- try {
893
- const { data } = req.body;
894
- const workflow = await this.workflowService.createWorkflow(data);
895
- res.status(201).json(workflow);
896
- } catch (error) {
897
- throw new ContentManagementSuiteInternalError("Failed to create workflow", error);
898
- }
520
+ return result;
521
+ }
522
+ var ConfigNamespaceImpl = class {
523
+ constructor(initialConfig, emitter) {
524
+ this.config = initialConfig;
525
+ this.emitter = emitter;
899
526
  }
900
- async updateWorkflow(req, res) {
901
- try {
902
- const { id } = req.params;
903
- const { data } = req.body;
904
- const workflow = await this.workflowService.updateWorkflow(id, data);
905
- res.json(workflow);
906
- } catch (error) {
907
- throw new ContentManagementSuiteInternalError("Failed to update workflow", error);
908
- }
527
+ get() {
528
+ return this.config;
909
529
  }
910
- async deleteWorkflow(req, res) {
530
+ update(partial) {
531
+ const merged = deepMerge(this.config, partial);
911
532
  try {
912
- const { id } = req.params;
913
- await this.workflowService.deleteWorkflow(id);
914
- res.status(204).send();
915
- } catch (error) {
916
- throw new ContentManagementSuiteInternalError("Failed to delete workflow", error);
917
- }
533
+ this.config = ContentManagementConfigSchema.parse(merged);
534
+ } catch (err) {
535
+ throw new ValidationError(
536
+ "Invalid configuration",
537
+ err instanceof Error ? { cause: err } : void 0
538
+ );
539
+ }
540
+ this.emitter.emit("config:updated", this.config);
541
+ return this.config;
918
542
  }
919
- async getContentTypes(req, res) {
920
- try {
921
- const contentTypes = this.listContentTypes();
922
- res.json(contentTypes);
923
- } catch (error) {
924
- throw new ContentManagementSuiteInternalError("Failed to get content types", error);
925
- }
543
+ };
544
+
545
+ // src/namespaces/plugins.ts
546
+ var PluginsNamespaceImpl = class {
547
+ constructor(suite) {
548
+ this.store = /* @__PURE__ */ new Map();
549
+ this.suite = suite;
926
550
  }
927
- async handleGetContentType(req, res) {
928
- try {
929
- const id = req.params.id;
930
- if (!id) {
931
- throw new ContentManagementSuiteNotFoundError("Content type ID required");
932
- }
933
- const contentType = this.contentTypes.get(id);
934
- if (!contentType) {
935
- throw new ContentManagementSuiteNotFoundError("Content type not found");
936
- }
937
- res.json(contentType);
938
- } catch (error) {
939
- throw new ContentManagementSuiteNotFoundError("Content type not found", error);
551
+ async register(plugin) {
552
+ if (this.store.has(plugin.name)) {
553
+ throw new ConflictError(`Plugin already registered: ${plugin.name}`);
940
554
  }
555
+ await plugin.setup(this.suite);
556
+ this.store.set(plugin.name, plugin);
941
557
  }
942
- async createContentType(req, res) {
943
- try {
944
- const { data } = req.body;
945
- this.registerContentType(data);
946
- res.status(201).json(data);
947
- } catch (error) {
948
- throw new ContentManagementSuiteInternalError("Failed to create content type", error);
558
+ async unregister(name) {
559
+ const plugin = this.store.get(name);
560
+ if (!plugin) {
561
+ throw new NotFoundError(`Plugin not found: ${name}`);
949
562
  }
950
- }
951
- async updateContentType(req, res) {
952
- try {
953
- const id = req.params.id;
954
- if (!id) {
955
- throw new ContentManagementSuiteNotFoundError("Content type ID required");
956
- }
957
- const { data } = req.body;
958
- this.unregisterContentType(id);
959
- this.registerContentType(data);
960
- res.json(data);
961
- } catch (error) {
962
- throw new ContentManagementSuiteInternalError("Failed to update content type", error);
563
+ if (plugin.teardown) {
564
+ await plugin.teardown(this.suite);
963
565
  }
566
+ this.store.delete(name);
964
567
  }
965
- async deleteContentType(req, res) {
966
- try {
967
- const id = req.params.id;
968
- if (!id) {
969
- throw new ContentManagementSuiteNotFoundError("Content type ID required");
568
+ };
569
+
570
+ // src/content-management-suite.ts
571
+ var ContentManagementSuiteImpl = class extends import_events.EventEmitter {
572
+ constructor(options) {
573
+ super();
574
+ this._initialized = false;
575
+ this._options = options ?? {};
576
+ this._logger = this._options.logger;
577
+ const parsedConfig = ContentManagementConfigSchema.parse(
578
+ this._options.config ?? {}
579
+ );
580
+ this.content = new ContentNamespaceImpl(this);
581
+ this.contentTypes = new ContentTypesNamespaceImpl();
582
+ this.workflows = new WorkflowsNamespaceImpl();
583
+ this.users = new UsersNamespaceImpl(this);
584
+ this.permissions = new PermissionsNamespaceImpl();
585
+ this.config = new ConfigNamespaceImpl(parsedConfig, this);
586
+ this.plugins = new PluginsNamespaceImpl(this);
587
+ }
588
+ async initialize() {
589
+ if (this._initialized) {
590
+ throw new InternalError("Suite is already initialized");
591
+ }
592
+ this.contentTypes.register({ id: "text", name: "text" });
593
+ this.contentTypes.register({ id: "image", name: "image" });
594
+ this.contentTypes.register({ id: "audio", name: "audio" });
595
+ this.contentTypes.register({ id: "video", name: "video" });
596
+ if (this._options.plugins) {
597
+ for (const plugin of this._options.plugins) {
598
+ await this.plugins.register(plugin);
970
599
  }
971
- this.unregisterContentType(id);
972
- res.status(204).send();
973
- } catch (error) {
974
- throw new ContentManagementSuiteInternalError("Failed to delete content type", error);
975
- }
976
- }
977
- async handleGetConfig(req, res) {
978
- try {
979
- res.json(this.config);
980
- } catch (error) {
981
- throw new ContentManagementSuiteInternalError("Failed to get config", error);
982
600
  }
601
+ this._initialized = true;
602
+ this.emit("initialized", void 0);
983
603
  }
984
- async handleUpdateConfig(req, res) {
985
- try {
986
- const { config } = req.body;
987
- const newConfig = ContentManagementConfigSchema.parse({
988
- ...this.config,
989
- ...config
990
- });
991
- this.config = newConfig;
992
- await this.configManager.updateConfig(newConfig);
993
- this.emit("config:updated", newConfig);
994
- res.json(this.config);
995
- } catch (error) {
996
- throw new ContentManagementSuiteValidationError("Invalid configuration", error);
997
- }
998
- }
999
- async getUsers(req, res) {
1000
- try {
1001
- res.json([]);
1002
- } catch (error) {
1003
- throw new ContentManagementSuiteInternalError("Failed to get users", error);
1004
- }
1005
- }
1006
- async getUser(req, res) {
1007
- try {
1008
- const { id } = req.params;
1009
- res.json({ id, name: "User" });
1010
- } catch (error) {
1011
- throw new ContentManagementSuiteNotFoundError("User not found", error);
1012
- }
1013
- }
1014
- async createUser(req, res) {
1015
- try {
1016
- const { data } = req.body;
1017
- res.status(201).json({ id: (0, import_uuid.v4)(), ...data });
1018
- } catch (error) {
1019
- throw new ContentManagementSuiteInternalError("Failed to create user", error);
604
+ async dispose() {
605
+ if (!this._initialized) {
606
+ throw new InternalError("Suite is not initialized");
1020
607
  }
608
+ this._initialized = false;
609
+ this.emit("disposed", void 0);
1021
610
  }
1022
- async updateUser(req, res) {
1023
- try {
1024
- const { id } = req.params;
1025
- const { data } = req.body;
1026
- res.json({ id, ...data });
1027
- } catch (error) {
1028
- throw new ContentManagementSuiteInternalError("Failed to update user", error);
1029
- }
611
+ on(event, listener) {
612
+ return super.on(event, listener);
1030
613
  }
1031
- async deleteUser(req, res) {
1032
- try {
1033
- const { id: _id } = req.params;
1034
- res.status(204).send();
1035
- } catch (error) {
1036
- throw new ContentManagementSuiteInternalError("Failed to delete user", error);
1037
- }
614
+ emit(event, ...args) {
615
+ return super.emit(event, ...args);
1038
616
  }
1039
617
  };
1040
- function createContentManagementSuite(options = {}) {
618
+ function createContentManagementSuite(options) {
1041
619
  return new ContentManagementSuiteImpl(options);
1042
620
  }
621
+
622
+ // src/index.ts
623
+ var import_content_type_registry = require("@bernierllc/content-type-registry");
624
+ var import_content_editorial_workflow = require("@bernierllc/content-editorial-workflow");
625
+ var import_content_autosave_manager = require("@bernierllc/content-autosave-manager");
626
+ var import_content_soft_delete = require("@bernierllc/content-soft-delete");
627
+ var import_content_type_text = require("@bernierllc/content-type-text");
628
+ var import_content_type_image = require("@bernierllc/content-type-image");
629
+ var import_content_type_audio = require("@bernierllc/content-type-audio");
630
+ var import_content_type_video = require("@bernierllc/content-type-video");
1043
631
  // Annotate the CommonJS export names for ESM import in node:
1044
632
  0 && (module.exports = {
1045
633
  AudioContentTypeManager,
1046
634
  AutosaveManager,
635
+ ConflictError,
1047
636
  ContentManagementConfigSchema,
1048
- ContentManagementSuiteConflictError,
1049
- ContentManagementSuiteError,
1050
- ContentManagementSuiteForbiddenError,
1051
- ContentManagementSuiteInternalError,
1052
- ContentManagementSuiteNotFoundError,
1053
- ContentManagementSuiteUnauthorizedError,
1054
- ContentManagementSuiteValidationError,
637
+ ContentManagementError,
1055
638
  ContentSoftDelete,
1056
639
  ContentTypeRegistry,
1057
640
  EditorialWorkflowEngine,
641
+ ForbiddenError,
1058
642
  ImageContentType,
1059
- StageActionButtons,
643
+ InternalError,
644
+ NotFoundError,
1060
645
  TextContentType,
646
+ UnauthorizedError,
647
+ ValidationError,
1061
648
  VideoContentType,
1062
- WorkflowAdminConfig,
1063
649
  WorkflowBuilder,
1064
650
  WorkflowFactory,
1065
- WorkflowStepper,
1066
651
  WorkflowTemplates,
1067
- WorkflowTimeline,
1068
652
  createContentManagementSuite
1069
653
  });
1070
654
  //# sourceMappingURL=index.js.map