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