@sonicjs-cms/core 1.0.0-alpha.1
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/LICENSE +21 -0
- package/README.md +285 -0
- package/dist/chunk-JIINOD2W.js +471 -0
- package/dist/chunk-JIINOD2W.js.map +1 -0
- package/dist/chunk-KYGRJCZM.cjs +44 -0
- package/dist/chunk-KYGRJCZM.cjs.map +1 -0
- package/dist/chunk-LOUJRBXV.js +42 -0
- package/dist/chunk-LOUJRBXV.js.map +1 -0
- package/dist/chunk-PZ5AY32C.js +9 -0
- package/dist/chunk-PZ5AY32C.js.map +1 -0
- package/dist/chunk-Q7SFCCGT.cjs +11 -0
- package/dist/chunk-Q7SFCCGT.cjs.map +1 -0
- package/dist/chunk-RGCQSFKC.cjs +481 -0
- package/dist/chunk-RGCQSFKC.cjs.map +1 -0
- package/dist/index.cjs +744 -0
- package/dist/index.cjs.map +1 -0
- package/dist/index.d.cts +8077 -0
- package/dist/index.d.ts +8077 -0
- package/dist/index.js +660 -0
- package/dist/index.js.map +1 -0
- package/dist/middleware.cjs +10 -0
- package/dist/middleware.cjs.map +1 -0
- package/dist/middleware.d.cts +8 -0
- package/dist/middleware.d.ts +8 -0
- package/dist/middleware.js +8 -0
- package/dist/middleware.js.map +1 -0
- package/dist/plugins.cjs +10 -0
- package/dist/plugins.cjs.map +1 -0
- package/dist/plugins.d.cts +8 -0
- package/dist/plugins.d.ts +8 -0
- package/dist/plugins.js +8 -0
- package/dist/plugins.js.map +1 -0
- package/dist/routes.cjs +10 -0
- package/dist/routes.cjs.map +1 -0
- package/dist/routes.d.cts +8 -0
- package/dist/routes.d.ts +8 -0
- package/dist/routes.js +8 -0
- package/dist/routes.js.map +1 -0
- package/dist/services.cjs +10 -0
- package/dist/services.cjs.map +1 -0
- package/dist/services.d.cts +8 -0
- package/dist/services.d.ts +8 -0
- package/dist/services.js +8 -0
- package/dist/services.js.map +1 -0
- package/dist/templates.cjs +10 -0
- package/dist/templates.cjs.map +1 -0
- package/dist/templates.d.cts +8 -0
- package/dist/templates.d.ts +8 -0
- package/dist/templates.js +8 -0
- package/dist/templates.js.map +1 -0
- package/dist/types.cjs +13 -0
- package/dist/types.cjs.map +1 -0
- package/dist/types.d.cts +497 -0
- package/dist/types.d.ts +497 -0
- package/dist/types.js +4 -0
- package/dist/types.js.map +1 -0
- package/dist/utils.cjs +45 -0
- package/dist/utils.cjs.map +1 -0
- package/dist/utils.d.cts +184 -0
- package/dist/utils.d.ts +184 -0
- package/dist/utils.js +4 -0
- package/dist/utils.js.map +1 -0
- package/package.json +131 -0
|
@@ -0,0 +1,471 @@
|
|
|
1
|
+
// src/utils/sanitize.ts
|
|
2
|
+
function escapeHtml(text) {
|
|
3
|
+
if (typeof text !== "string") {
|
|
4
|
+
return "";
|
|
5
|
+
}
|
|
6
|
+
const map = {
|
|
7
|
+
"&": "&",
|
|
8
|
+
"<": "<",
|
|
9
|
+
">": ">",
|
|
10
|
+
'"': """,
|
|
11
|
+
"'": "'"
|
|
12
|
+
};
|
|
13
|
+
return text.replace(/[&<>"']/g, (char) => map[char] || char);
|
|
14
|
+
}
|
|
15
|
+
function sanitizeInput(input) {
|
|
16
|
+
if (!input) {
|
|
17
|
+
return "";
|
|
18
|
+
}
|
|
19
|
+
return escapeHtml(String(input).trim());
|
|
20
|
+
}
|
|
21
|
+
function sanitizeObject(obj, fields) {
|
|
22
|
+
const sanitized = { ...obj };
|
|
23
|
+
for (const field of fields) {
|
|
24
|
+
if (typeof obj[field] === "string") {
|
|
25
|
+
sanitized[field] = sanitizeInput(obj[field]);
|
|
26
|
+
}
|
|
27
|
+
}
|
|
28
|
+
return sanitized;
|
|
29
|
+
}
|
|
30
|
+
|
|
31
|
+
// src/utils/template-renderer.ts
|
|
32
|
+
var TemplateRenderer = class {
|
|
33
|
+
templateCache = /* @__PURE__ */ new Map();
|
|
34
|
+
constructor() {
|
|
35
|
+
}
|
|
36
|
+
/**
|
|
37
|
+
* Simple Handlebars-like template engine
|
|
38
|
+
*/
|
|
39
|
+
renderTemplate(template, data) {
|
|
40
|
+
let rendered = template;
|
|
41
|
+
rendered = rendered.replace(/\{\{#each\s+([^}]+)\}\}([\s\S]*?)\{\{\/each\}\}/g, (_match, arrayName, content) => {
|
|
42
|
+
const array = this.getNestedValue(data, arrayName.trim());
|
|
43
|
+
if (!Array.isArray(array)) return "";
|
|
44
|
+
return array.map((item, index) => {
|
|
45
|
+
const itemContext = {
|
|
46
|
+
...data,
|
|
47
|
+
// Handle primitive items (for {{.}} syntax)
|
|
48
|
+
".": item,
|
|
49
|
+
// Spread item properties if it's an object
|
|
50
|
+
...typeof item === "object" && item !== null ? item : {},
|
|
51
|
+
"@index": index,
|
|
52
|
+
"@first": index === 0,
|
|
53
|
+
"@last": index === array.length - 1
|
|
54
|
+
};
|
|
55
|
+
return this.renderTemplate(content, itemContext);
|
|
56
|
+
}).join("");
|
|
57
|
+
});
|
|
58
|
+
let ifCount = 0;
|
|
59
|
+
while (rendered.includes("{{#if ") && ifCount < 100) {
|
|
60
|
+
const previousRendered = rendered;
|
|
61
|
+
rendered = rendered.replace(/\{\{#if\s+([^}]+)\}\}([\s\S]*?)\{\{\/if\}\}/g, (_match, condition, content) => {
|
|
62
|
+
const value = this.getNestedValue(data, condition.trim());
|
|
63
|
+
const isTruthy = value === true || value && value !== 0 && value !== "" && value !== null && value !== void 0;
|
|
64
|
+
return isTruthy ? this.renderTemplate(content, data) : "";
|
|
65
|
+
});
|
|
66
|
+
if (previousRendered === rendered) break;
|
|
67
|
+
ifCount++;
|
|
68
|
+
}
|
|
69
|
+
rendered = rendered.replace(/\{\{\{([^}]+)\}\}\}/g, (_match, variable) => {
|
|
70
|
+
const value = this.getNestedValue(data, variable.trim());
|
|
71
|
+
return value !== void 0 && value !== null ? String(value) : "";
|
|
72
|
+
});
|
|
73
|
+
rendered = rendered.replace(/\{\{([^}#\/]+)\s+([^}]+)\}\}/g, (match, helper, variable) => {
|
|
74
|
+
const helperName = helper.trim();
|
|
75
|
+
const varName = variable.trim();
|
|
76
|
+
if (helperName === "titleCase") {
|
|
77
|
+
const value = this.getNestedValue(data, varName);
|
|
78
|
+
if (value !== void 0 && value !== null) {
|
|
79
|
+
return this.titleCase(String(value));
|
|
80
|
+
}
|
|
81
|
+
}
|
|
82
|
+
return match;
|
|
83
|
+
});
|
|
84
|
+
rendered = rendered.replace(/\{\{([^}#\/]+)\}\}/g, (match, variable) => {
|
|
85
|
+
const trimmed = variable.trim();
|
|
86
|
+
if (trimmed.includes(" ")) {
|
|
87
|
+
return match;
|
|
88
|
+
}
|
|
89
|
+
const value = this.getNestedValue(data, trimmed);
|
|
90
|
+
if (value === null) return "";
|
|
91
|
+
if (value === void 0) return "";
|
|
92
|
+
return String(value);
|
|
93
|
+
});
|
|
94
|
+
return rendered;
|
|
95
|
+
}
|
|
96
|
+
/**
|
|
97
|
+
* Get nested value from object using dot notation
|
|
98
|
+
*/
|
|
99
|
+
getNestedValue(obj, path) {
|
|
100
|
+
if (!obj || path === "") return void 0;
|
|
101
|
+
return path.split(".").reduce((current, key) => {
|
|
102
|
+
if (current === null || current === void 0) return void 0;
|
|
103
|
+
return current[key];
|
|
104
|
+
}, obj);
|
|
105
|
+
}
|
|
106
|
+
/**
|
|
107
|
+
* Title case helper function
|
|
108
|
+
*/
|
|
109
|
+
titleCase(str) {
|
|
110
|
+
return str.replace(/_/g, " ").replace(/\b\w/g, (l) => l.toUpperCase());
|
|
111
|
+
}
|
|
112
|
+
/**
|
|
113
|
+
* Render a template string with data
|
|
114
|
+
*/
|
|
115
|
+
render(template, data = {}) {
|
|
116
|
+
return this.renderTemplate(template, data);
|
|
117
|
+
}
|
|
118
|
+
/**
|
|
119
|
+
* Clear template cache (useful for development)
|
|
120
|
+
*/
|
|
121
|
+
clearCache() {
|
|
122
|
+
this.templateCache.clear();
|
|
123
|
+
}
|
|
124
|
+
};
|
|
125
|
+
var templateRenderer = new TemplateRenderer();
|
|
126
|
+
function renderTemplate(template, data = {}) {
|
|
127
|
+
return templateRenderer.render(template, data);
|
|
128
|
+
}
|
|
129
|
+
|
|
130
|
+
// src/utils/query-filter.ts
|
|
131
|
+
var QueryFilterBuilder = class {
|
|
132
|
+
params = [];
|
|
133
|
+
errors = [];
|
|
134
|
+
/**
|
|
135
|
+
* Build a complete SQL query from filter object
|
|
136
|
+
*/
|
|
137
|
+
build(baseTable, filter) {
|
|
138
|
+
this.params = [];
|
|
139
|
+
this.errors = [];
|
|
140
|
+
let sql = `SELECT * FROM ${baseTable}`;
|
|
141
|
+
if (filter.where) {
|
|
142
|
+
const whereClause = this.buildWhereClause(filter.where);
|
|
143
|
+
if (whereClause) {
|
|
144
|
+
sql += ` WHERE ${whereClause}`;
|
|
145
|
+
}
|
|
146
|
+
}
|
|
147
|
+
if (filter.sort && filter.sort.length > 0) {
|
|
148
|
+
const orderClauses = filter.sort.map((s) => `${this.sanitizeFieldName(s.field)} ${s.order.toUpperCase()}`).join(", ");
|
|
149
|
+
sql += ` ORDER BY ${orderClauses}`;
|
|
150
|
+
}
|
|
151
|
+
if (filter.limit) {
|
|
152
|
+
sql += ` LIMIT ?`;
|
|
153
|
+
this.params.push(filter.limit);
|
|
154
|
+
}
|
|
155
|
+
if (filter.offset) {
|
|
156
|
+
sql += ` OFFSET ?`;
|
|
157
|
+
this.params.push(filter.offset);
|
|
158
|
+
}
|
|
159
|
+
return {
|
|
160
|
+
sql,
|
|
161
|
+
params: this.params,
|
|
162
|
+
errors: this.errors
|
|
163
|
+
};
|
|
164
|
+
}
|
|
165
|
+
/**
|
|
166
|
+
* Build WHERE clause from filter group
|
|
167
|
+
*/
|
|
168
|
+
buildWhereClause(group) {
|
|
169
|
+
const clauses = [];
|
|
170
|
+
if (group.and && group.and.length > 0) {
|
|
171
|
+
const andClauses = group.and.map((condition) => this.buildCondition(condition)).filter((clause) => clause !== null);
|
|
172
|
+
if (andClauses.length > 0) {
|
|
173
|
+
clauses.push(`(${andClauses.join(" AND ")})`);
|
|
174
|
+
}
|
|
175
|
+
}
|
|
176
|
+
if (group.or && group.or.length > 0) {
|
|
177
|
+
const orClauses = group.or.map((condition) => this.buildCondition(condition)).filter((clause) => clause !== null);
|
|
178
|
+
if (orClauses.length > 0) {
|
|
179
|
+
clauses.push(`(${orClauses.join(" OR ")})`);
|
|
180
|
+
}
|
|
181
|
+
}
|
|
182
|
+
return clauses.join(" AND ");
|
|
183
|
+
}
|
|
184
|
+
/**
|
|
185
|
+
* Build a single condition
|
|
186
|
+
*/
|
|
187
|
+
buildCondition(condition) {
|
|
188
|
+
const field = this.sanitizeFieldName(condition.field);
|
|
189
|
+
switch (condition.operator) {
|
|
190
|
+
case "equals":
|
|
191
|
+
return this.buildEquals(field, condition.value);
|
|
192
|
+
case "not_equals":
|
|
193
|
+
return this.buildNotEquals(field, condition.value);
|
|
194
|
+
case "greater_than":
|
|
195
|
+
return this.buildComparison(field, ">", condition.value);
|
|
196
|
+
case "greater_than_equal":
|
|
197
|
+
return this.buildComparison(field, ">=", condition.value);
|
|
198
|
+
case "less_than":
|
|
199
|
+
return this.buildComparison(field, "<", condition.value);
|
|
200
|
+
case "less_than_equal":
|
|
201
|
+
return this.buildComparison(field, "<=", condition.value);
|
|
202
|
+
case "like":
|
|
203
|
+
return this.buildLike(field, condition.value);
|
|
204
|
+
case "contains":
|
|
205
|
+
return this.buildContains(field, condition.value);
|
|
206
|
+
case "in":
|
|
207
|
+
return this.buildIn(field, condition.value);
|
|
208
|
+
case "not_in":
|
|
209
|
+
return this.buildNotIn(field, condition.value);
|
|
210
|
+
case "all":
|
|
211
|
+
return this.buildAll(field, condition.value);
|
|
212
|
+
case "exists":
|
|
213
|
+
return this.buildExists(field, condition.value);
|
|
214
|
+
case "near":
|
|
215
|
+
this.errors.push(`'near' operator not supported in SQLite. Use spatial extension or application-level filtering.`);
|
|
216
|
+
return null;
|
|
217
|
+
case "within":
|
|
218
|
+
this.errors.push(`'within' operator not supported in SQLite. Use spatial extension or application-level filtering.`);
|
|
219
|
+
return null;
|
|
220
|
+
case "intersects":
|
|
221
|
+
this.errors.push(`'intersects' operator not supported in SQLite. Use spatial extension or application-level filtering.`);
|
|
222
|
+
return null;
|
|
223
|
+
default:
|
|
224
|
+
this.errors.push(`Unknown operator: ${condition.operator}`);
|
|
225
|
+
return null;
|
|
226
|
+
}
|
|
227
|
+
}
|
|
228
|
+
/**
|
|
229
|
+
* Build equals condition
|
|
230
|
+
*/
|
|
231
|
+
buildEquals(field, value) {
|
|
232
|
+
if (value === null) {
|
|
233
|
+
return `${field} IS NULL`;
|
|
234
|
+
}
|
|
235
|
+
this.params.push(value);
|
|
236
|
+
return `${field} = ?`;
|
|
237
|
+
}
|
|
238
|
+
/**
|
|
239
|
+
* Build not equals condition
|
|
240
|
+
*/
|
|
241
|
+
buildNotEquals(field, value) {
|
|
242
|
+
if (value === null) {
|
|
243
|
+
return `${field} IS NOT NULL`;
|
|
244
|
+
}
|
|
245
|
+
this.params.push(value);
|
|
246
|
+
return `${field} != ?`;
|
|
247
|
+
}
|
|
248
|
+
/**
|
|
249
|
+
* Build comparison condition (>, >=, <, <=)
|
|
250
|
+
*/
|
|
251
|
+
buildComparison(field, operator, value) {
|
|
252
|
+
this.params.push(value);
|
|
253
|
+
return `${field} ${operator} ?`;
|
|
254
|
+
}
|
|
255
|
+
/**
|
|
256
|
+
* Build LIKE condition (case-insensitive, all words must be present)
|
|
257
|
+
*/
|
|
258
|
+
buildLike(field, value) {
|
|
259
|
+
const words = value.split(/\s+/).filter((w) => w.length > 0);
|
|
260
|
+
if (words.length === 0) {
|
|
261
|
+
return `1=1`;
|
|
262
|
+
}
|
|
263
|
+
const conditions = words.map((word) => {
|
|
264
|
+
this.params.push(`%${word}%`);
|
|
265
|
+
return `${field} LIKE ?`;
|
|
266
|
+
});
|
|
267
|
+
return `(${conditions.join(" AND ")})`;
|
|
268
|
+
}
|
|
269
|
+
/**
|
|
270
|
+
* Build CONTAINS condition (case-insensitive substring)
|
|
271
|
+
*/
|
|
272
|
+
buildContains(field, value) {
|
|
273
|
+
this.params.push(`%${value}%`);
|
|
274
|
+
return `${field} LIKE ?`;
|
|
275
|
+
}
|
|
276
|
+
/**
|
|
277
|
+
* Build IN condition
|
|
278
|
+
*/
|
|
279
|
+
buildIn(field, value) {
|
|
280
|
+
let values;
|
|
281
|
+
if (typeof value === "string") {
|
|
282
|
+
values = value.split(",").map((v) => v.trim()).filter((v) => v.length > 0);
|
|
283
|
+
} else if (Array.isArray(value)) {
|
|
284
|
+
values = value;
|
|
285
|
+
} else {
|
|
286
|
+
values = [value];
|
|
287
|
+
}
|
|
288
|
+
if (values.length === 0) {
|
|
289
|
+
return `1=0`;
|
|
290
|
+
}
|
|
291
|
+
const placeholders = values.map((v) => {
|
|
292
|
+
this.params.push(v);
|
|
293
|
+
return "?";
|
|
294
|
+
}).join(", ");
|
|
295
|
+
return `${field} IN (${placeholders})`;
|
|
296
|
+
}
|
|
297
|
+
/**
|
|
298
|
+
* Build NOT IN condition
|
|
299
|
+
*/
|
|
300
|
+
buildNotIn(field, value) {
|
|
301
|
+
let values;
|
|
302
|
+
if (typeof value === "string") {
|
|
303
|
+
values = value.split(",").map((v) => v.trim()).filter((v) => v.length > 0);
|
|
304
|
+
} else if (Array.isArray(value)) {
|
|
305
|
+
values = value;
|
|
306
|
+
} else {
|
|
307
|
+
values = [value];
|
|
308
|
+
}
|
|
309
|
+
if (values.length === 0) {
|
|
310
|
+
return `1=1`;
|
|
311
|
+
}
|
|
312
|
+
const placeholders = values.map((v) => {
|
|
313
|
+
this.params.push(v);
|
|
314
|
+
return "?";
|
|
315
|
+
}).join(", ");
|
|
316
|
+
return `${field} NOT IN (${placeholders})`;
|
|
317
|
+
}
|
|
318
|
+
/**
|
|
319
|
+
* Build ALL condition (value must contain all items in list)
|
|
320
|
+
* For SQLite, we'll check if a JSON array contains all values
|
|
321
|
+
*/
|
|
322
|
+
buildAll(field, value) {
|
|
323
|
+
let values;
|
|
324
|
+
if (typeof value === "string") {
|
|
325
|
+
values = value.split(",").map((v) => v.trim()).filter((v) => v.length > 0);
|
|
326
|
+
} else if (Array.isArray(value)) {
|
|
327
|
+
values = value;
|
|
328
|
+
} else {
|
|
329
|
+
values = [value];
|
|
330
|
+
}
|
|
331
|
+
if (values.length === 0) {
|
|
332
|
+
return `1=1`;
|
|
333
|
+
}
|
|
334
|
+
const conditions = values.map((val) => {
|
|
335
|
+
this.params.push(`%${val}%`);
|
|
336
|
+
return `${field} LIKE ?`;
|
|
337
|
+
});
|
|
338
|
+
return `(${conditions.join(" AND ")})`;
|
|
339
|
+
}
|
|
340
|
+
/**
|
|
341
|
+
* Build EXISTS condition
|
|
342
|
+
*/
|
|
343
|
+
buildExists(field, value) {
|
|
344
|
+
if (value) {
|
|
345
|
+
return `${field} IS NOT NULL AND ${field} != ''`;
|
|
346
|
+
} else {
|
|
347
|
+
return `(${field} IS NULL OR ${field} = '')`;
|
|
348
|
+
}
|
|
349
|
+
}
|
|
350
|
+
/**
|
|
351
|
+
* Sanitize field names to prevent SQL injection
|
|
352
|
+
*/
|
|
353
|
+
sanitizeFieldName(field) {
|
|
354
|
+
const sanitized = field.replace(/[^a-zA-Z0-9_$.]/g, "");
|
|
355
|
+
if (sanitized.includes(".")) {
|
|
356
|
+
const [table, ...path] = sanitized.split(".");
|
|
357
|
+
return `json_extract(${table}, '$.${path.join(".")}')`;
|
|
358
|
+
}
|
|
359
|
+
return sanitized;
|
|
360
|
+
}
|
|
361
|
+
/**
|
|
362
|
+
* Parse filter from query string
|
|
363
|
+
*/
|
|
364
|
+
static parseFromQuery(query) {
|
|
365
|
+
const filter = {};
|
|
366
|
+
if (query.where) {
|
|
367
|
+
try {
|
|
368
|
+
filter.where = typeof query.where === "string" ? JSON.parse(query.where) : query.where;
|
|
369
|
+
} catch (e) {
|
|
370
|
+
console.error("Failed to parse where clause:", e);
|
|
371
|
+
}
|
|
372
|
+
}
|
|
373
|
+
if (!filter.where) {
|
|
374
|
+
filter.where = { and: [] };
|
|
375
|
+
}
|
|
376
|
+
if (!filter.where.and) {
|
|
377
|
+
filter.where.and = [];
|
|
378
|
+
}
|
|
379
|
+
const simpleFieldMappings = {
|
|
380
|
+
"status": "status",
|
|
381
|
+
"collection_id": "collection_id"
|
|
382
|
+
};
|
|
383
|
+
for (const [queryParam, dbField] of Object.entries(simpleFieldMappings)) {
|
|
384
|
+
if (query[queryParam]) {
|
|
385
|
+
filter.where.and.push({
|
|
386
|
+
field: dbField,
|
|
387
|
+
operator: "equals",
|
|
388
|
+
value: query[queryParam]
|
|
389
|
+
});
|
|
390
|
+
}
|
|
391
|
+
}
|
|
392
|
+
if (query.limit) {
|
|
393
|
+
filter.limit = Math.min(parseInt(query.limit), 1e3);
|
|
394
|
+
}
|
|
395
|
+
if (query.offset) {
|
|
396
|
+
filter.offset = parseInt(query.offset);
|
|
397
|
+
}
|
|
398
|
+
if (query.sort) {
|
|
399
|
+
try {
|
|
400
|
+
filter.sort = typeof query.sort === "string" ? JSON.parse(query.sort) : query.sort;
|
|
401
|
+
} catch (e) {
|
|
402
|
+
console.error("Failed to parse sort clause:", e);
|
|
403
|
+
}
|
|
404
|
+
}
|
|
405
|
+
return filter;
|
|
406
|
+
}
|
|
407
|
+
};
|
|
408
|
+
function buildQuery(table, filter) {
|
|
409
|
+
const builder = new QueryFilterBuilder();
|
|
410
|
+
return builder.build(table, filter);
|
|
411
|
+
}
|
|
412
|
+
|
|
413
|
+
// src/utils/metrics.ts
|
|
414
|
+
var MetricsTracker = class {
|
|
415
|
+
requests = [];
|
|
416
|
+
windowSize = 1e4;
|
|
417
|
+
// 10 seconds window
|
|
418
|
+
/**
|
|
419
|
+
* Record a new request
|
|
420
|
+
*/
|
|
421
|
+
recordRequest() {
|
|
422
|
+
const now = Date.now();
|
|
423
|
+
this.requests.push({ timestamp: now });
|
|
424
|
+
this.cleanup(now);
|
|
425
|
+
}
|
|
426
|
+
/**
|
|
427
|
+
* Clean up old requests outside the window
|
|
428
|
+
*/
|
|
429
|
+
cleanup(now) {
|
|
430
|
+
const cutoff = now - this.windowSize;
|
|
431
|
+
this.requests = this.requests.filter((req) => req.timestamp > cutoff);
|
|
432
|
+
}
|
|
433
|
+
/**
|
|
434
|
+
* Get current requests per second
|
|
435
|
+
*/
|
|
436
|
+
getRequestsPerSecond() {
|
|
437
|
+
const now = Date.now();
|
|
438
|
+
this.cleanup(now);
|
|
439
|
+
if (this.requests.length === 0) {
|
|
440
|
+
return 0;
|
|
441
|
+
}
|
|
442
|
+
const oneSecondAgo = now - 1e3;
|
|
443
|
+
const recentRequests = this.requests.filter((req) => req.timestamp > oneSecondAgo);
|
|
444
|
+
return recentRequests.length;
|
|
445
|
+
}
|
|
446
|
+
/**
|
|
447
|
+
* Get total requests in the current window
|
|
448
|
+
*/
|
|
449
|
+
getTotalRequests() {
|
|
450
|
+
const now = Date.now();
|
|
451
|
+
this.cleanup(now);
|
|
452
|
+
return this.requests.length;
|
|
453
|
+
}
|
|
454
|
+
/**
|
|
455
|
+
* Get average requests per second over the window
|
|
456
|
+
*/
|
|
457
|
+
getAverageRPS() {
|
|
458
|
+
const now = Date.now();
|
|
459
|
+
this.cleanup(now);
|
|
460
|
+
if (this.requests.length === 0) {
|
|
461
|
+
return 0;
|
|
462
|
+
}
|
|
463
|
+
const windowSeconds = this.windowSize / 1e3;
|
|
464
|
+
return this.requests.length / windowSeconds;
|
|
465
|
+
}
|
|
466
|
+
};
|
|
467
|
+
var metricsTracker = new MetricsTracker();
|
|
468
|
+
|
|
469
|
+
export { QueryFilterBuilder, TemplateRenderer, buildQuery, escapeHtml, metricsTracker, renderTemplate, sanitizeInput, sanitizeObject, templateRenderer };
|
|
470
|
+
//# sourceMappingURL=chunk-JIINOD2W.js.map
|
|
471
|
+
//# sourceMappingURL=chunk-JIINOD2W.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"sources":["../src/utils/sanitize.ts","../src/utils/template-renderer.ts","../src/utils/query-filter.ts","../src/utils/metrics.ts"],"names":[],"mappings":"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","file":"chunk-JIINOD2W.js","sourcesContent":["/**\n * HTML sanitization utilities for preventing XSS attacks\n */\n\n/**\n * Escapes HTML special characters to prevent XSS attacks\n * @param text - The text to escape\n * @returns The escaped text safe for HTML output\n */\nexport function escapeHtml(text: string): string {\n if (typeof text !== 'string') {\n return ''\n }\n\n const map: Record<string, string> = {\n '&': '&',\n '<': '<',\n '>': '>',\n '\"': '"',\n \"'\": '''\n }\n\n return text.replace(/[&<>\"']/g, (char) => map[char] || char)\n}\n\n/**\n * Sanitizes user input by escaping HTML special characters\n * This should be used for all user-provided text fields to prevent XSS\n * @param input - The input string to sanitize\n * @returns The sanitized string\n */\nexport function sanitizeInput(input: string | null | undefined): string {\n if (!input) {\n return ''\n }\n return escapeHtml(String(input).trim())\n}\n\n/**\n * Sanitizes an object's string properties\n * @param obj - Object with string properties to sanitize\n * @param fields - Array of field names to sanitize\n * @returns New object with sanitized fields\n */\nexport function sanitizeObject<T extends Record<string, any>>(\n obj: T,\n fields: (keyof T)[]\n): T {\n const sanitized = { ...obj }\n\n for (const field of fields) {\n if (typeof obj[field] === 'string') {\n sanitized[field] = sanitizeInput(obj[field]) as T[keyof T]\n }\n }\n\n return sanitized\n}\n","// Template renderer compatible with Cloudflare Workers\n// No filesystem access available\n\ninterface TemplateData {\n [key: string]: any\n}\n\nexport class TemplateRenderer {\n private templateCache = new Map<string, string>()\n\n constructor() {\n // Cloudflare Workers compatible - no filesystem access\n }\n\n /**\n * Simple Handlebars-like template engine\n */\n private renderTemplate(template: string, data: TemplateData): string {\n let rendered = template\n\n // Handle each loops - process outermost loops first for proper nesting\n rendered = rendered.replace(/\\{\\{#each\\s+([^}]+)\\}\\}([\\s\\S]*?)\\{\\{\\/each\\}\\}/g, (_match, arrayName, content) => {\n const array = this.getNestedValue(data, arrayName.trim())\n if (!Array.isArray(array)) return ''\n \n return array.map((item, index) => {\n // Create context with array item and special variables\n const itemContext = {\n ...data,\n // Handle primitive items (for {{.}} syntax)\n '.': item,\n // Spread item properties if it's an object\n ...(typeof item === 'object' && item !== null ? item : {}),\n '@index': index,\n '@first': index === 0,\n '@last': index === array.length - 1\n }\n return this.renderTemplate(content, itemContext)\n }).join('')\n })\n\n // Second pass: Handle conditionals\n let ifCount = 0\n while (rendered.includes('{{#if ') && ifCount < 100) {\n const previousRendered = rendered\n rendered = rendered.replace(/\\{\\{#if\\s+([^}]+)\\}\\}([\\s\\S]*?)\\{\\{\\/if\\}\\}/g, (_match, condition, content) => {\n const value = this.getNestedValue(data, condition.trim())\n // Handle boolean values properly - @first/@last are explicitly boolean\n const isTruthy = value === true || (value && value !== 0 && value !== '' && value !== null && value !== undefined)\n return isTruthy ? this.renderTemplate(content, data) : ''\n })\n if (previousRendered === rendered) break\n ifCount++\n }\n\n // Third pass: Handle triple braces for raw HTML {{{variable}}}\n rendered = rendered.replace(/\\{\\{\\{([^}]+)\\}\\}\\}/g, (_match, variable) => {\n const value = this.getNestedValue(data, variable.trim())\n return value !== undefined && value !== null ? String(value) : ''\n })\n\n // Fourth pass: Handle helper functions like {{titleCase field}}\n rendered = rendered.replace(/\\{\\{([^}#\\/]+)\\s+([^}]+)\\}\\}/g, (match, helper, variable) => {\n const helperName = helper.trim()\n const varName = variable.trim()\n \n if (helperName === 'titleCase') {\n const value = this.getNestedValue(data, varName)\n if (value !== undefined && value !== null) {\n return this.titleCase(String(value))\n }\n }\n \n return match // Return original if helper not found\n })\n\n // Final pass: Handle simple variables {{variable}}\n rendered = rendered.replace(/\\{\\{([^}#\\/]+)\\}\\}/g, (match, variable) => {\n const trimmed = variable.trim()\n \n // Skip if it's a helper function (has spaces)\n if (trimmed.includes(' ')) {\n return match\n }\n \n const value = this.getNestedValue(data, trimmed)\n if (value === null) return ''\n if (value === undefined) return ''\n return String(value)\n })\n\n return rendered\n }\n\n /**\n * Get nested value from object using dot notation\n */\n private getNestedValue(obj: any, path: string): any {\n if (!obj || path === '') return undefined\n \n return path.split('.').reduce((current, key) => {\n if (current === null || current === undefined) return undefined\n return current[key]\n }, obj)\n }\n\n /**\n * Title case helper function\n */\n private titleCase(str: string): string {\n return str\n .replace(/_/g, ' ')\n .replace(/\\b\\w/g, l => l.toUpperCase())\n }\n\n /**\n * Render a template string with data\n */\n render(template: string, data: TemplateData = {}): string {\n return this.renderTemplate(template, data)\n }\n\n /**\n * Clear template cache (useful for development)\n */\n clearCache(): void {\n this.templateCache.clear()\n }\n}\n\n// Export singleton instance\nexport const templateRenderer = new TemplateRenderer()\n\n// Utility function to render template strings directly\nexport function renderTemplate(template: string, data: TemplateData = {}): string {\n return templateRenderer.render(template, data)\n}","/**\n * Query Filter Builder for SonicJS AI\n * Supports comprehensive filtering with AND/OR logic\n * Compatible with D1 Database (SQLite)\n */\n\nexport type FilterOperator =\n | 'equals'\n | 'not_equals'\n | 'greater_than'\n | 'greater_than_equal'\n | 'less_than'\n | 'less_than_equal'\n | 'like'\n | 'contains'\n | 'in'\n | 'not_in'\n | 'all'\n | 'exists'\n | 'near'\n | 'within'\n | 'intersects'\n\nexport interface FilterCondition {\n field: string\n operator: FilterOperator\n value: any\n}\n\nexport interface FilterGroup {\n and?: FilterCondition[]\n or?: FilterCondition[]\n}\n\nexport interface QueryFilter {\n where?: FilterGroup\n limit?: number\n offset?: number\n sort?: {\n field: string\n order: 'asc' | 'desc'\n }[]\n}\n\nexport interface QueryResult {\n sql: string\n params: any[]\n errors: string[]\n}\n\n/**\n * Query Filter Builder\n * Converts filter objects into SQL WHERE clauses with parameterized queries\n */\nexport class QueryFilterBuilder {\n private params: any[] = []\n private errors: string[] = []\n\n /**\n * Build a complete SQL query from filter object\n */\n build(baseTable: string, filter: QueryFilter): QueryResult {\n this.params = []\n this.errors = []\n\n let sql = `SELECT * FROM ${baseTable}`\n\n // Build WHERE clause\n if (filter.where) {\n const whereClause = this.buildWhereClause(filter.where)\n if (whereClause) {\n sql += ` WHERE ${whereClause}`\n }\n }\n\n // Build ORDER BY clause\n if (filter.sort && filter.sort.length > 0) {\n const orderClauses = filter.sort\n .map(s => `${this.sanitizeFieldName(s.field)} ${s.order.toUpperCase()}`)\n .join(', ')\n sql += ` ORDER BY ${orderClauses}`\n }\n\n // Build LIMIT clause\n if (filter.limit) {\n sql += ` LIMIT ?`\n this.params.push(filter.limit)\n }\n\n // Build OFFSET clause\n if (filter.offset) {\n sql += ` OFFSET ?`\n this.params.push(filter.offset)\n }\n\n return {\n sql,\n params: this.params,\n errors: this.errors\n }\n }\n\n /**\n * Build WHERE clause from filter group\n */\n private buildWhereClause(group: FilterGroup): string {\n const clauses: string[] = []\n\n // Handle AND conditions\n if (group.and && group.and.length > 0) {\n const andClauses = group.and\n .map(condition => this.buildCondition(condition))\n .filter(clause => clause !== null)\n\n if (andClauses.length > 0) {\n clauses.push(`(${andClauses.join(' AND ')})`)\n }\n }\n\n // Handle OR conditions\n if (group.or && group.or.length > 0) {\n const orClauses = group.or\n .map(condition => this.buildCondition(condition))\n .filter(clause => clause !== null)\n\n if (orClauses.length > 0) {\n clauses.push(`(${orClauses.join(' OR ')})`)\n }\n }\n\n return clauses.join(' AND ')\n }\n\n /**\n * Build a single condition\n */\n private buildCondition(condition: FilterCondition): string | null {\n const field = this.sanitizeFieldName(condition.field)\n\n switch (condition.operator) {\n case 'equals':\n return this.buildEquals(field, condition.value)\n\n case 'not_equals':\n return this.buildNotEquals(field, condition.value)\n\n case 'greater_than':\n return this.buildComparison(field, '>', condition.value)\n\n case 'greater_than_equal':\n return this.buildComparison(field, '>=', condition.value)\n\n case 'less_than':\n return this.buildComparison(field, '<', condition.value)\n\n case 'less_than_equal':\n return this.buildComparison(field, '<=', condition.value)\n\n case 'like':\n return this.buildLike(field, condition.value)\n\n case 'contains':\n return this.buildContains(field, condition.value)\n\n case 'in':\n return this.buildIn(field, condition.value)\n\n case 'not_in':\n return this.buildNotIn(field, condition.value)\n\n case 'all':\n return this.buildAll(field, condition.value)\n\n case 'exists':\n return this.buildExists(field, condition.value)\n\n case 'near':\n this.errors.push(`'near' operator not supported in SQLite. Use spatial extension or application-level filtering.`)\n return null\n\n case 'within':\n this.errors.push(`'within' operator not supported in SQLite. Use spatial extension or application-level filtering.`)\n return null\n\n case 'intersects':\n this.errors.push(`'intersects' operator not supported in SQLite. Use spatial extension or application-level filtering.`)\n return null\n\n default:\n this.errors.push(`Unknown operator: ${condition.operator}`)\n return null\n }\n }\n\n /**\n * Build equals condition\n */\n private buildEquals(field: string, value: any): string {\n if (value === null) {\n return `${field} IS NULL`\n }\n this.params.push(value)\n return `${field} = ?`\n }\n\n /**\n * Build not equals condition\n */\n private buildNotEquals(field: string, value: any): string {\n if (value === null) {\n return `${field} IS NOT NULL`\n }\n this.params.push(value)\n return `${field} != ?`\n }\n\n /**\n * Build comparison condition (>, >=, <, <=)\n */\n private buildComparison(field: string, operator: string, value: any): string {\n this.params.push(value)\n return `${field} ${operator} ?`\n }\n\n /**\n * Build LIKE condition (case-insensitive, all words must be present)\n */\n private buildLike(field: string, value: string): string {\n const words = value.split(/\\s+/).filter(w => w.length > 0)\n\n if (words.length === 0) {\n return `1=1` // No-op condition\n }\n\n const conditions = words.map(word => {\n this.params.push(`%${word}%`)\n return `${field} LIKE ?`\n })\n\n return `(${conditions.join(' AND ')})`\n }\n\n /**\n * Build CONTAINS condition (case-insensitive substring)\n */\n private buildContains(field: string, value: string): string {\n this.params.push(`%${value}%`)\n return `${field} LIKE ?`\n }\n\n /**\n * Build IN condition\n */\n private buildIn(field: string, value: any): string {\n let values: any[]\n\n if (typeof value === 'string') {\n // Parse comma-delimited string\n values = value.split(',').map(v => v.trim()).filter(v => v.length > 0)\n } else if (Array.isArray(value)) {\n values = value\n } else {\n values = [value]\n }\n\n if (values.length === 0) {\n return `1=0` // No values means no matches\n }\n\n const placeholders = values.map(v => {\n this.params.push(v)\n return '?'\n }).join(', ')\n\n return `${field} IN (${placeholders})`\n }\n\n /**\n * Build NOT IN condition\n */\n private buildNotIn(field: string, value: any): string {\n let values: any[]\n\n if (typeof value === 'string') {\n // Parse comma-delimited string\n values = value.split(',').map(v => v.trim()).filter(v => v.length > 0)\n } else if (Array.isArray(value)) {\n values = value\n } else {\n values = [value]\n }\n\n if (values.length === 0) {\n return `1=1` // No values means all match\n }\n\n const placeholders = values.map(v => {\n this.params.push(v)\n return '?'\n }).join(', ')\n\n return `${field} NOT IN (${placeholders})`\n }\n\n /**\n * Build ALL condition (value must contain all items in list)\n * For SQLite, we'll check if a JSON array contains all values\n */\n private buildAll(field: string, value: any): string {\n let values: any[]\n\n if (typeof value === 'string') {\n values = value.split(',').map(v => v.trim()).filter(v => v.length > 0)\n } else if (Array.isArray(value)) {\n values = value\n } else {\n values = [value]\n }\n\n if (values.length === 0) {\n return `1=1`\n }\n\n // For SQLite, check if field contains all values using JSON functions\n // This assumes the field is a JSON array or comma-separated string\n const conditions = values.map(val => {\n this.params.push(`%${val}%`)\n return `${field} LIKE ?`\n })\n\n return `(${conditions.join(' AND ')})`\n }\n\n /**\n * Build EXISTS condition\n */\n private buildExists(field: string, value: boolean): string {\n if (value) {\n return `${field} IS NOT NULL AND ${field} != ''`\n } else {\n return `(${field} IS NULL OR ${field} = '')`\n }\n }\n\n /**\n * Sanitize field names to prevent SQL injection\n */\n private sanitizeFieldName(field: string): string {\n // Allow alphanumeric, underscores, dots (for JSON fields)\n const sanitized = field.replace(/[^a-zA-Z0-9_$.]/g, '')\n\n // Handle JSON field access (e.g., data.title -> json_extract(data, '$.title'))\n if (sanitized.includes('.')) {\n const [table, ...path] = sanitized.split('.')\n return `json_extract(${table}, '$.${path.join('.')}')`\n }\n\n return sanitized\n }\n\n /**\n * Parse filter from query string\n */\n static parseFromQuery(query: Record<string, any>): QueryFilter {\n const filter: QueryFilter = {}\n\n // Parse where clause from 'where' parameter (JSON string)\n if (query.where) {\n try {\n filter.where = typeof query.where === 'string'\n ? JSON.parse(query.where)\n : query.where\n } catch (e) {\n console.error('Failed to parse where clause:', e)\n }\n }\n\n // Initialize where clause if not present\n if (!filter.where) {\n filter.where = { and: [] }\n }\n if (!filter.where.and) {\n filter.where.and = []\n }\n\n // Parse simple field filters (status, collection_id, etc.)\n // These are convenience parameters that get converted to WHERE conditions\n const simpleFieldMappings: Record<string, string> = {\n 'status': 'status',\n 'collection_id': 'collection_id'\n }\n\n for (const [queryParam, dbField] of Object.entries(simpleFieldMappings)) {\n if (query[queryParam]) {\n filter.where.and.push({\n field: dbField,\n operator: 'equals',\n value: query[queryParam]\n })\n }\n }\n\n // Parse limit\n if (query.limit) {\n filter.limit = Math.min(parseInt(query.limit), 1000) // Max 1000\n }\n\n // Parse offset\n if (query.offset) {\n filter.offset = parseInt(query.offset)\n }\n\n // Parse sort\n if (query.sort) {\n try {\n filter.sort = typeof query.sort === 'string'\n ? JSON.parse(query.sort)\n : query.sort\n } catch (e) {\n console.error('Failed to parse sort clause:', e)\n }\n }\n\n return filter\n }\n}\n\n/**\n * Helper function to build query from filter\n */\nexport function buildQuery(table: string, filter: QueryFilter): QueryResult {\n const builder = new QueryFilterBuilder()\n return builder.build(table, filter)\n}\n","/**\n * Simple in-memory metrics tracker for real-time analytics\n * Tracks requests per second using a sliding window\n */\n\ninterface RequestMetrics {\n timestamp: number\n}\n\nclass MetricsTracker {\n private requests: RequestMetrics[] = []\n private readonly windowSize = 10000 // 10 seconds window\n\n /**\n * Record a new request\n */\n recordRequest(): void {\n const now = Date.now()\n this.requests.push({ timestamp: now })\n this.cleanup(now)\n }\n\n /**\n * Clean up old requests outside the window\n */\n private cleanup(now: number): void {\n const cutoff = now - this.windowSize\n this.requests = this.requests.filter(req => req.timestamp > cutoff)\n }\n\n /**\n * Get current requests per second\n */\n getRequestsPerSecond(): number {\n const now = Date.now()\n this.cleanup(now)\n\n if (this.requests.length === 0) {\n return 0\n }\n\n // Calculate RPS over the last second\n const oneSecondAgo = now - 1000\n const recentRequests = this.requests.filter(req => req.timestamp > oneSecondAgo)\n\n return recentRequests.length\n }\n\n /**\n * Get total requests in the current window\n */\n getTotalRequests(): number {\n const now = Date.now()\n this.cleanup(now)\n return this.requests.length\n }\n\n /**\n * Get average requests per second over the window\n */\n getAverageRPS(): number {\n const now = Date.now()\n this.cleanup(now)\n\n if (this.requests.length === 0) {\n return 0\n }\n\n const windowSeconds = this.windowSize / 1000\n return this.requests.length / windowSeconds\n }\n}\n\n// Global singleton instance\nexport const metricsTracker = new MetricsTracker()\n"]}
|
|
@@ -0,0 +1,44 @@
|
|
|
1
|
+
'use strict';
|
|
2
|
+
|
|
3
|
+
// src/types/plugin.ts
|
|
4
|
+
var HOOKS = {
|
|
5
|
+
// Application lifecycle
|
|
6
|
+
APP_INIT: "app:init",
|
|
7
|
+
APP_READY: "app:ready",
|
|
8
|
+
APP_SHUTDOWN: "app:shutdown",
|
|
9
|
+
// Request lifecycle
|
|
10
|
+
REQUEST_START: "request:start",
|
|
11
|
+
REQUEST_END: "request:end",
|
|
12
|
+
REQUEST_ERROR: "request:error",
|
|
13
|
+
// Authentication
|
|
14
|
+
AUTH_LOGIN: "auth:login",
|
|
15
|
+
AUTH_LOGOUT: "auth:logout",
|
|
16
|
+
AUTH_REGISTER: "auth:register",
|
|
17
|
+
USER_LOGIN: "user:login",
|
|
18
|
+
USER_LOGOUT: "user:logout",
|
|
19
|
+
// Content lifecycle
|
|
20
|
+
CONTENT_CREATE: "content:create",
|
|
21
|
+
CONTENT_UPDATE: "content:update",
|
|
22
|
+
CONTENT_DELETE: "content:delete",
|
|
23
|
+
CONTENT_PUBLISH: "content:publish",
|
|
24
|
+
CONTENT_SAVE: "content:save",
|
|
25
|
+
// Media lifecycle
|
|
26
|
+
MEDIA_UPLOAD: "media:upload",
|
|
27
|
+
MEDIA_DELETE: "media:delete",
|
|
28
|
+
MEDIA_TRANSFORM: "media:transform",
|
|
29
|
+
// Plugin lifecycle
|
|
30
|
+
PLUGIN_INSTALL: "plugin:install",
|
|
31
|
+
PLUGIN_UNINSTALL: "plugin:uninstall",
|
|
32
|
+
PLUGIN_ACTIVATE: "plugin:activate",
|
|
33
|
+
PLUGIN_DEACTIVATE: "plugin:deactivate",
|
|
34
|
+
// Admin interface
|
|
35
|
+
ADMIN_MENU_RENDER: "admin:menu:render",
|
|
36
|
+
ADMIN_PAGE_RENDER: "admin:page:render",
|
|
37
|
+
// Database
|
|
38
|
+
DB_MIGRATE: "db:migrate",
|
|
39
|
+
DB_SEED: "db:seed"
|
|
40
|
+
};
|
|
41
|
+
|
|
42
|
+
exports.HOOKS = HOOKS;
|
|
43
|
+
//# sourceMappingURL=chunk-KYGRJCZM.cjs.map
|
|
44
|
+
//# sourceMappingURL=chunk-KYGRJCZM.cjs.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"sources":["../src/types/plugin.ts"],"names":[],"mappings":";;;AAsXO,IAAM,KAAA,GAAQ;AAAA;AAAA,EAEnB,QAAA,EAAU,UAAA;AAAA,EACV,SAAA,EAAW,WAAA;AAAA,EACX,YAAA,EAAc,cAAA;AAAA;AAAA,EAGd,aAAA,EAAe,eAAA;AAAA,EACf,WAAA,EAAa,aAAA;AAAA,EACb,aAAA,EAAe,eAAA;AAAA;AAAA,EAGf,UAAA,EAAY,YAAA;AAAA,EACZ,WAAA,EAAa,aAAA;AAAA,EACb,aAAA,EAAe,eAAA;AAAA,EACf,UAAA,EAAY,YAAA;AAAA,EACZ,WAAA,EAAa,aAAA;AAAA;AAAA,EAGb,cAAA,EAAgB,gBAAA;AAAA,EAChB,cAAA,EAAgB,gBAAA;AAAA,EAChB,cAAA,EAAgB,gBAAA;AAAA,EAChB,eAAA,EAAiB,iBAAA;AAAA,EACjB,YAAA,EAAc,cAAA;AAAA;AAAA,EAGd,YAAA,EAAc,cAAA;AAAA,EACd,YAAA,EAAc,cAAA;AAAA,EACd,eAAA,EAAiB,iBAAA;AAAA;AAAA,EAGjB,cAAA,EAAgB,gBAAA;AAAA,EAChB,gBAAA,EAAkB,kBAAA;AAAA,EAClB,eAAA,EAAiB,iBAAA;AAAA,EACjB,iBAAA,EAAmB,mBAAA;AAAA;AAAA,EAGnB,iBAAA,EAAmB,mBAAA;AAAA,EACnB,iBAAA,EAAmB,mBAAA;AAAA;AAAA,EAGnB,UAAA,EAAY,YAAA;AAAA,EACZ,OAAA,EAAS;AACX","file":"chunk-KYGRJCZM.cjs","sourcesContent":["/**\n * SonicJS Plugin System Types\n * \n * Defines the core interfaces and types for the plugin system\n */\n\nimport { Hono, Context, MiddlewareHandler } from 'hono'\nimport { z } from 'zod'\nimport type { D1Database, KVNamespace, R2Bucket } from '@cloudflare/workers-types'\n\n// Core plugin definition\nexport interface Plugin {\n /** Unique plugin identifier */\n name: string\n /** Plugin version (semantic versioning) */\n version: string\n /** Human-readable description */\n description?: string\n /** Plugin author information */\n author?: {\n name: string\n email?: string\n url?: string\n }\n /** Plugin dependencies (other plugins required) */\n dependencies?: string[]\n /** SonicJS version compatibility */\n compatibility?: string\n /** Plugin license */\n license?: string\n \n // Extension points\n routes?: PluginRoutes[]\n middleware?: PluginMiddleware[]\n models?: PluginModel[]\n services?: PluginService[]\n adminPages?: PluginAdminPage[]\n adminComponents?: PluginComponent[]\n menuItems?: PluginMenuItem[]\n hooks?: PluginHook[]\n \n // Lifecycle hooks\n install?: (context: PluginContext) => Promise<void>\n uninstall?: (context: PluginContext) => Promise<void>\n activate?: (context: PluginContext) => Promise<void>\n deactivate?: (context: PluginContext) => Promise<void>\n configure?: (config: PluginConfig) => Promise<void>\n}\n\n// Plugin context provides access to SonicJS APIs\nexport interface PluginContext {\n /** Database instance */\n db: D1Database\n /** Key-value storage */\n kv: KVNamespace\n /** R2 storage bucket */\n r2?: R2Bucket\n /** Plugin configuration */\n config: PluginConfig\n /** Core SonicJS services */\n services: {\n auth: AuthService\n content: ContentService\n media: MediaService\n }\n /** Hook system for inter-plugin communication */\n hooks: HookSystem | ScopedHookSystem\n /** Logging utilities */\n logger: PluginLogger\n}\n\n// Plugin configuration\nexport interface PluginConfig {\n /** Plugin-specific configuration */\n [key: string]: any\n /** Whether plugin is enabled */\n enabled: boolean\n /** Plugin installation timestamp */\n installedAt?: number\n /** Plugin last update timestamp */\n updatedAt?: number\n}\n\n// Route definitions\nexport interface PluginRoutes {\n /** Route path prefix */\n path: string\n /** Hono route handler */\n handler: Hono\n /** Route description */\n description?: string\n /** Whether route requires authentication */\n requiresAuth?: boolean\n /** Required roles for access */\n roles?: string[]\n /** Route priority (for ordering) */\n priority?: number\n}\n\n// Middleware definitions\nexport interface PluginMiddleware {\n /** Middleware name */\n name: string\n /** Middleware handler function */\n handler: MiddlewareHandler\n /** Middleware description */\n description?: string\n /** Middleware priority (lower = earlier) */\n priority?: number\n /** Routes to apply middleware to */\n routes?: string[]\n /** Whether to apply globally */\n global?: boolean\n}\n\n// Database model definitions\nexport interface PluginModel {\n /** Model name */\n name: string\n /** Database table name */\n tableName: string\n /** Zod schema for validation */\n schema: z.ZodSchema\n /** Database migrations */\n migrations: string[]\n /** Model relationships */\n relationships?: ModelRelationship[]\n /** Whether model extends core content */\n extendsContent?: boolean\n}\n\nexport interface ModelRelationship {\n type: 'oneToOne' | 'oneToMany' | 'manyToMany'\n target: string\n foreignKey?: string\n joinTable?: string\n}\n\n// Service definitions\nexport interface PluginService {\n /** Service name */\n name: string\n /** Service implementation */\n implementation: any\n /** Service description */\n description?: string\n /** Service dependencies */\n dependencies?: string[]\n /** Whether service is singleton */\n singleton?: boolean\n}\n\n// Admin interface extensions\nexport interface PluginAdminPage {\n /** Page path (relative to /admin) */\n path: string\n /** Page title */\n title: string\n /** Page component/template */\n component: string\n /** Page description */\n description?: string\n /** Required permissions */\n permissions?: string[]\n /** Menu item configuration */\n menuItem?: PluginMenuItem\n /** Page icon */\n icon?: string\n}\n\nexport interface PluginComponent {\n /** Component name */\n name: string\n /** Component template function */\n template: (props: any) => string\n /** Component description */\n description?: string\n /** Component props schema */\n propsSchema?: z.ZodSchema\n}\n\nexport interface PluginMenuItem {\n /** Menu item label */\n label: string\n /** Menu item path */\n path: string\n /** Menu item icon */\n icon?: string\n /** Menu item order */\n order?: number\n /** Parent menu item */\n parent?: string\n /** Required permissions */\n permissions?: string[]\n /** Whether item is active */\n active?: boolean\n}\n\n// Hook system for extensibility\nexport interface PluginHook {\n /** Hook name */\n name: string\n /** Hook handler function */\n handler: HookHandler\n /** Hook priority */\n priority?: number\n /** Hook description */\n description?: string\n}\n\nexport type HookHandler = (data: any, context: HookContext) => Promise<any>\n\nexport interface HookContext {\n /** Plugin that registered the hook */\n plugin: string\n /** Hook execution context */\n context: PluginContext\n /** Cancel hook execution */\n cancel?: () => void\n}\n\n// Hook system interface\nexport interface HookSystem {\n /** Register a hook handler */\n register(hookName: string, handler: HookHandler, priority?: number): void\n /** Execute all handlers for a hook */\n execute(hookName: string, data: any, context?: any): Promise<any>\n /** Remove a hook handler */\n unregister(hookName: string, handler: HookHandler): void\n /** Get all registered hooks */\n getHooks(hookName: string): PluginHook[]\n /** Create a scoped hook system (optional) */\n createScope?(pluginName: string): ScopedHookSystem\n}\n\n// Scoped hook system for plugins\nexport interface ScopedHookSystem {\n /** Register a hook handler */\n register(hookName: string, handler: HookHandler, priority?: number): void\n /** Execute all handlers for a hook */\n execute(hookName: string, data: any, context?: any): Promise<any>\n /** Remove a hook handler */\n unregister(hookName: string, handler: HookHandler): void\n /** Remove all hooks for this scope */\n unregisterAll(): void\n}\n\n// Plugin registry\nexport interface PluginRegistry {\n /** Get plugin by name */\n get(name: string): Plugin | undefined\n /** Get all registered plugins */\n getAll(): Plugin[]\n /** Get active plugins */\n getActive(): Plugin[]\n /** Register a plugin */\n register(plugin: Plugin): Promise<void>\n /** Unregister a plugin */\n unregister(name: string): Promise<void>\n /** Check if plugin is registered */\n has(name: string): boolean\n /** Activate a plugin */\n activate(name: string): Promise<void>\n /** Deactivate a plugin */\n deactivate(name: string): Promise<void>\n /** Get plugin configuration */\n getConfig(name: string): PluginConfig | undefined\n /** Set plugin configuration */\n setConfig(name: string, config: PluginConfig): void\n /** Get plugin status */\n getStatus(name: string): PluginStatus | undefined\n /** Get all plugin statuses */\n getAllStatuses(): Map<string, PluginStatus>\n /** Resolve plugin load order based on dependencies */\n resolveLoadOrder(): string[]\n}\n\n// Plugin manager\nexport interface PluginManager {\n /** Plugin registry */\n registry: PluginRegistry\n /** Hook system */\n hooks: HookSystem\n /** Initialize plugin system */\n initialize(context: PluginContext): Promise<void>\n /** Load plugins from configuration */\n loadPlugins(config: PluginConfig[]): Promise<void>\n /** Install a plugin */\n install(plugin: Plugin, config?: PluginConfig): Promise<void>\n /** Uninstall a plugin */\n uninstall(name: string): Promise<void>\n /** Get plugin status */\n getStatus(name: string): PluginStatus\n}\n\nexport interface PluginStatus {\n name: string\n version: string\n active: boolean\n installed: boolean\n hasErrors: boolean\n errors?: string[]\n lastError?: string\n}\n\n// Service interfaces\nexport interface AuthService {\n /** Verify user permissions */\n hasPermission(userId: string, permission: string): Promise<boolean>\n /** Get current user */\n getCurrentUser(context: Context): Promise<any>\n /** Create authentication middleware */\n createMiddleware(options?: any): MiddlewareHandler\n}\n\nexport interface ContentService {\n /** Get content by ID */\n getById(id: string): Promise<any>\n /** Create new content */\n create(data: any): Promise<any>\n /** Update content */\n update(id: string, data: any): Promise<any>\n /** Delete content */\n delete(id: string): Promise<void>\n /** Search content */\n search(query: string, options?: any): Promise<any[]>\n}\n\nexport interface MediaService {\n /** Upload file */\n upload(file: File, options?: any): Promise<any>\n /** Get media by ID */\n getById(id: string): Promise<any>\n /** Delete media */\n delete(id: string): Promise<void>\n /** Transform image */\n transform(id: string, options: any): Promise<string>\n}\n\n// Plugin logger\nexport interface PluginLogger {\n debug(message: string, data?: any): void\n info(message: string, data?: any): void\n warn(message: string, data?: any): void\n error(message: string, error?: Error, data?: any): void\n}\n\n// Plugin development utilities interface\n\nexport interface PluginBuilderOptions {\n name: string\n version: string\n description?: string\n author?: Plugin['author']\n dependencies?: string[]\n}\n\n// Plugin validation\nexport interface PluginValidator {\n /** Validate plugin definition */\n validate(plugin: Plugin): PluginValidationResult\n /** Validate plugin dependencies */\n validateDependencies(plugin: Plugin, registry: PluginRegistry): PluginValidationResult\n /** Validate plugin compatibility */\n validateCompatibility(plugin: Plugin, version: string): PluginValidationResult\n}\n\nexport interface PluginValidationResult {\n valid: boolean\n errors: string[]\n warnings: string[]\n}\n\n// Standard hook names\nexport const HOOKS = {\n // Application lifecycle\n APP_INIT: 'app:init',\n APP_READY: 'app:ready',\n APP_SHUTDOWN: 'app:shutdown',\n \n // Request lifecycle\n REQUEST_START: 'request:start',\n REQUEST_END: 'request:end',\n REQUEST_ERROR: 'request:error',\n \n // Authentication\n AUTH_LOGIN: 'auth:login',\n AUTH_LOGOUT: 'auth:logout',\n AUTH_REGISTER: 'auth:register',\n USER_LOGIN: 'user:login',\n USER_LOGOUT: 'user:logout',\n \n // Content lifecycle\n CONTENT_CREATE: 'content:create',\n CONTENT_UPDATE: 'content:update',\n CONTENT_DELETE: 'content:delete',\n CONTENT_PUBLISH: 'content:publish',\n CONTENT_SAVE: 'content:save',\n \n // Media lifecycle\n MEDIA_UPLOAD: 'media:upload',\n MEDIA_DELETE: 'media:delete',\n MEDIA_TRANSFORM: 'media:transform',\n \n // Plugin lifecycle\n PLUGIN_INSTALL: 'plugin:install',\n PLUGIN_UNINSTALL: 'plugin:uninstall',\n PLUGIN_ACTIVATE: 'plugin:activate',\n PLUGIN_DEACTIVATE: 'plugin:deactivate',\n \n // Admin interface\n ADMIN_MENU_RENDER: 'admin:menu:render',\n ADMIN_PAGE_RENDER: 'admin:page:render',\n \n // Database\n DB_MIGRATE: 'db:migrate',\n DB_SEED: 'db:seed',\n} as const\n\nexport type HookName = typeof HOOKS[keyof typeof HOOKS]"]}
|
|
@@ -0,0 +1,42 @@
|
|
|
1
|
+
// src/types/plugin.ts
|
|
2
|
+
var HOOKS = {
|
|
3
|
+
// Application lifecycle
|
|
4
|
+
APP_INIT: "app:init",
|
|
5
|
+
APP_READY: "app:ready",
|
|
6
|
+
APP_SHUTDOWN: "app:shutdown",
|
|
7
|
+
// Request lifecycle
|
|
8
|
+
REQUEST_START: "request:start",
|
|
9
|
+
REQUEST_END: "request:end",
|
|
10
|
+
REQUEST_ERROR: "request:error",
|
|
11
|
+
// Authentication
|
|
12
|
+
AUTH_LOGIN: "auth:login",
|
|
13
|
+
AUTH_LOGOUT: "auth:logout",
|
|
14
|
+
AUTH_REGISTER: "auth:register",
|
|
15
|
+
USER_LOGIN: "user:login",
|
|
16
|
+
USER_LOGOUT: "user:logout",
|
|
17
|
+
// Content lifecycle
|
|
18
|
+
CONTENT_CREATE: "content:create",
|
|
19
|
+
CONTENT_UPDATE: "content:update",
|
|
20
|
+
CONTENT_DELETE: "content:delete",
|
|
21
|
+
CONTENT_PUBLISH: "content:publish",
|
|
22
|
+
CONTENT_SAVE: "content:save",
|
|
23
|
+
// Media lifecycle
|
|
24
|
+
MEDIA_UPLOAD: "media:upload",
|
|
25
|
+
MEDIA_DELETE: "media:delete",
|
|
26
|
+
MEDIA_TRANSFORM: "media:transform",
|
|
27
|
+
// Plugin lifecycle
|
|
28
|
+
PLUGIN_INSTALL: "plugin:install",
|
|
29
|
+
PLUGIN_UNINSTALL: "plugin:uninstall",
|
|
30
|
+
PLUGIN_ACTIVATE: "plugin:activate",
|
|
31
|
+
PLUGIN_DEACTIVATE: "plugin:deactivate",
|
|
32
|
+
// Admin interface
|
|
33
|
+
ADMIN_MENU_RENDER: "admin:menu:render",
|
|
34
|
+
ADMIN_PAGE_RENDER: "admin:page:render",
|
|
35
|
+
// Database
|
|
36
|
+
DB_MIGRATE: "db:migrate",
|
|
37
|
+
DB_SEED: "db:seed"
|
|
38
|
+
};
|
|
39
|
+
|
|
40
|
+
export { HOOKS };
|
|
41
|
+
//# sourceMappingURL=chunk-LOUJRBXV.js.map
|
|
42
|
+
//# sourceMappingURL=chunk-LOUJRBXV.js.map
|