@modern-admin/system-prisma 0.7.0 → 0.9.0
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/stores/ai-task-store.d.ts +3 -0
- package/dist/stores/ai-task-store.d.ts.map +1 -1
- package/dist/stores/ai-task-store.js +54 -13
- package/dist/stores/ai-task-store.js.map +1 -1
- package/dist/stores/log-store.d.ts +7 -1
- package/dist/stores/log-store.d.ts.map +1 -1
- package/dist/stores/log-store.js +34 -0
- package/dist/stores/log-store.js.map +1 -1
- package/dist/types.d.ts +6 -0
- package/dist/types.d.ts.map +1 -1
- package/dist/types.js.map +1 -1
- package/package.json +2 -2
- package/prisma/modern-admin.prisma +2 -1
- package/src/stores/ai-task-store.ts +50 -13
- package/src/stores/log-store.ts +39 -0
- package/src/types.ts +1 -0
|
@@ -6,12 +6,15 @@ export declare class PrismaAiTaskStore implements IAiTaskStore {
|
|
|
6
6
|
constructor(taskDelegate: PrismaDelegate<TaskRow>, eventDelegate: PrismaDelegate<EventRow>);
|
|
7
7
|
enqueue(input: AiTaskInput): Promise<AiTask>;
|
|
8
8
|
get(id: string): Promise<AiTask | null>;
|
|
9
|
+
claim(id: string): Promise<AiTask | null>;
|
|
10
|
+
getByIdempotencyKey(idempotencyKey: string): Promise<AiTask | null>;
|
|
9
11
|
list(filter?: Parameters<IAiTaskStore['list']>[0]): Promise<AiTask[]>;
|
|
10
12
|
updateStatus(id: string, patch: {
|
|
11
13
|
status: AiTaskStatus;
|
|
12
14
|
progress?: number | null;
|
|
13
15
|
output?: Record<string, unknown>;
|
|
14
16
|
error?: string;
|
|
17
|
+
expectedStatus?: AiTaskStatus[];
|
|
15
18
|
}): Promise<AiTask>;
|
|
16
19
|
appendEvent(taskId: string, type: string, data: Record<string, unknown>): Promise<AiTaskEvent>;
|
|
17
20
|
events(taskId: string, sinceId?: string): Promise<AiTaskEvent[]>;
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"ai-task-store.d.ts","sourceRoot":"","sources":["../../src/stores/ai-task-store.ts"],"names":[],"mappings":"AAAA,OAAO,EAIL,KAAK,MAAM,EACX,KAAK,WAAW,EAChB,KAAK,WAAW,EAChB,KAAK,YAAY,EACjB,KAAK,YAAY,EACjB,KAAK,QAAQ,EACb,KAAK,OAAO,EACb,MAAM,oBAAoB,CAAA;AAC3B,OAAO,KAAK,EAAE,cAAc,EAAE,MAAM,aAAa,CAAA;AAIjD,qBAAa,iBAAkB,YAAW,YAAY;IAElD,OAAO,CAAC,QAAQ,CAAC,YAAY;IAC7B,OAAO,CAAC,QAAQ,CAAC,aAAa;IAFhC,YACmB,YAAY,EAAE,cAAc,CAAC,OAAO,CAAC,EACrC,aAAa,EAAE,cAAc,CAAC,QAAQ,CAAC,EACtD;IAEE,OAAO,CAAC,KAAK,EAAE,WAAW,GAAG,OAAO,CAAC,MAAM,CAAC,
|
|
1
|
+
{"version":3,"file":"ai-task-store.d.ts","sourceRoot":"","sources":["../../src/stores/ai-task-store.ts"],"names":[],"mappings":"AAAA,OAAO,EAIL,KAAK,MAAM,EACX,KAAK,WAAW,EAChB,KAAK,WAAW,EAChB,KAAK,YAAY,EACjB,KAAK,YAAY,EACjB,KAAK,QAAQ,EACb,KAAK,OAAO,EACb,MAAM,oBAAoB,CAAA;AAC3B,OAAO,KAAK,EAAE,cAAc,EAAE,MAAM,aAAa,CAAA;AAIjD,qBAAa,iBAAkB,YAAW,YAAY;IAElD,OAAO,CAAC,QAAQ,CAAC,YAAY;IAC7B,OAAO,CAAC,QAAQ,CAAC,aAAa;IAFhC,YACmB,YAAY,EAAE,cAAc,CAAC,OAAO,CAAC,EACrC,aAAa,EAAE,cAAc,CAAC,QAAQ,CAAC,EACtD;IAEE,OAAO,CAAC,KAAK,EAAE,WAAW,GAAG,OAAO,CAAC,MAAM,CAAC,CAsBjD;IAEK,GAAG,CAAC,EAAE,EAAE,MAAM,GAAG,OAAO,CAAC,MAAM,GAAG,IAAI,CAAC,CAG5C;IAEK,KAAK,CAAC,EAAE,EAAE,MAAM,GAAG,OAAO,CAAC,MAAM,GAAG,IAAI,CAAC,CAO9C;IAEK,mBAAmB,CAAC,cAAc,EAAE,MAAM,GAAG,OAAO,CAAC,MAAM,GAAG,IAAI,CAAC,CAGxE;IAEK,IAAI,CAAC,MAAM,GAAE,UAAU,CAAC,YAAY,CAAC,MAAM,CAAC,CAAC,CAAC,CAAC,CAAM,GAAG,OAAO,CAAC,MAAM,EAAE,CAAC,CAiB9E;IAEK,YAAY,CAChB,EAAE,EAAE,MAAM,EACV,KAAK,EAAE;QACL,MAAM,EAAE,YAAY,CAAA;QACpB,QAAQ,CAAC,EAAE,MAAM,GAAG,IAAI,CAAA;QACxB,MAAM,CAAC,EAAE,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,CAAA;QAChC,KAAK,CAAC,EAAE,MAAM,CAAA;QACd,cAAc,CAAC,EAAE,YAAY,EAAE,CAAA;KAChC,GACA,OAAO,CAAC,MAAM,CAAC,CA2BjB;IAEK,WAAW,CACf,MAAM,EAAE,MAAM,EACd,IAAI,EAAE,MAAM,EACZ,IAAI,EAAE,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,GAC5B,OAAO,CAAC,WAAW,CAAC,CAKtB;IAEK,MAAM,CAAC,MAAM,EAAE,MAAM,EAAE,OAAO,CAAC,EAAE,MAAM,GAAG,OAAO,CAAC,WAAW,EAAE,CAAC,CAQrE;CACF"}
|
|
@@ -6,28 +6,54 @@ export class PrismaAiTaskStore {
|
|
|
6
6
|
this.eventDelegate = eventDelegate;
|
|
7
7
|
}
|
|
8
8
|
async enqueue(input) {
|
|
9
|
-
|
|
10
|
-
|
|
11
|
-
|
|
12
|
-
|
|
13
|
-
|
|
14
|
-
|
|
15
|
-
|
|
16
|
-
|
|
17
|
-
|
|
18
|
-
|
|
19
|
-
|
|
20
|
-
|
|
21
|
-
|
|
9
|
+
try {
|
|
10
|
+
const row = await this.taskDelegate.create({
|
|
11
|
+
data: {
|
|
12
|
+
id: uuidv7(),
|
|
13
|
+
idempotencyKey: input.idempotencyKey ?? null,
|
|
14
|
+
kind: input.kind,
|
|
15
|
+
resourceId: input.resourceId ?? null,
|
|
16
|
+
recordId: input.recordId ?? null,
|
|
17
|
+
userId: input.userId ?? null,
|
|
18
|
+
status: 'pending',
|
|
19
|
+
input: input.input ?? {},
|
|
20
|
+
progress: null,
|
|
21
|
+
},
|
|
22
|
+
});
|
|
23
|
+
return rowToTask(row);
|
|
24
|
+
}
|
|
25
|
+
catch (error) {
|
|
26
|
+
if (!input.idempotencyKey)
|
|
27
|
+
throw error;
|
|
28
|
+
const existing = await this.getByIdempotencyKey(input.idempotencyKey);
|
|
29
|
+
if (!existing)
|
|
30
|
+
throw error;
|
|
31
|
+
return existing;
|
|
32
|
+
}
|
|
22
33
|
}
|
|
23
34
|
async get(id) {
|
|
24
35
|
const row = await this.taskDelegate.findUnique({ where: { id } });
|
|
25
36
|
return row ? rowToTask(row) : null;
|
|
26
37
|
}
|
|
38
|
+
async claim(id) {
|
|
39
|
+
const result = await this.taskDelegate.updateMany({
|
|
40
|
+
where: { id, status: 'pending' },
|
|
41
|
+
data: { status: 'running', progress: 5, startedAt: new Date() },
|
|
42
|
+
});
|
|
43
|
+
if (result.count === 0)
|
|
44
|
+
return null;
|
|
45
|
+
return this.get(id);
|
|
46
|
+
}
|
|
47
|
+
async getByIdempotencyKey(idempotencyKey) {
|
|
48
|
+
const row = await this.taskDelegate.findUnique({ where: { idempotencyKey } });
|
|
49
|
+
return row ? rowToTask(row) : null;
|
|
50
|
+
}
|
|
27
51
|
async list(filter = {}) {
|
|
28
52
|
const where = {};
|
|
29
53
|
if (filter.kind)
|
|
30
54
|
where['kind'] = filter.kind;
|
|
55
|
+
if (filter.idempotencyKey)
|
|
56
|
+
where['idempotencyKey'] = filter.idempotencyKey;
|
|
31
57
|
if (filter.status) {
|
|
32
58
|
const list = Array.isArray(filter.status) ? filter.status : [filter.status];
|
|
33
59
|
where['status'] = { in: list };
|
|
@@ -36,6 +62,8 @@ export class PrismaAiTaskStore {
|
|
|
36
62
|
where['userId'] = filter.userId;
|
|
37
63
|
if (filter.resourceId)
|
|
38
64
|
where['resourceId'] = filter.resourceId;
|
|
65
|
+
if (filter.createdAfter)
|
|
66
|
+
where['createdAt'] = { gte: new Date(filter.createdAfter) };
|
|
39
67
|
const rows = await this.taskDelegate.findMany({
|
|
40
68
|
where,
|
|
41
69
|
orderBy: { createdAt: 'desc' },
|
|
@@ -60,6 +88,19 @@ export class PrismaAiTaskStore {
|
|
|
60
88
|
if (TERMINAL.includes(patch.status)) {
|
|
61
89
|
data['finishedAt'] = new Date();
|
|
62
90
|
}
|
|
91
|
+
if (patch.expectedStatus) {
|
|
92
|
+
// Atomic guarded write: the WHERE clause makes the update a no-op unless
|
|
93
|
+
// the row is still in an expected status, so a concurrent cancel/finalize
|
|
94
|
+
// is never overwritten. Return the current row either way.
|
|
95
|
+
await this.taskDelegate.updateMany({
|
|
96
|
+
where: { id, status: { in: patch.expectedStatus } },
|
|
97
|
+
data,
|
|
98
|
+
});
|
|
99
|
+
const row = await this.taskDelegate.findUnique({ where: { id } });
|
|
100
|
+
if (!row)
|
|
101
|
+
throw new Error(`AI task not found: ${id}`);
|
|
102
|
+
return rowToTask(row);
|
|
103
|
+
}
|
|
63
104
|
const row = await this.taskDelegate.update({ where: { id }, data });
|
|
64
105
|
return rowToTask(row);
|
|
65
106
|
}
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"ai-task-store.js","sourceRoot":"","sources":["../../src/stores/ai-task-store.ts"],"names":[],"mappings":"AAAA,OAAO,EACL,UAAU,EACV,SAAS,EACT,MAAM,GAQP,MAAM,oBAAoB,CAAA;AAG3B,MAAM,QAAQ,GAAmB,CAAC,WAAW,EAAE,QAAQ,EAAE,WAAW,CAAC,CAAA;AAErE,MAAM,OAAO,iBAAiB;IAC5B,YACmB,YAAqC,EACrC,aAAuC;4BADvC,YAAY;6BACZ,aAAa;IAC7B,CAAC;IAEJ,KAAK,CAAC,OAAO,CAAC,KAAkB;QAC9B,MAAM,GAAG,GAAG,MAAM,IAAI,CAAC,YAAY,CAAC,MAAM,CAAC;
|
|
1
|
+
{"version":3,"file":"ai-task-store.js","sourceRoot":"","sources":["../../src/stores/ai-task-store.ts"],"names":[],"mappings":"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"}
|
|
@@ -1,10 +1,16 @@
|
|
|
1
|
-
import { type ActionLogEntry, type ILogStore, type IQueryableLogStore, type LogRow } from '@modern-admin/core';
|
|
1
|
+
import { type ActionLogRetention, type ActionLogEntry, type ILogStore, type IQueryableLogStore, type LogRow } from '@modern-admin/core';
|
|
2
2
|
import type { PrismaDelegate } from '../types.js';
|
|
3
3
|
export declare class PrismaLogStore implements IQueryableLogStore {
|
|
4
4
|
private readonly delegate;
|
|
5
5
|
constructor(delegate: PrismaDelegate<LogRow>);
|
|
6
6
|
record(entry: ActionLogEntry): Promise<void>;
|
|
7
7
|
list(filter?: Parameters<IQueryableLogStore['list']>[0]): Promise<ActionLogEntry[]>;
|
|
8
|
+
/**
|
|
9
|
+
* Delete action-log entries outside the configured retention bounds.
|
|
10
|
+
* `keepLast` is global and deletions use an explicit id snapshot so a
|
|
11
|
+
* concurrent write can never be caught by a broad predicate.
|
|
12
|
+
*/
|
|
13
|
+
prune(retention: ActionLogRetention): Promise<number>;
|
|
8
14
|
}
|
|
9
15
|
/** Narrow type-test: a pure `ILogStore` is enough where readback isn't needed. */
|
|
10
16
|
export type { ILogStore };
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"log-store.d.ts","sourceRoot":"","sources":["../../src/stores/log-store.ts"],"names":[],"mappings":"AAAA,OAAO,EAGL,KAAK,cAAc,EACnB,KAAK,SAAS,EACd,KAAK,kBAAkB,EACvB,KAAK,MAAM,EACZ,MAAM,oBAAoB,CAAA;AAC3B,OAAO,KAAK,EAAE,cAAc,EAAE,MAAM,aAAa,CAAA;
|
|
1
|
+
{"version":3,"file":"log-store.d.ts","sourceRoot":"","sources":["../../src/stores/log-store.ts"],"names":[],"mappings":"AAAA,OAAO,EAGL,KAAK,kBAAkB,EACvB,KAAK,cAAc,EACnB,KAAK,SAAS,EACd,KAAK,kBAAkB,EACvB,KAAK,MAAM,EACZ,MAAM,oBAAoB,CAAA;AAC3B,OAAO,KAAK,EAAE,cAAc,EAAE,MAAM,aAAa,CAAA;AAMjD,qBAAa,cAAe,YAAW,kBAAkB;IAC3C,OAAO,CAAC,QAAQ,CAAC,QAAQ;IAArC,YAA6B,QAAQ,EAAE,cAAc,CAAC,MAAM,CAAC,EAAI;IAE3D,MAAM,CAAC,KAAK,EAAE,cAAc,GAAG,OAAO,CAAC,IAAI,CAAC,CAgBjD;IAEK,IAAI,CAAC,MAAM,GAAE,UAAU,CAAC,kBAAkB,CAAC,MAAM,CAAC,CAAC,CAAC,CAAC,CAAM,GAAG,OAAO,CAAC,cAAc,EAAE,CAAC,CA2C5F;IAED;;;;OAIG;IACG,KAAK,CAAC,SAAS,EAAE,kBAAkB,GAAG,OAAO,CAAC,MAAM,CAAC,CA8B1D;CACF;AAED,kFAAkF;AAClF,YAAY,EAAE,SAAS,EAAE,CAAA"}
|
package/dist/stores/log-store.js
CHANGED
|
@@ -1,6 +1,7 @@
|
|
|
1
1
|
import { rowToLogEntry, uuidv7, } from '@modern-admin/core';
|
|
2
2
|
/** Applied when the caller passes no `limit`. Matches `MemoryLogStore`. */
|
|
3
3
|
const DEFAULT_LIST_LIMIT = 50;
|
|
4
|
+
const PRUNE_BATCH_SIZE = 1_000;
|
|
4
5
|
export class PrismaLogStore {
|
|
5
6
|
constructor(delegate) {
|
|
6
7
|
this.delegate = delegate;
|
|
@@ -74,5 +75,38 @@ export class PrismaLogStore {
|
|
|
74
75
|
});
|
|
75
76
|
return rows.map(rowToLogEntry);
|
|
76
77
|
}
|
|
78
|
+
/**
|
|
79
|
+
* Delete action-log entries outside the configured retention bounds.
|
|
80
|
+
* `keepLast` is global and deletions use an explicit id snapshot so a
|
|
81
|
+
* concurrent write can never be caught by a broad predicate.
|
|
82
|
+
*/
|
|
83
|
+
async prune(retention) {
|
|
84
|
+
let removed = 0;
|
|
85
|
+
if (retention.keepDays !== undefined) {
|
|
86
|
+
const cutoff = new Date(Date.now() - retention.keepDays * 24 * 60 * 60 * 1000);
|
|
87
|
+
const result = await this.delegate.deleteMany({
|
|
88
|
+
where: { createdAt: { lt: cutoff } },
|
|
89
|
+
});
|
|
90
|
+
removed += result.count;
|
|
91
|
+
}
|
|
92
|
+
if (retention.keepLast !== undefined) {
|
|
93
|
+
const keep = Math.max(0, Math.trunc(retention.keepLast));
|
|
94
|
+
while (true) {
|
|
95
|
+
const obsolete = (await this.delegate.findMany({
|
|
96
|
+
orderBy: [{ createdAt: 'desc' }, { id: 'desc' }],
|
|
97
|
+
select: { id: true },
|
|
98
|
+
...(keep > 0 ? { skip: keep } : {}),
|
|
99
|
+
take: PRUNE_BATCH_SIZE,
|
|
100
|
+
}));
|
|
101
|
+
if (obsolete.length === 0)
|
|
102
|
+
break;
|
|
103
|
+
const result = await this.delegate.deleteMany({
|
|
104
|
+
where: { id: { in: obsolete.map((row) => row.id) } },
|
|
105
|
+
});
|
|
106
|
+
removed += result.count;
|
|
107
|
+
}
|
|
108
|
+
}
|
|
109
|
+
return removed;
|
|
110
|
+
}
|
|
77
111
|
}
|
|
78
112
|
//# sourceMappingURL=log-store.js.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"log-store.js","sourceRoot":"","sources":["../../src/stores/log-store.ts"],"names":[],"mappings":"AAAA,OAAO,EACL,aAAa,EACb,MAAM,
|
|
1
|
+
{"version":3,"file":"log-store.js","sourceRoot":"","sources":["../../src/stores/log-store.ts"],"names":[],"mappings":"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"}
|
package/dist/types.d.ts
CHANGED
|
@@ -33,6 +33,12 @@ export interface PrismaDelegate<TRow = any> {
|
|
|
33
33
|
}): Promise<{
|
|
34
34
|
count: number;
|
|
35
35
|
}>;
|
|
36
|
+
updateMany(args: {
|
|
37
|
+
where?: any;
|
|
38
|
+
data: any;
|
|
39
|
+
}): Promise<{
|
|
40
|
+
count: number;
|
|
41
|
+
}>;
|
|
36
42
|
count(args?: any): Promise<number>;
|
|
37
43
|
/**
|
|
38
44
|
* Present on every generated Prisma delegate. Optional here so hand-written
|
package/dist/types.d.ts.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"types.d.ts","sourceRoot":"","sources":["../src/types.ts"],"names":[],"mappings":"AAAA;;;;;;;;GAQG;AAIH,MAAM,WAAW,cAAc,CAAC,IAAI,GAAG,GAAG;IACxC,QAAQ,CAAC,IAAI,CAAC,EAAE,GAAG,GAAG,OAAO,CAAC,IAAI,EAAE,CAAC,CAAA;IACrC,UAAU,CAAC,IAAI,EAAE;QAAE,KAAK,EAAE,GAAG,CAAA;KAAE,GAAG,OAAO,CAAC,IAAI,GAAG,IAAI,CAAC,CAAA;IACtD,SAAS,CAAC,IAAI,CAAC,EAAE,GAAG,GAAG,OAAO,CAAC,IAAI,GAAG,IAAI,CAAC,CAAA;IAC3C,MAAM,CAAC,IAAI,EAAE;QAAE,IAAI,EAAE,GAAG,CAAA;KAAE,GAAG,OAAO,CAAC,IAAI,CAAC,CAAA;IAC1C,MAAM,CAAC,IAAI,EAAE;QAAE,KAAK,EAAE,GAAG,CAAC;QAAC,IAAI,EAAE,GAAG,CAAA;KAAE,GAAG,OAAO,CAAC,IAAI,CAAC,CAAA;IACtD,MAAM,CAAC,IAAI,EAAE;QAAE,KAAK,EAAE,GAAG,CAAC;QAAC,MAAM,EAAE,GAAG,CAAC;QAAC,MAAM,EAAE,GAAG,CAAA;KAAE,GAAG,OAAO,CAAC,IAAI,CAAC,CAAA;IACrE,MAAM,CAAC,IAAI,EAAE;QAAE,KAAK,EAAE,GAAG,CAAA;KAAE,GAAG,OAAO,CAAC,IAAI,CAAC,CAAA;IAC3C,UAAU,CAAC,IAAI,CAAC,EAAE;QAAE,KAAK,CAAC,EAAE,GAAG,CAAA;KAAE,GAAG,OAAO,CAAC;QAAE,KAAK,EAAE,MAAM,CAAA;KAAE,CAAC,CAAA;IAC9D,KAAK,CAAC,IAAI,CAAC,EAAE,GAAG,GAAG,OAAO,CAAC,MAAM,CAAC,CAAA;IAClC;;;OAGG;IACH,OAAO,CAAC,CAAC,IAAI,EAAE,GAAG,GAAG,OAAO,CAAC,GAAG,EAAE,CAAC,CAAA;CACpC;AAED;;;;;;;;;;;;GAYG;AAEH,MAAM,MAAM,UAAU,GAAG;IAAE,CAAC,CAAC,EAAE,MAAM,GAAG,GAAG,CAAA;CAAE,CAAA;AAE7C,eAAO,MAAM,cAAc;aACzB,GAAG,EAAE,OAAO;aACZ,OAAO,EAAE,WAAW;aACpB,eAAe,EAAE,mBAAmB;aACpC,MAAM,EAAE,UAAU;aAClB,OAAO,EAAE,WAAW;aACpB,MAAM,EAAE,UAAU;aAClB,WAAW,EAAE,eAAe;aAC5B,KAAK,EAAE,SAAS;CACR,CAAA;AAEV,MAAM,MAAM,QAAQ,GAAG,MAAM,OAAO,cAAc,CAAA;AAClD,MAAM,MAAM,cAAc,GAAG,OAAO,CAAC,MAAM,CAAC,QAAQ,EAAE,MAAM,CAAC,CAAC,CAAA;AAE9D,wBAAgB,eAAe,CAC7B,MAAM,EAAE,UAAU,EAClB,GAAG,EAAE,QAAQ,EACb,SAAS,EAAE,cAAc,GAAG,SAAS,GACpC,cAAc,CAWhB"}
|
|
1
|
+
{"version":3,"file":"types.d.ts","sourceRoot":"","sources":["../src/types.ts"],"names":[],"mappings":"AAAA;;;;;;;;GAQG;AAIH,MAAM,WAAW,cAAc,CAAC,IAAI,GAAG,GAAG;IACxC,QAAQ,CAAC,IAAI,CAAC,EAAE,GAAG,GAAG,OAAO,CAAC,IAAI,EAAE,CAAC,CAAA;IACrC,UAAU,CAAC,IAAI,EAAE;QAAE,KAAK,EAAE,GAAG,CAAA;KAAE,GAAG,OAAO,CAAC,IAAI,GAAG,IAAI,CAAC,CAAA;IACtD,SAAS,CAAC,IAAI,CAAC,EAAE,GAAG,GAAG,OAAO,CAAC,IAAI,GAAG,IAAI,CAAC,CAAA;IAC3C,MAAM,CAAC,IAAI,EAAE;QAAE,IAAI,EAAE,GAAG,CAAA;KAAE,GAAG,OAAO,CAAC,IAAI,CAAC,CAAA;IAC1C,MAAM,CAAC,IAAI,EAAE;QAAE,KAAK,EAAE,GAAG,CAAC;QAAC,IAAI,EAAE,GAAG,CAAA;KAAE,GAAG,OAAO,CAAC,IAAI,CAAC,CAAA;IACtD,MAAM,CAAC,IAAI,EAAE;QAAE,KAAK,EAAE,GAAG,CAAC;QAAC,MAAM,EAAE,GAAG,CAAC;QAAC,MAAM,EAAE,GAAG,CAAA;KAAE,GAAG,OAAO,CAAC,IAAI,CAAC,CAAA;IACrE,MAAM,CAAC,IAAI,EAAE;QAAE,KAAK,EAAE,GAAG,CAAA;KAAE,GAAG,OAAO,CAAC,IAAI,CAAC,CAAA;IAC3C,UAAU,CAAC,IAAI,CAAC,EAAE;QAAE,KAAK,CAAC,EAAE,GAAG,CAAA;KAAE,GAAG,OAAO,CAAC;QAAE,KAAK,EAAE,MAAM,CAAA;KAAE,CAAC,CAAA;IAC9D,UAAU,CAAC,IAAI,EAAE;QAAE,KAAK,CAAC,EAAE,GAAG,CAAC;QAAC,IAAI,EAAE,GAAG,CAAA;KAAE,GAAG,OAAO,CAAC;QAAE,KAAK,EAAE,MAAM,CAAA;KAAE,CAAC,CAAA;IACxE,KAAK,CAAC,IAAI,CAAC,EAAE,GAAG,GAAG,OAAO,CAAC,MAAM,CAAC,CAAA;IAClC;;;OAGG;IACH,OAAO,CAAC,CAAC,IAAI,EAAE,GAAG,GAAG,OAAO,CAAC,GAAG,EAAE,CAAC,CAAA;CACpC;AAED;;;;;;;;;;;;GAYG;AAEH,MAAM,MAAM,UAAU,GAAG;IAAE,CAAC,CAAC,EAAE,MAAM,GAAG,GAAG,CAAA;CAAE,CAAA;AAE7C,eAAO,MAAM,cAAc;aACzB,GAAG,EAAE,OAAO;aACZ,OAAO,EAAE,WAAW;aACpB,eAAe,EAAE,mBAAmB;aACpC,MAAM,EAAE,UAAU;aAClB,OAAO,EAAE,WAAW;aACpB,MAAM,EAAE,UAAU;aAClB,WAAW,EAAE,eAAe;aAC5B,KAAK,EAAE,SAAS;CACR,CAAA;AAEV,MAAM,MAAM,QAAQ,GAAG,MAAM,OAAO,cAAc,CAAA;AAClD,MAAM,MAAM,cAAc,GAAG,OAAO,CAAC,MAAM,CAAC,QAAQ,EAAE,MAAM,CAAC,CAAC,CAAA;AAE9D,wBAAgB,eAAe,CAC7B,MAAM,EAAE,UAAU,EAClB,GAAG,EAAE,QAAQ,EACb,SAAS,EAAE,cAAc,GAAG,SAAS,GACpC,cAAc,CAWhB"}
|
package/dist/types.js.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"types.js","sourceRoot":"","sources":["../src/types.ts"],"names":[],"mappings":"AAAA;;;;;;;;GAQG;
|
|
1
|
+
{"version":3,"file":"types.js","sourceRoot":"","sources":["../src/types.ts"],"names":[],"mappings":"AAAA;;;;;;;;GAQG;AAsCH,MAAM,CAAC,MAAM,cAAc,GAAG;IAC5B,GAAG,EAAE,OAAO;IACZ,OAAO,EAAE,WAAW;IACpB,eAAe,EAAE,mBAAmB;IACpC,MAAM,EAAE,UAAU;IAClB,OAAO,EAAE,WAAW;IACpB,MAAM,EAAE,UAAU;IAClB,WAAW,EAAE,eAAe;IAC5B,KAAK,EAAE,SAAS;CACR,CAAA;AAKV,MAAM,UAAU,eAAe,CAC7B,MAAkB,EAClB,GAAa,EACb,SAAqC;IAErC,MAAM,IAAI,GAAG,SAAS,EAAE,CAAC,GAAG,CAAC,IAAI,cAAc,CAAC,GAAG,CAAC,CAAA;IACpD,MAAM,QAAQ,GAAG,MAAM,CAAC,IAAI,CAA+B,CAAA;IAC3D,IAAI,CAAC,QAAQ,IAAI,OAAO,QAAQ,CAAC,QAAQ,KAAK,UAAU,EAAE,CAAC;QACzD,MAAM,IAAI,KAAK,CACb,yDAAyD,IAAI,KAAK;YAClE,+EAA+E;YAC/E,0FAA0F,CAC3F,CAAA;IACH,CAAC;IACD,OAAO,QAAQ,CAAA;AACjB,CAAC"}
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@modern-admin/system-prisma",
|
|
3
|
-
"version": "0.
|
|
3
|
+
"version": "0.9.0",
|
|
4
4
|
"description": "Prisma-backed implementation of Modern Admin system stores (logs, history, webhooks, AI tasks).",
|
|
5
5
|
"homepage": "https://github.com/modern-admin/modern-admin/tree/main/packages/system-prisma#readme",
|
|
6
6
|
"keywords": [
|
|
@@ -45,7 +45,7 @@
|
|
|
45
45
|
}
|
|
46
46
|
},
|
|
47
47
|
"dependencies": {
|
|
48
|
-
"@modern-admin/core": "^0.
|
|
48
|
+
"@modern-admin/core": "^0.9.0"
|
|
49
49
|
},
|
|
50
50
|
"devDependencies": {
|
|
51
51
|
"@modern-admin/tsconfig": "0.4.0",
|
|
@@ -21,19 +21,27 @@ export class PrismaAiTaskStore implements IAiTaskStore {
|
|
|
21
21
|
) {}
|
|
22
22
|
|
|
23
23
|
async enqueue(input: AiTaskInput): Promise<AiTask> {
|
|
24
|
-
|
|
25
|
-
|
|
26
|
-
|
|
27
|
-
|
|
28
|
-
|
|
29
|
-
|
|
30
|
-
|
|
31
|
-
|
|
32
|
-
|
|
33
|
-
|
|
34
|
-
|
|
35
|
-
|
|
36
|
-
|
|
24
|
+
try {
|
|
25
|
+
const row = await this.taskDelegate.create({
|
|
26
|
+
data: {
|
|
27
|
+
id: uuidv7(),
|
|
28
|
+
idempotencyKey: input.idempotencyKey ?? null,
|
|
29
|
+
kind: input.kind,
|
|
30
|
+
resourceId: input.resourceId ?? null,
|
|
31
|
+
recordId: input.recordId ?? null,
|
|
32
|
+
userId: input.userId ?? null,
|
|
33
|
+
status: 'pending',
|
|
34
|
+
input: input.input ?? {},
|
|
35
|
+
progress: null,
|
|
36
|
+
},
|
|
37
|
+
})
|
|
38
|
+
return rowToTask(row)
|
|
39
|
+
} catch (error) {
|
|
40
|
+
if (!input.idempotencyKey) throw error
|
|
41
|
+
const existing = await this.getByIdempotencyKey(input.idempotencyKey)
|
|
42
|
+
if (!existing) throw error
|
|
43
|
+
return existing
|
|
44
|
+
}
|
|
37
45
|
}
|
|
38
46
|
|
|
39
47
|
async get(id: string): Promise<AiTask | null> {
|
|
@@ -41,15 +49,31 @@ export class PrismaAiTaskStore implements IAiTaskStore {
|
|
|
41
49
|
return row ? rowToTask(row) : null
|
|
42
50
|
}
|
|
43
51
|
|
|
52
|
+
async claim(id: string): Promise<AiTask | null> {
|
|
53
|
+
const result = await this.taskDelegate.updateMany({
|
|
54
|
+
where: { id, status: 'pending' },
|
|
55
|
+
data: { status: 'running', progress: 5, startedAt: new Date() },
|
|
56
|
+
})
|
|
57
|
+
if (result.count === 0) return null
|
|
58
|
+
return this.get(id)
|
|
59
|
+
}
|
|
60
|
+
|
|
61
|
+
async getByIdempotencyKey(idempotencyKey: string): Promise<AiTask | null> {
|
|
62
|
+
const row = await this.taskDelegate.findUnique({ where: { idempotencyKey } })
|
|
63
|
+
return row ? rowToTask(row) : null
|
|
64
|
+
}
|
|
65
|
+
|
|
44
66
|
async list(filter: Parameters<IAiTaskStore['list']>[0] = {}): Promise<AiTask[]> {
|
|
45
67
|
const where: Record<string, unknown> = {}
|
|
46
68
|
if (filter.kind) where['kind'] = filter.kind
|
|
69
|
+
if (filter.idempotencyKey) where['idempotencyKey'] = filter.idempotencyKey
|
|
47
70
|
if (filter.status) {
|
|
48
71
|
const list = Array.isArray(filter.status) ? filter.status : [filter.status]
|
|
49
72
|
where['status'] = { in: list }
|
|
50
73
|
}
|
|
51
74
|
if (filter.userId) where['userId'] = filter.userId
|
|
52
75
|
if (filter.resourceId) where['resourceId'] = filter.resourceId
|
|
76
|
+
if (filter.createdAfter) where['createdAt'] = { gte: new Date(filter.createdAfter) }
|
|
53
77
|
const rows = await this.taskDelegate.findMany({
|
|
54
78
|
where,
|
|
55
79
|
orderBy: { createdAt: 'desc' },
|
|
@@ -65,6 +89,7 @@ export class PrismaAiTaskStore implements IAiTaskStore {
|
|
|
65
89
|
progress?: number | null
|
|
66
90
|
output?: Record<string, unknown>
|
|
67
91
|
error?: string
|
|
92
|
+
expectedStatus?: AiTaskStatus[]
|
|
68
93
|
},
|
|
69
94
|
): Promise<AiTask> {
|
|
70
95
|
const data: Record<string, unknown> = { status: patch.status }
|
|
@@ -79,6 +104,18 @@ export class PrismaAiTaskStore implements IAiTaskStore {
|
|
|
79
104
|
if (TERMINAL.includes(patch.status)) {
|
|
80
105
|
data['finishedAt'] = new Date()
|
|
81
106
|
}
|
|
107
|
+
if (patch.expectedStatus) {
|
|
108
|
+
// Atomic guarded write: the WHERE clause makes the update a no-op unless
|
|
109
|
+
// the row is still in an expected status, so a concurrent cancel/finalize
|
|
110
|
+
// is never overwritten. Return the current row either way.
|
|
111
|
+
await this.taskDelegate.updateMany({
|
|
112
|
+
where: { id, status: { in: patch.expectedStatus } },
|
|
113
|
+
data,
|
|
114
|
+
})
|
|
115
|
+
const row = await this.taskDelegate.findUnique({ where: { id } })
|
|
116
|
+
if (!row) throw new Error(`AI task not found: ${id}`)
|
|
117
|
+
return rowToTask(row)
|
|
118
|
+
}
|
|
82
119
|
const row = await this.taskDelegate.update({ where: { id }, data })
|
|
83
120
|
return rowToTask(row)
|
|
84
121
|
}
|
package/src/stores/log-store.ts
CHANGED
|
@@ -1,6 +1,7 @@
|
|
|
1
1
|
import {
|
|
2
2
|
rowToLogEntry,
|
|
3
3
|
uuidv7,
|
|
4
|
+
type ActionLogRetention,
|
|
4
5
|
type ActionLogEntry,
|
|
5
6
|
type ILogStore,
|
|
6
7
|
type IQueryableLogStore,
|
|
@@ -10,6 +11,7 @@ import type { PrismaDelegate } from '../types.js'
|
|
|
10
11
|
|
|
11
12
|
/** Applied when the caller passes no `limit`. Matches `MemoryLogStore`. */
|
|
12
13
|
const DEFAULT_LIST_LIMIT = 50
|
|
14
|
+
const PRUNE_BATCH_SIZE = 1_000
|
|
13
15
|
|
|
14
16
|
export class PrismaLogStore implements IQueryableLogStore {
|
|
15
17
|
constructor(private readonly delegate: PrismaDelegate<LogRow>) {}
|
|
@@ -76,6 +78,43 @@ export class PrismaLogStore implements IQueryableLogStore {
|
|
|
76
78
|
})
|
|
77
79
|
return rows.map(rowToLogEntry)
|
|
78
80
|
}
|
|
81
|
+
|
|
82
|
+
/**
|
|
83
|
+
* Delete action-log entries outside the configured retention bounds.
|
|
84
|
+
* `keepLast` is global and deletions use an explicit id snapshot so a
|
|
85
|
+
* concurrent write can never be caught by a broad predicate.
|
|
86
|
+
*/
|
|
87
|
+
async prune(retention: ActionLogRetention): Promise<number> {
|
|
88
|
+
let removed = 0
|
|
89
|
+
|
|
90
|
+
if (retention.keepDays !== undefined) {
|
|
91
|
+
const cutoff = new Date(Date.now() - retention.keepDays * 24 * 60 * 60 * 1000)
|
|
92
|
+
const result = await this.delegate.deleteMany({
|
|
93
|
+
where: { createdAt: { lt: cutoff } },
|
|
94
|
+
})
|
|
95
|
+
removed += result.count
|
|
96
|
+
}
|
|
97
|
+
|
|
98
|
+
if (retention.keepLast !== undefined) {
|
|
99
|
+
const keep = Math.max(0, Math.trunc(retention.keepLast))
|
|
100
|
+
while (true) {
|
|
101
|
+
const obsolete = (await this.delegate.findMany({
|
|
102
|
+
orderBy: [{ createdAt: 'desc' }, { id: 'desc' }],
|
|
103
|
+
select: { id: true },
|
|
104
|
+
...(keep > 0 ? { skip: keep } : {}),
|
|
105
|
+
take: PRUNE_BATCH_SIZE,
|
|
106
|
+
})) as unknown as Array<{ id: string }>
|
|
107
|
+
if (obsolete.length === 0) break
|
|
108
|
+
|
|
109
|
+
const result = await this.delegate.deleteMany({
|
|
110
|
+
where: { id: { in: obsolete.map((row) => row.id) } },
|
|
111
|
+
})
|
|
112
|
+
removed += result.count
|
|
113
|
+
}
|
|
114
|
+
}
|
|
115
|
+
|
|
116
|
+
return removed
|
|
117
|
+
}
|
|
79
118
|
}
|
|
80
119
|
|
|
81
120
|
/** Narrow type-test: a pure `ILogStore` is enough where readback isn't needed. */
|
package/src/types.ts
CHANGED
|
@@ -19,6 +19,7 @@ export interface PrismaDelegate<TRow = any> {
|
|
|
19
19
|
upsert(args: { where: any; update: any; create: any }): Promise<TRow>
|
|
20
20
|
delete(args: { where: any }): Promise<TRow>
|
|
21
21
|
deleteMany(args?: { where?: any }): Promise<{ count: number }>
|
|
22
|
+
updateMany(args: { where?: any; data: any }): Promise<{ count: number }>
|
|
22
23
|
count(args?: any): Promise<number>
|
|
23
24
|
/**
|
|
24
25
|
* Present on every generated Prisma delegate. Optional here so hand-written
|