@tstdl/base 0.93.77 → 0.93.78

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 (101) hide show
  1. package/authentication/client/http-client.middleware.js +2 -2
  2. package/authentication/models/authentication-credentials.model.d.ts +2 -2
  3. package/authentication/models/authentication-credentials.model.js +5 -3
  4. package/authentication/models/authentication-session.model.d.ts +2 -2
  5. package/authentication/models/authentication-session.model.js +5 -3
  6. package/authentication/models/index.d.ts +4 -0
  7. package/authentication/models/index.js +4 -0
  8. package/authentication/models/service-account.model.d.ts +7 -0
  9. package/authentication/models/service-account.model.js +31 -0
  10. package/authentication/models/subject.model.d.ts +16 -0
  11. package/authentication/models/subject.model.js +59 -0
  12. package/authentication/models/system-account.model.d.ts +5 -0
  13. package/authentication/models/system-account.model.js +25 -0
  14. package/authentication/models/user.model.d.ts +15 -0
  15. package/authentication/models/user.model.js +47 -0
  16. package/authentication/server/drizzle/0001_condemned_pretty_boy.sql +70 -0
  17. package/authentication/server/drizzle/meta/0001_snapshot.json +651 -0
  18. package/authentication/server/drizzle/meta/_journal.json +7 -0
  19. package/authentication/server/index.d.ts +1 -0
  20. package/authentication/server/index.js +1 -0
  21. package/authentication/server/schemas.d.ts +16 -1
  22. package/authentication/server/schemas.js +7 -1
  23. package/authentication/server/subject.service.d.ts +6 -0
  24. package/authentication/server/subject.service.js +44 -0
  25. package/circuit-breaker/circuit-breaker.d.ts +32 -0
  26. package/circuit-breaker/circuit-breaker.js +9 -0
  27. package/circuit-breaker/index.d.ts +2 -0
  28. package/circuit-breaker/index.js +2 -0
  29. package/circuit-breaker/postgres/circuit-breaker.d.ts +7 -0
  30. package/circuit-breaker/postgres/circuit-breaker.js +78 -0
  31. package/circuit-breaker/postgres/drizzle/0000_hard_shocker.sql +9 -0
  32. package/circuit-breaker/postgres/drizzle/meta/0000_snapshot.json +82 -0
  33. package/circuit-breaker/postgres/drizzle/meta/_journal.json +13 -0
  34. package/circuit-breaker/postgres/drizzle.config.d.ts +2 -0
  35. package/circuit-breaker/postgres/drizzle.config.js +11 -0
  36. package/circuit-breaker/postgres/index.d.ts +5 -0
  37. package/circuit-breaker/postgres/index.js +5 -0
  38. package/circuit-breaker/postgres/model.d.ts +9 -0
  39. package/circuit-breaker/postgres/model.js +40 -0
  40. package/circuit-breaker/postgres/module.d.ts +6 -0
  41. package/circuit-breaker/postgres/module.js +25 -0
  42. package/circuit-breaker/postgres/provider.d.ts +6 -0
  43. package/circuit-breaker/postgres/provider.js +21 -0
  44. package/circuit-breaker/postgres/schemas.d.ts +8 -0
  45. package/circuit-breaker/postgres/schemas.js +6 -0
  46. package/circuit-breaker/provider.d.ts +4 -0
  47. package/circuit-breaker/provider.js +2 -0
  48. package/circuit-breaker/tests/circuit-breaker.test.js +113 -0
  49. package/document-management/models/document.model.d.ts +0 -1
  50. package/document-management/models/document.model.js +0 -5
  51. package/document-management/server/api/document-management.api.js +1 -2
  52. package/document-management/server/drizzle/0002_round_warbird.sql +1 -0
  53. package/document-management/server/drizzle/meta/0002_snapshot.json +2722 -0
  54. package/document-management/server/drizzle/meta/_journal.json +7 -0
  55. package/document-management/server/services/document-collection.service.js +3 -3
  56. package/document-management/server/services/document-management-ancillary.service.d.ts +1 -1
  57. package/document-management/server/services/document-management.service.js +1 -1
  58. package/document-management/server/services/document-workflow.service.js +5 -5
  59. package/document-management/server/services/document.service.d.ts +0 -2
  60. package/document-management/server/services/document.service.js +1 -2
  61. package/document-management/service-models/enriched/enriched-document.view.d.ts +1 -1
  62. package/examples/document-management/main.d.ts +1 -1
  63. package/examples/document-management/main.js +1 -1
  64. package/logger/transports/console.d.ts +1 -1
  65. package/logger/transports/console.js +4 -1
  66. package/message-bus/message-bus-base.js +1 -1
  67. package/package.json +6 -3
  68. package/queue/enqueue-batch.d.ts +11 -11
  69. package/queue/enqueue-batch.js +2 -3
  70. package/queue/index.d.ts +1 -0
  71. package/queue/index.js +1 -0
  72. package/queue/postgres/drizzle/0003_tricky_venom.sql +30 -0
  73. package/queue/postgres/drizzle/meta/0003_snapshot.json +288 -0
  74. package/queue/postgres/drizzle/meta/_journal.json +7 -0
  75. package/queue/postgres/drizzle.config.js +2 -2
  76. package/queue/postgres/index.d.ts +1 -1
  77. package/queue/postgres/index.js +1 -1
  78. package/queue/postgres/module.d.ts +1 -1
  79. package/queue/postgres/module.js +1 -1
  80. package/queue/postgres/queue.d.ts +52 -23
  81. package/queue/postgres/queue.js +582 -64
  82. package/queue/postgres/queue.provider.d.ts +1 -1
  83. package/queue/postgres/schemas.d.ts +13 -2
  84. package/queue/postgres/schemas.js +4 -2
  85. package/queue/postgres/task.model.d.ts +24 -0
  86. package/queue/postgres/task.model.js +115 -0
  87. package/queue/provider.d.ts +1 -1
  88. package/queue/queue.d.ts +158 -37
  89. package/queue/queue.js +97 -19
  90. package/queue/task-context.d.ts +38 -0
  91. package/queue/task-context.js +102 -0
  92. package/queue/tests/queue.test.d.ts +1 -0
  93. package/queue/tests/queue.test.js +623 -0
  94. package/test4.d.ts +1 -1
  95. package/test4.js +1 -1
  96. package/utils/format-error.d.ts +17 -20
  97. package/utils/format-error.js +105 -47
  98. package/queue/postgres/job.model.d.ts +0 -12
  99. package/queue/postgres/job.model.js +0 -53
  100. package/test6.js +0 -33
  101. /package/{test6.d.ts → circuit-breaker/tests/circuit-breaker.test.d.ts} +0 -0
@@ -1,5 +1,11 @@
1
1
  import { databaseSchema } from '../../orm/server/index.js';
2
- import { AuthenticationCredentials, AuthenticationSession } from '../models/index.js';
2
+ import { AuthenticationCredentials, AuthenticationSession, ServiceAccount, Subject, SubjectType, SystemAccount, User, UserStatus } from '../models/index.js';
3
3
  export const authenticationSchema = databaseSchema('authentication');
4
+ export const subjectType = authenticationSchema.getEnum(SubjectType);
5
+ export const userStatus = authenticationSchema.getEnum(UserStatus);
4
6
  export const authenticationCredentials = authenticationSchema.getTable(AuthenticationCredentials);
5
7
  export const authenticationSession = authenticationSchema.getTable(AuthenticationSession);
8
+ export const serviceAccount = authenticationSchema.getTable(ServiceAccount);
9
+ export const subject = authenticationSchema.getTable(Subject);
10
+ export const systemAccount = authenticationSchema.getTable(SystemAccount);
11
+ export const user = authenticationSchema.getTable(User);
@@ -0,0 +1,6 @@
1
+ import { Subject, SystemAccount } from '../models/index.js';
2
+ export declare class SubjectService {
3
+ readonly subjectRepository: import("../../orm/server/index.js").EntityRepository<Subject>;
4
+ readonly systemAccountRepository: import("../../orm/server/index.js").EntityRepository<SystemAccount>;
5
+ getSystemAccountSubject(tenantId: string, identifier: string): Promise<Subject>;
6
+ }
@@ -0,0 +1,44 @@
1
+ var __decorate = (this && this.__decorate) || function (decorators, target, key, desc) {
2
+ var c = arguments.length, r = c < 3 ? target : desc === null ? desc = Object.getOwnPropertyDescriptor(target, key) : desc, d;
3
+ if (typeof Reflect === "object" && typeof Reflect.decorate === "function") r = Reflect.decorate(decorators, target, key, desc);
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
+ return c > 3 && r && Object.defineProperty(target, key, r), r;
6
+ };
7
+ import { Singleton } from '../../injector/index.js';
8
+ import { injectRepository } from '../../orm/server/index.js';
9
+ import { isUndefined } from '../../utils/type-guards.js';
10
+ import { Subject, SubjectType, SystemAccount } from '../models/index.js';
11
+ let SubjectService = class SubjectService {
12
+ subjectRepository = injectRepository(Subject);
13
+ systemAccountRepository = injectRepository(SystemAccount);
14
+ async getSystemAccountSubject(tenantId, identifier) {
15
+ return await this.subjectRepository.transaction(async (tx) => {
16
+ let systemAccount = await this.systemAccountRepository.withTransaction(tx).tryLoadByQuery({
17
+ tenantId,
18
+ identifier,
19
+ });
20
+ if (isUndefined(systemAccount)) {
21
+ systemAccount = await this.systemAccountRepository.withTransaction(tx).insert({
22
+ tenantId,
23
+ identifier,
24
+ });
25
+ return await this.subjectRepository.withTransaction(tx).insert({
26
+ type: SubjectType.System,
27
+ tenantId,
28
+ systemAccountId: systemAccount.id,
29
+ displayName: `System: ${identifier}`,
30
+ userId: null,
31
+ serviceAccountId: null,
32
+ });
33
+ }
34
+ return await this.subjectRepository.withTransaction(tx).loadByQuery({
35
+ tenantId,
36
+ systemAccountId: systemAccount.id,
37
+ });
38
+ });
39
+ }
40
+ };
41
+ SubjectService = __decorate([
42
+ Singleton()
43
+ ], SubjectService);
44
+ export { SubjectService };
@@ -0,0 +1,32 @@
1
+ import { type EnumType } from '../enumeration/enumeration.js';
2
+ import { resolveArgumentType, type Resolvable } from '../injector/interfaces.js';
3
+ export declare const CircuitBreakerState: {
4
+ readonly Closed: "closed";
5
+ readonly Open: "open";
6
+ readonly HalfOpen: "half-open";
7
+ };
8
+ export type CircuitBreakerState = EnumType<typeof CircuitBreakerState>;
9
+ export interface CircuitBreakerConfig {
10
+ threshold: number;
11
+ resetTimeout: number;
12
+ }
13
+ export interface CircuitBreakerCheckResult {
14
+ allowed: boolean;
15
+ state: CircuitBreakerState;
16
+ isProbe?: boolean;
17
+ }
18
+ export type CircuitBreakerArgument = string | (CircuitBreakerConfig & {
19
+ key: string;
20
+ });
21
+ export declare abstract class CircuitBreaker implements Resolvable<CircuitBreakerArgument> {
22
+ readonly [resolveArgumentType]: CircuitBreakerArgument;
23
+ /**
24
+ * Checks if execution is allowed.
25
+ * Transitions from Open to Half-Open automatically if timeout passed.
26
+ */
27
+ abstract check(): Promise<CircuitBreakerCheckResult>;
28
+ /** Records a success, resetting the breaker to Closed. */
29
+ abstract recordSuccess(): Promise<void>;
30
+ /** Records a failure, potentially tripping the breaker to Open. */
31
+ abstract recordFailure(): Promise<void>;
32
+ }
@@ -0,0 +1,9 @@
1
+ import { defineEnum } from '../enumeration/enumeration.js';
2
+ import { resolveArgumentType } from '../injector/interfaces.js';
3
+ export const CircuitBreakerState = defineEnum('CircuitBreakerState', {
4
+ Closed: 'closed',
5
+ Open: 'open',
6
+ HalfOpen: 'half-open',
7
+ });
8
+ export class CircuitBreaker {
9
+ }
@@ -0,0 +1,2 @@
1
+ export * from './circuit-breaker.js';
2
+ export * from './provider.js';
@@ -0,0 +1,2 @@
1
+ export * from './circuit-breaker.js';
2
+ export * from './provider.js';
@@ -0,0 +1,7 @@
1
+ import { CircuitBreaker, type CircuitBreakerCheckResult } from '../circuit-breaker.js';
2
+ export declare class PostgresCircuitBreakerService extends CircuitBreaker {
3
+ #private;
4
+ check(): Promise<CircuitBreakerCheckResult>;
5
+ recordSuccess(): Promise<void>;
6
+ recordFailure(): Promise<void>;
7
+ }
@@ -0,0 +1,78 @@
1
+ var __decorate = (this && this.__decorate) || function (decorators, target, key, desc) {
2
+ var c = arguments.length, r = c < 3 ? target : desc === null ? desc = Object.getOwnPropertyDescriptor(target, key) : desc, d;
3
+ if (typeof Reflect === "object" && typeof Reflect.decorate === "function") r = Reflect.decorate(decorators, target, key, desc);
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
+ return c > 3 && r && Object.defineProperty(target, key, r), r;
6
+ };
7
+ import { sql } from 'drizzle-orm';
8
+ import { injectArgument, provide, Singleton } from '../../injector/index.js';
9
+ import { interval, TRANSACTION_TIMESTAMP } from '../../orm/index.js';
10
+ import { DatabaseConfig, injectRepository } from '../../orm/server/index.js';
11
+ import { currentTimestamp } from '../../utils/date-time.js';
12
+ import { isDefined, isString, isUndefined } from '../../utils/type-guards.js';
13
+ import { millisecondsPerSecond } from '../../utils/units.js';
14
+ import { CircuitBreaker, CircuitBreakerState } from '../circuit-breaker.js';
15
+ import { PostgresCircuitBreaker } from './model.js';
16
+ import { PostgresCircuitBreakerModuleConfig } from './module.js';
17
+ let PostgresCircuitBreakerService = class PostgresCircuitBreakerService extends CircuitBreaker {
18
+ #repository = injectRepository(PostgresCircuitBreaker);
19
+ #arg = injectArgument(this);
20
+ #key = isString(this.#arg) ? this.#arg : this.#arg.key;
21
+ #threshold = (isString(this.#arg) ? undefined : this.#arg.threshold) ?? 5;
22
+ #resetTimeout = (isString(this.#arg) ? undefined : this.#arg.resetTimeout) ?? 30 * millisecondsPerSecond;
23
+ async check() {
24
+ return await this.#repository.transaction(async (tx) => {
25
+ const breaker = await this.#repository.withTransaction(tx).tryLoadByQuery({ key: this.#key });
26
+ if (isUndefined(breaker) || breaker.state === CircuitBreakerState.Closed) {
27
+ return { allowed: true, state: CircuitBreakerState.Closed };
28
+ }
29
+ if (breaker.state === CircuitBreakerState.HalfOpen) {
30
+ return { allowed: true, state: CircuitBreakerState.HalfOpen, isProbe: false };
31
+ }
32
+ // State is Open
33
+ if (currentTimestamp() < (breaker.resetTimestamp ?? 0)) {
34
+ return { allowed: false, state: CircuitBreakerState.Open };
35
+ }
36
+ // Atomic transition from Open -> HalfOpen (The Probe)
37
+ const updated = await this.#repository.withTransaction(tx).tryUpdateByQuery({ key: this.#key, state: CircuitBreakerState.Open }, { state: CircuitBreakerState.HalfOpen });
38
+ const isProbe = isDefined(updated);
39
+ return { allowed: isProbe, state: isProbe ? CircuitBreakerState.HalfOpen : CircuitBreakerState.Open, isProbe };
40
+ });
41
+ }
42
+ async recordSuccess() {
43
+ await this.#repository.tryDeleteByQuery({ key: this.#key });
44
+ }
45
+ async recordFailure() {
46
+ const table = this.#repository.table;
47
+ const initialTrip = 1 >= this.#threshold;
48
+ const initialState = initialTrip ? CircuitBreakerState.Open : CircuitBreakerState.Closed;
49
+ const initialResetTimestamp = initialTrip
50
+ ? sql `${TRANSACTION_TIMESTAMP} + ${interval(this.#resetTimeout, 'milliseconds')}`
51
+ : null;
52
+ await this.#repository.upsert(['key'], {
53
+ key: this.#key,
54
+ state: initialState,
55
+ failureCount: 1,
56
+ resetTimestamp: initialResetTimestamp,
57
+ }, {
58
+ failureCount: sql `${table.failureCount} + 1`,
59
+ state: sql `CASE
60
+ WHEN ${table.failureCount} + 1 >= ${this.#threshold} THEN ${CircuitBreakerState.Open}
61
+ ELSE ${table.state}
62
+ END`,
63
+ resetTimestamp: sql `CASE
64
+ WHEN ${table.failureCount} + 1 >= ${this.#threshold} THEN ${TRANSACTION_TIMESTAMP} + ${interval(this.#resetTimeout, 'milliseconds')}
65
+ ELSE ${table.resetTimestamp}
66
+ END`,
67
+ });
68
+ }
69
+ };
70
+ PostgresCircuitBreakerService = __decorate([
71
+ Singleton({
72
+ argumentIdentityProvider: (arg) => isString(arg) ? arg : arg.key,
73
+ providers: [
74
+ provide(DatabaseConfig, { useFactory: (_, context) => context.resolve(PostgresCircuitBreakerModuleConfig).database ?? context.resolve(DatabaseConfig, undefined, { skipSelf: 2 }) }),
75
+ ],
76
+ })
77
+ ], PostgresCircuitBreakerService);
78
+ export { PostgresCircuitBreakerService };
@@ -0,0 +1,9 @@
1
+ CREATE TYPE "circuit_breaker"."circuit_breaker_state" AS ENUM('closed', 'open', 'half-open');--> statement-breakpoint
2
+ CREATE TABLE "circuit_breaker"."circuit_breaker" (
3
+ "id" uuid PRIMARY KEY DEFAULT gen_random_uuid() NOT NULL,
4
+ "key" text NOT NULL,
5
+ "state" "circuit_breaker"."circuit_breaker_state" NOT NULL,
6
+ "failure_count" integer NOT NULL,
7
+ "reset_timestamp" timestamp with time zone,
8
+ CONSTRAINT "circuit_breaker_key_unique" UNIQUE("key")
9
+ );
@@ -0,0 +1,82 @@
1
+ {
2
+ "id": "cc140886-299f-4337-b208-50a976c703f3",
3
+ "prevId": "00000000-0000-0000-0000-000000000000",
4
+ "version": "7",
5
+ "dialect": "postgresql",
6
+ "tables": {
7
+ "circuit_breaker.circuit_breaker": {
8
+ "name": "circuit_breaker",
9
+ "schema": "circuit_breaker",
10
+ "columns": {
11
+ "id": {
12
+ "name": "id",
13
+ "type": "uuid",
14
+ "primaryKey": true,
15
+ "notNull": true,
16
+ "default": "gen_random_uuid()"
17
+ },
18
+ "key": {
19
+ "name": "key",
20
+ "type": "text",
21
+ "primaryKey": false,
22
+ "notNull": true
23
+ },
24
+ "state": {
25
+ "name": "state",
26
+ "type": "circuit_breaker_state",
27
+ "typeSchema": "circuit_breaker",
28
+ "primaryKey": false,
29
+ "notNull": true
30
+ },
31
+ "failure_count": {
32
+ "name": "failure_count",
33
+ "type": "integer",
34
+ "primaryKey": false,
35
+ "notNull": true
36
+ },
37
+ "reset_timestamp": {
38
+ "name": "reset_timestamp",
39
+ "type": "timestamp with time zone",
40
+ "primaryKey": false,
41
+ "notNull": false
42
+ }
43
+ },
44
+ "indexes": {},
45
+ "foreignKeys": {},
46
+ "compositePrimaryKeys": {},
47
+ "uniqueConstraints": {
48
+ "circuit_breaker_key_unique": {
49
+ "name": "circuit_breaker_key_unique",
50
+ "nullsNotDistinct": false,
51
+ "columns": [
52
+ "key"
53
+ ]
54
+ }
55
+ },
56
+ "policies": {},
57
+ "checkConstraints": {},
58
+ "isRLSEnabled": false
59
+ }
60
+ },
61
+ "enums": {
62
+ "circuit_breaker.circuit_breaker_state": {
63
+ "name": "circuit_breaker_state",
64
+ "schema": "circuit_breaker",
65
+ "values": [
66
+ "closed",
67
+ "open",
68
+ "half-open"
69
+ ]
70
+ }
71
+ },
72
+ "schemas": {},
73
+ "sequences": {},
74
+ "roles": {},
75
+ "policies": {},
76
+ "views": {},
77
+ "_meta": {
78
+ "columns": {},
79
+ "schemas": {},
80
+ "tables": {}
81
+ }
82
+ }
@@ -0,0 +1,13 @@
1
+ {
2
+ "version": "7",
3
+ "dialect": "postgresql",
4
+ "entries": [
5
+ {
6
+ "idx": 0,
7
+ "version": "7",
8
+ "when": 1767729693157,
9
+ "tag": "0000_hard_shocker",
10
+ "breakpoints": true
11
+ }
12
+ ]
13
+ }
@@ -0,0 +1,2 @@
1
+ declare const _default: import("drizzle-kit").Config;
2
+ export default _default;
@@ -0,0 +1,11 @@
1
+ import { relative, resolve } from 'node:path';
2
+ import { defineConfig } from 'drizzle-kit';
3
+ export default defineConfig({
4
+ dialect: 'postgresql',
5
+ out: relative('./', resolve(__dirname, './drizzle/').replace('dist', 'source')),
6
+ schema: resolve(__dirname, './schemas.js'),
7
+ migrations: {
8
+ schema: 'circuit_breaker',
9
+ table: '_migrations',
10
+ },
11
+ });
@@ -0,0 +1,5 @@
1
+ export * from './circuit-breaker.js';
2
+ export * from './model.js';
3
+ export * from './module.js';
4
+ export * from './provider.js';
5
+ export * from './schemas.js';
@@ -0,0 +1,5 @@
1
+ export * from './circuit-breaker.js';
2
+ export * from './model.js';
3
+ export * from './module.js';
4
+ export * from './provider.js';
5
+ export * from './schemas.js';
@@ -0,0 +1,9 @@
1
+ import { BaseEntity, type Timestamp } from '../../orm/index.js';
2
+ import { CircuitBreakerState } from '../circuit-breaker.js';
3
+ export declare class PostgresCircuitBreaker extends BaseEntity {
4
+ static readonly entityName = "CircuitBreaker";
5
+ key: string;
6
+ state: CircuitBreakerState;
7
+ failureCount: number;
8
+ resetTimestamp: Timestamp | null;
9
+ }
@@ -0,0 +1,40 @@
1
+ var __decorate = (this && this.__decorate) || function (decorators, target, key, desc) {
2
+ var c = arguments.length, r = c < 3 ? target : desc === null ? desc = Object.getOwnPropertyDescriptor(target, key) : desc, d;
3
+ if (typeof Reflect === "object" && typeof Reflect.decorate === "function") r = Reflect.decorate(decorators, target, key, desc);
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
+ return c > 3 && r && Object.defineProperty(target, key, r), r;
6
+ };
7
+ var __metadata = (this && this.__metadata) || function (k, v) {
8
+ if (typeof Reflect === "object" && typeof Reflect.metadata === "function") return Reflect.metadata(k, v);
9
+ };
10
+ import { BaseEntity, Table, TimestampProperty, Unique } from '../../orm/index.js';
11
+ import { Enumeration, Integer, StringProperty } from '../../schema/index.js';
12
+ import { CircuitBreakerState } from '../circuit-breaker.js';
13
+ let PostgresCircuitBreaker = class PostgresCircuitBreaker extends BaseEntity {
14
+ static entityName = 'CircuitBreaker';
15
+ key;
16
+ state;
17
+ failureCount;
18
+ resetTimestamp;
19
+ };
20
+ __decorate([
21
+ StringProperty(),
22
+ Unique(),
23
+ __metadata("design:type", String)
24
+ ], PostgresCircuitBreaker.prototype, "key", void 0);
25
+ __decorate([
26
+ Enumeration(CircuitBreakerState),
27
+ __metadata("design:type", String)
28
+ ], PostgresCircuitBreaker.prototype, "state", void 0);
29
+ __decorate([
30
+ Integer(),
31
+ __metadata("design:type", Number)
32
+ ], PostgresCircuitBreaker.prototype, "failureCount", void 0);
33
+ __decorate([
34
+ TimestampProperty({ nullable: true }),
35
+ __metadata("design:type", Object)
36
+ ], PostgresCircuitBreaker.prototype, "resetTimestamp", void 0);
37
+ PostgresCircuitBreaker = __decorate([
38
+ Table('circuit_breaker', { schema: 'circuit_breaker' })
39
+ ], PostgresCircuitBreaker);
40
+ export { PostgresCircuitBreaker };
@@ -0,0 +1,6 @@
1
+ import { type DatabaseConfig } from '../../orm/server/index.js';
2
+ export declare class PostgresCircuitBreakerModuleConfig {
3
+ database?: DatabaseConfig;
4
+ }
5
+ export declare function configurePostgresCircuitBreaker(config?: PostgresCircuitBreakerModuleConfig, register?: boolean): void;
6
+ export declare function migratePostgresCircuitBreaker(): Promise<void>;
@@ -0,0 +1,25 @@
1
+ import { inject, Injector } from '../../injector/index.js';
2
+ import { Database, migrate } from '../../orm/server/index.js';
3
+ import { CircuitBreaker } from '../circuit-breaker.js';
4
+ import { CircuitBreakerProvider } from '../provider.js';
5
+ import { PostgresCircuitBreakerService } from './circuit-breaker.js';
6
+ import { PostgresCircuitBreakerProvider } from './provider.js';
7
+ export class PostgresCircuitBreakerModuleConfig {
8
+ database;
9
+ }
10
+ export function configurePostgresCircuitBreaker(config, register = true) {
11
+ Injector.register(PostgresCircuitBreakerModuleConfig, { useValue: config });
12
+ if (register) {
13
+ Injector.registerSingleton(CircuitBreakerProvider, { useToken: PostgresCircuitBreakerProvider });
14
+ Injector.registerSingleton(CircuitBreaker, { useToken: PostgresCircuitBreakerService });
15
+ }
16
+ }
17
+ export async function migratePostgresCircuitBreaker() {
18
+ const connection = inject(PostgresCircuitBreakerModuleConfig, undefined, { optional: true })?.database?.connection;
19
+ const database = inject(Database, connection);
20
+ await migrate(database, {
21
+ migrationsSchema: 'circuit_breaker',
22
+ migrationsTable: '_migrations',
23
+ migrationsFolder: import.meta.resolve('./drizzle'),
24
+ });
25
+ }
@@ -0,0 +1,6 @@
1
+ import type { CircuitBreaker, CircuitBreakerConfig } from '../circuit-breaker.js';
2
+ import { CircuitBreakerProvider } from '../provider.js';
3
+ export declare class PostgresCircuitBreakerProvider extends CircuitBreakerProvider {
4
+ #private;
5
+ provide(key: string, config?: CircuitBreakerConfig): CircuitBreaker;
6
+ }
@@ -0,0 +1,21 @@
1
+ var __decorate = (this && this.__decorate) || function (decorators, target, key, desc) {
2
+ var c = arguments.length, r = c < 3 ? target : desc === null ? desc = Object.getOwnPropertyDescriptor(target, key) : desc, d;
3
+ if (typeof Reflect === "object" && typeof Reflect.decorate === "function") r = Reflect.decorate(decorators, target, key, desc);
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
+ return c > 3 && r && Object.defineProperty(target, key, r), r;
6
+ };
7
+ import { inject, Singleton } from '../../injector/index.js';
8
+ import { Injector } from '../../injector/injector.js';
9
+ import { CircuitBreakerProvider } from '../provider.js';
10
+ import { PostgresCircuitBreakerService } from './circuit-breaker.js';
11
+ let PostgresCircuitBreakerProvider = class PostgresCircuitBreakerProvider extends CircuitBreakerProvider {
12
+ #injector = inject(Injector);
13
+ provide(key, config) {
14
+ const argument = config ? { key, ...config } : key;
15
+ return this.#injector.resolve(PostgresCircuitBreakerService, argument);
16
+ }
17
+ };
18
+ PostgresCircuitBreakerProvider = __decorate([
19
+ Singleton()
20
+ ], PostgresCircuitBreakerProvider);
21
+ export { PostgresCircuitBreakerProvider };
@@ -0,0 +1,8 @@
1
+ import { PostgresCircuitBreaker } from './model.js';
2
+ export declare const circuitBreakerSchema: import("../../orm/server/index.js").DatabaseSchema<"circuit_breaker">;
3
+ export declare const circuitBreakerState: import("../../orm/enums.js").PgEnumFromEnumeration<{
4
+ readonly Closed: "closed";
5
+ readonly Open: "open";
6
+ readonly HalfOpen: "half-open";
7
+ }>;
8
+ export declare const circuitBreaker: import("../../orm/server/types.js").PgTableFromType<typeof PostgresCircuitBreaker, "circuit_breaker">;
@@ -0,0 +1,6 @@
1
+ import { databaseSchema } from '../../orm/server/index.js';
2
+ import { CircuitBreakerState } from '../circuit-breaker.js';
3
+ import { PostgresCircuitBreaker } from './model.js';
4
+ export const circuitBreakerSchema = databaseSchema('circuit_breaker');
5
+ export const circuitBreakerState = circuitBreakerSchema.getEnum(CircuitBreakerState);
6
+ export const circuitBreaker = circuitBreakerSchema.getTable(PostgresCircuitBreaker);
@@ -0,0 +1,4 @@
1
+ import type { CircuitBreaker, CircuitBreakerConfig } from './circuit-breaker.js';
2
+ export declare abstract class CircuitBreakerProvider {
3
+ abstract provide(key: string, config?: CircuitBreakerConfig): CircuitBreaker;
4
+ }
@@ -0,0 +1,2 @@
1
+ export class CircuitBreakerProvider {
2
+ }
@@ -0,0 +1,113 @@
1
+ import { afterAll, beforeAll, describe, expect, it } from 'vitest';
2
+ import { CircuitBreakerState } from '../../circuit-breaker/index.js';
3
+ import { CircuitBreakerProvider } from '../../circuit-breaker/provider.js';
4
+ import { Injector, runInInjectionContext } from '../../injector/index.js';
5
+ import { configureOrm } from '../../orm/server/index.js';
6
+ import * as configParser from '../../utils/config-parser.js';
7
+ import { timeout } from '../../utils/timing.js';
8
+ import { configurePostgresCircuitBreaker, migratePostgresCircuitBreaker } from '../postgres/module.js';
9
+ async function setupIntegrationTest() {
10
+ const injector = new Injector('TestInjector');
11
+ const dbConfig = {
12
+ host: configParser.string('DATABASE_HOST', '127.0.0.1'),
13
+ port: configParser.positiveInteger('DATABASE_PORT', 5432),
14
+ user: configParser.string('DATABASE_USER', 'tstdl'),
15
+ password: configParser.string('DATABASE_PASS', 'wf7rq6glrk5jykne'),
16
+ database: configParser.string('DATABASE_NAME', 'tstdl'),
17
+ };
18
+ configureOrm({
19
+ repositoryConfig: { schema: 'test' },
20
+ connection: dbConfig,
21
+ });
22
+ configurePostgresCircuitBreaker({ database: { connection: dbConfig } });
23
+ await runInInjectionContext(injector, migratePostgresCircuitBreaker);
24
+ return injector;
25
+ }
26
+ describe('Circuit Breaker (Standalone) Tests', () => {
27
+ let injector;
28
+ let provider;
29
+ beforeAll(async () => {
30
+ injector = await setupIntegrationTest();
31
+ provider = injector.resolve(CircuitBreakerProvider);
32
+ });
33
+ afterAll(async () => {
34
+ await injector.dispose();
35
+ });
36
+ it('should start in Closed state', async () => {
37
+ const breaker = provider.provide(`cb-init-${Date.now()}`, { threshold: 2, resetTimeout: 1000 });
38
+ const result = await breaker.check();
39
+ expect(result.allowed).toBe(true);
40
+ expect(result.state).toBe(CircuitBreakerState.Closed);
41
+ });
42
+ it('should trip to Open after threshold failures', async () => {
43
+ const breaker = provider.provide(`cb-trip-${Date.now()}`, { threshold: 2, resetTimeout: 1000 });
44
+ // 1. First Failure
45
+ await breaker.recordFailure();
46
+ let result = await breaker.check();
47
+ expect(result.state).toBe(CircuitBreakerState.Closed);
48
+ // 2. Second Failure (Threshold Reached)
49
+ await breaker.recordFailure();
50
+ result = await breaker.check();
51
+ expect(result.allowed).toBe(false);
52
+ expect(result.state).toBe(CircuitBreakerState.Open);
53
+ });
54
+ it('should reset to Closed on success', async () => {
55
+ const breaker = provider.provide(`cb-reset-${Date.now()}`, { threshold: 2, resetTimeout: 1000 });
56
+ // Trip it
57
+ await breaker.recordFailure();
58
+ await breaker.recordFailure();
59
+ expect((await breaker.check()).state).toBe(CircuitBreakerState.Open);
60
+ // Record Success
61
+ await breaker.recordSuccess();
62
+ const result = await breaker.check();
63
+ expect(result.allowed).toBe(true);
64
+ expect(result.state).toBe(CircuitBreakerState.Closed);
65
+ });
66
+ it('should transition to Half-Open (Probe) after timeout', async () => {
67
+ const timeoutMs = 200;
68
+ const breaker = provider.provide(`cb-probe-${Date.now()}`, { threshold: 1, resetTimeout: timeoutMs });
69
+ // Trip it
70
+ await breaker.recordFailure();
71
+ expect((await breaker.check()).state).toBe(CircuitBreakerState.Open);
72
+ // Wait for timeout
73
+ await timeout(timeoutMs + 50);
74
+ // First check should be the Probe
75
+ const probe = await breaker.check();
76
+ expect(probe.allowed).toBe(true);
77
+ expect(probe.state).toBe(CircuitBreakerState.HalfOpen);
78
+ expect(probe.isProbe).toBe(true);
79
+ // Subsequent check should be denied (Half-Open wait)
80
+ const subsequent = await breaker.check();
81
+ expect(subsequent.allowed).toBe(true); // check() allows HalfOpen, but queue logic restricts it.
82
+ // Wait, let's verify PostgresCircuitBreakerService logic:
83
+ // if (breaker.state === CircuitBreakerState.HalfOpen) return { allowed: true, state: CircuitBreakerState.HalfOpen, isProbe: false };
84
+ expect(subsequent.state).toBe(CircuitBreakerState.HalfOpen);
85
+ expect(subsequent.isProbe).toBe(false);
86
+ });
87
+ it('should close if Probe succeeds', async () => {
88
+ const timeoutMs = 100;
89
+ const breaker = provider.provide(`cb-probe-success-${Date.now()}`, { threshold: 1, resetTimeout: timeoutMs });
90
+ // Trip and Probe
91
+ await breaker.recordFailure();
92
+ await timeout(timeoutMs + 50);
93
+ await breaker.check(); // Probe triggered
94
+ // Probe succeeds
95
+ await breaker.recordSuccess();
96
+ const result = await breaker.check();
97
+ expect(result.state).toBe(CircuitBreakerState.Closed);
98
+ });
99
+ it('should reopen if Probe fails', async () => {
100
+ const timeoutMs = 100;
101
+ const breaker = provider.provide(`cb-probe-fail-${Date.now()}`, { threshold: 1, resetTimeout: timeoutMs });
102
+ // Trip and Probe
103
+ await breaker.recordFailure();
104
+ await timeout(timeoutMs + 50);
105
+ await breaker.check(); // Probe triggered (State: HalfOpen)
106
+ // Probe fails
107
+ await breaker.recordFailure();
108
+ // Should be Open again
109
+ const result = await breaker.check();
110
+ expect(result.allowed).toBe(false);
111
+ expect(result.state).toBe(CircuitBreakerState.Open);
112
+ });
113
+ });
@@ -21,5 +21,4 @@ export declare class Document extends TenantEntity {
21
21
  mimeType: string;
22
22
  hash: string;
23
23
  size: number;
24
- createUserId: Uuid | null;
25
24
  }
@@ -31,7 +31,6 @@ let Document = class Document extends TenantEntity {
31
31
  mimeType;
32
32
  hash;
33
33
  size;
34
- createUserId;
35
34
  };
36
35
  __decorate([
37
36
  UuidProperty({ nullable: true }),
@@ -82,10 +81,6 @@ __decorate([
82
81
  Integer(),
83
82
  __metadata("design:type", Number)
84
83
  ], Document.prototype, "size", void 0);
85
- __decorate([
86
- UuidProperty({ nullable: true }),
87
- __metadata("design:type", Object)
88
- ], Document.prototype, "createUserId", void 0);
89
84
  Document = __decorate([
90
85
  DocumentManagementTable(),
91
86
  Unique(['tenantId', 'id'])
@@ -155,8 +155,7 @@ let DocumentManagementApiController = DocumentManagementApiController_1 = class
155
155
  }
156
156
  }
157
157
  }
158
- const actionUserId = await this.#authorizationService.getSubject(token);
159
- return await this.#documentService.create(tenantId, createParameters, { uploadId, uploadKey: subject }, { createUserId: actionUserId });
158
+ return await this.#documentService.create(tenantId, createParameters, { uploadId, uploadKey: subject });
160
159
  }
161
160
  async createDocumentRequestsTemplate(context) {
162
161
  const token = await context.getToken();
@@ -0,0 +1 @@
1
+ ALTER TABLE "document_management"."document" DROP COLUMN "create_user_id";