@dudousxd/nestjs-durable-store-typeorm 0.13.0 → 0.15.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 CHANGED
@@ -21,6 +21,7 @@ var __toCommonJS = (mod) => __copyProps(__defProp({}, "__esModule", { value: tru
21
21
  // src/index.ts
22
22
  var index_exports = {};
23
23
  __export(index_exports, {
24
+ BufferedEventEntity: () => BufferedEventEntity,
24
25
  BufferedSignalEntity: () => BufferedSignalEntity,
25
26
  ENTITIES: () => ENTITIES,
26
27
  JSON_BLOB_COLUMNS: () => JSON_BLOB_COLUMNS,
@@ -89,6 +90,7 @@ var WorkflowRunEntity = class {
89
90
  tags;
90
91
  searchAttributes;
91
92
  priority;
93
+ origin;
92
94
  createdAt;
93
95
  updatedAt;
94
96
  };
@@ -140,6 +142,15 @@ var BufferedSignalEntity = class {
140
142
  token;
141
143
  payload;
142
144
  };
145
+ var BufferedEventEntity = class {
146
+ static {
147
+ __name(this, "BufferedEventEntity");
148
+ }
149
+ id;
150
+ name;
151
+ payload;
152
+ publishedAt;
153
+ };
143
154
  function durableEntities(options = {}) {
144
155
  const col = columnNamer(options.naming ?? "snake_case");
145
156
  const workflowRuns = new import_typeorm.EntitySchema({
@@ -226,6 +237,18 @@ function durableEntities(options = {}) {
226
237
  nullable: true,
227
238
  name: col("priority")
228
239
  },
240
+ // Which library/module registered the workflow this run belongs to (e.g.
241
+ // `@dudousxd/nestjs-catalog-pipeline`), derived at registration time — never caller input.
242
+ // Nullable with NO default: an origin cannot be reconstructed for a row written before this
243
+ // column existed, so it stays NULL and reads back as `undefined` = "unknown". Defaulting it to
244
+ // a real-looking string would be indistinguishable from a genuine registration in the
245
+ // dashboard's facet. `ensureTypeOrmDurableSchema` back-fills the COLUMN onto pre-existing
246
+ // tables (see the `additive` map in ./schema), never its value.
247
+ origin: {
248
+ type: "text",
249
+ nullable: true,
250
+ name: col("origin")
251
+ },
229
252
  createdAt: {
230
253
  type: Date,
231
254
  name: col("createdAt")
@@ -408,12 +431,44 @@ function durableEntities(options = {}) {
408
431
  }
409
432
  }
410
433
  });
434
+ const bufferedEvents = new import_typeorm.EntitySchema({
435
+ name: "BufferedEventEntity",
436
+ target: BufferedEventEntity,
437
+ tableName: "durable_buffered_events",
438
+ // No `indices` here (unlike MikroORM's EntitySchema, which does declare one): this store manages
439
+ // its DDL — including the `(name, publishedAt)` index — via raw SQL in `schema.ts`'s
440
+ // `ensureTypeOrmDurableSchema`, the same as every other durable_* table's indexes.
441
+ columns: {
442
+ // Caller-minted uuid (engine.publishEvent), not autoincrement — removeBufferedEvent targets it
443
+ // directly and needs to be handed the SAME id it was buffered with.
444
+ id: {
445
+ type: "text",
446
+ primary: true,
447
+ name: col("id")
448
+ },
449
+ name: {
450
+ type: "text",
451
+ name: col("name")
452
+ },
453
+ payload: {
454
+ type: "text",
455
+ nullable: true,
456
+ name: col("payload"),
457
+ transformer: jsonColumnTransformer("buffered.eventPayload")
458
+ },
459
+ publishedAt: {
460
+ type: Date,
461
+ name: col("publishedAt")
462
+ }
463
+ }
464
+ });
411
465
  return [
412
466
  workflowRuns,
413
467
  stepCheckpoints,
414
468
  runAttributes,
415
469
  signalWaiters,
416
- bufferedSignals
470
+ bufferedSignals,
471
+ bufferedEvents
417
472
  ];
418
473
  }
419
474
  __name(durableEntities, "durableEntities");
@@ -440,7 +495,8 @@ var TABLE_TO_ENTITY = {
440
495
  durable_step_checkpoints: StepCheckpointEntity,
441
496
  durable_run_attributes: RunAttributeEntity,
442
497
  durable_signal_waiters: SignalWaiterEntity,
443
- durable_buffered_signals: BufferedSignalEntity
498
+ durable_buffered_signals: BufferedSignalEntity,
499
+ durable_buffered_events: BufferedEventEntity
444
500
  };
445
501
  function durableManagedTables() {
446
502
  return Object.keys(TABLE_TO_ENTITY);
@@ -490,11 +546,13 @@ async function ensureTypeOrmDurableSchema(dataSource) {
490
546
  const runAttributes = q("durable_run_attributes");
491
547
  const waiters = q("durable_signal_waiters");
492
548
  const buffered = q("durable_buffered_signals");
549
+ const bufferedEvents = q("durable_buffered_events");
493
550
  const runsCol = /* @__PURE__ */ __name((property) => q(resolve("durable_workflow_runs", property)), "runsCol");
494
551
  const cpCol = /* @__PURE__ */ __name((property) => q(resolve("durable_step_checkpoints", property)), "cpCol");
495
552
  const attrCol = /* @__PURE__ */ __name((property) => q(resolve("durable_run_attributes", property)), "attrCol");
496
553
  const waiterCol = /* @__PURE__ */ __name((property) => q(resolve("durable_signal_waiters", property)), "waiterCol");
497
554
  const bufCol = /* @__PURE__ */ __name((property) => q(resolve("durable_buffered_signals", property)), "bufCol");
555
+ const bevCol = /* @__PURE__ */ __name((property) => q(resolve("durable_buffered_events", property)), "bevCol");
498
556
  const num = isPg ? "double precision" : isMysql ? "double" : "real";
499
557
  const bufferedId = isSqlite ? `${bufCol("id")} integer PRIMARY KEY AUTOINCREMENT` : isMysql ? `${bufCol("id")} bigint NOT NULL AUTO_INCREMENT PRIMARY KEY` : isPg ? `${bufCol("id")} bigserial PRIMARY KEY` : `${bufCol("id")} bigint NOT NULL AUTO_INCREMENT PRIMARY KEY`;
500
558
  const tables = [
@@ -507,7 +565,7 @@ async function ensureTypeOrmDurableSchema(dataSource) {
507
565
  ${runsCol("wakeAt")} ${ts}, ${runsCol("lockedBy")} ${str}, ${runsCol("lockedUntil")} ${ts},
508
566
  ${runsCol("awaitingDecisionTaskId")} ${str},
509
567
  ${runsCol("recoveryAttempts")} ${int}, ${runsCol("tags")} ${txt}, ${runsCol("searchAttributes")} ${txt},
510
- ${runsCol("priority")} ${int},
568
+ ${runsCol("priority")} ${int}, ${runsCol("origin")} ${str},
511
569
  ${runsCol("createdAt")} ${ts} NOT NULL, ${runsCol("updatedAt")} ${ts} NOT NULL
512
570
  )`,
513
571
  `CREATE TABLE IF NOT EXISTS ${checkpoints} (
@@ -532,6 +590,12 @@ async function ensureTypeOrmDurableSchema(dataSource) {
532
590
  )`,
533
591
  `CREATE TABLE IF NOT EXISTS ${buffered} (
534
592
  ${bufferedId}, ${bufCol("token")} ${str} NOT NULL, ${bufCol("payload")} ${txt}
593
+ )`,
594
+ // Caller-minted uuid PK (engine.publishEvent), not auto-increment — unlike durable_buffered_signals
595
+ // above, removeBufferedEvent needs to target the EXACT id it was buffered with.
596
+ `CREATE TABLE IF NOT EXISTS ${bufferedEvents} (
597
+ ${bevCol("id")} ${str} PRIMARY KEY, ${bevCol("name")} ${str} NOT NULL,
598
+ ${bevCol("payload")} ${txt}, ${bevCol("publishedAt")} ${ts} NOT NULL
535
599
  )`
536
600
  ];
537
601
  const additive = {
@@ -567,6 +631,14 @@ async function ensureTypeOrmDurableSchema(dataSource) {
567
631
  [
568
632
  "priority",
569
633
  int
634
+ ],
635
+ // Nullable and NOT back-filled with a value: every row that predates the column keeps a NULL
636
+ // origin, which the store reads as `undefined` = "unknown origin". There is no honest value to
637
+ // back-fill — the origin is derived from the registration that created the run, which is long
638
+ // gone by the time this ALTER runs.
639
+ [
640
+ "origin",
641
+ str
570
642
  ]
571
643
  ],
572
644
  durable_step_checkpoints: [
@@ -643,6 +715,11 @@ async function ensureTypeOrmDurableSchema(dataSource) {
643
715
  "durable_buffered_signals_token_idx",
644
716
  `${buffered} (${bufCol("token")})`
645
717
  ],
718
+ // buffered events are scanned oldest-first per name — one composite index serves both.
719
+ [
720
+ "durable_buffered_events_name_published_at_idx",
721
+ `${bufferedEvents} (${bevCol("name")}, ${bevCol("publishedAt")})`
722
+ ],
646
723
  // Search-attribute pushdown: equality + range predicates probe by (key, value). Two composite
647
724
  // indexes — one per typed column — so a numeric range or a string equality is an index scan.
648
725
  [
@@ -705,6 +782,9 @@ var TypeOrmStateStore = class {
705
782
  buffered() {
706
783
  return this.dataSource.getRepository(BufferedSignalEntity);
707
784
  }
785
+ bufferedEvents() {
786
+ return this.dataSource.getRepository(BufferedEventEntity);
787
+ }
708
788
  attributes() {
709
789
  return this.dataSource.getRepository(RunAttributeEntity);
710
790
  }
@@ -738,6 +818,7 @@ var TypeOrmStateStore = class {
738
818
  if ("tags" in patch) update.tags = patch.tags ?? null;
739
819
  if ("searchAttributes" in patch) update.searchAttributes = patch.searchAttributes ?? null;
740
820
  if ("priority" in patch) update.priority = patch.priority ?? null;
821
+ if ("origin" in patch) update.origin = patch.origin ?? null;
741
822
  if ("createdAt" in patch) update.createdAt = patch.createdAt;
742
823
  if ("updatedAt" in patch) update.updatedAt = patch.updatedAt;
743
824
  const result = await this.runs().createQueryBuilder().update().set(update).where({
@@ -851,6 +932,9 @@ var TypeOrmStateStore = class {
851
932
  if (query.workflow) qb.andWhere("r.workflow = :workflow", {
852
933
  workflow: query.workflow
853
934
  });
935
+ if (query.origin !== void 0) qb.andWhere("r.origin = :origin", {
936
+ origin: query.origin
937
+ });
854
938
  if (query.status) qb.andWhere("r.status = :status", {
855
939
  status: query.status
856
940
  });
@@ -999,6 +1083,36 @@ var TypeOrmStateStore = class {
999
1083
  payload: e.payload ?? void 0
1000
1084
  };
1001
1085
  }
1086
+ async bufferEvent(input) {
1087
+ await this.bufferedEvents().save({
1088
+ id: input.id,
1089
+ name: input.name,
1090
+ payload: input.payload ?? null,
1091
+ publishedAt: new Date(input.publishedAt)
1092
+ });
1093
+ }
1094
+ async listBufferedEvents(name, limit) {
1095
+ const rows = await this.bufferedEvents().find({
1096
+ where: {
1097
+ name
1098
+ },
1099
+ order: {
1100
+ publishedAt: "ASC"
1101
+ },
1102
+ take: limit
1103
+ });
1104
+ return rows.map((e) => ({
1105
+ id: e.id,
1106
+ payload: e.payload ?? void 0,
1107
+ publishedAt: e.publishedAt.getTime()
1108
+ }));
1109
+ }
1110
+ async removeBufferedEvent(id) {
1111
+ const result = await this.bufferedEvents().delete({
1112
+ id
1113
+ });
1114
+ return result.affected === 1;
1115
+ }
1002
1116
  };
1003
1117
  function toRunEntity(run) {
1004
1118
  return {
@@ -1023,6 +1137,8 @@ function toRunEntity(run) {
1023
1137
  tags: run.tags ?? null,
1024
1138
  searchAttributes: run.searchAttributes ?? null,
1025
1139
  priority: run.priority ?? null,
1140
+ // Absent origin stays SQL NULL — "unknown", never coerced into a real-looking library name.
1141
+ origin: run.origin ?? null,
1026
1142
  createdAt: run.createdAt,
1027
1143
  updatedAt: run.updatedAt
1028
1144
  };
@@ -1045,6 +1161,8 @@ function fromRunEntity(e) {
1045
1161
  tags: e.tags ?? void 0,
1046
1162
  searchAttributes: e.searchAttributes ?? void 0,
1047
1163
  priority: e.priority ?? void 0,
1164
+ // NULL (a row written before the column existed) surfaces as `undefined` = unknown origin.
1165
+ origin: e.origin ?? void 0,
1048
1166
  createdAt: e.createdAt,
1049
1167
  updatedAt: e.updatedAt
1050
1168
  };
@@ -1099,6 +1217,7 @@ function fromCheckpointEntity(e) {
1099
1217
  __name(fromCheckpointEntity, "fromCheckpointEntity");
1100
1218
  // Annotate the CommonJS export names for ESM import in node:
1101
1219
  0 && (module.exports = {
1220
+ BufferedEventEntity,
1102
1221
  BufferedSignalEntity,
1103
1222
  ENTITIES,
1104
1223
  JSON_BLOB_COLUMNS,