@tstdl/base 0.93.178 → 0.93.180
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/api/response.js +4 -3
- package/api/server/gateway.js +9 -3
- package/audit/auditor.d.ts +1 -2
- package/audit/drizzle/{0000_lumpy_thunderball.sql → 0000_shallow_elektra.sql} +1 -1
- package/audit/drizzle/meta/0000_snapshot.json +2 -2
- package/audit/drizzle/meta/_journal.json +2 -2
- package/authentication/README.md +87 -42
- package/authentication/authentication.api.d.ts +392 -53
- package/authentication/authentication.api.js +133 -28
- package/authentication/client/api.client.d.ts +3 -3
- package/authentication/client/api.client.js +4 -4
- package/authentication/client/authentication.service.d.ts +93 -23
- package/authentication/client/authentication.service.js +113 -28
- package/authentication/client/http-client.middleware.d.ts +1 -1
- package/authentication/client/http-client.middleware.js +5 -4
- package/authentication/client/module.d.ts +1 -1
- package/authentication/client/module.js +2 -2
- package/authentication/errors/index.d.ts +1 -1
- package/authentication/errors/index.js +1 -1
- package/authentication/errors/password-requirements.error.d.ts +5 -0
- package/authentication/errors/{secret-requirements.error.js → password-requirements.error.js} +2 -2
- package/authentication/models/authentication-password.model.d.ts +8 -0
- package/authentication/models/{authentication-credentials.model.js → authentication-password.model.js} +11 -17
- package/authentication/models/authentication-session.model.d.ts +0 -2
- package/authentication/models/authentication-session.model.js +1 -7
- package/authentication/models/authentication-totp-recovery-code.model.d.ts +6 -0
- package/authentication/models/authentication-totp-recovery-code.model.js +34 -0
- package/authentication/models/authentication-totp.model.d.ts +19 -0
- package/authentication/models/authentication-totp.model.js +51 -0
- package/authentication/models/authentication-used-totp-token.model.d.ts +5 -0
- package/authentication/models/authentication-used-totp-token.model.js +32 -0
- package/authentication/models/index.d.ts +6 -3
- package/authentication/models/index.js +6 -3
- package/authentication/models/{init-secret-reset-data.model.d.ts → init-password-reset-data.model.d.ts} +3 -3
- package/authentication/models/{init-secret-reset-data.model.js → init-password-reset-data.model.js} +5 -5
- package/authentication/models/password-check-result.model.d.ts +3 -0
- package/authentication/models/{secret-check-result.model.js → password-check-result.model.js} +6 -6
- package/authentication/models/subject.model.d.ts +0 -6
- package/authentication/models/subject.model.js +0 -6
- package/authentication/models/token.model.d.ts +16 -2
- package/authentication/server/authentication-ancillary.service.d.ts +6 -6
- package/authentication/server/authentication-ancillary.service.js +1 -1
- package/authentication/server/authentication-password-requirements.validator.d.ts +55 -0
- package/authentication/server/{authentication-secret-requirements.validator.js → authentication-password-requirements.validator.js} +22 -22
- package/authentication/server/authentication.api-controller.d.ts +55 -27
- package/authentication/server/authentication.api-controller.js +214 -39
- package/authentication/server/authentication.audit.d.ts +42 -5
- package/authentication/server/authentication.service.d.ts +182 -93
- package/authentication/server/authentication.service.js +628 -206
- package/authentication/server/drizzle/{0000_soft_tag.sql → 0000_odd_echo.sql} +59 -13
- package/authentication/server/drizzle/meta/0000_snapshot.json +345 -32
- package/authentication/server/drizzle/meta/_journal.json +2 -2
- package/authentication/server/helper.d.ts +16 -16
- package/authentication/server/helper.js +33 -34
- package/authentication/server/index.d.ts +1 -1
- package/authentication/server/index.js +1 -1
- package/authentication/server/module.d.ts +2 -2
- package/authentication/server/module.js +4 -2
- package/authentication/server/schemas.d.ts +11 -7
- package/authentication/server/schemas.js +7 -3
- package/authentication/tests/authentication-password-requirements.validator.test.js +29 -0
- package/authentication/tests/authentication.api-controller.test.js +49 -15
- package/authentication/tests/authentication.client-error-handling.test.js +3 -2
- package/authentication/tests/authentication.client-middleware.test.js +5 -5
- package/authentication/tests/authentication.client-service-methods.test.js +28 -14
- package/authentication/tests/authentication.client-service-refresh.test.js +7 -6
- package/authentication/tests/authentication.client-service.test.js +10 -8
- package/authentication/tests/authentication.service.test.js +37 -29
- package/authentication/tests/authentication.test-ancillary-service.d.ts +1 -1
- package/authentication/tests/authentication.test-ancillary-service.js +1 -1
- package/authentication/tests/brute-force-protection.test.js +211 -0
- package/authentication/tests/helper.test.js +25 -21
- package/authentication/tests/password-requirements.error.test.js +14 -0
- package/authentication/tests/remember.api.test.js +22 -14
- package/authentication/tests/remember.service.test.js +23 -16
- package/authentication/tests/subject.service.test.js +2 -2
- package/authentication/tests/suspended-subject.test.d.ts +1 -0
- package/authentication/tests/suspended-subject.test.js +120 -0
- package/authentication/tests/totp.enrollment.test.d.ts +1 -0
- package/authentication/tests/totp.enrollment.test.js +123 -0
- package/authentication/tests/totp.login.test.d.ts +1 -0
- package/authentication/tests/totp.login.test.js +213 -0
- package/authentication/tests/totp.recovery-codes.test.d.ts +1 -0
- package/authentication/tests/totp.recovery-codes.test.js +97 -0
- package/authentication/tests/totp.status.test.d.ts +1 -0
- package/authentication/tests/totp.status.test.js +72 -0
- package/circuit-breaker/postgres/drizzle/{0000_cooing_korath.sql → 0000_same_captain_cross.sql} +1 -1
- package/circuit-breaker/postgres/drizzle/meta/0000_snapshot.json +2 -2
- package/circuit-breaker/postgres/drizzle/meta/_journal.json +2 -2
- package/cryptography/cryptography.d.ts +336 -0
- package/cryptography/cryptography.js +328 -0
- package/cryptography/index.d.ts +4 -0
- package/cryptography/index.js +4 -0
- package/{utils → cryptography}/jwt.d.ts +22 -4
- package/{utils → cryptography}/jwt.js +36 -18
- package/cryptography/module.d.ts +35 -0
- package/cryptography/module.js +148 -0
- package/cryptography/tests/cryptography.test.d.ts +1 -0
- package/cryptography/tests/cryptography.test.js +175 -0
- package/cryptography/tests/jwt.test.d.ts +1 -0
- package/cryptography/tests/jwt.test.js +54 -0
- package/cryptography/tests/modern.test.d.ts +1 -0
- package/cryptography/tests/modern.test.js +105 -0
- package/cryptography/tests/module.test.d.ts +1 -0
- package/cryptography/tests/module.test.js +100 -0
- package/cryptography/tests/totp.test.d.ts +1 -0
- package/cryptography/tests/totp.test.js +108 -0
- package/cryptography/totp.d.ts +96 -0
- package/cryptography/totp.js +123 -0
- package/document-management/server/drizzle/{0000_curious_nighthawk.sql → 0000_sharp_scream.sql} +21 -21
- package/document-management/server/drizzle/meta/0000_snapshot.json +22 -22
- package/document-management/server/drizzle/meta/_journal.json +2 -2
- package/document-management/server/services/document-file.service.js +1 -1
- package/errors/errors.localization.d.ts +2 -2
- package/errors/errors.localization.js +2 -2
- package/errors/index.d.ts +1 -0
- package/errors/index.js +1 -0
- package/errors/too-many-requests.error.d.ts +5 -0
- package/errors/too-many-requests.error.js +7 -0
- package/examples/api/authentication.js +5 -5
- package/examples/api/custom-authentication.js +4 -3
- package/file/server/mime-type.js +1 -1
- package/http/http-body.d.ts +1 -0
- package/http/http-body.js +3 -0
- package/image-service/imgproxy/imgproxy-image-service.d.ts +0 -1
- package/image-service/imgproxy/imgproxy-image-service.js +9 -27
- package/key-value-store/postgres/drizzle/{0000_shocking_slipstream.sql → 0000_moaning_calypso.sql} +1 -1
- package/key-value-store/postgres/drizzle/meta/0000_snapshot.json +2 -2
- package/key-value-store/postgres/drizzle/meta/_journal.json +2 -2
- package/lock/postgres/drizzle/{0000_busy_tattoo.sql → 0000_nappy_wraith.sql} +1 -1
- package/lock/postgres/drizzle/meta/0000_snapshot.json +2 -2
- package/lock/postgres/drizzle/meta/_journal.json +2 -2
- package/logger/formatters/json.js +1 -1
- package/logger/formatters/pretty-print.js +1 -1
- package/mail/drizzle/{0000_numerous_the_watchers.sql → 0000_cultured_quicksilver.sql} +2 -2
- package/mail/drizzle/meta/0000_snapshot.json +4 -4
- package/mail/drizzle/meta/_journal.json +2 -9
- package/notification/server/drizzle/{0000_wise_pyro.sql → 0000_new_tenebrous.sql} +6 -6
- package/notification/server/drizzle/meta/0000_snapshot.json +7 -7
- package/notification/server/drizzle/meta/_journal.json +2 -2
- package/notification/tests/notification-flow.test.js +1 -8
- package/notification/tests/notification-type.service.test.js +3 -3
- package/openid-connect/oidc.service.js +2 -3
- package/orm/data-types/common.js +1 -1
- package/orm/server/drizzle/schema-converter.js +9 -4
- package/orm/server/encryption.js +1 -1
- package/orm/server/module.d.ts +0 -1
- package/orm/server/module.js +0 -4
- package/orm/server/repository.d.ts +2 -1
- package/orm/server/repository.js +7 -10
- package/orm/tests/encryption.test.js +4 -6
- package/orm/tests/repository-extra-coverage.test.js +0 -2
- package/orm/tests/repository-regression.test.js +0 -3
- package/package.json +9 -8
- package/password/README.md +1 -1
- package/password/have-i-been-pwned.js +1 -1
- package/rate-limit/postgres/drizzle/{0000_watery_rage.sql → 0000_serious_sauron.sql} +1 -1
- package/rate-limit/postgres/drizzle/meta/0000_snapshot.json +2 -2
- package/rate-limit/postgres/drizzle/meta/_journal.json +2 -2
- package/rate-limit/postgres/postgres-rate-limiter.d.ts +1 -1
- package/rate-limit/postgres/postgres-rate-limiter.js +1 -1
- package/rate-limit/rate-limiter.d.ts +1 -1
- package/rpc/tests/rpc.integration.test.js +25 -31
- package/supports.d.ts +1 -0
- package/supports.js +1 -0
- package/task-queue/postgres/drizzle/{0000_faithful_daimon_hellstrom.sql → 0000_dark_ronan.sql} +5 -5
- package/task-queue/postgres/drizzle/meta/0000_snapshot.json +10 -10
- package/task-queue/postgres/drizzle/meta/_journal.json +2 -9
- package/task-queue/postgres/task-queue.js +2 -2
- package/task-queue/tests/coverage-enhancement.test.js +2 -2
- package/test/drizzle/{0000_natural_cannonball.sql → 0000_organic_gamora.sql} +2 -2
- package/test/drizzle/meta/0000_snapshot.json +3 -4
- package/test/drizzle/meta/_journal.json +2 -9
- package/testing/integration-setup.d.ts +7 -3
- package/testing/integration-setup.js +119 -96
- package/utils/alphabet.d.ts +1 -0
- package/utils/alphabet.js +1 -0
- package/utils/base32.d.ts +4 -0
- package/utils/base32.js +49 -0
- package/utils/base64.d.ts +0 -2
- package/utils/base64.js +6 -70
- package/utils/equals.d.ts +13 -3
- package/utils/equals.js +29 -9
- package/utils/index.d.ts +1 -2
- package/utils/index.js +1 -2
- package/utils/random.d.ts +1 -0
- package/utils/random.js +14 -8
- package/authentication/errors/secret-requirements.error.d.ts +0 -5
- package/authentication/models/authentication-credentials.model.d.ts +0 -10
- package/authentication/models/secret-check-result.model.d.ts +0 -3
- package/authentication/server/authentication-secret-requirements.validator.d.ts +0 -55
- package/authentication/tests/authentication-ancillary.service.test.js +0 -13
- package/authentication/tests/authentication-secret-requirements.validator.test.js +0 -29
- package/authentication/tests/secret-requirements.error.test.js +0 -14
- package/mail/drizzle/0001_married_tarantula.sql +0 -12
- package/mail/drizzle/meta/0001_snapshot.json +0 -69
- package/orm/server/tokens.d.ts +0 -1
- package/orm/server/tokens.js +0 -2
- package/task-queue/postgres/drizzle/0001_rapid_infant_terrible.sql +0 -16
- package/task-queue/postgres/drizzle/meta/0001_snapshot.json +0 -753
- package/test/drizzle/0001_closed_the_captain.sql +0 -2
- package/test/drizzle/meta/0001_snapshot.json +0 -117
- package/utils/cryptography.d.ts +0 -137
- package/utils/cryptography.js +0 -201
- /package/authentication/tests/{authentication-ancillary.service.test.d.ts → authentication-password-requirements.validator.test.d.ts} +0 -0
- /package/authentication/tests/{authentication-secret-requirements.validator.test.d.ts → brute-force-protection.test.d.ts} +0 -0
- /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
|
|
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
|
|
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
|
|
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
|
|
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
|
|
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
|
|
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": "
|
|
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": "
|
|
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": "
|
|
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": "
|
|
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": "
|
|
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": "
|
|
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": "
|
|
734
|
+
"default": "uuidv7()"
|
|
735
735
|
},
|
|
736
736
|
"tenant_id": {
|
|
737
737
|
"name": "tenant_id",
|
|
@@ -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/
|
|
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
|
|
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 {
|
|
8
|
-
import { NotImplementedError } from '../errors/
|
|
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';
|
package/orm/data-types/common.js
CHANGED
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import { customType
|
|
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.
|
|
458
|
+
column = column.default(RANDOM_UUID_V7);
|
|
454
459
|
}
|
|
455
460
|
return column;
|
|
456
461
|
})
|
package/orm/server/encryption.js
CHANGED
|
@@ -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 '../../
|
|
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. */
|
package/orm/server/module.d.ts
CHANGED
|
@@ -25,6 +25,5 @@ export type OrmModuleOptions = {
|
|
|
25
25
|
* @param options - Configuration options including connection details, repository settings, and the encryption secret.
|
|
26
26
|
*/
|
|
27
27
|
export declare function configureOrm({ injector, ...options }?: OrmModuleOptions & {
|
|
28
|
-
encryptionSecret?: Uint8Array;
|
|
29
28
|
injector?: Injector;
|
|
30
29
|
}): void;
|
package/orm/server/module.js
CHANGED
|
@@ -1,7 +1,6 @@
|
|
|
1
1
|
import { Injector } from '../../injector/injector.js';
|
|
2
2
|
import { isDefined } from '../../utils/type-guards.js';
|
|
3
3
|
import { EntityRepositoryConfig } from './repository-config.js';
|
|
4
|
-
import { ENCRYPTION_SECRET } from './tokens.js';
|
|
5
4
|
/**
|
|
6
5
|
* Configuration class for the database connection.
|
|
7
6
|
*/
|
|
@@ -20,7 +19,4 @@ export function configureOrm({ injector, ...options } = {}) {
|
|
|
20
19
|
if (isDefined(options.repositoryConfig)) {
|
|
21
20
|
targetInjector.register(EntityRepositoryConfig, { useValue: options.repositoryConfig });
|
|
22
21
|
}
|
|
23
|
-
if (isDefined(options.encryptionSecret)) {
|
|
24
|
-
targetInjector.register(ENCRYPTION_SECRET, { useValue: options.encryptionSecret });
|
|
25
|
-
}
|
|
26
22
|
}
|
|
@@ -1,6 +1,7 @@
|
|
|
1
1
|
/** biome-ignore-all lint/nursery/noExcessiveClassesPerFile: <explanation> */
|
|
2
2
|
import { SQL, type SQLWrapper } from 'drizzle-orm';
|
|
3
3
|
import type { AnyPgTable, PgColumn, PgInsertValue, PgSelectBuilder, PgUpdateSetSource, SelectedFields } from 'drizzle-orm/pg-core';
|
|
4
|
+
import { type DerivedKey } from '../../cryptography/index.js';
|
|
4
5
|
import { afterResolve, resolveArgumentType, type Resolvable } from '../../injector/interfaces.js';
|
|
5
6
|
import type { DeepPartial, Function, OneOrMany, Record, SimplifyObject, Type, TypedOmit } from '../../types/index.js';
|
|
6
7
|
import { Entity, type BaseEntity, type EntityMetadataAttributes, type EntityType } from '../entity.js';
|
|
@@ -16,7 +17,7 @@ type EntityRepositoryContext = {
|
|
|
16
17
|
table: PgTableFromType;
|
|
17
18
|
columnDefinitions: ColumnDefinition[];
|
|
18
19
|
columnDefinitionsMap: Map<string, ColumnDefinition>;
|
|
19
|
-
|
|
20
|
+
encryptionKey: DerivedKey | undefined;
|
|
20
21
|
transformContext: TransformContext | Promise<TransformContext> | undefined;
|
|
21
22
|
};
|
|
22
23
|
export type InferSelect<T extends BaseEntity = BaseEntity> = PgTableFromType<EntityType<T>>['$inferSelect'];
|
package/orm/server/repository.js
CHANGED
|
@@ -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 { injectDerivedCryptoKey } 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';
|
|
@@ -30,7 +30,6 @@ import { getInheritanceMetadata, isChildEntity } from '../utils.js';
|
|
|
30
30
|
import { getColumnDefinitions, getColumnDefinitionsMap, getDrizzleTableFromType, getPrimaryKeyColumnDefinitions, getPrimaryKeyColumns, getTableColumnDefinitions, isTableOwning } from './drizzle/schema-converter.js';
|
|
31
31
|
import { convertQuery, getTsQuery, getTsVector, resolveTargetColumn } from './query-converter.js';
|
|
32
32
|
import { EntityRepositoryConfig } from './repository-config.js';
|
|
33
|
-
import { ENCRYPTION_SECRET } from './tokens.js';
|
|
34
33
|
import { injectTransactional, injectTransactionalAsync, isInTransactionalContext, Transactional, tryGetTransactionalContextData } from './transactional.js';
|
|
35
34
|
const searchScoreColumn = '__tsl_score';
|
|
36
35
|
const searchDistanceColumn = '__tsl_distance';
|
|
@@ -40,7 +39,7 @@ export const repositoryType = Symbol('repositoryType');
|
|
|
40
39
|
const entityTypeToken = Symbol('EntityType');
|
|
41
40
|
let EntityRepository = class EntityRepository extends Transactional {
|
|
42
41
|
#context = (isInTransactionalContext() ? tryGetTransactionalContextData(this) : undefined) ?? {};
|
|
43
|
-
#
|
|
42
|
+
#encryptionKey = isInTransactionalContext() ? this.#context.encryptionKey : injectDerivedCryptoKey('orm:repository-encryption', { name: 'AES-GCM', length: 256 }, ['encrypt', 'decrypt']);
|
|
44
43
|
#cancellationSignal = isInTransactionalContext() ? undefined : inject(CancellationSignal);
|
|
45
44
|
#transformContext = this.#context.transformContext;
|
|
46
45
|
type = assertDefinedPass(this.#context.type ?? this.constructor[entityTypeToken] ?? injectArgument(this, { optional: true }), 'Missing entity type.');
|
|
@@ -57,7 +56,6 @@ let EntityRepository = class EntityRepository extends Transactional {
|
|
|
57
56
|
#columnDefinitionsMap = this.#context.columnDefinitionsMap ?? getColumnDefinitionsMap(this.#table);
|
|
58
57
|
#primaryKeyColumns = getPrimaryKeyColumns(this.type, this.#table);
|
|
59
58
|
#primaryKeyColumnNames = this.#primaryKeyColumns.map((column) => column.name);
|
|
60
|
-
#joinedTables = this.#tablesChain.filter((info) => info.table != this.#table).map((info) => info.table);
|
|
61
59
|
#inheritanceMetadata = getInheritanceMetadata(this.type);
|
|
62
60
|
#subclasses = this.#inheritanceMetadata?.subclasses ?? [];
|
|
63
61
|
#subclassTablesInfo = this.#subclasses.map((subclass) => {
|
|
@@ -138,7 +136,7 @@ let EntityRepository = class EntityRepository extends Transactional {
|
|
|
138
136
|
table: this.#table,
|
|
139
137
|
columnDefinitions: this.#columnDefinitions,
|
|
140
138
|
columnDefinitionsMap: this.#columnDefinitionsMap,
|
|
141
|
-
|
|
139
|
+
encryptionKey: this.#encryptionKey,
|
|
142
140
|
transformContext: this.#transformContext,
|
|
143
141
|
};
|
|
144
142
|
return context;
|
|
@@ -1746,15 +1744,14 @@ let EntityRepository = class EntityRepository extends Transactional {
|
|
|
1746
1744
|
}
|
|
1747
1745
|
async getTransformContext() {
|
|
1748
1746
|
if (isUndefined(this.#transformContext)) {
|
|
1749
|
-
if (isUndefined(this.#
|
|
1747
|
+
if (isUndefined(this.#encryptionKey)) {
|
|
1750
1748
|
this.#transformContext = {};
|
|
1751
1749
|
return this.#transformContext;
|
|
1752
1750
|
}
|
|
1753
|
-
this.#transformContext =
|
|
1754
|
-
|
|
1755
|
-
this.#transformContext = transformContext;
|
|
1751
|
+
this.#transformContext = this.#encryptionKey.getKey().then((encryptionKey) => ({ encryptionKey }));
|
|
1752
|
+
this.#transformContext = await this.#transformContext;
|
|
1756
1753
|
}
|
|
1757
|
-
return
|
|
1754
|
+
return this.#transformContext; // eslint-disable-line @typescript-eslint/return-await
|
|
1758
1755
|
}
|
|
1759
1756
|
async _mapSearchResults(rows, scoreTransformer = (s) => s, options) {
|
|
1760
1757
|
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
|
|
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
|
|
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
|
|
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)
|
|
@@ -17,7 +17,6 @@ import { toArrayAsync } from '../../utils/async-iterable-helpers/to-array.js';
|
|
|
17
17
|
import { ChildEntity, Column, Inheritance, Table } from '../decorators.js';
|
|
18
18
|
import { BaseEntity, Entity } from '../entity.js';
|
|
19
19
|
import { getRepository } from '../server/repository.js';
|
|
20
|
-
import { ENCRYPTION_SECRET } from '../server/tokens.js';
|
|
21
20
|
describe('ORM Repository Extra Coverage', () => {
|
|
22
21
|
let injector;
|
|
23
22
|
let database;
|
|
@@ -80,7 +79,6 @@ describe('ORM Repository Extra Coverage', () => {
|
|
|
80
79
|
], PlainItem);
|
|
81
80
|
beforeAll(async () => {
|
|
82
81
|
({ injector, database } = await setupIntegrationTest({ orm: { schema } }));
|
|
83
|
-
injector.register(ENCRYPTION_SECRET, { useValue: new Uint8Array(32).fill(1) });
|
|
84
82
|
baseItemRepo = injector.resolve(getRepository(BaseItem));
|
|
85
83
|
premiumItemRepo = injector.resolve(getRepository(PremiumItem));
|
|
86
84
|
simpleItemRepo = injector.resolve(getRepository(SimpleItem));
|
|
@@ -17,7 +17,6 @@ import { Column, EmbeddedProperty, EncryptedProperty, Reference, Table } from '.
|
|
|
17
17
|
import { Entity } from '../entity.js';
|
|
18
18
|
import { JsonProperty, NumericDateProperty } from '../schemas/index.js';
|
|
19
19
|
import { getRepository } from '../server/index.js';
|
|
20
|
-
import { ENCRYPTION_SECRET } from '../server/tokens.js';
|
|
21
20
|
describe('ORM Repository Regression (Integration)', () => {
|
|
22
21
|
let injector;
|
|
23
22
|
let db;
|
|
@@ -101,11 +100,9 @@ describe('ORM Repository Regression (Integration)', () => {
|
|
|
101
100
|
Table('posts', { schema })
|
|
102
101
|
], Post);
|
|
103
102
|
beforeAll(async () => {
|
|
104
|
-
const encryptionSecret = new Uint8Array(32).fill(1);
|
|
105
103
|
({ injector, database: db } = await setupIntegrationTest({
|
|
106
104
|
orm: { schema },
|
|
107
105
|
}));
|
|
108
|
-
injector.register(ENCRYPTION_SECRET, { useValue: encryptionSecret });
|
|
109
106
|
standardRepository = injector.resolve(getRepository(StandardEntity));
|
|
110
107
|
postRepository = injector.resolve(getRepository(Post));
|
|
111
108
|
await db.execute(sql `CREATE SCHEMA IF NOT EXISTS ${sql.identifier(schema)}`);
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@tstdl/base",
|
|
3
|
-
"version": "0.93.
|
|
3
|
+
"version": "0.93.180",
|
|
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.
|
|
156
|
-
"@aws-sdk/s3-request-presigner": "^3.
|
|
157
|
-
"@genkit-ai/google-genai": "^1.
|
|
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": "^
|
|
167
|
-
"genkit": "^1.
|
|
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": "
|
|
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.
|
|
206
|
+
"typescript-eslint": "8.58",
|
|
206
207
|
"vitest": "4.1"
|
|
207
208
|
}
|
|
208
209
|
}
|
package/password/README.md
CHANGED
|
@@ -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 `
|
|
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,5 +1,5 @@
|
|
|
1
1
|
CREATE TABLE "rate_limit"."rate_limit" (
|
|
2
|
-
"id" uuid PRIMARY KEY DEFAULT
|
|
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": "
|
|
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": "
|
|
16
|
+
"default": "uuidv7()"
|
|
17
17
|
},
|
|
18
18
|
"resource": {
|
|
19
19
|
"name": "resource",
|
|
@@ -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
|
|
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
|
|
34
|
+
abstract refund(resource: string, amount?: number, options?: Partial<Pick<RateLimiterConfig, 'burstCapacity'>>): Promise<void>;
|
|
35
35
|
}
|