webspresso 0.0.101 → 0.0.102
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/AGENTS.md +1 -1
- package/.agents/ARCHITECTURE.md +11 -0
- package/.agents/CONVENTIONS.md +4 -0
- package/.agents/PLUGINS.md +32 -6
- package/.agents/ROUTING.md +99 -2
- package/.agents/skills/webspresso-framework/SKILL.md +32 -0
- package/.agents/skills/webspresso-routing-and-api/SKILL.md +4 -4
- package/AGENTS.md +6 -0
- package/README.md +18 -5
- package/bin/commands/add-tailwind.js +10 -0
- package/bin/commands/build.js +34 -0
- package/bin/commands/routes.js +8 -0
- package/core/applySchema.js +18 -1
- package/index.d.ts +156 -1
- package/index.js +71 -16
- package/package.json +5 -5
- package/plugins/admin-panel/index.js +12 -0
- package/plugins/csrf/index.js +1 -1
- package/plugins/file-manager/index.js +13 -0
- package/plugins/index.js +2 -0
- package/plugins/lazy.js +258 -0
- package/src/api/api-loader.js +17 -1
- package/src/api/validation-i18n.js +231 -0
- package/src/discovery/route-manifest.js +197 -0
- package/src/discovery/scan-routes.js +70 -4
- package/src/file-router.js +153 -91
- package/src/njk-frontmatter.js +17 -1
- package/src/plugin-manager.js +12 -0
- package/src/routing/route-table.js +1 -1
- package/src/server.js +63 -8
- package/src/services/builtins/system.js +4 -6
- package/src/services/registry.js +12 -2
- package/src/template/precompile.js +247 -0
package/index.d.ts
CHANGED
|
@@ -68,6 +68,14 @@ export interface CreateAppOptions {
|
|
|
68
68
|
compression?: boolean | CompressionOptions;
|
|
69
69
|
/** Shutdown and lifecycle configuration */
|
|
70
70
|
shutdown?: ShutdownOptions;
|
|
71
|
+
/**
|
|
72
|
+
* Ahead-Of-Time (AOT) route manifest: boolean to enable/disable loading, or explicit path to manifest JSON file
|
|
73
|
+
*/
|
|
74
|
+
routesManifest?: boolean | string;
|
|
75
|
+
/**
|
|
76
|
+
* Precompiled Nunjucks templates: boolean to enable/disable loading, or explicit path to compiled bundle file
|
|
77
|
+
*/
|
|
78
|
+
precompiledTemplates?: boolean | string;
|
|
71
79
|
/** Development tooling and DX options */
|
|
72
80
|
dev?: {
|
|
73
81
|
banner?: boolean;
|
|
@@ -657,6 +665,25 @@ export function detectLocale(
|
|
|
657
665
|
defaultLocale: string
|
|
658
666
|
): string;
|
|
659
667
|
|
|
668
|
+
export interface TranslateValidationIssuesOptions {
|
|
669
|
+
req?: Request;
|
|
670
|
+
t?: Translator;
|
|
671
|
+
locale?: string;
|
|
672
|
+
pagesDir?: string;
|
|
673
|
+
routeDir?: string;
|
|
674
|
+
isDev?: boolean;
|
|
675
|
+
}
|
|
676
|
+
|
|
677
|
+
export function translateValidationIssues<T = unknown>(
|
|
678
|
+
issues: T[],
|
|
679
|
+
options?: TranslateValidationIssuesOptions
|
|
680
|
+
): T[];
|
|
681
|
+
|
|
682
|
+
export function getTranslatorForRequest(
|
|
683
|
+
req?: Request,
|
|
684
|
+
options?: { pagesDir?: string; routeDir?: string; isDev?: boolean }
|
|
685
|
+
): { t: Translator; locale: string };
|
|
686
|
+
|
|
660
687
|
export function parseNjkFrontmatter(content: string): {
|
|
661
688
|
body: string;
|
|
662
689
|
fm: Record<string, unknown> | null;
|
|
@@ -1561,9 +1588,38 @@ export interface AdminPanelPluginOptions {
|
|
|
1561
1588
|
windowMs?: number;
|
|
1562
1589
|
blockDurationMs?: number;
|
|
1563
1590
|
};
|
|
1591
|
+
/** Lazy / On-Demand mount: defers plugin initialization until first request to adminPath or service execution */
|
|
1592
|
+
lazy?: boolean | LazyPluginOptions;
|
|
1564
1593
|
[key: string]: unknown;
|
|
1565
1594
|
}
|
|
1566
1595
|
|
|
1596
|
+
export interface LazyPluginOptions {
|
|
1597
|
+
name?: string;
|
|
1598
|
+
prefix?: string | string[];
|
|
1599
|
+
services?: string[];
|
|
1600
|
+
helpers?: string[];
|
|
1601
|
+
events?: string[];
|
|
1602
|
+
dependencies?: Record<string, string> | string[];
|
|
1603
|
+
csp?: Record<string, string[]>;
|
|
1604
|
+
onHydrate?: (realPlugin: WebspressoPlugin) => void;
|
|
1605
|
+
}
|
|
1606
|
+
|
|
1607
|
+
export interface LazyPlugin extends WebspressoPlugin {
|
|
1608
|
+
isLazy: true;
|
|
1609
|
+
readonly isHydrated: boolean;
|
|
1610
|
+
hydrate(): WebspressoPlugin;
|
|
1611
|
+
}
|
|
1612
|
+
|
|
1613
|
+
export function lazyPlugin(
|
|
1614
|
+
pluginFactory: (() => WebspressoPlugin) | WebspressoPlugin,
|
|
1615
|
+
lazyOptions?: LazyPluginOptions
|
|
1616
|
+
): LazyPlugin;
|
|
1617
|
+
|
|
1618
|
+
export function defineLazyPlugin(
|
|
1619
|
+
pluginFactory: (() => WebspressoPlugin) | WebspressoPlugin,
|
|
1620
|
+
lazyOptions?: LazyPluginOptions
|
|
1621
|
+
): LazyPlugin;
|
|
1622
|
+
|
|
1567
1623
|
export function adminPanelPlugin(options?: AdminPanelPluginOptions): WebspressoPlugin;
|
|
1568
1624
|
|
|
1569
1625
|
export function dataExchangePlugin(options?: Record<string, unknown>): WebspressoPlugin;
|
|
@@ -3142,11 +3198,14 @@ export interface ApiContext<TBody = any, TParams = Record<string, string>, TQuer
|
|
|
3142
3198
|
query: TQuery;
|
|
3143
3199
|
body: TBody;
|
|
3144
3200
|
input: { body?: TBody; params?: TParams; query?: TQuery; headers?: Record<string, string> };
|
|
3201
|
+
locale: string;
|
|
3202
|
+
t: Translator;
|
|
3145
3203
|
service: WebspressoServiceCaller;
|
|
3146
3204
|
module: string | null;
|
|
3147
3205
|
config: Record<string, unknown>;
|
|
3148
3206
|
logger: Console;
|
|
3149
3207
|
db: unknown;
|
|
3208
|
+
sse?: (sourceOrOptions?: any, maybeOptions?: any) => any;
|
|
3150
3209
|
}
|
|
3151
3210
|
|
|
3152
3211
|
export interface DefineApiOptions<TResult = any, TBody = any, TParams = Record<string, string>, TQuery = Record<string, string>> {
|
|
@@ -3213,7 +3272,21 @@ export function scanRoutes(options?: {
|
|
|
3213
3272
|
pages?: boolean | { dir?: string; prefix?: string };
|
|
3214
3273
|
api?: boolean | { dir?: string; prefix?: string };
|
|
3215
3274
|
modules?: boolean | { dir?: string };
|
|
3216
|
-
}): RouteDescriptor[];
|
|
3275
|
+
}): RouteDescriptor[] & { scannedPagesFiles?: string[]; scannedPagesDir?: string | null };
|
|
3276
|
+
|
|
3277
|
+
export function discoverAppRoutes(options?: {
|
|
3278
|
+
rootDir?: string;
|
|
3279
|
+
pages?: boolean | { dir?: string; prefix?: string };
|
|
3280
|
+
api?: boolean | { dir?: string; prefix?: string };
|
|
3281
|
+
modules?: boolean | { dir?: string };
|
|
3282
|
+
routes?: Array<{ method?: string; path: string }>;
|
|
3283
|
+
isDev?: boolean;
|
|
3284
|
+
}): {
|
|
3285
|
+
descriptors: RouteDescriptor[];
|
|
3286
|
+
routeTable: RouteTable;
|
|
3287
|
+
scannedPagesFiles: string[];
|
|
3288
|
+
scannedPagesDir: string | null;
|
|
3289
|
+
};
|
|
3217
3290
|
|
|
3218
3291
|
export function parseFileRoute(
|
|
3219
3292
|
relativePath: string,
|
|
@@ -3225,6 +3298,88 @@ export function compileRouteTable(
|
|
|
3225
3298
|
options?: { explicitRoutes?: Array<{ method?: string; path: string }>; isDev?: boolean }
|
|
3226
3299
|
): RouteTable;
|
|
3227
3300
|
|
|
3301
|
+
export function generateRouteManifest(options?: {
|
|
3302
|
+
rootDir?: string;
|
|
3303
|
+
pages?: boolean | string | { dir?: string; prefix?: string };
|
|
3304
|
+
api?: boolean | string | { dir?: string; prefix?: string };
|
|
3305
|
+
modules?: boolean | { dir?: string };
|
|
3306
|
+
pagesDir?: string;
|
|
3307
|
+
outDir?: string;
|
|
3308
|
+
outFile?: string;
|
|
3309
|
+
silent?: boolean;
|
|
3310
|
+
}): {
|
|
3311
|
+
manifest: {
|
|
3312
|
+
version: number;
|
|
3313
|
+
generatedAt: string;
|
|
3314
|
+
pagesDirRel: string;
|
|
3315
|
+
scannedPagesFiles: string[];
|
|
3316
|
+
routes: Array<{
|
|
3317
|
+
type: 'page' | 'api';
|
|
3318
|
+
method: string;
|
|
3319
|
+
path: string;
|
|
3320
|
+
source: string;
|
|
3321
|
+
module?: string | null;
|
|
3322
|
+
moduleConfig?: { name?: string } | null;
|
|
3323
|
+
}>;
|
|
3324
|
+
};
|
|
3325
|
+
manifestPath: string;
|
|
3326
|
+
routeCount: number;
|
|
3327
|
+
scannedFilesCount: number;
|
|
3328
|
+
};
|
|
3329
|
+
|
|
3330
|
+
export function loadRouteManifest(options?: {
|
|
3331
|
+
rootDir?: string;
|
|
3332
|
+
manifestPath?: string;
|
|
3333
|
+
}): {
|
|
3334
|
+
manifest: {
|
|
3335
|
+
version: number;
|
|
3336
|
+
generatedAt: string;
|
|
3337
|
+
pagesDirRel: string;
|
|
3338
|
+
scannedPagesFiles: string[];
|
|
3339
|
+
routes: Array<{
|
|
3340
|
+
type: 'page' | 'api';
|
|
3341
|
+
method: string;
|
|
3342
|
+
path: string;
|
|
3343
|
+
source: string;
|
|
3344
|
+
module?: string | null;
|
|
3345
|
+
moduleConfig?: { name?: string } | null;
|
|
3346
|
+
}>;
|
|
3347
|
+
};
|
|
3348
|
+
descriptors: RouteDescriptor[] & { scannedPagesFiles?: string[]; scannedPagesDir?: string | null };
|
|
3349
|
+
} | null;
|
|
3350
|
+
|
|
3351
|
+
export function precompileTemplates(options?: {
|
|
3352
|
+
rootDir?: string;
|
|
3353
|
+
viewsDir?: string;
|
|
3354
|
+
pagesDir?: string;
|
|
3355
|
+
outDir?: string;
|
|
3356
|
+
outFile?: string;
|
|
3357
|
+
env?: any;
|
|
3358
|
+
}): {
|
|
3359
|
+
templateCount: number;
|
|
3360
|
+
manifestPath: string;
|
|
3361
|
+
bundle: {
|
|
3362
|
+
version: number;
|
|
3363
|
+
generatedAt: string;
|
|
3364
|
+
templates: Record<string, string>;
|
|
3365
|
+
frontmatter: Record<string, any>;
|
|
3366
|
+
};
|
|
3367
|
+
};
|
|
3368
|
+
|
|
3369
|
+
export function loadPrecompiledTemplates(options?: {
|
|
3370
|
+
rootDir?: string;
|
|
3371
|
+
bundlePath?: string;
|
|
3372
|
+
}): {
|
|
3373
|
+
loader: any;
|
|
3374
|
+
templateCount: number;
|
|
3375
|
+
bundle: {
|
|
3376
|
+
version: number;
|
|
3377
|
+
generatedAt: string;
|
|
3378
|
+
templates: Record<string, string>;
|
|
3379
|
+
frontmatter: Record<string, any>;
|
|
3380
|
+
};
|
|
3381
|
+
} | null;
|
|
3382
|
+
|
|
3228
3383
|
export interface GenerateTypesOptions {
|
|
3229
3384
|
/** Root directory of the project (default: process.cwd()) */
|
|
3230
3385
|
rootDir?: string;
|
package/index.js
CHANGED
|
@@ -58,13 +58,21 @@ const {
|
|
|
58
58
|
const { definePage } = require('./src/pages/define-page');
|
|
59
59
|
const { defineApi } = require('./src/api/define-api');
|
|
60
60
|
const { defineModule } = require('./src/modules/define-module');
|
|
61
|
-
const { scanRoutes } = require('./src/discovery/scan-routes');
|
|
61
|
+
const { scanRoutes, discoverAppRoutes } = require('./src/discovery/scan-routes');
|
|
62
|
+
const { generateRouteManifest, loadRouteManifest } = require('./src/discovery/route-manifest');
|
|
63
|
+
const { precompileTemplates, loadPrecompiledTemplates } = require('./src/template/precompile');
|
|
62
64
|
const { parseFileRoute } = require('./src/discovery/file-route-parser');
|
|
63
65
|
const { compileRouteTable, RouteTable } = require('./src/routing/route-table');
|
|
64
66
|
const { mountDiscoveredRoutes } = require('./src/routing/mount-discovered-routes');
|
|
65
67
|
|
|
66
|
-
// ORM
|
|
67
|
-
|
|
68
|
+
// Lazy-loaded ORM accessor
|
|
69
|
+
let _orm = null;
|
|
70
|
+
function getOrm() {
|
|
71
|
+
if (!_orm) {
|
|
72
|
+
_orm = require('./core/orm');
|
|
73
|
+
}
|
|
74
|
+
return _orm;
|
|
75
|
+
}
|
|
68
76
|
|
|
69
77
|
// Lazy-loaded built-in plugins
|
|
70
78
|
const plugins = require('./plugins');
|
|
@@ -99,12 +107,6 @@ module.exports = {
|
|
|
99
107
|
discoverServices: require('./src/services').discoverServices,
|
|
100
108
|
filePathToServiceName: require('./src/services').filePathToServiceName,
|
|
101
109
|
toCamelCase: require('./src/services').toCamelCase,
|
|
102
|
-
createAuthServices: require('./src/services').createAuthServices,
|
|
103
|
-
createMailServices: require('./src/services').createMailServices,
|
|
104
|
-
createMediaServices: require('./src/services').createMediaServices,
|
|
105
|
-
createFileManagerServices: require('./src/services').createFileManagerServices,
|
|
106
|
-
createSystemServices: require('./src/services').createSystemServices,
|
|
107
|
-
createExchangeServices: require('./src/services').createExchangeServices,
|
|
108
110
|
validateServiceInput: require('./src/services').validateServiceInput,
|
|
109
111
|
executeService: require('./src/services').executeService,
|
|
110
112
|
|
|
@@ -171,12 +173,6 @@ module.exports = {
|
|
|
171
173
|
createPluginManager,
|
|
172
174
|
getPluginManager,
|
|
173
175
|
resetPluginManager,
|
|
174
|
-
|
|
175
|
-
// ORM
|
|
176
|
-
...orm,
|
|
177
|
-
|
|
178
|
-
// Direct zdb export (for convenience)
|
|
179
|
-
zdb: orm.zdb,
|
|
180
176
|
|
|
181
177
|
// Discovery, Pages, API, Modules & Routing primitives
|
|
182
178
|
definePage,
|
|
@@ -186,11 +182,18 @@ module.exports = {
|
|
|
186
182
|
defineModule,
|
|
187
183
|
module: defineModule,
|
|
188
184
|
scanRoutes,
|
|
185
|
+
discoverAppRoutes,
|
|
186
|
+
generateRouteManifest,
|
|
187
|
+
loadRouteManifest,
|
|
188
|
+
precompileTemplates,
|
|
189
|
+
loadPrecompiledTemplates,
|
|
189
190
|
parseFileRoute,
|
|
190
191
|
compileRouteTable,
|
|
191
192
|
RouteTable,
|
|
192
193
|
mountDiscoveredRoutes,
|
|
193
194
|
resolveMiddlewares: require('./src/routing/middleware-resolver').resolveMiddlewares,
|
|
195
|
+
translateValidationIssues: require('./src/api/validation-i18n').translateValidationIssues,
|
|
196
|
+
getTranslatorForRequest: require('./src/api/validation-i18n').getTranslatorForRequest,
|
|
194
197
|
|
|
195
198
|
// Forms & Flash subsystem (AdonisJS & Django-inspired)
|
|
196
199
|
createFlashMiddleware: require('./core/forms').createFlashMiddleware,
|
|
@@ -218,10 +221,62 @@ module.exports = {
|
|
|
218
221
|
loadListeners: require('./core/events').loadListeners,
|
|
219
222
|
};
|
|
220
223
|
|
|
221
|
-
// Define lazy getters for plugins and heavy core subsystems
|
|
224
|
+
// Define lazy getters for plugins, ORM, and heavy core subsystems
|
|
222
225
|
Object.defineProperties(module.exports, {
|
|
223
226
|
...Object.getOwnPropertyDescriptors(plugins),
|
|
224
227
|
|
|
228
|
+
// Built-in Services Creators (lazy loaded)
|
|
229
|
+
createAuthServices: { get: () => require('./src/services').createAuthServices, enumerable: true, configurable: true },
|
|
230
|
+
createMailServices: { get: () => require('./src/services').createMailServices, enumerable: true, configurable: true },
|
|
231
|
+
createMediaServices: { get: () => require('./src/services').createMediaServices, enumerable: true, configurable: true },
|
|
232
|
+
createFileManagerServices: { get: () => require('./src/services').createFileManagerServices, enumerable: true, configurable: true },
|
|
233
|
+
createSystemServices: { get: () => require('./src/services').createSystemServices, enumerable: true, configurable: true },
|
|
234
|
+
createExchangeServices: { get: () => require('./src/services').createExchangeServices, enumerable: true, configurable: true },
|
|
235
|
+
|
|
236
|
+
// ORM & Database Layer (lazy loaded)
|
|
237
|
+
orm: { get: () => getOrm(), enumerable: true, configurable: true },
|
|
238
|
+
createDatabase: { get: () => getOrm().createDatabase, enumerable: true, configurable: true },
|
|
239
|
+
createInMemoryDatabase: { get: () => getOrm().createInMemoryDatabase, enumerable: true, configurable: true },
|
|
240
|
+
defineModel: { get: () => getOrm().defineModel, enumerable: true, configurable: true },
|
|
241
|
+
zdb: { get: () => getOrm().zdb, enumerable: true, configurable: true },
|
|
242
|
+
BaseRepository: { get: () => getOrm().BaseRepository, enumerable: true, configurable: true },
|
|
243
|
+
Repository: { get: () => getOrm().Repository, enumerable: true, configurable: true },
|
|
244
|
+
createRepository: { get: () => getOrm().createRepository, enumerable: true, configurable: true },
|
|
245
|
+
getModel: { get: () => getOrm().getModel, enumerable: true, configurable: true },
|
|
246
|
+
getAllModels: { get: () => getOrm().getAllModels, enumerable: true, configurable: true },
|
|
247
|
+
hasModel: { get: () => getOrm().hasModel, enumerable: true, configurable: true },
|
|
248
|
+
clearRegistry: { get: () => getOrm().clearRegistry, enumerable: true, configurable: true },
|
|
249
|
+
isCascadeEnabled: { get: () => getOrm().isCascadeEnabled, enumerable: true, configurable: true },
|
|
250
|
+
extractColumnsFromSchema: { get: () => getOrm().extractColumnsFromSchema, enumerable: true, configurable: true },
|
|
251
|
+
getColumnMeta: { get: () => getOrm().getColumnMeta, enumerable: true, configurable: true },
|
|
252
|
+
generateNanoid: { get: () => getOrm().generateNanoid, enumerable: true, configurable: true },
|
|
253
|
+
zodNanoid: { get: () => getOrm().zodNanoid, enumerable: true, configurable: true },
|
|
254
|
+
extendZ: { get: () => getOrm().extendZ, enumerable: true, configurable: true },
|
|
255
|
+
omitHiddenColumns: { get: () => getOrm().omitHiddenColumns, enumerable: true, configurable: true },
|
|
256
|
+
sanitizeForOutput: { get: () => getOrm().sanitizeForOutput, enumerable: true, configurable: true },
|
|
257
|
+
ModelEvents: { get: () => getOrm().ModelEvents, enumerable: true, configurable: true },
|
|
258
|
+
Hooks: { get: () => getOrm().Hooks, enumerable: true, configurable: true },
|
|
259
|
+
HookCancellationError: { get: () => getOrm().HookCancellationError, enumerable: true, configurable: true },
|
|
260
|
+
createEventContext: { get: () => getOrm().createEventContext, enumerable: true, configurable: true },
|
|
261
|
+
getTransactionContext: { get: () => getOrm().getTransactionContext, enumerable: true, configurable: true },
|
|
262
|
+
createTransactionContext: { get: () => getOrm().createTransactionContext, enumerable: true, configurable: true },
|
|
263
|
+
runTransaction: { get: () => getOrm().runTransaction, enumerable: true, configurable: true },
|
|
264
|
+
createSchemaHelpers: { get: () => getOrm().createSchemaHelpers, enumerable: true, configurable: true },
|
|
265
|
+
loadRelations: { get: () => getOrm().loadRelations, enumerable: true, configurable: true },
|
|
266
|
+
loadRelation: { get: () => getOrm().loadRelation, enumerable: true, configurable: true },
|
|
267
|
+
parseRelationTree: { get: () => getOrm().parseRelationTree, enumerable: true, configurable: true },
|
|
268
|
+
QueryComplexityError: { get: () => getOrm().QueryComplexityError, enumerable: true, configurable: true },
|
|
269
|
+
validateQueryComplexity: { get: () => getOrm().validateQueryComplexity, enumerable: true, configurable: true },
|
|
270
|
+
resolveQueryLimits: { get: () => getOrm().resolveQueryLimits, enumerable: true, configurable: true },
|
|
271
|
+
DEFAULT_QUERY_LIMITS: { get: () => getOrm().DEFAULT_QUERY_LIMITS, enumerable: true, configurable: true },
|
|
272
|
+
buildSearchClause: { get: () => getOrm().buildSearchClause, enumerable: true, configurable: true },
|
|
273
|
+
tokenizeSearchTerm: { get: () => getOrm().tokenizeSearchTerm, enumerable: true, configurable: true },
|
|
274
|
+
detectDialect: { get: () => getOrm().detectDialect, enumerable: true, configurable: true },
|
|
275
|
+
defineFactory: { get: () => getOrm().defineFactory, enumerable: true, configurable: true },
|
|
276
|
+
FactoryBuilder: { get: () => getOrm().FactoryBuilder, enumerable: true, configurable: true },
|
|
277
|
+
diffSchema: { get: () => getOrm().diffSchema, enumerable: true, configurable: true },
|
|
278
|
+
makeMigrations: { get: () => getOrm().makeMigrations, enumerable: true, configurable: true },
|
|
279
|
+
|
|
225
280
|
// Cascading Middleware & Layouts
|
|
226
281
|
cascading: { get: () => require('./src/routing/cascading'), enumerable: true, configurable: true },
|
|
227
282
|
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "webspresso",
|
|
3
|
-
"version": "0.0.
|
|
3
|
+
"version": "0.0.102",
|
|
4
4
|
"description": "Minimal, production-ready SSR framework for Node.js with file-based routing, Nunjucks templating, built-in i18n, and CLI tooling",
|
|
5
5
|
"main": "index.js",
|
|
6
6
|
"types": "index.d.ts",
|
|
@@ -47,21 +47,21 @@
|
|
|
47
47
|
"test:services": "vitest run tests/**/service*",
|
|
48
48
|
"test:plugins": "vitest run tests/**/plugin* tests/unit/*plugin*.test.js",
|
|
49
49
|
"test:core": "vitest run tests/unit/core* tests/unit/server* tests/unit/routing* tests/unit/template*",
|
|
50
|
-
"test:branches": "vitest run tests/unit/*branches
|
|
51
|
-
"test:fast": "vitest run tests/unit/*branches
|
|
50
|
+
"test:branches": "vitest run tests/unit/*scenarios*.test.js tests/unit/*branches*.test.js",
|
|
51
|
+
"test:fast": "vitest run tests/unit/*scenarios*.test.js tests/unit/*branches*.test.js tests/unit/auth.test.js tests/unit/services.test.js tests/unit/server.test.js",
|
|
52
52
|
"test:watch": "vitest",
|
|
53
53
|
"test:coverage": "vitest run --coverage",
|
|
54
54
|
"test:coverage:quick": "vitest run --coverage",
|
|
55
55
|
"test:coverage:changed": "vitest run --coverage --changed",
|
|
56
56
|
"test:coverage:full": "FULL_REPORT=true vitest run --coverage",
|
|
57
|
-
"test:coverage:branches": "vitest run tests/unit/*branches
|
|
57
|
+
"test:coverage:branches": "vitest run tests/unit/*scenarios*.test.js tests/unit/*branches*.test.js --coverage",
|
|
58
58
|
"test:coverage:unit": "vitest run tests/unit/ --coverage",
|
|
59
59
|
"test:coverage:core": "vitest run tests/unit/core* tests/unit/server* tests/unit/routing* tests/unit/template* --coverage",
|
|
60
60
|
"test:coverage:auth": "vitest run tests/**/auth* tests/unit/server-auth-branches.test.js --coverage",
|
|
61
61
|
"test:coverage:orm": "vitest run tests/**/orm* tests/**/database* --coverage",
|
|
62
62
|
"test:coverage:services": "vitest run tests/**/service* --coverage",
|
|
63
63
|
"test:coverage:plugins": "vitest run tests/**/plugin* tests/unit/*plugin*.test.js --coverage",
|
|
64
|
-
"test:coverage:fast": "vitest run tests/unit/*branches
|
|
64
|
+
"test:coverage:fast": "vitest run tests/unit/*scenarios*.test.js tests/unit/*branches*.test.js tests/unit/auth.test.js tests/unit/services.test.js tests/unit/server.test.js --coverage",
|
|
65
65
|
"test:e2e": "playwright test",
|
|
66
66
|
"test:e2e:ui": "playwright test --ui",
|
|
67
67
|
"test:e2e:debug": "playwright test --debug",
|
|
@@ -55,8 +55,20 @@ function adminPanelPlugin(options = {}) {
|
|
|
55
55
|
richTextSanitize = true,
|
|
56
56
|
dataExchange: dataExchangeOption = true,
|
|
57
57
|
loginRateLimit,
|
|
58
|
+
lazy: lazyOption,
|
|
58
59
|
} = options;
|
|
59
60
|
|
|
61
|
+
if (lazyOption) {
|
|
62
|
+
const { lazyPlugin } = require('../lazy');
|
|
63
|
+
const lazyOpts = typeof lazyOption === 'object' ? lazyOption : {};
|
|
64
|
+
return lazyPlugin(() => adminPanelPlugin({ ...options, lazy: false }), {
|
|
65
|
+
name: 'admin-panel',
|
|
66
|
+
prefix: adminPath,
|
|
67
|
+
services: ['exchange.export', 'exchange.import'],
|
|
68
|
+
...lazyOpts,
|
|
69
|
+
});
|
|
70
|
+
}
|
|
71
|
+
|
|
60
72
|
const adminUsersConfig = typeof adminUsersOption === 'object' ? adminUsersOption : { enabled: adminUsersOption !== false };
|
|
61
73
|
|
|
62
74
|
// Validate required options
|
package/plugins/csrf/index.js
CHANGED
|
@@ -199,7 +199,7 @@ function csrfPlugin(options = {}) {
|
|
|
199
199
|
|
|
200
200
|
if (!submitted || !safeCompare(submitted, csrfTokenValue)) {
|
|
201
201
|
res.status(errorStatus);
|
|
202
|
-
if (req.accepts('html') && !req.path.startsWith('/api')) {
|
|
202
|
+
if (typeof req.accepts === 'function' && req.accepts('html') && !req.path.startsWith('/api')) {
|
|
203
203
|
return res.send(`<h1>${errorStatus} Forbidden</h1><p>${errorMessage}</p>`);
|
|
204
204
|
} else {
|
|
205
205
|
return res.json({ error: errorMessage });
|
|
@@ -44,8 +44,21 @@ function fileManagerPlugin(options = {}) {
|
|
|
44
44
|
permissions = null,
|
|
45
45
|
security: securityOpts = { validateMagicBytes: true, sanitizeSvg: true },
|
|
46
46
|
includePage = true,
|
|
47
|
+
lazy: lazyOption,
|
|
47
48
|
} = options;
|
|
48
49
|
|
|
50
|
+
if (lazyOption) {
|
|
51
|
+
const { lazyPlugin } = require('../lazy');
|
|
52
|
+
const lazyOpts = typeof lazyOption === 'object' ? lazyOption : {};
|
|
53
|
+
return lazyPlugin(() => fileManagerPlugin({ ...options, lazy: false }), {
|
|
54
|
+
name: 'file-manager',
|
|
55
|
+
prefix: apiPrefix,
|
|
56
|
+
services: ['file-manager.list', 'file-manager.upload', 'file-manager.delete', 'file-manager.create-folder'],
|
|
57
|
+
dependencies: { 'admin-panel': '*' },
|
|
58
|
+
...lazyOpts,
|
|
59
|
+
});
|
|
60
|
+
}
|
|
61
|
+
|
|
49
62
|
const resolvedBaseDir = path.resolve(baseDir);
|
|
50
63
|
|
|
51
64
|
const handlers = createFileManagerApiHandlers({
|
package/plugins/index.js
CHANGED
|
@@ -61,6 +61,8 @@ module.exports = {
|
|
|
61
61
|
get createApiKeyMiddleware() { return require('./api-key').createApiKeyMiddleware; },
|
|
62
62
|
get webhooksPlugin() { return require('./webhooks').webhooksPlugin; },
|
|
63
63
|
get WebhookDispatcher() { return require('./webhooks').WebhookDispatcher; },
|
|
64
|
+
get lazyPlugin() { return require('./lazy').lazyPlugin; },
|
|
65
|
+
get defineLazyPlugin() { return require('./lazy').defineLazyPlugin; },
|
|
64
66
|
};
|
|
65
67
|
|
|
66
68
|
|