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