@warlock.js/core 4.16.0 → 5.0.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/CHANGELOG.md +13 -0
- package/bin/warlock.js +154 -1
- package/esm/application/application.d.mts +65 -1
- package/esm/application/application.d.mts.map +1 -1
- package/esm/application/application.mjs +62 -0
- package/esm/application/application.mjs.map +1 -1
- package/esm/application/index.d.mts +1 -1
- package/esm/cli/cli-commands.manager.mjs +60 -10
- package/esm/cli/cli-commands.manager.mjs.map +1 -1
- package/esm/cli/commands/dev-server.command.mjs +1 -0
- package/esm/cli/commands/dev-server.command.mjs.map +1 -1
- package/esm/cli/commands/doctor/checks/handler-signature.check.mjs +40 -0
- package/esm/cli/commands/doctor/checks/handler-signature.check.mjs.map +1 -0
- package/esm/cli/commands/doctor/checks/index.mjs +4 -2
- package/esm/cli/commands/doctor/checks/index.mjs.map +1 -1
- package/esm/commands/cli-command.d.mts +1 -1
- package/esm/commands/cli-command.d.mts.map +1 -1
- package/esm/commands/cli-command.mjs.map +1 -1
- package/esm/commands/types.d.mts +10 -2
- package/esm/commands/types.d.mts.map +1 -1
- package/esm/config/config-handlers.d.mts +1 -2
- package/esm/config/config-handlers.d.mts.map +1 -1
- package/esm/config/config-handlers.mjs +3 -2
- package/esm/config/config-handlers.mjs.map +1 -1
- package/esm/config/locale-configuration.mjs +29 -0
- package/esm/config/locale-configuration.mjs.map +1 -0
- package/esm/connectors/assert-no-reserved-connector-names.d.mts +7 -0
- package/esm/connectors/assert-no-reserved-connector-names.d.mts.map +1 -0
- package/esm/connectors/assert-no-reserved-connector-names.mjs +44 -0
- package/esm/connectors/assert-no-reserved-connector-names.mjs.map +1 -0
- package/esm/connectors/assert-unique-connector-names.d.mts +7 -0
- package/esm/connectors/assert-unique-connector-names.d.mts.map +1 -0
- package/esm/connectors/assert-unique-connector-names.mjs +20 -0
- package/esm/connectors/assert-unique-connector-names.mjs.map +1 -0
- package/esm/connectors/connectors-manager.d.mts +38 -0
- package/esm/connectors/connectors-manager.d.mts.map +1 -1
- package/esm/connectors/connectors-manager.mjs +45 -12
- package/esm/connectors/connectors-manager.mjs.map +1 -1
- package/esm/connectors/describe-server-address.mjs +75 -0
- package/esm/connectors/describe-server-address.mjs.map +1 -0
- package/esm/connectors/http-connector.d.mts.map +1 -1
- package/esm/connectors/http-connector.mjs +6 -3
- package/esm/connectors/http-connector.mjs.map +1 -1
- package/esm/connectors/index.d.mts +4 -1
- package/esm/connectors/index.mjs +4 -1
- package/esm/connectors/register-configured-connectors.d.mts +14 -0
- package/esm/connectors/register-configured-connectors.d.mts.map +1 -0
- package/esm/connectors/register-configured-connectors.mjs +99 -0
- package/esm/connectors/register-configured-connectors.mjs.map +1 -0
- package/esm/connectors/socket-connector.d.mts.map +1 -1
- package/esm/connectors/socket-connector.mjs +4 -1
- package/esm/connectors/socket-connector.mjs.map +1 -1
- package/esm/connectors/types.d.mts +76 -1
- package/esm/connectors/types.d.mts.map +1 -1
- package/esm/connectors/types.mjs.map +1 -1
- package/esm/database/models/database-log/database-log.d.mts +50 -2
- package/esm/database/models/database-log/database-log.d.mts.map +1 -1
- package/esm/database/utils.d.mts +2 -2
- package/esm/database/utils.d.mts.map +1 -1
- package/esm/dev-server/development-server.mjs +1 -0
- package/esm/dev-server/development-server.mjs.map +1 -1
- package/esm/dev-server/layer-executor.mjs +2 -1
- package/esm/dev-server/layer-executor.mjs.map +1 -1
- package/esm/dev-server/read-config-ast.mjs +48 -0
- package/esm/dev-server/read-config-ast.mjs.map +1 -0
- package/esm/dev-server/run-typings-generation.mjs +18 -0
- package/esm/dev-server/run-typings-generation.mjs.map +1 -0
- package/esm/dev-server/type-generator.mjs +30 -39
- package/esm/dev-server/type-generator.mjs.map +1 -1
- package/esm/generations/add-command.action.mjs +169 -1
- package/esm/generations/add-command.action.mjs.map +1 -1
- package/esm/generations/stubs.mjs +93 -1
- package/esm/generations/stubs.mjs.map +1 -1
- package/esm/http/context/request-context.d.mts +14 -3
- package/esm/http/context/request-context.d.mts.map +1 -1
- package/esm/http/context/request-context.mjs +11 -1
- package/esm/http/context/request-context.mjs.map +1 -1
- package/esm/http/context/request-memo.d.mts +21 -0
- package/esm/http/context/request-memo.d.mts.map +1 -0
- package/esm/http/context/request-memo.mjs +48 -0
- package/esm/http/context/request-memo.mjs.map +1 -0
- package/esm/http/database/RequestLog.d.mts +164 -2
- package/esm/http/database/RequestLog.d.mts.map +1 -1
- package/esm/http/index.d.mts +6 -5
- package/esm/http/index.mjs +2 -1
- package/esm/http/middleware/cache-response-middleware.d.mts +2 -2
- package/esm/http/middleware/cache-response-middleware.d.mts.map +1 -1
- package/esm/http/middleware/cache-response-middleware.mjs +1 -1
- package/esm/http/middleware/cache-response-middleware.mjs.map +1 -1
- package/esm/http/middleware/concurrency-limit.middleware.mjs +1 -1
- package/esm/http/middleware/concurrency-limit.middleware.mjs.map +1 -1
- package/esm/http/middleware/idempotency.middleware.mjs +1 -1
- package/esm/http/middleware/idempotency.middleware.mjs.map +1 -1
- package/esm/http/middleware/index.d.mts +1 -1
- package/esm/http/middleware/index.mjs +1 -1
- package/esm/http/middleware/inject-request-context.d.mts +1 -8
- package/esm/http/middleware/inject-request-context.d.mts.map +1 -1
- package/esm/http/middleware/inject-request-context.mjs +9 -22
- package/esm/http/middleware/inject-request-context.mjs.map +1 -1
- package/esm/http/middleware/ip-filter.middleware.mjs +1 -1
- package/esm/http/middleware/ip-filter.middleware.mjs.map +1 -1
- package/esm/http/middleware/maintenance.middleware.mjs +1 -1
- package/esm/http/middleware/maintenance.middleware.mjs.map +1 -1
- package/esm/http/middleware/max-body-size.middleware.mjs +1 -1
- package/esm/http/middleware/max-body-size.middleware.mjs.map +1 -1
- package/esm/http/middleware/rate-limit.middleware.mjs +1 -1
- package/esm/http/middleware/rate-limit.middleware.mjs.map +1 -1
- package/esm/http/middleware/utils/idempotency-key.d.mts +0 -14
- package/esm/http/middleware/utils/idempotency-key.d.mts.map +1 -1
- package/esm/http/middleware/utils/idempotency-key.mjs +19 -1
- package/esm/http/middleware/utils/idempotency-key.mjs.map +1 -1
- package/esm/http/request.d.mts +119 -30
- package/esm/http/request.d.mts.map +1 -1
- package/esm/http/request.mjs +98 -25
- package/esm/http/request.mjs.map +1 -1
- package/esm/http/response.mjs +1 -1
- package/esm/http/response.mjs.map +1 -1
- package/esm/http/types.d.mts +36 -1
- package/esm/http/types.d.mts.map +1 -1
- package/esm/http/uploaded-file.d.mts +51 -19
- package/esm/http/uploaded-file.d.mts.map +1 -1
- package/esm/http/uploaded-file.mjs +36 -8
- package/esm/http/uploaded-file.mjs.map +1 -1
- package/esm/index.d.mts +17 -9
- package/esm/index.mjs +10 -4
- package/esm/production/build-contributions.mjs +115 -0
- package/esm/production/build-contributions.mjs.map +1 -0
- package/esm/production/production-builder.mjs +97 -2
- package/esm/production/production-builder.mjs.map +1 -1
- package/esm/production/resolve-build-config.d.mts +25 -0
- package/esm/production/resolve-build-config.d.mts.map +1 -0
- package/esm/production/resolve-build-config.mjs +43 -1
- package/esm/production/resolve-build-config.mjs.map +1 -1
- package/esm/repositories/adapters/cascade/cascade-query-builder.d.mts +1 -1
- package/esm/repositories/adapters/cascade/filter-applicator.mjs +20 -9
- package/esm/repositories/adapters/cascade/filter-applicator.mjs.map +1 -1
- package/esm/restful/restful.d.mts +29 -8
- package/esm/restful/restful.d.mts.map +1 -1
- package/esm/restful/restful.mjs +31 -13
- package/esm/restful/restful.mjs.map +1 -1
- package/esm/router/describe-route-for-log.mjs +29 -0
- package/esm/router/describe-route-for-log.mjs.map +1 -0
- package/esm/router/index.d.mts +3 -1
- package/esm/router/index.mjs +2 -0
- package/esm/router/log-request-lifecycle.mjs +38 -0
- package/esm/router/log-request-lifecycle.mjs.map +1 -0
- package/esm/router/positional-handler-diagnostics.d.mts +90 -0
- package/esm/router/positional-handler-diagnostics.d.mts.map +1 -0
- package/esm/router/positional-handler-diagnostics.mjs +247 -0
- package/esm/router/positional-handler-diagnostics.mjs.map +1 -0
- package/esm/router/route-registry.d.mts +34 -0
- package/esm/router/route-registry.d.mts.map +1 -0
- package/esm/router/router.d.mts.map +1 -1
- package/esm/router/router.mjs +87 -63
- package/esm/router/router.mjs.map +1 -1
- package/esm/router/types.d.mts +23 -5
- package/esm/router/types.d.mts.map +1 -1
- package/esm/storage/storage.d.mts.map +1 -1
- package/esm/storage/storage.mjs +1 -1
- package/esm/storage/storage.mjs.map +1 -1
- package/esm/storage/utils/safe-fetch.d.mts +11 -1
- package/esm/storage/utils/safe-fetch.d.mts.map +1 -1
- package/esm/storage/utils/safe-fetch.mjs +51 -4
- package/esm/storage/utils/safe-fetch.mjs.map +1 -1
- package/esm/tests/vitest-setup.mjs +1 -1
- package/esm/utils/load-environment.mjs +33 -2
- package/esm/utils/load-environment.mjs.map +1 -1
- package/esm/utils/types.d.mts +4 -0
- package/esm/utils/types.d.mts.map +1 -1
- package/esm/validation/validateAll.mjs +4 -1
- package/esm/validation/validateAll.mjs.map +1 -1
- package/esm/validation/validators/file-validator.d.mts +25 -1
- package/esm/validation/validators/file-validator.d.mts.map +1 -1
- package/esm/warlock-config/index.mjs +1 -1
- package/esm/warlock-config/normalize-build-config.mjs.map +1 -1
- package/esm/warlock-config/types.d.mts +36 -2
- package/esm/warlock-config/types.d.mts.map +1 -1
- package/package.json +15 -12
- package/skills/request-memo/SKILL.md +142 -0
- package/skills/use-request-locals/SKILL.md +144 -0
|
@@ -15,6 +15,23 @@ type UploadedFileMetadata = {
|
|
|
15
15
|
width?: number;
|
|
16
16
|
height?: number;
|
|
17
17
|
};
|
|
18
|
+
/**
|
|
19
|
+
* What an `UploadedFile` looks like on the wire.
|
|
20
|
+
*
|
|
21
|
+
* Every member is knowable **without reading the file**, which is what lets
|
|
22
|
+
* {@link UploadedFile.toJSON} be synchronous — see the note there. `size` is
|
|
23
|
+
* the one exception and it is optional for exactly that reason: present when
|
|
24
|
+
* the file has already been buffered, absent otherwise, never guessed.
|
|
25
|
+
*/
|
|
26
|
+
type UploadedFileJson = {
|
|
27
|
+
name: string;
|
|
28
|
+
mimeType: string;
|
|
29
|
+
extension: string;
|
|
30
|
+
isImage: boolean;
|
|
31
|
+
isVideo: boolean;
|
|
32
|
+
isAudio: boolean;
|
|
33
|
+
size?: number;
|
|
34
|
+
};
|
|
18
35
|
/**
|
|
19
36
|
* Options for validating file before saving
|
|
20
37
|
*/
|
|
@@ -440,25 +457,40 @@ declare class UploadedFile {
|
|
|
440
457
|
*/
|
|
441
458
|
protected adjustLocationForFormat(location: string): string;
|
|
442
459
|
/**
|
|
443
|
-
* Convert to JSON representation
|
|
444
|
-
*
|
|
445
|
-
*
|
|
446
|
-
|
|
447
|
-
|
|
448
|
-
|
|
449
|
-
|
|
450
|
-
|
|
451
|
-
|
|
452
|
-
|
|
453
|
-
|
|
454
|
-
|
|
455
|
-
|
|
456
|
-
|
|
457
|
-
|
|
458
|
-
|
|
459
|
-
|
|
460
|
-
|
|
460
|
+
* Convert to JSON representation.
|
|
461
|
+
*
|
|
462
|
+
* **Synchronous, and that is the whole point.** `toJSON` is not an ordinary
|
|
463
|
+
* method name — it is the hook `JSON.stringify` calls, and `JSON.stringify`
|
|
464
|
+
* does not await. While this was `async`, every implicit serialization of an
|
|
465
|
+
* upload produced `{}`: no base64, no size, not even the filename.
|
|
466
|
+
*
|
|
467
|
+
* Two call sites in core awaited it and worked (`http/response.ts:304`,
|
|
468
|
+
* `utils/to-json.ts:9`). The ones that could not were the ones that mattered:
|
|
469
|
+
* `cascade`'s model serializer calls `toJSON()` without awaiting, and
|
|
470
|
+
* `Resource.toJSON()` is itself synchronous. Those paths were silently
|
|
471
|
+
* broken. See canon `cd60b894`.
|
|
472
|
+
*
|
|
473
|
+
* **What is NOT here, and why.** `base64` forced the async — `buffer()` is
|
|
474
|
+
* async — and it also put the entire file, inflated by a third, into any
|
|
475
|
+
* response that happened to carry an upload. It is opt-in now via
|
|
476
|
+
* {@link UploadedFile.toBase64}. `dimensions` costs an image decode; ask for
|
|
477
|
+
* it with {@link UploadedFile.dimensions} when you want it.
|
|
478
|
+
*
|
|
479
|
+
* `size` is reported **only when the file has already been read**. Reading it
|
|
480
|
+
* here would make the method async again, and guessing would be worse than
|
|
481
|
+
* omitting: a wrong number is believed, an absent one is asked about. In
|
|
482
|
+
* practice validation or `save()` has usually buffered the file long before
|
|
483
|
+
* anything serializes it.
|
|
484
|
+
*/
|
|
485
|
+
toJSON(): UploadedFileJson;
|
|
486
|
+
/**
|
|
487
|
+
* The file's contents as base64.
|
|
488
|
+
*
|
|
489
|
+
* Explicit because it is expensive: it reads the whole file into memory and
|
|
490
|
+
* grows it by a third. This used to happen on every serialization.
|
|
491
|
+
*/
|
|
492
|
+
toBase64(): Promise<string>;
|
|
461
493
|
}
|
|
462
494
|
//#endregion
|
|
463
|
-
export { FileValidationOptions, UploadedFile };
|
|
495
|
+
export { FileValidationOptions, UploadedFile, UploadedFileJson };
|
|
464
496
|
//# sourceMappingURL=uploaded-file.d.mts.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"uploaded-file.d.mts","names":[],"sources":["../../../../../../../core/src/http/uploaded-file.ts"],"mappings":";;;;;;;;;KAiBK,oBAAA;EACH,IAAA;EACA,QAAA;EACA,SAAA;EACA,IAAA;EACA,KAAA;EACA,MAAA;AAAA;;;;KAMU,qBAAA;
|
|
1
|
+
{"version":3,"file":"uploaded-file.d.mts","names":[],"sources":["../../../../../../../core/src/http/uploaded-file.ts"],"mappings":"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"}
|
|
@@ -555,23 +555,51 @@ var UploadedFile = class {
|
|
|
555
555
|
return `${location}.${ext}`;
|
|
556
556
|
}
|
|
557
557
|
/**
|
|
558
|
-
* Convert to JSON representation
|
|
559
|
-
*
|
|
560
|
-
*
|
|
561
|
-
|
|
562
|
-
async
|
|
558
|
+
* Convert to JSON representation.
|
|
559
|
+
*
|
|
560
|
+
* **Synchronous, and that is the whole point.** `toJSON` is not an ordinary
|
|
561
|
+
* method name — it is the hook `JSON.stringify` calls, and `JSON.stringify`
|
|
562
|
+
* does not await. While this was `async`, every implicit serialization of an
|
|
563
|
+
* upload produced `{}`: no base64, no size, not even the filename.
|
|
564
|
+
*
|
|
565
|
+
* Two call sites in core awaited it and worked (`http/response.ts:304`,
|
|
566
|
+
* `utils/to-json.ts:9`). The ones that could not were the ones that mattered:
|
|
567
|
+
* `cascade`'s model serializer calls `toJSON()` without awaiting, and
|
|
568
|
+
* `Resource.toJSON()` is itself synchronous. Those paths were silently
|
|
569
|
+
* broken. See canon `cd60b894`.
|
|
570
|
+
*
|
|
571
|
+
* **What is NOT here, and why.** `base64` forced the async — `buffer()` is
|
|
572
|
+
* async — and it also put the entire file, inflated by a third, into any
|
|
573
|
+
* response that happened to carry an upload. It is opt-in now via
|
|
574
|
+
* {@link UploadedFile.toBase64}. `dimensions` costs an image decode; ask for
|
|
575
|
+
* it with {@link UploadedFile.dimensions} when you want it.
|
|
576
|
+
*
|
|
577
|
+
* `size` is reported **only when the file has already been read**. Reading it
|
|
578
|
+
* here would make the method async again, and guessing would be worse than
|
|
579
|
+
* omitting: a wrong number is believed, an absent one is asked about. In
|
|
580
|
+
* practice validation or `save()` has usually buffered the file long before
|
|
581
|
+
* anything serializes it.
|
|
582
|
+
*/
|
|
583
|
+
toJSON() {
|
|
563
584
|
return {
|
|
564
585
|
name: this.name,
|
|
565
586
|
mimeType: this.mimeType,
|
|
566
587
|
extension: this.extension,
|
|
567
|
-
size: await this.size(),
|
|
568
588
|
isImage: this.isImage,
|
|
569
589
|
isVideo: this.isVideo,
|
|
570
590
|
isAudio: this.isAudio,
|
|
571
|
-
|
|
572
|
-
base64: (await this.buffer()).toString("base64")
|
|
591
|
+
size: this.bufferedFileContent?.length
|
|
573
592
|
};
|
|
574
593
|
}
|
|
594
|
+
/**
|
|
595
|
+
* The file's contents as base64.
|
|
596
|
+
*
|
|
597
|
+
* Explicit because it is expensive: it reads the whole file into memory and
|
|
598
|
+
* grows it by a third. This used to happen on every serialization.
|
|
599
|
+
*/
|
|
600
|
+
async toBase64() {
|
|
601
|
+
return (await this.buffer()).toString("base64");
|
|
602
|
+
}
|
|
575
603
|
};
|
|
576
604
|
|
|
577
605
|
//#endregion
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"uploaded-file.mjs","names":[],"sources":["../../../../../../../core/src/http/uploaded-file.ts"],"sourcesContent":["import type { MultipartFile } from \"@fastify/multipart\";\nimport { Random } from \"@mongez/reinforcements\";\nimport dayjs from \"dayjs\";\nimport path from \"path\";\nimport { Image, type ImageFormat, type ImageTransformOptions } from \"../image\";\nimport { storage, type ScopedStorage, type StorageDriverName, type StorageFile } from \"../storage\";\nimport { sanitizePath } from \"../utils/paths\";\nimport { uploadsConfig } from \"./uploads-config\";\nimport type {\n FileNamingStrategy,\n ImageTransformCallback,\n PrefixConfig,\n SaveAsOptions,\n SaveOptions,\n UploadedFileImageOptions,\n} from \"./uploads-types\";\n\ntype UploadedFileMetadata = {\n name: string;\n mimeType: string;\n extension: string;\n size: number;\n width?: number;\n height?: number;\n};\n\n/**\n * Options for validating file before saving\n */\nexport type FileValidationOptions = {\n /**\n * List of allowed MIME types\n *\n * @example [\"image/jpeg\", \"image/png\", \"image/webp\"]\n */\n allowedMimeTypes?: string[];\n\n /**\n * List of allowed file extensions (without dot)\n *\n * @example [\"jpg\", \"jpeg\", \"png\", \"webp\"]\n */\n allowedExtensions?: string[];\n\n /**\n * Maximum file size in bytes\n *\n * @example 5 * 1024 * 1024 // 5MB\n */\n maxSize?: number;\n};\n\n/**\n * UploadedFile - Handles multipart file uploads with storage and image integration\n *\n * Provides a fluent API for validating, transforming, and saving uploaded files\n * to various storage drivers (local, S3, R2, etc.).\n *\n * @example\n * ```typescript\n * // Simple save with random name\n * const file = await uploadedFile.save(\"avatars\");\n *\n * // Original name with date prefix\n * const file = await uploadedFile.save(\"avatars\", {\n * name: \"original\",\n * prefix: { format: \"yyyy/mm/dd\", as: \"directory\" }\n * });\n *\n * // With image transformations\n * const file = await uploadedFile\n * .resize(800, 600)\n * .quality(85)\n * .format(\"webp\")\n * .save(\"avatars\");\n *\n * // Different storage driver\n * const file = await uploadedFile.use(\"s3\").save(\"avatars\");\n * ```\n */\nexport class UploadedFile {\n /**\n * File buffered content\n * @internal\n */\n protected bufferedFileContent?: Buffer;\n\n /**\n * Upload file hash (SHA-256)\n *\n * Populated after file is saved.\n */\n public hash = \"\";\n\n /**\n * Selected storage driver\n * @internal\n */\n protected _storage: ScopedStorage = storage;\n\n /**\n * Saved StorageFile reference\n * @internal\n */\n protected _storageFile?: StorageFile;\n\n /**\n * Queued image options (high-level API)\n * @internal\n */\n protected _imageOptions: UploadedFileImageOptions = {};\n\n /**\n * Full transform options or callback\n * @internal\n */\n protected _transformConfig?: ImageTransformOptions | ImageTransformCallback;\n\n /**\n * Create a new UploadedFile instance\n *\n * @param fileData - Multipart file data from Fastify\n * @throws Error if file data is invalid\n */\n public constructor(protected readonly fileData: MultipartFile) {\n if (!fileData?.filename) {\n throw new Error(\"Invalid file data: filename is required\");\n }\n }\n\n // ============================================================\n // File Properties\n // ============================================================\n\n /**\n * Get file name (sanitized)\n *\n * Returns the original filename with special characters removed/replaced.\n */\n public get name(): string {\n return sanitizePath(this.fileData.filename);\n }\n\n /**\n * Get file MIME type\n *\n * @example \"image/jpeg\", \"application/pdf\"\n */\n public get mimeType(): string {\n return this.fileData.mimetype;\n }\n\n /**\n * Get file extension (lowercase, without dot)\n *\n * @example \"jpg\", \"png\", \"pdf\"\n */\n public get extension(): string {\n return path.extname(this.fileData.filename).replace(\".\", \"\").toLowerCase();\n }\n\n /**\n * Get file metadata\n */\n public async metadata(): Promise<UploadedFileMetadata> {\n const data: UploadedFileMetadata = {\n name: this.name,\n mimeType: this.mimeType,\n extension: this.extension,\n size: await this.size(),\n };\n\n if (this.isImage) {\n const dimensions = await this.dimensions();\n data.width = dimensions.width;\n data.height = dimensions.height;\n }\n\n return data;\n }\n\n /**\n * Get file size in bytes\n *\n * Buffers the file content if not already buffered.\n */\n public async size(): Promise<number> {\n const file = await this.buffer();\n return file.length;\n }\n\n /**\n * Get file buffer\n *\n * Caches the buffer after first call for efficiency.\n */\n public async buffer(): Promise<Buffer> {\n if (this.bufferedFileContent) {\n return this.bufferedFileContent;\n }\n\n this.bufferedFileContent = await this.fileData.toBuffer();\n return this.bufferedFileContent;\n }\n\n // ============================================================\n // File Type Checks\n // ============================================================\n\n /**\n * Check if file is an image based on MIME type\n */\n public get isImage(): boolean {\n return this.mimeType.startsWith(\"image\");\n }\n\n /**\n * Check if file is a video based on MIME type\n */\n public get isVideo(): boolean {\n return this.mimeType.startsWith(\"video\");\n }\n\n /**\n * Check if file is an audio based on MIME type\n */\n public get isAudio(): boolean {\n return this.mimeType.startsWith(\"audio\");\n }\n\n // ============================================================\n // Storage Driver Selection\n // ============================================================\n\n /**\n * Select a specific storage driver for this upload\n *\n * Returns this instance for chaining. The driver is used\n * when `save()` or `saveAs()` is called.\n *\n * @param driver - Driver name from storage configuration\n * @returns This instance for chaining\n *\n * @example\n * ```typescript\n * await file.use(\"s3\").save(\"avatars\");\n * await file.use(\"r2\").save(\"cdn/images\");\n * ```\n */\n public use(driver: StorageDriverName): this {\n this._storage = storage.use(driver) as ScopedStorage;\n return this;\n }\n\n // ============================================================\n // High-Level Image Transform API\n // ============================================================\n\n /**\n * Resize the image before saving\n *\n * Only applies to image files. Non-image files ignore this.\n *\n * @param width - Target width in pixels\n * @param height - Optional target height (maintains aspect ratio if omitted)\n * @returns This instance for chaining\n *\n * @example\n * ```typescript\n * await file.resize(800).save(\"thumbnails\");\n * await file.resize(400, 400).save(\"avatars\");\n * ```\n */\n public resize(width: number, height?: number): this {\n this._imageOptions.resize = { width, height };\n return this;\n }\n\n /**\n * Set image output quality\n *\n * Quality affects file size and visual fidelity.\n * Only applies to formats that support quality (JPEG, WebP, AVIF).\n *\n * @param value - Quality value (1-100)\n * @returns This instance for chaining\n *\n * @example\n * ```typescript\n * await file.quality(85).save(\"images\");\n * ```\n */\n public quality(value: number): this {\n if (value < 1 || value > 100) {\n throw new Error(\"Quality must be between 1 and 100\");\n }\n this._imageOptions.quality = value;\n return this;\n }\n\n /**\n * Convert image to a specific format\n *\n * Changes the output format and updates the file extension accordingly.\n *\n * @param format - Target image format (jpeg, png, webp, avif, etc.)\n * @returns This instance for chaining\n *\n * @example\n * ```typescript\n * await file.format(\"webp\").save(\"images\");\n * await file.resize(800).format(\"avif\").quality(80).save(\"optimized\");\n * ```\n */\n public format(format: ImageFormat): this {\n this._imageOptions.format = format;\n return this;\n }\n\n /**\n * Rotate the image\n *\n * @param degrees - Rotation angle in degrees (positive = clockwise)\n * @returns This instance for chaining\n *\n * @example\n * ```typescript\n * await file.rotate(90).save(\"rotated\");\n * ```\n */\n public rotate(degrees: number): this {\n this._imageOptions.rotate = degrees;\n return this;\n }\n\n /**\n * Apply blur effect to the image\n *\n * @param sigma - Blur intensity (default: 3, minimum: 0.3)\n * @returns This instance for chaining\n *\n * @example\n * ```typescript\n * await file.blur(5).save(\"blurred\");\n * ```\n */\n public blur(sigma = 3): this {\n if (sigma < 0.3) {\n throw new Error(\"Blur sigma must be at least 0.3\");\n }\n this._imageOptions.blur = sigma;\n return this;\n }\n\n /**\n * Convert image to grayscale (black and white)\n *\n * @returns This instance for chaining\n *\n * @example\n * ```typescript\n * await file.grayscale().save(\"bw-images\");\n * ```\n */\n public grayscale(): this {\n this._imageOptions.grayscale = true;\n return this;\n }\n\n // ============================================================\n // Full Transform Control\n // ============================================================\n\n /**\n * Apply full image transformations\n *\n * Provides complete control over image processing. Can be used with:\n * - An options object for predefined transforms\n * - A callback function for chained operations\n *\n * @param config - Transform options or callback function\n * @returns This instance for chaining\n *\n * @example\n * ```typescript\n * // Using options object\n * await file.transform({\n * resize: { width: 800, fit: \"inside\" },\n * quality: 85\n * }).save(\"images\");\n *\n * // Using callback for full control\n * await file.transform(img =>\n * img.resize({ width: 800 })\n * .watermark(\"logo.png\", { gravity: \"southeast\" })\n * .sharpen()\n * ).save(\"products\");\n * ```\n */\n public transform(config: ImageTransformOptions | ImageTransformCallback): this {\n this._transformConfig = config;\n return this;\n }\n\n /**\n * Get an Image instance for advanced manipulation\n *\n * Returns an Image instance from the file buffer for manual processing.\n * Use this when you need operations not covered by the fluent API.\n *\n * @returns Promise resolving to Image instance\n *\n * @example\n * ```typescript\n * const img = await file.toImage();\n * await img\n * .resize({ width: 800 })\n * .watermark(\"logo.png\", { gravity: \"southeast\" })\n * .save(\"path/to/output.jpg\");\n * ```\n */\n public async toImage(): Promise<Image> {\n return new Image(await this.buffer());\n }\n\n // ============================================================\n // Image Metadata\n // ============================================================\n\n /**\n * Get file width and height (only for images)\n *\n * @returns Dimensions object, or empty object if not an image\n */\n public async dimensions(): Promise<{ width?: number; height?: number }> {\n if (!this.isImage) {\n return {};\n }\n\n return new Image(await this.buffer()).dimensions();\n }\n\n // ============================================================\n // Validation\n // ============================================================\n\n /**\n * Validate file against the given options\n *\n * @param options - Validation rules\n * @throws Error if validation fails\n *\n * @example\n * ```typescript\n * await file.validate({\n * allowedMimeTypes: [\"image/jpeg\", \"image/png\"],\n * maxSize: 5 * 1024 * 1024 // 5MB\n * });\n * ```\n */\n public async validate(options: FileValidationOptions): Promise<void> {\n const { allowedMimeTypes, allowedExtensions, maxSize } = options;\n\n if (allowedMimeTypes && !allowedMimeTypes.includes(this.mimeType)) {\n throw new Error(\n `Invalid file type: ${this.mimeType}. Allowed types: ${allowedMimeTypes.join(\", \")}`,\n );\n }\n\n if (allowedExtensions && !allowedExtensions.includes(this.extension)) {\n throw new Error(\n `Invalid file extension: ${this.extension}. Allowed extensions: ${allowedExtensions.join(\", \")}`,\n );\n }\n\n if (maxSize) {\n const fileSize = await this.size();\n if (fileSize > maxSize) {\n throw new Error(`File too large: ${fileSize} bytes. Maximum allowed: ${maxSize} bytes`);\n }\n }\n }\n\n // ============================================================\n // Save Operations\n // ============================================================\n\n /**\n * Save the file to a directory with automatic naming\n * Keep in mind to use only relative path to the root of storage\n * If you are using local driver\n * Uses the configured naming strategy and prefix options to generate\n * the final path. Returns a StorageFile for accessing file metadata.\n *\n * @param directory - Target directory path\n * @param options - Save options (name, prefix, driver, validate)\n * @returns StorageFile instance with file metadata and operations\n *\n * @example\n * ```typescript\n * // Random name (default)\n * await file.save(\"avatars\");\n * // → avatars/x7k9m2p4.jpg\n *\n * // Original name\n * await file.save(\"avatars\", { name: \"original\" });\n * // → avatars/photo.jpg\n *\n * // With date directory\n * await file.save(\"avatars\", {\n * prefix: { format: \"yyyy/mm/dd\", as: \"directory\" }\n * });\n * // → avatars/2025/12/21/x7k9m2p4.jpg\n *\n * // Original name with datetime prefix\n * await file.save(\"avatars\", { name: \"original\", prefix: true });\n * // → avatars/21-12-2025-16-45-30-photo.jpg\n * ```\n */\n public async save(directory: string, options?: SaveOptions): Promise<StorageFile> {\n // Validate if requested\n if (options?.validate) {\n await this.validate(options.validate);\n }\n\n // Resolve filename and prefix\n const filename = this.resolveFilename(options);\n const prefix = this.resolvePrefix(options?.prefix);\n const location = this.buildLocation(directory, prefix, filename);\n\n return this.saveToLocation(location, options?.driver);\n }\n\n /**\n * Save the file to an explicit path\n *\n * Unlike `save()`, this method uses the exact path you provide.\n * No automatic naming or prefix is applied.\n *\n * @param location - Full file path (directory + filename)\n * @param options - Save options (driver, validate)\n * @returns StorageFile instance with file metadata\n *\n * @example\n * ```typescript\n * await file.saveAs(\"avatars/profile-123.png\");\n * await file.saveAs(\"products/2025/featured-image.webp\");\n * ```\n */\n public async saveAs(location: string, options?: SaveAsOptions): Promise<StorageFile> {\n // Validate if requested\n if (options?.validate) {\n await this.validate(options.validate);\n }\n\n return this.saveToLocation(location, options?.driver);\n }\n\n /**\n * Get the StorageFile reference if file has been saved\n *\n * Returns undefined if file hasn't been saved yet.\n */\n public get storageFile(): StorageFile | undefined {\n return this._storageFile;\n }\n\n // ============================================================\n // Internal Helpers\n // ============================================================\n\n /**\n * Execute save to the specified location\n * @internal\n */\n protected async saveToLocation(\n location: string,\n driver?: StorageDriverName,\n ): Promise<StorageFile> {\n // Get file content (apply transforms if image)\n const content = await this.getProcessedContent();\n\n // Select storage\n const storageInstance = this.resolveStorage(driver);\n\n // Determine final location (adjust extension if format changed)\n const finalLocation = this.adjustLocationForFormat(location);\n\n // Save to storage\n this._storageFile = await storageInstance.put(content, finalLocation, {\n mimeType: this.getFinalMimeType(),\n });\n\n // Store hash from StorageFile\n const info = await this._storageFile.data();\n this.hash = info.hash || \"\";\n\n return this._storageFile;\n }\n\n /**\n * Get processed content (with transforms applied if applicable)\n * @internal\n */\n protected async getProcessedContent(): Promise<Buffer> {\n const content = await this.buffer();\n\n // If not an image or no transforms, return as-is\n if (!this.isImage || !this.hasTransforms()) {\n return content;\n }\n\n // Create Image and apply transforms\n let img = new Image(content);\n\n // Apply transform callback or options\n if (typeof this._transformConfig === \"function\") {\n img = this._transformConfig(img);\n } else if (this._transformConfig) {\n img = img.apply(this._transformConfig);\n }\n\n // Apply high-level options on top\n img = this.applyImageOptions(img);\n\n return img.toBuffer();\n }\n\n /**\n * Apply high-level image options\n * @internal\n */\n protected applyImageOptions(img: Image): Image {\n const opts = this._imageOptions;\n\n if (opts.resize) {\n img = img.resize({ width: opts.resize.width, height: opts.resize.height });\n }\n\n if (opts.rotate !== undefined) {\n img = img.rotate(opts.rotate);\n }\n\n if (opts.blur !== undefined) {\n img = img.blur(opts.blur);\n }\n\n if (opts.grayscale) {\n img = img.grayscale();\n }\n\n if (opts.quality !== undefined) {\n img = img.quality(opts.quality);\n }\n\n if (opts.format) {\n img = img.format(opts.format);\n }\n\n return img;\n }\n\n /**\n * Check if any transforms are queued\n * @internal\n */\n protected hasTransforms(): boolean {\n return this._transformConfig !== undefined || Object.keys(this._imageOptions).length > 0;\n }\n\n /**\n * Resolve storage instance to use\n * @internal\n */\n protected resolveStorage(driver?: StorageDriverName): ScopedStorage | typeof storage {\n if (driver) {\n return storage.use(driver) as ScopedStorage;\n }\n\n return this._storage || storage;\n }\n\n /**\n * Resolve the filename based on options and config\n * @internal\n */\n protected resolveFilename(options?: SaveOptions): string {\n const namingStrategy: FileNamingStrategy = options?.name ?? uploadsConfig(\"name\") ?? \"random\";\n let baseName: string;\n\n if (namingStrategy === \"original\") {\n baseName = path.basename(this.name, path.extname(this.name));\n } else if (namingStrategy === \"random\") {\n const length = uploadsConfig(\"randomLength\");\n baseName = Random.string(length);\n } else {\n // Custom name - strip extension if provided, we'll add it\n baseName = path.basename(namingStrategy, path.extname(namingStrategy));\n }\n\n // Get extension (may be changed by format transform)\n const ext = this.getFinalExtension();\n\n return `${baseName}.${ext}`;\n }\n\n /**\n * Resolve prefix based on options and config\n * @internal\n */\n protected resolvePrefix(prefix?: PrefixConfig): string {\n // No prefix\n if (prefix === false || prefix === undefined) {\n const configPrefix = uploadsConfig(\"prefix\");\n if (!configPrefix) {\n return \"\";\n }\n // Use config prefix if no explicit prefix provided\n prefix = configPrefix;\n }\n\n // Boolean true = use default format\n if (prefix === true) {\n const format = uploadsConfig(\"defaultPrefixFormat\")!;\n return this.formatDatePrefix(format, \"file\");\n }\n\n // String = static prefix\n if (typeof prefix === \"string\") {\n return prefix;\n }\n\n // PrefixOptions object\n const parts: string[] = [];\n\n // Add date format if specified\n if (prefix.format) {\n parts.push(this.formatDate(prefix.format));\n }\n\n // Add random string if specified\n if (prefix.randomLength) {\n parts.push(Random.string(prefix.randomLength));\n }\n\n const combined = parts.join(\"-\");\n const as = prefix.as ?? \"file\";\n\n if (as === \"directory\") {\n return combined ? `${combined}/` : \"\";\n }\n\n return combined ? `${combined}-` : \"\";\n }\n\n /**\n * Format a date prefix with the given format\n * @internal\n */\n protected formatDatePrefix(format: string, as: \"file\" | \"directory\"): string {\n const formatted = this.formatDate(format);\n return as === \"directory\" ? `${formatted}/` : `${formatted}-`;\n }\n\n /**\n * Format current date using token-based format string\n * @internal\n */\n protected formatDate(format: string): string {\n return dayjs().format(format);\n }\n\n /**\n * Build final location from directory, prefix, and filename\n * @internal\n */\n protected buildLocation(directory: string, prefix: string, filename: string): string {\n // Clean up directory (remove trailing slash)\n const dir = directory.replace(/\\/$/, \"\");\n\n // If prefix ends with /, it's a directory\n if (prefix.endsWith(\"/\")) {\n return `${dir}/${prefix}${filename}`;\n }\n\n // Otherwise prefix is part of filename\n return `${dir}/${prefix}${filename}`;\n }\n\n /**\n * Get final extension (accounting for format changes)\n * @internal\n */\n protected getFinalExtension(): string {\n if (this._imageOptions.format) {\n // Map formats to extensions\n const format = this._imageOptions.format;\n\n if (format === \"jpeg\") return \"jpg\";\n\n return format;\n }\n\n return this.extension;\n }\n\n /**\n * Get final MIME type (accounting for format changes)\n * @internal\n */\n protected getFinalMimeType(): string {\n if (this._imageOptions.format) {\n const format = this._imageOptions.format;\n\n if (format === \"jpeg\" || format === \"jpg\") return \"image/jpeg\";\n\n return `image/${format}`;\n }\n\n return this.mimeType;\n }\n\n /**\n * Adjust location to use correct extension if format changed\n * @internal\n */\n protected adjustLocationForFormat(location: string): string {\n if (!this._imageOptions.format) {\n return location;\n }\n\n const ext = this.getFinalExtension();\n const currentExt = path.extname(location);\n\n if (currentExt) {\n return location.replace(currentExt, `.${ext}`);\n }\n\n return `${location}.${ext}`;\n }\n\n // ============================================================\n // Serialization\n // ============================================================\n\n /**\n * Convert to JSON representation\n *\n * Includes file metadata and base64 content for serialization.\n */\n public async toJSON() {\n return {\n name: this.name,\n mimeType: this.mimeType,\n extension: this.extension,\n size: await this.size(),\n isImage: this.isImage,\n isVideo: this.isVideo,\n isAudio: this.isAudio,\n dimensions: this.isImage ? await this.dimensions() : undefined,\n base64: (await this.buffer()).toString(\"base64\"),\n };\n }\n}\n"],"mappings":"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"}
|
|
1
|
+
{"version":3,"file":"uploaded-file.mjs","names":[],"sources":["../../../../../../../core/src/http/uploaded-file.ts"],"sourcesContent":["import type { MultipartFile } from \"@fastify/multipart\";\nimport { Random } from \"@mongez/reinforcements\";\nimport dayjs from \"dayjs\";\nimport path from \"path\";\nimport { Image, type ImageFormat, type ImageTransformOptions } from \"../image\";\nimport { storage, type ScopedStorage, type StorageDriverName, type StorageFile } from \"../storage\";\nimport { sanitizePath } from \"../utils/paths\";\nimport { uploadsConfig } from \"./uploads-config\";\nimport type {\n FileNamingStrategy,\n ImageTransformCallback,\n PrefixConfig,\n SaveAsOptions,\n SaveOptions,\n UploadedFileImageOptions,\n} from \"./uploads-types\";\n\ntype UploadedFileMetadata = {\n name: string;\n mimeType: string;\n extension: string;\n size: number;\n width?: number;\n height?: number;\n};\n\n/**\n * What an `UploadedFile` looks like on the wire.\n *\n * Every member is knowable **without reading the file**, which is what lets\n * {@link UploadedFile.toJSON} be synchronous — see the note there. `size` is\n * the one exception and it is optional for exactly that reason: present when\n * the file has already been buffered, absent otherwise, never guessed.\n */\nexport type UploadedFileJson = {\n name: string;\n mimeType: string;\n extension: string;\n isImage: boolean;\n isVideo: boolean;\n isAudio: boolean;\n size?: number;\n};\n\n/**\n * Options for validating file before saving\n */\nexport type FileValidationOptions = {\n /**\n * List of allowed MIME types\n *\n * @example [\"image/jpeg\", \"image/png\", \"image/webp\"]\n */\n allowedMimeTypes?: string[];\n\n /**\n * List of allowed file extensions (without dot)\n *\n * @example [\"jpg\", \"jpeg\", \"png\", \"webp\"]\n */\n allowedExtensions?: string[];\n\n /**\n * Maximum file size in bytes\n *\n * @example 5 * 1024 * 1024 // 5MB\n */\n maxSize?: number;\n};\n\n/**\n * UploadedFile - Handles multipart file uploads with storage and image integration\n *\n * Provides a fluent API for validating, transforming, and saving uploaded files\n * to various storage drivers (local, S3, R2, etc.).\n *\n * @example\n * ```typescript\n * // Simple save with random name\n * const file = await uploadedFile.save(\"avatars\");\n *\n * // Original name with date prefix\n * const file = await uploadedFile.save(\"avatars\", {\n * name: \"original\",\n * prefix: { format: \"yyyy/mm/dd\", as: \"directory\" }\n * });\n *\n * // With image transformations\n * const file = await uploadedFile\n * .resize(800, 600)\n * .quality(85)\n * .format(\"webp\")\n * .save(\"avatars\");\n *\n * // Different storage driver\n * const file = await uploadedFile.use(\"s3\").save(\"avatars\");\n * ```\n */\nexport class UploadedFile {\n /**\n * File buffered content\n * @internal\n */\n protected bufferedFileContent?: Buffer;\n\n /**\n * Upload file hash (SHA-256)\n *\n * Populated after file is saved.\n */\n public hash = \"\";\n\n /**\n * Selected storage driver\n * @internal\n */\n protected _storage: ScopedStorage = storage;\n\n /**\n * Saved StorageFile reference\n * @internal\n */\n protected _storageFile?: StorageFile;\n\n /**\n * Queued image options (high-level API)\n * @internal\n */\n protected _imageOptions: UploadedFileImageOptions = {};\n\n /**\n * Full transform options or callback\n * @internal\n */\n protected _transformConfig?: ImageTransformOptions | ImageTransformCallback;\n\n /**\n * Create a new UploadedFile instance\n *\n * @param fileData - Multipart file data from Fastify\n * @throws Error if file data is invalid\n */\n public constructor(protected readonly fileData: MultipartFile) {\n if (!fileData?.filename) {\n throw new Error(\"Invalid file data: filename is required\");\n }\n }\n\n // ============================================================\n // File Properties\n // ============================================================\n\n /**\n * Get file name (sanitized)\n *\n * Returns the original filename with special characters removed/replaced.\n */\n public get name(): string {\n return sanitizePath(this.fileData.filename);\n }\n\n /**\n * Get file MIME type\n *\n * @example \"image/jpeg\", \"application/pdf\"\n */\n public get mimeType(): string {\n return this.fileData.mimetype;\n }\n\n /**\n * Get file extension (lowercase, without dot)\n *\n * @example \"jpg\", \"png\", \"pdf\"\n */\n public get extension(): string {\n return path.extname(this.fileData.filename).replace(\".\", \"\").toLowerCase();\n }\n\n /**\n * Get file metadata\n */\n public async metadata(): Promise<UploadedFileMetadata> {\n const data: UploadedFileMetadata = {\n name: this.name,\n mimeType: this.mimeType,\n extension: this.extension,\n size: await this.size(),\n };\n\n if (this.isImage) {\n const dimensions = await this.dimensions();\n data.width = dimensions.width;\n data.height = dimensions.height;\n }\n\n return data;\n }\n\n /**\n * Get file size in bytes\n *\n * Buffers the file content if not already buffered.\n */\n public async size(): Promise<number> {\n const file = await this.buffer();\n return file.length;\n }\n\n /**\n * Get file buffer\n *\n * Caches the buffer after first call for efficiency.\n */\n public async buffer(): Promise<Buffer> {\n if (this.bufferedFileContent) {\n return this.bufferedFileContent;\n }\n\n this.bufferedFileContent = await this.fileData.toBuffer();\n return this.bufferedFileContent;\n }\n\n // ============================================================\n // File Type Checks\n // ============================================================\n\n /**\n * Check if file is an image based on MIME type\n */\n public get isImage(): boolean {\n return this.mimeType.startsWith(\"image\");\n }\n\n /**\n * Check if file is a video based on MIME type\n */\n public get isVideo(): boolean {\n return this.mimeType.startsWith(\"video\");\n }\n\n /**\n * Check if file is an audio based on MIME type\n */\n public get isAudio(): boolean {\n return this.mimeType.startsWith(\"audio\");\n }\n\n // ============================================================\n // Storage Driver Selection\n // ============================================================\n\n /**\n * Select a specific storage driver for this upload\n *\n * Returns this instance for chaining. The driver is used\n * when `save()` or `saveAs()` is called.\n *\n * @param driver - Driver name from storage configuration\n * @returns This instance for chaining\n *\n * @example\n * ```typescript\n * await file.use(\"s3\").save(\"avatars\");\n * await file.use(\"r2\").save(\"cdn/images\");\n * ```\n */\n public use(driver: StorageDriverName): this {\n this._storage = storage.use(driver) as ScopedStorage;\n return this;\n }\n\n // ============================================================\n // High-Level Image Transform API\n // ============================================================\n\n /**\n * Resize the image before saving\n *\n * Only applies to image files. Non-image files ignore this.\n *\n * @param width - Target width in pixels\n * @param height - Optional target height (maintains aspect ratio if omitted)\n * @returns This instance for chaining\n *\n * @example\n * ```typescript\n * await file.resize(800).save(\"thumbnails\");\n * await file.resize(400, 400).save(\"avatars\");\n * ```\n */\n public resize(width: number, height?: number): this {\n this._imageOptions.resize = { width, height };\n return this;\n }\n\n /**\n * Set image output quality\n *\n * Quality affects file size and visual fidelity.\n * Only applies to formats that support quality (JPEG, WebP, AVIF).\n *\n * @param value - Quality value (1-100)\n * @returns This instance for chaining\n *\n * @example\n * ```typescript\n * await file.quality(85).save(\"images\");\n * ```\n */\n public quality(value: number): this {\n if (value < 1 || value > 100) {\n throw new Error(\"Quality must be between 1 and 100\");\n }\n this._imageOptions.quality = value;\n return this;\n }\n\n /**\n * Convert image to a specific format\n *\n * Changes the output format and updates the file extension accordingly.\n *\n * @param format - Target image format (jpeg, png, webp, avif, etc.)\n * @returns This instance for chaining\n *\n * @example\n * ```typescript\n * await file.format(\"webp\").save(\"images\");\n * await file.resize(800).format(\"avif\").quality(80).save(\"optimized\");\n * ```\n */\n public format(format: ImageFormat): this {\n this._imageOptions.format = format;\n return this;\n }\n\n /**\n * Rotate the image\n *\n * @param degrees - Rotation angle in degrees (positive = clockwise)\n * @returns This instance for chaining\n *\n * @example\n * ```typescript\n * await file.rotate(90).save(\"rotated\");\n * ```\n */\n public rotate(degrees: number): this {\n this._imageOptions.rotate = degrees;\n return this;\n }\n\n /**\n * Apply blur effect to the image\n *\n * @param sigma - Blur intensity (default: 3, minimum: 0.3)\n * @returns This instance for chaining\n *\n * @example\n * ```typescript\n * await file.blur(5).save(\"blurred\");\n * ```\n */\n public blur(sigma = 3): this {\n if (sigma < 0.3) {\n throw new Error(\"Blur sigma must be at least 0.3\");\n }\n this._imageOptions.blur = sigma;\n return this;\n }\n\n /**\n * Convert image to grayscale (black and white)\n *\n * @returns This instance for chaining\n *\n * @example\n * ```typescript\n * await file.grayscale().save(\"bw-images\");\n * ```\n */\n public grayscale(): this {\n this._imageOptions.grayscale = true;\n return this;\n }\n\n // ============================================================\n // Full Transform Control\n // ============================================================\n\n /**\n * Apply full image transformations\n *\n * Provides complete control over image processing. Can be used with:\n * - An options object for predefined transforms\n * - A callback function for chained operations\n *\n * @param config - Transform options or callback function\n * @returns This instance for chaining\n *\n * @example\n * ```typescript\n * // Using options object\n * await file.transform({\n * resize: { width: 800, fit: \"inside\" },\n * quality: 85\n * }).save(\"images\");\n *\n * // Using callback for full control\n * await file.transform(img =>\n * img.resize({ width: 800 })\n * .watermark(\"logo.png\", { gravity: \"southeast\" })\n * .sharpen()\n * ).save(\"products\");\n * ```\n */\n public transform(config: ImageTransformOptions | ImageTransformCallback): this {\n this._transformConfig = config;\n return this;\n }\n\n /**\n * Get an Image instance for advanced manipulation\n *\n * Returns an Image instance from the file buffer for manual processing.\n * Use this when you need operations not covered by the fluent API.\n *\n * @returns Promise resolving to Image instance\n *\n * @example\n * ```typescript\n * const img = await file.toImage();\n * await img\n * .resize({ width: 800 })\n * .watermark(\"logo.png\", { gravity: \"southeast\" })\n * .save(\"path/to/output.jpg\");\n * ```\n */\n public async toImage(): Promise<Image> {\n return new Image(await this.buffer());\n }\n\n // ============================================================\n // Image Metadata\n // ============================================================\n\n /**\n * Get file width and height (only for images)\n *\n * @returns Dimensions object, or empty object if not an image\n */\n public async dimensions(): Promise<{ width?: number; height?: number }> {\n if (!this.isImage) {\n return {};\n }\n\n return new Image(await this.buffer()).dimensions();\n }\n\n // ============================================================\n // Validation\n // ============================================================\n\n /**\n * Validate file against the given options\n *\n * @param options - Validation rules\n * @throws Error if validation fails\n *\n * @example\n * ```typescript\n * await file.validate({\n * allowedMimeTypes: [\"image/jpeg\", \"image/png\"],\n * maxSize: 5 * 1024 * 1024 // 5MB\n * });\n * ```\n */\n public async validate(options: FileValidationOptions): Promise<void> {\n const { allowedMimeTypes, allowedExtensions, maxSize } = options;\n\n if (allowedMimeTypes && !allowedMimeTypes.includes(this.mimeType)) {\n throw new Error(\n `Invalid file type: ${this.mimeType}. Allowed types: ${allowedMimeTypes.join(\", \")}`,\n );\n }\n\n if (allowedExtensions && !allowedExtensions.includes(this.extension)) {\n throw new Error(\n `Invalid file extension: ${this.extension}. Allowed extensions: ${allowedExtensions.join(\", \")}`,\n );\n }\n\n if (maxSize) {\n const fileSize = await this.size();\n if (fileSize > maxSize) {\n throw new Error(`File too large: ${fileSize} bytes. Maximum allowed: ${maxSize} bytes`);\n }\n }\n }\n\n // ============================================================\n // Save Operations\n // ============================================================\n\n /**\n * Save the file to a directory with automatic naming\n * Keep in mind to use only relative path to the root of storage\n * If you are using local driver\n * Uses the configured naming strategy and prefix options to generate\n * the final path. Returns a StorageFile for accessing file metadata.\n *\n * @param directory - Target directory path\n * @param options - Save options (name, prefix, driver, validate)\n * @returns StorageFile instance with file metadata and operations\n *\n * @example\n * ```typescript\n * // Random name (default)\n * await file.save(\"avatars\");\n * // → avatars/x7k9m2p4.jpg\n *\n * // Original name\n * await file.save(\"avatars\", { name: \"original\" });\n * // → avatars/photo.jpg\n *\n * // With date directory\n * await file.save(\"avatars\", {\n * prefix: { format: \"yyyy/mm/dd\", as: \"directory\" }\n * });\n * // → avatars/2025/12/21/x7k9m2p4.jpg\n *\n * // Original name with datetime prefix\n * await file.save(\"avatars\", { name: \"original\", prefix: true });\n * // → avatars/21-12-2025-16-45-30-photo.jpg\n * ```\n */\n public async save(directory: string, options?: SaveOptions): Promise<StorageFile> {\n // Validate if requested\n if (options?.validate) {\n await this.validate(options.validate);\n }\n\n // Resolve filename and prefix\n const filename = this.resolveFilename(options);\n const prefix = this.resolvePrefix(options?.prefix);\n const location = this.buildLocation(directory, prefix, filename);\n\n return this.saveToLocation(location, options?.driver);\n }\n\n /**\n * Save the file to an explicit path\n *\n * Unlike `save()`, this method uses the exact path you provide.\n * No automatic naming or prefix is applied.\n *\n * @param location - Full file path (directory + filename)\n * @param options - Save options (driver, validate)\n * @returns StorageFile instance with file metadata\n *\n * @example\n * ```typescript\n * await file.saveAs(\"avatars/profile-123.png\");\n * await file.saveAs(\"products/2025/featured-image.webp\");\n * ```\n */\n public async saveAs(location: string, options?: SaveAsOptions): Promise<StorageFile> {\n // Validate if requested\n if (options?.validate) {\n await this.validate(options.validate);\n }\n\n return this.saveToLocation(location, options?.driver);\n }\n\n /**\n * Get the StorageFile reference if file has been saved\n *\n * Returns undefined if file hasn't been saved yet.\n */\n public get storageFile(): StorageFile | undefined {\n return this._storageFile;\n }\n\n // ============================================================\n // Internal Helpers\n // ============================================================\n\n /**\n * Execute save to the specified location\n * @internal\n */\n protected async saveToLocation(\n location: string,\n driver?: StorageDriverName,\n ): Promise<StorageFile> {\n // Get file content (apply transforms if image)\n const content = await this.getProcessedContent();\n\n // Select storage\n const storageInstance = this.resolveStorage(driver);\n\n // Determine final location (adjust extension if format changed)\n const finalLocation = this.adjustLocationForFormat(location);\n\n // Save to storage\n this._storageFile = await storageInstance.put(content, finalLocation, {\n mimeType: this.getFinalMimeType(),\n });\n\n // Store hash from StorageFile\n const info = await this._storageFile.data();\n this.hash = info.hash || \"\";\n\n return this._storageFile;\n }\n\n /**\n * Get processed content (with transforms applied if applicable)\n * @internal\n */\n protected async getProcessedContent(): Promise<Buffer> {\n const content = await this.buffer();\n\n // If not an image or no transforms, return as-is\n if (!this.isImage || !this.hasTransforms()) {\n return content;\n }\n\n // Create Image and apply transforms\n let img = new Image(content);\n\n // Apply transform callback or options\n if (typeof this._transformConfig === \"function\") {\n img = this._transformConfig(img);\n } else if (this._transformConfig) {\n img = img.apply(this._transformConfig);\n }\n\n // Apply high-level options on top\n img = this.applyImageOptions(img);\n\n return img.toBuffer();\n }\n\n /**\n * Apply high-level image options\n * @internal\n */\n protected applyImageOptions(img: Image): Image {\n const opts = this._imageOptions;\n\n if (opts.resize) {\n img = img.resize({ width: opts.resize.width, height: opts.resize.height });\n }\n\n if (opts.rotate !== undefined) {\n img = img.rotate(opts.rotate);\n }\n\n if (opts.blur !== undefined) {\n img = img.blur(opts.blur);\n }\n\n if (opts.grayscale) {\n img = img.grayscale();\n }\n\n if (opts.quality !== undefined) {\n img = img.quality(opts.quality);\n }\n\n if (opts.format) {\n img = img.format(opts.format);\n }\n\n return img;\n }\n\n /**\n * Check if any transforms are queued\n * @internal\n */\n protected hasTransforms(): boolean {\n return this._transformConfig !== undefined || Object.keys(this._imageOptions).length > 0;\n }\n\n /**\n * Resolve storage instance to use\n * @internal\n */\n protected resolveStorage(driver?: StorageDriverName): ScopedStorage | typeof storage {\n if (driver) {\n return storage.use(driver) as ScopedStorage;\n }\n\n return this._storage || storage;\n }\n\n /**\n * Resolve the filename based on options and config\n * @internal\n */\n protected resolveFilename(options?: SaveOptions): string {\n const namingStrategy: FileNamingStrategy = options?.name ?? uploadsConfig(\"name\") ?? \"random\";\n let baseName: string;\n\n if (namingStrategy === \"original\") {\n baseName = path.basename(this.name, path.extname(this.name));\n } else if (namingStrategy === \"random\") {\n const length = uploadsConfig(\"randomLength\");\n baseName = Random.string(length);\n } else {\n // Custom name - strip extension if provided, we'll add it\n baseName = path.basename(namingStrategy, path.extname(namingStrategy));\n }\n\n // Get extension (may be changed by format transform)\n const ext = this.getFinalExtension();\n\n return `${baseName}.${ext}`;\n }\n\n /**\n * Resolve prefix based on options and config\n * @internal\n */\n protected resolvePrefix(prefix?: PrefixConfig): string {\n // No prefix\n if (prefix === false || prefix === undefined) {\n const configPrefix = uploadsConfig(\"prefix\");\n if (!configPrefix) {\n return \"\";\n }\n // Use config prefix if no explicit prefix provided\n prefix = configPrefix;\n }\n\n // Boolean true = use default format\n if (prefix === true) {\n const format = uploadsConfig(\"defaultPrefixFormat\")!;\n return this.formatDatePrefix(format, \"file\");\n }\n\n // String = static prefix\n if (typeof prefix === \"string\") {\n return prefix;\n }\n\n // PrefixOptions object\n const parts: string[] = [];\n\n // Add date format if specified\n if (prefix.format) {\n parts.push(this.formatDate(prefix.format));\n }\n\n // Add random string if specified\n if (prefix.randomLength) {\n parts.push(Random.string(prefix.randomLength));\n }\n\n const combined = parts.join(\"-\");\n const as = prefix.as ?? \"file\";\n\n if (as === \"directory\") {\n return combined ? `${combined}/` : \"\";\n }\n\n return combined ? `${combined}-` : \"\";\n }\n\n /**\n * Format a date prefix with the given format\n * @internal\n */\n protected formatDatePrefix(format: string, as: \"file\" | \"directory\"): string {\n const formatted = this.formatDate(format);\n return as === \"directory\" ? `${formatted}/` : `${formatted}-`;\n }\n\n /**\n * Format current date using token-based format string\n * @internal\n */\n protected formatDate(format: string): string {\n return dayjs().format(format);\n }\n\n /**\n * Build final location from directory, prefix, and filename\n * @internal\n */\n protected buildLocation(directory: string, prefix: string, filename: string): string {\n // Clean up directory (remove trailing slash)\n const dir = directory.replace(/\\/$/, \"\");\n\n // If prefix ends with /, it's a directory\n if (prefix.endsWith(\"/\")) {\n return `${dir}/${prefix}${filename}`;\n }\n\n // Otherwise prefix is part of filename\n return `${dir}/${prefix}${filename}`;\n }\n\n /**\n * Get final extension (accounting for format changes)\n * @internal\n */\n protected getFinalExtension(): string {\n if (this._imageOptions.format) {\n // Map formats to extensions\n const format = this._imageOptions.format;\n\n if (format === \"jpeg\") return \"jpg\";\n\n return format;\n }\n\n return this.extension;\n }\n\n /**\n * Get final MIME type (accounting for format changes)\n * @internal\n */\n protected getFinalMimeType(): string {\n if (this._imageOptions.format) {\n const format = this._imageOptions.format;\n\n if (format === \"jpeg\" || format === \"jpg\") return \"image/jpeg\";\n\n return `image/${format}`;\n }\n\n return this.mimeType;\n }\n\n /**\n * Adjust location to use correct extension if format changed\n * @internal\n */\n protected adjustLocationForFormat(location: string): string {\n if (!this._imageOptions.format) {\n return location;\n }\n\n const ext = this.getFinalExtension();\n const currentExt = path.extname(location);\n\n if (currentExt) {\n return location.replace(currentExt, `.${ext}`);\n }\n\n return `${location}.${ext}`;\n }\n\n // ============================================================\n // Serialization\n // ============================================================\n\n /**\n * Convert to JSON representation.\n *\n * **Synchronous, and that is the whole point.** `toJSON` is not an ordinary\n * method name — it is the hook `JSON.stringify` calls, and `JSON.stringify`\n * does not await. While this was `async`, every implicit serialization of an\n * upload produced `{}`: no base64, no size, not even the filename.\n *\n * Two call sites in core awaited it and worked (`http/response.ts:304`,\n * `utils/to-json.ts:9`). The ones that could not were the ones that mattered:\n * `cascade`'s model serializer calls `toJSON()` without awaiting, and\n * `Resource.toJSON()` is itself synchronous. Those paths were silently\n * broken. See canon `cd60b894`.\n *\n * **What is NOT here, and why.** `base64` forced the async — `buffer()` is\n * async — and it also put the entire file, inflated by a third, into any\n * response that happened to carry an upload. It is opt-in now via\n * {@link UploadedFile.toBase64}. `dimensions` costs an image decode; ask for\n * it with {@link UploadedFile.dimensions} when you want it.\n *\n * `size` is reported **only when the file has already been read**. Reading it\n * here would make the method async again, and guessing would be worse than\n * omitting: a wrong number is believed, an absent one is asked about. In\n * practice validation or `save()` has usually buffered the file long before\n * anything serializes it.\n */\n public toJSON(): UploadedFileJson {\n return {\n name: this.name,\n mimeType: this.mimeType,\n extension: this.extension,\n isImage: this.isImage,\n isVideo: this.isVideo,\n isAudio: this.isAudio,\n size: this.bufferedFileContent?.length,\n };\n }\n\n /**\n * The file's contents as base64.\n *\n * Explicit because it is expensive: it reads the whole file into memory and\n * grows it by a third. This used to happen on every serialization.\n */\n public async toBase64(): Promise<string> {\n return (await this.buffer()).toString(\"base64\");\n }\n}\n"],"mappings":"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"}
|
package/esm/index.d.mts
CHANGED
|
@@ -1,4 +1,3 @@
|
|
|
1
|
-
import { ClosableServer, FastifyInstance, closeServerWithTimeout, getHttpServer, startHttpServer } from "./http/server.mjs";
|
|
2
1
|
import { StorageFile } from "./storage/storage-file.mjs";
|
|
3
2
|
import { CloudStorageDriverContract, CloudStorageDriverOptions, CloudStorageFileData, DeleteManyResult, EventSubscription, FileVisibility, ListOptions, LocalStorageDriverOptions, PresignedOptions, PresignedUploadOptions, PutDirectoryOptions, PutDirectoryResult, PutFromUrlOptions, PutOptions, R2StorageDriverOptions, ScopedStorageContract, StorageConfigurations, StorageCopyEventPayload, StorageDriverConfig, StorageDriverContract, StorageDriverName, StorageDriverRegistry, StorageDriverType, StorageEventHandler, StorageEventPayload, StorageEventType, StorageFileData, StorageFileInfo, StorageManagerContract, StoragePutEventPayload, TemporaryTokenError, TemporaryTokenPayload, TemporaryTokenValidation } from "./storage/types.mjs";
|
|
4
3
|
import { storageConfig, storageConfigurations } from "./storage/config.mjs";
|
|
@@ -16,10 +15,10 @@ import { R2Driver } from "./storage/drivers/r2-driver.mjs";
|
|
|
16
15
|
import { S3Driver } from "./storage/drivers/s3-driver.mjs";
|
|
17
16
|
import { Image, ImageFormat, ImageInput, ImageTransformOptions, WatermarkConfig } from "./image/image.mjs";
|
|
18
17
|
import { FileNamingStrategy, ImageTransformCallback, ImageTransformConfig, PrefixConfig, PrefixOptions, SaveAsOptions, SaveOptions, UploadedFileImageOptions, UploadsConfigurations } from "./http/uploads-types.mjs";
|
|
19
|
-
import { FileValidationOptions, UploadedFile } from "./http/uploaded-file.mjs";
|
|
18
|
+
import { FileValidationOptions, UploadedFile, UploadedFileJson } from "./http/uploaded-file.mjs";
|
|
20
19
|
import { Request } from "./http/request.mjs";
|
|
21
20
|
import { CookieOptions, Response, ResponseStatus, SendBufferOptions, SendFileOptions } from "./http/response.mjs";
|
|
22
|
-
import { HttpConfigurations, PartialMiddleware, RequestEvent, ResponseEvent, ResponseSSEController, ResponseStreamController, ReturnedResponse } from "./http/types.mjs";
|
|
21
|
+
import { HttpConfigurations, PartialMiddleware, RequestEvent, RequestLocals, RequestUser, ResponseEvent, ResponseSSEController, ResponseStreamController, ReturnedResponse } from "./http/types.mjs";
|
|
23
22
|
import { defaultHttpConfigurations, httpConfig } from "./http/config.mjs";
|
|
24
23
|
import { createHttpApplication, stopHttpApplication } from "./http/createHttpApplication.mjs";
|
|
25
24
|
import { RequestLog } from "./http/database/RequestLog.mjs";
|
|
@@ -36,22 +35,26 @@ import { IpFilterOptions } from "./http/middleware/ip-filter.middleware.mjs";
|
|
|
36
35
|
import { MaintenanceOptions } from "./http/middleware/maintenance.middleware.mjs";
|
|
37
36
|
import { RateLimitOptions } from "./http/middleware/rate-limit.middleware.mjs";
|
|
38
37
|
import { middleware } from "./http/middleware/middleware-list.mjs";
|
|
39
|
-
import { createRequestStore,
|
|
38
|
+
import { createRequestStore, t } from "./http/middleware/inject-request-context.mjs";
|
|
40
39
|
import { anyMatch, ipMatches } from "./http/middleware/utils/cidr-match.mjs";
|
|
41
40
|
import { buildIdempotencyCacheKey, hashBody, isValidIdempotencyKey } from "./http/middleware/utils/idempotency-key.mjs";
|
|
42
41
|
import { parseSize } from "./http/middleware/utils/parse-size.mjs";
|
|
42
|
+
import { ClosableServer, FastifyInstance, closeServerWithTimeout, getHttpServer, startHttpServer } from "./http/server.mjs";
|
|
43
43
|
import { registerHttpPlugins } from "./http/plugins.mjs";
|
|
44
44
|
import { PortInUseError, assertPortIsAvailable, isPortAvailable } from "./http/port-preflight.mjs";
|
|
45
45
|
import { RequestContextStore, requestContext, useCurrentUser, useRequest, useRequestStore } from "./http/context/request-context.mjs";
|
|
46
|
+
import { requestMemo } from "./http/context/request-memo.mjs";
|
|
46
47
|
import { LocalizedObject, getLocalized } from "./utils/get-localized.mjs";
|
|
47
48
|
import { ResourceFieldBuilder } from "./resource/resource-field-builder.mjs";
|
|
48
49
|
import { Resource, ResourceConstructor, ResourceContract } from "./resource/resource.mjs";
|
|
49
50
|
import { ResourceArraySchema, ResourceCastType, ResourceFieldBuilderDateOutputOptions, ResourceFieldConfig, ResourceOutputValueCastType, ResourceSchema, ResourceSelfReference, ResponseBodyValue, ResponseSchema } from "./resource/types.mjs";
|
|
50
|
-
import { GroupedRoutesOptions, Middleware, MiddlewareResponse, PartialPick, RequestControllerContract, RequestHandler, RequestHandlerType, RequestHandlerValidation, RequestMethod, ResourceMethod, RestfulMiddleware, Route, RouteOptions, RouteResource, RouterGroupCallback, RouterStacks } from "./router/types.mjs";
|
|
51
|
+
import { GroupedRoutesOptions, HttpContext, Middleware, MiddlewareResponse, PartialPick, RequestControllerContract, RequestHandler, RequestHandlerType, RequestHandlerValidation, RequestMethod, ResourceMethod, RestfulMiddleware, Route, RouteOptions, RouteResource, RouterGroupCallback, RouterStacks } from "./router/types.mjs";
|
|
52
|
+
import { PositionalHandlerSuspect, clearPositionalHandlerSuspects, describePositionalHandlerSuspect, forgetPositionalHandlerSuspects, inspectHandlerSignature, listPositionalHandlerSuspects, looksLikePositionalHandler, reportPositionalHandlerSuspects } from "./router/positional-handler-diagnostics.mjs";
|
|
53
|
+
import { RouteRegistry } from "./router/route-registry.mjs";
|
|
51
54
|
import { Router, router } from "./router/router.mjs";
|
|
52
55
|
import { app } from "./application/app.mjs";
|
|
53
56
|
import { Environment, RuntimeStrategy, environment, setEnvironment } from "./utils/environment.mjs";
|
|
54
|
-
import { Application, BootContext, BootListener, ShutdownListener } from "./application/application.mjs";
|
|
57
|
+
import { Application, BootContext, BootListener, BootValidator, ShutdownListener } from "./application/application.mjs";
|
|
55
58
|
import { BOOT_SIGNAL_ENV_KEY, BOOT_SIGNAL_VERSION, BootSignal, BootSignalType, isBootSignal, sendBootSignal } from "./application/boot-signal.mjs";
|
|
56
59
|
import { AppConfigurations } from "./application/application-config-types.mjs";
|
|
57
60
|
import { BenchmarkSnapshots } from "./benchmark/benchmark-snapshots.mjs";
|
|
@@ -68,10 +71,13 @@ import { config } from "./config/config-getter.mjs";
|
|
|
68
71
|
import { registerAppConfig } from "./config/config-handlers.mjs";
|
|
69
72
|
import { setConfig } from "./config/config-setter.mjs";
|
|
70
73
|
import { ConfigSpecialHandlers, configSpecialHandlers } from "./config/config-special-handlers.mjs";
|
|
71
|
-
import {
|
|
74
|
+
import { WarlockConfig } from "./warlock-config/types.mjs";
|
|
75
|
+
import { Connector, ConnectorBuildContext, ConnectorBuildContribution, ConnectorBuildGenerateResult, ConnectorEsbuildPatch, ConnectorLifecyclePhase, ConnectorName, ConnectorPriority } from "./connectors/types.mjs";
|
|
72
76
|
import { BaseConnector } from "./connectors/base-connector.mjs";
|
|
73
77
|
import { AccessConnector } from "./connectors/access-connector.mjs";
|
|
74
78
|
import { AiConnector } from "./connectors/ai-connector.mjs";
|
|
79
|
+
import { assertNoReservedConnectorNames } from "./connectors/assert-no-reserved-connector-names.mjs";
|
|
80
|
+
import { assertUniqueConnectorNames } from "./connectors/assert-unique-connector-names.mjs";
|
|
75
81
|
import { CacheConnector } from "./connectors/cache-connector.mjs";
|
|
76
82
|
import { HeraldConnector } from "./connectors/herald-connector.mjs";
|
|
77
83
|
import { ConnectorsManager, connectorsManager } from "./connectors/connectors-manager.mjs";
|
|
@@ -80,6 +86,7 @@ import { HttpConnector } from "./connectors/http-connector.mjs";
|
|
|
80
86
|
import { LoggerConnector } from "./connectors/logger-connector.mjs";
|
|
81
87
|
import { MailerConnector } from "./connectors/mail-connector.mjs";
|
|
82
88
|
import { NotificationsConnector } from "./connectors/notifications-connector.mjs";
|
|
89
|
+
import { RegisterConfiguredConnectorsOptions, registerConfiguredConnectors } from "./connectors/register-configured-connectors.mjs";
|
|
83
90
|
import { SocketConnector } from "./connectors/socket-connector.mjs";
|
|
84
91
|
import { StorageConnector } from "./connectors/storage.connector.mjs";
|
|
85
92
|
import { CLICommandAction, CLICommandOption, CLICommandOptions, CLICommandPreload, CLICommandSource, CommandActionData, ResolvedCLICommandOption } from "./commands/types.mjs";
|
|
@@ -143,13 +150,14 @@ import { uniqueExceptCurrentUserRule } from "./validation/database/unique-except
|
|
|
143
150
|
import { FileValidator, uploadedFileMetadataSchema } from "./validation/validators/file-validator.mjs";
|
|
144
151
|
import { ValidationConfiguration } from "./validation/types.mjs";
|
|
145
152
|
import { fileExtensionRule, fileRule, fileTypeRule, imageRule } from "./validation/file/file.mjs";
|
|
146
|
-
import { WarlockConfig } from "./warlock-config/types.mjs";
|
|
147
153
|
import { defineConfig } from "./warlock-config/define-config.mjs";
|
|
148
154
|
import { WarlockConfigManager, isUnknownTsExtensionError, warlockConfigManager } from "./warlock-config/warlock-config.manager.mjs";
|
|
149
155
|
import { env } from "@mongez/dotenv";
|
|
150
156
|
import { colors } from "@mongez/copper";
|
|
151
157
|
export * from "@mongez/localization";
|
|
152
|
-
export { $registerUseCase, $unregisterUseCase, AccessConnector, AggregateExpressionInput, AggregateExpressions, AiConnector, AllRepositoryOptions, AppConfigurations, Application, BOOT_SIGNAL_ENV_KEY, BOOT_SIGNAL_VERSION, BadRequestError, BadSchemaUseCaseError, BaseConnector, type BenchmarkChannel, type BenchmarkConfigurations, type BenchmarkErrorResult, type BenchmarkOptions, BenchmarkProfiler, type BenchmarkProfilerOptions, type BenchmarkResult, BenchmarkSnapshots, type BenchmarkSnapshotsOptions, type BenchmarkStats, type BenchmarkSuccessResult, BootContext, BootListener, BootSignal, BootSignalType, CLICommand, type CLICommandAction, type CLICommandOption, type CLICommandOptions, type CLICommandPreload, type CLICommandSource, CacheConnector, type CacheMiddlewareOptions, CachedRepositoryOptions, type CapturedMail, CascadeAdapter, CascadeQueryBuilder, ChunkCallback, ClosableServer, CloudDriver, CloudStorageDriverContract, CloudStorageDriverOptions, CloudStorageFileData, type CommandActionData, type ConcurrencyLimitOptions, ConfigKey, ConfigKeyRegistry, ConfigName, ConfigRegistry, ConfigSpecialHandlers, ConflictError, Connector, ConnectorLifecyclePhase, ConnectorName, ConnectorPriority, ConnectorsManager, ConsoleChannel, ContainerTypes, CookieOptions, CursorPaginationOptions, CursorPaginationResult, DOSpacesDriver, DatabaseCacheDriver, type DatabaseCacheOptions, DatabaseConnector, DatabaseLog, DatabaseLogModel, DatabaseLogOptions, DefineResourceOptions, DeleteManyResult, EncryptionConfigurations, EncryptionPasswordConfigurations, Environment, EventSubscription, ExistsExceptCurrentIdRuleOptions, ExistsExceptCurrentUserRuleOptions, FastifyInstance, FileNamingStrategy, FileValidationOptions, FileValidator, FileVisibility, FilterFunction, FilterOperator, FilterOptions, FilterRule, FilterRules, ForbiddenError, GroupByFields, GroupedRoutesOptions, HealthCheck, HealthStatus, HeraldConnector, HttpConfigurations, HttpConnector, HttpError, HttpErrorCodes, type IdempotencyOptions, Image, ImageFormat, ImageInput, ImageTransformCallback, ImageTransformConfig, ImageTransformOptions, type IpFilterOptions, ListOptions, LocalDriver, LocalStorageDriverOptions, LocalizedObject, LogConfigurations, LoggerConnector, MAIL_EVENTS, Mail, type MailAddress, type MailAttachment, type MailConfigurations, MailError, type MailErrorCode, type MailEvents, type MailMode, type MailOptions, type MailPriority, type MailResult, MailerConnector, type MailersConfig, type MaintenanceOptions, Middleware, MiddlewareResponse, MimeTypes, NoopChannel, type NormalizedMail, NotAcceptableError, NotAllowedError, NotificationsConnector, PaginationMode, PaginationResult, PartialMiddleware, PartialPick, Path, PipelineOptions, PortInUseError, PrefixConfig, PrefixOptions, PresignedOptions, PresignedUploadOptions, PutDirectoryOptions, PutDirectoryResult, PutFromUrlOptions, PutOptions, QueryBuilderContract, Queue, R2Driver, R2StorageDriverOptions, type RateLimitOptions, RegisterResource, RegisteredUseCase, RepositoryAdapterContract, RepositoryConfigurations, RepositoryEvent, RepositoryManager, RepositoryOptions, RepositoryOptionsWithCursor, RepositoryOptionsWithPages, Request, RequestContextStore, RequestController, RequestControllerContract, RequestEvent, RequestHandler, RequestHandlerType, RequestHandlerValidation, RequestLog, RequestMethod, type ResolvedCLICommandOption, Resource, ResourceArraySchema, ResourceCastType, ResourceConstructor, ResourceContract, ResourceFieldBuilder, ResourceFieldBuilderDateOutputOptions, ResourceFieldConfig, ResourceMethod, ResourceNotFoundError, ResourceOutputValueCastType, ResourceSchema, ResourceSelfReference, Response, ResponseBodyValue, ResponseEvent, ResponseSSEController, ResponseSchema, ResponseStatus, ResponseStreamController, Restful, RestfulMiddleware, ReturnedResponse, Route, RouteOptions, RouteResource, Router, RouterGroupCallback, RouterStacks, RuntimeStrategy, S3Driver, type SESConfigurations, type SMTPConfigurations, SafeFetchOptions, SafeFetchResult, SaveAsOptions, SaveMode, SaveOptions, ScopedStorage, ScopedStorageContract, SeedClock, SeedContext, SeedRecordRef, SeedResult, Seeder, SeederDependencyCycleError, SeederMetadata, SendBufferOptions, SendFileOptions, ServerError, ShutdownListener, SocketConnector, SocketOptions, Storage, StorageConfigurations, StorageConnector, StorageCopyEventPayload, StorageDriverConfig, StorageDriverContextStore, StorageDriverContract, StorageDriverName, StorageDriverRegistry, StorageDriverType, StorageError, StorageErrorOptions, StorageEventHandler, StorageEventPayload, StorageEventType, StorageFile, StorageFileData, StorageFileInfo, StorageManagerContract, StoragePutEventPayload, TemporaryTokenError, TemporaryTokenPayload, TemporaryTokenValidation, Track, TrackableModel, TypedAllRepositoryOptions, TypedRepositoryOptions, TypedRepositoryOptionsWithCursor, TypedRepositoryOptionsWithPages, UPLOADS_DEFAULTS, UnAuthorizedError, UniqueExceptCurrentIdRuleOptions, UniqueExceptCurrentUserRuleOptions, UnknownSeederDependencyError, UploadedFile, UploadedFileImageOptions, UploadsConfigurations, UseCase, UseCaseAfterMiddleware, UseCaseBeforeMiddleware, UseCaseBroadcastChannel, UseCaseBroadcastEvent, UseCaseBroadcastOption, UseCaseConfigurations, UseCaseContext, UseCaseErrorResult, UseCaseEventsCallbacksMap, UseCaseGuard, UseCaseHandler, UseCaseOnExecutingContext, UseCaseResult, UseCaseRuntimeOptions, UseCaseWithSchema, ValidationConfiguration, WarlockConfig, WarlockConfigManager, WatermarkConfig, WhereOperator, addUseCaseHistory, anyMatch, app, appLog, appPath, assertMailCount, assertMailSent, assertPortIsAvailable, assetsUrl, bootstrap, broadcastUseCaseResult, buildIdempotencyCacheKey, cachePath, captureMail, clearTestMailbox, closeAllMailers, closeMailer, closeServerWithTimeout, colors, command, config, configPath, configSpecialHandlers, connectorsManager, container, createHttpApplication, createRequestStore, decrypt, defaultHttpConfigurations, defineConfig, defineResource, displayEnvironmentMode, encrypt, env, environment, existsExceptCurrentIdRule, existsExceptCurrentUserRule, fetchLatestVersion, fileExtensionRule, fileRule, fileTypeRule, findMailsBySubject, findMailsTo, fireLifecycleEvent,
|
|
158
|
+
export { $registerUseCase, $unregisterUseCase, AccessConnector, AggregateExpressionInput, AggregateExpressions, AiConnector, AllRepositoryOptions, AppConfigurations, Application, BOOT_SIGNAL_ENV_KEY, BOOT_SIGNAL_VERSION, BadRequestError, BadSchemaUseCaseError, BaseConnector, type BenchmarkChannel, type BenchmarkConfigurations, type BenchmarkErrorResult, type BenchmarkOptions, BenchmarkProfiler, type BenchmarkProfilerOptions, type BenchmarkResult, BenchmarkSnapshots, type BenchmarkSnapshotsOptions, type BenchmarkStats, type BenchmarkSuccessResult, BootContext, BootListener, BootSignal, BootSignalType, BootValidator, CLICommand, type CLICommandAction, type CLICommandOption, type CLICommandOptions, type CLICommandPreload, type CLICommandSource, CacheConnector, type CacheMiddlewareOptions, CachedRepositoryOptions, type CapturedMail, CascadeAdapter, CascadeQueryBuilder, ChunkCallback, ClosableServer, CloudDriver, CloudStorageDriverContract, CloudStorageDriverOptions, CloudStorageFileData, type CommandActionData, type ConcurrencyLimitOptions, ConfigKey, ConfigKeyRegistry, ConfigName, ConfigRegistry, ConfigSpecialHandlers, ConflictError, Connector, ConnectorBuildContext, ConnectorBuildContribution, ConnectorBuildGenerateResult, ConnectorEsbuildPatch, ConnectorLifecyclePhase, ConnectorName, ConnectorPriority, ConnectorsManager, ConsoleChannel, ContainerTypes, CookieOptions, CursorPaginationOptions, CursorPaginationResult, DOSpacesDriver, DatabaseCacheDriver, type DatabaseCacheOptions, DatabaseConnector, DatabaseLog, DatabaseLogModel, DatabaseLogOptions, DefineResourceOptions, DeleteManyResult, EncryptionConfigurations, EncryptionPasswordConfigurations, Environment, EventSubscription, ExistsExceptCurrentIdRuleOptions, ExistsExceptCurrentUserRuleOptions, FastifyInstance, FileNamingStrategy, FileValidationOptions, FileValidator, FileVisibility, FilterFunction, FilterOperator, FilterOptions, FilterRule, FilterRules, ForbiddenError, GroupByFields, GroupedRoutesOptions, HealthCheck, HealthStatus, HeraldConnector, HttpConfigurations, HttpConnector, HttpContext, HttpError, HttpErrorCodes, type IdempotencyOptions, Image, ImageFormat, ImageInput, ImageTransformCallback, ImageTransformConfig, ImageTransformOptions, type IpFilterOptions, ListOptions, LocalDriver, LocalStorageDriverOptions, LocalizedObject, LogConfigurations, LoggerConnector, MAIL_EVENTS, Mail, type MailAddress, type MailAttachment, type MailConfigurations, MailError, type MailErrorCode, type MailEvents, type MailMode, type MailOptions, type MailPriority, type MailResult, MailerConnector, type MailersConfig, type MaintenanceOptions, Middleware, MiddlewareResponse, MimeTypes, NoopChannel, type NormalizedMail, NotAcceptableError, NotAllowedError, NotificationsConnector, PaginationMode, PaginationResult, PartialMiddleware, PartialPick, Path, PipelineOptions, PortInUseError, PositionalHandlerSuspect, PrefixConfig, PrefixOptions, PresignedOptions, PresignedUploadOptions, PutDirectoryOptions, PutDirectoryResult, PutFromUrlOptions, PutOptions, QueryBuilderContract, Queue, R2Driver, R2StorageDriverOptions, type RateLimitOptions, RegisterConfiguredConnectorsOptions, RegisterResource, RegisteredUseCase, RepositoryAdapterContract, RepositoryConfigurations, RepositoryEvent, RepositoryManager, RepositoryOptions, RepositoryOptionsWithCursor, RepositoryOptionsWithPages, Request, RequestContextStore, RequestController, RequestControllerContract, RequestEvent, RequestHandler, RequestHandlerType, RequestHandlerValidation, RequestLocals, RequestLog, RequestMethod, RequestUser, type ResolvedCLICommandOption, Resource, ResourceArraySchema, ResourceCastType, ResourceConstructor, ResourceContract, ResourceFieldBuilder, ResourceFieldBuilderDateOutputOptions, ResourceFieldConfig, ResourceMethod, ResourceNotFoundError, ResourceOutputValueCastType, ResourceSchema, ResourceSelfReference, Response, ResponseBodyValue, ResponseEvent, ResponseSSEController, ResponseSchema, ResponseStatus, ResponseStreamController, Restful, RestfulMiddleware, ReturnedResponse, Route, RouteOptions, RouteRegistry, RouteResource, Router, RouterGroupCallback, RouterStacks, RuntimeStrategy, S3Driver, type SESConfigurations, type SMTPConfigurations, SafeFetchOptions, SafeFetchResult, SaveAsOptions, SaveMode, SaveOptions, ScopedStorage, ScopedStorageContract, SeedClock, SeedContext, SeedRecordRef, SeedResult, Seeder, SeederDependencyCycleError, SeederMetadata, SendBufferOptions, SendFileOptions, ServerError, ShutdownListener, SocketConnector, SocketOptions, Storage, StorageConfigurations, StorageConnector, StorageCopyEventPayload, StorageDriverConfig, StorageDriverContextStore, StorageDriverContract, StorageDriverName, StorageDriverRegistry, StorageDriverType, StorageError, StorageErrorOptions, StorageEventHandler, StorageEventPayload, StorageEventType, StorageFile, StorageFileData, StorageFileInfo, StorageManagerContract, StoragePutEventPayload, TemporaryTokenError, TemporaryTokenPayload, TemporaryTokenValidation, Track, TrackableModel, TypedAllRepositoryOptions, TypedRepositoryOptions, TypedRepositoryOptionsWithCursor, TypedRepositoryOptionsWithPages, UPLOADS_DEFAULTS, UnAuthorizedError, UniqueExceptCurrentIdRuleOptions, UniqueExceptCurrentUserRuleOptions, UnknownSeederDependencyError, UploadedFile, UploadedFileImageOptions, UploadedFileJson, UploadsConfigurations, UseCase, UseCaseAfterMiddleware, UseCaseBeforeMiddleware, UseCaseBroadcastChannel, UseCaseBroadcastEvent, UseCaseBroadcastOption, UseCaseConfigurations, UseCaseContext, UseCaseErrorResult, UseCaseEventsCallbacksMap, UseCaseGuard, UseCaseHandler, UseCaseOnExecutingContext, UseCaseResult, UseCaseRuntimeOptions, UseCaseWithSchema, ValidationConfiguration, WarlockConfig, WarlockConfigManager, WatermarkConfig, WhereOperator, addUseCaseHistory, anyMatch, app, appLog, appPath, assertMailCount, assertMailSent, assertNoReservedConnectorNames, assertPortIsAvailable, assertUniqueConnectorNames, assetsUrl, bootstrap, broadcastUseCaseResult, buildIdempotencyCacheKey, cachePath, captureMail, clearPositionalHandlerSuspects, clearTestMailbox, closeAllMailers, closeMailer, closeServerWithTimeout, colors, command, config, configPath, configSpecialHandlers, connectorsManager, container, createHttpApplication, createRequestStore, decrypt, defaultHttpConfigurations, defineConfig, defineResource, describePositionalHandlerSuspect, displayEnvironmentMode, encrypt, env, environment, existsExceptCurrentIdRule, existsExceptCurrentUserRule, fetchLatestVersion, fileExtensionRule, fileRule, fileTypeRule, findMailsBySubject, findMailsTo, fireLifecycleEvent, forgetPositionalHandlerSuspects, generateMailId, getDefaultMailConfig, getHttpServer, getLastMail, getLocalized, getMailEventName, getMailMode, getMailboxSize, getMailer, getMailerConfig, getMimeType, getPoolStats, getSocketServer, getTestMailbox, getUseCase, getUseCaseHistory, getUseCases, globalEventsCallbacksMap, globalUseCasesEvents, hashBody, hashPassword, health, hmacHash, httpConfig, imageRule, increaseUseCaseFailedCalls, increaseUseCaseSuccessCalls, inspectHandlerSignature, ipMatches, isBootSignal, isDevelopmentMode, isNewerVersion, isPortAvailable, isPrivateOrReservedIp, isProductionMode, isTestMode, isUnknownTsExtensionError, isValidIdempotencyKey, listPositionalHandlerSuspects, loadS3, logResponse, logsPath, looksLikePositionalHandler, mailEvents, measure, middleware, parseSize, paths, promiseAllObject, publicPath, publicUrl, registerAppConfig, registerConfiguredConnectors, registerHttpPlugins, renderReact, renderReactMail, reportPositionalHandlerSuspects, requestContext, requestMemo, resetMailConfig, resolveMailConfig, resolveWithinRoot, rootPath, router, runPipeline, safeFetchToBuffer, sanitizePath, seeder, sendBootSignal, sendMail, setBaseUrl, setConfig, setEnvironment, setLogConfigurations, setMailConfigurations, setMailMode, sleep, sluggable, srcPath, startHttpServer, stopHttpApplication, storage, storageConfig, storageConfigurations, storageDriverContext, storagePath, t, tempPath, toJson, uniqueExceptCurrentIdRule, uniqueExceptCurrentUserRule, uploadedFileMetadataSchema, uploadsConfig, uploadsPath, uploadsUrl, url, useCase, useComputedModel, useComputedSlug, useCurrentUser, useHashedPassword, useRequest, useRequestStore, verifyMailer, verifyPassword, warlockConfigManager, warlockPath, wasMailSentTo, wasMailSentWithSubject, wrapResponseInDataKey };
|
|
153
159
|
import "./config/types.mjs";
|
|
160
|
+
import "./http/request.mjs";
|
|
161
|
+
import "./http/types.mjs";
|
|
154
162
|
import "./storage/types.mjs";
|
|
155
163
|
import "./validation/types.mjs";
|
package/esm/index.mjs
CHANGED
|
@@ -21,8 +21,10 @@ import { assetsUrl, publicUrl, setBaseUrl, uploadsUrl, url } from "./utils/urls.
|
|
|
21
21
|
import { isNewerVersion } from "./utils/version-compare.mjs";
|
|
22
22
|
import "./utils/index.mjs";
|
|
23
23
|
import { BadRequestError, ConflictError, ForbiddenError, HttpError, NotAcceptableError, NotAllowedError, ResourceNotFoundError, ServerError, UnAuthorizedError } from "./http/errors/errors.mjs";
|
|
24
|
-
import { createRequestStore,
|
|
24
|
+
import { createRequestStore, t } from "./http/middleware/inject-request-context.mjs";
|
|
25
25
|
import { defaultHttpConfigurations, httpConfig } from "./http/config.mjs";
|
|
26
|
+
import { clearPositionalHandlerSuspects, describePositionalHandlerSuspect, forgetPositionalHandlerSuspects, inspectHandlerSignature, listPositionalHandlerSuspects, looksLikePositionalHandler, reportPositionalHandlerSuspects } from "./router/positional-handler-diagnostics.mjs";
|
|
27
|
+
import { RouteRegistry } from "./router/route-registry.mjs";
|
|
26
28
|
import { container } from "./container/index.mjs";
|
|
27
29
|
import { BOOT_SIGNAL_ENV_KEY, BOOT_SIGNAL_VERSION, isBootSignal, sendBootSignal } from "./application/boot-signal.mjs";
|
|
28
30
|
import { Application } from "./application/application.mjs";
|
|
@@ -65,6 +67,7 @@ import { anyMatch, ipMatches } from "./http/middleware/utils/cidr-match.mjs";
|
|
|
65
67
|
import { parseSize } from "./http/middleware/utils/parse-size.mjs";
|
|
66
68
|
import { middleware } from "./http/middleware/middleware-list.mjs";
|
|
67
69
|
import { PortInUseError, assertPortIsAvailable, isPortAvailable } from "./http/port-preflight.mjs";
|
|
70
|
+
import { requestMemo } from "./http/context/request-memo.mjs";
|
|
68
71
|
import "./http/index.mjs";
|
|
69
72
|
import { existsExceptCurrentIdRule } from "./validation/database/exists-except-current-id.mjs";
|
|
70
73
|
import { existsExceptCurrentUserRule } from "./validation/database/exists-except-current-user.mjs";
|
|
@@ -89,8 +92,8 @@ import { BaseConnector } from "./connectors/base-connector.mjs";
|
|
|
89
92
|
import { AccessConnector } from "./connectors/access-connector.mjs";
|
|
90
93
|
import { AiConnector } from "./connectors/ai-connector.mjs";
|
|
91
94
|
import { CacheConnector } from "./connectors/cache-connector.mjs";
|
|
92
|
-
import { HeraldConnector } from "./connectors/herald-connector.mjs";
|
|
93
95
|
import { DatabaseConnector } from "./connectors/database-connector.mjs";
|
|
96
|
+
import { HeraldConnector } from "./connectors/herald-connector.mjs";
|
|
94
97
|
import { HttpConnector } from "./connectors/http-connector.mjs";
|
|
95
98
|
import { setLogConfigurations } from "./logger/logger.mjs";
|
|
96
99
|
import "./logger/index.mjs";
|
|
@@ -109,6 +112,10 @@ import { NotificationsConnector } from "./connectors/notifications-connector.mjs
|
|
|
109
112
|
import { SocketConnector } from "./connectors/socket-connector.mjs";
|
|
110
113
|
import { StorageConnector } from "./connectors/storage.connector.mjs";
|
|
111
114
|
import { ConnectorsManager, connectorsManager } from "./connectors/connectors-manager.mjs";
|
|
115
|
+
import { assertNoReservedConnectorNames } from "./connectors/assert-no-reserved-connector-names.mjs";
|
|
116
|
+
import { assertUniqueConnectorNames } from "./connectors/assert-unique-connector-names.mjs";
|
|
117
|
+
import { WarlockConfigManager, isUnknownTsExtensionError, warlockConfigManager } from "./warlock-config/warlock-config.manager.mjs";
|
|
118
|
+
import { registerConfiguredConnectors } from "./connectors/register-configured-connectors.mjs";
|
|
112
119
|
import "./connectors/index.mjs";
|
|
113
120
|
import { seeder } from "./database/seeds/seeder.mjs";
|
|
114
121
|
import { SeederDependencyCycleError, UnknownSeederDependencyError } from "./database/seeds/seeder.errors.mjs";
|
|
@@ -140,11 +147,10 @@ import { useCase } from "./use-cases/use-case.mjs";
|
|
|
140
147
|
import "./use-cases/index.mjs";
|
|
141
148
|
import "./validation/index.mjs";
|
|
142
149
|
import { defineConfig } from "./warlock-config/define-config.mjs";
|
|
143
|
-
import { WarlockConfigManager, isUnknownTsExtensionError, warlockConfigManager } from "./warlock-config/warlock-config.manager.mjs";
|
|
144
150
|
import "./warlock-config/index.mjs";
|
|
145
151
|
import { env } from "@mongez/dotenv";
|
|
146
152
|
import { colors } from "@mongez/copper";
|
|
147
153
|
|
|
148
154
|
export * from "@mongez/localization"
|
|
149
155
|
|
|
150
|
-
export { $registerUseCase, $unregisterUseCase, AccessConnector, AiConnector, Application, BOOT_SIGNAL_ENV_KEY, BOOT_SIGNAL_VERSION, BadRequestError, BadSchemaUseCaseError, BaseConnector, BenchmarkProfiler, BenchmarkSnapshots, CLICommand, CacheConnector, CascadeAdapter, CascadeQueryBuilder, CloudDriver, ConfigSpecialHandlers, ConflictError, ConnectorLifecyclePhase, ConnectorPriority, ConnectorsManager, ConsoleChannel, DOSpacesDriver, DatabaseCacheDriver, DatabaseConnector, DatabaseLog, DatabaseLogModel, FileValidator, ForbiddenError, HeraldConnector, HttpConnector, HttpError, HttpErrorCodes, Image, LocalDriver, LoggerConnector, MAIL_EVENTS, Mail, MailError, MailerConnector, MimeTypes, NoopChannel, NotAcceptableError, NotAllowedError, NotificationsConnector, Path, PortInUseError, Queue, R2Driver, RegisterResource, RepositoryManager, Request, RequestController, RequestLog, Resource, ResourceFieldBuilder, ResourceNotFoundError, Response, ResponseStatus, Restful, Router, S3Driver, ScopedStorage, SeederDependencyCycleError, ServerError, SocketConnector, Storage, StorageConnector, StorageError, StorageFile, UPLOADS_DEFAULTS, UnAuthorizedError, UnknownSeederDependencyError, UploadedFile, WarlockConfigManager, addUseCaseHistory, anyMatch, app, appLog, appPath, assertMailCount, assertMailSent, assertPortIsAvailable, assetsUrl, bootstrap, broadcastUseCaseResult, buildIdempotencyCacheKey, cachePath, captureMail, clearTestMailbox, closeAllMailers, closeMailer, closeServerWithTimeout, colors, command, config, configPath, configSpecialHandlers, connectorsManager, container, createHttpApplication, createRequestStore, decrypt, defaultHttpConfigurations, defineConfig, defineResource, displayEnvironmentMode, encrypt, env, environment, existsExceptCurrentIdRule, existsExceptCurrentUserRule, fetchLatestVersion, fileExtensionRule, fileRule, fileTypeRule, findMailsBySubject, findMailsTo, fireLifecycleEvent,
|
|
156
|
+
export { $registerUseCase, $unregisterUseCase, AccessConnector, AiConnector, Application, BOOT_SIGNAL_ENV_KEY, BOOT_SIGNAL_VERSION, BadRequestError, BadSchemaUseCaseError, BaseConnector, BenchmarkProfiler, BenchmarkSnapshots, CLICommand, CacheConnector, CascadeAdapter, CascadeQueryBuilder, CloudDriver, ConfigSpecialHandlers, ConflictError, ConnectorLifecyclePhase, ConnectorPriority, ConnectorsManager, ConsoleChannel, DOSpacesDriver, DatabaseCacheDriver, DatabaseConnector, DatabaseLog, DatabaseLogModel, FileValidator, ForbiddenError, HeraldConnector, HttpConnector, HttpError, HttpErrorCodes, Image, LocalDriver, LoggerConnector, MAIL_EVENTS, Mail, MailError, MailerConnector, MimeTypes, NoopChannel, NotAcceptableError, NotAllowedError, NotificationsConnector, Path, PortInUseError, Queue, R2Driver, RegisterResource, RepositoryManager, Request, RequestController, RequestLog, Resource, ResourceFieldBuilder, ResourceNotFoundError, Response, ResponseStatus, Restful, RouteRegistry, Router, S3Driver, ScopedStorage, SeederDependencyCycleError, ServerError, SocketConnector, Storage, StorageConnector, StorageError, StorageFile, UPLOADS_DEFAULTS, UnAuthorizedError, UnknownSeederDependencyError, UploadedFile, WarlockConfigManager, addUseCaseHistory, anyMatch, app, appLog, appPath, assertMailCount, assertMailSent, assertNoReservedConnectorNames, assertPortIsAvailable, assertUniqueConnectorNames, assetsUrl, bootstrap, broadcastUseCaseResult, buildIdempotencyCacheKey, cachePath, captureMail, clearPositionalHandlerSuspects, clearTestMailbox, closeAllMailers, closeMailer, closeServerWithTimeout, colors, command, config, configPath, configSpecialHandlers, connectorsManager, container, createHttpApplication, createRequestStore, decrypt, defaultHttpConfigurations, defineConfig, defineResource, describePositionalHandlerSuspect, displayEnvironmentMode, encrypt, env, environment, existsExceptCurrentIdRule, existsExceptCurrentUserRule, fetchLatestVersion, fileExtensionRule, fileRule, fileTypeRule, findMailsBySubject, findMailsTo, fireLifecycleEvent, forgetPositionalHandlerSuspects, generateMailId, getDefaultMailConfig, getHttpServer, getLastMail, getLocalized, getMailEventName, getMailMode, getMailboxSize, getMailer, getMailerConfig, getMimeType, getPoolStats, getSocketServer, getTestMailbox, getUseCase, getUseCaseHistory, getUseCases, globalEventsCallbacksMap, globalUseCasesEvents, hashBody, hashPassword, health, hmacHash, httpConfig, imageRule, increaseUseCaseFailedCalls, increaseUseCaseSuccessCalls, inspectHandlerSignature, ipMatches, isBootSignal, isDevelopmentMode, isNewerVersion, isPortAvailable, isPrivateOrReservedIp, isProductionMode, isTestMode, isUnknownTsExtensionError, isValidIdempotencyKey, listPositionalHandlerSuspects, loadS3, logResponse, logsPath, looksLikePositionalHandler, mailEvents, measure, middleware, parseSize, paths, promiseAllObject, publicPath, publicUrl, registerAppConfig, registerConfiguredConnectors, registerHttpPlugins, renderReact, renderReactMail, reportPositionalHandlerSuspects, requestContext, requestMemo, resetMailConfig, resolveMailConfig, resolveWithinRoot, rootPath, router, runPipeline, safeFetchToBuffer, sanitizePath, seeder, sendBootSignal, sendMail, setBaseUrl, setConfig, setEnvironment, setLogConfigurations, setMailConfigurations, setMailMode, sleep, sluggable, srcPath, startHttpServer, stopHttpApplication, storage, storageConfig, storageConfigurations, storageDriverContext, storagePath, t, tempPath, toJson, uniqueExceptCurrentIdRule, uniqueExceptCurrentUserRule, uploadedFileMetadataSchema, uploadsConfig, uploadsPath, uploadsUrl, url, useCase, useComputedModel, useComputedSlug, useCurrentUser, useHashedPassword, useRequest, useRequestStore, verifyMailer, verifyPassword, warlockConfigManager, warlockPath, wasMailSentTo, wasMailSentWithSubject, wrapResponseInDataKey };
|