@open-mercato/enterprise 0.5.1-develop.2691.d8a0934b37 → 0.5.1-develop.2694.732417c5ec
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/dist/modules/record_locks/data/entities.js +2 -1
- package/dist/modules/record_locks/data/entities.js.map +2 -2
- package/dist/modules/record_locks/lib/recordLockService.js +19 -15
- package/dist/modules/record_locks/lib/recordLockService.js.map +2 -2
- package/dist/modules/security/data/entities.js +1 -1
- package/dist/modules/security/data/entities.js.map +1 -1
- package/dist/modules/sso/data/entities.js +1 -1
- package/dist/modules/sso/data/entities.js.map +2 -2
- package/dist/modules/sso/services/accountLinkingService.js +4 -4
- package/dist/modules/sso/services/accountLinkingService.js.map +2 -2
- package/dist/modules/sso/services/hrdService.js +3 -2
- package/dist/modules/sso/services/hrdService.js.map +2 -2
- package/dist/modules/sso/services/scimService.js +7 -7
- package/dist/modules/sso/services/scimService.js.map +2 -2
- package/dist/modules/sso/services/scimTokenService.js +1 -1
- package/dist/modules/sso/services/scimTokenService.js.map +2 -2
- package/dist/modules/sso/services/ssoConfigService.js +1 -1
- package/dist/modules/sso/services/ssoConfigService.js.map +2 -2
- package/dist/modules/sso/setup.js +1 -1
- package/dist/modules/sso/setup.js.map +2 -2
- package/jest.config.cjs +4 -2
- package/package.json +5 -5
- package/src/modules/record_locks/data/entities.ts +2 -1
- package/src/modules/record_locks/lib/recordLockService.ts +33 -28
- package/src/modules/security/data/entities.ts +1 -1
- package/src/modules/sso/data/entities.ts +1 -1
- package/src/modules/sso/services/accountLinkingService.ts +4 -4
- package/src/modules/sso/services/hrdService.ts +10 -7
- package/src/modules/sso/services/scimService.ts +7 -7
- package/src/modules/sso/services/scimTokenService.ts +1 -1
- package/src/modules/sso/services/ssoConfigService.ts +1 -1
- package/src/modules/sso/setup.ts +1 -1
|
@@ -8,7 +8,8 @@ var __decorateClass = (decorators, target, key, kind) => {
|
|
|
8
8
|
if (kind && result) __defProp(target, key, result);
|
|
9
9
|
return result;
|
|
10
10
|
};
|
|
11
|
-
import {
|
|
11
|
+
import { OptionalProps } from "@mikro-orm/core";
|
|
12
|
+
import { Entity, Index, PrimaryKey, Property, Unique } from "@mikro-orm/decorators/legacy";
|
|
12
13
|
OptionalProps;
|
|
13
14
|
let RecordLock = class {
|
|
14
15
|
constructor() {
|
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
{
|
|
2
2
|
"version": 3,
|
|
3
3
|
"sources": ["../../../../src/modules/record_locks/data/entities.ts"],
|
|
4
|
-
"sourcesContent": ["import { Entity, Index,
|
|
5
|
-
"mappings": ";;;;;;;;;;AAAA,SAAS,QAAQ,OAAO,
|
|
4
|
+
"sourcesContent": ["import { OptionalProps } from '@mikro-orm/core'\nimport { Entity, Index, PrimaryKey, Property, Unique } from '@mikro-orm/decorators/legacy'\n\nexport type RecordLockStatus = 'active' | 'released' | 'expired' | 'force_released'\nexport type RecordLockStrategy = 'optimistic' | 'pessimistic'\nexport type RecordLockReleaseReason = 'saved' | 'cancelled' | 'unmount' | 'expired' | 'force' | 'conflict_resolved'\n\nexport type RecordLockConflictStatus = 'pending' | 'resolved_accept_incoming' | 'resolved_accept_mine' | 'resolved_merged'\nexport type RecordLockConflictResolution = 'accept_incoming' | 'accept_mine' | 'merged'\n\n@Entity({ tableName: 'record_locks' })\n@Unique({ name: 'record_locks_token_unique', properties: ['token'] })\n@Index({ name: 'record_locks_resource_status_idx', properties: ['tenantId', 'resourceKind', 'resourceId', 'status'] })\n@Index({ name: 'record_locks_owner_status_idx', properties: ['tenantId', 'lockedByUserId', 'status'] })\n@Index({ name: 'record_locks_expiry_status_idx', properties: ['tenantId', 'expiresAt', 'status'] })\n@Index({\n name: 'record_locks_active_scope_user_org_unique',\n expression:\n `create unique index \"record_locks_active_scope_user_org_unique\" on \"record_locks\" (\"tenant_id\", \"organization_id\", \"resource_kind\", \"resource_id\", \"locked_by_user_id\") where deleted_at is null and status = 'active' and organization_id is not null`,\n})\n@Index({\n name: 'record_locks_active_scope_user_tenant_unique',\n expression:\n `create unique index \"record_locks_active_scope_user_tenant_unique\" on \"record_locks\" (\"tenant_id\", \"resource_kind\", \"resource_id\", \"locked_by_user_id\") where deleted_at is null and status = 'active' and organization_id is null`,\n})\nexport class RecordLock {\n [OptionalProps]?: 'createdAt' | 'updatedAt' | 'deletedAt' | 'releasedAt' | 'releasedByUserId' | 'releaseReason'\n\n @PrimaryKey({ type: 'uuid', defaultRaw: 'gen_random_uuid()' })\n id!: string\n\n @Property({ name: 'resource_kind', type: 'text' })\n resourceKind!: string\n\n @Property({ name: 'resource_id', type: 'text' })\n resourceId!: string\n\n @Property({ name: 'token', type: 'text' })\n token!: string\n\n @Property({ name: 'strategy', type: 'text' })\n strategy: RecordLockStrategy = 'optimistic'\n\n @Property({ name: 'status', type: 'text' })\n status: RecordLockStatus = 'active'\n\n @Property({ name: 'locked_by_user_id', type: 'uuid' })\n lockedByUserId!: string\n\n @Property({ name: 'locked_by_ip', type: 'text', nullable: true })\n lockedByIp: string | null = null\n\n @Property({ name: 'base_action_log_id', type: 'uuid', nullable: true })\n baseActionLogId: string | null = null\n\n @Property({ name: 'locked_at', type: Date })\n lockedAt: Date = new Date()\n\n @Property({ name: 'last_heartbeat_at', type: Date })\n lastHeartbeatAt: Date = new Date()\n\n @Property({ name: 'expires_at', type: Date })\n expiresAt: Date = new Date()\n\n @Property({ name: 'released_at', type: Date, nullable: true })\n releasedAt: Date | null = null\n\n @Property({ name: 'released_by_user_id', type: 'uuid', nullable: true })\n releasedByUserId: string | null = null\n\n @Property({ name: 'release_reason', type: 'text', nullable: true })\n releaseReason: string | null = null\n\n @Property({ name: 'tenant_id', type: 'uuid' })\n tenantId!: string\n\n @Property({ name: 'organization_id', type: 'uuid', nullable: true })\n organizationId: string | null = null\n\n @Property({ name: 'created_at', type: Date, onCreate: () => new Date() })\n createdAt: Date = new Date()\n\n @Property({ name: 'updated_at', type: Date, onUpdate: () => new Date() })\n updatedAt: Date = new Date()\n\n @Property({ name: 'deleted_at', type: Date, nullable: true })\n deletedAt: Date | null = null\n}\n\n@Entity({ tableName: 'record_lock_conflicts' })\n@Index({ name: 'record_lock_conflicts_resource_idx', properties: ['tenantId', 'resourceKind', 'resourceId', 'status', 'createdAt'] })\n@Index({ name: 'record_lock_conflicts_users_idx', properties: ['tenantId', 'conflictActorUserId', 'incomingActorUserId', 'createdAt'] })\nexport class RecordLockConflict {\n [OptionalProps]?: 'createdAt' | 'updatedAt' | 'deletedAt' | 'resolution' | 'resolvedByUserId' | 'resolvedAt'\n\n @PrimaryKey({ type: 'uuid', defaultRaw: 'gen_random_uuid()' })\n id!: string\n\n @Property({ name: 'resource_kind', type: 'text' })\n resourceKind!: string\n\n @Property({ name: 'resource_id', type: 'text' })\n resourceId!: string\n\n @Property({ name: 'status', type: 'text' })\n status: RecordLockConflictStatus = 'pending'\n\n @Property({ name: 'resolution', type: 'text', nullable: true })\n resolution: RecordLockConflictResolution | null = null\n\n @Property({ name: 'base_action_log_id', type: 'uuid', nullable: true })\n baseActionLogId: string | null = null\n\n @Property({ name: 'incoming_action_log_id', type: 'uuid', nullable: true })\n incomingActionLogId: string | null = null\n\n @Property({ name: 'conflict_actor_user_id', type: 'uuid' })\n conflictActorUserId!: string\n\n @Property({ name: 'incoming_actor_user_id', type: 'uuid', nullable: true })\n incomingActorUserId: string | null = null\n\n @Property({ name: 'resolved_by_user_id', type: 'uuid', nullable: true })\n resolvedByUserId: string | null = null\n\n @Property({ name: 'resolved_at', type: Date, nullable: true })\n resolvedAt: Date | null = null\n\n @Property({ name: 'tenant_id', type: 'uuid' })\n tenantId!: string\n\n @Property({ name: 'organization_id', type: 'uuid', nullable: true })\n organizationId: string | null = null\n\n @Property({ name: 'created_at', type: Date, onCreate: () => new Date() })\n createdAt: Date = new Date()\n\n @Property({ name: 'updated_at', type: Date, onUpdate: () => new Date() })\n updatedAt: Date = new Date()\n\n @Property({ name: 'deleted_at', type: Date, nullable: true })\n deletedAt: Date | null = null\n}\n"],
|
|
5
|
+
"mappings": "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",
|
|
6
6
|
"names": []
|
|
7
7
|
}
|
|
@@ -1,5 +1,6 @@
|
|
|
1
1
|
import { randomUUID } from "crypto";
|
|
2
2
|
import { UniqueConstraintViolationException } from "@mikro-orm/core";
|
|
3
|
+
import { sql } from "kysely";
|
|
3
4
|
import { ActionLog } from "@open-mercato/core/modules/audit_logs/data/entities";
|
|
4
5
|
import { emitRecordLocksEvent } from "../events.js";
|
|
5
6
|
import {
|
|
@@ -88,8 +89,8 @@ function isActiveLockScopeUniqueViolation(error) {
|
|
|
88
89
|
}
|
|
89
90
|
return false;
|
|
90
91
|
}
|
|
91
|
-
function
|
|
92
|
-
return em.
|
|
92
|
+
function getKysely(em) {
|
|
93
|
+
return em.getKysely();
|
|
93
94
|
}
|
|
94
95
|
const SKIPPED_CONFLICT_FIELDS = /* @__PURE__ */ new Set([
|
|
95
96
|
"updatedAt",
|
|
@@ -904,26 +905,29 @@ class RecordLockService {
|
|
|
904
905
|
}
|
|
905
906
|
async cleanupHistoricalRecords(tenantId) {
|
|
906
907
|
try {
|
|
907
|
-
const
|
|
908
|
+
const db = getKysely(this.em);
|
|
908
909
|
const now = Date.now();
|
|
909
910
|
const lockCutoff = new Date(now - LOCK_RETENTION_MS);
|
|
910
911
|
const resolvedConflictCutoff = new Date(now - RESOLVED_CONFLICT_RETENTION_MS);
|
|
911
912
|
const pendingConflictCutoff = new Date(now - PENDING_CONFLICT_RETENTION_MS);
|
|
912
913
|
const deletedAt = new Date(now);
|
|
913
|
-
await
|
|
914
|
+
await db.updateTable("record_locks").set({
|
|
914
915
|
deleted_at: deletedAt,
|
|
915
916
|
updated_at: deletedAt
|
|
916
|
-
});
|
|
917
|
-
await
|
|
918
|
-
query.where((pending) => {
|
|
919
|
-
pending.where("status", "pending").andWhere("created_at", "<", pendingConflictCutoff);
|
|
920
|
-
}).orWhere((resolved) => {
|
|
921
|
-
resolved.whereNot("status", "pending").andWhere("updated_at", "<", resolvedConflictCutoff);
|
|
922
|
-
});
|
|
923
|
-
}).update({
|
|
917
|
+
}).where("tenant_id", "=", tenantId).where("deleted_at", "is", null).where("status", "!=", ACTIVE_LOCK_STATUS).where("updated_at", "<", lockCutoff).execute();
|
|
918
|
+
await db.updateTable("record_lock_conflicts").set({
|
|
924
919
|
deleted_at: deletedAt,
|
|
925
920
|
updated_at: deletedAt
|
|
926
|
-
})
|
|
921
|
+
}).where("tenant_id", "=", tenantId).where("deleted_at", "is", null).where((eb) => eb.or([
|
|
922
|
+
eb.and([
|
|
923
|
+
eb("status", "=", "pending"),
|
|
924
|
+
eb("created_at", "<", pendingConflictCutoff)
|
|
925
|
+
]),
|
|
926
|
+
eb.and([
|
|
927
|
+
eb("status", "!=", "pending"),
|
|
928
|
+
eb("updated_at", "<", resolvedConflictCutoff)
|
|
929
|
+
])
|
|
930
|
+
])).execute();
|
|
927
931
|
} catch {
|
|
928
932
|
}
|
|
929
933
|
}
|
|
@@ -1168,8 +1172,8 @@ class RecordLockService {
|
|
|
1168
1172
|
].join(":");
|
|
1169
1173
|
const result = await this.em.transactional(async (tx) => {
|
|
1170
1174
|
try {
|
|
1171
|
-
const
|
|
1172
|
-
await
|
|
1175
|
+
const db = getKysely(tx);
|
|
1176
|
+
await sql`select pg_advisory_xact_lock(hashtext(${dedupeKey}))`.execute(db);
|
|
1173
1177
|
} catch {
|
|
1174
1178
|
}
|
|
1175
1179
|
const existing = await this.findPendingConflictByFingerprint(tx, input);
|