@objectstack/service-messaging 10.0.0 → 10.3.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.js CHANGED
@@ -892,6 +892,19 @@ function classifyDeliveryAttempt(result, errorClass, attemptsSoFar, now = Date.n
892
892
  return { success: false, error: result.error, nextAttemptAt: now + delay };
893
893
  }
894
894
 
895
+ // src/audit-timestamp.ts
896
+ function toEpochMs(value) {
897
+ if (typeof value === "number") return value;
898
+ if (value instanceof Date) return value.getTime();
899
+ if (typeof value === "string") {
900
+ const parsed = Date.parse(value);
901
+ if (Number.isFinite(parsed)) return parsed;
902
+ const numeric = Number(value);
903
+ if (Number.isFinite(numeric)) return numeric;
904
+ }
905
+ return 0;
906
+ }
907
+
895
908
  // src/sql-outbox.ts
896
909
  var DELIVERY_OBJECT = "sys_notification_delivery";
897
910
  var SqlNotificationOutbox = class {
@@ -910,7 +923,7 @@ var SqlNotificationOutbox = class {
910
923
  const existing = await this.engine.findOne(this.objectName, { where: dedup, fields: ["id"] });
911
924
  if (existing?.id) return String(existing.id);
912
925
  const id = randomUUID();
913
- const now = Date.now();
926
+ const now = /* @__PURE__ */ new Date();
914
927
  const row = {
915
928
  id,
916
929
  notification_id: input.notificationId,
@@ -1071,8 +1084,8 @@ var SqlNotificationOutbox = class {
1071
1084
  lastAttemptedAt: r.last_attempted_at ?? void 0,
1072
1085
  error: r.error ?? void 0,
1073
1086
  digestKey: r.digest_key ?? void 0,
1074
- createdAt: r.created_at,
1075
- updatedAt: r.updated_at
1087
+ createdAt: toEpochMs(r.created_at),
1088
+ updatedAt: toEpochMs(r.updated_at)
1076
1089
  };
1077
1090
  }
1078
1091
  };
@@ -1201,8 +1214,11 @@ var HttpDelivery = ObjectSchema.create({
1201
1214
  response_code: Field.number({ label: "HTTP Status", required: false }),
1202
1215
  response_body: Field.textarea({ label: "Response Body (capped)", required: false }),
1203
1216
  error: Field.textarea({ label: "Error", required: false }),
1204
- created_at: Field.number({ label: "Created At (ms)", required: true }),
1205
- updated_at: Field.number({ label: "Updated At (ms)", required: true })
1217
+ // Builtin audit columns are native TIMESTAMP columns (Postgres/MySQL),
1218
+ // so declare them `datetime` and write `Date`s (not epoch-ms numbers,
1219
+ // which a real timestamp column rejects). See SqlHttpOutbox.
1220
+ created_at: Field.datetime({ label: "Created At", required: true }),
1221
+ updated_at: Field.datetime({ label: "Updated At", required: true })
1206
1222
  },
1207
1223
  indexes: [
1208
1224
  { fields: ["source", "dedup_key"], unique: true },
@@ -1232,7 +1248,7 @@ var SqlHttpOutbox = class {
1232
1248
  });
1233
1249
  if (existing?.id) return existing.id;
1234
1250
  const id = randomUUID2();
1235
- const now = Date.now();
1251
+ const now = /* @__PURE__ */ new Date();
1236
1252
  const row = {
1237
1253
  id,
1238
1254
  source: input.source,
@@ -1401,8 +1417,8 @@ var SqlHttpOutbox = class {
1401
1417
  responseCode: r.response_code ?? void 0,
1402
1418
  responseBody: r.response_body ?? void 0,
1403
1419
  error: r.error ?? void 0,
1404
- createdAt: r.created_at,
1405
- updatedAt: r.updated_at
1420
+ createdAt: toEpochMs(r.created_at),
1421
+ updatedAt: toEpochMs(r.updated_at)
1406
1422
  };
1407
1423
  }
1408
1424
  };
@@ -1876,10 +1892,10 @@ function stableNodeOffset2(nodeId, partitionCount) {
1876
1892
  // src/retention.ts
1877
1893
  var DEFAULT_NOTIFICATION_RETENTION_DAYS = 90;
1878
1894
  var DEFAULT_RETENTION_TARGETS = [
1879
- { object: RECEIPT_OBJECT, tsField: "created_at", format: "iso" },
1880
- { object: INBOX_OBJECT, tsField: "created_at", format: "iso" },
1881
- { object: DELIVERY_OBJECT, tsField: "created_at", format: "epoch" },
1882
- { object: NOTIFICATION_EVENT_OBJECT, tsField: "created_at", format: "iso" }
1895
+ { object: RECEIPT_OBJECT, tsField: "created_at" },
1896
+ { object: INBOX_OBJECT, tsField: "created_at" },
1897
+ { object: DELIVERY_OBJECT, tsField: "created_at" },
1898
+ { object: NOTIFICATION_EVENT_OBJECT, tsField: "created_at" }
1883
1899
  ];
1884
1900
  var NotificationRetention = class {
1885
1901
  constructor(opts) {
@@ -1902,14 +1918,15 @@ var NotificationRetention = class {
1902
1918
  this.opts.logger.warn(`[messaging] retention: invalid retentionDays=${retentionDays}; prune skipped`);
1903
1919
  return [];
1904
1920
  }
1905
- const cutoffMs = this.now() - retentionDays * 864e5;
1906
- const cutoffIso = new Date(cutoffMs).toISOString();
1921
+ const cutoffIso = new Date(this.now() - retentionDays * 864e5).toISOString();
1907
1922
  const outcomes = [];
1908
1923
  for (const t of this.targets) {
1909
- const cutoff = t.format === "epoch" ? cutoffMs : cutoffIso;
1910
1924
  try {
1911
1925
  const res = await data.delete(t.object, {
1912
- where: { [t.tsField]: { $lt: cutoff } },
1926
+ // ISO-8601 cutoff for every target: `created_at` is a native
1927
+ // timestamp column, which rejects a bare epoch-ms number on
1928
+ // Postgres. The driver coerces this per dialect on the way down.
1929
+ where: { [t.tsField]: { $lt: cutoffIso } },
1913
1930
  multi: true,
1914
1931
  // System context: retention is an operator policy that spans
1915
1932
  // tenants, so it must not be scoped by the caller's RLS.
@@ -2261,8 +2278,12 @@ var NotificationDelivery = ObjectSchema4.create({
2261
2278
  next_attempt_at: Field4.number({ label: "Next Attempt At (ms)" }),
2262
2279
  last_attempted_at: Field4.number({ label: "Last Attempted At (ms)" }),
2263
2280
  error: Field4.textarea({ label: "Error" }),
2264
- created_at: Field4.number({ label: "Created At (ms)", readonly: true }),
2265
- updated_at: Field4.number({ label: "Updated At (ms)" })
2281
+ // Builtin audit columns: the SQL driver provisions `created_at` /
2282
+ // `updated_at` as native TIMESTAMP columns (Postgres/MySQL), so they are
2283
+ // declared `datetime` and written as `Date`s — a bare epoch-ms number is
2284
+ // rejected by a real timestamp column. See SqlNotificationOutbox.
2285
+ created_at: Field4.datetime({ label: "Created At", readonly: true }),
2286
+ updated_at: Field4.datetime({ label: "Updated At" })
2266
2287
  },
2267
2288
  indexes: [
2268
2289
  // Dedup: one delivery per (event, recipient, channel).