@dudousxd/nestjs-durable-store-mikro-orm 0.17.0 → 0.18.1
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/index.cjs +77 -26
- package/dist/index.cjs.map +1 -1
- package/dist/index.d.cts +33 -10
- package/dist/index.d.ts +33 -10
- package/dist/index.js +77 -26
- package/dist/index.js.map +1 -1
- package/package.json +2 -2
package/dist/index.cjs
CHANGED
|
@@ -116,11 +116,35 @@ var BufferedSignalEntity = class {
|
|
|
116
116
|
token;
|
|
117
117
|
payload;
|
|
118
118
|
};
|
|
119
|
+
function namespaceFilterCond(args) {
|
|
120
|
+
if (args?.namespace === void 0) return {};
|
|
121
|
+
return {
|
|
122
|
+
namespace: args.namespace
|
|
123
|
+
};
|
|
124
|
+
}
|
|
125
|
+
__name(namespaceFilterCond, "namespaceFilterCond");
|
|
119
126
|
function durableEntities(options = {}) {
|
|
120
127
|
const col = columnNamer(options.naming ?? "snake_case");
|
|
121
128
|
const workflowRuns = new import_core.EntitySchema({
|
|
122
129
|
class: WorkflowRunEntity,
|
|
123
130
|
tableName: "durable_workflow_runs",
|
|
131
|
+
// Global filter: confines every read to the tenant's namespace when the store is scoped.
|
|
132
|
+
// The `cond` returns `{}` (no-op) when the `namespace` arg is `undefined`, so an unscoped
|
|
133
|
+
// (operator / control-plane) store sees all rows unchanged — existing behaviour is preserved.
|
|
134
|
+
filters: {
|
|
135
|
+
namespace: {
|
|
136
|
+
name: "namespace",
|
|
137
|
+
cond: namespaceFilterCond,
|
|
138
|
+
default: true,
|
|
139
|
+
// Optional args: the store's own forks set the scope via `setFilterParams` (undefined =
|
|
140
|
+
// operator, sees all), but an external consumer that shares this ORM (an operator app reading
|
|
141
|
+
// WorkflowRunEntity through its own EntityManager) never sets it. Without this, MikroORM
|
|
142
|
+
// throws "No arguments provided for filter 'namespace'" on those queries. `args: false` makes
|
|
143
|
+
// the param optional — cond then receives `undefined` and no-ops (sees all), which is exactly
|
|
144
|
+
// the operator view, while a scoped store still passes its namespace through.
|
|
145
|
+
args: false
|
|
146
|
+
}
|
|
147
|
+
},
|
|
124
148
|
// Indexes mirror the Prisma adapter so a store swap keeps the same plan. The poller hits these
|
|
125
149
|
// every tick: `(status, wakeAt)` serves both the due-timer scan (status='suspended' AND wakeAt<=now)
|
|
126
150
|
// and, via its `status` prefix, the pending/incomplete status lookups; `(workflow, status)` serves
|
|
@@ -646,25 +670,51 @@ async function alignDurableCollation(orm) {
|
|
|
646
670
|
__name(alignDurableCollation, "alignDurableCollation");
|
|
647
671
|
|
|
648
672
|
// src/mikro-orm-state-store.ts
|
|
649
|
-
var MikroOrmStateStore = class {
|
|
673
|
+
var MikroOrmStateStore = class _MikroOrmStateStore {
|
|
650
674
|
static {
|
|
651
675
|
__name(this, "MikroOrmStateStore");
|
|
652
676
|
}
|
|
653
677
|
orm;
|
|
654
|
-
|
|
678
|
+
scopeNamespace;
|
|
679
|
+
constructor(orm, opts) {
|
|
655
680
|
this.orm = orm;
|
|
681
|
+
this.scopeNamespace = opts?.scope?.namespace;
|
|
682
|
+
}
|
|
683
|
+
/**
|
|
684
|
+
* Derive a store confined to a single tenant `scope.namespace`, sharing this store's ORM (no new
|
|
685
|
+
* connection). Turns the operator (unscoped) store into a tenant-boundary view at wiring time —
|
|
686
|
+
* used by the NestJS module's `scopeReads` option, which receives a pre-built store and can't
|
|
687
|
+
* reconstruct it. Pass `{ namespace: undefined }` for the unscoped operator view.
|
|
688
|
+
*/
|
|
689
|
+
withScope(scope) {
|
|
690
|
+
return new _MikroOrmStateStore(this.orm, {
|
|
691
|
+
scope
|
|
692
|
+
});
|
|
693
|
+
}
|
|
694
|
+
/**
|
|
695
|
+
* Create a forked EntityManager and activate the `namespace` global filter with the store's
|
|
696
|
+
* scope (if any). All read operations go through this so the tenant boundary is applied
|
|
697
|
+
* uniformly. Write operations (nativeDelete, nativeUpdate, upsert, insertMany) bypass global
|
|
698
|
+
* filters in MikroORM and are unaffected.
|
|
699
|
+
*/
|
|
700
|
+
fork() {
|
|
701
|
+
const em = this.orm.em.fork();
|
|
702
|
+
em.setFilterParams("namespace", {
|
|
703
|
+
namespace: this.scopeNamespace
|
|
704
|
+
});
|
|
705
|
+
return em;
|
|
656
706
|
}
|
|
657
707
|
async ensureSchema() {
|
|
658
708
|
await ensureMikroOrmDurableSchema(this.orm);
|
|
659
709
|
}
|
|
660
710
|
async createRun(run) {
|
|
661
|
-
const em = this.
|
|
711
|
+
const em = this.fork();
|
|
662
712
|
em.create(WorkflowRunEntity, toRunEntity(run));
|
|
663
713
|
await em.flush();
|
|
664
714
|
await this.reindexAttributes(run.id, run.searchAttributes);
|
|
665
715
|
}
|
|
666
716
|
async updateRun(runId, patch) {
|
|
667
|
-
const em = this.
|
|
717
|
+
const em = this.fork();
|
|
668
718
|
const entity = await em.findOneOrFail(WorkflowRunEntity, {
|
|
669
719
|
id: runId
|
|
670
720
|
});
|
|
@@ -678,7 +728,7 @@ var MikroOrmStateStore = class {
|
|
|
678
728
|
/** Rewrite a run's normalized attribute rows: delete the old set, insert the current one. Mirrors
|
|
679
729
|
* the in-memory store's reindex so the side-table always reflects the run's live searchAttributes. */
|
|
680
730
|
async reindexAttributes(runId, attributes, forked) {
|
|
681
|
-
const em = forked ?? this.
|
|
731
|
+
const em = forked ?? this.fork();
|
|
682
732
|
await em.nativeDelete(RunAttributeEntity, {
|
|
683
733
|
runId
|
|
684
734
|
});
|
|
@@ -686,14 +736,14 @@ var MikroOrmStateStore = class {
|
|
|
686
736
|
if (rows.length) await em.insertMany(RunAttributeEntity, rows);
|
|
687
737
|
}
|
|
688
738
|
async getRun(runId) {
|
|
689
|
-
const em = this.
|
|
739
|
+
const em = this.fork();
|
|
690
740
|
const entity = await em.findOne(WorkflowRunEntity, {
|
|
691
741
|
id: runId
|
|
692
742
|
});
|
|
693
743
|
return entity ? fromRunEntity(entity) : null;
|
|
694
744
|
}
|
|
695
745
|
async deleteRun(runId) {
|
|
696
|
-
const em = this.
|
|
746
|
+
const em = this.fork();
|
|
697
747
|
await em.nativeDelete(StepCheckpointEntity, {
|
|
698
748
|
runId
|
|
699
749
|
});
|
|
@@ -709,7 +759,7 @@ var MikroOrmStateStore = class {
|
|
|
709
759
|
}
|
|
710
760
|
async pruneTerminalRuns(policy, nowMs, limit) {
|
|
711
761
|
if (policy.statuses.length === 0 || limit <= 0) return 0;
|
|
712
|
-
const em = this.
|
|
762
|
+
const em = this.fork();
|
|
713
763
|
const status = {
|
|
714
764
|
$in: policy.statuses
|
|
715
765
|
};
|
|
@@ -775,7 +825,7 @@ var MikroOrmStateStore = class {
|
|
|
775
825
|
return idList.length;
|
|
776
826
|
}
|
|
777
827
|
async getCheckpoint(runId, seq) {
|
|
778
|
-
const em = this.
|
|
828
|
+
const em = this.fork();
|
|
779
829
|
const entity = await em.findOne(StepCheckpointEntity, {
|
|
780
830
|
runId,
|
|
781
831
|
seq
|
|
@@ -783,12 +833,12 @@ var MikroOrmStateStore = class {
|
|
|
783
833
|
return entity ? fromCheckpointEntity(entity) : null;
|
|
784
834
|
}
|
|
785
835
|
async saveCheckpoint(checkpoint) {
|
|
786
|
-
const em = this.
|
|
836
|
+
const em = this.fork();
|
|
787
837
|
await em.upsert(StepCheckpointEntity, toCheckpointEntity(checkpoint));
|
|
788
838
|
await em.flush();
|
|
789
839
|
}
|
|
790
840
|
async transaction(work) {
|
|
791
|
-
return this.
|
|
841
|
+
return this.fork().transactional(async (em) => work({
|
|
792
842
|
raw: em,
|
|
793
843
|
saveCheckpoint: /* @__PURE__ */ __name(async (cp) => {
|
|
794
844
|
await em.upsert(StepCheckpointEntity, toCheckpointEntity(cp));
|
|
@@ -796,7 +846,7 @@ var MikroOrmStateStore = class {
|
|
|
796
846
|
}));
|
|
797
847
|
}
|
|
798
848
|
async listIncompleteRuns(namespace) {
|
|
799
|
-
const em = this.
|
|
849
|
+
const em = this.fork();
|
|
800
850
|
const rows = await em.find(WorkflowRunEntity, {
|
|
801
851
|
status: {
|
|
802
852
|
$in: [
|
|
@@ -811,7 +861,7 @@ var MikroOrmStateStore = class {
|
|
|
811
861
|
return rows.map(fromRunEntity);
|
|
812
862
|
}
|
|
813
863
|
async listPendingRuns(limit, namespace) {
|
|
814
|
-
const em = this.
|
|
864
|
+
const em = this.fork();
|
|
815
865
|
const rows = await em.find(WorkflowRunEntity, {
|
|
816
866
|
status: "pending",
|
|
817
867
|
...namespace !== void 0 ? {
|
|
@@ -826,7 +876,7 @@ var MikroOrmStateStore = class {
|
|
|
826
876
|
return rows.map(fromRunEntity);
|
|
827
877
|
}
|
|
828
878
|
async listDueTimers(nowMs, namespace) {
|
|
829
|
-
const em = this.
|
|
879
|
+
const em = this.fork();
|
|
830
880
|
const rows = await em.find(WorkflowRunEntity, {
|
|
831
881
|
status: "suspended",
|
|
832
882
|
wakeAt: {
|
|
@@ -840,7 +890,7 @@ var MikroOrmStateStore = class {
|
|
|
840
890
|
return rows.map(fromRunEntity);
|
|
841
891
|
}
|
|
842
892
|
async tryLockRun(runId, owner, leaseUntilMs, nowMs) {
|
|
843
|
-
const em = this.
|
|
893
|
+
const em = this.fork();
|
|
844
894
|
const affected = await em.nativeUpdate(WorkflowRunEntity, {
|
|
845
895
|
id: runId,
|
|
846
896
|
$or: [
|
|
@@ -860,7 +910,7 @@ var MikroOrmStateStore = class {
|
|
|
860
910
|
return affected === 1;
|
|
861
911
|
}
|
|
862
912
|
async releaseRunLock(runId) {
|
|
863
|
-
const em = this.
|
|
913
|
+
const em = this.fork();
|
|
864
914
|
await em.nativeUpdate(WorkflowRunEntity, {
|
|
865
915
|
id: runId
|
|
866
916
|
}, {
|
|
@@ -869,7 +919,7 @@ var MikroOrmStateStore = class {
|
|
|
869
919
|
});
|
|
870
920
|
}
|
|
871
921
|
async renewRunLock(runId, owner, leaseUntilMs) {
|
|
872
|
-
const em = this.
|
|
922
|
+
const em = this.fork();
|
|
873
923
|
const affected = await em.nativeUpdate(WorkflowRunEntity, {
|
|
874
924
|
id: runId,
|
|
875
925
|
lockedBy: owner
|
|
@@ -879,7 +929,7 @@ var MikroOrmStateStore = class {
|
|
|
879
929
|
return affected === 1;
|
|
880
930
|
}
|
|
881
931
|
async listRuns(query) {
|
|
882
|
-
const em = this.
|
|
932
|
+
const em = this.fork();
|
|
883
933
|
const where = {};
|
|
884
934
|
if (query.workflow) where.workflow = query.workflow;
|
|
885
935
|
if (query.namespace !== void 0) where.namespace = query.namespace;
|
|
@@ -905,6 +955,7 @@ var MikroOrmStateStore = class {
|
|
|
905
955
|
createdAt: "desc"
|
|
906
956
|
};
|
|
907
957
|
if (query.tag || query.attributes?.length) {
|
|
958
|
+
if (this.scopeNamespace !== void 0) where.namespace = this.scopeNamespace;
|
|
908
959
|
const quote = this.idQuote(em);
|
|
909
960
|
const cols = this.attributeColumns(em);
|
|
910
961
|
const qb = em.createQueryBuilder(WorkflowRunEntity, "r").where(where).orderBy(orderBy);
|
|
@@ -987,7 +1038,7 @@ var MikroOrmStateStore = class {
|
|
|
987
1038
|
return (id) => `${ch}${id}${ch}`;
|
|
988
1039
|
}
|
|
989
1040
|
async listCheckpoints(runId) {
|
|
990
|
-
const em = this.
|
|
1041
|
+
const em = this.fork();
|
|
991
1042
|
const rows = await em.find(StepCheckpointEntity, {
|
|
992
1043
|
runId
|
|
993
1044
|
}, {
|
|
@@ -998,7 +1049,7 @@ var MikroOrmStateStore = class {
|
|
|
998
1049
|
return rows.map(fromCheckpointEntity);
|
|
999
1050
|
}
|
|
1000
1051
|
async getLatestCheckpointByName(runId, name) {
|
|
1001
|
-
const em = this.
|
|
1052
|
+
const em = this.fork();
|
|
1002
1053
|
const entity = await em.findOne(StepCheckpointEntity, {
|
|
1003
1054
|
runId,
|
|
1004
1055
|
name
|
|
@@ -1011,7 +1062,7 @@ var MikroOrmStateStore = class {
|
|
|
1011
1062
|
}
|
|
1012
1063
|
async listCheckpointsByNamePrefix(runId, prefixes) {
|
|
1013
1064
|
if (prefixes.length === 0) return [];
|
|
1014
|
-
const em = this.
|
|
1065
|
+
const em = this.fork();
|
|
1015
1066
|
const rows = await em.find(StepCheckpointEntity, {
|
|
1016
1067
|
runId,
|
|
1017
1068
|
$or: prefixes.map((p) => ({
|
|
@@ -1027,7 +1078,7 @@ var MikroOrmStateStore = class {
|
|
|
1027
1078
|
return rows.map(fromCheckpointEntity);
|
|
1028
1079
|
}
|
|
1029
1080
|
async putSignalWaiter(waiter) {
|
|
1030
|
-
const em = this.
|
|
1081
|
+
const em = this.fork();
|
|
1031
1082
|
await em.upsert(SignalWaiterEntity, {
|
|
1032
1083
|
token: waiter.token,
|
|
1033
1084
|
runId: waiter.runId,
|
|
@@ -1037,7 +1088,7 @@ var MikroOrmStateStore = class {
|
|
|
1037
1088
|
await em.flush();
|
|
1038
1089
|
}
|
|
1039
1090
|
async takeSignalWaiter(token) {
|
|
1040
|
-
const em = this.
|
|
1091
|
+
const em = this.fork();
|
|
1041
1092
|
const entity = await em.findOne(SignalWaiterEntity, {
|
|
1042
1093
|
token
|
|
1043
1094
|
});
|
|
@@ -1052,7 +1103,7 @@ var MikroOrmStateStore = class {
|
|
|
1052
1103
|
return waiter;
|
|
1053
1104
|
}
|
|
1054
1105
|
async listSignalWaiters(prefix) {
|
|
1055
|
-
const em = this.
|
|
1106
|
+
const em = this.fork();
|
|
1056
1107
|
const rows = await em.find(SignalWaiterEntity, {
|
|
1057
1108
|
token: {
|
|
1058
1109
|
$like: `${prefix}%`
|
|
@@ -1066,7 +1117,7 @@ var MikroOrmStateStore = class {
|
|
|
1066
1117
|
}));
|
|
1067
1118
|
}
|
|
1068
1119
|
async bufferSignal(token, payload) {
|
|
1069
|
-
const em = this.
|
|
1120
|
+
const em = this.fork();
|
|
1070
1121
|
const e = new BufferedSignalEntity();
|
|
1071
1122
|
e.token = token;
|
|
1072
1123
|
e.payload = payload ?? null;
|
|
@@ -1074,7 +1125,7 @@ var MikroOrmStateStore = class {
|
|
|
1074
1125
|
await em.flush();
|
|
1075
1126
|
}
|
|
1076
1127
|
async takeBufferedSignal(token) {
|
|
1077
|
-
const em = this.
|
|
1128
|
+
const em = this.fork();
|
|
1078
1129
|
const entity = await em.findOne(BufferedSignalEntity, {
|
|
1079
1130
|
token
|
|
1080
1131
|
}, {
|