@wener/common 2.0.2 → 2.0.5
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/lib/ai/qwen3vl/index.js +2 -0
- package/lib/ai/qwen3vl/index.js.map +1 -0
- package/lib/ai/qwen3vl/utils.js +31 -0
- package/lib/ai/qwen3vl/utils.js.map +1 -0
- package/lib/ai/vision/DocLayoutElementTypeSchema.js +28 -0
- package/lib/ai/vision/DocLayoutElementTypeSchema.js.map +1 -0
- package/lib/ai/vision/ImageAnnotationSchema.js +50 -0
- package/lib/ai/vision/ImageAnnotationSchema.js.map +1 -0
- package/lib/ai/vision/index.js +3 -0
- package/lib/ai/vision/index.js.map +1 -0
- package/lib/ai/vision/resolveImageAnnotation.js +105 -0
- package/lib/ai/vision/resolveImageAnnotation.js.map +1 -0
- package/lib/cn/ChineseResidentIdNo.js +22 -15
- package/lib/cn/ChineseResidentIdNo.js.map +1 -0
- package/lib/cn/ChineseResidentIdNo.test.js +1 -1
- package/lib/cn/DivisionCode.js +30 -25
- package/lib/cn/DivisionCode.js.map +1 -0
- package/lib/cn/DivisionCode.test.js +1 -1
- package/lib/cn/Mod11.js +38 -81
- package/lib/cn/Mod11.js.map +1 -0
- package/lib/cn/Mod31.js +41 -90
- package/lib/cn/Mod31.js.map +1 -0
- package/lib/cn/UnifiedSocialCreditCode.js +43 -34
- package/lib/cn/UnifiedSocialCreditCode.js.map +1 -0
- package/lib/cn/UnifiedSocialCreditCode.test.js +1 -1
- package/lib/cn/formatChineseAmount.js +77 -0
- package/lib/cn/formatChineseAmount.js.map +1 -0
- package/lib/cn/index.js +7 -1
- package/lib/cn/index.js.map +1 -0
- package/lib/cn/parseChineseNumber.js +94 -0
- package/lib/cn/parseChineseNumber.js.map +1 -0
- package/lib/cn/parseChineseNumber.test.js +278 -0
- package/lib/cn/pinyin/cartesianProduct.js +22 -0
- package/lib/cn/pinyin/cartesianProduct.js.map +1 -0
- package/lib/cn/pinyin/cartesianProduct.test.js +179 -0
- package/lib/cn/pinyin/data.json +23573 -0
- package/lib/cn/pinyin/loader.js +14 -0
- package/lib/cn/pinyin/loader.js.map +1 -0
- package/lib/cn/pinyin/preload.js +3 -0
- package/lib/cn/pinyin/preload.js.map +1 -0
- package/lib/cn/pinyin/toPinyin.test.js +167 -0
- package/lib/cn/pinyin/toPinyinPure.js +33 -0
- package/lib/cn/pinyin/toPinyinPure.js.map +1 -0
- package/lib/cn/pinyin/transform.js +14 -0
- package/lib/cn/pinyin/transform.js.map +1 -0
- package/lib/cn/types.d.js +2 -0
- package/lib/cn/types.d.js.map +1 -0
- package/lib/consola/createStandardConsolaReporter.js +6 -6
- package/lib/consola/createStandardConsolaReporter.js.map +1 -0
- package/lib/consola/formatLogObject.js +66 -146
- package/lib/consola/formatLogObject.js.map +1 -0
- package/lib/consola/formatLogObject.test.js +184 -0
- package/lib/consola/index.js +1 -0
- package/lib/consola/index.js.map +1 -0
- package/lib/data/formatSort.js +6 -5
- package/lib/data/formatSort.js.map +1 -0
- package/lib/data/index.js +1 -0
- package/lib/data/index.js.map +1 -0
- package/lib/data/maybeNumber.js +6 -8
- package/lib/data/maybeNumber.js.map +1 -0
- package/lib/data/parseSort.js +22 -28
- package/lib/data/parseSort.js.map +1 -0
- package/lib/data/resolvePagination.js +13 -17
- package/lib/data/resolvePagination.js.map +1 -0
- package/lib/data/types.d.js +2 -0
- package/lib/data/types.d.js.map +1 -0
- package/lib/dayjs/dayjs.js +21 -19
- package/lib/dayjs/dayjs.js.map +1 -0
- package/lib/dayjs/formatDuration.js +15 -14
- package/lib/dayjs/formatDuration.js.map +1 -0
- package/lib/dayjs/index.js +2 -0
- package/lib/dayjs/index.js.map +1 -0
- package/lib/dayjs/parseDuration.js +5 -8
- package/lib/dayjs/parseDuration.js.map +1 -0
- package/lib/dayjs/parseRelativeTime.js +90 -0
- package/lib/dayjs/parseRelativeTime.js.map +1 -0
- package/lib/dayjs/parseRelativeTime.test.js +247 -0
- package/lib/dayjs/resolveRelativeTime.js +87 -0
- package/lib/dayjs/resolveRelativeTime.js.map +1 -0
- package/lib/dayjs/resolveRelativeTime.test.js +310 -0
- package/lib/decimal/index.js +1 -0
- package/lib/decimal/index.js.map +1 -0
- package/lib/decimal/parseDecimal.js +3 -1
- package/lib/decimal/parseDecimal.js.map +1 -0
- package/lib/drain3/Drain.js +356 -0
- package/lib/drain3/Drain.js.map +1 -0
- package/lib/drain3/LogCluster.js +38 -0
- package/lib/drain3/LogCluster.js.map +1 -0
- package/lib/drain3/Node.js +39 -0
- package/lib/drain3/Node.js.map +1 -0
- package/lib/drain3/TemplateMiner.js +204 -0
- package/lib/drain3/TemplateMiner.js.map +1 -0
- package/lib/drain3/index.js +31 -0
- package/lib/drain3/index.js.map +1 -0
- package/lib/drain3/persistence/FilePersistence.js +24 -0
- package/lib/drain3/persistence/FilePersistence.js.map +1 -0
- package/lib/drain3/persistence/MemoryPersistence.js +18 -0
- package/lib/drain3/persistence/MemoryPersistence.js.map +1 -0
- package/lib/drain3/persistence/PersistenceHandler.js +5 -0
- package/lib/drain3/persistence/PersistenceHandler.js.map +1 -0
- package/lib/drain3/types.js +7 -0
- package/lib/drain3/types.js.map +1 -0
- package/lib/emittery/emitter.js +10 -0
- package/lib/emittery/emitter.js.map +1 -0
- package/lib/emittery/index.js +2 -0
- package/lib/emittery/index.js.map +1 -0
- package/lib/foundation/schema/SexType.js +5 -3
- package/lib/foundation/schema/SexType.js.map +1 -0
- package/lib/foundation/schema/index.js +1 -0
- package/lib/foundation/schema/index.js.map +1 -0
- package/lib/foundation/schema/parseSexType.js +1 -0
- package/lib/foundation/schema/parseSexType.js.map +1 -0
- package/lib/foundation/schema/types.js +4 -2
- package/lib/foundation/schema/types.js.map +1 -0
- package/lib/fs/FileSystemError.js +23 -0
- package/lib/fs/FileSystemError.js.map +1 -0
- package/lib/fs/IFileSystem.d.js +3 -0
- package/lib/fs/IFileSystem.d.js.map +1 -0
- package/lib/fs/MemoryFileSystem.test.js +188 -0
- package/lib/fs/createBrowserFileSystem.js +250 -0
- package/lib/fs/createBrowserFileSystem.js.map +1 -0
- package/lib/fs/createMemoryFileSystem.js +517 -0
- package/lib/fs/createMemoryFileSystem.js.map +1 -0
- package/lib/fs/createSandboxFileSystem.js +108 -0
- package/lib/fs/createSandboxFileSystem.js.map +1 -0
- package/lib/fs/createWebDavFileSystem.js +154 -0
- package/lib/fs/createWebDavFileSystem.js.map +1 -0
- package/lib/fs/createWebFileSystem.js +225 -0
- package/lib/fs/createWebFileSystem.js.map +1 -0
- package/lib/fs/findMimeType.js +17 -0
- package/lib/fs/findMimeType.js.map +1 -0
- package/lib/fs/index.js +8 -0
- package/lib/fs/index.js.map +1 -0
- package/lib/fs/minio/createMinioFileSystem.js +974 -0
- package/lib/fs/minio/createMinioFileSystem.js.map +1 -0
- package/lib/fs/minio/index.js +2 -0
- package/lib/fs/minio/index.js.map +1 -0
- package/lib/fs/orpc/FileSystemContract.js +93 -0
- package/lib/fs/orpc/FileSystemContract.js.map +1 -0
- package/lib/fs/orpc/createContractClientFileSystem.js +93 -0
- package/lib/fs/orpc/createContractClientFileSystem.js.map +1 -0
- package/lib/fs/orpc/index.js +3 -0
- package/lib/fs/orpc/index.js.map +1 -0
- package/lib/fs/orpc/server/createFileSystemContractImpl.js +63 -0
- package/lib/fs/orpc/server/createFileSystemContractImpl.js.map +1 -0
- package/lib/fs/orpc/server/index.js +2 -0
- package/lib/fs/orpc/server/index.js.map +1 -0
- package/lib/fs/s3/createS3MiniFileSystem.js +753 -0
- package/lib/fs/s3/createS3MiniFileSystem.js.map +1 -0
- package/lib/fs/s3/index.js +2 -0
- package/lib/fs/s3/index.js.map +1 -0
- package/lib/fs/s3/s3mini.test.js +584 -0
- package/lib/fs/scandir.js +59 -0
- package/lib/fs/scandir.js.map +1 -0
- package/lib/fs/server/createDatabaseFileSystem.js +750 -0
- package/lib/fs/server/createDatabaseFileSystem.js.map +1 -0
- package/lib/fs/server/createNodeFileSystem.js +426 -0
- package/lib/fs/server/createNodeFileSystem.js.map +1 -0
- package/lib/fs/server/dbfs.test.js +221 -0
- package/lib/fs/server/index.js +2 -0
- package/lib/fs/server/index.js.map +1 -0
- package/lib/fs/server/loadTestDatabase.js +127 -0
- package/lib/fs/server/loadTestDatabase.js.map +1 -0
- package/lib/fs/tests/runFileSystemTest.js +319 -0
- package/lib/fs/tests/runFileSystemTest.js.map +1 -0
- package/lib/fs/types.js +27 -0
- package/lib/fs/types.js.map +1 -0
- package/lib/fs/utils/getFileUrl.js +35 -0
- package/lib/fs/utils/getFileUrl.js.map +1 -0
- package/lib/fs/utils.js +22 -0
- package/lib/fs/utils.js.map +1 -0
- package/lib/fs/webdav/index.js +2 -0
- package/lib/fs/webdav/index.js.map +1 -0
- package/lib/index.js +1 -0
- package/lib/index.js.map +1 -0
- package/lib/jsonschema/JsonSchema.js +146 -172
- package/lib/jsonschema/JsonSchema.js.map +1 -0
- package/lib/jsonschema/forEachJsonSchema.js +44 -0
- package/lib/jsonschema/forEachJsonSchema.js.map +1 -0
- package/lib/jsonschema/index.js +2 -0
- package/lib/jsonschema/index.js.map +1 -0
- package/lib/jsonschema/types.d.js +2 -0
- package/lib/jsonschema/types.d.js.map +1 -0
- package/lib/meta/defineFileType.js +20 -103
- package/lib/meta/defineFileType.js.map +1 -0
- package/lib/meta/defineInit.js +31 -250
- package/lib/meta/defineInit.js.map +1 -0
- package/lib/meta/defineMetadata.js +24 -140
- package/lib/meta/defineMetadata.js.map +1 -0
- package/lib/meta/index.js +1 -0
- package/lib/meta/index.js.map +1 -0
- package/lib/orpc/createOpenApiContractClient.js +27 -0
- package/lib/orpc/createOpenApiContractClient.js.map +1 -0
- package/lib/orpc/createRpcContractClient.js +34 -0
- package/lib/orpc/createRpcContractClient.js.map +1 -0
- package/lib/orpc/index.js +3 -0
- package/lib/orpc/index.js.map +1 -0
- package/lib/orpc/resolveLinkPlugins.js +28 -0
- package/lib/orpc/resolveLinkPlugins.js.map +1 -0
- package/lib/password/PHC.js +63 -87
- package/lib/password/PHC.js.map +1 -0
- package/lib/password/PHC.test.js +11 -3
- package/lib/password/Password.js +29 -294
- package/lib/password/Password.js.map +1 -0
- package/lib/password/Password.test.js +35 -22
- package/lib/password/createArgon2PasswordAlgorithm.js +35 -191
- package/lib/password/createArgon2PasswordAlgorithm.js.map +1 -0
- package/lib/password/createBase64PasswordAlgorithm.js +8 -141
- package/lib/password/createBase64PasswordAlgorithm.js.map +1 -0
- package/lib/password/createBcryptPasswordAlgorithm.js +13 -168
- package/lib/password/createBcryptPasswordAlgorithm.js.map +1 -0
- package/lib/password/createPBKDF2PasswordAlgorithm.js +46 -228
- package/lib/password/createPBKDF2PasswordAlgorithm.js.map +1 -0
- package/lib/password/createScryptPasswordAlgorithm.js +55 -211
- package/lib/password/createScryptPasswordAlgorithm.js.map +1 -0
- package/lib/password/index.js +1 -0
- package/lib/password/index.js.map +1 -0
- package/lib/password/server/index.js +1 -0
- package/lib/password/server/index.js.map +1 -0
- package/lib/resource/Identifiable.js +2 -0
- package/lib/resource/Identifiable.js.map +1 -0
- package/lib/resource/ListQuery.js +21 -93
- package/lib/resource/ListQuery.js.map +1 -0
- package/lib/resource/getTitleOfResource.js +3 -5
- package/lib/resource/getTitleOfResource.js.map +1 -0
- package/lib/resource/index.js +1 -0
- package/lib/resource/index.js.map +1 -0
- package/lib/resource/schema/AnyResourceSchema.js +2 -1
- package/lib/resource/schema/AnyResourceSchema.js.map +1 -0
- package/lib/resource/schema/BaseResourceSchema.js +2 -1
- package/lib/resource/schema/BaseResourceSchema.js.map +1 -0
- package/lib/resource/schema/ResourceActionType.js +6 -4
- package/lib/resource/schema/ResourceActionType.js.map +1 -0
- package/lib/resource/schema/ResourceStatus.js +5 -3
- package/lib/resource/schema/ResourceStatus.js.map +1 -0
- package/lib/resource/schema/ResourceType.js +5 -3
- package/lib/resource/schema/ResourceType.js.map +1 -0
- package/lib/resource/schema/index.js +1 -0
- package/lib/resource/schema/index.js.map +1 -0
- package/lib/resource/schema/types.js +16 -20
- package/lib/resource/schema/types.js.map +1 -0
- package/lib/s3/formatS3Url.js +65 -0
- package/lib/s3/formatS3Url.js.map +1 -0
- package/lib/s3/formatS3Url.test.js +262 -0
- package/lib/s3/index.js +3 -0
- package/lib/s3/index.js.map +1 -0
- package/lib/s3/parseS3Url.js +65 -0
- package/lib/s3/parseS3Url.js.map +1 -0
- package/lib/s3/parseS3Url.test.js +270 -0
- package/lib/schema/SchemaRegistry.js +38 -38
- package/lib/schema/SchemaRegistry.js.map +1 -0
- package/lib/schema/TypeSchema.d.js +2 -0
- package/lib/schema/TypeSchema.d.js.map +1 -0
- package/lib/schema/createSchemaData.js +26 -125
- package/lib/schema/createSchemaData.js.map +1 -0
- package/lib/schema/findJsonSchemaByPath.js +13 -36
- package/lib/schema/findJsonSchemaByPath.js.map +1 -0
- package/lib/schema/formatZodError.js +138 -0
- package/lib/schema/formatZodError.js.map +1 -0
- package/lib/schema/formatZodError.test.js +196 -0
- package/lib/schema/getSchemaCache.js +5 -5
- package/lib/schema/getSchemaCache.js.map +1 -0
- package/lib/schema/getSchemaOptions.js +8 -11
- package/lib/schema/getSchemaOptions.js.map +1 -0
- package/lib/schema/index.js +2 -1
- package/lib/schema/index.js.map +1 -0
- package/lib/schema/toJsonSchema.js +50 -293
- package/lib/schema/toJsonSchema.js.map +1 -0
- package/lib/schema/validate.js +34 -46
- package/lib/schema/validate.js.map +1 -0
- package/lib/tools/generateSchema.js +39 -197
- package/lib/tools/generateSchema.js.map +1 -0
- package/lib/tools/renderJsonSchemaToMarkdownDoc.js +55 -143
- package/lib/tools/renderJsonSchemaToMarkdownDoc.js.map +1 -0
- package/lib/utils/buildBaseUrl.js +13 -0
- package/lib/utils/buildBaseUrl.js.map +1 -0
- package/lib/utils/buildRedactorFormSchema.js +59 -0
- package/lib/utils/buildRedactorFormSchema.js.map +1 -0
- package/lib/utils/getEstimateProcessTime.js +12 -11
- package/lib/utils/getEstimateProcessTime.js.map +1 -0
- package/lib/utils/index.js +3 -0
- package/lib/utils/index.js.map +1 -0
- package/lib/utils/resolveFeatureOptions.js +12 -0
- package/lib/utils/resolveFeatureOptions.js.map +1 -0
- package/package.json +80 -13
- package/src/ai/qwen3vl/index.ts +1 -0
- package/src/ai/qwen3vl/utils.ts +36 -0
- package/src/ai/vision/DocLayoutElementTypeSchema.ts +30 -0
- package/src/ai/vision/ImageAnnotationSchema.ts +60 -0
- package/src/ai/vision/index.ts +2 -0
- package/src/ai/vision/resolveImageAnnotation.ts +135 -0
- package/src/cn/ChineseResidentIdNo.test.ts +1 -1
- package/src/cn/ChineseResidentIdNo.ts +9 -1
- package/src/cn/DivisionCode.test.ts +1 -1
- package/src/cn/DivisionCode.ts +8 -0
- package/src/cn/Mod11.ts +1 -1
- package/src/cn/UnifiedSocialCreditCode.test.ts +1 -1
- package/src/cn/UnifiedSocialCreditCode.ts +15 -0
- package/src/cn/__snapshots__/ChineseResidentIdNo.test.ts.snap +1 -1
- package/src/cn/formatChineseAmount.ts +61 -0
- package/src/cn/index.ts +7 -1
- package/src/cn/parseChineseNumber.test.ts +159 -0
- package/src/cn/parseChineseNumber.ts +97 -0
- package/src/cn/pinyin/cartesianProduct.test.ts +64 -0
- package/src/cn/pinyin/cartesianProduct.ts +24 -0
- package/src/cn/pinyin/data.json +23573 -0
- package/src/cn/pinyin/loader.ts +12 -0
- package/src/cn/pinyin/preload.ts +3 -0
- package/src/cn/pinyin/toPinyin.test.ts +12 -0
- package/src/cn/pinyin/toPinyinPure.ts +43 -0
- package/src/cn/pinyin/transform.ts +12 -0
- package/src/consola/formatLogObject.test.ts +27 -0
- package/src/consola/formatLogObject.ts +40 -12
- package/src/data/maybeNumber.ts +1 -1
- package/src/data/parseSort.test.ts +0 -1
- package/src/data/types.d.ts +2 -2
- package/src/dayjs/dayjs.ts +18 -18
- package/src/dayjs/formatDuration.ts +2 -2
- package/src/dayjs/index.ts +3 -1
- package/src/dayjs/parseRelativeTime.test.ts +185 -0
- package/src/dayjs/parseRelativeTime.ts +115 -0
- package/src/dayjs/resolveRelativeTime.test.ts +357 -0
- package/src/dayjs/resolveRelativeTime.ts +164 -0
- package/src/drain3/Drain.test.ts +378 -0
- package/src/drain3/Drain.ts +394 -0
- package/src/drain3/LogCluster.ts +46 -0
- package/src/drain3/Node.ts +53 -0
- package/src/drain3/TemplateMiner.ts +246 -0
- package/src/drain3/index.ts +36 -0
- package/src/drain3/persistence/FilePersistence.ts +24 -0
- package/src/drain3/persistence/MemoryPersistence.ts +23 -0
- package/src/drain3/persistence/PersistenceHandler.ts +19 -0
- package/src/drain3/types.ts +75 -0
- package/src/emittery/emitter.ts +9 -0
- package/src/emittery/index.ts +1 -0
- package/src/fs/FileSystemError.ts +26 -0
- package/src/fs/IFileSystem.d.ts +101 -0
- package/src/fs/MemoryFileSystem.test.ts +37 -0
- package/src/fs/createBrowserFileSystem.ts +293 -0
- package/src/fs/createMemoryFileSystem.ts +600 -0
- package/src/fs/createSandboxFileSystem.ts +136 -0
- package/src/fs/createWebDavFileSystem.ts +190 -0
- package/src/fs/createWebFileSystem.ts +242 -0
- package/src/fs/findMimeType.ts +20 -0
- package/src/fs/index.ts +8 -0
- package/src/fs/minio/createMinioFileSystem.ts +1148 -0
- package/src/fs/minio/index.ts +1 -0
- package/src/fs/orpc/FileSystemContract.ts +92 -0
- package/src/fs/orpc/createContractClientFileSystem.ts +115 -0
- package/src/fs/orpc/index.ts +2 -0
- package/src/fs/orpc/server/createFileSystemContractImpl.ts +64 -0
- package/src/fs/orpc/server/index.ts +1 -0
- package/src/fs/s3/createS3MiniFileSystem.ts +871 -0
- package/src/fs/s3/index.ts +1 -0
- package/src/fs/s3/s3fs.test.ts +441 -0
- package/src/fs/s3/s3mini.test.ts +264 -0
- package/src/fs/scandir.ts +75 -0
- package/src/fs/server/createDatabaseFileSystem.ts +668 -0
- package/src/fs/server/createNodeFileSystem.ts +518 -0
- package/src/fs/server/dbfs.test.ts +48 -0
- package/src/fs/server/index.ts +1 -0
- package/src/fs/server/loadTestDatabase.ts +131 -0
- package/src/fs/tests/runFileSystemTest.ts +289 -0
- package/src/fs/types.ts +29 -0
- package/src/fs/utils/getFileUrl.ts +44 -0
- package/src/fs/utils.ts +23 -0
- package/src/fs/webdav/index.ts +1 -0
- package/src/jsonschema/JsonSchema.ts +118 -110
- package/src/jsonschema/forEachJsonSchema.ts +50 -0
- package/src/jsonschema/index.ts +1 -0
- package/src/jsonschema/types.d.ts +1 -1
- package/src/meta/defineMetadata.ts +1 -1
- package/src/orpc/createOpenApiContractClient.ts +52 -0
- package/src/orpc/createRpcContractClient.ts +50 -0
- package/src/orpc/index.ts +2 -0
- package/src/orpc/resolveLinkPlugins.ts +29 -0
- package/src/password/PHC.ts +6 -6
- package/src/password/Password.test.ts +1 -1
- package/src/password/createArgon2PasswordAlgorithm.ts +1 -1
- package/src/password/createBase64PasswordAlgorithm.ts +2 -2
- package/src/password/createBcryptPasswordAlgorithm.ts +4 -2
- package/src/password/createPBKDF2PasswordAlgorithm.ts +4 -4
- package/src/password/createScryptPasswordAlgorithm.ts +4 -4
- package/src/resource/ListQuery.ts +4 -1
- package/src/resource/index.ts +2 -2
- package/src/resource/schema/AnyResourceSchema.ts +16 -2
- package/src/s3/formatS3Url.test.ts +254 -0
- package/src/s3/formatS3Url.ts +84 -0
- package/src/s3/index.ts +2 -0
- package/src/s3/parseS3Url.test.ts +258 -0
- package/src/s3/parseS3Url.ts +88 -0
- package/src/schema/SchemaRegistry.ts +35 -33
- package/src/schema/TypeSchema.d.ts +6 -6
- package/src/schema/createSchemaData.ts +4 -4
- package/src/schema/findJsonSchemaByPath.ts +4 -4
- package/src/schema/formatZodError.test.ts +197 -0
- package/src/schema/formatZodError.ts +139 -0
- package/src/schema/getSchemaOptions.ts +2 -2
- package/src/schema/index.ts +1 -1
- package/src/schema/toJsonSchema.ts +6 -6
- package/src/schema/validate.ts +1 -1
- package/src/utils/buildBaseUrl.ts +12 -0
- package/src/utils/buildRedactorFormSchema.ts +85 -0
- package/src/utils/index.ts +4 -0
- package/src/utils/resolveFeatureOptions.ts +14 -0
- package/src/cn/ChineseResidentIdNo.mod.ts +0 -7
- package/src/cn/DivisionCode.mod.ts +0 -7
- package/src/cn/UnifiedSocialCreditCode.mod.ts +0 -7
- package/src/cn/mod.ts +0 -3
- package/src/schema/SchemaRegistry.mod.ts +0 -1
|
@@ -0,0 +1,50 @@
|
|
|
1
|
+
import type { JsonSchemaDef } from './types';
|
|
2
|
+
|
|
3
|
+
export type VisitJsonSchemaContext = { path: string[]; parent?: JsonSchemaDef };
|
|
4
|
+
|
|
5
|
+
export function forEachJsonSchema(js: JsonSchemaDef, cb: (js: JsonSchemaDef, ctx: VisitJsonSchemaContext) => void) {
|
|
6
|
+
const ctx: VisitJsonSchemaContext = { path: [] };
|
|
7
|
+
const _visit = (
|
|
8
|
+
js: JsonSchemaDef,
|
|
9
|
+
_f: (js: JsonSchemaDef, ctx: VisitJsonSchemaContext) => void,
|
|
10
|
+
parent: JsonSchemaDef | undefined,
|
|
11
|
+
path: string[],
|
|
12
|
+
_k?: string,
|
|
13
|
+
) => {
|
|
14
|
+
if (!js) {
|
|
15
|
+
return;
|
|
16
|
+
}
|
|
17
|
+
ctx.path = path;
|
|
18
|
+
ctx.parent = parent;
|
|
19
|
+
_f(js, ctx);
|
|
20
|
+
if (js.properties) {
|
|
21
|
+
for (const [k, v] of Object.entries(js.properties)) {
|
|
22
|
+
if (v) {
|
|
23
|
+
_visit(v, _f, js, path.concat(k), 'properties');
|
|
24
|
+
}
|
|
25
|
+
}
|
|
26
|
+
} else if (js.items) {
|
|
27
|
+
// array should be `key[].subkey` or `key.*.subkey`?
|
|
28
|
+
if (Array.isArray(js.items)) {
|
|
29
|
+
for (const v of js.items) {
|
|
30
|
+
_visit(v, _f, js, path, 'items');
|
|
31
|
+
}
|
|
32
|
+
} else {
|
|
33
|
+
_visit(js.items, _f, js, path, 'items');
|
|
34
|
+
}
|
|
35
|
+
} else if (js.anyOf) {
|
|
36
|
+
for (const v of js.anyOf) {
|
|
37
|
+
_visit(v, _f, js, path, 'anyOf');
|
|
38
|
+
}
|
|
39
|
+
} else if (js.oneOf) {
|
|
40
|
+
for (const v of js.oneOf) {
|
|
41
|
+
_visit(v, _f, js, path, 'oneOf');
|
|
42
|
+
}
|
|
43
|
+
} else if (js.allOf) {
|
|
44
|
+
for (const v of js.allOf) {
|
|
45
|
+
_visit(v, _f, js, path, 'allOf');
|
|
46
|
+
}
|
|
47
|
+
}
|
|
48
|
+
};
|
|
49
|
+
_visit(js, cb, undefined, []);
|
|
50
|
+
}
|
package/src/jsonschema/index.ts
CHANGED
|
@@ -30,7 +30,7 @@ export function createMetadataKey<T = never>(a: any, b?: any): MetadataKey<T> {
|
|
|
30
30
|
|
|
31
31
|
export function defineMetadata<T>(res: HasMetadata, key: MetadataKey<T>, opts: T): void;
|
|
32
32
|
export function defineMetadata<T>(key: MetadataKey<T>, items: Array<[HasMetadata, T]>): void;
|
|
33
|
-
export function defineMetadata<
|
|
33
|
+
export function defineMetadata<_T>(a: any, b: any, c?: any) {
|
|
34
34
|
if (Array.isArray(b)) {
|
|
35
35
|
const key = a;
|
|
36
36
|
const items = b;
|
|
@@ -0,0 +1,52 @@
|
|
|
1
|
+
import { createORPCClient, type ClientContext } from '@orpc/client';
|
|
2
|
+
import type { LinkFetchClientOptions } from '@orpc/client/fetch';
|
|
3
|
+
import type { BatchLinkPluginOptions, DedupeRequestsPluginOptions } from '@orpc/client/plugins';
|
|
4
|
+
import type { StandardLinkPlugin } from '@orpc/client/standard';
|
|
5
|
+
import type { AnyContractRouter, ContractRouterClient } from '@orpc/contract';
|
|
6
|
+
import type { JsonifiedClient } from '@orpc/openapi-client';
|
|
7
|
+
import { OpenAPILink } from '@orpc/openapi-client/fetch';
|
|
8
|
+
import type { PartialRequired } from '@wener/utils';
|
|
9
|
+
import { buildBaseUrl } from '../utils/buildBaseUrl';
|
|
10
|
+
import { resolveLinkPlugins } from './resolveLinkPlugins';
|
|
11
|
+
|
|
12
|
+
export function createOpenApiContractClient<TContract extends AnyContractRouter>(
|
|
13
|
+
contract: TContract,
|
|
14
|
+
options: PartialRequired<CreateContractClientOptions, 'url'>,
|
|
15
|
+
): JsonifiedClient<ContractRouterClient<TContract, ClientContext>> {
|
|
16
|
+
let { url, baseUrl, apiKey, getApiKey, getHeaders } = options;
|
|
17
|
+
const baseHeaders = new Headers(options.headers);
|
|
18
|
+
if (apiKey) {
|
|
19
|
+
baseHeaders.set('Authorization', `Bearer ${apiKey}`);
|
|
20
|
+
}
|
|
21
|
+
url = buildBaseUrl(url, baseUrl);
|
|
22
|
+
return createORPCClient(
|
|
23
|
+
new OpenAPILink(contract, {
|
|
24
|
+
url,
|
|
25
|
+
headers: () => {
|
|
26
|
+
let headers = new Headers(baseHeaders);
|
|
27
|
+
|
|
28
|
+
let accessToken = getApiKey?.();
|
|
29
|
+
if (accessToken) {
|
|
30
|
+
headers.set('Authorization', `Bearer ${accessToken}`);
|
|
31
|
+
}
|
|
32
|
+
headers = getHeaders?.(headers) ?? headers;
|
|
33
|
+
return headers;
|
|
34
|
+
},
|
|
35
|
+
plugins: resolveLinkPlugins(options),
|
|
36
|
+
fetch: options.fetch,
|
|
37
|
+
}),
|
|
38
|
+
) as JsonifiedClient<ContractRouterClient<TContract, ClientContext>>;
|
|
39
|
+
}
|
|
40
|
+
|
|
41
|
+
export type CreateContractClientOptions = {
|
|
42
|
+
url?: string;
|
|
43
|
+
baseUrl?: string;
|
|
44
|
+
apiKey?: string;
|
|
45
|
+
headers?: Record<string, string> | Headers;
|
|
46
|
+
getApiKey?: () => string | undefined;
|
|
47
|
+
getHeaders?: (headers: Headers) => Headers | undefined;
|
|
48
|
+
plugins?: StandardLinkPlugin<any>[];
|
|
49
|
+
fetch?: LinkFetchClientOptions<any>['fetch'];
|
|
50
|
+
batch?: BatchLinkPluginOptions<any> | boolean;
|
|
51
|
+
dedup?: DedupeRequestsPluginOptions<any> | boolean;
|
|
52
|
+
};
|
|
@@ -0,0 +1,50 @@
|
|
|
1
|
+
import { createORPCClient } from '@orpc/client';
|
|
2
|
+
import { RPCLink } from '@orpc/client/fetch';
|
|
3
|
+
import type { AnyContractRouter, ContractRouterClient } from '@orpc/contract';
|
|
4
|
+
import { buildBaseUrl } from '../utils/buildBaseUrl';
|
|
5
|
+
import type { CreateContractClientOptions } from './createOpenApiContractClient';
|
|
6
|
+
import { resolveLinkPlugins } from './resolveLinkPlugins';
|
|
7
|
+
|
|
8
|
+
export type CreateRpcContractClientOptions = CreateContractClientOptions;
|
|
9
|
+
|
|
10
|
+
export function createRpcContractClient<C extends AnyContractRouter>(
|
|
11
|
+
options: CreateRpcContractClientOptions = {},
|
|
12
|
+
): ContractRouterClient<C> {
|
|
13
|
+
let {
|
|
14
|
+
url = '/api/rpc',
|
|
15
|
+
baseUrl = globalThis.location?.origin || 'http://localhost',
|
|
16
|
+
apiKey,
|
|
17
|
+
getApiKey,
|
|
18
|
+
getHeaders,
|
|
19
|
+
} = options;
|
|
20
|
+
url = buildBaseUrl(url, baseUrl);
|
|
21
|
+
|
|
22
|
+
const baseHeaders = new Headers(options.headers);
|
|
23
|
+
if (apiKey) {
|
|
24
|
+
baseHeaders.set('Authorization', `Bearer ${apiKey}`);
|
|
25
|
+
}
|
|
26
|
+
|
|
27
|
+
const plugins = resolveLinkPlugins({
|
|
28
|
+
dedup: true,
|
|
29
|
+
batch: true,
|
|
30
|
+
...options,
|
|
31
|
+
});
|
|
32
|
+
const link = new RPCLink({
|
|
33
|
+
url,
|
|
34
|
+
headers: () => {
|
|
35
|
+
let headers = new Headers(baseHeaders);
|
|
36
|
+
|
|
37
|
+
let accessToken = getApiKey?.();
|
|
38
|
+
if (accessToken) {
|
|
39
|
+
headers.set('Authorization', `Bearer ${accessToken}`);
|
|
40
|
+
}
|
|
41
|
+
headers = getHeaders?.(headers) ?? headers;
|
|
42
|
+
return headers;
|
|
43
|
+
},
|
|
44
|
+
fetch: options.fetch,
|
|
45
|
+
plugins,
|
|
46
|
+
});
|
|
47
|
+
|
|
48
|
+
const client: ContractRouterClient<C> = createORPCClient(link);
|
|
49
|
+
return client;
|
|
50
|
+
}
|
|
@@ -0,0 +1,29 @@
|
|
|
1
|
+
import { BatchLinkPlugin, DedupeRequestsPlugin } from '@orpc/client/plugins';
|
|
2
|
+
import { resolveFeatureOptions } from '../utils/resolveFeatureOptions';
|
|
3
|
+
import type { CreateRpcContractClientOptions } from './createRpcContractClient';
|
|
4
|
+
|
|
5
|
+
export function resolveLinkPlugins({ plugins = [], dedup, batch }: CreateRpcContractClientOptions) {
|
|
6
|
+
batch = resolveFeatureOptions(batch, {
|
|
7
|
+
groups: [
|
|
8
|
+
{
|
|
9
|
+
condition: () => true,
|
|
10
|
+
context: {},
|
|
11
|
+
},
|
|
12
|
+
],
|
|
13
|
+
});
|
|
14
|
+
if (batch) {
|
|
15
|
+
plugins.push(new BatchLinkPlugin(batch));
|
|
16
|
+
}
|
|
17
|
+
dedup = resolveFeatureOptions(dedup, {
|
|
18
|
+
groups: [
|
|
19
|
+
{
|
|
20
|
+
condition: () => true,
|
|
21
|
+
context: {},
|
|
22
|
+
},
|
|
23
|
+
],
|
|
24
|
+
});
|
|
25
|
+
if (dedup) {
|
|
26
|
+
plugins.push(new DedupeRequestsPlugin(dedup));
|
|
27
|
+
}
|
|
28
|
+
return plugins;
|
|
29
|
+
}
|
package/src/password/PHC.ts
CHANGED
|
@@ -99,11 +99,11 @@ export namespace PHC {
|
|
|
99
99
|
|
|
100
100
|
// Convert Numbers into Numeric Strings and Buffers into B64 encoded strings.
|
|
101
101
|
pk.forEach((k) => {
|
|
102
|
-
const value = opts.params
|
|
102
|
+
const value = opts.params?.[k];
|
|
103
103
|
if (typeof value === 'number') {
|
|
104
104
|
opts.params![k] = value.toString();
|
|
105
105
|
} else if (value instanceof Uint8Array) {
|
|
106
|
-
opts.params![k] = toBase64(value).split('=')[0];
|
|
106
|
+
opts.params![k] = toBase64(value as BufferSource).split('=')[0];
|
|
107
107
|
}
|
|
108
108
|
});
|
|
109
109
|
const pv = objectValues(opts.params);
|
|
@@ -125,7 +125,7 @@ export namespace PHC {
|
|
|
125
125
|
throw new TypeError('salt must be a Buffer');
|
|
126
126
|
}
|
|
127
127
|
|
|
128
|
-
fields.push(toBase64(opts.salt).split('=')[0]);
|
|
128
|
+
fields.push(toBase64(opts.salt as BufferSource).split('=')[0]);
|
|
129
129
|
|
|
130
130
|
if (typeof opts.hash !== 'undefined') {
|
|
131
131
|
// Hash Validation
|
|
@@ -133,7 +133,7 @@ export namespace PHC {
|
|
|
133
133
|
throw new TypeError('hash must be a Buffer');
|
|
134
134
|
}
|
|
135
135
|
|
|
136
|
-
fields.push(toBase64(opts.hash).split('=')[0]);
|
|
136
|
+
fields.push(toBase64(opts.hash as BufferSource).split('=')[0]);
|
|
137
137
|
}
|
|
138
138
|
}
|
|
139
139
|
|
|
@@ -143,7 +143,7 @@ export namespace PHC {
|
|
|
143
143
|
return phcstr;
|
|
144
144
|
}
|
|
145
145
|
|
|
146
|
-
interface DeserializeResult {
|
|
146
|
+
export interface DeserializeResult {
|
|
147
147
|
id: string;
|
|
148
148
|
version?: number;
|
|
149
149
|
params?: Record<string, string | number>;
|
|
@@ -223,7 +223,7 @@ export namespace PHC {
|
|
|
223
223
|
|
|
224
224
|
// Convert Decimal Strings into Numbers
|
|
225
225
|
Object.keys(params).forEach((k) => {
|
|
226
|
-
const value = params
|
|
226
|
+
const value = params?.[k];
|
|
227
227
|
if (typeof value === 'string' && decimalRegex.test(value)) {
|
|
228
228
|
params![k] = parseInt(value, 10);
|
|
229
229
|
}
|
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
import { maybeFunction, type MaybeFunction, type MaybePromise } from '@wener/utils';
|
|
2
|
-
import { Password } from './Password';
|
|
2
|
+
import type { Password } from './Password';
|
|
3
3
|
|
|
4
4
|
type Provide = {
|
|
5
5
|
hash: (password: string, options: { salt?: Buffer; raw?: boolean; type?: 0 | 1 | 2 }) => Promise<string>;
|
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
import { ArrayBuffers } from '@wener/utils';
|
|
2
|
-
import { Password } from './Password';
|
|
2
|
+
import type { Password } from './Password';
|
|
3
3
|
|
|
4
4
|
export function createBase64PasswordAlgorithm({ id = 'base64' }: { id?: string } = {}): Password.PasswordAlgorithm {
|
|
5
5
|
return {
|
|
@@ -7,7 +7,7 @@ export function createBase64PasswordAlgorithm({ id = 'base64' }: { id?: string }
|
|
|
7
7
|
async hash(password: string) {
|
|
8
8
|
return `$${id}$$${ArrayBuffers.toBase64(password).replace(/=/g, '')}`;
|
|
9
9
|
},
|
|
10
|
-
async verify(password: string,
|
|
10
|
+
async verify(password: string, _hash: string, opts) {
|
|
11
11
|
return Boolean(opts.hash) && ArrayBuffers.toString(opts.hash!) === password;
|
|
12
12
|
},
|
|
13
13
|
};
|
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
import type { MaybePromise } from '@wener/utils';
|
|
2
|
-
import { Password } from './Password';
|
|
2
|
+
import type { Password } from './Password';
|
|
3
3
|
|
|
4
4
|
type ProviderType = () => MaybePromise<{
|
|
5
5
|
hash: (password: string, rounds: number | string) => Promise<string>;
|
|
@@ -9,7 +9,9 @@ type ProviderType = () => MaybePromise<{
|
|
|
9
9
|
export function createBcryptPasswordAlgorithm({
|
|
10
10
|
// provider = () => import('bcrypt').then((v) => v.default),
|
|
11
11
|
provider = () => import('bcryptjs').then((v) => v.default),
|
|
12
|
-
}: {
|
|
12
|
+
}: {
|
|
13
|
+
provider?: ProviderType;
|
|
14
|
+
} = {}): Password.PasswordAlgorithm {
|
|
13
15
|
// bcrypt or bcryptjs
|
|
14
16
|
return {
|
|
15
17
|
name: 'bcrypt',
|
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
import { Errors } from '@wener/utils';
|
|
2
|
-
import { Password } from './Password';
|
|
2
|
+
import type { Password } from './Password';
|
|
3
3
|
import { PHC } from './PHC';
|
|
4
4
|
|
|
5
5
|
export function createPBKDF2PasswordAlgorithm({
|
|
@@ -33,7 +33,7 @@ export function createPBKDF2PasswordAlgorithm({
|
|
|
33
33
|
'deriveBits',
|
|
34
34
|
]);
|
|
35
35
|
let hash = await crypto.subtle.deriveBits(
|
|
36
|
-
{ name: 'PBKDF2', iterations: rounds, salt, hash: digest },
|
|
36
|
+
{ name: 'PBKDF2', iterations: rounds, salt: salt as BufferSource, hash: digest },
|
|
37
37
|
key,
|
|
38
38
|
keylen * 8,
|
|
39
39
|
);
|
|
@@ -51,11 +51,11 @@ export function createPBKDF2PasswordAlgorithm({
|
|
|
51
51
|
'deriveBits',
|
|
52
52
|
]);
|
|
53
53
|
let hash = await crypto.subtle.deriveBits(
|
|
54
|
-
{ name: 'PBKDF2', iterations: rounds, salt, hash: digest },
|
|
54
|
+
{ name: 'PBKDF2', iterations: rounds, salt: salt as BufferSource, hash: digest },
|
|
55
55
|
key,
|
|
56
56
|
storedHash.length * 8,
|
|
57
57
|
);
|
|
58
|
-
return new Uint8Array(hash).every((v, i) => v === storedHash
|
|
58
|
+
return new Uint8Array(hash).every((v, i) => v === storedHash?.[i]);
|
|
59
59
|
},
|
|
60
60
|
};
|
|
61
61
|
}
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
import { randomBytes, scrypt, timingSafeEqual } from 'node:crypto';
|
|
2
2
|
import { Errors } from '@wener/utils';
|
|
3
|
-
import { Password } from './Password';
|
|
3
|
+
import type { Password } from './Password';
|
|
4
4
|
import { PHC } from './PHC';
|
|
5
5
|
|
|
6
6
|
export function createScryptPasswordAlgorithm(
|
|
@@ -14,7 +14,7 @@ export function createScryptPasswordAlgorithm(
|
|
|
14
14
|
} = {},
|
|
15
15
|
): Password.PasswordAlgorithm {
|
|
16
16
|
let id = options.id || 'scrypt';
|
|
17
|
-
options.cost ||=
|
|
17
|
+
options.cost ||= 2 ** 14;
|
|
18
18
|
options.blocksize ||= 8;
|
|
19
19
|
options.parallelism ||= 1;
|
|
20
20
|
options.saltlen ||= 16;
|
|
@@ -35,7 +35,7 @@ export function createScryptPasswordAlgorithm(
|
|
|
35
35
|
});
|
|
36
36
|
},
|
|
37
37
|
|
|
38
|
-
async verify(password: string,
|
|
38
|
+
async verify(password: string, _hash: string, opts): Promise<boolean> {
|
|
39
39
|
try {
|
|
40
40
|
const salt = Errors.BadRequest.require(opts.salt);
|
|
41
41
|
const storedHash = Errors.BadRequest.require(opts.hash);
|
|
@@ -53,7 +53,7 @@ export function createScryptPasswordAlgorithm(
|
|
|
53
53
|
resolve(isMatch);
|
|
54
54
|
});
|
|
55
55
|
});
|
|
56
|
-
} catch (
|
|
56
|
+
} catch (_error) {
|
|
57
57
|
return Promise.resolve(false);
|
|
58
58
|
}
|
|
59
59
|
},
|
|
@@ -25,7 +25,10 @@ export const ListQuerySchema = z.object({
|
|
|
25
25
|
deleted: z.coerce.boolean().optional(),
|
|
26
26
|
});
|
|
27
27
|
|
|
28
|
-
type ListQueryOverride =
|
|
28
|
+
type ListQueryOverride =
|
|
29
|
+
| ListQueryInput
|
|
30
|
+
| undefined
|
|
31
|
+
| ((input: ListQueryInput) => ListQueryInput | undefined | undefined);
|
|
29
32
|
|
|
30
33
|
export function resolveListQuery(target: ListQueryInput | undefined, ...args: ListQueryOverride[]): ListQuery {
|
|
31
34
|
let out = args.reduce((a: ListQueryInput, source) => {
|
package/src/resource/index.ts
CHANGED
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
export {
|
|
2
|
-
export {
|
|
1
|
+
export type { AnyResource } from './schema/AnyResourceSchema';
|
|
2
|
+
export type { Identifiable } from './Identifiable';
|
|
3
3
|
export { getTitleOfResource } from './getTitleOfResource';
|
|
4
4
|
export { type ListQueryInput, type ListQuery, resolveListQuery, ListQuerySchema } from './ListQuery';
|
|
@@ -2,9 +2,23 @@ import { z } from 'zod/v4';
|
|
|
2
2
|
import { SexTypeSchema } from '../../foundation/schema/SexType';
|
|
3
3
|
import { rz } from './types';
|
|
4
4
|
|
|
5
|
-
export type AnyResource = z.infer<typeof AnyResourceSchema
|
|
5
|
+
export type AnyResource = z.infer<typeof AnyResourceSchema> & {
|
|
6
|
+
owner?: AnyResource;
|
|
7
|
+
|
|
8
|
+
entity?: AnyResource;
|
|
9
|
+
|
|
10
|
+
customer?: AnyResource;
|
|
11
|
+
account?: AnyResource;
|
|
12
|
+
contact?: AnyResource;
|
|
13
|
+
|
|
14
|
+
user?: AnyResource;
|
|
15
|
+
createdBy?: AnyResource;
|
|
16
|
+
updatedBy?: AnyResource;
|
|
17
|
+
deletedBy?: AnyResource;
|
|
18
|
+
};
|
|
19
|
+
|
|
6
20
|
export const AnyResourceSchema = z
|
|
7
|
-
.
|
|
21
|
+
.looseObject({
|
|
8
22
|
id: rz.resourceId.readonly().describe('ID'),
|
|
9
23
|
uid: z.guid().nullish().readonly().describe('唯一ID'),
|
|
10
24
|
tid: rz.resourceId.nullish().readonly().describe('租户ID'),
|
|
@@ -0,0 +1,254 @@
|
|
|
1
|
+
import { describe, expect, it } from 'vitest';
|
|
2
|
+
import { formatS3Url } from './formatS3Url';
|
|
3
|
+
import type { ParsedS3Options } from './parseS3Url';
|
|
4
|
+
|
|
5
|
+
describe('formatS3Url', () => {
|
|
6
|
+
it('should format basic S3 URL with default endpoint', () => {
|
|
7
|
+
const options: ParsedS3Options = {
|
|
8
|
+
endpoint: 's3.amazonaws.com',
|
|
9
|
+
};
|
|
10
|
+
const result = formatS3Url(options);
|
|
11
|
+
expect(result).toBe('https://s3.amazonaws.com/');
|
|
12
|
+
});
|
|
13
|
+
|
|
14
|
+
it('should format S3 URL with custom endpoint', () => {
|
|
15
|
+
const options: ParsedS3Options = {
|
|
16
|
+
endpoint: 'custom-s3.com',
|
|
17
|
+
};
|
|
18
|
+
const result = formatS3Url(options);
|
|
19
|
+
expect(result).toBe('https://custom-s3.com/');
|
|
20
|
+
});
|
|
21
|
+
|
|
22
|
+
it('should format S3 URL with HTTP protocol', () => {
|
|
23
|
+
const options: ParsedS3Options = {
|
|
24
|
+
endpoint: 's3.amazonaws.com',
|
|
25
|
+
useSsl: false,
|
|
26
|
+
};
|
|
27
|
+
const result = formatS3Url(options);
|
|
28
|
+
expect(result).toBe('http://s3.amazonaws.com/');
|
|
29
|
+
});
|
|
30
|
+
|
|
31
|
+
it('should format S3 URL with port', () => {
|
|
32
|
+
const options: ParsedS3Options = {
|
|
33
|
+
endpoint: 's3.amazonaws.com',
|
|
34
|
+
port: 9000,
|
|
35
|
+
};
|
|
36
|
+
const result = formatS3Url(options);
|
|
37
|
+
expect(result).toBe('https://s3.amazonaws.com:9000/');
|
|
38
|
+
});
|
|
39
|
+
|
|
40
|
+
it('should format S3 URL with bucket in path style', () => {
|
|
41
|
+
const options: ParsedS3Options = {
|
|
42
|
+
endpoint: 's3.amazonaws.com',
|
|
43
|
+
bucket: 'my-bucket',
|
|
44
|
+
pathStyle: true,
|
|
45
|
+
};
|
|
46
|
+
const result = formatS3Url(options);
|
|
47
|
+
expect(result).toBe('https://s3.amazonaws.com/my-bucket/');
|
|
48
|
+
});
|
|
49
|
+
|
|
50
|
+
it('should format S3 URL with bucket in virtual hosted style', () => {
|
|
51
|
+
const options: ParsedS3Options = {
|
|
52
|
+
endpoint: 's3.amazonaws.com',
|
|
53
|
+
bucket: 'my-bucket',
|
|
54
|
+
pathStyle: false,
|
|
55
|
+
};
|
|
56
|
+
const result = formatS3Url(options);
|
|
57
|
+
expect(result).toBe('https://my-bucket.s3.amazonaws.com/');
|
|
58
|
+
});
|
|
59
|
+
|
|
60
|
+
it('should format S3 URL with credentials', () => {
|
|
61
|
+
const options: ParsedS3Options = {
|
|
62
|
+
endpoint: 's3.amazonaws.com',
|
|
63
|
+
accessKeyId: 'user',
|
|
64
|
+
secretAccessKey: 'pass',
|
|
65
|
+
};
|
|
66
|
+
const result = formatS3Url(options, { credentials: true });
|
|
67
|
+
expect(result).toBe('https://user:pass@s3.amazonaws.com/');
|
|
68
|
+
});
|
|
69
|
+
|
|
70
|
+
it('should format S3 URL with credentials and special characters', () => {
|
|
71
|
+
const options: ParsedS3Options = {
|
|
72
|
+
endpoint: 's3.amazonaws.com',
|
|
73
|
+
accessKeyId: 'user@example.com',
|
|
74
|
+
secretAccessKey: 'pass/word',
|
|
75
|
+
};
|
|
76
|
+
const result = formatS3Url(options, { credentials: true });
|
|
77
|
+
expect(result).toBe('https://user%40example.com:pass%2Fword@s3.amazonaws.com/');
|
|
78
|
+
});
|
|
79
|
+
|
|
80
|
+
it('should format S3 URL with region in query parameters', () => {
|
|
81
|
+
const options: ParsedS3Options = {
|
|
82
|
+
endpoint: 's3.amazonaws.com',
|
|
83
|
+
region: 'us-east-1',
|
|
84
|
+
};
|
|
85
|
+
const result = formatS3Url(options, { useParams: true });
|
|
86
|
+
expect(result).toBe('https://s3.amazonaws.com/?region=us-east-1');
|
|
87
|
+
});
|
|
88
|
+
|
|
89
|
+
it('should format S3 URL with pathStyle in query parameters', () => {
|
|
90
|
+
const options: ParsedS3Options = {
|
|
91
|
+
endpoint: 's3.amazonaws.com',
|
|
92
|
+
pathStyle: true,
|
|
93
|
+
};
|
|
94
|
+
const result = formatS3Url(options, { useParams: true });
|
|
95
|
+
expect(result).toBe('https://s3.amazonaws.com/?pathStyle=true');
|
|
96
|
+
});
|
|
97
|
+
|
|
98
|
+
it('should format S3 URL with all parameters', () => {
|
|
99
|
+
const options: ParsedS3Options = {
|
|
100
|
+
endpoint: 's3.amazonaws.com',
|
|
101
|
+
accessKeyId: 'user',
|
|
102
|
+
secretAccessKey: 'pass',
|
|
103
|
+
region: 'us-east-1',
|
|
104
|
+
port: 9000,
|
|
105
|
+
bucket: 'my-bucket',
|
|
106
|
+
pathStyle: true,
|
|
107
|
+
useSsl: true,
|
|
108
|
+
};
|
|
109
|
+
const result = formatS3Url(options, { credentials: true, useParams: true });
|
|
110
|
+
expect(result).toBe('https://user:pass@s3.amazonaws.com:9000/my-bucket/?region=us-east-1&pathStyle=true');
|
|
111
|
+
});
|
|
112
|
+
|
|
113
|
+
it('should handle full URL as endpoint', () => {
|
|
114
|
+
const options: ParsedS3Options = {
|
|
115
|
+
endpoint: 'https://custom-s3.com:9000',
|
|
116
|
+
bucket: 'my-bucket',
|
|
117
|
+
pathStyle: true,
|
|
118
|
+
};
|
|
119
|
+
const result = formatS3Url(options);
|
|
120
|
+
expect(result).toBe('https://custom-s3.com:9000/my-bucket/');
|
|
121
|
+
});
|
|
122
|
+
|
|
123
|
+
it('should handle complex virtual hosted style with existing bucket in hostname', () => {
|
|
124
|
+
const options: ParsedS3Options = {
|
|
125
|
+
endpoint: 'my-bucket.s3.amazonaws.com',
|
|
126
|
+
bucket: 'my-bucket',
|
|
127
|
+
pathStyle: false,
|
|
128
|
+
};
|
|
129
|
+
const result = formatS3Url(options);
|
|
130
|
+
expect(result).toBe('https://my-bucket.s3.amazonaws.com/');
|
|
131
|
+
});
|
|
132
|
+
|
|
133
|
+
it('should throw error for missing endpoint', () => {
|
|
134
|
+
const options = {} as ParsedS3Options;
|
|
135
|
+
expect(() => formatS3Url(options)).toThrow('Endpoint is required');
|
|
136
|
+
});
|
|
137
|
+
|
|
138
|
+
it('should handle endpoint without protocol by adding https://', () => {
|
|
139
|
+
const options: ParsedS3Options = {
|
|
140
|
+
endpoint: 'custom-s3.com',
|
|
141
|
+
};
|
|
142
|
+
const result = formatS3Url(options);
|
|
143
|
+
expect(result).toBe('https://custom-s3.com/');
|
|
144
|
+
});
|
|
145
|
+
|
|
146
|
+
it('should throw error for missing credentials when credentials=true', () => {
|
|
147
|
+
const options: ParsedS3Options = {
|
|
148
|
+
endpoint: 's3.amazonaws.com',
|
|
149
|
+
accessKeyId: 'user',
|
|
150
|
+
};
|
|
151
|
+
expect(() => formatS3Url(options, { credentials: true })).toThrow(
|
|
152
|
+
'Access Key ID and Secret Access Key are required for credentials',
|
|
153
|
+
);
|
|
154
|
+
});
|
|
155
|
+
|
|
156
|
+
it('should throw error for invalid port', () => {
|
|
157
|
+
const options: ParsedS3Options = {
|
|
158
|
+
endpoint: 's3.amazonaws.com',
|
|
159
|
+
port: 99999,
|
|
160
|
+
};
|
|
161
|
+
expect(() => formatS3Url(options)).toThrow('Port must be a valid number between 1 and 65535');
|
|
162
|
+
});
|
|
163
|
+
|
|
164
|
+
it('should throw error for invalid bucket name', () => {
|
|
165
|
+
const options: ParsedS3Options = {
|
|
166
|
+
endpoint: 's3.amazonaws.com',
|
|
167
|
+
bucket: 'Invalid Bucket Name',
|
|
168
|
+
};
|
|
169
|
+
expect(() => formatS3Url(options)).toThrow('Invalid bucket name: Invalid Bucket Name');
|
|
170
|
+
});
|
|
171
|
+
|
|
172
|
+
it('should throw error for bucket name with consecutive dots', () => {
|
|
173
|
+
const options: ParsedS3Options = {
|
|
174
|
+
endpoint: 's3.amazonaws.com',
|
|
175
|
+
bucket: 'my..bucket',
|
|
176
|
+
};
|
|
177
|
+
expect(() => formatS3Url(options)).toThrow('Invalid bucket name: my..bucket');
|
|
178
|
+
});
|
|
179
|
+
|
|
180
|
+
it('should throw error for bucket name with hyphen at start', () => {
|
|
181
|
+
const options: ParsedS3Options = {
|
|
182
|
+
endpoint: 's3.amazonaws.com',
|
|
183
|
+
bucket: '-mybucket',
|
|
184
|
+
};
|
|
185
|
+
expect(() => formatS3Url(options)).toThrow('Invalid bucket name: -mybucket');
|
|
186
|
+
});
|
|
187
|
+
|
|
188
|
+
it('should throw error for bucket name with hyphen at end', () => {
|
|
189
|
+
const options: ParsedS3Options = {
|
|
190
|
+
endpoint: 's3.amazonaws.com',
|
|
191
|
+
bucket: 'mybucket-',
|
|
192
|
+
};
|
|
193
|
+
expect(() => formatS3Url(options)).toThrow('Invalid bucket name: mybucket-');
|
|
194
|
+
});
|
|
195
|
+
|
|
196
|
+
it('should handle bucket name with dot-hyphen (currently allowed)', () => {
|
|
197
|
+
const options: ParsedS3Options = {
|
|
198
|
+
endpoint: 's3.amazonaws.com',
|
|
199
|
+
bucket: 'my.bucket-name',
|
|
200
|
+
pathStyle: true,
|
|
201
|
+
};
|
|
202
|
+
const result = formatS3Url(options);
|
|
203
|
+
expect(result).toBe('https://s3.amazonaws.com/my.bucket-name/');
|
|
204
|
+
});
|
|
205
|
+
|
|
206
|
+
it('should throw error for bucket name that is too short', () => {
|
|
207
|
+
const options: ParsedS3Options = {
|
|
208
|
+
endpoint: 's3.amazonaws.com',
|
|
209
|
+
bucket: 'ab',
|
|
210
|
+
};
|
|
211
|
+
expect(() => formatS3Url(options)).toThrow('Invalid bucket name: ab');
|
|
212
|
+
});
|
|
213
|
+
|
|
214
|
+
it('should throw error for bucket name that is too long', () => {
|
|
215
|
+
const options: ParsedS3Options = {
|
|
216
|
+
endpoint: 's3.amazonaws.com',
|
|
217
|
+
bucket: 'a'.repeat(64),
|
|
218
|
+
};
|
|
219
|
+
expect(() => formatS3Url(options)).toThrow(`Invalid bucket name: ${'a'.repeat(64)}`);
|
|
220
|
+
});
|
|
221
|
+
|
|
222
|
+
it('should handle valid bucket names with various formats', () => {
|
|
223
|
+
const validBuckets = ['my-bucket', 'my.bucket', 'mybucket123', '123bucket', 'test-bucket-123'];
|
|
224
|
+
|
|
225
|
+
validBuckets.forEach((bucket) => {
|
|
226
|
+
const options: ParsedS3Options = {
|
|
227
|
+
endpoint: 's3.amazonaws.com',
|
|
228
|
+
bucket,
|
|
229
|
+
pathStyle: true,
|
|
230
|
+
};
|
|
231
|
+
expect(() => formatS3Url(options)).not.toThrow();
|
|
232
|
+
});
|
|
233
|
+
});
|
|
234
|
+
|
|
235
|
+
it('should handle pathname concatenation correctly in path style', () => {
|
|
236
|
+
const options: ParsedS3Options = {
|
|
237
|
+
endpoint: 'https://s3.amazonaws.com/path/to/something',
|
|
238
|
+
bucket: 'my-bucket',
|
|
239
|
+
pathStyle: true,
|
|
240
|
+
};
|
|
241
|
+
const result = formatS3Url(options);
|
|
242
|
+
expect(result).toBe('https://s3.amazonaws.com/my-bucket/path/to/something');
|
|
243
|
+
});
|
|
244
|
+
|
|
245
|
+
it('should handle URL with existing pathname in virtual hosted style', () => {
|
|
246
|
+
const options: ParsedS3Options = {
|
|
247
|
+
endpoint: 'https://s3.amazonaws.com/path/to/something',
|
|
248
|
+
bucket: 'my-bucket',
|
|
249
|
+
pathStyle: false,
|
|
250
|
+
};
|
|
251
|
+
const result = formatS3Url(options);
|
|
252
|
+
expect(result).toBe('https://my-bucket.s3.amazonaws.com/path/to/something');
|
|
253
|
+
});
|
|
254
|
+
});
|