@zintrust/core 2.7.1 → 2.7.3

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/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@zintrust/core",
3
- "version": "2.7.1",
3
+ "version": "2.7.3",
4
4
  "description": "Production-grade TypeScript backend framework for JavaScript",
5
5
  "homepage": "https://zintrust.com",
6
6
  "repository": {
@@ -213,16 +213,16 @@
213
213
  "./package.json": "./package.json"
214
214
  },
215
215
  "dependencies": {
216
- "@cloudflare/containers": "^0.3.5",
216
+ "@cloudflare/containers": "^0.3.7",
217
217
  "bcryptjs": "^3.0.3",
218
- "bullmq": "^5.77.6",
218
+ "bullmq": "^5.79.0",
219
219
  "chalk": "^5.6.2",
220
220
  "commander": "^15.0.0",
221
221
  "inquirer": "^14.0.1",
222
- "ioredis": "^5.11.0",
222
+ "ioredis": "^5.11.1",
223
223
  "jsonwebtoken": "^9.0.3",
224
- "mysql2": "^3.22.4",
225
- "pg": "^8.21.0",
224
+ "mysql2": "^3.22.5",
225
+ "pg": "^8.22.0",
226
226
  "redis": "^6.0.0",
227
227
  "tsx": "^4.22.4"
228
228
  },
@@ -234,18 +234,21 @@
234
234
  "node-forge": "^1.4.0",
235
235
  "fast-uri": "3.1.2",
236
236
  "fast-xml-parser": "5.8.0",
237
- "protobufjs": "7.5.9",
237
+ "@babel/core": "^7.29.7",
238
+ "protobufjs": "7.6.4",
238
239
  "picomatch": "^4.0.4",
239
240
  "cross-spawn": "^7.0.5",
240
241
  "glob": "^11.1.0",
241
242
  "minimatch": "^10.2.2",
242
243
  "rollup": "^4.59.0",
243
- "vite": "^8.0.5",
244
+ "vite": "^8.0.16",
244
245
  "flatted": "^3.4.2",
245
246
  "uuid": "14.0.0",
246
- "ioredis": "^5.11.0",
247
+ "ioredis": "^5.11.1",
247
248
  "axios": "^1.16.1",
248
- "tmp": "^0.2.6",
249
+ "form-data": "^4.0.6",
250
+ "js-yaml": "^4.2.0",
251
+ "tmp": "^0.2.7",
249
252
  "sonarqube-scanner": {
250
253
  "axios": "^1.16.1"
251
254
  },
@@ -256,7 +259,7 @@
256
259
  "undici": "^6.24.0"
257
260
  },
258
261
  "miniflare": {
259
- "undici": "^7.24.4"
262
+ "undici": "^7.28.0"
260
263
  },
261
264
  "http-proxy-agent": "7.0.2",
262
265
  "retry-request": "8.0.2",
@@ -265,7 +268,7 @@
265
268
  "braces": "^3.0.3",
266
269
  "lodash": "^4.17.21",
267
270
  "semver": "^7.6.3",
268
- "ws": "^8.20.0",
271
+ "ws": "^8.21.0",
269
272
  "micromatch": "^4.0.8",
270
273
  "brace-expansion": "^5.0.6",
271
274
  "esbuild": "0.28.1",
@@ -1 +1 @@
1
- {"version":3,"file":"KVDriver.d.ts","sourceRoot":"","sources":["../../../../src/cache/drivers/KVDriver.ts"],"names":[],"mappings":"AAAA;;;GAGG;AAEH,OAAO,KAAK,EAAE,WAAW,EAAE,MAAM,oBAAoB,CAAC;AA2DtD;;GAEG;AACH,eAAO,MAAM,QAAQ;kBAtDF,WAAW;EAwD5B,CAAC"}
1
+ {"version":3,"file":"KVDriver.d.ts","sourceRoot":"","sources":["../../../../src/cache/drivers/KVDriver.ts"],"names":[],"mappings":"AAAA;;;GAGG;AAEH,OAAO,KAAK,EAAE,WAAW,EAAE,MAAM,oBAAoB,CAAC;AA0DtD;;GAEG;AACH,eAAO,MAAM,QAAQ;kBArDF,WAAW;EAuD5B,CAAC"}
@@ -9,8 +9,7 @@ import { ErrorFactory } from '../../exceptions/ZintrustError.js';
9
9
  * Create a new KV driver instance
10
10
  */
11
11
  const create = () => {
12
- // In Cloudflare Workers, the KV namespace is usually bound to a variable in the environment
13
- const kv = Cloudflare.getKVBinding('CACHE');
12
+ const kv = Cloudflare.getKVBinding();
14
13
  return {
15
14
  async get(key) {
16
15
  if (kv === null)
@@ -20,7 +19,7 @@ const create = () => {
20
19
  },
21
20
  async set(key, value, ttl) {
22
21
  if (kv === null) {
23
- Logger.warn('KV binding "CACHE" not found. Cache set ignored.');
22
+ Logger.warn('Configured KV binding not found. Cache set ignored.');
24
23
  return;
25
24
  }
26
25
  const options = {};
@@ -40,9 +40,9 @@ const pingKvCache = async (timeoutMs = 2000) => {
40
40
  if (driver !== 'kv')
41
41
  return null;
42
42
  const start = Date.now();
43
- const kv = Cloudflare.getKVBinding('CACHE');
43
+ const kv = Cloudflare.getKVBinding();
44
44
  if (kv === null) {
45
- throw ErrorFactory.createConfigError('KV binding "CACHE" not found');
45
+ throw ErrorFactory.createConfigError('Configured KV binding not found');
46
46
  }
47
47
  const key = `__runtime_health__:kv:${Date.now()}`;
48
48
  await withTimeout('runtime.cache.kv.ping', timeoutMs, async () => {
@@ -1 +1 @@
1
- {"version":3,"file":"FileUploadMiddleware.d.ts","sourceRoot":"","sources":["../../../../src/http/middleware/FileUploadMiddleware.ts"],"names":[],"mappings":"AAAA;;;GAGG;AAaH,OAAO,KAAK,EAAE,UAAU,EAAE,MAAM,6BAA6B,CAAC;AA0H9D;;;GAGG;AACH,eAAO,MAAM,oBAAoB,EAAE,UAsDlC,CAAC;AAEF,eAAe,oBAAoB,CAAC"}
1
+ {"version":3,"file":"FileUploadMiddleware.d.ts","sourceRoot":"","sources":["../../../../src/http/middleware/FileUploadMiddleware.ts"],"names":[],"mappings":"AAAA;;;GAGG;AAaH,OAAO,KAAK,EAAE,UAAU,EAAE,MAAM,6BAA6B,CAAC;AAqJ9D;;;GAGG;AACH,eAAO,MAAM,oBAAoB,EAAE,UAsDlC,CAAC;AAEF,eAAe,oBAAoB,CAAC"}
@@ -49,7 +49,29 @@ const isPipeable = (req) => {
49
49
  * e.g. `doc[reg_cer]` -> `doc.reg_cer`, `doc[reg_cer][file]` -> `doc.reg_cer.file`.
50
50
  * Empty brackets (`files[]`) collapse to the base name (`files`).
51
51
  */
52
- const toDottedName = (name) => name.replaceAll(/\[([^\]]*)\]/g, (_match, inner) => (inner === '' ? '' : `.${inner}`));
52
+ const toDottedName = (name) => {
53
+ let result = '';
54
+ let cursor = 0;
55
+ while (cursor < name.length) {
56
+ const openBracket = name.indexOf('[', cursor);
57
+ if (openBracket === -1) {
58
+ result += name.slice(cursor);
59
+ break;
60
+ }
61
+ result += name.slice(cursor, openBracket);
62
+ const closeBracket = name.indexOf(']', openBracket + 1);
63
+ if (closeBracket === -1) {
64
+ result += name.slice(openBracket);
65
+ break;
66
+ }
67
+ const inner = name.slice(openBracket + 1, closeBracket);
68
+ if (inner !== '') {
69
+ result += `.${inner}`;
70
+ }
71
+ cursor = closeBracket + 1;
72
+ }
73
+ return result;
74
+ };
53
75
  /**
54
76
  * Add dotted-notation aliases for any bracket-notation keys, without removing
55
77
  * the original field names. Existing keys are never overwritten.
package/src/index.js CHANGED
@@ -1,11 +1,11 @@
1
1
  /**
2
- * @zintrust/core v2.7.1
2
+ * @zintrust/core v2.7.3
3
3
  *
4
4
  * ZinTrust Framework - Production-Grade TypeScript Backend
5
5
  * Built for performance, type safety, and exceptional developer experience
6
6
  *
7
7
  * Build Information:
8
- * Built: 2026-06-15T10:44:07.685Z
8
+ * Built: 2026-06-20T09:43:35.633Z
9
9
  * Node: >=20.0.0
10
10
  * License: MIT
11
11
  *
@@ -21,7 +21,7 @@
21
21
  * Available at runtime for debugging and health checks
22
22
  */
23
23
  export const ZINTRUST_VERSION = '0.1.41';
24
- export const ZINTRUST_BUILD_DATE = '2026-06-15T10:44:07.641Z'; // Replaced during build
24
+ export const ZINTRUST_BUILD_DATE = '2026-06-20T09:43:35.558Z'; // Replaced during build
25
25
  export { Application } from './boot/Application.js';
26
26
  export { AwsSigV4 } from './common/index.js';
27
27
  export { SignedRequest } from './security/SignedRequest.js';
@@ -1 +1 @@
1
- {"version":3,"file":"QueryBuilder.d.ts","sourceRoot":"","sources":["../../../src/orm/QueryBuilder.ts"],"names":[],"mappings":"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"}
1
+ {"version":3,"file":"QueryBuilder.d.ts","sourceRoot":"","sources":["../../../src/orm/QueryBuilder.ts"],"names":[],"mappings":"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"}
@@ -382,14 +382,30 @@ const buildLimitOffsetClause = (limit, offset) => {
382
382
  }
383
383
  return sql;
384
384
  };
385
+ // Matches `left OP right` where both sides are identifier paths (e.g.
386
+ // `users.id = profiles.user_id`). Operator alternation lists the two-char
387
+ // operators before their single-char prefixes so `<=`/`>=`/`<>` win the match.
388
+ const JOIN_CONDITION = /^([A-Za-z_]\w*(?:\.[A-Za-z_]\w*)*)\s*(=|!=|<>|<=|>=|<|>)\s*([A-Za-z_]\w*(?:\.[A-Za-z_]\w*)*)$/;
389
+ const buildJoinClause = (joins, dialect) => joins
390
+ .map(({ table, on, type }) => {
391
+ assertSafeIdentifierPath(table, 'join table');
392
+ const match = JOIN_CONDITION.exec(on.trim());
393
+ if (!match) {
394
+ throw ErrorFactory.createDatabaseError('Unsafe SQL join condition');
395
+ }
396
+ const [, left, op, right] = match;
397
+ return ` ${type} JOIN ${escapeIdentifier(table, dialect)} ON ${escapeIdentifier(left, dialect)} ${op} ${escapeIdentifier(right, dialect)}`;
398
+ })
399
+ .join('');
385
400
  const buildSelectQuery = (state) => {
386
401
  if (state.tableName.length > 0) {
387
402
  assertSafeIdentifierPath(state.tableName, 'table name');
388
403
  }
389
404
  const columns = buildSelectClause(state.selectColumns, state.dialect);
390
405
  const fromClause = state.tableName.length > 0 ? ` FROM ${escapeIdentifier(state.tableName, state.dialect)}` : '';
406
+ const joinClause = buildJoinClause(state.joins, state.dialect);
391
407
  const where = compileWhere(getEffectiveWhereConditions(state), state.dialect);
392
- const sql = `SELECT ${columns}${fromClause}${where.sql}${buildOrderByClause(state.orderByClauses, state.randomOrder, state.dialect)}${buildLimitOffsetClause(state.limitValue, state.offsetValue)}`;
408
+ const sql = `SELECT ${columns}${fromClause}${joinClause}${where.sql}${buildOrderByClause(state.orderByClauses, state.randomOrder, state.dialect)}${buildLimitOffsetClause(state.limitValue, state.offsetValue)}`;
393
409
  return { sql, parameters: where.parameters };
394
410
  };
395
411
  const buildCountQuery = (state) => {
@@ -706,10 +722,13 @@ function attachSoftDeleteMethods(builder, state) {
706
722
  }
707
723
  function attachJoinOrderPagingMethods(builder, state) {
708
724
  builder.join = (tableJoin, on) => {
709
- state.joins.push({ table: tableJoin, on });
725
+ state.joins.push({ table: tableJoin, on, type: 'INNER' });
726
+ return builder;
727
+ };
728
+ builder.leftJoin = (tableJoin, on) => {
729
+ state.joins.push({ table: tableJoin, on, type: 'LEFT' });
710
730
  return builder;
711
731
  };
712
- builder.leftJoin = (tableJoin, on) => builder.join(tableJoin, on);
713
732
  builder.orderBy = (column, direction = 'ASC') => {
714
733
  applyOrderByClause(state, column, direction);
715
734
  return builder;
@@ -1 +1 @@
1
- {"version":3,"file":"Broadcast.d.ts","sourceRoot":"","sources":["../../../../src/tools/broadcast/Broadcast.ts"],"names":[],"mappings":"AAQA,OAAO,KAAK,EAAE,0BAA0B,EAAE,MAAM,cAAc,CAAC;AAE/D,OAAO,KAAK,EAAE,QAAQ,EAAE,MAAM,eAAe,CAAC;AAE9C,KAAK,WAAW,GAAG,QAAQ,CAAC;IAC1B,IAAI,EAAE,CAAC,OAAO,EAAE,MAAM,EAAE,KAAK,EAAE,MAAM,EAAE,IAAI,EAAE,OAAO,KAAK,OAAO,CAAC,OAAO,CAAC,CAAC;IAC1E,OAAO,EAAE,CAAC,KAAK,EAAE,qBAAqB,KAAK,OAAO,CAAC,sBAAsB,CAAC,CAAC;CAC5E,CAAC,CAAC;AAEH,KAAK,qBAAqB,GAAG,QAAQ,GAAG,SAAS,GAAG,UAAU,GAAG,YAAY,CAAC;AAC9E,KAAK,qBAAqB,GAAG,MAAM,GAAG,QAAQ,GAAG,QAAQ,CAAC;AAC1D,KAAK,kBAAkB,GAAG,eAAe,GAAG,QAAQ,GAAG,QAAQ,CAAC;AAShE,MAAM,MAAM,qBAAqB,GAAG,QAAQ,CAAC;IAC3C,OAAO,CAAC,EAAE,MAAM,CAAC;IACjB,QAAQ,CAAC,EAAE,SAAS,MAAM,EAAE,CAAC;IAC7B,KAAK,CAAC,EAAE,qBAAqB,CAAC;IAC9B,YAAY,CAAC,EAAE,qBAAqB,CAAC;IACrC,KAAK,CAAC,EAAE,MAAM,CAAC;IACf,IAAI,CAAC,EAAE,MAAM,CAAC;IACd,IAAI,CAAC,EAAE,OAAO,CAAC;IACf,QAAQ,CAAC,EAAE,MAAM,CAAC;IAClB,QAAQ,CAAC,EAAE,qBAAqB,CAAC;IACjC,WAAW,CAAC,EAAE,MAAM,CAAC;IACrB,OAAO,CAAC,EAAE,QAAQ,CAAC;IACnB,IAAI,CAAC,EAAE,OAAO,CAAC;CAChB,CAAC,CAAC;AA0BH,MAAM,MAAM,sBAAsB,GAAG,QAAQ,CAAC;IAC5C,EAAE,EAAE,IAAI,CAAC;IACT,SAAS,EAAE,kBAAkB,CAAC;IAC9B,QAAQ,EAAE,SAAS,MAAM,EAAE,CAAC;IAC5B,KAAK,EAAE,MAAM,CAAC;IACd,UAAU,CAAC,EAAE,MAAM,CAAC;IACpB,MAAM,CAAC,EAAE,0BAA0B,CAAC,QAAQ,CAAC,CAAC;IAC9C,WAAW,CAAC,EAAE,MAAM,CAAC;IACrB,QAAQ,CAAC,EAAE,MAAM,CAAC;IAClB,mBAAmB,CAAC,EAAE,SAAS,kBAAkB,EAAE,CAAC;IACpD,MAAM,CAAC,EAAE,OAAO,CAAC;IACjB,OAAO,CAAC,EAAE,SAAS,OAAO,EAAE,CAAC;CAC9B,CAAC,CAAC;AA4yBH,eAAO,MAAM,SAAS;mBACC,qBAAqB,GAAG,OAAO,CAAC,sBAAsB,CAAC;kBAIxD,MAAM,SAAS,MAAM,QAAQ,OAAO;0BAU5B,MAAM,SAAS,MAAM,QAAQ,OAAO;wBAKvD,qBAAqB,YACnB;QAAE,SAAS,CAAC,EAAE,MAAM,CAAC;QAAC,SAAS,CAAC,EAAE,MAAM,CAAA;KAAE;4BAO1C,MAAM,SACR,MAAM,QACP,OAAO,YACJ;QAAE,SAAS,CAAC,EAAE,MAAM,CAAC;QAAC,SAAS,CAAC,EAAE,MAAM,CAAA;KAAE;qBAKpC,MAAM;8BAES,qBAAqB;kCAEjB,MAAM,SAAS,MAAM,QAAQ,OAAO;;uBAKrD,MAAM,GAAG,WAAW;EAmBvC,CAAC;AAEH,eAAe,SAAS,CAAC"}
1
+ {"version":3,"file":"Broadcast.d.ts","sourceRoot":"","sources":["../../../../src/tools/broadcast/Broadcast.ts"],"names":[],"mappings":"AASA,OAAO,KAAK,EAAE,0BAA0B,EAAE,MAAM,cAAc,CAAC;AAE/D,OAAO,KAAK,EAAE,QAAQ,EAAE,MAAM,eAAe,CAAC;AAE9C,KAAK,WAAW,GAAG,QAAQ,CAAC;IAC1B,IAAI,EAAE,CAAC,OAAO,EAAE,MAAM,EAAE,KAAK,EAAE,MAAM,EAAE,IAAI,EAAE,OAAO,KAAK,OAAO,CAAC,OAAO,CAAC,CAAC;IAC1E,OAAO,EAAE,CAAC,KAAK,EAAE,qBAAqB,KAAK,OAAO,CAAC,sBAAsB,CAAC,CAAC;CAC5E,CAAC,CAAC;AAEH,KAAK,qBAAqB,GAAG,QAAQ,GAAG,SAAS,GAAG,UAAU,GAAG,YAAY,CAAC;AAC9E,KAAK,qBAAqB,GAAG,MAAM,GAAG,QAAQ,GAAG,QAAQ,CAAC;AAC1D,KAAK,kBAAkB,GAAG,eAAe,GAAG,QAAQ,GAAG,QAAQ,CAAC;AAShE,MAAM,MAAM,qBAAqB,GAAG,QAAQ,CAAC;IAC3C,OAAO,CAAC,EAAE,MAAM,CAAC;IACjB,QAAQ,CAAC,EAAE,SAAS,MAAM,EAAE,CAAC;IAC7B,KAAK,CAAC,EAAE,qBAAqB,CAAC;IAC9B,YAAY,CAAC,EAAE,qBAAqB,CAAC;IACrC,KAAK,CAAC,EAAE,MAAM,CAAC;IACf,IAAI,CAAC,EAAE,MAAM,CAAC;IACd,IAAI,CAAC,EAAE,OAAO,CAAC;IACf,QAAQ,CAAC,EAAE,MAAM,CAAC;IAClB,QAAQ,CAAC,EAAE,qBAAqB,CAAC;IACjC,WAAW,CAAC,EAAE,MAAM,CAAC;IACrB,OAAO,CAAC,EAAE,QAAQ,CAAC;IACnB,IAAI,CAAC,EAAE,OAAO,CAAC;CAChB,CAAC,CAAC;AA0BH,MAAM,MAAM,sBAAsB,GAAG,QAAQ,CAAC;IAC5C,EAAE,EAAE,IAAI,CAAC;IACT,SAAS,EAAE,kBAAkB,CAAC;IAC9B,QAAQ,EAAE,SAAS,MAAM,EAAE,CAAC;IAC5B,KAAK,EAAE,MAAM,CAAC;IACd,UAAU,CAAC,EAAE,MAAM,CAAC;IACpB,MAAM,CAAC,EAAE,0BAA0B,CAAC,QAAQ,CAAC,CAAC;IAC9C,WAAW,CAAC,EAAE,MAAM,CAAC;IACrB,QAAQ,CAAC,EAAE,MAAM,CAAC;IAClB,mBAAmB,CAAC,EAAE,SAAS,kBAAkB,EAAE,CAAC;IACpD,MAAM,CAAC,EAAE,OAAO,CAAC;IACjB,OAAO,CAAC,EAAE,SAAS,OAAO,EAAE,CAAC;CAC9B,CAAC,CAAC;AAs3BH,eAAO,MAAM,SAAS;mBACC,qBAAqB,GAAG,OAAO,CAAC,sBAAsB,CAAC;kBAIxD,MAAM,SAAS,MAAM,QAAQ,OAAO;0BAU5B,MAAM,SAAS,MAAM,QAAQ,OAAO;wBAKvD,qBAAqB,YACnB;QAAE,SAAS,CAAC,EAAE,MAAM,CAAC;QAAC,SAAS,CAAC,EAAE,MAAM,CAAA;KAAE;4BAO1C,MAAM,SACR,MAAM,QACP,OAAO,YACJ;QAAE,SAAS,CAAC,EAAE,MAAM,CAAC;QAAC,SAAS,CAAC,EAAE,MAAM,CAAA;KAAE;qBAKpC,MAAM;8BAES,qBAAqB;kCAEjB,MAAM,SAAS,MAAM,QAAQ,OAAO;;uBAKrD,MAAM,GAAG,WAAW;EAmBvC,CAAC;AAEH,eAAe,SAAS,CAAC"}
@@ -3,6 +3,7 @@ import { InMemoryDriver } from './drivers/InMemory.js';
3
3
  import { PusherDriver } from './drivers/Pusher.js';
4
4
  import { RedisDriver } from './drivers/Redis.js';
5
5
  import { RedisHttpsDriver } from './drivers/RedisHttps.js';
6
+ import { delay } from '../../common/index.js';
6
7
  import broadcastConfig from '../../config/broadcast.js';
7
8
  import { Env } from '../../config/env.js';
8
9
  import { Logger } from '../../config/logger.js';
@@ -15,6 +16,25 @@ const BROADCAST_CHANNEL_SCOPES = new Set([
15
16
  ]);
16
17
  const INTERNAL_SOCKET_SECRET_HEADER = 'x-zintrust-socket-secret';
17
18
  const DEFAULT_BROADCAST_EVENTS_PATH_TEMPLATE = '/apps/{appId}/events';
19
+ // A POST that returns one of these never completed at the application origin, so
20
+ // re-sending it cannot duplicate a delivered event. 520-524 are the edge->origin
21
+ // (e.g. Cloudflare) statuses: a 522 means the edge could not connect to the origin,
22
+ // not that the broadcast was processed. Genuine application responses (2xx and 4xx
23
+ // such as 401/403/422) reached the origin and are never retried.
24
+ const TRANSIENT_PUBLISH_STATUSES = new Set([
25
+ 408, 425, 429, 500, 502, 503, 504, 520, 521, 522, 523, 524,
26
+ ]);
27
+ const resolveInternalPublishRetryConfig = () => ({
28
+ maxAttempts: Math.max(1, Env.getInt('BROADCAST_INTERNAL_PUBLISH_RETRIES', 3)),
29
+ baseDelayMs: Math.max(0, Env.getInt('BROADCAST_INTERNAL_PUBLISH_RETRY_BASE_MS', 200)),
30
+ });
31
+ // exponential backoff + full jitter
32
+ const computeRetryDelayMs = (baseDelayMs, attempt) => {
33
+ const exponential = baseDelayMs * Math.pow(2, attempt - 1);
34
+ const num = Math.random(); // NOSONAR
35
+ const jitter = baseDelayMs === 0 ? 0 : Math.floor(num * baseDelayMs);
36
+ return exponential + jitter;
37
+ };
18
38
  const pickFirstNonEmpty = (...values) => {
19
39
  for (const value of values) {
20
40
  if (value.trim() !== '') {
@@ -224,7 +244,7 @@ const logTransportFallback = (transport, details) => {
224
244
  ...details,
225
245
  });
226
246
  };
227
- const requestInternalPublishEndpoint = async (endpoint, secret, payload) => {
247
+ const attemptInternalPublishEndpoint = async (endpoint, secret, payload) => {
228
248
  try {
229
249
  const response = await tracedFetch(endpoint, {
230
250
  method: 'POST',
@@ -251,7 +271,12 @@ const requestInternalPublishEndpoint = async (endpoint, secret, payload) => {
251
271
  status: response.status,
252
272
  body: responseBody,
253
273
  });
254
- return { result: null, error };
274
+ return {
275
+ result: null,
276
+ error,
277
+ status: response.status,
278
+ transient: TRANSIENT_PUBLISH_STATUSES.has(response.status),
279
+ };
255
280
  }
256
281
  const resolvedChannels = isObject(responseBody) && isArray(responseBody['channels'])
257
282
  ? responseBody['channels'].filter(isNonEmptyString).map((channel) => channel.trim())
@@ -276,8 +301,34 @@ const requestInternalPublishEndpoint = async (endpoint, secret, payload) => {
276
301
  endpoint,
277
302
  error: describeError(error),
278
303
  });
279
- return { result: null, error };
280
- }
304
+ // A thrown error means the POST never completed at the application origin, so
305
+ // it is safe to retry.
306
+ return { result: null, error, transient: true };
307
+ }
308
+ };
309
+ const requestInternalPublishEndpoint = async (endpoint, secret, payload, attempt = 1, retryConfig) => {
310
+ const { maxAttempts, baseDelayMs } = retryConfig ?? resolveInternalPublishRetryConfig();
311
+ const result = await attemptInternalPublishEndpoint(endpoint, secret, payload);
312
+ if (result.result !== null) {
313
+ return result;
314
+ }
315
+ // Non-transient failures (application 4xx, etc.) reached the origin; do not retry.
316
+ if (result.transient !== true || attempt >= maxAttempts) {
317
+ return result;
318
+ }
319
+ const delayMs = computeRetryDelayMs(baseDelayMs, attempt);
320
+ Logger.warn('Broadcast internal publish retrying transient failure.', {
321
+ endpoint,
322
+ attempt,
323
+ maxAttempts,
324
+ delayMs,
325
+ status: result.status,
326
+ });
327
+ await delay(delayMs);
328
+ return requestInternalPublishEndpoint(endpoint, secret, payload, attempt + 1, {
329
+ maxAttempts,
330
+ baseDelayMs,
331
+ });
281
332
  };
282
333
  const tryInternalPublishEndpoints = async (endpoints, secret, payload, index = 0, lastError) => {
283
334
  const endpoint = endpoints[index];