@tstdl/base 0.93.178 → 0.93.179

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 (200) hide show
  1. package/api/response.js +4 -3
  2. package/api/server/gateway.js +9 -3
  3. package/audit/auditor.d.ts +1 -2
  4. package/audit/drizzle/{0000_lumpy_thunderball.sql → 0000_shallow_elektra.sql} +1 -1
  5. package/audit/drizzle/meta/0000_snapshot.json +2 -2
  6. package/audit/drizzle/meta/_journal.json +2 -2
  7. package/authentication/README.md +87 -42
  8. package/authentication/authentication.api.d.ts +392 -53
  9. package/authentication/authentication.api.js +133 -28
  10. package/authentication/client/api.client.d.ts +3 -3
  11. package/authentication/client/api.client.js +4 -4
  12. package/authentication/client/authentication.service.d.ts +93 -23
  13. package/authentication/client/authentication.service.js +113 -28
  14. package/authentication/client/http-client.middleware.d.ts +1 -1
  15. package/authentication/client/http-client.middleware.js +5 -4
  16. package/authentication/client/module.d.ts +1 -1
  17. package/authentication/client/module.js +2 -2
  18. package/authentication/errors/index.d.ts +1 -1
  19. package/authentication/errors/index.js +1 -1
  20. package/authentication/errors/password-requirements.error.d.ts +5 -0
  21. package/authentication/errors/{secret-requirements.error.js → password-requirements.error.js} +2 -2
  22. package/authentication/models/authentication-password.model.d.ts +8 -0
  23. package/authentication/models/{authentication-credentials.model.js → authentication-password.model.js} +11 -17
  24. package/authentication/models/authentication-session.model.d.ts +0 -2
  25. package/authentication/models/authentication-session.model.js +1 -7
  26. package/authentication/models/authentication-totp-recovery-code.model.d.ts +6 -0
  27. package/authentication/models/authentication-totp-recovery-code.model.js +34 -0
  28. package/authentication/models/authentication-totp.model.d.ts +19 -0
  29. package/authentication/models/authentication-totp.model.js +51 -0
  30. package/authentication/models/authentication-used-totp-token.model.d.ts +5 -0
  31. package/authentication/models/authentication-used-totp-token.model.js +32 -0
  32. package/authentication/models/index.d.ts +6 -3
  33. package/authentication/models/index.js +6 -3
  34. package/authentication/models/{init-secret-reset-data.model.d.ts → init-password-reset-data.model.d.ts} +3 -3
  35. package/authentication/models/{init-secret-reset-data.model.js → init-password-reset-data.model.js} +5 -5
  36. package/authentication/models/password-check-result.model.d.ts +3 -0
  37. package/authentication/models/{secret-check-result.model.js → password-check-result.model.js} +6 -6
  38. package/authentication/models/subject.model.d.ts +0 -6
  39. package/authentication/models/subject.model.js +0 -6
  40. package/authentication/models/token.model.d.ts +16 -2
  41. package/authentication/server/authentication-ancillary.service.d.ts +6 -6
  42. package/authentication/server/authentication-ancillary.service.js +1 -1
  43. package/authentication/server/authentication-password-requirements.validator.d.ts +55 -0
  44. package/authentication/server/{authentication-secret-requirements.validator.js → authentication-password-requirements.validator.js} +22 -22
  45. package/authentication/server/authentication.api-controller.d.ts +55 -27
  46. package/authentication/server/authentication.api-controller.js +214 -39
  47. package/authentication/server/authentication.audit.d.ts +42 -5
  48. package/authentication/server/authentication.service.d.ts +182 -93
  49. package/authentication/server/authentication.service.js +628 -206
  50. package/authentication/server/drizzle/{0000_soft_tag.sql → 0000_odd_echo.sql} +59 -13
  51. package/authentication/server/drizzle/meta/0000_snapshot.json +345 -32
  52. package/authentication/server/drizzle/meta/_journal.json +2 -2
  53. package/authentication/server/helper.d.ts +16 -16
  54. package/authentication/server/helper.js +33 -34
  55. package/authentication/server/index.d.ts +1 -1
  56. package/authentication/server/index.js +1 -1
  57. package/authentication/server/module.d.ts +2 -2
  58. package/authentication/server/module.js +4 -2
  59. package/authentication/server/schemas.d.ts +11 -7
  60. package/authentication/server/schemas.js +7 -3
  61. package/authentication/tests/authentication-password-requirements.validator.test.js +29 -0
  62. package/authentication/tests/authentication.api-controller.test.js +49 -15
  63. package/authentication/tests/authentication.client-error-handling.test.js +3 -2
  64. package/authentication/tests/authentication.client-middleware.test.js +5 -5
  65. package/authentication/tests/authentication.client-service-methods.test.js +28 -14
  66. package/authentication/tests/authentication.client-service-refresh.test.js +7 -6
  67. package/authentication/tests/authentication.client-service.test.js +10 -8
  68. package/authentication/tests/authentication.service.test.js +37 -29
  69. package/authentication/tests/authentication.test-ancillary-service.d.ts +1 -1
  70. package/authentication/tests/authentication.test-ancillary-service.js +1 -1
  71. package/authentication/tests/brute-force-protection.test.js +211 -0
  72. package/authentication/tests/helper.test.js +25 -21
  73. package/authentication/tests/password-requirements.error.test.js +14 -0
  74. package/authentication/tests/remember.api.test.js +22 -14
  75. package/authentication/tests/remember.service.test.js +23 -16
  76. package/authentication/tests/subject.service.test.js +2 -2
  77. package/authentication/tests/suspended-subject.test.d.ts +1 -0
  78. package/authentication/tests/suspended-subject.test.js +120 -0
  79. package/authentication/tests/totp.enrollment.test.d.ts +1 -0
  80. package/authentication/tests/totp.enrollment.test.js +123 -0
  81. package/authentication/tests/totp.login.test.d.ts +1 -0
  82. package/authentication/tests/totp.login.test.js +213 -0
  83. package/authentication/tests/totp.recovery-codes.test.d.ts +1 -0
  84. package/authentication/tests/totp.recovery-codes.test.js +97 -0
  85. package/authentication/tests/totp.status.test.d.ts +1 -0
  86. package/authentication/tests/totp.status.test.js +72 -0
  87. package/circuit-breaker/postgres/drizzle/{0000_cooing_korath.sql → 0000_same_captain_cross.sql} +1 -1
  88. package/circuit-breaker/postgres/drizzle/meta/0000_snapshot.json +2 -2
  89. package/circuit-breaker/postgres/drizzle/meta/_journal.json +2 -2
  90. package/cryptography/cryptography.d.ts +336 -0
  91. package/cryptography/cryptography.js +328 -0
  92. package/cryptography/index.d.ts +4 -0
  93. package/cryptography/index.js +4 -0
  94. package/{utils → cryptography}/jwt.d.ts +22 -4
  95. package/{utils → cryptography}/jwt.js +36 -18
  96. package/cryptography/module.d.ts +35 -0
  97. package/cryptography/module.js +148 -0
  98. package/cryptography/tests/cryptography.test.d.ts +1 -0
  99. package/cryptography/tests/cryptography.test.js +175 -0
  100. package/cryptography/tests/jwt.test.d.ts +1 -0
  101. package/cryptography/tests/jwt.test.js +54 -0
  102. package/cryptography/tests/modern.test.d.ts +1 -0
  103. package/cryptography/tests/modern.test.js +105 -0
  104. package/cryptography/tests/module.test.d.ts +1 -0
  105. package/cryptography/tests/module.test.js +100 -0
  106. package/cryptography/tests/totp.test.d.ts +1 -0
  107. package/cryptography/tests/totp.test.js +108 -0
  108. package/cryptography/totp.d.ts +96 -0
  109. package/cryptography/totp.js +123 -0
  110. package/document-management/server/drizzle/{0000_curious_nighthawk.sql → 0000_sharp_scream.sql} +21 -21
  111. package/document-management/server/drizzle/meta/0000_snapshot.json +22 -22
  112. package/document-management/server/drizzle/meta/_journal.json +2 -2
  113. package/document-management/server/services/document-file.service.js +1 -1
  114. package/errors/errors.localization.d.ts +2 -2
  115. package/errors/errors.localization.js +2 -2
  116. package/errors/index.d.ts +1 -0
  117. package/errors/index.js +1 -0
  118. package/errors/too-many-requests.error.d.ts +5 -0
  119. package/errors/too-many-requests.error.js +7 -0
  120. package/examples/api/authentication.js +5 -5
  121. package/examples/api/custom-authentication.js +4 -3
  122. package/file/server/mime-type.js +1 -1
  123. package/http/http-body.d.ts +1 -0
  124. package/http/http-body.js +3 -0
  125. package/image-service/imgproxy/imgproxy-image-service.d.ts +0 -1
  126. package/image-service/imgproxy/imgproxy-image-service.js +9 -27
  127. package/key-value-store/postgres/drizzle/{0000_shocking_slipstream.sql → 0000_moaning_calypso.sql} +1 -1
  128. package/key-value-store/postgres/drizzle/meta/0000_snapshot.json +2 -2
  129. package/key-value-store/postgres/drizzle/meta/_journal.json +2 -2
  130. package/lock/postgres/drizzle/{0000_busy_tattoo.sql → 0000_nappy_wraith.sql} +1 -1
  131. package/lock/postgres/drizzle/meta/0000_snapshot.json +2 -2
  132. package/lock/postgres/drizzle/meta/_journal.json +2 -2
  133. package/logger/formatters/json.js +1 -1
  134. package/logger/formatters/pretty-print.js +1 -1
  135. package/mail/drizzle/{0000_numerous_the_watchers.sql → 0000_cultured_quicksilver.sql} +2 -2
  136. package/mail/drizzle/meta/0000_snapshot.json +4 -4
  137. package/mail/drizzle/meta/_journal.json +2 -9
  138. package/notification/server/drizzle/{0000_wise_pyro.sql → 0000_new_tenebrous.sql} +6 -6
  139. package/notification/server/drizzle/meta/0000_snapshot.json +7 -7
  140. package/notification/server/drizzle/meta/_journal.json +2 -2
  141. package/notification/tests/notification-flow.test.js +1 -8
  142. package/notification/tests/notification-type.service.test.js +3 -3
  143. package/openid-connect/oidc.service.js +2 -3
  144. package/orm/data-types/common.js +1 -1
  145. package/orm/server/drizzle/schema-converter.js +9 -4
  146. package/orm/server/encryption.js +1 -1
  147. package/orm/server/repository.js +4 -6
  148. package/orm/tests/encryption.test.js +4 -6
  149. package/package.json +9 -8
  150. package/password/README.md +1 -1
  151. package/password/have-i-been-pwned.js +1 -1
  152. package/rate-limit/postgres/drizzle/{0000_watery_rage.sql → 0000_serious_sauron.sql} +1 -1
  153. package/rate-limit/postgres/drizzle/meta/0000_snapshot.json +2 -2
  154. package/rate-limit/postgres/drizzle/meta/_journal.json +2 -2
  155. package/rate-limit/postgres/postgres-rate-limiter.d.ts +1 -1
  156. package/rate-limit/postgres/postgres-rate-limiter.js +1 -1
  157. package/rate-limit/rate-limiter.d.ts +1 -1
  158. package/rpc/tests/rpc.integration.test.js +25 -31
  159. package/supports.d.ts +1 -0
  160. package/supports.js +1 -0
  161. package/task-queue/postgres/drizzle/{0000_faithful_daimon_hellstrom.sql → 0000_dark_ronan.sql} +5 -5
  162. package/task-queue/postgres/drizzle/meta/0000_snapshot.json +10 -10
  163. package/task-queue/postgres/drizzle/meta/_journal.json +2 -9
  164. package/task-queue/postgres/task-queue.js +2 -2
  165. package/task-queue/tests/coverage-enhancement.test.js +2 -2
  166. package/test/drizzle/{0000_natural_cannonball.sql → 0000_organic_gamora.sql} +2 -2
  167. package/test/drizzle/meta/0000_snapshot.json +3 -4
  168. package/test/drizzle/meta/_journal.json +2 -9
  169. package/testing/integration-setup.d.ts +7 -3
  170. package/testing/integration-setup.js +119 -96
  171. package/utils/alphabet.d.ts +1 -0
  172. package/utils/alphabet.js +1 -0
  173. package/utils/base32.d.ts +4 -0
  174. package/utils/base32.js +49 -0
  175. package/utils/base64.d.ts +0 -2
  176. package/utils/base64.js +6 -70
  177. package/utils/equals.d.ts +13 -3
  178. package/utils/equals.js +29 -9
  179. package/utils/index.d.ts +1 -2
  180. package/utils/index.js +1 -2
  181. package/utils/random.d.ts +1 -0
  182. package/utils/random.js +14 -8
  183. package/authentication/errors/secret-requirements.error.d.ts +0 -5
  184. package/authentication/models/authentication-credentials.model.d.ts +0 -10
  185. package/authentication/models/secret-check-result.model.d.ts +0 -3
  186. package/authentication/server/authentication-secret-requirements.validator.d.ts +0 -55
  187. package/authentication/tests/authentication-ancillary.service.test.js +0 -13
  188. package/authentication/tests/authentication-secret-requirements.validator.test.js +0 -29
  189. package/authentication/tests/secret-requirements.error.test.js +0 -14
  190. package/mail/drizzle/0001_married_tarantula.sql +0 -12
  191. package/mail/drizzle/meta/0001_snapshot.json +0 -69
  192. package/task-queue/postgres/drizzle/0001_rapid_infant_terrible.sql +0 -16
  193. package/task-queue/postgres/drizzle/meta/0001_snapshot.json +0 -753
  194. package/test/drizzle/0001_closed_the_captain.sql +0 -2
  195. package/test/drizzle/meta/0001_snapshot.json +0 -117
  196. package/utils/cryptography.d.ts +0 -137
  197. package/utils/cryptography.js +0 -201
  198. /package/authentication/tests/{authentication-ancillary.service.test.d.ts → authentication-password-requirements.validator.test.d.ts} +0 -0
  199. /package/authentication/tests/{authentication-secret-requirements.validator.test.d.ts → brute-force-protection.test.d.ts} +0 -0
  200. /package/authentication/tests/{secret-requirements.error.test.d.ts → password-requirements.error.test.d.ts} +0 -0
@@ -2,7 +2,7 @@ CREATE TYPE "notification"."notification_channel" AS ENUM('in-app', 'email', 'we
2
2
  CREATE TYPE "notification"."notification_priority" AS ENUM('low', 'medium', 'high', 'urgent');--> statement-breakpoint
3
3
  CREATE TYPE "notification"."notification_status" AS ENUM('pending', 'sent', 'delivered', 'read', 'failed');--> statement-breakpoint
4
4
  CREATE TABLE "notification"."in_app" (
5
- "id" uuid DEFAULT gen_random_uuid() NOT NULL,
5
+ "id" uuid DEFAULT uuidv7() NOT NULL,
6
6
  "tenant_id" uuid NOT NULL,
7
7
  "user_id" uuid NOT NULL,
8
8
  "log_id" uuid NOT NULL,
@@ -14,7 +14,7 @@ CREATE TABLE "notification"."in_app" (
14
14
  );
15
15
  --> statement-breakpoint
16
16
  CREATE TABLE "notification"."in_app_archive" (
17
- "id" uuid DEFAULT gen_random_uuid() NOT NULL,
17
+ "id" uuid DEFAULT uuidv7() NOT NULL,
18
18
  "tenant_id" uuid NOT NULL,
19
19
  "user_id" uuid NOT NULL,
20
20
  "log_id" uuid NOT NULL,
@@ -25,7 +25,7 @@ CREATE TABLE "notification"."in_app_archive" (
25
25
  );
26
26
  --> statement-breakpoint
27
27
  CREATE TABLE "notification"."log" (
28
- "id" uuid DEFAULT gen_random_uuid() NOT NULL,
28
+ "id" uuid DEFAULT uuidv7() NOT NULL,
29
29
  "tenant_id" uuid NOT NULL,
30
30
  "user_id" uuid NOT NULL,
31
31
  "type" text NOT NULL,
@@ -40,7 +40,7 @@ CREATE TABLE "notification"."log" (
40
40
  );
41
41
  --> statement-breakpoint
42
42
  CREATE TABLE "notification"."preference" (
43
- "id" uuid DEFAULT gen_random_uuid() NOT NULL,
43
+ "id" uuid DEFAULT uuidv7() NOT NULL,
44
44
  "tenant_id" uuid NOT NULL,
45
45
  "user_id" uuid NOT NULL,
46
46
  "type" text NOT NULL,
@@ -56,7 +56,7 @@ CREATE TABLE "notification"."preference" (
56
56
  );
57
57
  --> statement-breakpoint
58
58
  CREATE TABLE "notification"."type" (
59
- "id" uuid PRIMARY KEY DEFAULT gen_random_uuid() NOT NULL,
59
+ "id" uuid PRIMARY KEY DEFAULT uuidv7() NOT NULL,
60
60
  "label" text NOT NULL,
61
61
  "key" text NOT NULL,
62
62
  "throttling" jsonb,
@@ -70,7 +70,7 @@ CREATE TABLE "notification"."type" (
70
70
  );
71
71
  --> statement-breakpoint
72
72
  CREATE TABLE "notification"."web_push_subscription" (
73
- "id" uuid DEFAULT gen_random_uuid() NOT NULL,
73
+ "id" uuid DEFAULT uuidv7() NOT NULL,
74
74
  "tenant_id" uuid NOT NULL,
75
75
  "user_id" uuid NOT NULL,
76
76
  "endpoint" text NOT NULL,
@@ -1,5 +1,5 @@
1
1
  {
2
- "id": "23b5cedb-d56a-4f37-b838-fc9874b72ce3",
2
+ "id": "2c3e8dbf-7a78-43d2-9241-1a34ef49ec60",
3
3
  "prevId": "00000000-0000-0000-0000-000000000000",
4
4
  "version": "7",
5
5
  "dialect": "postgresql",
@@ -13,7 +13,7 @@
13
13
  "type": "uuid",
14
14
  "primaryKey": false,
15
15
  "notNull": true,
16
- "default": "gen_random_uuid()"
16
+ "default": "uuidv7()"
17
17
  },
18
18
  "tenant_id": {
19
19
  "name": "tenant_id",
@@ -233,7 +233,7 @@
233
233
  "type": "uuid",
234
234
  "primaryKey": false,
235
235
  "notNull": true,
236
- "default": "gen_random_uuid()"
236
+ "default": "uuidv7()"
237
237
  },
238
238
  "tenant_id": {
239
239
  "name": "tenant_id",
@@ -375,7 +375,7 @@
375
375
  "type": "uuid",
376
376
  "primaryKey": false,
377
377
  "notNull": true,
378
- "default": "gen_random_uuid()"
378
+ "default": "uuidv7()"
379
379
  },
380
380
  "tenant_id": {
381
381
  "name": "tenant_id",
@@ -516,7 +516,7 @@
516
516
  "type": "uuid",
517
517
  "primaryKey": false,
518
518
  "notNull": true,
519
- "default": "gen_random_uuid()"
519
+ "default": "uuidv7()"
520
520
  },
521
521
  "tenant_id": {
522
522
  "name": "tenant_id",
@@ -648,7 +648,7 @@
648
648
  "type": "uuid",
649
649
  "primaryKey": true,
650
650
  "notNull": true,
651
- "default": "gen_random_uuid()"
651
+ "default": "uuidv7()"
652
652
  },
653
653
  "label": {
654
654
  "name": "label",
@@ -731,7 +731,7 @@
731
731
  "type": "uuid",
732
732
  "primaryKey": false,
733
733
  "notNull": true,
734
- "default": "gen_random_uuid()"
734
+ "default": "uuidv7()"
735
735
  },
736
736
  "tenant_id": {
737
737
  "name": "tenant_id",
@@ -5,8 +5,8 @@
5
5
  {
6
6
  "idx": 0,
7
7
  "version": "7",
8
- "when": 1770754328787,
9
- "tag": "0000_wise_pyro",
8
+ "when": 1774646423051,
9
+ "tag": "0000_new_tenebrous",
10
10
  "breakpoints": true
11
11
  }
12
12
  ]
@@ -11,13 +11,7 @@ import { MailService } from '../../mail/mail.service.js';
11
11
  import { getRepository } from '../../orm/server/index.js';
12
12
  import { clearTenantData, setupIntegrationTest } from '../../testing/index.js';
13
13
  import { InAppNotification, NotificationChannel, NotificationLogEntity, NotificationStatus, WebPushSubscription } from '../models/index.js';
14
- import { configureNotification } from '../server/module.js';
15
- import { EmailChannelProvider } from '../server/providers/email-channel-provider.js';
16
- import { NotificationAncillaryService } from '../server/services/notification-ancillary.service.js';
17
- import { NotificationDeliveryWorker } from '../server/services/notification-delivery.worker.js';
18
- import { NotificationSseService } from '../server/services/notification-sse.service.js';
19
- import { NotificationTypeService } from '../server/services/notification-type.service.js';
20
- import { NotificationService } from '../server/services/notification.service.js';
14
+ import { configureNotification, EmailChannelProvider, InAppChannelProvider, NotificationAncillaryService, NotificationDeliveryWorker, NotificationService, NotificationSseService, NotificationTypeService } from '../server/index.js';
21
15
  let MockNotificationAncillaryService = class MockNotificationAncillaryService extends NotificationAncillaryService {
22
16
  async getViewData(_tenantId, notifications) {
23
17
  return notifications.map(() => ({}));
@@ -68,7 +62,6 @@ describe('Notification Flow (Integration)', () => {
68
62
  webPushRepo = injector.resolve(getRepository(WebPushSubscription));
69
63
  // Register providers
70
64
  worker.registerProvider(NotificationChannel.Email, injector.resolve(EmailChannelProvider));
71
- const InAppChannelProvider = (await import('../server/providers/in-app-channel-provider.js')).InAppChannelProvider;
72
65
  worker.registerProvider(NotificationChannel.InApp, injector.resolve(InAppChannelProvider));
73
66
  });
74
67
  beforeEach(async () => {
@@ -9,7 +9,7 @@ describe('NotificationTypeService', () => {
9
9
  await truncateTables(database, 'notification', ['type']);
10
10
  });
11
11
  afterEach(async () => {
12
- await injector.dispose();
12
+ await injector?.dispose();
13
13
  });
14
14
  test('should initialize types correctly', async () => {
15
15
  const service = injector.resolve(NotificationTypeService);
@@ -18,7 +18,7 @@ describe('NotificationTypeService', () => {
18
18
  const type2 = `${prefix}_TYPE2`;
19
19
  const typeData = {
20
20
  [type1]: { label: 'Type 1' },
21
- [type2]: { label: 'Type 2', throttling: { limit: 1, interval: 1000 } }
21
+ [type2]: { label: 'Type 2', throttling: { limit: 1, interval: 1000 } },
22
22
  };
23
23
  const result = await service.initializeTypes(typeData);
24
24
  expect(result[type1]?.label).toBe('Type 1');
@@ -30,7 +30,7 @@ describe('NotificationTypeService', () => {
30
30
  // Update
31
31
  const updatedData = {
32
32
  [type1]: { label: 'Type 1 Updated' },
33
- [type2]: { label: 'Type 2', throttling: { limit: 1, interval: 1000 } }
33
+ [type2]: { label: 'Type 2', throttling: { limit: 1, interval: 1000 } },
34
34
  };
35
35
  const resultUpdated = await service.initializeTypes(updatedData);
36
36
  expect(resultUpdated[type1]?.label).toBe('Type 1 Updated');
@@ -4,15 +4,14 @@ var __decorate = (this && this.__decorate) || function (decorators, target, key,
4
4
  else for (var i = decorators.length - 1; i >= 0; i--) if (d = decorators[i]) r = (c < 3 ? d(r) : c > 3 ? d(target, key, r) : d(target, key)) || r;
5
5
  return c > 3 && r && Object.defineProperty(target, key, r), r;
6
6
  };
7
- import { ForbiddenError } from '../errors/forbidden.error.js';
8
- import { NotImplementedError } from '../errors/not-implemented.error.js';
7
+ import { digest } from '../cryptography/index.js';
8
+ import { ForbiddenError, NotImplementedError } from '../errors/index.js';
9
9
  import { HttpClient } from '../http/client/index.js';
10
10
  import { HttpHeaders } from '../http/http-headers.js';
11
11
  import { inject, Singleton } from '../injector/index.js';
12
12
  import { injectRepository } from '../orm/server/index.js';
13
13
  import { object, optional, Schema, string } from '../schema/index.js';
14
14
  import { Alphabet } from '../utils/alphabet.js';
15
- import { digest } from '../utils/cryptography.js';
16
15
  import { currentTimestamp } from '../utils/date-time.js';
17
16
  import { getRandomString } from '../utils/random.js';
18
17
  import { assertDefinedPass, isUndefined } from '../utils/type-guards.js';
@@ -1,4 +1,4 @@
1
- import { customType, } from 'drizzle-orm/pg-core';
1
+ import { customType } from 'drizzle-orm/pg-core';
2
2
  /**
3
3
  * Factory function to create a custom Drizzle type with the standard builder overloads.
4
4
  * This reduces boilerplate by wrapping `drizzle-orm/pg-core#customType` and applying a common type cast.
@@ -5,6 +5,7 @@ import { match, P } from 'ts-pattern';
5
5
  import { MultiKeyMap } from '../../../data-structures/multi-key-map.js';
6
6
  import { NotSupportedError } from '../../../errors/not-supported.error.js';
7
7
  import { JsonPath } from '../../../json-path/json-path.js';
8
+ import { RANDOM_UUID_V7 } from '../../../orm/sqls/sqls.js';
8
9
  import { reflectionRegistry } from '../../../reflection/registry.js';
9
10
  import { ArraySchema, BooleanSchema, DefaultSchema, EnumerationSchema, getObjectSchema, NullableSchema, NumberSchema, ObjectSchema, OptionalSchema, StringSchema, Uint8ArraySchema } from '../../../schema/index.js';
10
11
  import { compareByValueSelectionToOrder, orderRest } from '../../../utils/comparison.js';
@@ -15,7 +16,7 @@ import { typeExtends } from '../../../utils/index.js';
15
16
  import { merge } from '../../../utils/merge.js';
16
17
  import { compileDereferencer } from '../../../utils/object/dereference.js';
17
18
  import { fromEntries, mapObjectKeysToSnakeCase, objectEntries } from '../../../utils/object/object.js';
18
- import { assertDefined, assertDefinedPass, isArray, isDefined, isNotNull, isNull, isString, isUndefined } from '../../../utils/type-guards.js';
19
+ import { assertDefined, assertDefinedPass, assertUint8ArrayPass, isArray, isDefined, isInstanceOf, isNotNull, isNull, isString, isUndefined } from '../../../utils/type-guards.js';
19
20
  import { resolveValueOrProvider } from '../../../utils/value-or-provider.js';
20
21
  import { bytea, numericDate, timestamp, tsvector } from '../../data-types/index.js';
21
22
  import { TenantBaseEntity, TenantEntity } from '../../entity.js';
@@ -381,16 +382,17 @@ function getPostgresColumnEntries(type, dbSchema, tableName, path = new JsonPath
381
382
  return getPostgresColumnEntries(columnReflectionData?.embedded?.type ?? propertyMetadata.type, dbSchema, tableName, path.add(property), nestedPrefix, { ...options, inherited, table }, rootType);
382
383
  }
383
384
  const encrypted = columnReflectionData?.encrypted == true;
385
+ const unwrappedSchemaIsUint8Array = isInstanceOf(unwrapSchema(schema).schema, Uint8ArraySchema);
384
386
  const toDatabase = encrypted
385
387
  ? async (value, context) => {
386
- const bytes = encodeUtf8(value);
388
+ const bytes = isString(value) ? encodeUtf8(value) : assertUint8ArrayPass(value);
387
389
  return await encryptBytes(bytes, context.encryptionKey);
388
390
  }
389
391
  : (value) => value;
390
392
  const fromDatabase = encrypted
391
393
  ? async (value, context) => {
392
394
  const decrypted = await decryptBytes(value, context.encryptionKey);
393
- return decodeText(decrypted);
395
+ return unwrappedSchemaIsUint8Array ? decrypted : decodeText(decrypted);
394
396
  }
395
397
  : (value) => value;
396
398
  const prefixedColumnName = [prefix, columnName].join('');
@@ -446,11 +448,14 @@ function getPostgresBaseColumn(columnName, dbSchema, schema, reflectionData, con
446
448
  if (isDefined(reflectionData.tsVector)) {
447
449
  return tsvector(columnName);
448
450
  }
451
+ return getPgColumnBuilder(columnName, dbSchema, schema, reflectionData, context);
452
+ }
453
+ function getPgColumnBuilder(columnName, dbSchema, schema, _reflectionData, context) {
449
454
  return match(schema)
450
455
  .with(P.instanceOf(UuidSchema), (s) => {
451
456
  let column = uuid(columnName);
452
457
  if (s.defaultRandom) {
453
- column = column.defaultRandom();
458
+ column = column.default(RANDOM_UUID_V7);
454
459
  }
455
460
  return column;
456
461
  })
@@ -3,7 +3,7 @@
3
3
  * Provides utility functions for encrypting and decrypting byte arrays using AES-GCM.
4
4
  * It includes versioning to handle potential future changes in the encryption format.
5
5
  */
6
- import { decrypt, encrypt } from '../../utils/cryptography.js';
6
+ import { decrypt, encrypt } from '../../cryptography/index.js';
7
7
  import { getRandomBytes } from '../../utils/random.js';
8
8
  import { assert } from '../../utils/type-guards.js';
9
9
  /** Current version of the encryption format. */
@@ -8,6 +8,7 @@ var __decorate = (this && this.__decorate) || function (decorators, target, key,
8
8
  import { and, asc, count, desc, eq, getTableName, inArray, isNotNull as isSqlNotNull, isNull as isSqlNull, isSQLWrapper, lte, or, SQL, sql } from 'drizzle-orm';
9
9
  import { match, P } from 'ts-pattern';
10
10
  import { CancellationSignal } from '../../cancellation/token.js';
11
+ import { importSymmetricKey } from '../../cryptography/index.js';
11
12
  import { NotFoundError } from '../../errors/not-found.error.js';
12
13
  import { Singleton } from '../../injector/decorators.js';
13
14
  import { inject, injectArgument } from '../../injector/inject.js';
@@ -16,7 +17,6 @@ import { reflectionRegistry } from '../../reflection/index.js';
16
17
  import { distinct, toArray } from '../../utils/array/array.js';
17
18
  import { mapAsync } from '../../utils/async-iterable-helpers/map.js';
18
19
  import { toArrayAsync } from '../../utils/async-iterable-helpers/to-array.js';
19
- import { importSymmetricKey } from '../../utils/cryptography.js';
20
20
  import { assignDeep, fromEntries, objectEntries, objectKeys } from '../../utils/object/object.js';
21
21
  import { toSnakeCase } from '../../utils/string/index.js';
22
22
  import { cancelableTimeout } from '../../utils/timing.js';
@@ -57,7 +57,6 @@ let EntityRepository = class EntityRepository extends Transactional {
57
57
  #columnDefinitionsMap = this.#context.columnDefinitionsMap ?? getColumnDefinitionsMap(this.#table);
58
58
  #primaryKeyColumns = getPrimaryKeyColumns(this.type, this.#table);
59
59
  #primaryKeyColumnNames = this.#primaryKeyColumns.map((column) => column.name);
60
- #joinedTables = this.#tablesChain.filter((info) => info.table != this.#table).map((info) => info.table);
61
60
  #inheritanceMetadata = getInheritanceMetadata(this.type);
62
61
  #subclasses = this.#inheritanceMetadata?.subclasses ?? [];
63
62
  #subclassTablesInfo = this.#subclasses.map((subclass) => {
@@ -1750,11 +1749,10 @@ let EntityRepository = class EntityRepository extends Transactional {
1750
1749
  this.#transformContext = {};
1751
1750
  return this.#transformContext;
1752
1751
  }
1753
- this.#transformContext = importSymmetricKey('AES-GCM', 256, this.#encryptionSecret, false).then((encryptionKey) => ({ encryptionKey }));
1754
- const transformContext = await this.#transformContext;
1755
- this.#transformContext = transformContext;
1752
+ this.#transformContext = importSymmetricKey('raw', { name: 'AES-GCM', length: 256 }, this.#encryptionSecret, false).then((encryptionKey) => ({ encryptionKey }));
1753
+ this.#transformContext = await this.#transformContext;
1756
1754
  }
1757
- return await this.#transformContext;
1755
+ return this.#transformContext; // eslint-disable-line @typescript-eslint/return-await
1758
1756
  }
1759
1757
  async _mapSearchResults(rows, scoreTransformer = (s) => s, options) {
1760
1758
  const transformContext = await this.getTransformContext();
@@ -1,18 +1,16 @@
1
1
  import { describe, expect, test } from 'vitest';
2
+ import { generateSymmetricKey } from '../../cryptography/index.js';
2
3
  import { decryptBytes, encryptBytes } from '../server/encryption.js';
3
4
  describe('ORM Encryption', () => {
4
- async function generateKey() {
5
- return await globalThis.crypto.subtle.generateKey({ name: 'AES-GCM', length: 256 }, true, ['encrypt', 'decrypt']);
6
- }
7
5
  test('should encrypt and decrypt correctly', async () => {
8
- const key = await generateKey();
6
+ const key = await generateSymmetricKey({ name: 'AES-GCM', length: 256 }, true);
9
7
  const data = new TextEncoder().encode('Hello, ORM Encryption!');
10
8
  const encrypted = await encryptBytes(data, key);
11
9
  const decrypted = await decryptBytes(encrypted, key);
12
10
  expect(new TextDecoder().decode(decrypted)).toBe('Hello, ORM Encryption!');
13
11
  });
14
12
  test('should throw Error on corrupted data', async () => {
15
- const key = await generateKey();
13
+ const key = await generateSymmetricKey({ name: 'AES-GCM', length: 256 }, true);
16
14
  const data = new TextEncoder().encode('Corrupt me');
17
15
  const encrypted = await encryptBytes(data, key);
18
16
  // Corrupt the ciphertext (last byte)
@@ -22,7 +20,7 @@ describe('ORM Encryption', () => {
22
20
  await expect(decryptBytes(encrypted, key)).rejects.toThrow('Decryption failed.');
23
21
  });
24
22
  test('should throw error on invalid version', async () => {
25
- const key = await generateKey();
23
+ const key = await generateSymmetricKey({ name: 'AES-GCM', length: 256 }, true);
26
24
  const data = new TextEncoder().encode('Wrong version');
27
25
  const encrypted = await encryptBytes(data, key);
28
26
  // Corrupt version byte (set to a very high number)
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@tstdl/base",
3
- "version": "0.93.178",
3
+ "version": "0.93.179",
4
4
  "author": "Patrick Hein",
5
5
  "publishConfig": {
6
6
  "access": "public"
@@ -53,6 +53,7 @@
53
53
  "./circuit-breaker": "./circuit-breaker/index.js",
54
54
  "./circuit-breaker/postgres": "./circuit-breaker/postgres/index.js",
55
55
  "./cookie": "./cookie/index.js",
56
+ "./cryptography": "./cryptography/index.js",
56
57
  "./css": "./css/index.js",
57
58
  "./data-structures": "./data-structures/index.js",
58
59
  "./decorators": "./decorators/index.js",
@@ -152,9 +153,9 @@
152
153
  "type-fest": "^5.5"
153
154
  },
154
155
  "peerDependencies": {
155
- "@aws-sdk/client-s3": "^3.1015",
156
- "@aws-sdk/s3-request-presigner": "^3.1015",
157
- "@genkit-ai/google-genai": "^1.30",
156
+ "@aws-sdk/client-s3": "^3.1020",
157
+ "@aws-sdk/s3-request-presigner": "^3.1020",
158
+ "@genkit-ai/google-genai": "^1.31",
158
159
  "@google-cloud/storage": "^7.19",
159
160
  "@toon-format/toon": "^2.1.0",
160
161
  "@tstdl/angular": "^0.93",
@@ -163,8 +164,8 @@
163
164
  "@zxcvbn-ts/language-de": "^3.0",
164
165
  "@zxcvbn-ts/language-en": "^3.0",
165
166
  "drizzle-orm": "^0.45",
166
- "file-type": "^21.3",
167
- "genkit": "^1.30",
167
+ "file-type": "^22.0",
168
+ "genkit": "^1.31",
168
169
  "handlebars": "^4.7",
169
170
  "mjml": "^4.18",
170
171
  "nodemailer": "^8.0",
@@ -195,14 +196,14 @@
195
196
  "@vitest/ui": "4.1",
196
197
  "concurrently": "9.2",
197
198
  "drizzle-kit": "0.31",
198
- "eslint": "9.39",
199
+ "eslint": "10.1",
199
200
  "globals": "17.4",
200
201
  "tsc-alias": "1.8",
201
202
  "typedoc-github-wiki-theme": "2.1",
202
203
  "typedoc-plugin-markdown": "4.11",
203
204
  "typedoc-plugin-missing-exports": "4.1",
204
205
  "typescript": "5.9",
205
- "typescript-eslint": "8.57",
206
+ "typescript-eslint": "8.58",
206
207
  "vitest": "4.1"
207
208
  }
208
209
  }
@@ -135,7 +135,7 @@ export const myApiDefinition = defineApi({
135
135
 
136
136
  ### Authentication Integration
137
137
 
138
- This module is used by the `@tstdl/base/authentication` framework to enforce password requirements during registration or password changes. See `AuthenticationSecretRequirementsValidator` for more details on how to customize these checks in your application.
138
+ This module is used by the `@tstdl/base/authentication` framework to enforce password requirements during registration or password changes. See `AuthenticationPasswordRequirementsValidator` for more details on how to customize these checks in your application.
139
139
 
140
140
  ## 📚 API
141
141
 
@@ -1,4 +1,4 @@
1
- import { digest } from '../utils/cryptography.js';
1
+ import { digest } from '../cryptography/index.js';
2
2
  const urlBase = 'https://api.pwnedpasswords.com';
3
3
  /**
4
4
  * Checks password against https://haveibeenpwned.com/passwords
@@ -1,5 +1,5 @@
1
1
  CREATE TABLE "rate_limit"."rate_limit" (
2
- "id" uuid PRIMARY KEY DEFAULT gen_random_uuid() NOT NULL,
2
+ "id" uuid PRIMARY KEY DEFAULT uuidv7() NOT NULL,
3
3
  "resource" text NOT NULL,
4
4
  "tokens" double precision NOT NULL,
5
5
  "last_refill_timestamp" timestamp with time zone NOT NULL,
@@ -1,5 +1,5 @@
1
1
  {
2
- "id": "0270ac12-b454-4601-b7e9-f825d71b1f4e",
2
+ "id": "7e627538-45f2-41c1-991c-f40ad4f76787",
3
3
  "prevId": "00000000-0000-0000-0000-000000000000",
4
4
  "version": "7",
5
5
  "dialect": "postgresql",
@@ -13,7 +13,7 @@
13
13
  "type": "uuid",
14
14
  "primaryKey": true,
15
15
  "notNull": true,
16
- "default": "gen_random_uuid()"
16
+ "default": "uuidv7()"
17
17
  },
18
18
  "resource": {
19
19
  "name": "resource",
@@ -5,8 +5,8 @@
5
5
  {
6
6
  "idx": 0,
7
7
  "version": "7",
8
- "when": 1768608042456,
9
- "tag": "0000_watery_rage",
8
+ "when": 1774646421753,
9
+ "tag": "0000_serious_sauron",
10
10
  "breakpoints": true
11
11
  }
12
12
  ]
@@ -8,7 +8,7 @@ export declare class PostgresRateLimiter extends RateLimiter {
8
8
  readonly refillInterval: number;
9
9
  readonly refillRate: number;
10
10
  tryAcquire(resource: string, cost?: number, options?: Partial<RateLimiterConfig>): Promise<boolean>;
11
- refund(resource: string, amount: number, options?: Partial<Pick<RateLimiterConfig, 'burstCapacity'>>): Promise<void>;
11
+ refund(resource: string, amount?: number, options?: Partial<Pick<RateLimiterConfig, 'burstCapacity'>>): Promise<void>;
12
12
  protected getTransactionalContextData(): PostgresRateLimiterContext;
13
13
  }
14
14
  export {};
@@ -41,7 +41,7 @@ let PostgresRateLimiter = class PostgresRateLimiter extends RateLimiter {
41
41
  const result = await this.#repository.tryUpsert('resource', { resource, tokens: burstCapacity - cost, lastRefillTimestamp: TRANSACTION_TIMESTAMP }, { tokens: sql `${newTokensExpression} - ${cost}`, lastRefillTimestamp: TRANSACTION_TIMESTAMP }, { set: gte(newTokensExpression, cost) });
42
42
  return isDefined(result);
43
43
  }
44
- async refund(resource, amount, options) {
44
+ async refund(resource, amount = 1, options) {
45
45
  if (amount <= 0) {
46
46
  return;
47
47
  }
@@ -31,5 +31,5 @@ export declare abstract class RateLimiter extends Transactional implements Resol
31
31
  * @param amount The number of tokens to refund.
32
32
  * @param options Optional configuration overrides for this refund.
33
33
  */
34
- abstract refund(resource: string, amount: number, options?: Partial<Pick<RateLimiterConfig, 'burstCapacity'>>): Promise<void>;
34
+ abstract refund(resource: string, amount?: number, options?: Partial<Pick<RateLimiterConfig, 'burstCapacity'>>): Promise<void>;
35
35
  }