@wener/common 2.0.5 → 2.0.6

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.
Files changed (206) hide show
  1. package/lib/ai/qwen3vl/index.js +1 -1
  2. package/lib/ai/qwen3vl/utils.js +15 -15
  3. package/lib/ai/vision/DocLayoutElementTypeSchema.js +22 -22
  4. package/lib/ai/vision/ImageAnnotationSchema.js +63 -47
  5. package/lib/ai/vision/index.js +2 -2
  6. package/lib/ai/vision/resolveImageAnnotation.js +81 -95
  7. package/lib/cn/ChineseResidentIdNo.js +55 -41
  8. package/lib/cn/ChineseResidentIdNo.mod.js +6 -1
  9. package/lib/cn/ChineseResidentIdNo.test.js +22 -21
  10. package/lib/cn/DivisionCode.js +220 -235
  11. package/lib/cn/DivisionCode.mod.js +6 -1
  12. package/lib/cn/DivisionCode.test.js +92 -121
  13. package/lib/cn/Mod11.js +18 -37
  14. package/lib/cn/Mod31.js +23 -41
  15. package/lib/cn/UnifiedSocialCreditCode.js +143 -137
  16. package/lib/cn/UnifiedSocialCreditCode.mod.js +6 -1
  17. package/lib/cn/UnifiedSocialCreditCode.test.js +21 -15
  18. package/lib/cn/formatChineseAmount.js +46 -71
  19. package/lib/cn/index.js +6 -6
  20. package/lib/cn/mod.js +5 -3
  21. package/lib/cn/parseChineseNumber.js +81 -85
  22. package/lib/cn/parseChineseNumber.test.js +183 -261
  23. package/lib/cn/pinyin/cartesianProduct.js +19 -19
  24. package/lib/cn/pinyin/cartesianProduct.test.js +78 -178
  25. package/lib/cn/pinyin/loader.js +13 -11
  26. package/lib/cn/pinyin/preload.js +2 -1
  27. package/lib/cn/pinyin/toPinyin.test.js +149 -161
  28. package/lib/cn/pinyin/toPinyinPure.js +28 -23
  29. package/lib/cn/pinyin/transform.js +11 -11
  30. package/lib/cn/types.d.js +2 -2
  31. package/lib/consola/createStandardConsolaReporter.js +14 -15
  32. package/lib/consola/formatLogObject.js +149 -133
  33. package/lib/consola/formatLogObject.test.js +167 -178
  34. package/lib/consola/index.js +2 -2
  35. package/lib/data/formatSort.js +14 -12
  36. package/lib/data/formatSort.test.js +33 -33
  37. package/lib/data/index.js +3 -3
  38. package/lib/data/maybeNumber.js +23 -23
  39. package/lib/data/parseSort.js +75 -68
  40. package/lib/data/parseSort.test.js +196 -187
  41. package/lib/data/resolvePagination.js +38 -39
  42. package/lib/data/resolvePagination.test.js +228 -218
  43. package/lib/data/types.d.js +2 -2
  44. package/lib/dayjs/dayjs.js +20 -20
  45. package/lib/dayjs/formatDuration.js +56 -56
  46. package/lib/dayjs/formatDuration.test.js +63 -77
  47. package/lib/dayjs/index.js +4 -4
  48. package/lib/dayjs/parseDuration.js +21 -26
  49. package/lib/dayjs/parseRelativeTime.js +65 -66
  50. package/lib/dayjs/parseRelativeTime.test.js +227 -243
  51. package/lib/dayjs/resolveRelativeTime.js +73 -72
  52. package/lib/dayjs/resolveRelativeTime.test.js +296 -307
  53. package/lib/decimal/index.js +1 -1
  54. package/lib/decimal/parseDecimal.js +12 -12
  55. package/lib/drain3/Drain.js +303 -338
  56. package/lib/drain3/LogCluster.js +25 -25
  57. package/lib/drain3/Node.js +24 -24
  58. package/lib/drain3/TemplateMiner.js +197 -196
  59. package/lib/drain3/index.js +5 -5
  60. package/lib/drain3/persistence/FilePersistence.js +19 -19
  61. package/lib/drain3/persistence/MemoryPersistence.js +8 -8
  62. package/lib/drain3/persistence/PersistenceHandler.js +2 -2
  63. package/lib/drain3/types.js +2 -2
  64. package/lib/emittery/emitter.js +7 -7
  65. package/lib/emittery/index.js +1 -1
  66. package/lib/foundation/schema/SexType.js +15 -12
  67. package/lib/foundation/schema/index.js +1 -1
  68. package/lib/foundation/schema/parseSexType.js +15 -16
  69. package/lib/foundation/schema/types.js +8 -6
  70. package/lib/fs/FileSystemError.js +18 -18
  71. package/lib/fs/IFileSystem.d.js +2 -2
  72. package/lib/fs/MemoryFileSystem.test.js +172 -181
  73. package/lib/fs/createBrowserFileSystem.js +222 -235
  74. package/lib/fs/createMemoryFileSystem.js +472 -510
  75. package/lib/fs/createSandboxFileSystem.js +102 -101
  76. package/lib/fs/createWebDavFileSystem.js +162 -149
  77. package/lib/fs/createWebFileSystem.js +197 -220
  78. package/lib/fs/findMimeType.js +14 -14
  79. package/lib/fs/index.js +7 -7
  80. package/lib/fs/minio/createMinioFileSystem.js +959 -956
  81. package/lib/fs/minio/index.js +1 -1
  82. package/lib/fs/orpc/FileSystemContract.js +57 -57
  83. package/lib/fs/orpc/createContractClientFileSystem.js +88 -88
  84. package/lib/fs/orpc/index.js +2 -2
  85. package/lib/fs/orpc/server/createFileSystemContractImpl.js +62 -60
  86. package/lib/fs/orpc/server/index.js +1 -1
  87. package/lib/fs/s3/createS3MiniFileSystem.js +756 -737
  88. package/lib/fs/s3/index.js +1 -1
  89. package/lib/fs/s3/s3mini.test.js +524 -553
  90. package/lib/fs/scandir.js +56 -56
  91. package/lib/fs/server/createDatabaseFileSystem.js +834 -741
  92. package/lib/fs/server/createNodeFileSystem.js +407 -405
  93. package/lib/fs/server/dbfs.test.js +201 -214
  94. package/lib/fs/server/index.js +1 -1
  95. package/lib/fs/server/loadTestDatabase.js +40 -43
  96. package/lib/fs/tests/runFileSystemTest.js +352 -316
  97. package/lib/fs/types.js +17 -20
  98. package/lib/fs/utils/getFileUrl.js +24 -30
  99. package/lib/fs/utils.js +17 -17
  100. package/lib/fs/webdav/index.js +1 -1
  101. package/lib/index.js +2 -2
  102. package/lib/jsonschema/JsonSchema.js +216 -155
  103. package/lib/jsonschema/JsonSchema.test.js +123 -124
  104. package/lib/jsonschema/forEachJsonSchema.js +41 -41
  105. package/lib/jsonschema/index.js +2 -2
  106. package/lib/jsonschema/types.d.js +2 -2
  107. package/lib/meta/defineFileType.js +32 -38
  108. package/lib/meta/defineInit.js +39 -35
  109. package/lib/meta/defineMetadata.js +37 -34
  110. package/lib/meta/defineMetadata.test.js +13 -12
  111. package/lib/meta/index.js +3 -3
  112. package/lib/orpc/createOpenApiContractClient.js +26 -24
  113. package/lib/orpc/createRpcContractClient.js +37 -31
  114. package/lib/orpc/index.js +2 -2
  115. package/lib/orpc/resolveLinkPlugins.js +25 -25
  116. package/lib/password/PHC.js +187 -189
  117. package/lib/password/PHC.test.js +517 -535
  118. package/lib/password/Password.js +85 -80
  119. package/lib/password/Password.test.js +330 -364
  120. package/lib/password/createArgon2PasswordAlgorithm.js +50 -51
  121. package/lib/password/createBase64PasswordAlgorithm.js +11 -11
  122. package/lib/password/createBcryptPasswordAlgorithm.js +20 -18
  123. package/lib/password/createPBKDF2PasswordAlgorithm.js +65 -52
  124. package/lib/password/createScryptPasswordAlgorithm.js +74 -63
  125. package/lib/password/index.js +5 -5
  126. package/lib/password/server/index.js +1 -1
  127. package/lib/resource/Identifiable.js +2 -2
  128. package/lib/resource/ListQuery.js +42 -42
  129. package/lib/resource/getTitleOfResource.js +5 -5
  130. package/lib/resource/index.js +2 -2
  131. package/lib/resource/schema/AnyResourceSchema.js +91 -89
  132. package/lib/resource/schema/BaseResourceSchema.js +26 -26
  133. package/lib/resource/schema/ResourceActionType.js +117 -115
  134. package/lib/resource/schema/ResourceStatus.js +94 -92
  135. package/lib/resource/schema/ResourceType.js +25 -23
  136. package/lib/resource/schema/index.js +5 -5
  137. package/lib/resource/schema/types.js +86 -55
  138. package/lib/resource/schema/types.test.js +16 -13
  139. package/lib/s3/formatS3Url.js +60 -60
  140. package/lib/s3/formatS3Url.test.js +238 -261
  141. package/lib/s3/index.js +2 -2
  142. package/lib/s3/parseS3Url.js +61 -60
  143. package/lib/s3/parseS3Url.test.js +270 -269
  144. package/lib/schema/SchemaRegistry.js +41 -42
  145. package/lib/schema/SchemaRegistry.mod.js +1 -1
  146. package/lib/schema/TypeSchema.d.js +2 -2
  147. package/lib/schema/createSchemaData.js +113 -67
  148. package/lib/schema/findJsonSchemaByPath.js +28 -23
  149. package/lib/schema/formatZodError.js +112 -131
  150. package/lib/schema/formatZodError.test.js +192 -195
  151. package/lib/schema/getSchemaCache.js +7 -7
  152. package/lib/schema/getSchemaOptions.js +17 -16
  153. package/lib/schema/index.js +6 -6
  154. package/lib/schema/toJsonSchema.js +195 -189
  155. package/lib/schema/toJsonSchema.test.js +34 -26
  156. package/lib/schema/validate.js +105 -96
  157. package/lib/tools/generateSchema.js +40 -40
  158. package/lib/tools/renderJsonSchemaToMarkdownDoc.js +74 -74
  159. package/lib/utils/buildBaseUrl.js +8 -8
  160. package/lib/utils/buildRedactorFormSchema.js +54 -53
  161. package/lib/utils/getEstimateProcessTime.js +24 -19
  162. package/lib/utils/index.js +3 -3
  163. package/lib/utils/resolveFeatureOptions.js +9 -9
  164. package/package.json +14 -14
  165. package/src/ai/vision/index.ts +2 -2
  166. package/src/cn/index.ts +1 -2
  167. package/src/consola/index.ts +1 -1
  168. package/src/data/index.ts +3 -4
  169. package/src/data/resolvePagination.ts +2 -2
  170. package/src/dayjs/formatDuration.ts +8 -9
  171. package/src/dayjs/index.ts +1 -1
  172. package/src/dayjs/parseRelativeTime.ts +1 -1
  173. package/src/dayjs/resolveRelativeTime.ts +1 -1
  174. package/src/drain3/Drain.test.ts +2 -2
  175. package/src/drain3/index.ts +2 -4
  176. package/src/fs/createWebDavFileSystem.ts +2 -7
  177. package/src/fs/createWebFileSystem.ts +1 -1
  178. package/src/fs/index.ts +4 -4
  179. package/src/fs/minio/createMinioFileSystem.ts +2 -2
  180. package/src/fs/minio/index.ts +1 -1
  181. package/src/fs/s3/createS3MiniFileSystem.ts +1 -1
  182. package/src/fs/server/createDatabaseFileSystem.ts +84 -120
  183. package/src/fs/server/dbfs.test.ts +14 -10
  184. package/src/fs/server/index.ts +1 -0
  185. package/src/fs/server/loadTestDatabase.ts +8 -119
  186. package/src/jsonschema/index.ts +1 -1
  187. package/src/meta/index.ts +2 -3
  188. package/src/orm/createSqliteDialect.ts +17 -0
  189. package/src/orm/index.ts +1 -0
  190. package/src/orpc/createOpenApiContractClient.ts +1 -1
  191. package/src/orpc/index.ts +1 -1
  192. package/src/password/createArgon2PasswordAlgorithm.ts +1 -1
  193. package/src/password/index.ts +2 -2
  194. package/src/resource/index.ts +3 -3
  195. package/src/resource/schema/index.ts +4 -4
  196. package/src/s3/index.ts +1 -1
  197. package/src/schema/SchemaRegistry.ts +1 -1
  198. package/src/schema/createSchemaData.ts +1 -1
  199. package/src/schema/findJsonSchemaByPath.ts +1 -1
  200. package/src/schema/index.ts +5 -5
  201. package/src/schema/validate.ts +1 -1
  202. package/src/utils/buildRedactorFormSchema.ts +1 -1
  203. package/src/utils/formatNumber.ts +18 -0
  204. package/src/utils/formatPercent.ts +17 -0
  205. package/src/utils/index.ts +3 -3
  206. package/src/utils/resolveFeatureOptions.ts +1 -1
@@ -1,27 +1,29 @@
1
- import { createORPCClient } from "@orpc/client";
2
- import { OpenAPILink } from "@orpc/openapi-client/fetch";
3
- import { buildBaseUrl } from "../utils/buildBaseUrl.js";
4
- import { resolveLinkPlugins } from "./resolveLinkPlugins.js";
1
+ import { createORPCClient } from '@orpc/client';
2
+ import { OpenAPILink } from '@orpc/openapi-client/fetch';
3
+ import { buildBaseUrl } from '../utils/buildBaseUrl.js';
4
+ import { resolveLinkPlugins } from './resolveLinkPlugins.js';
5
5
  export function createOpenApiContractClient(contract, options) {
6
- let { url, baseUrl, apiKey, getApiKey, getHeaders } = options;
7
- const baseHeaders = new Headers(options.headers);
8
- if (apiKey) {
9
- baseHeaders.set("Authorization", `Bearer ${apiKey}`);
10
- }
11
- url = buildBaseUrl(url, baseUrl);
12
- return createORPCClient(new OpenAPILink(contract, {
13
- url,
14
- headers: () => {
15
- let headers = new Headers(baseHeaders);
16
- let accessToken = getApiKey?.();
17
- if (accessToken) {
18
- headers.set("Authorization", `Bearer ${accessToken}`);
19
- }
20
- headers = getHeaders?.(headers) ?? headers;
21
- return headers;
22
- },
23
- plugins: resolveLinkPlugins(options),
24
- fetch: options.fetch
25
- }));
6
+ let { url, baseUrl, apiKey, getApiKey, getHeaders } = options;
7
+ const baseHeaders = new Headers(options.headers);
8
+ if (apiKey) {
9
+ baseHeaders.set('Authorization', `Bearer ${apiKey}`);
10
+ }
11
+ url = buildBaseUrl(url, baseUrl);
12
+ return createORPCClient(
13
+ new OpenAPILink(contract, {
14
+ url,
15
+ headers: () => {
16
+ let headers = new Headers(baseHeaders);
17
+ let accessToken = getApiKey?.();
18
+ if (accessToken) {
19
+ headers.set('Authorization', `Bearer ${accessToken}`);
20
+ }
21
+ headers = getHeaders?.(headers) ?? headers;
22
+ return headers;
23
+ },
24
+ plugins: resolveLinkPlugins(options),
25
+ fetch: options.fetch,
26
+ }),
27
+ );
26
28
  }
27
29
  //# sourceMappingURL=createOpenApiContractClient.js.map
@@ -1,34 +1,40 @@
1
- import { createORPCClient } from "@orpc/client";
2
- import { RPCLink } from "@orpc/client/fetch";
3
- import { buildBaseUrl } from "../utils/buildBaseUrl.js";
4
- import { resolveLinkPlugins } from "./resolveLinkPlugins.js";
1
+ import { createORPCClient } from '@orpc/client';
2
+ import { RPCLink } from '@orpc/client/fetch';
3
+ import { buildBaseUrl } from '../utils/buildBaseUrl.js';
4
+ import { resolveLinkPlugins } from './resolveLinkPlugins.js';
5
5
  export function createRpcContractClient(options = {}) {
6
- let { url = "/api/rpc", baseUrl = globalThis.location?.origin || "http://localhost", apiKey, getApiKey, getHeaders } = options;
7
- url = buildBaseUrl(url, baseUrl);
8
- const baseHeaders = new Headers(options.headers);
9
- if (apiKey) {
10
- baseHeaders.set("Authorization", `Bearer ${apiKey}`);
11
- }
12
- const plugins = resolveLinkPlugins({
13
- dedup: true,
14
- batch: true,
15
- ...options
16
- });
17
- const link = new RPCLink({
18
- url,
19
- headers: () => {
20
- let headers = new Headers(baseHeaders);
21
- let accessToken = getApiKey?.();
22
- if (accessToken) {
23
- headers.set("Authorization", `Bearer ${accessToken}`);
24
- }
25
- headers = getHeaders?.(headers) ?? headers;
26
- return headers;
27
- },
28
- fetch: options.fetch,
29
- plugins
30
- });
31
- const client = createORPCClient(link);
32
- return client;
6
+ let {
7
+ url = '/api/rpc',
8
+ baseUrl = globalThis.location?.origin || 'http://localhost',
9
+ apiKey,
10
+ getApiKey,
11
+ getHeaders,
12
+ } = options;
13
+ url = buildBaseUrl(url, baseUrl);
14
+ const baseHeaders = new Headers(options.headers);
15
+ if (apiKey) {
16
+ baseHeaders.set('Authorization', `Bearer ${apiKey}`);
17
+ }
18
+ const plugins = resolveLinkPlugins({
19
+ dedup: true,
20
+ batch: true,
21
+ ...options,
22
+ });
23
+ const link = new RPCLink({
24
+ url,
25
+ headers: () => {
26
+ let headers = new Headers(baseHeaders);
27
+ let accessToken = getApiKey?.();
28
+ if (accessToken) {
29
+ headers.set('Authorization', `Bearer ${accessToken}`);
30
+ }
31
+ headers = getHeaders?.(headers) ?? headers;
32
+ return headers;
33
+ },
34
+ fetch: options.fetch,
35
+ plugins,
36
+ });
37
+ const client = createORPCClient(link);
38
+ return client;
33
39
  }
34
40
  //# sourceMappingURL=createRpcContractClient.js.map
package/lib/orpc/index.js CHANGED
@@ -1,3 +1,3 @@
1
- export { createRpcContractClient } from "./createRpcContractClient.js";
2
- export { createOpenApiContractClient } from "./createOpenApiContractClient.js";
1
+ export { createOpenApiContractClient } from './createOpenApiContractClient.js';
2
+ export { createRpcContractClient } from './createRpcContractClient.js';
3
3
  //# sourceMappingURL=index.js.map
@@ -1,28 +1,28 @@
1
- import { BatchLinkPlugin, DedupeRequestsPlugin } from "@orpc/client/plugins";
2
- import { resolveFeatureOptions } from "../utils/resolveFeatureOptions.js";
1
+ import { BatchLinkPlugin, DedupeRequestsPlugin } from '@orpc/client/plugins';
2
+ import { resolveFeatureOptions } from '../utils/resolveFeatureOptions.js';
3
3
  export function resolveLinkPlugins({ plugins = [], dedup, batch }) {
4
- batch = resolveFeatureOptions(batch, {
5
- groups: [
6
- {
7
- condition: () => true,
8
- context: {}
9
- }
10
- ]
11
- });
12
- if (batch) {
13
- plugins.push(new BatchLinkPlugin(batch));
14
- }
15
- dedup = resolveFeatureOptions(dedup, {
16
- groups: [
17
- {
18
- condition: () => true,
19
- context: {}
20
- }
21
- ]
22
- });
23
- if (dedup) {
24
- plugins.push(new DedupeRequestsPlugin(dedup));
25
- }
26
- return plugins;
4
+ batch = resolveFeatureOptions(batch, {
5
+ groups: [
6
+ {
7
+ condition: () => true,
8
+ context: {},
9
+ },
10
+ ],
11
+ });
12
+ if (batch) {
13
+ plugins.push(new BatchLinkPlugin(batch));
14
+ }
15
+ dedup = resolveFeatureOptions(dedup, {
16
+ groups: [
17
+ {
18
+ condition: () => true,
19
+ context: {},
20
+ },
21
+ ],
22
+ });
23
+ if (dedup) {
24
+ plugins.push(new DedupeRequestsPlugin(dedup));
25
+ }
26
+ return plugins;
27
27
  }
28
28
  //# sourceMappingURL=resolveLinkPlugins.js.map
@@ -1,195 +1,193 @@
1
- import { ArrayBuffers } from "@wener/utils";
2
- (function(PHC) {
3
- // https://github.com/simonepri/phc-format/blob/master/index.js
4
- const idRegex = /^[a-z0-9-]{1,32}$/;
5
- const nameRegex = /^[a-z0-9-]{1,32}$/;
6
- const valueRegex = /^[a-zA-Z0-9/+.-]+$/;
7
- const b64Regex = /^([a-zA-Z0-9/+.-]+|)$/;
8
- const decimalRegex = /^((-)?[1-9]\d*|0)$/;
9
- const versionRegex = /^v=(\d+)$/;
10
- const fromBase64 = ArrayBuffers.fromBase64;
11
- const toBase64 = ArrayBuffers.toBase64;
12
- const isBuffer = (v)=>{
13
- return v instanceof Uint8Array;
14
- };
15
- function objToKeyVal(obj) {
16
- return objectKeys(obj).map((k)=>[
17
- k,
18
- obj[k]
19
- ].join('=')).join(',');
20
- }
21
- function keyValtoObj(str) {
22
- const obj = {};
23
- str.split(',').forEach((ps)=>{
24
- const pss = ps.split('=');
25
- if (pss.length < 2) {
26
- throw new TypeError(`params must be in the format name=value`);
27
- }
28
- const key = pss.shift();
29
- if (key !== undefined) {
30
- obj[key] = pss.join('=');
31
- }
32
- });
33
- return obj;
34
- }
35
- function objectKeys(object) {
36
- return Object.keys(object);
37
- }
38
- function objectValues(object) {
39
- if (typeof Object.values === 'function') return Object.values(object);
40
- return objectKeys(object).map((k)=>object[k]);
41
- }
42
- function serialize(opts) {
43
- const fields = [
44
- ''
45
- ];
46
- if (typeof opts !== 'object' || opts === null) {
47
- throw new TypeError('opts must be an object');
48
- }
49
- // Identifier Validation
50
- if (typeof opts.id !== 'string') {
51
- throw new TypeError('id must be a string');
52
- }
53
- if (!idRegex.test(opts.id)) {
54
- throw new TypeError(`id must satisfy ${idRegex}`);
55
- }
56
- fields.push(opts.id);
57
- if (typeof opts.version !== 'undefined') {
58
- if (typeof opts.version !== 'number' || opts.version < 0 || !Number.isInteger(opts.version)) {
59
- throw new TypeError('version must be a positive integer number');
60
- }
61
- fields.push(`v=${opts.version}`);
62
- }
63
- // Parameters Validation
64
- if (typeof opts.params !== 'undefined') {
65
- if (typeof opts.params !== 'object' || opts.params === null) {
66
- throw new TypeError('params must be an object');
67
- }
68
- const pk = objectKeys(opts.params);
69
- if (!pk.every((p)=>nameRegex.test(p.toString()))) {
70
- throw new TypeError(`params names must satisfy ${nameRegex}`);
71
- }
72
- // Convert Numbers into Numeric Strings and Buffers into B64 encoded strings.
73
- pk.forEach((k)=>{
74
- const value = opts.params?.[k];
75
- if (typeof value === 'number') {
76
- opts.params[k] = value.toString();
77
- } else if (value instanceof Uint8Array) {
78
- opts.params[k] = toBase64(value).split('=')[0];
79
- }
80
- });
81
- const pv = objectValues(opts.params);
82
- if (!pv.every((v)=>typeof v === 'string')) {
83
- throw new TypeError('params values must be strings');
84
- }
85
- if (!pv.every((v)=>valueRegex.test(v))) {
86
- throw new TypeError(`params values must satisfy ${valueRegex}`);
87
- }
88
- const strpar = objToKeyVal(opts.params);
89
- fields.push(strpar);
90
- }
91
- if (typeof opts.salt !== 'undefined') {
92
- // Salt Validation
93
- if (!isBuffer(opts.salt)) {
94
- throw new TypeError('salt must be a Buffer');
95
- }
96
- fields.push(toBase64(opts.salt).split('=')[0]);
97
- if (typeof opts.hash !== 'undefined') {
98
- // Hash Validation
99
- if (!isBuffer(opts.hash)) {
100
- throw new TypeError('hash must be a Buffer');
101
- }
102
- fields.push(toBase64(opts.hash).split('=')[0]);
103
- }
104
- }
105
- // Create the PHC formatted string
106
- const phcstr = fields.join('$');
107
- return phcstr;
108
- }
109
- /**
1
+ import { ArrayBuffers } from '@wener/utils';
2
+
3
+ ((PHC) => {
4
+ // https://github.com/simonepri/phc-format/blob/master/index.js
5
+ const idRegex = /^[a-z0-9-]{1,32}$/;
6
+ const nameRegex = /^[a-z0-9-]{1,32}$/;
7
+ const valueRegex = /^[a-zA-Z0-9/+.-]+$/;
8
+ const b64Regex = /^([a-zA-Z0-9/+.-]+|)$/;
9
+ const decimalRegex = /^((-)?[1-9]\d*|0)$/;
10
+ const versionRegex = /^v=(\d+)$/;
11
+ const fromBase64 = ArrayBuffers.fromBase64;
12
+ const toBase64 = ArrayBuffers.toBase64;
13
+ const isBuffer = (v) => {
14
+ return v instanceof Uint8Array;
15
+ };
16
+ function objToKeyVal(obj) {
17
+ return objectKeys(obj)
18
+ .map((k) => [k, obj[k]].join('='))
19
+ .join(',');
20
+ }
21
+ function keyValtoObj(str) {
22
+ const obj = {};
23
+ str.split(',').forEach((ps) => {
24
+ const pss = ps.split('=');
25
+ if (pss.length < 2) {
26
+ throw new TypeError(`params must be in the format name=value`);
27
+ }
28
+ const key = pss.shift();
29
+ if (key !== undefined) {
30
+ obj[key] = pss.join('=');
31
+ }
32
+ });
33
+ return obj;
34
+ }
35
+ function objectKeys(object) {
36
+ return Object.keys(object);
37
+ }
38
+ function objectValues(object) {
39
+ if (typeof Object.values === 'function') return Object.values(object);
40
+ return objectKeys(object).map((k) => object[k]);
41
+ }
42
+ function serialize(opts) {
43
+ const fields = [''];
44
+ if (typeof opts !== 'object' || opts === null) {
45
+ throw new TypeError('opts must be an object');
46
+ }
47
+ // Identifier Validation
48
+ if (typeof opts.id !== 'string') {
49
+ throw new TypeError('id must be a string');
50
+ }
51
+ if (!idRegex.test(opts.id)) {
52
+ throw new TypeError(`id must satisfy ${idRegex}`);
53
+ }
54
+ fields.push(opts.id);
55
+ if (typeof opts.version !== 'undefined') {
56
+ if (typeof opts.version !== 'number' || opts.version < 0 || !Number.isInteger(opts.version)) {
57
+ throw new TypeError('version must be a positive integer number');
58
+ }
59
+ fields.push(`v=${opts.version}`);
60
+ }
61
+ // Parameters Validation
62
+ if (typeof opts.params !== 'undefined') {
63
+ if (typeof opts.params !== 'object' || opts.params === null) {
64
+ throw new TypeError('params must be an object');
65
+ }
66
+ const pk = objectKeys(opts.params);
67
+ if (!pk.every((p) => nameRegex.test(p.toString()))) {
68
+ throw new TypeError(`params names must satisfy ${nameRegex}`);
69
+ }
70
+ // Convert Numbers into Numeric Strings and Buffers into B64 encoded strings.
71
+ pk.forEach((k) => {
72
+ const value = opts.params?.[k];
73
+ if (typeof value === 'number') {
74
+ opts.params[k] = value.toString();
75
+ } else if (value instanceof Uint8Array) {
76
+ opts.params[k] = toBase64(value).split('=')[0];
77
+ }
78
+ });
79
+ const pv = objectValues(opts.params);
80
+ if (!pv.every((v) => typeof v === 'string')) {
81
+ throw new TypeError('params values must be strings');
82
+ }
83
+ if (!pv.every((v) => valueRegex.test(v))) {
84
+ throw new TypeError(`params values must satisfy ${valueRegex}`);
85
+ }
86
+ const strpar = objToKeyVal(opts.params);
87
+ fields.push(strpar);
88
+ }
89
+ if (typeof opts.salt !== 'undefined') {
90
+ // Salt Validation
91
+ if (!isBuffer(opts.salt)) {
92
+ throw new TypeError('salt must be a Buffer');
93
+ }
94
+ fields.push(toBase64(opts.salt).split('=')[0]);
95
+ if (typeof opts.hash !== 'undefined') {
96
+ // Hash Validation
97
+ if (!isBuffer(opts.hash)) {
98
+ throw new TypeError('hash must be a Buffer');
99
+ }
100
+ fields.push(toBase64(opts.hash).split('=')[0]);
101
+ }
102
+ }
103
+ // Create the PHC formatted string
104
+ const phcstr = fields.join('$');
105
+ return phcstr;
106
+ }
107
+ /**
110
108
  * Generates a PHC string using the data provided.
111
109
  * @param {SerializeOptions} opts Object that holds the data needed to generate the PHC string.
112
110
  * @return {string} The hash string adhering to the PHC format.
113
111
  */ PHC.serialize = serialize;
114
- function deserialize(phcstr) {
115
- if (typeof phcstr !== 'string' || phcstr === '') {
116
- throw new TypeError('pchstr must be a non-empty string');
117
- }
118
- if (phcstr[0] !== '$') {
119
- throw new TypeError('pchstr must contain a $ as first char');
120
- }
121
- const fields = phcstr.split('$');
122
- // Remove first empty $
123
- fields.shift();
124
- // Parse Fields
125
- let maxf = 5;
126
- if (!versionRegex.test(fields[1])) maxf--;
127
- if (fields.length > maxf) {
128
- throw new TypeError(`pchstr contains too many fileds: ${fields.length}/${maxf}`);
129
- }
130
- // Parse Identifier
131
- const id = fields.shift();
132
- if (!id || !idRegex.test(id)) {
133
- throw new TypeError(`id must satisfy ${idRegex}`);
134
- }
135
- let version;
136
- // Parse Version
137
- if (fields[0] && versionRegex.test(fields[0])) {
138
- const versionMatch = fields.shift()?.match(versionRegex);
139
- version = versionMatch ? parseInt(versionMatch[1], 10) : undefined;
140
- }
141
- let hash;
142
- let salt;
143
- if (fields[fields.length - 1] && b64Regex.test(fields[fields.length - 1])) {
144
- if (fields.length > 1 && b64Regex.test(fields[fields.length - 2])) {
145
- // Parse Hash
146
- const hashStr = fields.pop();
147
- if (hashStr) hash = fromBase64(hashStr);
148
- // Parse Salt
149
- const saltStr = fields.pop();
150
- if (saltStr !== undefined) salt = fromBase64(saltStr);
151
- } else {
152
- // Parse Salt
153
- const saltStr = fields.pop();
154
- if (saltStr !== undefined) salt = fromBase64(saltStr);
155
- }
156
- }
157
- // Parse Parameters
158
- let params;
159
- if (fields.length > 0) {
160
- const parstr = fields.pop();
161
- if (parstr) {
162
- params = keyValtoObj(parstr);
163
- if (!Object.keys(params).every((p)=>nameRegex.test(p))) {
164
- throw new TypeError(`params names must satisfy ${nameRegex}}`);
165
- }
166
- const pv = Object.values(params);
167
- if (!pv.every((v)=>valueRegex.test(String(v)))) {
168
- throw new TypeError(`params values must satisfy ${valueRegex}`);
169
- }
170
- // Convert Decimal Strings into Numbers
171
- Object.keys(params).forEach((k)=>{
172
- const value = params?.[k];
173
- if (typeof value === 'string' && decimalRegex.test(value)) {
174
- params[k] = parseInt(value, 10);
175
- }
176
- });
177
- }
178
- }
179
- if (fields.length > 0) {
180
- throw new TypeError(`pchstr contains unrecognized fileds: ${fields}`);
181
- }
182
- // Build the output object
183
- const phcobj = {
184
- id
185
- };
186
- if (version !== undefined) phcobj.version = version;
187
- if (params) phcobj.params = params;
188
- if (salt) phcobj.salt = salt;
189
- if (hash) phcobj.hash = hash;
190
- return phcobj;
191
- }
192
- /**
112
+ function deserialize(phcstr) {
113
+ if (typeof phcstr !== 'string' || phcstr === '') {
114
+ throw new TypeError('pchstr must be a non-empty string');
115
+ }
116
+ if (phcstr[0] !== '$') {
117
+ throw new TypeError('pchstr must contain a $ as first char');
118
+ }
119
+ const fields = phcstr.split('$');
120
+ // Remove first empty $
121
+ fields.shift();
122
+ // Parse Fields
123
+ let maxf = 5;
124
+ if (!versionRegex.test(fields[1])) maxf--;
125
+ if (fields.length > maxf) {
126
+ throw new TypeError(`pchstr contains too many fileds: ${fields.length}/${maxf}`);
127
+ }
128
+ // Parse Identifier
129
+ const id = fields.shift();
130
+ if (!id || !idRegex.test(id)) {
131
+ throw new TypeError(`id must satisfy ${idRegex}`);
132
+ }
133
+ let version;
134
+ // Parse Version
135
+ if (fields[0] && versionRegex.test(fields[0])) {
136
+ const versionMatch = fields.shift()?.match(versionRegex);
137
+ version = versionMatch ? parseInt(versionMatch[1], 10) : undefined;
138
+ }
139
+ let hash;
140
+ let salt;
141
+ if (fields[fields.length - 1] && b64Regex.test(fields[fields.length - 1])) {
142
+ if (fields.length > 1 && b64Regex.test(fields[fields.length - 2])) {
143
+ // Parse Hash
144
+ const hashStr = fields.pop();
145
+ if (hashStr) hash = fromBase64(hashStr);
146
+ // Parse Salt
147
+ const saltStr = fields.pop();
148
+ if (saltStr !== undefined) salt = fromBase64(saltStr);
149
+ } else {
150
+ // Parse Salt
151
+ const saltStr = fields.pop();
152
+ if (saltStr !== undefined) salt = fromBase64(saltStr);
153
+ }
154
+ }
155
+ // Parse Parameters
156
+ let params;
157
+ if (fields.length > 0) {
158
+ const parstr = fields.pop();
159
+ if (parstr) {
160
+ params = keyValtoObj(parstr);
161
+ if (!Object.keys(params).every((p) => nameRegex.test(p))) {
162
+ throw new TypeError(`params names must satisfy ${nameRegex}}`);
163
+ }
164
+ const pv = Object.values(params);
165
+ if (!pv.every((v) => valueRegex.test(String(v)))) {
166
+ throw new TypeError(`params values must satisfy ${valueRegex}`);
167
+ }
168
+ // Convert Decimal Strings into Numbers
169
+ Object.keys(params).forEach((k) => {
170
+ const value = params?.[k];
171
+ if (typeof value === 'string' && decimalRegex.test(value)) {
172
+ params[k] = parseInt(value, 10);
173
+ }
174
+ });
175
+ }
176
+ }
177
+ if (fields.length > 0) {
178
+ throw new TypeError(`pchstr contains unrecognized fileds: ${fields}`);
179
+ }
180
+ // Build the output object
181
+ const phcobj = {
182
+ id,
183
+ };
184
+ if (version !== undefined) phcobj.version = version;
185
+ if (params) phcobj.params = params;
186
+ if (salt) phcobj.salt = salt;
187
+ if (hash) phcobj.hash = hash;
188
+ return phcobj;
189
+ }
190
+ /**
193
191
  * Parses data from a PHC string.
194
192
  * @param {string} phcstr A PHC string to parse.
195
193
  * @return {DeserializeResult} The object containing the data parsed from the PHC string.
@@ -197,4 +195,4 @@ import { ArrayBuffers } from "@wener/utils";
197
195
  })(PHC || (PHC = {}));
198
196
  export var PHC;
199
197
 
200
- //# sourceMappingURL=PHC.js.map
198
+ //# sourceMappingURL=PHC.js.map