@dudousxd/nestjs-durable-store-mikro-orm 0.31.0 → 0.33.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/index.cjs +134 -18
- package/dist/index.cjs.map +1 -1
- package/dist/index.d.cts +84 -49
- package/dist/index.d.ts +84 -49
- package/dist/index.js +132 -17
- package/dist/index.js.map +1 -1
- package/package.json +3 -3
package/dist/index.cjs
CHANGED
|
@@ -39,7 +39,8 @@ __export(index_exports, {
|
|
|
39
39
|
WorkflowRunRepository: () => WorkflowRunRepository,
|
|
40
40
|
durableEntities: () => durableEntities,
|
|
41
41
|
durableManagedTables: () => durableManagedTables,
|
|
42
|
-
ensureMikroOrmDurableSchema: () => ensureMikroOrmDurableSchema
|
|
42
|
+
ensureMikroOrmDurableSchema: () => ensureMikroOrmDurableSchema,
|
|
43
|
+
mikroOrmSchemaRepairWarning: () => mikroOrmSchemaRepairWarning
|
|
43
44
|
});
|
|
44
45
|
module.exports = __toCommonJS(index_exports);
|
|
45
46
|
|
|
@@ -721,6 +722,78 @@ var MARKER_TABLE = "durable_schema_meta";
|
|
|
721
722
|
var MARKER_ROW_ID = "durable";
|
|
722
723
|
var SCHEMA_LOCK_NAME = "durable_schema";
|
|
723
724
|
var SCHEMA_REVISION = 1;
|
|
725
|
+
function mikroOrmSchemaRepairWarning(repairs) {
|
|
726
|
+
return [
|
|
727
|
+
`[nestjs-durable] store-mikro-orm repaired the durable schema at boot: ${repairs.join("; ")}.`,
|
|
728
|
+
"The database had drifted from the schema this library version expects (it was created by an",
|
|
729
|
+
"older version, or a migration left these out), so they were applied at runtime and nothing",
|
|
730
|
+
"recorded them in your migration history. To make them permanent, add a migration that calls",
|
|
731
|
+
"`ensureMikroOrmDurableSchema(orm)`. This warning appears only when a repair was applied; a",
|
|
732
|
+
"schema that is already current logs nothing."
|
|
733
|
+
].join(" ");
|
|
734
|
+
}
|
|
735
|
+
__name(mikroOrmSchemaRepairWarning, "mikroOrmSchemaRepairWarning");
|
|
736
|
+
function unquote(identifier) {
|
|
737
|
+
return identifier.replace(/^[`"']|[`"']$/g, "");
|
|
738
|
+
}
|
|
739
|
+
__name(unquote, "unquote");
|
|
740
|
+
function describeDurableStatement(statement) {
|
|
741
|
+
const table = targetTable(statement) ?? "?";
|
|
742
|
+
if (/^create\s+table\b/i.test(statement)) return [
|
|
743
|
+
`created table ${table}`
|
|
744
|
+
];
|
|
745
|
+
const createIndex = statement.match(/^create\s+(?:unique\s+)?index\s+(?:if\s+not\s+exists\s+)?([`"']?[\w$]+[`"']?)/i);
|
|
746
|
+
if (createIndex?.[1]) return [
|
|
747
|
+
`created index ${unquote(createIndex[1])} on ${table}`
|
|
748
|
+
];
|
|
749
|
+
if (/^alter\s+table\b/i.test(statement)) {
|
|
750
|
+
const out = [];
|
|
751
|
+
let other = false;
|
|
752
|
+
for (const action of splitTopLevel(statement.replace(/^alter\s+table\s+[`"']?[\w$]+[`"']?\s*/i, ""))) {
|
|
753
|
+
const index = action.match(/^add\s+(?:unique\s+|fulltext\s+)?(?:index|key)\s+([`"']?[\w$]+[`"']?)/i);
|
|
754
|
+
const constraint = action.match(/^add\s+constraint\s+([`"']?[\w$]+[`"']?)/i);
|
|
755
|
+
const column = action.match(/^add\s+(?:column\s+)?([`"']?[\w$]+[`"']?)/i);
|
|
756
|
+
if (index?.[1]) out.push(`created index ${unquote(index[1])} on ${table}`);
|
|
757
|
+
else if (constraint?.[1]) out.push(`added constraint ${unquote(constraint[1])} on ${table}`);
|
|
758
|
+
else if (column?.[1] && !/^add\s+(?:primary|unique|fulltext|foreign)\b/i.test(action)) out.push(`added column ${table}.${unquote(column[1])}`);
|
|
759
|
+
else other = true;
|
|
760
|
+
}
|
|
761
|
+
if (other || out.length === 0) {
|
|
762
|
+
const flat = statement.replace(/\s+/g, " ");
|
|
763
|
+
out.push(`altered ${table} (${flat.length > 160 ? `${flat.slice(0, 157)}...` : flat})`);
|
|
764
|
+
}
|
|
765
|
+
return out;
|
|
766
|
+
}
|
|
767
|
+
return [
|
|
768
|
+
`ran ${statement.replace(/\s+/g, " ").slice(0, 160)}`
|
|
769
|
+
];
|
|
770
|
+
}
|
|
771
|
+
__name(describeDurableStatement, "describeDurableStatement");
|
|
772
|
+
function splitTopLevel(text) {
|
|
773
|
+
const parts = [];
|
|
774
|
+
let depth = 0;
|
|
775
|
+
let quote;
|
|
776
|
+
let current = "";
|
|
777
|
+
for (const ch of text) {
|
|
778
|
+
if (quote) {
|
|
779
|
+
if (ch === quote) quote = void 0;
|
|
780
|
+
} else if (ch === "'" || ch === '"' || ch === "`") {
|
|
781
|
+
quote = ch;
|
|
782
|
+
} else if (ch === "(") {
|
|
783
|
+
depth++;
|
|
784
|
+
} else if (ch === ")") {
|
|
785
|
+
depth--;
|
|
786
|
+
} else if (ch === "," && depth === 0) {
|
|
787
|
+
parts.push(current.trim());
|
|
788
|
+
current = "";
|
|
789
|
+
continue;
|
|
790
|
+
}
|
|
791
|
+
current += ch;
|
|
792
|
+
}
|
|
793
|
+
if (current.trim()) parts.push(current.trim());
|
|
794
|
+
return parts;
|
|
795
|
+
}
|
|
796
|
+
__name(splitTopLevel, "splitTopLevel");
|
|
724
797
|
function compareStrings(a, b) {
|
|
725
798
|
return a < b ? -1 : a > b ? 1 : 0;
|
|
726
799
|
}
|
|
@@ -839,7 +912,8 @@ async function releaseSchemaLock(orm, dialect) {
|
|
|
839
912
|
}
|
|
840
913
|
}
|
|
841
914
|
__name(releaseSchemaLock, "releaseSchemaLock");
|
|
842
|
-
async function ensureMikroOrmDurableSchema(orm) {
|
|
915
|
+
async function ensureMikroOrmDurableSchema(orm, options = {}) {
|
|
916
|
+
const logger = options.logger ?? console;
|
|
843
917
|
const dialect = detectSqlDialect(orm);
|
|
844
918
|
await orm.em.getConnection().execute(createMarkerTableSql());
|
|
845
919
|
const expected = computeExpectedFingerprint(orm, DURABLE_TABLE_NAMES);
|
|
@@ -852,8 +926,9 @@ async function ensureMikroOrmDurableSchema(orm) {
|
|
|
852
926
|
if (await readStoredFingerprint(orm) === expected) {
|
|
853
927
|
return;
|
|
854
928
|
}
|
|
855
|
-
await healDurableSchema(orm);
|
|
929
|
+
const { repairs, freshInstall } = await healDurableSchema(orm);
|
|
856
930
|
await writeFingerprint(orm, dialect, expected);
|
|
931
|
+
if (repairs.length > 0 && !freshInstall) logger.warn(mikroOrmSchemaRepairWarning(repairs));
|
|
857
932
|
} finally {
|
|
858
933
|
await releaseSchemaLock(orm, dialect);
|
|
859
934
|
}
|
|
@@ -868,9 +943,14 @@ async function healDurableSchema(orm) {
|
|
|
868
943
|
return table !== void 0 && DURABLE_TABLE_NAMES.has(table);
|
|
869
944
|
});
|
|
870
945
|
const connection = orm.em.getConnection();
|
|
946
|
+
const created = new Set(ours.filter((statement) => /^create\s+table\b/i.test(statement)).map((statement) => targetTable(statement)));
|
|
947
|
+
const repairs = [];
|
|
871
948
|
for (const statement of ours) {
|
|
872
949
|
try {
|
|
873
950
|
await connection.execute(statement);
|
|
951
|
+
const table = targetTable(statement);
|
|
952
|
+
const isCreateTable = /^create\s+table\b/i.test(statement);
|
|
953
|
+
if (isCreateTable || !created.has(table)) repairs.push(...describeDurableStatement(statement));
|
|
874
954
|
} catch (err) {
|
|
875
955
|
if (isRequiredStructure(statement)) {
|
|
876
956
|
throw err;
|
|
@@ -879,7 +959,17 @@ async function healDurableSchema(orm) {
|
|
|
879
959
|
console.warn(`[nestjs-durable-store-mikro-orm] skipped a non-structural durable-schema statement that failed; the column is left as-is (functional) \u2014 repair the data out of band to converge its type. Statement: ${statement} \u2014 ${message}`);
|
|
880
960
|
}
|
|
881
961
|
}
|
|
882
|
-
await alignDurableCollation(orm);
|
|
962
|
+
const converted = await alignDurableCollation(orm);
|
|
963
|
+
for (const { table, from, to } of converted) {
|
|
964
|
+
if (!created.has(table)) repairs.push(`converted ${table} collation from ${from} to ${to}`);
|
|
965
|
+
}
|
|
966
|
+
const freshInstall = [
|
|
967
|
+
...DURABLE_TABLE_NAMES
|
|
968
|
+
].every((table) => created.has(table));
|
|
969
|
+
return {
|
|
970
|
+
repairs,
|
|
971
|
+
freshInstall
|
|
972
|
+
};
|
|
883
973
|
}
|
|
884
974
|
__name(healDurableSchema, "healDurableSchema");
|
|
885
975
|
function isSafeSqlIdentifier(value) {
|
|
@@ -887,17 +977,18 @@ function isSafeSqlIdentifier(value) {
|
|
|
887
977
|
}
|
|
888
978
|
__name(isSafeSqlIdentifier, "isSafeSqlIdentifier");
|
|
889
979
|
async function alignDurableCollation(orm) {
|
|
980
|
+
const converted = [];
|
|
890
981
|
const platform = String(orm.em.getPlatform().constructor.name).toLowerCase();
|
|
891
982
|
if (!platform.includes("mysql") && !platform.includes("maria")) {
|
|
892
|
-
return;
|
|
983
|
+
return converted;
|
|
893
984
|
}
|
|
894
985
|
const collate = orm.config.get("collate");
|
|
895
986
|
if (typeof collate !== "string" || !isSafeSqlIdentifier(collate)) {
|
|
896
|
-
return;
|
|
987
|
+
return converted;
|
|
897
988
|
}
|
|
898
989
|
const charset = collate.split("_")[0];
|
|
899
990
|
if (!charset || !isSafeSqlIdentifier(charset)) {
|
|
900
|
-
return;
|
|
991
|
+
return converted;
|
|
901
992
|
}
|
|
902
993
|
const connection = orm.em.getConnection();
|
|
903
994
|
for (const table of DURABLE_TABLE_NAMES) {
|
|
@@ -910,11 +1001,17 @@ async function alignDurableCollation(orm) {
|
|
|
910
1001
|
continue;
|
|
911
1002
|
}
|
|
912
1003
|
await connection.execute(`alter table \`${table}\` convert to character set ${charset} collate ${collate}`);
|
|
1004
|
+
converted.push({
|
|
1005
|
+
table,
|
|
1006
|
+
from: current,
|
|
1007
|
+
to: collate
|
|
1008
|
+
});
|
|
913
1009
|
} catch (err) {
|
|
914
1010
|
const message = err instanceof Error ? err.message : String(err);
|
|
915
1011
|
console.warn(`[nestjs-durable-store-mikro-orm] could not align collation for \`${table}\` to ${collate} (left as-is): ${message}`);
|
|
916
1012
|
}
|
|
917
1013
|
}
|
|
1014
|
+
return converted;
|
|
918
1015
|
}
|
|
919
1016
|
__name(alignDurableCollation, "alignDurableCollation");
|
|
920
1017
|
|
|
@@ -924,10 +1021,12 @@ var MikroOrmStateStore = class _MikroOrmStateStore {
|
|
|
924
1021
|
__name(this, "MikroOrmStateStore");
|
|
925
1022
|
}
|
|
926
1023
|
orm;
|
|
1024
|
+
opts;
|
|
927
1025
|
scopeNamespace;
|
|
928
|
-
constructor(orm, opts) {
|
|
1026
|
+
constructor(orm, opts = {}) {
|
|
929
1027
|
this.orm = orm;
|
|
930
|
-
this.
|
|
1028
|
+
this.opts = opts;
|
|
1029
|
+
this.scopeNamespace = opts.scope?.namespace;
|
|
931
1030
|
}
|
|
932
1031
|
/**
|
|
933
1032
|
* Derive a store confined to a single tenant `scope.namespace`, sharing this store's ORM (no new
|
|
@@ -937,6 +1036,7 @@ var MikroOrmStateStore = class _MikroOrmStateStore {
|
|
|
937
1036
|
*/
|
|
938
1037
|
withScope(scope) {
|
|
939
1038
|
return new _MikroOrmStateStore(this.orm, {
|
|
1039
|
+
...this.opts,
|
|
940
1040
|
scope
|
|
941
1041
|
});
|
|
942
1042
|
}
|
|
@@ -954,7 +1054,9 @@ var MikroOrmStateStore = class _MikroOrmStateStore {
|
|
|
954
1054
|
return em;
|
|
955
1055
|
}
|
|
956
1056
|
async ensureSchema() {
|
|
957
|
-
await ensureMikroOrmDurableSchema(this.orm
|
|
1057
|
+
await ensureMikroOrmDurableSchema(this.orm, {
|
|
1058
|
+
logger: this.opts.schemaLogger
|
|
1059
|
+
});
|
|
958
1060
|
}
|
|
959
1061
|
async tryAdmitSingleton(runId, tag, workflow, limit, retryWakeAt) {
|
|
960
1062
|
return this.fork().transactional(async (em) => {
|
|
@@ -980,6 +1082,7 @@ var MikroOrmStateStore = class _MikroOrmStateStore {
|
|
|
980
1082
|
}, {
|
|
981
1083
|
status: "suspended",
|
|
982
1084
|
wakeAt: new Date(patch.wakeAt),
|
|
1085
|
+
tags: patch.tags,
|
|
983
1086
|
updatedAt: patch.updatedAt
|
|
984
1087
|
});
|
|
985
1088
|
return false;
|
|
@@ -1199,7 +1302,7 @@ var MikroOrmStateStore = class _MikroOrmStateStore {
|
|
|
1199
1302
|
});
|
|
1200
1303
|
return rows.map(fromRunEntity);
|
|
1201
1304
|
}
|
|
1202
|
-
async listOrphanedRuns(nowMs, limit, namespace) {
|
|
1305
|
+
async listOrphanedRuns(nowMs, limit, namespace, ownedBy) {
|
|
1203
1306
|
if (limit <= 0) return [];
|
|
1204
1307
|
const em = this.fork();
|
|
1205
1308
|
const rows = await em.find(WorkflowRunEntity, {
|
|
@@ -1217,7 +1320,16 @@ var MikroOrmStateStore = class _MikroOrmStateStore {
|
|
|
1217
1320
|
lockedUntil: {
|
|
1218
1321
|
$lte: new Date(nowMs)
|
|
1219
1322
|
}
|
|
1220
|
-
}
|
|
1323
|
+
},
|
|
1324
|
+
// A live lease left by a previous process with the caller's own instance id.
|
|
1325
|
+
...ownedBy ? [
|
|
1326
|
+
{
|
|
1327
|
+
lockedBy: ownedBy.owner,
|
|
1328
|
+
lockedUntil: {
|
|
1329
|
+
$lt: new Date(ownedBy.lockedBefore)
|
|
1330
|
+
}
|
|
1331
|
+
}
|
|
1332
|
+
] : []
|
|
1221
1333
|
],
|
|
1222
1334
|
...namespace !== void 0 ? {
|
|
1223
1335
|
namespace
|
|
@@ -1286,10 +1398,13 @@ var MikroOrmStateStore = class _MikroOrmStateStore {
|
|
|
1286
1398
|
});
|
|
1287
1399
|
return affected === 1;
|
|
1288
1400
|
}
|
|
1289
|
-
async releaseRunLock(runId) {
|
|
1401
|
+
async releaseRunLock(runId, owner) {
|
|
1290
1402
|
const em = this.fork();
|
|
1291
|
-
await em.nativeUpdate(WorkflowRunEntity, {
|
|
1403
|
+
await em.nativeUpdate(WorkflowRunEntity, owner === void 0 ? {
|
|
1292
1404
|
id: runId
|
|
1405
|
+
} : {
|
|
1406
|
+
id: runId,
|
|
1407
|
+
lockedBy: owner
|
|
1293
1408
|
}, {
|
|
1294
1409
|
lockedBy: null,
|
|
1295
1410
|
lockedUntil: null
|
|
@@ -1621,7 +1736,7 @@ var MikroOrmStateStore = class _MikroOrmStateStore {
|
|
|
1621
1736
|
* single statement. */
|
|
1622
1737
|
async updateSchedule(id, patch, expectedNextFireAt) {
|
|
1623
1738
|
const data = {};
|
|
1624
|
-
if (patch.namespace !== void 0) data.namespace = patch.namespace;
|
|
1739
|
+
if (patch.namespace !== void 0) data.namespace = patch.namespace || "default";
|
|
1625
1740
|
if (patch.workflow !== void 0) data.workflow = patch.workflow;
|
|
1626
1741
|
if (patch.paused !== void 0) data.paused = patch.paused;
|
|
1627
1742
|
if ("nextFireAt" in patch) data.nextFireAt = patch.nextFireAt ?? null;
|
|
@@ -2007,7 +2122,7 @@ function runUpdateData(patch) {
|
|
|
2007
2122
|
if ("tags" in patch) data.tags = patch.tags ?? null;
|
|
2008
2123
|
if ("searchAttributes" in patch) data.searchAttributes = patch.searchAttributes ?? null;
|
|
2009
2124
|
if ("priority" in patch) data.priority = patch.priority ?? null;
|
|
2010
|
-
if ("namespace" in patch) data.namespace = patch.namespace
|
|
2125
|
+
if ("namespace" in patch) data.namespace = patch.namespace || "default";
|
|
2011
2126
|
if ("origin" in patch) data.origin = patch.origin ?? null;
|
|
2012
2127
|
if (patch.createdAt != null) data.createdAt = patch.createdAt;
|
|
2013
2128
|
if (patch.updatedAt != null) data.updatedAt = patch.updatedAt;
|
|
@@ -2031,7 +2146,7 @@ function toRunEntity(run) {
|
|
|
2031
2146
|
e.tags = run.tags ?? null;
|
|
2032
2147
|
e.searchAttributes = run.searchAttributes ?? null;
|
|
2033
2148
|
e.priority = run.priority ?? null;
|
|
2034
|
-
e.namespace = run.namespace
|
|
2149
|
+
e.namespace = run.namespace || "default";
|
|
2035
2150
|
e.origin = run.origin ?? null;
|
|
2036
2151
|
e.createdAt = run.createdAt;
|
|
2037
2152
|
e.updatedAt = run.updatedAt;
|
|
@@ -2174,6 +2289,7 @@ __name(fromScheduleEntity, "fromScheduleEntity");
|
|
|
2174
2289
|
WorkflowRunRepository,
|
|
2175
2290
|
durableEntities,
|
|
2176
2291
|
durableManagedTables,
|
|
2177
|
-
ensureMikroOrmDurableSchema
|
|
2292
|
+
ensureMikroOrmDurableSchema,
|
|
2293
|
+
mikroOrmSchemaRepairWarning
|
|
2178
2294
|
});
|
|
2179
2295
|
//# sourceMappingURL=index.cjs.map
|