@objectstack/plugin-webhooks 17.2.0 → 17.4.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/CHANGELOG.md +794 -0
- package/dist/{chunk-DRHJ2M45.cjs → chunk-CWE6CIEZ.cjs} +1 -1
- package/dist/chunk-CWE6CIEZ.cjs.map +1 -0
- package/dist/{chunk-XERWWQKN.js → chunk-MEX2VC7T.js} +1 -1
- package/dist/chunk-MEX2VC7T.js.map +1 -0
- package/dist/index.cjs +202 -82
- package/dist/index.cjs.map +1 -1
- package/dist/index.d.cts +105 -2
- package/dist/index.d.ts +105 -2
- package/dist/index.js +144 -24
- package/dist/index.js.map +1 -1
- package/dist/schema.cjs +2 -2
- package/dist/schema.d.cts +357 -249
- package/dist/schema.d.ts +357 -249
- package/dist/schema.js +1 -1
- package/dist/schema.js.map +1 -1
- package/dist/{translations-IAKF6NAP.js → translations-MNRJO53N.js} +46 -10
- package/dist/translations-MNRJO53N.js.map +1 -0
- package/dist/{translations-IHRALWSP.cjs → translations-VX3ONQXN.cjs} +47 -11
- package/dist/translations-VX3ONQXN.cjs.map +1 -0
- package/package.json +27 -14
- package/dist/chunk-DRHJ2M45.cjs.map +0 -1
- package/dist/chunk-XERWWQKN.js.map +0 -1
- package/dist/translations-IAKF6NAP.js.map +0 -1
- package/dist/translations-IHRALWSP.cjs.map +0 -1
package/dist/index.cjs
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
"use strict";Object.defineProperty(exports, "__esModule", {value: true}); function _interopRequireWildcard(obj) { if (obj && obj.__esModule) { return obj; } else { var newObj = {}; if (obj != null) { for (var key in obj) { if (Object.prototype.hasOwnProperty.call(obj, key)) { newObj[key] = obj[key]; } } } newObj.default = obj; return newObj; } } function _nullishCoalesce(lhs, rhsFn) { if (lhs != null) { return lhs; } else { return rhsFn(); } } function _optionalChain(ops) { let lastAccessLHS = undefined; let value = ops[0]; let i = 1; while (i < ops.length) { const op = ops[i]; const fn = ops[i + 1]; i += 2; if ((op === 'optionalAccess' || op === 'optionalCall') && value == null) { return undefined; } if (op === 'access' || op === 'optionalAccess') { lastAccessLHS = value; value = fn(value); } else if (op === 'call' || op === 'optionalCall') { value = fn((...args) => value.call(lastAccessLHS, ...args)); lastAccessLHS = undefined; } } return value; }
|
|
2
2
|
|
|
3
|
-
var
|
|
3
|
+
var _chunkCWE6CIEZcjs = require('./chunk-CWE6CIEZ.cjs');
|
|
4
4
|
|
|
5
5
|
// src/webhook-secret.ts
|
|
6
6
|
var WEBHOOK_SECRET_FIELD = "signing_secret";
|
|
@@ -192,6 +192,17 @@ var AutoEnqueuer = class {
|
|
|
192
192
|
* refresh, forever.
|
|
193
193
|
*/
|
|
194
194
|
this.droppedForSecret = /* @__PURE__ */ new Set();
|
|
195
|
+
/**
|
|
196
|
+
* [#13566] Webhook ids whose FIRST organization-dimension refusal has been
|
|
197
|
+
* said out loud (see {@link admitsOrganization}). Same say-once shape as
|
|
198
|
+
* {@link droppedForSecret}, for the same reason: a subscription that
|
|
199
|
+
* cannot receive a class of events must be reported once, with the
|
|
200
|
+
* remedy, and not once per event forever — an org-less `'*'` subscription
|
|
201
|
+
* on a walled deployment would otherwise warn on every write of every
|
|
202
|
+
* organization. Pruned on refresh to the rows still live, so a row that
|
|
203
|
+
* is deleted and re-created reports again.
|
|
204
|
+
*/
|
|
205
|
+
this.organizationRefusalReported = /* @__PURE__ */ new Set();
|
|
195
206
|
this.subscriptionsObject = _nullishCoalesce(opts.subscriptionsObject, () => ( "sys_webhook"));
|
|
196
207
|
this.refreshIntervalMs = _nullishCoalesce(opts.refreshIntervalMs, () => ( 6e4));
|
|
197
208
|
this.logger = opts.logger;
|
|
@@ -294,11 +305,14 @@ var AutoEnqueuer = class {
|
|
|
294
305
|
}
|
|
295
306
|
this.subscriptions.clear();
|
|
296
307
|
for (const [k, v] of next) this.subscriptions.set(k, v);
|
|
297
|
-
if (this.droppedForSecret.size > 0) {
|
|
308
|
+
if (this.droppedForSecret.size > 0 || this.organizationRefusalReported.size > 0) {
|
|
298
309
|
const live = new Set(rows.map((r) => String(_optionalChain([r, 'optionalAccess', _21 => _21.id]))));
|
|
299
310
|
for (const id of this.droppedForSecret) {
|
|
300
311
|
if (!live.has(id)) this.droppedForSecret.delete(id);
|
|
301
312
|
}
|
|
313
|
+
for (const id of this.organizationRefusalReported) {
|
|
314
|
+
if (!live.has(id)) this.organizationRefusalReported.delete(id);
|
|
315
|
+
}
|
|
302
316
|
}
|
|
303
317
|
_optionalChain([this, 'access', _22 => _22.logger, 'optionalAccess', _23 => _23.debug, 'optionalCall', _24 => _24("[webhook-auto-enqueuer] cache refreshed", {
|
|
304
318
|
objects: this.subscriptions.size,
|
|
@@ -596,7 +610,11 @@ var AutoEnqueuer = class {
|
|
|
596
610
|
// `headers` and `secret` are both filled by attachCredentials()
|
|
597
611
|
// from their encrypted columns, NOT read off the row — see #7799
|
|
598
612
|
// (secret) and #7986 (headers).
|
|
599
|
-
timeoutMs: defn.timeoutMs
|
|
613
|
+
timeoutMs: defn.timeoutMs,
|
|
614
|
+
// [#13546] The tenant column the kernel provisions on sys_webhook.
|
|
615
|
+
// This cache read is a dispatcher-side unscoped find, so the column
|
|
616
|
+
// comes back for every organization's rows.
|
|
617
|
+
organizationId: row.organization_id ? String(row.organization_id) : void 0
|
|
600
618
|
};
|
|
601
619
|
}
|
|
602
620
|
/**
|
|
@@ -631,9 +649,18 @@ var AutoEnqueuer = class {
|
|
|
631
649
|
)]);
|
|
632
650
|
return;
|
|
633
651
|
}
|
|
652
|
+
const organization = readEventOrganizationId(payload);
|
|
653
|
+
if (!organization) {
|
|
654
|
+
_optionalChain([this, 'access', _75 => _75.logger, 'optionalAccess', _76 => _76.warn, 'optionalCall', _77 => _77(
|
|
655
|
+
'[webhook-auto-enqueuer] dropping off-contract data event: `organizationId` is present but not a non-empty string (DataEventSchema refuses that at the publish site) \u2014 fix the producer; never coerced and never read as "no organization"',
|
|
656
|
+
{ type: event.type, object: event.object }
|
|
657
|
+
)]);
|
|
658
|
+
return;
|
|
659
|
+
}
|
|
634
660
|
const eventId = `${event.object}:${recordId}:${action}:${event.timestamp}`;
|
|
635
661
|
for (const sub of subs) {
|
|
636
662
|
if (!sub.triggers.has(trigger)) continue;
|
|
663
|
+
if (!this.admitsOrganization(sub, organization.organizationId, event)) continue;
|
|
637
664
|
void this.enqueue({
|
|
638
665
|
source: "webhook",
|
|
639
666
|
refId: sub.id,
|
|
@@ -650,6 +677,12 @@ var AutoEnqueuer = class {
|
|
|
650
677
|
// subscription, so the delivery path is byte-identical to before.
|
|
651
678
|
undeliverableReason: sub.parkedReason,
|
|
652
679
|
timeoutMs: sub.timeoutMs,
|
|
680
|
+
// [#13546] The delivery row belongs to the SUBSCRIPTION's
|
|
681
|
+
// organization — the one honest tenant in scope on this
|
|
682
|
+
// fire-and-forget path (no request context exists here).
|
|
683
|
+
// Absent for an org-less subscription; the row then lands
|
|
684
|
+
// NULL, the global-row shape.
|
|
685
|
+
organizationId: sub.organizationId,
|
|
653
686
|
// [#3946] Envelope keys are written LAST so the event payload
|
|
654
687
|
// cannot rewrite them. Behaviour-neutral for the engine's own
|
|
655
688
|
// publishers — since #4626 a `data.record.*` payload is a
|
|
@@ -694,7 +727,7 @@ var AutoEnqueuer = class {
|
|
|
694
727
|
const payload = _nullishCoalesce(event.payload, () => ( {}));
|
|
695
728
|
const matched = payload.matched;
|
|
696
729
|
if (typeof matched !== "number" || !Number.isInteger(matched) || matched < 0) {
|
|
697
|
-
_optionalChain([this, 'access',
|
|
730
|
+
_optionalChain([this, 'access', _78 => _78.logger, 'optionalAccess', _79 => _79.warn, 'optionalCall', _80 => _80(
|
|
698
731
|
"[webhook-auto-enqueuer] dropping off-contract bulk data event: payload is not a BulkDataEvent (no top-level non-negative integer `matched`) \u2014 fix the producer",
|
|
699
732
|
{ type: event.type, object: event.object }
|
|
700
733
|
)]);
|
|
@@ -702,15 +735,24 @@ var AutoEnqueuer = class {
|
|
|
702
735
|
}
|
|
703
736
|
const eventUuid = payload.id;
|
|
704
737
|
if (typeof eventUuid !== "string" || eventUuid === "") {
|
|
705
|
-
_optionalChain([this, 'access',
|
|
738
|
+
_optionalChain([this, 'access', _81 => _81.logger, 'optionalAccess', _82 => _82.warn, 'optionalCall', _83 => _83(
|
|
706
739
|
"[webhook-auto-enqueuer] dropping off-contract bulk data event: payload has no top-level string `id` to dedup on \u2014 fix the producer",
|
|
707
740
|
{ type: event.type, object: event.object }
|
|
708
741
|
)]);
|
|
709
742
|
return;
|
|
710
743
|
}
|
|
711
744
|
const eventId = `${event.object}:${event.type}:${eventUuid}`;
|
|
745
|
+
const organization = readEventOrganizationId(payload);
|
|
746
|
+
if (!organization) {
|
|
747
|
+
_optionalChain([this, 'access', _84 => _84.logger, 'optionalAccess', _85 => _85.warn, 'optionalCall', _86 => _86(
|
|
748
|
+
'[webhook-auto-enqueuer] dropping off-contract bulk data event: `organizationId` is present but not a non-empty string (BulkDataEventSchema refuses that at the publish site) \u2014 fix the producer; never coerced and never read as "not asserted"',
|
|
749
|
+
{ type: event.type, object: event.object }
|
|
750
|
+
)]);
|
|
751
|
+
return;
|
|
752
|
+
}
|
|
712
753
|
for (const sub of subs) {
|
|
713
754
|
if (!sub.triggers.has(trigger)) continue;
|
|
755
|
+
if (!this.admitsOrganization(sub, organization.organizationId, event)) continue;
|
|
714
756
|
void this.enqueue({
|
|
715
757
|
source: "webhook",
|
|
716
758
|
refId: sub.id,
|
|
@@ -724,6 +766,9 @@ var AutoEnqueuer = class {
|
|
|
724
766
|
// an undeliverable row instead of enqueuing a delivery.
|
|
725
767
|
undeliverableReason: sub.parkedReason,
|
|
726
768
|
timeoutMs: sub.timeoutMs,
|
|
769
|
+
// [#13546] See the per-record path — the subscription's own
|
|
770
|
+
// organization, absent for an org-less subscription.
|
|
771
|
+
organizationId: sub.organizationId,
|
|
727
772
|
// [#3946] Envelope keys last so the payload cannot rewrite them.
|
|
728
773
|
payload: {
|
|
729
774
|
...payload,
|
|
@@ -735,11 +780,96 @@ var AutoEnqueuer = class {
|
|
|
735
780
|
}).catch((err) => this.reportWriteFailure(sub, eventId, err, "bulk enqueue"));
|
|
736
781
|
}
|
|
737
782
|
}
|
|
783
|
+
/**
|
|
784
|
+
* [#13566] The organization dimension of the match — ONE comparison
|
|
785
|
+
* between the subscription's own organization (cached off its
|
|
786
|
+
* `sys_webhook` row, #13546) and the organization the producer stamped on
|
|
787
|
+
* the event (#14970 per record; #15225 / #15813 per batch). ⛔ No lookup:
|
|
788
|
+
* the enqueuer exists to keep this path O(1), and both halves are already
|
|
789
|
+
* in hand — the filter is a comparison, never a resolution.
|
|
790
|
+
*
|
|
791
|
+
* The cells, and why each falls where it does:
|
|
792
|
+
*
|
|
793
|
+
* | subscription | event | verdict |
|
|
794
|
+
* |--------------|--------|------------------------------------------------|
|
|
795
|
+
* | org A | org A | deliver |
|
|
796
|
+
* | org A | org B | not a match — the routine outcome of the new |
|
|
797
|
+
* | | | term, silent like an object-name mismatch |
|
|
798
|
+
* | org A | absent | REFUSE (fail-closed), said once per sub |
|
|
799
|
+
* | none | org A | REFUSE, said once per sub — the ruling's case |
|
|
800
|
+
* | none | absent | deliver — no wall on either side |
|
|
801
|
+
*
|
|
802
|
+
* **`none` × `org A` — the ruling.** A `sys_webhook` row with no
|
|
803
|
+
* organization on a walled deployment (a package-declared row bootstrapped
|
|
804
|
+
* under `isSystem`, a row authored before the column was provisioned)
|
|
805
|
+
* would otherwise receive EVERY organization's records at its URL, signed
|
|
806
|
+
* with its secret — the leak this card is. Maintainer's ruling
|
|
807
|
+
* (2026-09-07), verbatim: *a subscription with no organisation ownership
|
|
808
|
+
* does not fan out — loud refusal, never a silent cross-organisation
|
|
809
|
+
* delivery.* ADR-0131 D1 is why there is no third reading — NULL is not a
|
|
810
|
+
* state, so "no organization" is never "every organization".
|
|
811
|
+
*
|
|
812
|
+
* **`org A` × `absent` — fail-closed, on BOTH paths.** The two event
|
|
813
|
+
* families spell absence with the same key and mean different things by
|
|
814
|
+
* it (`packages/spec/src/api/events.zod.ts`, both members' docs). On a
|
|
815
|
+
* `DataEvent` it is "this record belongs to no organization" — an
|
|
816
|
+
* environment-wide row, an object outside the wall, or (the per-record
|
|
817
|
+
* producer's own docblock, `eventOrganizationId` in
|
|
818
|
+
* `packages/objectql/src/engine.ts`) no row in hand at the publish site,
|
|
819
|
+
* published absent rather than substituting the caller's organization.
|
|
820
|
+
* On a `BulkDataEvent` it is "the producer did not assert one
|
|
821
|
+
* organization for this batch" — a system or cross-membership predicate
|
|
822
|
+
* write — and the contract says outright that a tenant-scoped consumer
|
|
823
|
+
* must not deliver it inside an organization wall. Neither reading names
|
|
824
|
+
* organization A, so a subscription that belongs to A delivers on
|
|
825
|
+
* neither. ⛔ Absent is never "no tenancy concern": delivering on it
|
|
826
|
+
* would turn each of those cases into a cross-organization delivery. The
|
|
827
|
+
* cost is an environment-wide record not reaching an organization's
|
|
828
|
+
* webhook — accepted, and said once so the subscription is not dead while
|
|
829
|
+
* looking armed.
|
|
830
|
+
*
|
|
831
|
+
* **`none` × `absent` — deliver.** A `single`-posture deployment stamps
|
|
832
|
+
* nothing on either side (`postureStampsOrganization` is false there), so
|
|
833
|
+
* this cell is every event on every non-walled install; on a walled one
|
|
834
|
+
* it is an environment-wide subscription taking an environment-wide
|
|
835
|
+
* event. No organization is named anywhere, so there is no wall to cross.
|
|
836
|
+
*
|
|
837
|
+
* Both refusals are said ONCE per subscription (the #8022 say-once rule,
|
|
838
|
+
* ledger {@link organizationRefusalReported}): the first refused event is
|
|
839
|
+
* a `warn` naming the consequence and the remedy, later ones are
|
|
840
|
+
* debug-level. Without that a refused subscription reads active:true in
|
|
841
|
+
* Setup with nothing ever arriving — the "dead while looking armed" shape
|
|
842
|
+
* ADR-0078 refuses.
|
|
843
|
+
*/
|
|
844
|
+
admitsOrganization(sub, eventOrganizationId, event) {
|
|
845
|
+
if (sub.organizationId === eventOrganizationId) return true;
|
|
846
|
+
if (sub.organizationId !== void 0 && eventOrganizationId !== void 0) return false;
|
|
847
|
+
const orgless = sub.organizationId === void 0;
|
|
848
|
+
const meta = {
|
|
849
|
+
id: sub.id,
|
|
850
|
+
webhook: sub.name,
|
|
851
|
+
type: event.type,
|
|
852
|
+
object: event.object,
|
|
853
|
+
subscriptionOrganizationId: sub.organizationId,
|
|
854
|
+
eventNamesOrganization: eventOrganizationId !== void 0
|
|
855
|
+
};
|
|
856
|
+
if (this.organizationRefusalReported.has(sub.id)) {
|
|
857
|
+
_optionalChain([this, 'access', _87 => _87.logger, 'optionalAccess', _88 => _88.debug, 'optionalCall', _89 => _89(
|
|
858
|
+
`[webhook-auto-enqueuer] webhook '${sub.name}' still refused on the organization dimension`,
|
|
859
|
+
meta
|
|
860
|
+
)]);
|
|
861
|
+
return false;
|
|
862
|
+
}
|
|
863
|
+
this.organizationRefusalReported.add(sub.id);
|
|
864
|
+
const message = orgless ? `[webhook-auto-enqueuer] webhook '${sub.name}' belongs to NO organization, but this ${event.type} event on '${event.object}' is organization-walled (the producer stamped organizationId) \u2014 refusing to fan out: a subscription with no organization ownership does not receive an organization's records. It will receive NO organization-walled event while reading active:true in Setup; author the webhook inside the organization that should receive these events. Said once per subscription.` : `[webhook-auto-enqueuer] webhook '${sub.name}' belongs to organization '${sub.organizationId}', but this ${event.type} event on '${event.object}' names no organization \u2014 refusing to deliver it inside an organization wall: on the per-record path an absent organizationId is an environment-wide row or an object outside the wall; on the bulk path it is a batch the producer could not attribute to one organization (a system or cross-membership predicate write). A tenant-scoped subscription receives only events attributable to its own organization. Said once per subscription.`;
|
|
865
|
+
_optionalChain([this, 'access', _90 => _90.logger, 'optionalAccess', _91 => _91.warn, 'optionalCall', _92 => _92(message, meta)]);
|
|
866
|
+
return false;
|
|
867
|
+
}
|
|
738
868
|
handleSelfHealEvent(event) {
|
|
739
869
|
if (event.object !== this.subscriptionsObject) return;
|
|
740
|
-
if (!_optionalChain([event, 'access',
|
|
870
|
+
if (!_optionalChain([event, 'access', _93 => _93.type, 'optionalAccess', _94 => _94.startsWith, 'call', _95 => _95("data.record.")]) && !_optionalChain([event, 'access', _96 => _96.type, 'optionalAccess', _97 => _97.startsWith, 'call', _98 => _98("data.records.")])) return;
|
|
741
871
|
this.refresh().catch(
|
|
742
|
-
(err) => _optionalChain([this, 'access',
|
|
872
|
+
(err) => _optionalChain([this, 'access', _99 => _99.logger, 'optionalAccess', _100 => _100.warn, 'optionalCall', _101 => _101("[webhook-auto-enqueuer] self-heal refresh failed", err)])
|
|
743
873
|
);
|
|
744
874
|
}
|
|
745
875
|
/** Test / admin accessor. */
|
|
@@ -759,6 +889,12 @@ function mapActionToTrigger(action) {
|
|
|
759
889
|
return null;
|
|
760
890
|
}
|
|
761
891
|
}
|
|
892
|
+
function readEventOrganizationId(payload) {
|
|
893
|
+
const value = payload.organizationId;
|
|
894
|
+
if (value === void 0) return { organizationId: void 0 };
|
|
895
|
+
if (typeof value !== "string" || value === "") return void 0;
|
|
896
|
+
return { organizationId: value };
|
|
897
|
+
}
|
|
762
898
|
function mapBulkActionToTrigger(action) {
|
|
763
899
|
switch (action) {
|
|
764
900
|
case "updated":
|
|
@@ -782,21 +918,21 @@ var _automation = require('@objectstack/spec/automation');
|
|
|
782
918
|
var SYSTEM_CTX = { isSystem: true, positions: [], permissions: [] };
|
|
783
919
|
function uid(prefix) {
|
|
784
920
|
const g = globalThis;
|
|
785
|
-
if (_optionalChain([g, 'access',
|
|
921
|
+
if (_optionalChain([g, 'access', _102 => _102.crypto, 'optionalAccess', _103 => _103.randomUUID])) return `${prefix}_${g.crypto.randomUUID()}`;
|
|
786
922
|
return `${prefix}_${Math.random().toString(36).slice(2, 10)}`;
|
|
787
923
|
}
|
|
788
924
|
function readDeclared(engine, metadataService, type) {
|
|
789
925
|
try {
|
|
790
|
-
const reg = _optionalChain([engine, 'optionalAccess',
|
|
791
|
-
if (_optionalChain([reg, 'optionalAccess',
|
|
926
|
+
const reg = _optionalChain([engine, 'optionalAccess', _104 => _104._registry]);
|
|
927
|
+
if (_optionalChain([reg, 'optionalAccess', _105 => _105.listItems])) {
|
|
792
928
|
const items = (_nullishCoalesce(reg.listItems(type), () => ( []))).filter(Boolean);
|
|
793
929
|
if (items.length > 0) return items;
|
|
794
930
|
}
|
|
795
931
|
} catch (e7) {
|
|
796
932
|
}
|
|
797
933
|
try {
|
|
798
|
-
const listed = _optionalChain([metadataService, 'optionalAccess',
|
|
799
|
-
const arr = typeof _optionalChain([listed, 'optionalAccess',
|
|
934
|
+
const listed = _optionalChain([metadataService, 'optionalAccess', _106 => _106.list, 'optionalCall', _107 => _107(type)]);
|
|
935
|
+
const arr = typeof _optionalChain([listed, 'optionalAccess', _108 => _108.then]) === "function" ? [] : _nullishCoalesce(listed, () => ( []));
|
|
800
936
|
return Array.isArray(arr) ? arr.filter(Boolean) : [];
|
|
801
937
|
} catch (e8) {
|
|
802
938
|
return [];
|
|
@@ -813,9 +949,9 @@ async function bootstrapDeclaredWebhooks(engine, metadataService, logger, subscr
|
|
|
813
949
|
try {
|
|
814
950
|
wh = _automation.WebhookSchema.parse(raw);
|
|
815
951
|
} catch (err) {
|
|
816
|
-
_optionalChain([logger, 'optionalAccess',
|
|
817
|
-
name: _optionalChain([raw, 'optionalAccess',
|
|
818
|
-
error: _nullishCoalesce(_optionalChain([err, 'optionalAccess',
|
|
952
|
+
_optionalChain([logger, 'optionalAccess', _109 => _109.warn, 'optionalCall', _110 => _110("[webhook] declared webhook failed validation \u2014 skipped", {
|
|
953
|
+
name: _optionalChain([raw, 'optionalAccess', _111 => _111.name]),
|
|
954
|
+
error: _nullishCoalesce(_optionalChain([err, 'optionalAccess', _112 => _112.message]), () => ( String(err)))
|
|
819
955
|
})]);
|
|
820
956
|
skipped += 1;
|
|
821
957
|
continue;
|
|
@@ -829,7 +965,7 @@ async function bootstrapDeclaredWebhooks(engine, metadataService, logger, subscr
|
|
|
829
965
|
const row = Array.isArray(existing) ? existing[0] : void 0;
|
|
830
966
|
if (row) {
|
|
831
967
|
if (row.managed_by === "admin") {
|
|
832
|
-
_optionalChain([logger, 'optionalAccess',
|
|
968
|
+
_optionalChain([logger, 'optionalAccess', _113 => _113.warn, 'optionalCall', _114 => _114("[webhook] declared name collides with an admin-authored row \u2014 seed skipped", {
|
|
833
969
|
name: wh.name
|
|
834
970
|
})]);
|
|
835
971
|
skipped += 1;
|
|
@@ -881,18 +1017,18 @@ async function bootstrapDeclaredWebhooks(engine, metadataService, logger, subscr
|
|
|
881
1017
|
seeded += 1;
|
|
882
1018
|
} catch (err) {
|
|
883
1019
|
const protection = isSecretProtectionFailure(err);
|
|
884
|
-
_optionalChain([logger, 'optionalAccess',
|
|
1020
|
+
_optionalChain([logger, 'optionalAccess', _115 => _115.warn, 'optionalCall', _116 => _116(
|
|
885
1021
|
protection ? "[webhook] declared webhook NOT seeded \u2014 its signing secret cannot be stored encrypted (#7799)" : "[webhook] declared webhook seed failed",
|
|
886
1022
|
{
|
|
887
1023
|
name: wh.name,
|
|
888
1024
|
...protection ? { code: WEBHOOK_SECRET_REFUSAL_CODE, status: WEBHOOK_SECRET_REFUSAL_STATUS } : {},
|
|
889
|
-
error: _nullishCoalesce(_optionalChain([err, 'optionalAccess',
|
|
1025
|
+
error: _nullishCoalesce(_optionalChain([err, 'optionalAccess', _117 => _117.message]), () => ( String(err)))
|
|
890
1026
|
}
|
|
891
1027
|
)]);
|
|
892
1028
|
skipped += 1;
|
|
893
1029
|
}
|
|
894
1030
|
}
|
|
895
|
-
_optionalChain([logger, 'optionalAccess',
|
|
1031
|
+
_optionalChain([logger, 'optionalAccess', _118 => _118.info, 'optionalCall', _119 => _119("[webhook] declared webhooks materialized into sys_webhook", {
|
|
896
1032
|
seeded,
|
|
897
1033
|
skipped,
|
|
898
1034
|
total: declared.length
|
|
@@ -901,7 +1037,7 @@ async function bootstrapDeclaredWebhooks(engine, metadataService, logger, subscr
|
|
|
901
1037
|
}
|
|
902
1038
|
async function secretPatch(engine, wh, row, subscriptionsObject) {
|
|
903
1039
|
const { secret } = splitWebhookSecret(wh);
|
|
904
|
-
const hasStored = _optionalChain([row, 'optionalAccess',
|
|
1040
|
+
const hasStored = _optionalChain([row, 'optionalAccess', _120 => _120[WEBHOOK_SECRET_FIELD]]) != null && row[WEBHOOK_SECRET_FIELD] !== "";
|
|
905
1041
|
if (!secret) return hasStored ? { [WEBHOOK_SECRET_FIELD]: null } : {};
|
|
906
1042
|
if (!hasStored || !canResolveSecrets(engine)) return { [WEBHOOK_SECRET_FIELD]: secret };
|
|
907
1043
|
try {
|
|
@@ -943,16 +1079,16 @@ async function migrateLegacyWebhookSecrets(engine, logger, subscriptionsObject =
|
|
|
943
1079
|
let rows;
|
|
944
1080
|
try {
|
|
945
1081
|
const found = await engine.find(subscriptionsObject, SYSTEM_QUERY);
|
|
946
|
-
rows = Array.isArray(found) ? found : _nullishCoalesce(_optionalChain([found, 'optionalAccess',
|
|
1082
|
+
rows = Array.isArray(found) ? found : _nullishCoalesce(_optionalChain([found, 'optionalAccess', _121 => _121.data]), () => ( []));
|
|
947
1083
|
} catch (err) {
|
|
948
|
-
_optionalChain([logger, 'optionalAccess',
|
|
1084
|
+
_optionalChain([logger, 'optionalAccess', _122 => _122.warn, 'optionalCall', _123 => _123("[webhook] legacy secret sweep skipped \u2014 could not read subscriptions", {
|
|
949
1085
|
object: subscriptionsObject,
|
|
950
|
-
error: _nullishCoalesce(_optionalChain([err, 'optionalAccess',
|
|
1086
|
+
error: _nullishCoalesce(_optionalChain([err, 'optionalAccess', _124 => _124.message]), () => ( String(err)))
|
|
951
1087
|
})]);
|
|
952
1088
|
return out;
|
|
953
1089
|
}
|
|
954
1090
|
for (const row of rows) {
|
|
955
|
-
if (!_optionalChain([row, 'optionalAccess',
|
|
1091
|
+
if (!_optionalChain([row, 'optionalAccess', _125 => _125.id])) continue;
|
|
956
1092
|
const legacySecret = readLegacySecret(row.definition_json);
|
|
957
1093
|
const legacyHeaders = readLegacyHeaders(row.definition_json);
|
|
958
1094
|
if (!legacySecret && !legacyHeaders) continue;
|
|
@@ -973,20 +1109,20 @@ async function migrateLegacyWebhookSecrets(engine, logger, subscriptionsObject =
|
|
|
973
1109
|
out.failed += 1;
|
|
974
1110
|
const protection = isSecretProtectionFailure(err);
|
|
975
1111
|
const what = legacySecret && legacyHeaders ? "signing secret and custom headers" : legacySecret ? "signing secret" : "custom headers";
|
|
976
|
-
_optionalChain([logger, 'optionalAccess',
|
|
1112
|
+
_optionalChain([logger, 'optionalAccess', _126 => _126.warn, 'optionalCall', _127 => _127(
|
|
977
1113
|
protection ? `[webhook] ${what} STILL CLEARTEXT in definition_json \u2014 no CryptoProvider to encrypt them (#7799/#7986)` : `[webhook] ${what} migration failed \u2014 row left unchanged (#7799/#7986)`,
|
|
978
1114
|
{
|
|
979
1115
|
name: _nullishCoalesce(row.name, () => ( row.id)),
|
|
980
1116
|
id: row.id,
|
|
981
1117
|
code: WEBHOOK_SECRET_REFUSAL_CODE,
|
|
982
1118
|
status: WEBHOOK_SECRET_REFUSAL_STATUS,
|
|
983
|
-
error: _nullishCoalesce(_optionalChain([err, 'optionalAccess',
|
|
1119
|
+
error: _nullishCoalesce(_optionalChain([err, 'optionalAccess', _128 => _128.message]), () => ( String(err)))
|
|
984
1120
|
}
|
|
985
1121
|
)]);
|
|
986
1122
|
}
|
|
987
1123
|
}
|
|
988
1124
|
if (out.found > 0) {
|
|
989
|
-
_optionalChain([logger, 'optionalAccess',
|
|
1125
|
+
_optionalChain([logger, 'optionalAccess', _129 => _129.info, 'optionalCall', _130 => _130("[webhook] legacy cleartext credentials swept into sys_secret", { ...out })]);
|
|
990
1126
|
}
|
|
991
1127
|
return out;
|
|
992
1128
|
}
|
|
@@ -1022,42 +1158,26 @@ function createWebhookRedeliverGuard(engine, subscriptionsObject = WEBHOOK_OBJEC
|
|
|
1022
1158
|
|
|
1023
1159
|
// src/webhook-provenance.ts
|
|
1024
1160
|
var WEBHOOK_PROVENANCE_PACKAGE = "plugin-webhooks:provenance";
|
|
1025
|
-
var SYSTEM_CTX3 = { isSystem: true, positions: [], permissions: [] };
|
|
1026
1161
|
function bindWebhookProvenanceStamp(engine, logger) {
|
|
1027
|
-
if (typeof _optionalChain([engine, 'optionalAccess',
|
|
1162
|
+
if (typeof _optionalChain([engine, 'optionalAccess', _131 => _131.registerHook]) !== "function") return;
|
|
1028
1163
|
engine.registerHook(
|
|
1029
1164
|
"beforeUpdate",
|
|
1030
1165
|
async (ctx) => {
|
|
1031
|
-
if (_optionalChain([ctx, 'optionalAccess',
|
|
1032
|
-
const
|
|
1033
|
-
if (!id) return;
|
|
1034
|
-
const data = _optionalChain([ctx, 'optionalAccess', _127 => _127.input, 'optionalAccess', _128 => _128.data]);
|
|
1166
|
+
if (_optionalChain([ctx, 'optionalAccess', _132 => _132.session, 'optionalAccess', _133 => _133.isSystem])) return;
|
|
1167
|
+
const data = _optionalChain([ctx, 'optionalAccess', _134 => _134.input, 'optionalAccess', _135 => _135.data]);
|
|
1035
1168
|
if (!data || typeof data !== "object") return;
|
|
1036
|
-
|
|
1037
|
-
|
|
1038
|
-
|
|
1039
|
-
|
|
1040
|
-
limit: 1,
|
|
1041
|
-
context: SYSTEM_CTX3
|
|
1042
|
-
});
|
|
1043
|
-
const row = Array.isArray(rows) ? rows[0] : void 0;
|
|
1044
|
-
if (!row) return;
|
|
1045
|
-
if ((row.managed_by === "package" || row.managed_by === "platform") && row.customized !== true) {
|
|
1046
|
-
data.customized = true;
|
|
1047
|
-
}
|
|
1048
|
-
} catch (err) {
|
|
1049
|
-
_optionalChain([logger, 'optionalAccess', _129 => _129.warn, 'optionalCall', _130 => _130("[webhook] provenance stamp failed (edit proceeds unstamped)", {
|
|
1050
|
-
id,
|
|
1051
|
-
error: _optionalChain([err, 'optionalAccess', _131 => _131.message])
|
|
1052
|
-
})]);
|
|
1169
|
+
const previous = _optionalChain([ctx, 'optionalAccess', _136 => _136.previous]);
|
|
1170
|
+
if (!previous || typeof previous !== "object") return;
|
|
1171
|
+
if ((previous.managed_by === "package" || previous.managed_by === "platform") && previous.customized !== true) {
|
|
1172
|
+
data.customized = true;
|
|
1053
1173
|
}
|
|
1054
1174
|
},
|
|
1055
1175
|
{ object: "sys_webhook", packageId: WEBHOOK_PROVENANCE_PACKAGE, priority: 150 }
|
|
1056
1176
|
);
|
|
1057
|
-
_optionalChain([logger, 'optionalAccess',
|
|
1177
|
+
_optionalChain([logger, 'optionalAccess', _137 => _137.info, 'optionalCall', _138 => _138("[webhook] provenance stamp hook bound")]);
|
|
1058
1178
|
}
|
|
1059
1179
|
function unbindWebhookProvenanceStamp(engine) {
|
|
1060
|
-
if (typeof _optionalChain([engine, 'optionalAccess',
|
|
1180
|
+
if (typeof _optionalChain([engine, 'optionalAccess', _139 => _139.unregisterHooksByPackage]) === "function") {
|
|
1061
1181
|
engine.unregisterHooksByPackage(WEBHOOK_PROVENANCE_PACKAGE);
|
|
1062
1182
|
}
|
|
1063
1183
|
}
|
|
@@ -1135,9 +1255,9 @@ function assertWritableWebhookHeaders(data, object = WEBHOOK_OBJECT, field = WEB
|
|
|
1135
1255
|
var WEBHOOK_HEADERS_GATE_PACKAGE = "plugin-webhooks:headers-shape-gate";
|
|
1136
1256
|
var GATE_PRIORITY = 50;
|
|
1137
1257
|
function bindWebhookHeadersShapeGate(engine, logger) {
|
|
1138
|
-
if (typeof _optionalChain([engine, 'optionalAccess',
|
|
1258
|
+
if (typeof _optionalChain([engine, 'optionalAccess', _140 => _140.registerHook]) !== "function") return;
|
|
1139
1259
|
const handler = (ctx) => {
|
|
1140
|
-
assertWritableWebhookHeaders(_optionalChain([ctx, 'optionalAccess',
|
|
1260
|
+
assertWritableWebhookHeaders(_optionalChain([ctx, 'optionalAccess', _141 => _141.input, 'optionalAccess', _142 => _142.data]));
|
|
1141
1261
|
};
|
|
1142
1262
|
for (const event of ["beforeInsert", "beforeUpdate"]) {
|
|
1143
1263
|
engine.registerHook(event, handler, {
|
|
@@ -1146,10 +1266,10 @@ function bindWebhookHeadersShapeGate(engine, logger) {
|
|
|
1146
1266
|
priority: GATE_PRIORITY
|
|
1147
1267
|
});
|
|
1148
1268
|
}
|
|
1149
|
-
_optionalChain([logger, 'optionalAccess',
|
|
1269
|
+
_optionalChain([logger, 'optionalAccess', _143 => _143.info, 'optionalCall', _144 => _144("[webhook] headers_secret shape gate bound (refuses non-flat-string-map plaintext)")]);
|
|
1150
1270
|
}
|
|
1151
1271
|
function unbindWebhookHeadersShapeGate(engine) {
|
|
1152
|
-
if (typeof _optionalChain([engine, 'optionalAccess',
|
|
1272
|
+
if (typeof _optionalChain([engine, 'optionalAccess', _145 => _145.unregisterHooksByPackage]) === "function") {
|
|
1153
1273
|
engine.unregisterHooksByPackage(WEBHOOK_HEADERS_GATE_PACKAGE);
|
|
1154
1274
|
}
|
|
1155
1275
|
}
|
|
@@ -1184,7 +1304,7 @@ var WebhookOutboxPlugin = class {
|
|
|
1184
1304
|
scope: "system",
|
|
1185
1305
|
name: "Webhook Schemas",
|
|
1186
1306
|
description: "Registers sys_webhook (configuration). Deliveries use messaging's sys_http_delivery outbox.",
|
|
1187
|
-
objects: [
|
|
1307
|
+
objects: [_chunkCWE6CIEZcjs.SysWebhook],
|
|
1188
1308
|
navigationContributions: [
|
|
1189
1309
|
{
|
|
1190
1310
|
app: "setup",
|
|
@@ -1198,7 +1318,7 @@ var WebhookOutboxPlugin = class {
|
|
|
1198
1318
|
]
|
|
1199
1319
|
});
|
|
1200
1320
|
} else {
|
|
1201
|
-
_optionalChain([ctx, 'access',
|
|
1321
|
+
_optionalChain([ctx, 'access', _146 => _146.logger, 'access', _147 => _147.warn, 'optionalCall', _148 => _148(
|
|
1202
1322
|
"[webhook-outbox] manifest service unavailable \u2014 sys_webhook will NOT appear in REST or Studio nav. Register MetadataService before WebhookOutboxPlugin."
|
|
1203
1323
|
)]);
|
|
1204
1324
|
}
|
|
@@ -1207,7 +1327,7 @@ var WebhookOutboxPlugin = class {
|
|
|
1207
1327
|
try {
|
|
1208
1328
|
const i18n = ctx.getService("i18n");
|
|
1209
1329
|
if (i18n && typeof i18n.loadTranslations === "function") {
|
|
1210
|
-
const { WebhooksTranslations } = await Promise.resolve().then(() => _interopRequireWildcard(require("./translations-
|
|
1330
|
+
const { WebhooksTranslations } = await Promise.resolve().then(() => _interopRequireWildcard(require("./translations-VX3ONQXN.cjs")));
|
|
1211
1331
|
for (const [locale, data] of Object.entries(WebhooksTranslations)) {
|
|
1212
1332
|
i18n.loadTranslations(locale, data);
|
|
1213
1333
|
}
|
|
@@ -1224,7 +1344,7 @@ var WebhookOutboxPlugin = class {
|
|
|
1224
1344
|
this.registerAdminRoutes(ctx);
|
|
1225
1345
|
});
|
|
1226
1346
|
}
|
|
1227
|
-
_optionalChain([ctx, 'access',
|
|
1347
|
+
_optionalChain([ctx, 'access', _149 => _149.logger, 'access', _150 => _150.info, 'optionalCall', _151 => _151("[webhook-outbox] initialised (delivery via shared messaging HTTP outbox)", {
|
|
1228
1348
|
autoEnqueue: autoEnqueueOpt !== false
|
|
1229
1349
|
})]);
|
|
1230
1350
|
}
|
|
@@ -1244,7 +1364,7 @@ var WebhookOutboxPlugin = class {
|
|
|
1244
1364
|
* teardown is a no-op rather than a second unbind.
|
|
1245
1365
|
*/
|
|
1246
1366
|
async destroy() {
|
|
1247
|
-
await _optionalChain([this, 'access',
|
|
1367
|
+
await _optionalChain([this, 'access', _152 => _152.autoEnqueuer, 'optionalAccess', _153 => _153.stop, 'call', _154 => _154()]);
|
|
1248
1368
|
if (this.boundEngine) {
|
|
1249
1369
|
try {
|
|
1250
1370
|
unbindWebhookProvenanceStamp(this.boundEngine);
|
|
@@ -1285,7 +1405,7 @@ var WebhookOutboxPlugin = class {
|
|
|
1285
1405
|
async bootDeclaredWebhooks(ctx) {
|
|
1286
1406
|
const engine = this.tryGetService(ctx, ["objectql", "data"]);
|
|
1287
1407
|
if (!engine) {
|
|
1288
|
-
_optionalChain([ctx, 'access',
|
|
1408
|
+
_optionalChain([ctx, 'access', _155 => _155.logger, 'access', _156 => _156.warn, 'optionalCall', _157 => _157("[webhook] declared-webhook bootstrap skipped \u2014 no data engine available")]);
|
|
1289
1409
|
return;
|
|
1290
1410
|
}
|
|
1291
1411
|
this.boundEngine = engine;
|
|
@@ -1299,15 +1419,15 @@ var WebhookOutboxPlugin = class {
|
|
|
1299
1419
|
try {
|
|
1300
1420
|
await bootstrapDeclaredWebhooks(engine, metadataService, ctx.logger);
|
|
1301
1421
|
} catch (err) {
|
|
1302
|
-
_optionalChain([ctx, 'access',
|
|
1303
|
-
error: _nullishCoalesce(_optionalChain([err, 'optionalAccess',
|
|
1422
|
+
_optionalChain([ctx, 'access', _158 => _158.logger, 'access', _159 => _159.warn, 'optionalCall', _160 => _160("[webhook] declared-webhook bootstrap failed (dispatcher still serves admin rows)", {
|
|
1423
|
+
error: _nullishCoalesce(_optionalChain([err, 'optionalAccess', _161 => _161.message]), () => ( String(err)))
|
|
1304
1424
|
})]);
|
|
1305
1425
|
}
|
|
1306
1426
|
try {
|
|
1307
1427
|
await migrateLegacyWebhookSecrets(engine, ctx.logger);
|
|
1308
1428
|
} catch (err) {
|
|
1309
|
-
_optionalChain([ctx, 'access',
|
|
1310
|
-
error: _nullishCoalesce(_optionalChain([err, 'optionalAccess',
|
|
1429
|
+
_optionalChain([ctx, 'access', _162 => _162.logger, 'access', _163 => _163.warn, 'optionalCall', _164 => _164("[webhook] legacy signing-secret sweep failed (rows left unchanged)", {
|
|
1430
|
+
error: _nullishCoalesce(_optionalChain([err, 'optionalAccess', _165 => _165.message]), () => ( String(err)))
|
|
1311
1431
|
})]);
|
|
1312
1432
|
}
|
|
1313
1433
|
}
|
|
@@ -1317,14 +1437,14 @@ var WebhookOutboxPlugin = class {
|
|
|
1317
1437
|
const realtime = this.tryGetService(ctx, ["realtime"]);
|
|
1318
1438
|
const messaging = this.getMessaging(ctx);
|
|
1319
1439
|
if (!engine || !realtime || !messaging) {
|
|
1320
|
-
_optionalChain([ctx, 'access',
|
|
1440
|
+
_optionalChain([ctx, 'access', _166 => _166.logger, 'access', _167 => _167.warn, 'optionalCall', _168 => _168(
|
|
1321
1441
|
"[webhook-auto-enqueuer] disabled \u2014 ObjectQL, Realtime, or Messaging service not available",
|
|
1322
1442
|
{ hasEngine: !!engine, hasRealtime: !!realtime, hasMessaging: !!messaging }
|
|
1323
1443
|
)]);
|
|
1324
1444
|
return;
|
|
1325
1445
|
}
|
|
1326
1446
|
if (!messaging.isHttpDeliveryReady()) {
|
|
1327
|
-
_optionalChain([ctx, 'access',
|
|
1447
|
+
_optionalChain([ctx, 'access', _169 => _169.logger, 'access', _170 => _170.warn, 'optionalCall', _171 => _171(
|
|
1328
1448
|
"[webhook-auto-enqueuer] messaging HTTP outbox not ready (no data engine / reliableDelivery off) \u2014 webhook deliveries will not be durable"
|
|
1329
1449
|
)]);
|
|
1330
1450
|
}
|
|
@@ -1338,7 +1458,7 @@ var WebhookOutboxPlugin = class {
|
|
|
1338
1458
|
);
|
|
1339
1459
|
await this.autoEnqueuer.start();
|
|
1340
1460
|
ctx.registerService("webhook.autoEnqueuer", this.autoEnqueuer);
|
|
1341
|
-
_optionalChain([ctx, 'access',
|
|
1461
|
+
_optionalChain([ctx, 'access', _172 => _172.logger, 'access', _173 => _173.info, 'optionalCall', _174 => _174("[webhook-auto-enqueuer] started (enqueues source=webhook onto sys_http_delivery)")]);
|
|
1342
1462
|
}
|
|
1343
1463
|
/**
|
|
1344
1464
|
* [#8069] Register {@link createWebhookRedeliverGuard} with messaging, so
|
|
@@ -1354,7 +1474,7 @@ var WebhookOutboxPlugin = class {
|
|
|
1354
1474
|
*/
|
|
1355
1475
|
installRedeliverGuard(ctx, messaging, engine, subscriptionsObject) {
|
|
1356
1476
|
if (typeof messaging.registerRedeliverGuard !== "function") {
|
|
1357
|
-
_optionalChain([ctx, 'access',
|
|
1477
|
+
_optionalChain([ctx, 'access', _175 => _175.logger, 'access', _176 => _176.error, 'optionalCall', _177 => _177(
|
|
1358
1478
|
"[webhook-outbox] messaging service exposes no registerRedeliverGuard() \u2014 redelivery of a webhook whose signing configuration is gone CANNOT be refused, so an operator pressing redeliver may send a delivery that can no longer be authenticated (#7799, #8069). The POST /api/v1/webhooks/redeliver endpoint is reachable by any authenticated user. Fix: upgrade @objectstack/service-messaging to a build that implements registerRedeliverGuard."
|
|
1359
1479
|
)]);
|
|
1360
1480
|
return;
|
|
@@ -1363,7 +1483,7 @@ var WebhookOutboxPlugin = class {
|
|
|
1363
1483
|
"webhook",
|
|
1364
1484
|
createWebhookRedeliverGuard(engine, subscriptionsObject)
|
|
1365
1485
|
);
|
|
1366
|
-
_optionalChain([ctx, 'access',
|
|
1486
|
+
_optionalChain([ctx, 'access', _178 => _178.logger, 'access', _179 => _179.debug, 'optionalCall', _180 => _180("[webhook-outbox] redeliver guard installed for source=webhook")]);
|
|
1367
1487
|
}
|
|
1368
1488
|
tryGetService(ctx, names) {
|
|
1369
1489
|
for (const n of names) {
|
|
@@ -1396,7 +1516,7 @@ var WebhookOutboxPlugin = class {
|
|
|
1396
1516
|
registerAdminRoutes(ctx) {
|
|
1397
1517
|
const http = this.tryGetService(ctx, ["http-server"]);
|
|
1398
1518
|
if (!http || typeof http.getRawApp !== "function") {
|
|
1399
|
-
_optionalChain([ctx, 'access',
|
|
1519
|
+
_optionalChain([ctx, 'access', _181 => _181.logger, 'access', _182 => _182.debug, 'optionalCall', _183 => _183("[webhook-outbox] HTTP server not available; redeliver endpoint not mounted")]);
|
|
1400
1520
|
return;
|
|
1401
1521
|
}
|
|
1402
1522
|
const rawApp = http.getRawApp();
|
|
@@ -1404,7 +1524,7 @@ var WebhookOutboxPlugin = class {
|
|
|
1404
1524
|
if (!rawApp || !messaging) return;
|
|
1405
1525
|
rawApp.post("/api/v1/webhooks/redeliver", async (c) => {
|
|
1406
1526
|
const session = await this.resolveSession(ctx, c);
|
|
1407
|
-
const userId = _optionalChain([session, 'optionalAccess',
|
|
1527
|
+
const userId = _optionalChain([session, 'optionalAccess', _184 => _184.user, 'optionalAccess', _185 => _185.id]);
|
|
1408
1528
|
if (typeof userId !== "string" || userId.length === 0) {
|
|
1409
1529
|
return c.json(
|
|
1410
1530
|
{ success: false, error: { code: "UNAUTHENTICATED", message: "Sign in to redeliver webhook deliveries." } },
|
|
@@ -1417,7 +1537,7 @@ var WebhookOutboxPlugin = class {
|
|
|
1417
1537
|
} catch (e17) {
|
|
1418
1538
|
return c.json({ success: false, error: { code: "INVALID_REQUEST", message: "Request body must be JSON." } }, 400);
|
|
1419
1539
|
}
|
|
1420
|
-
const deliveryId = typeof _optionalChain([body, 'optionalAccess',
|
|
1540
|
+
const deliveryId = typeof _optionalChain([body, 'optionalAccess', _186 => _186.deliveryId]) === "string" ? body.deliveryId.trim() : "";
|
|
1421
1541
|
if (!deliveryId) {
|
|
1422
1542
|
return c.json(
|
|
1423
1543
|
{ success: false, error: { code: "MISSING_REQUIRED_FIELD", message: "Body must include `deliveryId: string`." } },
|
|
@@ -1425,27 +1545,27 @@ var WebhookOutboxPlugin = class {
|
|
|
1425
1545
|
);
|
|
1426
1546
|
}
|
|
1427
1547
|
try {
|
|
1428
|
-
const activeOrg = _optionalChain([session, 'optionalAccess',
|
|
1548
|
+
const activeOrg = _optionalChain([session, 'optionalAccess', _187 => _187.session, 'optionalAccess', _188 => _188.activeOrganizationId]);
|
|
1429
1549
|
const tenantId = typeof activeOrg === "string" && activeOrg.length > 0 ? activeOrg : void 0;
|
|
1430
1550
|
const row = await messaging.redeliverHttp(deliveryId, { tenantId });
|
|
1431
|
-
_optionalChain([ctx, 'access',
|
|
1551
|
+
_optionalChain([ctx, 'access', _189 => _189.logger, 'access', _190 => _190.info, 'optionalCall', _191 => _191("[webhook-outbox] redelivered", { deliveryId, requestedBy: userId, tenantId })]);
|
|
1432
1552
|
return c.json({ success: true, data: { id: row.id, status: row.status } });
|
|
1433
1553
|
} catch (err) {
|
|
1434
|
-
const code = _optionalChain([err, 'optionalAccess',
|
|
1554
|
+
const code = _optionalChain([err, 'optionalAccess', _192 => _192.code]);
|
|
1435
1555
|
if (code === "RESOURCE_NOT_FOUND") {
|
|
1436
1556
|
return c.json({ success: false, error: { code, message: err.message } }, 404);
|
|
1437
1557
|
}
|
|
1438
1558
|
if (code === "DELIVERY_NOT_ELIGIBLE" || code === "DELIVERY_NEVER_SENT") {
|
|
1439
1559
|
return c.json({ success: false, error: { code, message: err.message } }, 409);
|
|
1440
1560
|
}
|
|
1441
|
-
_optionalChain([ctx, 'access',
|
|
1561
|
+
_optionalChain([ctx, 'access', _193 => _193.logger, 'access', _194 => _194.error, 'optionalCall', _195 => _195("[webhook-outbox] redeliver failed", err)]);
|
|
1442
1562
|
return c.json(
|
|
1443
|
-
{ success: false, error: { code: "INTERNAL_ERROR", message: _nullishCoalesce(_optionalChain([err, 'optionalAccess',
|
|
1563
|
+
{ success: false, error: { code: "INTERNAL_ERROR", message: _nullishCoalesce(_optionalChain([err, 'optionalAccess', _196 => _196.message]), () => ( String(err))) } },
|
|
1444
1564
|
500
|
|
1445
1565
|
);
|
|
1446
1566
|
}
|
|
1447
1567
|
});
|
|
1448
|
-
_optionalChain([ctx, 'access',
|
|
1568
|
+
_optionalChain([ctx, 'access', _197 => _197.logger, 'access', _198 => _198.info, 'optionalCall', _199 => _199("[webhook-outbox] redeliver endpoint mounted at POST /api/v1/webhooks/redeliver")]);
|
|
1449
1569
|
}
|
|
1450
1570
|
/**
|
|
1451
1571
|
* [#10740] The better-auth session envelope (`{ user, session }`) for this
|
|
@@ -1466,7 +1586,7 @@ var WebhookOutboxPlugin = class {
|
|
|
1466
1586
|
if (!api && typeof authService.getApi === "function") {
|
|
1467
1587
|
api = await authService.getApi();
|
|
1468
1588
|
}
|
|
1469
|
-
if (!_optionalChain([api, 'optionalAccess',
|
|
1589
|
+
if (!_optionalChain([api, 'optionalAccess', _200 => _200.getSession])) return void 0;
|
|
1470
1590
|
return await api.getSession({ headers: c.req.raw.headers });
|
|
1471
1591
|
} catch (e18) {
|
|
1472
1592
|
return void 0;
|
|
@@ -1486,5 +1606,5 @@ var WebhookOutboxPlugin = class {
|
|
|
1486
1606
|
|
|
1487
1607
|
|
|
1488
1608
|
|
|
1489
|
-
exports.AutoEnqueuer = AutoEnqueuer; exports.SysWebhook =
|
|
1609
|
+
exports.AutoEnqueuer = AutoEnqueuer; exports.SysWebhook = _chunkCWE6CIEZcjs.SysWebhook; exports.WEBHOOK_HEADERS_FIELD = WEBHOOK_HEADERS_FIELD; exports.WEBHOOK_HEADERS_SHAPE_REFUSAL_CODE = WEBHOOK_HEADERS_SHAPE_REFUSAL_CODE; exports.WEBHOOK_HEADERS_SHAPE_REFUSAL_STATUS = WEBHOOK_HEADERS_SHAPE_REFUSAL_STATUS; exports.WEBHOOK_SECRET_FIELD = WEBHOOK_SECRET_FIELD; exports.WebhookHeadersShapeError = WebhookHeadersShapeError; exports.WebhookOutboxPlugin = WebhookOutboxPlugin; exports.assertWritableWebhookHeaders = assertWritableWebhookHeaders; exports.bindWebhookHeadersShapeGate = bindWebhookHeadersShapeGate; exports.migrateLegacyWebhookSecrets = migrateLegacyWebhookSecrets; exports.unbindWebhookHeadersShapeGate = unbindWebhookHeadersShapeGate;
|
|
1490
1610
|
//# sourceMappingURL=index.cjs.map
|