@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.js
CHANGED
|
@@ -84,11 +84,35 @@ var BufferedSignalEntity = class {
|
|
|
84
84
|
token;
|
|
85
85
|
payload;
|
|
86
86
|
};
|
|
87
|
+
function namespaceFilterCond(args) {
|
|
88
|
+
if (args?.namespace === void 0) return {};
|
|
89
|
+
return {
|
|
90
|
+
namespace: args.namespace
|
|
91
|
+
};
|
|
92
|
+
}
|
|
93
|
+
__name(namespaceFilterCond, "namespaceFilterCond");
|
|
87
94
|
function durableEntities(options = {}) {
|
|
88
95
|
const col = columnNamer(options.naming ?? "snake_case");
|
|
89
96
|
const workflowRuns = new EntitySchema({
|
|
90
97
|
class: WorkflowRunEntity,
|
|
91
98
|
tableName: "durable_workflow_runs",
|
|
99
|
+
// Global filter: confines every read to the tenant's namespace when the store is scoped.
|
|
100
|
+
// The `cond` returns `{}` (no-op) when the `namespace` arg is `undefined`, so an unscoped
|
|
101
|
+
// (operator / control-plane) store sees all rows unchanged — existing behaviour is preserved.
|
|
102
|
+
filters: {
|
|
103
|
+
namespace: {
|
|
104
|
+
name: "namespace",
|
|
105
|
+
cond: namespaceFilterCond,
|
|
106
|
+
default: true,
|
|
107
|
+
// Optional args: the store's own forks set the scope via `setFilterParams` (undefined =
|
|
108
|
+
// operator, sees all), but an external consumer that shares this ORM (an operator app reading
|
|
109
|
+
// WorkflowRunEntity through its own EntityManager) never sets it. Without this, MikroORM
|
|
110
|
+
// throws "No arguments provided for filter 'namespace'" on those queries. `args: false` makes
|
|
111
|
+
// the param optional — cond then receives `undefined` and no-ops (sees all), which is exactly
|
|
112
|
+
// the operator view, while a scoped store still passes its namespace through.
|
|
113
|
+
args: false
|
|
114
|
+
}
|
|
115
|
+
},
|
|
92
116
|
// Indexes mirror the Prisma adapter so a store swap keeps the same plan. The poller hits these
|
|
93
117
|
// every tick: `(status, wakeAt)` serves both the due-timer scan (status='suspended' AND wakeAt<=now)
|
|
94
118
|
// and, via its `status` prefix, the pending/incomplete status lookups; `(workflow, status)` serves
|
|
@@ -614,25 +638,51 @@ async function alignDurableCollation(orm) {
|
|
|
614
638
|
__name(alignDurableCollation, "alignDurableCollation");
|
|
615
639
|
|
|
616
640
|
// src/mikro-orm-state-store.ts
|
|
617
|
-
var MikroOrmStateStore = class {
|
|
641
|
+
var MikroOrmStateStore = class _MikroOrmStateStore {
|
|
618
642
|
static {
|
|
619
643
|
__name(this, "MikroOrmStateStore");
|
|
620
644
|
}
|
|
621
645
|
orm;
|
|
622
|
-
|
|
646
|
+
scopeNamespace;
|
|
647
|
+
constructor(orm, opts) {
|
|
623
648
|
this.orm = orm;
|
|
649
|
+
this.scopeNamespace = opts?.scope?.namespace;
|
|
650
|
+
}
|
|
651
|
+
/**
|
|
652
|
+
* Derive a store confined to a single tenant `scope.namespace`, sharing this store's ORM (no new
|
|
653
|
+
* connection). Turns the operator (unscoped) store into a tenant-boundary view at wiring time —
|
|
654
|
+
* used by the NestJS module's `scopeReads` option, which receives a pre-built store and can't
|
|
655
|
+
* reconstruct it. Pass `{ namespace: undefined }` for the unscoped operator view.
|
|
656
|
+
*/
|
|
657
|
+
withScope(scope) {
|
|
658
|
+
return new _MikroOrmStateStore(this.orm, {
|
|
659
|
+
scope
|
|
660
|
+
});
|
|
661
|
+
}
|
|
662
|
+
/**
|
|
663
|
+
* Create a forked EntityManager and activate the `namespace` global filter with the store's
|
|
664
|
+
* scope (if any). All read operations go through this so the tenant boundary is applied
|
|
665
|
+
* uniformly. Write operations (nativeDelete, nativeUpdate, upsert, insertMany) bypass global
|
|
666
|
+
* filters in MikroORM and are unaffected.
|
|
667
|
+
*/
|
|
668
|
+
fork() {
|
|
669
|
+
const em = this.orm.em.fork();
|
|
670
|
+
em.setFilterParams("namespace", {
|
|
671
|
+
namespace: this.scopeNamespace
|
|
672
|
+
});
|
|
673
|
+
return em;
|
|
624
674
|
}
|
|
625
675
|
async ensureSchema() {
|
|
626
676
|
await ensureMikroOrmDurableSchema(this.orm);
|
|
627
677
|
}
|
|
628
678
|
async createRun(run) {
|
|
629
|
-
const em = this.
|
|
679
|
+
const em = this.fork();
|
|
630
680
|
em.create(WorkflowRunEntity, toRunEntity(run));
|
|
631
681
|
await em.flush();
|
|
632
682
|
await this.reindexAttributes(run.id, run.searchAttributes);
|
|
633
683
|
}
|
|
634
684
|
async updateRun(runId, patch) {
|
|
635
|
-
const em = this.
|
|
685
|
+
const em = this.fork();
|
|
636
686
|
const entity = await em.findOneOrFail(WorkflowRunEntity, {
|
|
637
687
|
id: runId
|
|
638
688
|
});
|
|
@@ -646,7 +696,7 @@ var MikroOrmStateStore = class {
|
|
|
646
696
|
/** Rewrite a run's normalized attribute rows: delete the old set, insert the current one. Mirrors
|
|
647
697
|
* the in-memory store's reindex so the side-table always reflects the run's live searchAttributes. */
|
|
648
698
|
async reindexAttributes(runId, attributes, forked) {
|
|
649
|
-
const em = forked ?? this.
|
|
699
|
+
const em = forked ?? this.fork();
|
|
650
700
|
await em.nativeDelete(RunAttributeEntity, {
|
|
651
701
|
runId
|
|
652
702
|
});
|
|
@@ -654,14 +704,14 @@ var MikroOrmStateStore = class {
|
|
|
654
704
|
if (rows.length) await em.insertMany(RunAttributeEntity, rows);
|
|
655
705
|
}
|
|
656
706
|
async getRun(runId) {
|
|
657
|
-
const em = this.
|
|
707
|
+
const em = this.fork();
|
|
658
708
|
const entity = await em.findOne(WorkflowRunEntity, {
|
|
659
709
|
id: runId
|
|
660
710
|
});
|
|
661
711
|
return entity ? fromRunEntity(entity) : null;
|
|
662
712
|
}
|
|
663
713
|
async deleteRun(runId) {
|
|
664
|
-
const em = this.
|
|
714
|
+
const em = this.fork();
|
|
665
715
|
await em.nativeDelete(StepCheckpointEntity, {
|
|
666
716
|
runId
|
|
667
717
|
});
|
|
@@ -677,7 +727,7 @@ var MikroOrmStateStore = class {
|
|
|
677
727
|
}
|
|
678
728
|
async pruneTerminalRuns(policy, nowMs, limit) {
|
|
679
729
|
if (policy.statuses.length === 0 || limit <= 0) return 0;
|
|
680
|
-
const em = this.
|
|
730
|
+
const em = this.fork();
|
|
681
731
|
const status = {
|
|
682
732
|
$in: policy.statuses
|
|
683
733
|
};
|
|
@@ -743,7 +793,7 @@ var MikroOrmStateStore = class {
|
|
|
743
793
|
return idList.length;
|
|
744
794
|
}
|
|
745
795
|
async getCheckpoint(runId, seq) {
|
|
746
|
-
const em = this.
|
|
796
|
+
const em = this.fork();
|
|
747
797
|
const entity = await em.findOne(StepCheckpointEntity, {
|
|
748
798
|
runId,
|
|
749
799
|
seq
|
|
@@ -751,12 +801,12 @@ var MikroOrmStateStore = class {
|
|
|
751
801
|
return entity ? fromCheckpointEntity(entity) : null;
|
|
752
802
|
}
|
|
753
803
|
async saveCheckpoint(checkpoint) {
|
|
754
|
-
const em = this.
|
|
804
|
+
const em = this.fork();
|
|
755
805
|
await em.upsert(StepCheckpointEntity, toCheckpointEntity(checkpoint));
|
|
756
806
|
await em.flush();
|
|
757
807
|
}
|
|
758
808
|
async transaction(work) {
|
|
759
|
-
return this.
|
|
809
|
+
return this.fork().transactional(async (em) => work({
|
|
760
810
|
raw: em,
|
|
761
811
|
saveCheckpoint: /* @__PURE__ */ __name(async (cp) => {
|
|
762
812
|
await em.upsert(StepCheckpointEntity, toCheckpointEntity(cp));
|
|
@@ -764,7 +814,7 @@ var MikroOrmStateStore = class {
|
|
|
764
814
|
}));
|
|
765
815
|
}
|
|
766
816
|
async listIncompleteRuns(namespace) {
|
|
767
|
-
const em = this.
|
|
817
|
+
const em = this.fork();
|
|
768
818
|
const rows = await em.find(WorkflowRunEntity, {
|
|
769
819
|
status: {
|
|
770
820
|
$in: [
|
|
@@ -779,7 +829,7 @@ var MikroOrmStateStore = class {
|
|
|
779
829
|
return rows.map(fromRunEntity);
|
|
780
830
|
}
|
|
781
831
|
async listPendingRuns(limit, namespace) {
|
|
782
|
-
const em = this.
|
|
832
|
+
const em = this.fork();
|
|
783
833
|
const rows = await em.find(WorkflowRunEntity, {
|
|
784
834
|
status: "pending",
|
|
785
835
|
...namespace !== void 0 ? {
|
|
@@ -794,7 +844,7 @@ var MikroOrmStateStore = class {
|
|
|
794
844
|
return rows.map(fromRunEntity);
|
|
795
845
|
}
|
|
796
846
|
async listDueTimers(nowMs, namespace) {
|
|
797
|
-
const em = this.
|
|
847
|
+
const em = this.fork();
|
|
798
848
|
const rows = await em.find(WorkflowRunEntity, {
|
|
799
849
|
status: "suspended",
|
|
800
850
|
wakeAt: {
|
|
@@ -808,7 +858,7 @@ var MikroOrmStateStore = class {
|
|
|
808
858
|
return rows.map(fromRunEntity);
|
|
809
859
|
}
|
|
810
860
|
async tryLockRun(runId, owner, leaseUntilMs, nowMs) {
|
|
811
|
-
const em = this.
|
|
861
|
+
const em = this.fork();
|
|
812
862
|
const affected = await em.nativeUpdate(WorkflowRunEntity, {
|
|
813
863
|
id: runId,
|
|
814
864
|
$or: [
|
|
@@ -828,7 +878,7 @@ var MikroOrmStateStore = class {
|
|
|
828
878
|
return affected === 1;
|
|
829
879
|
}
|
|
830
880
|
async releaseRunLock(runId) {
|
|
831
|
-
const em = this.
|
|
881
|
+
const em = this.fork();
|
|
832
882
|
await em.nativeUpdate(WorkflowRunEntity, {
|
|
833
883
|
id: runId
|
|
834
884
|
}, {
|
|
@@ -837,7 +887,7 @@ var MikroOrmStateStore = class {
|
|
|
837
887
|
});
|
|
838
888
|
}
|
|
839
889
|
async renewRunLock(runId, owner, leaseUntilMs) {
|
|
840
|
-
const em = this.
|
|
890
|
+
const em = this.fork();
|
|
841
891
|
const affected = await em.nativeUpdate(WorkflowRunEntity, {
|
|
842
892
|
id: runId,
|
|
843
893
|
lockedBy: owner
|
|
@@ -847,7 +897,7 @@ var MikroOrmStateStore = class {
|
|
|
847
897
|
return affected === 1;
|
|
848
898
|
}
|
|
849
899
|
async listRuns(query) {
|
|
850
|
-
const em = this.
|
|
900
|
+
const em = this.fork();
|
|
851
901
|
const where = {};
|
|
852
902
|
if (query.workflow) where.workflow = query.workflow;
|
|
853
903
|
if (query.namespace !== void 0) where.namespace = query.namespace;
|
|
@@ -873,6 +923,7 @@ var MikroOrmStateStore = class {
|
|
|
873
923
|
createdAt: "desc"
|
|
874
924
|
};
|
|
875
925
|
if (query.tag || query.attributes?.length) {
|
|
926
|
+
if (this.scopeNamespace !== void 0) where.namespace = this.scopeNamespace;
|
|
876
927
|
const quote = this.idQuote(em);
|
|
877
928
|
const cols = this.attributeColumns(em);
|
|
878
929
|
const qb = em.createQueryBuilder(WorkflowRunEntity, "r").where(where).orderBy(orderBy);
|
|
@@ -955,7 +1006,7 @@ var MikroOrmStateStore = class {
|
|
|
955
1006
|
return (id) => `${ch}${id}${ch}`;
|
|
956
1007
|
}
|
|
957
1008
|
async listCheckpoints(runId) {
|
|
958
|
-
const em = this.
|
|
1009
|
+
const em = this.fork();
|
|
959
1010
|
const rows = await em.find(StepCheckpointEntity, {
|
|
960
1011
|
runId
|
|
961
1012
|
}, {
|
|
@@ -966,7 +1017,7 @@ var MikroOrmStateStore = class {
|
|
|
966
1017
|
return rows.map(fromCheckpointEntity);
|
|
967
1018
|
}
|
|
968
1019
|
async getLatestCheckpointByName(runId, name) {
|
|
969
|
-
const em = this.
|
|
1020
|
+
const em = this.fork();
|
|
970
1021
|
const entity = await em.findOne(StepCheckpointEntity, {
|
|
971
1022
|
runId,
|
|
972
1023
|
name
|
|
@@ -979,7 +1030,7 @@ var MikroOrmStateStore = class {
|
|
|
979
1030
|
}
|
|
980
1031
|
async listCheckpointsByNamePrefix(runId, prefixes) {
|
|
981
1032
|
if (prefixes.length === 0) return [];
|
|
982
|
-
const em = this.
|
|
1033
|
+
const em = this.fork();
|
|
983
1034
|
const rows = await em.find(StepCheckpointEntity, {
|
|
984
1035
|
runId,
|
|
985
1036
|
$or: prefixes.map((p) => ({
|
|
@@ -995,7 +1046,7 @@ var MikroOrmStateStore = class {
|
|
|
995
1046
|
return rows.map(fromCheckpointEntity);
|
|
996
1047
|
}
|
|
997
1048
|
async putSignalWaiter(waiter) {
|
|
998
|
-
const em = this.
|
|
1049
|
+
const em = this.fork();
|
|
999
1050
|
await em.upsert(SignalWaiterEntity, {
|
|
1000
1051
|
token: waiter.token,
|
|
1001
1052
|
runId: waiter.runId,
|
|
@@ -1005,7 +1056,7 @@ var MikroOrmStateStore = class {
|
|
|
1005
1056
|
await em.flush();
|
|
1006
1057
|
}
|
|
1007
1058
|
async takeSignalWaiter(token) {
|
|
1008
|
-
const em = this.
|
|
1059
|
+
const em = this.fork();
|
|
1009
1060
|
const entity = await em.findOne(SignalWaiterEntity, {
|
|
1010
1061
|
token
|
|
1011
1062
|
});
|
|
@@ -1020,7 +1071,7 @@ var MikroOrmStateStore = class {
|
|
|
1020
1071
|
return waiter;
|
|
1021
1072
|
}
|
|
1022
1073
|
async listSignalWaiters(prefix) {
|
|
1023
|
-
const em = this.
|
|
1074
|
+
const em = this.fork();
|
|
1024
1075
|
const rows = await em.find(SignalWaiterEntity, {
|
|
1025
1076
|
token: {
|
|
1026
1077
|
$like: `${prefix}%`
|
|
@@ -1034,7 +1085,7 @@ var MikroOrmStateStore = class {
|
|
|
1034
1085
|
}));
|
|
1035
1086
|
}
|
|
1036
1087
|
async bufferSignal(token, payload) {
|
|
1037
|
-
const em = this.
|
|
1088
|
+
const em = this.fork();
|
|
1038
1089
|
const e = new BufferedSignalEntity();
|
|
1039
1090
|
e.token = token;
|
|
1040
1091
|
e.payload = payload ?? null;
|
|
@@ -1042,7 +1093,7 @@ var MikroOrmStateStore = class {
|
|
|
1042
1093
|
await em.flush();
|
|
1043
1094
|
}
|
|
1044
1095
|
async takeBufferedSignal(token) {
|
|
1045
|
-
const em = this.
|
|
1096
|
+
const em = this.fork();
|
|
1046
1097
|
const entity = await em.findOne(BufferedSignalEntity, {
|
|
1047
1098
|
token
|
|
1048
1099
|
}, {
|