webspresso 0.0.97 → 0.0.98
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/.agents/ADMIN.md +153 -5
- package/.agents/ARCHITECTURE.md +10 -0
- package/.agents/CLI.md +195 -1
- package/.agents/PLUGINS.md +153 -9
- package/.agents/QUEUE.md +43 -0
- package/bin/commands/add-esbuild.js +80 -0
- package/bin/commands/add-tailwind.js +76 -31
- package/bin/commands/analytics-prune.js +57 -0
- package/bin/commands/api.js +207 -15
- package/bin/commands/build.js +99 -0
- package/bin/commands/dev.js +64 -35
- package/bin/commands/doctor.js +26 -0
- package/bin/commands/email-prune.js +47 -0
- package/bin/commands/make-job.js +86 -0
- package/bin/commands/make-model.js +250 -0
- package/bin/commands/new.js +45 -28
- package/bin/commands/openapi.js +102 -0
- package/bin/commands/page.js +6 -3
- package/bin/commands/queue-prune.js +59 -0
- package/bin/commands/routes.js +52 -0
- package/bin/commands/service.js +6 -3
- package/bin/commands/typegen.js +106 -0
- package/bin/commands/upload-prune.js +79 -0
- package/bin/webspresso.js +22 -0
- package/core/applySchema.js +13 -6
- package/core/auth/hash.js +21 -12
- package/core/compression/middleware.js +23 -17
- package/core/openapi/build-from-api-routes.js +160 -29
- package/core/orm/cache/fingerprint.js +15 -1
- package/core/orm/cache/memory-provider.js +27 -2
- package/core/orm/index.js +12 -7
- package/core/orm/model.js +49 -7
- package/core/queue/adapters/database.js +94 -0
- package/core/queue/adapters/memory.js +62 -0
- package/core/queue/adapters/redis.js +80 -0
- package/core/queue/manager.js +123 -0
- package/core/ssr/stream.js +11 -0
- package/index.d.ts +660 -10
- package/index.js +44 -96
- package/package.json +1 -1
- package/plugins/admin-panel/api.js +279 -17
- package/plugins/admin-panel/app.js +114 -22
- package/plugins/admin-panel/client/parts/01-state-api-breadcrumb.js +314 -9
- package/plugins/admin-panel/client/parts/04-field-renderers.js +264 -67
- package/plugins/admin-panel/client/parts/05-rich-text-file-helpers.js +10 -5
- package/plugins/admin-panel/client/parts/06-login-setup-forms.js +119 -28
- package/plugins/admin-panel/client/parts/07-model-list.js +49 -8
- package/plugins/admin-panel/client/parts/08-record-list.js +243 -23
- package/plugins/admin-panel/client/parts/09-record-form.js +59 -12
- package/plugins/admin-panel/client/parts/10-export-registry.js +23 -0
- package/plugins/admin-panel/core/admin-module.js +13 -7
- package/plugins/admin-panel/core/api-extensions.js +30 -2
- package/plugins/admin-panel/core/registry.js +96 -16
- package/plugins/admin-panel/index.js +96 -0
- package/plugins/admin-panel/lib/login-rate-limiter.js +119 -0
- package/plugins/admin-panel/modules/admin-users.js +16 -1
- package/plugins/admin-panel/modules/bulk-actions.js +13 -5
- package/plugins/admin-panel/modules/custom-pages.js +492 -3
- package/plugins/admin-panel/modules/dashboard.js +283 -0
- package/plugins/admin-panel/modules/menu.js +56 -18
- package/plugins/admin-panel/modules/user-management.js +24 -6
- package/plugins/audit-log/admin-component.js +11 -0
- package/plugins/audit-log/api-handlers.js +34 -0
- package/plugins/audit-log/index.js +129 -3
- package/plugins/audit-log/purge.js +60 -10
- package/plugins/dashboard/app.js +152 -27
- package/plugins/dashboard/index.js +143 -39
- package/plugins/dashboard/styles.js +78 -0
- package/plugins/data-exchange/export-xlsx.js +9 -2
- package/plugins/data-exchange/import.js +9 -2
- package/plugins/data-exchange/index.js +6 -3
- package/plugins/email/index.js +132 -2
- package/plugins/email/purge.js +60 -10
- package/plugins/index.js +4 -0
- package/plugins/orm-cache-admin/index.js +4 -2
- package/plugins/queue/index.js +11 -0
- package/plugins/schema-explorer/admin-component.js +714 -0
- package/plugins/schema-explorer/relations-graph.js +205 -0
- package/plugins/schema-explorer.js +248 -69
- package/plugins/site-analytics/admin-component.js +23 -0
- package/plugins/site-analytics/api-handlers.js +42 -0
- package/plugins/site-analytics/index.js +147 -2
- package/plugins/site-analytics/purge.js +168 -0
- package/plugins/swagger.js +261 -13
- package/plugins/upload/index.js +26 -0
- package/plugins/upload/orphan-pruner.js +292 -0
- package/src/api/api-loader.js +3 -1
- package/src/bundle/index.js +517 -0
- package/src/bundle/manifest.js +165 -0
- package/src/dev/banner.js +296 -0
- package/src/dev/colors.js +70 -0
- package/src/dev/index.js +62 -0
- package/src/dev/profiler.js +354 -0
- package/src/dev/typegen.js +497 -0
- package/src/dev-reload/index.js +611 -0
- package/src/file-router.js +210 -62
- package/src/helpers.js +958 -98
- package/src/njk-frontmatter.js +12 -0
- package/src/pages/page-loader.js +61 -11
- package/src/server.js +629 -63
package/plugins/email/purge.js
CHANGED
|
@@ -3,24 +3,74 @@
|
|
|
3
3
|
* @module plugins/email/purge
|
|
4
4
|
*/
|
|
5
5
|
|
|
6
|
+
'use strict';
|
|
7
|
+
|
|
6
8
|
/**
|
|
7
9
|
* @param {import('knex').Knex} knex
|
|
8
|
-
* @param {Object} options
|
|
10
|
+
* @param {Object} [options={}]
|
|
9
11
|
* @param {string} [options.tableName='email_logs']
|
|
10
|
-
* @param {Date|string} options.olderThan
|
|
11
|
-
* @
|
|
12
|
+
* @param {Date|string|number} [options.olderThan] - Rows with created_at strictly before this are removed
|
|
13
|
+
* @param {number} [options.days] - Number of days of email logs to keep
|
|
14
|
+
* @param {number} [options.retentionDays=90] - Alias for days
|
|
15
|
+
* @returns {Promise<number>} Deleted row count
|
|
12
16
|
*/
|
|
13
|
-
async function purgeEmailLogs(knex, options) {
|
|
17
|
+
async function purgeEmailLogs(knex, options = {}) {
|
|
18
|
+
if (!knex) {
|
|
19
|
+
throw new Error('purgeEmailLogs requires a database (knex) instance');
|
|
20
|
+
}
|
|
21
|
+
|
|
14
22
|
const tableName = options.tableName || 'email_logs';
|
|
15
|
-
const olderThan = options.olderThan instanceof Date
|
|
16
|
-
? options.olderThan
|
|
17
|
-
: new Date(options.olderThan);
|
|
18
23
|
|
|
19
|
-
|
|
20
|
-
|
|
24
|
+
let olderThan;
|
|
25
|
+
if (options.olderThan !== undefined) {
|
|
26
|
+
olderThan = options.olderThan instanceof Date
|
|
27
|
+
? options.olderThan
|
|
28
|
+
: new Date(options.olderThan);
|
|
29
|
+
|
|
30
|
+
if (Number.isNaN(olderThan.getTime())) {
|
|
31
|
+
throw new Error('purgeEmailLogs: invalid olderThan date');
|
|
32
|
+
}
|
|
33
|
+
} else {
|
|
34
|
+
const rawDays = options.days !== undefined ? options.days : (options.retentionDays !== undefined ? options.retentionDays : 90);
|
|
35
|
+
const days = typeof rawDays === 'number' ? rawDays : Number(rawDays);
|
|
36
|
+
if (Number.isNaN(days) || days <= 0) {
|
|
37
|
+
throw new Error('purgeEmailLogs: days must be a positive number');
|
|
38
|
+
}
|
|
39
|
+
olderThan = new Date(Date.now() - days * 24 * 60 * 60 * 1000);
|
|
40
|
+
}
|
|
41
|
+
|
|
42
|
+
let hasTable = true;
|
|
43
|
+
if (knex.schema && typeof knex.schema.hasTable === 'function') {
|
|
44
|
+
try {
|
|
45
|
+
hasTable = await knex.schema.hasTable(tableName);
|
|
46
|
+
} catch {
|
|
47
|
+
hasTable = false;
|
|
48
|
+
}
|
|
49
|
+
}
|
|
50
|
+
|
|
51
|
+
if (!hasTable) {
|
|
52
|
+
return 0;
|
|
53
|
+
}
|
|
54
|
+
|
|
55
|
+
const client = knex?.client?.config?.client;
|
|
56
|
+
const isSqlite = client === 'sqlite3' || client === 'better-sqlite3';
|
|
57
|
+
|
|
58
|
+
let query = knex(tableName);
|
|
59
|
+
if (isSqlite) {
|
|
60
|
+
const iso = olderThan.toISOString();
|
|
61
|
+
const cutoffMs = olderThan.getTime();
|
|
62
|
+
query = query.where((builder) => {
|
|
63
|
+
builder.whereRaw(
|
|
64
|
+
"((typeof(created_at) = 'integer' and created_at < ?) or (typeof(created_at) = 'text' and created_at < ?))",
|
|
65
|
+
[cutoffMs, iso]
|
|
66
|
+
);
|
|
67
|
+
});
|
|
68
|
+
} else {
|
|
69
|
+
query = query.where('created_at', '<', olderThan);
|
|
21
70
|
}
|
|
22
71
|
|
|
23
|
-
|
|
72
|
+
const deleted = await query.delete();
|
|
73
|
+
return Number(deleted) || 0;
|
|
24
74
|
}
|
|
25
75
|
|
|
26
76
|
module.exports = {
|
package/plugins/index.js
CHANGED
|
@@ -7,6 +7,8 @@ module.exports = {
|
|
|
7
7
|
get sitemapPlugin() { return require('./sitemap'); },
|
|
8
8
|
get analyticsPlugin() { return require('./analytics'); },
|
|
9
9
|
get dashboardPlugin() { return require('./dashboard/index'); },
|
|
10
|
+
get devToolbarPlugin() { return require('./dashboard/index').devToolbarPlugin; },
|
|
11
|
+
get devtoolsPlugin() { return require('./dashboard/index').devtoolsPlugin; },
|
|
10
12
|
get schemaExplorerPlugin() { return require('./schema-explorer'); },
|
|
11
13
|
get adminPanelPlugin() { return require('./admin-panel'); },
|
|
12
14
|
get seoCheckerPlugin() { return require('./seo-checker'); },
|
|
@@ -14,6 +16,8 @@ module.exports = {
|
|
|
14
16
|
get auditLogPlugin() { return require('./audit-log'); },
|
|
15
17
|
get recaptchaPlugin() { return require('./recaptcha'); },
|
|
16
18
|
get swaggerPlugin() { return require('./swagger'); },
|
|
19
|
+
get openapiPlugin() { return require('./swagger'); },
|
|
20
|
+
get apiDocsPlugin() { return require('./swagger'); },
|
|
17
21
|
get healthCheckPlugin() { return require('./health-check'); },
|
|
18
22
|
get restResourcePlugin() { return require('./rest-resources'); },
|
|
19
23
|
get ormCacheAdminPlugin() { return require('./orm-cache-admin'); },
|
|
@@ -11,7 +11,8 @@ const { generateOrmCacheAdminComponent } = require('./admin-component');
|
|
|
11
11
|
* @param {import('../../core/orm/types').DatabaseInstance} options.db - From createDatabase({ cache: true })
|
|
12
12
|
*/
|
|
13
13
|
function ormCacheAdminPlugin(options = {}) {
|
|
14
|
-
const { db } = options;
|
|
14
|
+
const { db, title, adminTitle } = options;
|
|
15
|
+
const pageTitle = title || adminTitle || 'ORM Cache';
|
|
15
16
|
|
|
16
17
|
if (!db) {
|
|
17
18
|
throw new Error('orm-cache-admin plugin requires `db` (database instance from createDatabase)');
|
|
@@ -41,9 +42,10 @@ function ormCacheAdminPlugin(options = {}) {
|
|
|
41
42
|
|
|
42
43
|
adminApi.registerModule({
|
|
43
44
|
id: 'orm-cache',
|
|
45
|
+
title: pageTitle,
|
|
44
46
|
pages: [{
|
|
45
47
|
id: 'orm-cache',
|
|
46
|
-
title:
|
|
48
|
+
title: pageTitle,
|
|
47
49
|
path: '/orm-cache',
|
|
48
50
|
icon: 'database',
|
|
49
51
|
component: generateOrmCacheAdminComponent(),
|
package/plugins/queue/index.js
CHANGED
|
@@ -72,6 +72,12 @@ function queuePlugin(options = {}) {
|
|
|
72
72
|
pollInterval,
|
|
73
73
|
jobsDir,
|
|
74
74
|
autoStart,
|
|
75
|
+
retention: options.retention,
|
|
76
|
+
retentionDays: options.retentionDays,
|
|
77
|
+
retentionStatuses: options.retentionStatuses,
|
|
78
|
+
cleanupIntervalMs: options.cleanupIntervalMs,
|
|
79
|
+
autoCleanup: options.autoCleanup,
|
|
80
|
+
cleanupOnStart: options.cleanupOnStart,
|
|
75
81
|
});
|
|
76
82
|
|
|
77
83
|
// Expose to ctx & app
|
|
@@ -90,6 +96,11 @@ function queuePlugin(options = {}) {
|
|
|
90
96
|
this.queue = queueManager;
|
|
91
97
|
},
|
|
92
98
|
|
|
99
|
+
api: {
|
|
100
|
+
getQueueManager: () => queueManager,
|
|
101
|
+
clean: (opts) => queueManager?.clean(opts),
|
|
102
|
+
},
|
|
103
|
+
|
|
93
104
|
onRoutesReady(ctx) {
|
|
94
105
|
if (jobsDir && fs.existsSync(jobsDir)) {
|
|
95
106
|
queueManager.loadJobsFromDirectory(jobsDir);
|