@nestarc/webhook 0.9.0 → 0.10.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/README.md +76 -25
- package/dist/adapters/fetch-http-client.d.ts.map +1 -1
- package/dist/adapters/fetch-http-client.js +1 -1
- package/dist/adapters/fetch-http-client.js.map +1 -1
- package/dist/adapters/plaintext-secret-vault.d.ts.map +1 -1
- package/dist/adapters/plaintext-secret-vault.js +12 -2
- package/dist/adapters/plaintext-secret-vault.js.map +1 -1
- package/dist/adapters/prisma-delivery.repository.d.ts +8 -4
- package/dist/adapters/prisma-delivery.repository.d.ts.map +1 -1
- package/dist/adapters/prisma-delivery.repository.js +134 -77
- package/dist/adapters/prisma-delivery.repository.js.map +1 -1
- package/dist/adapters/prisma-endpoint.repository.d.ts +4 -3
- package/dist/adapters/prisma-endpoint.repository.d.ts.map +1 -1
- package/dist/adapters/prisma-endpoint.repository.js +39 -6
- package/dist/adapters/prisma-endpoint.repository.js.map +1 -1
- package/dist/index.d.ts +11 -6
- package/dist/index.d.ts.map +1 -1
- package/dist/index.js +9 -2
- package/dist/index.js.map +1 -1
- package/dist/interfaces/webhook-delivery.interface.d.ts +6 -2
- package/dist/interfaces/webhook-delivery.interface.d.ts.map +1 -1
- package/dist/interfaces/webhook-endpoint.interface.d.ts +11 -2
- package/dist/interfaces/webhook-endpoint.interface.d.ts.map +1 -1
- package/dist/interfaces/webhook-options.interface.d.ts +8 -6
- package/dist/interfaces/webhook-options.interface.d.ts.map +1 -1
- package/dist/ports/webhook-delivery.repository.d.ts +28 -10
- package/dist/ports/webhook-delivery.repository.d.ts.map +1 -1
- package/dist/ports/webhook-endpoint.repository.d.ts +24 -4
- package/dist/ports/webhook-endpoint.repository.d.ts.map +1 -1
- package/dist/ports/webhook-event.repository.d.ts +3 -1
- package/dist/ports/webhook-event.repository.d.ts.map +1 -1
- package/dist/ports/webhook-http-client.d.ts +4 -0
- package/dist/ports/webhook-http-client.d.ts.map +1 -1
- package/dist/ports/webhook-secret-vault.d.ts +1 -0
- package/dist/ports/webhook-secret-vault.d.ts.map +1 -1
- package/dist/webhook.admin.service.d.ts +4 -3
- package/dist/webhook.admin.service.d.ts.map +1 -1
- package/dist/webhook.admin.service.js +5 -2
- package/dist/webhook.admin.service.js.map +1 -1
- package/dist/webhook.circuit-breaker.d.ts +6 -4
- package/dist/webhook.circuit-breaker.d.ts.map +1 -1
- package/dist/webhook.circuit-breaker.js +10 -8
- package/dist/webhook.circuit-breaker.js.map +1 -1
- package/dist/webhook.constants.d.ts +9 -2
- package/dist/webhook.constants.d.ts.map +1 -1
- package/dist/webhook.constants.js +11 -4
- package/dist/webhook.constants.js.map +1 -1
- package/dist/webhook.delivery-worker.d.ts +4 -0
- package/dist/webhook.delivery-worker.d.ts.map +1 -1
- package/dist/webhook.delivery-worker.js +49 -22
- package/dist/webhook.delivery-worker.js.map +1 -1
- package/dist/webhook.dispatcher.d.ts +1 -0
- package/dist/webhook.dispatcher.d.ts.map +1 -1
- package/dist/webhook.dispatcher.js +13 -6
- package/dist/webhook.dispatcher.js.map +1 -1
- package/dist/webhook.endpoint-admin.service.d.ts +4 -1
- package/dist/webhook.endpoint-admin.service.d.ts.map +1 -1
- package/dist/webhook.endpoint-admin.service.js +36 -9
- package/dist/webhook.endpoint-admin.service.js.map +1 -1
- package/dist/webhook.module.d.ts.map +1 -1
- package/dist/webhook.module.js +22 -13
- package/dist/webhook.module.js.map +1 -1
- package/package.json +4 -4
- package/src/sql/create-webhook-tables.sql +1 -1
- package/src/sql/migrations/v0.9.0.sql +32 -0
|
@@ -1,10 +1,10 @@
|
|
|
1
1
|
import { WebhookEndpointAdminService } from './webhook.endpoint-admin.service';
|
|
2
2
|
import { WebhookDeliveryAdminService } from './webhook.delivery-admin.service';
|
|
3
|
-
import { CreateEndpointDto, EndpointRecord, EndpointRecordWithSecret, UpdateEndpointDto } from './interfaces/webhook-endpoint.interface';
|
|
3
|
+
import { CreateEndpointDto, EndpointRecord, EndpointRecordWithSecret, RotateEndpointSecretDto, UpdateEndpointDto } from './interfaces/webhook-endpoint.interface';
|
|
4
4
|
import { DeliveryAttemptRecord, DeliveryLogFilters, DeliveryRecord } from './interfaces/webhook-delivery.interface';
|
|
5
5
|
/**
|
|
6
|
-
* @deprecated
|
|
7
|
-
*
|
|
6
|
+
* @deprecated since v0.2.0. Will be removed in v1.0.0.
|
|
7
|
+
* Use WebhookEndpointAdminService and WebhookDeliveryAdminService directly.
|
|
8
8
|
*/
|
|
9
9
|
export declare class WebhookAdminService {
|
|
10
10
|
private readonly endpoints;
|
|
@@ -14,6 +14,7 @@ export declare class WebhookAdminService {
|
|
|
14
14
|
listEndpoints(tenantId?: string): Promise<EndpointRecord[]>;
|
|
15
15
|
getEndpoint(endpointId: string): Promise<EndpointRecord | null>;
|
|
16
16
|
updateEndpoint(endpointId: string, dto: UpdateEndpointDto): Promise<EndpointRecord | null>;
|
|
17
|
+
rotateSecret(endpointId: string, dto: RotateEndpointSecretDto): Promise<EndpointRecordWithSecret | null>;
|
|
17
18
|
deleteEndpoint(endpointId: string): Promise<boolean>;
|
|
18
19
|
getDeliveryLogs(endpointId: string, filters?: DeliveryLogFilters): Promise<DeliveryRecord[]>;
|
|
19
20
|
getDeliveryAttempts(deliveryId: string): Promise<DeliveryAttemptRecord[]>;
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"webhook.admin.service.d.ts","sourceRoot":"","sources":["../src/webhook.admin.service.ts"],"names":[],"mappings":"AACA,OAAO,EAAE,2BAA2B,EAAE,MAAM,kCAAkC,CAAC;AAC/E,OAAO,EAAE,2BAA2B,EAAE,MAAM,kCAAkC,CAAC;AAC/E,OAAO,EACL,iBAAiB,EACjB,cAAc,EACd,wBAAwB,EACxB,iBAAiB,EAClB,MAAM,yCAAyC,CAAC;AACjD,OAAO,EACL,qBAAqB,EACrB,kBAAkB,EAClB,cAAc,EACf,MAAM,yCAAyC,CAAC;AAEjD;;;GAGG;AACH,qBACa,mBAAmB;IAE5B,OAAO,CAAC,QAAQ,CAAC,SAAS;IAC1B,OAAO,CAAC,QAAQ,CAAC,UAAU;gBADV,SAAS,EAAE,2BAA2B,EACtC,UAAU,EAAE,2BAA2B;IAGpD,cAAc,CAAC,GAAG,EAAE,iBAAiB,GAAG,OAAO,CAAC,wBAAwB,CAAC;IAIzE,aAAa,CAAC,QAAQ,CAAC,EAAE,MAAM,GAAG,OAAO,CAAC,cAAc,EAAE,CAAC;IAI3D,WAAW,CAAC,UAAU,EAAE,MAAM,GAAG,OAAO,CAAC,cAAc,GAAG,IAAI,CAAC;IAI/D,cAAc,CAClB,UAAU,EAAE,MAAM,EAClB,GAAG,EAAE,iBAAiB,GACrB,OAAO,CAAC,cAAc,GAAG,IAAI,CAAC;IAI3B,cAAc,CAAC,UAAU,EAAE,MAAM,GAAG,OAAO,CAAC,OAAO,CAAC;IAIpD,eAAe,CACnB,UAAU,EAAE,MAAM,EAClB,OAAO,CAAC,EAAE,kBAAkB,GAC3B,OAAO,CAAC,cAAc,EAAE,CAAC;IAItB,mBAAmB,CAAC,UAAU,EAAE,MAAM,GAAG,OAAO,CAAC,qBAAqB,EAAE,CAAC;IAIzE,aAAa,CAAC,UAAU,EAAE,MAAM,GAAG,OAAO,CAAC,OAAO,CAAC;IAInD,aAAa,CAAC,UAAU,EAAE,MAAM,GAAG,OAAO,CAAC,MAAM,GAAG,IAAI,CAAC;CAGhE"}
|
|
1
|
+
{"version":3,"file":"webhook.admin.service.d.ts","sourceRoot":"","sources":["../src/webhook.admin.service.ts"],"names":[],"mappings":"AACA,OAAO,EAAE,2BAA2B,EAAE,MAAM,kCAAkC,CAAC;AAC/E,OAAO,EAAE,2BAA2B,EAAE,MAAM,kCAAkC,CAAC;AAC/E,OAAO,EACL,iBAAiB,EACjB,cAAc,EACd,wBAAwB,EACxB,uBAAuB,EACvB,iBAAiB,EAClB,MAAM,yCAAyC,CAAC;AACjD,OAAO,EACL,qBAAqB,EACrB,kBAAkB,EAClB,cAAc,EACf,MAAM,yCAAyC,CAAC;AAEjD;;;GAGG;AACH,qBACa,mBAAmB;IAE5B,OAAO,CAAC,QAAQ,CAAC,SAAS;IAC1B,OAAO,CAAC,QAAQ,CAAC,UAAU;gBADV,SAAS,EAAE,2BAA2B,EACtC,UAAU,EAAE,2BAA2B;IAGpD,cAAc,CAAC,GAAG,EAAE,iBAAiB,GAAG,OAAO,CAAC,wBAAwB,CAAC;IAIzE,aAAa,CAAC,QAAQ,CAAC,EAAE,MAAM,GAAG,OAAO,CAAC,cAAc,EAAE,CAAC;IAI3D,WAAW,CAAC,UAAU,EAAE,MAAM,GAAG,OAAO,CAAC,cAAc,GAAG,IAAI,CAAC;IAI/D,cAAc,CAClB,UAAU,EAAE,MAAM,EAClB,GAAG,EAAE,iBAAiB,GACrB,OAAO,CAAC,cAAc,GAAG,IAAI,CAAC;IAI3B,YAAY,CAChB,UAAU,EAAE,MAAM,EAClB,GAAG,EAAE,uBAAuB,GAC3B,OAAO,CAAC,wBAAwB,GAAG,IAAI,CAAC;IAIrC,cAAc,CAAC,UAAU,EAAE,MAAM,GAAG,OAAO,CAAC,OAAO,CAAC;IAIpD,eAAe,CACnB,UAAU,EAAE,MAAM,EAClB,OAAO,CAAC,EAAE,kBAAkB,GAC3B,OAAO,CAAC,cAAc,EAAE,CAAC;IAItB,mBAAmB,CAAC,UAAU,EAAE,MAAM,GAAG,OAAO,CAAC,qBAAqB,EAAE,CAAC;IAIzE,aAAa,CAAC,UAAU,EAAE,MAAM,GAAG,OAAO,CAAC,OAAO,CAAC;IAInD,aAAa,CAAC,UAAU,EAAE,MAAM,GAAG,OAAO,CAAC,MAAM,GAAG,IAAI,CAAC;CAGhE"}
|
|
@@ -14,8 +14,8 @@ const common_1 = require("@nestjs/common");
|
|
|
14
14
|
const webhook_endpoint_admin_service_1 = require("./webhook.endpoint-admin.service");
|
|
15
15
|
const webhook_delivery_admin_service_1 = require("./webhook.delivery-admin.service");
|
|
16
16
|
/**
|
|
17
|
-
* @deprecated
|
|
18
|
-
*
|
|
17
|
+
* @deprecated since v0.2.0. Will be removed in v1.0.0.
|
|
18
|
+
* Use WebhookEndpointAdminService and WebhookDeliveryAdminService directly.
|
|
19
19
|
*/
|
|
20
20
|
let WebhookAdminService = class WebhookAdminService {
|
|
21
21
|
endpoints;
|
|
@@ -36,6 +36,9 @@ let WebhookAdminService = class WebhookAdminService {
|
|
|
36
36
|
async updateEndpoint(endpointId, dto) {
|
|
37
37
|
return this.endpoints.updateEndpoint(endpointId, dto);
|
|
38
38
|
}
|
|
39
|
+
async rotateSecret(endpointId, dto) {
|
|
40
|
+
return this.endpoints.rotateSecret(endpointId, dto);
|
|
41
|
+
}
|
|
39
42
|
async deleteEndpoint(endpointId) {
|
|
40
43
|
return this.endpoints.deleteEndpoint(endpointId);
|
|
41
44
|
}
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"webhook.admin.service.js","sourceRoot":"","sources":["../src/webhook.admin.service.ts"],"names":[],"mappings":";;;;;;;;;;;;AAAA,2CAA4C;AAC5C,qFAA+E;AAC/E,qFAA+E;
|
|
1
|
+
{"version":3,"file":"webhook.admin.service.js","sourceRoot":"","sources":["../src/webhook.admin.service.ts"],"names":[],"mappings":";;;;;;;;;;;;AAAA,2CAA4C;AAC5C,qFAA+E;AAC/E,qFAA+E;AAc/E;;;GAGG;AAEI,IAAM,mBAAmB,GAAzB,MAAM,mBAAmB;IAEX;IACA;IAFnB,YACmB,SAAsC,EACtC,UAAuC;QADvC,cAAS,GAAT,SAAS,CAA6B;QACtC,eAAU,GAAV,UAAU,CAA6B;IACvD,CAAC;IAEJ,KAAK,CAAC,cAAc,CAAC,GAAsB;QACzC,OAAO,IAAI,CAAC,SAAS,CAAC,cAAc,CAAC,GAAG,CAAC,CAAC;IAC5C,CAAC;IAED,KAAK,CAAC,aAAa,CAAC,QAAiB;QACnC,OAAO,IAAI,CAAC,SAAS,CAAC,aAAa,CAAC,QAAQ,CAAC,CAAC;IAChD,CAAC;IAED,KAAK,CAAC,WAAW,CAAC,UAAkB;QAClC,OAAO,IAAI,CAAC,SAAS,CAAC,WAAW,CAAC,UAAU,CAAC,CAAC;IAChD,CAAC;IAED,KAAK,CAAC,cAAc,CAClB,UAAkB,EAClB,GAAsB;QAEtB,OAAO,IAAI,CAAC,SAAS,CAAC,cAAc,CAAC,UAAU,EAAE,GAAG,CAAC,CAAC;IACxD,CAAC;IAED,KAAK,CAAC,YAAY,CAChB,UAAkB,EAClB,GAA4B;QAE5B,OAAO,IAAI,CAAC,SAAS,CAAC,YAAY,CAAC,UAAU,EAAE,GAAG,CAAC,CAAC;IACtD,CAAC;IAED,KAAK,CAAC,cAAc,CAAC,UAAkB;QACrC,OAAO,IAAI,CAAC,SAAS,CAAC,cAAc,CAAC,UAAU,CAAC,CAAC;IACnD,CAAC;IAED,KAAK,CAAC,eAAe,CACnB,UAAkB,EAClB,OAA4B;QAE5B,OAAO,IAAI,CAAC,UAAU,CAAC,eAAe,CAAC,UAAU,EAAE,OAAO,CAAC,CAAC;IAC9D,CAAC;IAED,KAAK,CAAC,mBAAmB,CAAC,UAAkB;QAC1C,OAAO,IAAI,CAAC,UAAU,CAAC,mBAAmB,CAAC,UAAU,CAAC,CAAC;IACzD,CAAC;IAED,KAAK,CAAC,aAAa,CAAC,UAAkB;QACpC,OAAO,IAAI,CAAC,UAAU,CAAC,aAAa,CAAC,UAAU,CAAC,CAAC;IACnD,CAAC;IAED,KAAK,CAAC,aAAa,CAAC,UAAkB;QACpC,OAAO,IAAI,CAAC,SAAS,CAAC,aAAa,CAAC,UAAU,CAAC,CAAC;IAClD,CAAC;CACF,CAAA;AAtDY,kDAAmB;8BAAnB,mBAAmB;IAD/B,IAAA,mBAAU,GAAE;qCAGmB,4DAA2B;QAC1B,4DAA2B;GAH/C,mBAAmB,CAsD/B"}
|
|
@@ -1,5 +1,9 @@
|
|
|
1
1
|
import { WebhookModuleOptions } from './interfaces/webhook-options.interface';
|
|
2
2
|
import { WebhookEndpointRepository } from './ports/webhook-endpoint.repository';
|
|
3
|
+
interface DeliveryEndpointMeta {
|
|
4
|
+
tenantId: string | null;
|
|
5
|
+
url: string;
|
|
6
|
+
}
|
|
3
7
|
export declare class WebhookCircuitBreaker {
|
|
4
8
|
private readonly endpointRepo;
|
|
5
9
|
private readonly options;
|
|
@@ -7,10 +11,8 @@ export declare class WebhookCircuitBreaker {
|
|
|
7
11
|
private readonly failureThreshold;
|
|
8
12
|
private readonly cooldownMinutes;
|
|
9
13
|
constructor(endpointRepo: WebhookEndpointRepository, options: WebhookModuleOptions);
|
|
10
|
-
afterDelivery(endpointId: string, success: boolean, meta
|
|
11
|
-
tenantId: string | null;
|
|
12
|
-
url: string;
|
|
13
|
-
}): Promise<void>;
|
|
14
|
+
afterDelivery(endpointId: string, success: boolean, meta: DeliveryEndpointMeta): Promise<void>;
|
|
14
15
|
recoverEligibleEndpoints(): Promise<number>;
|
|
15
16
|
}
|
|
17
|
+
export {};
|
|
16
18
|
//# sourceMappingURL=webhook.circuit-breaker.d.ts.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"webhook.circuit-breaker.d.ts","sourceRoot":"","sources":["../src/webhook.circuit-breaker.ts"],"names":[],"mappings":"
|
|
1
|
+
{"version":3,"file":"webhook.circuit-breaker.d.ts","sourceRoot":"","sources":["../src/webhook.circuit-breaker.ts"],"names":[],"mappings":"AAQA,OAAO,EAAE,oBAAoB,EAAE,MAAM,wCAAwC,CAAC;AAC9E,OAAO,EAAE,yBAAyB,EAAE,MAAM,qCAAqC,CAAC;AAEhF,UAAU,oBAAoB;IAC5B,QAAQ,EAAE,MAAM,GAAG,IAAI,CAAC;IACxB,GAAG,EAAE,MAAM,CAAC;CACb;AAED,qBACa,qBAAqB;IAO9B,OAAO,CAAC,QAAQ,CAAC,YAAY;IAE7B,OAAO,CAAC,QAAQ,CAAC,OAAO;IAR1B,OAAO,CAAC,QAAQ,CAAC,MAAM,CAA0C;IACjE,OAAO,CAAC,QAAQ,CAAC,gBAAgB,CAAS;IAC1C,OAAO,CAAC,QAAQ,CAAC,eAAe,CAAS;gBAItB,YAAY,EAAE,yBAAyB,EAEvC,OAAO,EAAE,oBAAoB;IAQ1C,aAAa,CACjB,UAAU,EAAE,MAAM,EAClB,OAAO,EAAE,OAAO,EAChB,IAAI,EAAE,oBAAoB,GACzB,OAAO,CAAC,IAAI,CAAC;IAkCV,wBAAwB,IAAI,OAAO,CAAC,MAAM,CAAC;CASlD"}
|
|
@@ -37,16 +37,18 @@ let WebhookCircuitBreaker = WebhookCircuitBreaker_1 = class WebhookCircuitBreake
|
|
|
37
37
|
else {
|
|
38
38
|
const failures = await this.endpointRepo.incrementFailures(endpointId);
|
|
39
39
|
if (failures >= this.failureThreshold) {
|
|
40
|
-
await this.endpointRepo.disableEndpoint(endpointId,
|
|
41
|
-
|
|
42
|
-
|
|
43
|
-
|
|
44
|
-
|
|
40
|
+
const disabled = await this.endpointRepo.disableEndpoint(endpointId, webhook_constants_1.ENDPOINT_DISABLED_REASON_CONSECUTIVE_FAILURES_EXCEEDED);
|
|
41
|
+
if (!disabled)
|
|
42
|
+
return;
|
|
43
|
+
this.logger.warn(`Endpoint ${endpointId} disabled: ${webhook_constants_1.ENDPOINT_DISABLED_REASON_CONSECUTIVE_FAILURES_EXCEEDED} (threshold=${this.failureThreshold})`);
|
|
44
|
+
// Fire only on active->inactive transition to prevent duplicate notifications
|
|
45
|
+
// and still notify if a prior disable attempt failed at the exact threshold.
|
|
46
|
+
if (this.options.onEndpointDisabled) {
|
|
45
47
|
void Promise.resolve(this.options.onEndpointDisabled({
|
|
46
48
|
endpointId,
|
|
47
|
-
tenantId: meta
|
|
48
|
-
url: meta
|
|
49
|
-
reason:
|
|
49
|
+
tenantId: meta.tenantId,
|
|
50
|
+
url: meta.url,
|
|
51
|
+
reason: webhook_constants_1.ENDPOINT_DISABLED_REASON_CONSECUTIVE_FAILURES_EXCEEDED,
|
|
50
52
|
consecutiveFailures: failures,
|
|
51
53
|
})).catch((hookError) => {
|
|
52
54
|
this.logger.error(`onEndpointDisabled callback error: ${hookError}`);
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"webhook.circuit-breaker.js","sourceRoot":"","sources":["../src/webhook.circuit-breaker.ts"],"names":[],"mappings":";;;;;;;;;;;;;;;;AAAA,2CAA4D;AAC5D,
|
|
1
|
+
{"version":3,"file":"webhook.circuit-breaker.js","sourceRoot":"","sources":["../src/webhook.circuit-breaker.ts"],"names":[],"mappings":";;;;;;;;;;;;;;;;AAAA,2CAA4D;AAC5D,2DAM6B;AAUtB,IAAM,qBAAqB,6BAA3B,MAAM,qBAAqB;IAOb;IAEA;IARF,MAAM,GAAG,IAAI,eAAM,CAAC,uBAAqB,CAAC,IAAI,CAAC,CAAC;IAChD,gBAAgB,CAAS;IACzB,eAAe,CAAS;IAEzC,YAEmB,YAAuC,EAEvC,OAA6B;QAF7B,iBAAY,GAAZ,YAAY,CAA2B;QAEvC,YAAO,GAAP,OAAO,CAAsB;QAE9C,IAAI,CAAC,gBAAgB;YACnB,OAAO,CAAC,cAAc,EAAE,gBAAgB,IAAI,qDAAiC,CAAC;QAChF,IAAI,CAAC,eAAe;YAClB,OAAO,CAAC,cAAc,EAAE,eAAe,IAAI,4DAAwC,CAAC;IACxF,CAAC;IAED,KAAK,CAAC,aAAa,CACjB,UAAkB,EAClB,OAAgB,EAChB,IAA0B;QAE1B,IAAI,OAAO,EAAE,CAAC;YACZ,MAAM,IAAI,CAAC,YAAY,CAAC,aAAa,CAAC,UAAU,CAAC,CAAC;QACpD,CAAC;aAAM,CAAC;YACN,MAAM,QAAQ,GAAG,MAAM,IAAI,CAAC,YAAY,CAAC,iBAAiB,CAAC,UAAU,CAAC,CAAC;YACvE,IAAI,QAAQ,IAAI,IAAI,CAAC,gBAAgB,EAAE,CAAC;gBACtC,MAAM,QAAQ,GAAG,MAAM,IAAI,CAAC,YAAY,CAAC,eAAe,CACtD,UAAU,EACV,0EAAsD,CACvD,CAAC;gBACF,IAAI,CAAC,QAAQ;oBAAE,OAAO;gBAEtB,IAAI,CAAC,MAAM,CAAC,IAAI,CACd,YAAY,UAAU,cAAc,0EAAsD,eAAe,IAAI,CAAC,gBAAgB,GAAG,CAClI,CAAC;gBACF,8EAA8E;gBAC9E,6EAA6E;gBAC7E,IAAI,IAAI,CAAC,OAAO,CAAC,kBAAkB,EAAE,CAAC;oBACpC,KAAK,OAAO,CAAC,OAAO,CAClB,IAAI,CAAC,OAAO,CAAC,kBAAkB,CAAC;wBAC9B,UAAU;wBACV,QAAQ,EAAE,IAAI,CAAC,QAAQ;wBACvB,GAAG,EAAE,IAAI,CAAC,GAAG;wBACb,MAAM,EAAE,0EAAsD;wBAC9D,mBAAmB,EAAE,QAAQ;qBAC9B,CAAC,CACH,CAAC,KAAK,CAAC,CAAC,SAAS,EAAE,EAAE;wBACpB,IAAI,CAAC,MAAM,CAAC,KAAK,CAAC,sCAAsC,SAAS,EAAE,CAAC,CAAC;oBACvE,CAAC,CAAC,CAAC;gBACL,CAAC;YACH,CAAC;QACH,CAAC;IACH,CAAC;IAED,KAAK,CAAC,wBAAwB;QAC5B,MAAM,KAAK,GAAG,MAAM,IAAI,CAAC,YAAY,CAAC,wBAAwB,CAC5D,IAAI,CAAC,eAAe,CACrB,CAAC;QACF,IAAI,KAAK,GAAG,CAAC,EAAE,CAAC;YACd,IAAI,CAAC,MAAM,CAAC,GAAG,CAAC,aAAa,KAAK,6BAA6B,CAAC,CAAC;QACnE,CAAC;QACD,OAAO,KAAK,CAAC;IACf,CAAC;CACF,CAAA;AAhEY,sDAAqB;gCAArB,qBAAqB;IADjC,IAAA,mBAAU,GAAE;IAOR,WAAA,IAAA,eAAM,EAAC,+CAA2B,CAAC,CAAA;IAEnC,WAAA,IAAA,eAAM,EAAC,0CAAsB,CAAC,CAAA;;GARtB,qBAAqB,CAgEjC"}
|
|
@@ -3,15 +3,22 @@ export declare const WEBHOOK_EVENT_REPOSITORY = "WEBHOOK_EVENT_REPOSITORY";
|
|
|
3
3
|
export declare const WEBHOOK_ENDPOINT_REPOSITORY = "WEBHOOK_ENDPOINT_REPOSITORY";
|
|
4
4
|
export declare const WEBHOOK_DELIVERY_REPOSITORY = "WEBHOOK_DELIVERY_REPOSITORY";
|
|
5
5
|
export declare const WEBHOOK_HTTP_CLIENT = "WEBHOOK_HTTP_CLIENT";
|
|
6
|
+
export declare const WEBHOOK_SECRET_VAULT = "WEBHOOK_SECRET_VAULT";
|
|
6
7
|
/** Svix/Stripe-style exponential backoff schedule (seconds) */
|
|
7
|
-
export declare const DEFAULT_BACKOFF_SCHEDULE:
|
|
8
|
+
export declare const DEFAULT_BACKOFF_SCHEDULE: readonly [30, 300, 1800, 7200, 86400];
|
|
8
9
|
export declare const DEFAULT_DELIVERY_TIMEOUT = 10000;
|
|
9
10
|
export declare const DEFAULT_MAX_RETRIES = 5;
|
|
10
11
|
export declare const DEFAULT_JITTER_FACTOR = 0.1;
|
|
11
12
|
export declare const DEFAULT_CIRCUIT_BREAKER_THRESHOLD = 5;
|
|
12
13
|
export declare const DEFAULT_CIRCUIT_BREAKER_COOLDOWN_MINUTES = 60;
|
|
14
|
+
export declare const ENDPOINT_DISABLED_REASON_CONSECUTIVE_FAILURES_EXCEEDED: "consecutive_failures_exceeded";
|
|
15
|
+
export type EndpointDisabledReason = typeof ENDPOINT_DISABLED_REASON_CONSECUTIVE_FAILURES_EXCEEDED;
|
|
13
16
|
export declare const DEFAULT_POLLING_INTERVAL = 5000;
|
|
14
17
|
export declare const DEFAULT_POLLING_BATCH_SIZE = 50;
|
|
15
18
|
export declare const DEFAULT_STALE_SENDING_MINUTES = 5;
|
|
16
|
-
|
|
19
|
+
/** Max JavaScript string length (UTF-16 code units) retained for response bodies. */
|
|
20
|
+
export declare const RESPONSE_BODY_MAX_LENGTH = 4096;
|
|
21
|
+
/** Mirrors RESPONSE_BODY_MAX_LENGTH for attempt logs; kept separate for future schema divergence. */
|
|
22
|
+
export declare const ATTEMPT_RESPONSE_BODY_MAX_LENGTH = 4096;
|
|
23
|
+
export declare const DEFAULT_USER_AGENT: string;
|
|
17
24
|
//# sourceMappingURL=webhook.constants.d.ts.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"webhook.constants.d.ts","sourceRoot":"","sources":["../src/webhook.constants.ts"],"names":[],"mappings":"AAAA,eAAO,MAAM,sBAAsB,2BAA2B,CAAC;AAE/D,eAAO,MAAM,wBAAwB,6BAA6B,CAAC;AACnE,eAAO,MAAM,2BAA2B,gCAAgC,CAAC;AACzE,eAAO,MAAM,2BAA2B,gCAAgC,CAAC;AACzE,eAAO,MAAM,mBAAmB,wBAAwB,CAAC;
|
|
1
|
+
{"version":3,"file":"webhook.constants.d.ts","sourceRoot":"","sources":["../src/webhook.constants.ts"],"names":[],"mappings":"AAAA,eAAO,MAAM,sBAAsB,2BAA2B,CAAC;AAE/D,eAAO,MAAM,wBAAwB,6BAA6B,CAAC;AACnE,eAAO,MAAM,2BAA2B,gCAAgC,CAAC;AACzE,eAAO,MAAM,2BAA2B,gCAAgC,CAAC;AACzE,eAAO,MAAM,mBAAmB,wBAAwB,CAAC;AACzD,eAAO,MAAM,oBAAoB,yBAAyB,CAAC;AAI3D,+DAA+D;AAC/D,eAAO,MAAM,wBAAwB,uCAM1B,CAAC;AAEZ,eAAO,MAAM,wBAAwB,QAAS,CAAC;AAC/C,eAAO,MAAM,mBAAmB,IAAI,CAAC;AACrC,eAAO,MAAM,qBAAqB,MAAM,CAAC;AAEzC,eAAO,MAAM,iCAAiC,IAAI,CAAC;AACnD,eAAO,MAAM,wCAAwC,KAAK,CAAC;AAC3D,eAAO,MAAM,sDAAsD,EACjE,+BAAwC,CAAC;AAC3C,MAAM,MAAM,sBAAsB,GAChC,OAAO,sDAAsD,CAAC;AAEhE,eAAO,MAAM,wBAAwB,OAAQ,CAAC;AAC9C,eAAO,MAAM,0BAA0B,KAAK,CAAC;AAC7C,eAAO,MAAM,6BAA6B,IAAI,CAAC;AAE/C,qFAAqF;AACrF,eAAO,MAAM,wBAAwB,OAAO,CAAC;AAC7C,qGAAqG;AACrG,eAAO,MAAM,gCAAgC,OAA2B,CAAC;AACzE,eAAO,MAAM,kBAAkB,QAAwC,CAAC"}
|
|
@@ -1,26 +1,33 @@
|
|
|
1
1
|
"use strict";
|
|
2
2
|
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
-
exports.RESPONSE_BODY_MAX_LENGTH = exports.DEFAULT_STALE_SENDING_MINUTES = exports.DEFAULT_POLLING_BATCH_SIZE = exports.DEFAULT_POLLING_INTERVAL = exports.DEFAULT_CIRCUIT_BREAKER_COOLDOWN_MINUTES = exports.DEFAULT_CIRCUIT_BREAKER_THRESHOLD = exports.DEFAULT_JITTER_FACTOR = exports.DEFAULT_MAX_RETRIES = exports.DEFAULT_DELIVERY_TIMEOUT = exports.DEFAULT_BACKOFF_SCHEDULE = exports.WEBHOOK_HTTP_CLIENT = exports.WEBHOOK_DELIVERY_REPOSITORY = exports.WEBHOOK_ENDPOINT_REPOSITORY = exports.WEBHOOK_EVENT_REPOSITORY = exports.WEBHOOK_MODULE_OPTIONS = void 0;
|
|
3
|
+
exports.DEFAULT_USER_AGENT = exports.ATTEMPT_RESPONSE_BODY_MAX_LENGTH = exports.RESPONSE_BODY_MAX_LENGTH = exports.DEFAULT_STALE_SENDING_MINUTES = exports.DEFAULT_POLLING_BATCH_SIZE = exports.DEFAULT_POLLING_INTERVAL = exports.ENDPOINT_DISABLED_REASON_CONSECUTIVE_FAILURES_EXCEEDED = exports.DEFAULT_CIRCUIT_BREAKER_COOLDOWN_MINUTES = exports.DEFAULT_CIRCUIT_BREAKER_THRESHOLD = exports.DEFAULT_JITTER_FACTOR = exports.DEFAULT_MAX_RETRIES = exports.DEFAULT_DELIVERY_TIMEOUT = exports.DEFAULT_BACKOFF_SCHEDULE = exports.WEBHOOK_SECRET_VAULT = exports.WEBHOOK_HTTP_CLIENT = exports.WEBHOOK_DELIVERY_REPOSITORY = exports.WEBHOOK_ENDPOINT_REPOSITORY = exports.WEBHOOK_EVENT_REPOSITORY = exports.WEBHOOK_MODULE_OPTIONS = void 0;
|
|
4
4
|
exports.WEBHOOK_MODULE_OPTIONS = 'WEBHOOK_MODULE_OPTIONS';
|
|
5
5
|
exports.WEBHOOK_EVENT_REPOSITORY = 'WEBHOOK_EVENT_REPOSITORY';
|
|
6
6
|
exports.WEBHOOK_ENDPOINT_REPOSITORY = 'WEBHOOK_ENDPOINT_REPOSITORY';
|
|
7
7
|
exports.WEBHOOK_DELIVERY_REPOSITORY = 'WEBHOOK_DELIVERY_REPOSITORY';
|
|
8
8
|
exports.WEBHOOK_HTTP_CLIENT = 'WEBHOOK_HTTP_CLIENT';
|
|
9
|
+
exports.WEBHOOK_SECRET_VAULT = 'WEBHOOK_SECRET_VAULT';
|
|
10
|
+
const { version: PACKAGE_VERSION } = require('../package.json');
|
|
9
11
|
/** Svix/Stripe-style exponential backoff schedule (seconds) */
|
|
10
|
-
exports.DEFAULT_BACKOFF_SCHEDULE = [
|
|
12
|
+
exports.DEFAULT_BACKOFF_SCHEDULE = Object.freeze([
|
|
11
13
|
30, // 30 seconds
|
|
12
14
|
300, // 5 minutes
|
|
13
15
|
1800, // 30 minutes
|
|
14
16
|
7200, // 2 hours
|
|
15
17
|
86400, // 24 hours
|
|
16
|
-
];
|
|
18
|
+
]);
|
|
17
19
|
exports.DEFAULT_DELIVERY_TIMEOUT = 10_000;
|
|
18
20
|
exports.DEFAULT_MAX_RETRIES = 5;
|
|
19
21
|
exports.DEFAULT_JITTER_FACTOR = 0.1;
|
|
20
22
|
exports.DEFAULT_CIRCUIT_BREAKER_THRESHOLD = 5;
|
|
21
23
|
exports.DEFAULT_CIRCUIT_BREAKER_COOLDOWN_MINUTES = 60;
|
|
24
|
+
exports.ENDPOINT_DISABLED_REASON_CONSECUTIVE_FAILURES_EXCEEDED = 'consecutive_failures_exceeded';
|
|
22
25
|
exports.DEFAULT_POLLING_INTERVAL = 5_000;
|
|
23
26
|
exports.DEFAULT_POLLING_BATCH_SIZE = 50;
|
|
24
27
|
exports.DEFAULT_STALE_SENDING_MINUTES = 5;
|
|
25
|
-
|
|
28
|
+
/** Max JavaScript string length (UTF-16 code units) retained for response bodies. */
|
|
29
|
+
exports.RESPONSE_BODY_MAX_LENGTH = 4096;
|
|
30
|
+
/** Mirrors RESPONSE_BODY_MAX_LENGTH for attempt logs; kept separate for future schema divergence. */
|
|
31
|
+
exports.ATTEMPT_RESPONSE_BODY_MAX_LENGTH = exports.RESPONSE_BODY_MAX_LENGTH;
|
|
32
|
+
exports.DEFAULT_USER_AGENT = `@nestarc/webhook/${PACKAGE_VERSION}`;
|
|
26
33
|
//# sourceMappingURL=webhook.constants.js.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"webhook.constants.js","sourceRoot":"","sources":["../src/webhook.constants.ts"],"names":[],"mappings":";;;AAAa,QAAA,sBAAsB,GAAG,wBAAwB,CAAC;AAElD,QAAA,wBAAwB,GAAG,0BAA0B,CAAC;AACtD,QAAA,2BAA2B,GAAG,6BAA6B,CAAC;AAC5D,QAAA,2BAA2B,GAAG,6BAA6B,CAAC;AAC5D,QAAA,mBAAmB,GAAG,qBAAqB,CAAC;
|
|
1
|
+
{"version":3,"file":"webhook.constants.js","sourceRoot":"","sources":["../src/webhook.constants.ts"],"names":[],"mappings":";;;AAAa,QAAA,sBAAsB,GAAG,wBAAwB,CAAC;AAElD,QAAA,wBAAwB,GAAG,0BAA0B,CAAC;AACtD,QAAA,2BAA2B,GAAG,6BAA6B,CAAC;AAC5D,QAAA,2BAA2B,GAAG,6BAA6B,CAAC;AAC5D,QAAA,mBAAmB,GAAG,qBAAqB,CAAC;AAC5C,QAAA,oBAAoB,GAAG,sBAAsB,CAAC;AAE3D,MAAM,EAAE,OAAO,EAAE,eAAe,EAAE,GAAG,OAAO,CAAC,iBAAiB,CAAwB,CAAC;AAEvF,+DAA+D;AAClD,QAAA,wBAAwB,GAAG,MAAM,CAAC,MAAM,CAAC;IACpD,EAAE,EAAM,aAAa;IACrB,GAAG,EAAK,YAAY;IACpB,IAAI,EAAI,aAAa;IACrB,IAAI,EAAI,UAAU;IAClB,KAAK,EAAG,WAAW;CACX,CAAC,CAAC;AAEC,QAAA,wBAAwB,GAAG,MAAM,CAAC;AAClC,QAAA,mBAAmB,GAAG,CAAC,CAAC;AACxB,QAAA,qBAAqB,GAAG,GAAG,CAAC;AAE5B,QAAA,iCAAiC,GAAG,CAAC,CAAC;AACtC,QAAA,wCAAwC,GAAG,EAAE,CAAC;AAC9C,QAAA,sDAAsD,GACjE,+BAAwC,CAAC;AAI9B,QAAA,wBAAwB,GAAG,KAAK,CAAC;AACjC,QAAA,0BAA0B,GAAG,EAAE,CAAC;AAChC,QAAA,6BAA6B,GAAG,CAAC,CAAC;AAE/C,qFAAqF;AACxE,QAAA,wBAAwB,GAAG,IAAI,CAAC;AAC7C,qGAAqG;AACxF,QAAA,gCAAgC,GAAG,gCAAwB,CAAC;AAC5D,QAAA,kBAAkB,GAAG,oBAAoB,eAAe,EAAE,CAAC"}
|
|
@@ -15,11 +15,15 @@ export declare class WebhookDeliveryWorker implements OnModuleDestroy {
|
|
|
15
15
|
private readonly staleSendingMinutes;
|
|
16
16
|
private isShuttingDown;
|
|
17
17
|
private isPolling;
|
|
18
|
+
private activePollCycle;
|
|
18
19
|
private activeDeliveries;
|
|
19
20
|
constructor(deliveryRepo: WebhookDeliveryRepository, dispatcher: WebhookDispatcher, retryPolicy: WebhookRetryPolicy, circuitBreaker: WebhookCircuitBreaker, options: WebhookModuleOptions);
|
|
20
21
|
poll(): Promise<void>;
|
|
22
|
+
private runPollCycle;
|
|
21
23
|
private processDelivery;
|
|
22
24
|
private fireDeliveryFailedHook;
|
|
25
|
+
private classifyResultFailure;
|
|
26
|
+
private logError;
|
|
23
27
|
onModuleDestroy(): Promise<void>;
|
|
24
28
|
}
|
|
25
29
|
//# sourceMappingURL=webhook.delivery-worker.d.ts.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"webhook.delivery-worker.d.ts","sourceRoot":"","sources":["../src/webhook.delivery-worker.ts"],"names":[],"mappings":"AAAA,OAAO,EAA8B,eAAe,EAAE,MAAM,gBAAgB,CAAC;AAC7E,OAAO,EAAE,qBAAqB,EAAE,MAAM,2BAA2B,CAAC;AAClE,OAAO,EAAE,iBAAiB,EAAE,MAAM,sBAAsB,CAAC;AACzD,OAAO,EAAE,kBAAkB,EAAE,MAAM,wBAAwB,CAAC;AAO5D,OAAO,EAEL,oBAAoB,EACrB,MAAM,wCAAwC,CAAC;
|
|
1
|
+
{"version":3,"file":"webhook.delivery-worker.d.ts","sourceRoot":"","sources":["../src/webhook.delivery-worker.ts"],"names":[],"mappings":"AAAA,OAAO,EAA8B,eAAe,EAAE,MAAM,gBAAgB,CAAC;AAC7E,OAAO,EAAE,qBAAqB,EAAE,MAAM,2BAA2B,CAAC;AAClE,OAAO,EAAE,iBAAiB,EAAE,MAAM,sBAAsB,CAAC;AACzD,OAAO,EAAE,kBAAkB,EAAE,MAAM,wBAAwB,CAAC;AAO5D,OAAO,EAEL,oBAAoB,EACrB,MAAM,wCAAwC,CAAC;AAEhD,OAAO,EAEL,yBAAyB,EAC1B,MAAM,qCAAqC,CAAC;AAa7C,qBACa,qBAAsB,YAAW,eAAe;IAWzD,OAAO,CAAC,QAAQ,CAAC,YAAY;IAC7B,OAAO,CAAC,QAAQ,CAAC,UAAU;IAC3B,OAAO,CAAC,QAAQ,CAAC,WAAW;IAC5B,OAAO,CAAC,QAAQ,CAAC,cAAc;IAE/B,OAAO,CAAC,QAAQ,CAAC,OAAO;IAf1B,OAAO,CAAC,QAAQ,CAAC,MAAM,CAA0C;IACjE,OAAO,CAAC,QAAQ,CAAC,SAAS,CAAS;IACnC,OAAO,CAAC,QAAQ,CAAC,mBAAmB,CAAS;IAC7C,OAAO,CAAC,cAAc,CAAS;IAC/B,OAAO,CAAC,SAAS,CAAS;IAC1B,OAAO,CAAC,eAAe,CAA8B;IACrD,OAAO,CAAC,gBAAgB,CAAK;gBAIV,YAAY,EAAE,yBAAyB,EACvC,UAAU,EAAE,iBAAiB,EAC7B,WAAW,EAAE,kBAAkB,EAC/B,cAAc,EAAE,qBAAqB,EAErC,OAAO,EAAE,oBAAoB;IAO1C,IAAI,IAAI,OAAO,CAAC,IAAI,CAAC;YAiBb,YAAY;YA6BZ,eAAe;IA2F7B,OAAO,CAAC,sBAAsB;IAyB9B,OAAO,CAAC,qBAAqB;IAM7B,OAAO,CAAC,QAAQ;IAQV,eAAe,IAAI,OAAO,CAAC,IAAI,CAAC;CAqBvC"}
|
|
@@ -31,6 +31,7 @@ let WebhookDeliveryWorker = WebhookDeliveryWorker_1 = class WebhookDeliveryWorke
|
|
|
31
31
|
staleSendingMinutes;
|
|
32
32
|
isShuttingDown = false;
|
|
33
33
|
isPolling = false;
|
|
34
|
+
activePollCycle = null;
|
|
34
35
|
activeDeliveries = 0;
|
|
35
36
|
constructor(deliveryRepo, dispatcher, retryPolicy, circuitBreaker, options) {
|
|
36
37
|
this.deliveryRepo = deliveryRepo;
|
|
@@ -48,6 +49,19 @@ let WebhookDeliveryWorker = WebhookDeliveryWorker_1 = class WebhookDeliveryWorke
|
|
|
48
49
|
if (this.isPolling)
|
|
49
50
|
return;
|
|
50
51
|
this.isPolling = true;
|
|
52
|
+
const pollCycle = this.runPollCycle();
|
|
53
|
+
this.activePollCycle = pollCycle;
|
|
54
|
+
try {
|
|
55
|
+
await pollCycle;
|
|
56
|
+
}
|
|
57
|
+
finally {
|
|
58
|
+
if (this.activePollCycle === pollCycle) {
|
|
59
|
+
this.activePollCycle = null;
|
|
60
|
+
}
|
|
61
|
+
this.isPolling = false;
|
|
62
|
+
}
|
|
63
|
+
}
|
|
64
|
+
async runPollCycle() {
|
|
51
65
|
try {
|
|
52
66
|
await this.circuitBreaker.recoverEligibleEndpoints();
|
|
53
67
|
// Recover deliveries stuck in SENDING from crashed workers
|
|
@@ -62,10 +76,7 @@ let WebhookDeliveryWorker = WebhookDeliveryWorker_1 = class WebhookDeliveryWorke
|
|
|
62
76
|
await Promise.all(deliveries.map((delivery) => this.processDelivery(delivery)));
|
|
63
77
|
}
|
|
64
78
|
catch (error) {
|
|
65
|
-
this.
|
|
66
|
-
}
|
|
67
|
-
finally {
|
|
68
|
-
this.isPolling = false;
|
|
79
|
+
this.logError('Poll cycle failed', error);
|
|
69
80
|
}
|
|
70
81
|
}
|
|
71
82
|
async processDelivery(delivery) {
|
|
@@ -77,10 +88,10 @@ let WebhookDeliveryWorker = WebhookDeliveryWorker_1 = class WebhookDeliveryWorke
|
|
|
77
88
|
if (result.success) {
|
|
78
89
|
await this.deliveryRepo.markSent(delivery.id, newAttempts, result);
|
|
79
90
|
}
|
|
80
|
-
else if (newAttempts >= delivery.
|
|
91
|
+
else if (newAttempts >= delivery.maxAttempts) {
|
|
81
92
|
await this.deliveryRepo.markFailed(delivery.id, newAttempts, result);
|
|
82
|
-
this.logger.warn(`Delivery ${delivery.id} exhausted retries (${newAttempts}/${delivery.
|
|
83
|
-
this.fireDeliveryFailedHook(delivery, newAttempts, result.error ?? null, result.statusCode ?? null,
|
|
93
|
+
this.logger.warn(`Delivery ${delivery.id} exhausted retries (${newAttempts}/${delivery.maxAttempts})`);
|
|
94
|
+
this.fireDeliveryFailedHook(delivery, newAttempts, result.error ?? null, result.statusCode ?? null, this.classifyResultFailure(result));
|
|
84
95
|
}
|
|
85
96
|
else {
|
|
86
97
|
const nextAt = this.retryPolicy.nextAttemptAt(newAttempts);
|
|
@@ -88,14 +99,14 @@ let WebhookDeliveryWorker = WebhookDeliveryWorker_1 = class WebhookDeliveryWorke
|
|
|
88
99
|
}
|
|
89
100
|
// Circuit breaker — failure here must NOT revert delivery state
|
|
90
101
|
try {
|
|
91
|
-
await this.circuitBreaker.afterDelivery(delivery.
|
|
102
|
+
await this.circuitBreaker.afterDelivery(delivery.endpointId, result.success, { tenantId: delivery.tenantId, url: delivery.url });
|
|
92
103
|
}
|
|
93
104
|
catch (cbError) {
|
|
94
|
-
this.
|
|
105
|
+
this.logError(`Circuit breaker update failed for ${delivery.endpointId}`, cbError);
|
|
95
106
|
}
|
|
96
107
|
}
|
|
97
108
|
catch (error) {
|
|
98
|
-
this.
|
|
109
|
+
this.logError(`Delivery ${delivery.id} processing error`, error);
|
|
99
110
|
// Increment attempts and apply backoff — never reset without accounting
|
|
100
111
|
try {
|
|
101
112
|
const newAttempts = delivery.attempts + 1;
|
|
@@ -104,9 +115,9 @@ let WebhookDeliveryWorker = WebhookDeliveryWorker_1 = class WebhookDeliveryWorke
|
|
|
104
115
|
latencyMs: 0,
|
|
105
116
|
error: error instanceof Error ? error.message : String(error),
|
|
106
117
|
};
|
|
107
|
-
if (newAttempts >= delivery.
|
|
118
|
+
if (newAttempts >= delivery.maxAttempts) {
|
|
108
119
|
await this.deliveryRepo.markFailed(delivery.id, newAttempts, errorResult);
|
|
109
|
-
this.logger.warn(`Delivery ${delivery.id} exhausted retries on exception (${newAttempts}/${delivery.
|
|
120
|
+
this.logger.warn(`Delivery ${delivery.id} exhausted retries on exception (${newAttempts}/${delivery.maxAttempts})`);
|
|
110
121
|
const meta = error instanceof webhook_url_validator_1.WebhookUrlValidationError
|
|
111
122
|
? {
|
|
112
123
|
failureKind: 'url_validation',
|
|
@@ -123,7 +134,7 @@ let WebhookDeliveryWorker = WebhookDeliveryWorker_1 = class WebhookDeliveryWorke
|
|
|
123
134
|
}
|
|
124
135
|
}
|
|
125
136
|
catch (fallbackError) {
|
|
126
|
-
this.
|
|
137
|
+
this.logError(`Delivery ${delivery.id} fallback error handling failed`, fallbackError);
|
|
127
138
|
}
|
|
128
139
|
}
|
|
129
140
|
finally {
|
|
@@ -135,27 +146,43 @@ let WebhookDeliveryWorker = WebhookDeliveryWorker_1 = class WebhookDeliveryWorke
|
|
|
135
146
|
return;
|
|
136
147
|
void Promise.resolve(this.options.onDeliveryFailed({
|
|
137
148
|
deliveryId: delivery.id,
|
|
138
|
-
endpointId: delivery.
|
|
139
|
-
eventId: delivery.
|
|
140
|
-
tenantId: delivery.
|
|
149
|
+
endpointId: delivery.endpointId,
|
|
150
|
+
eventId: delivery.eventId,
|
|
151
|
+
tenantId: delivery.tenantId,
|
|
141
152
|
attempts,
|
|
142
|
-
maxAttempts: delivery.
|
|
153
|
+
maxAttempts: delivery.maxAttempts,
|
|
143
154
|
lastError,
|
|
144
155
|
responseStatus,
|
|
145
156
|
...meta,
|
|
146
157
|
})).catch((hookError) => {
|
|
147
|
-
this.
|
|
158
|
+
this.logError('onDeliveryFailed callback error', hookError);
|
|
148
159
|
});
|
|
149
160
|
}
|
|
161
|
+
classifyResultFailure(result) {
|
|
162
|
+
return {
|
|
163
|
+
failureKind: result.statusCode == null ? 'dispatch_error' : 'http_error',
|
|
164
|
+
};
|
|
165
|
+
}
|
|
166
|
+
logError(message, error) {
|
|
167
|
+
if (error instanceof Error) {
|
|
168
|
+
this.logger.error(`${message}: ${error.message}`, error.stack);
|
|
169
|
+
return;
|
|
170
|
+
}
|
|
171
|
+
this.logger.error(`${message}: ${String(error)}`);
|
|
172
|
+
}
|
|
150
173
|
async onModuleDestroy() {
|
|
151
174
|
this.isShuttingDown = true;
|
|
152
175
|
this.logger.log('Shutting down delivery worker...');
|
|
153
176
|
const deadline = Date.now() + 30_000;
|
|
154
|
-
while (this.activeDeliveries > 0 &&
|
|
155
|
-
|
|
177
|
+
while ((this.activePollCycle || this.activeDeliveries > 0) &&
|
|
178
|
+
Date.now() < deadline) {
|
|
179
|
+
await Promise.race([
|
|
180
|
+
this.activePollCycle ?? new Promise((resolve) => setTimeout(resolve, 100)),
|
|
181
|
+
new Promise((resolve) => setTimeout(resolve, 100)),
|
|
182
|
+
]);
|
|
156
183
|
}
|
|
157
|
-
if (this.activeDeliveries > 0) {
|
|
158
|
-
this.logger.warn(`Shutdown with ${this.activeDeliveries} active deliveries`);
|
|
184
|
+
if (this.activePollCycle || this.activeDeliveries > 0) {
|
|
185
|
+
this.logger.warn(`Shutdown with ${this.activeDeliveries} active deliveries and an unfinished poll cycle`);
|
|
159
186
|
}
|
|
160
187
|
}
|
|
161
188
|
};
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"webhook.delivery-worker.js","sourceRoot":"","sources":["../src/webhook.delivery-worker.ts"],"names":[],"mappings":";;;;;;;;;;;;;;;;AAAA,2CAA6E;AAC7E,uEAAkE;AAClE,6DAAyD;AACzD,iEAA4D;AAC5D,2DAK6B;
|
|
1
|
+
{"version":3,"file":"webhook.delivery-worker.js","sourceRoot":"","sources":["../src/webhook.delivery-worker.ts"],"names":[],"mappings":"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"}
|
|
@@ -10,5 +10,6 @@ export declare class WebhookDispatcher {
|
|
|
10
10
|
private readonly allowPrivateUrls;
|
|
11
11
|
constructor(signer: WebhookSigner, httpClient: WebhookHttpClient, options: WebhookModuleOptions);
|
|
12
12
|
dispatch(delivery: PendingDelivery): Promise<DeliveryResult>;
|
|
13
|
+
private parseDeliveryUrl;
|
|
13
14
|
}
|
|
14
15
|
//# sourceMappingURL=webhook.dispatcher.d.ts.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"webhook.dispatcher.d.ts","sourceRoot":"","sources":["../src/webhook.dispatcher.ts"],"names":[],"mappings":"AACA,OAAO,EAAE,aAAa,EAAE,MAAM,kBAAkB,CAAC;
|
|
1
|
+
{"version":3,"file":"webhook.dispatcher.d.ts","sourceRoot":"","sources":["../src/webhook.dispatcher.ts"],"names":[],"mappings":"AACA,OAAO,EAAE,aAAa,EAAE,MAAM,kBAAkB,CAAC;AAMjD,OAAO,EAAE,oBAAoB,EAAE,MAAM,wCAAwC,CAAC;AAC9E,OAAO,EAAE,iBAAiB,EAAE,MAAM,6BAA6B,CAAC;AAChE,OAAO,EAAE,cAAc,EAAE,MAAM,yCAAyC,CAAC;AACzE,OAAO,EAAE,eAAe,EAAE,MAAM,qCAAqC,CAAC;AAMtE,qBACa,iBAAiB;IAK1B,OAAO,CAAC,QAAQ,CAAC,MAAM;IAEvB,OAAO,CAAC,QAAQ,CAAC,UAAU;IAN7B,OAAO,CAAC,QAAQ,CAAC,OAAO,CAAS;IACjC,OAAO,CAAC,QAAQ,CAAC,gBAAgB,CAAU;gBAGxB,MAAM,EAAE,aAAa,EAErB,UAAU,EAAE,iBAAiB,EAE9C,OAAO,EAAE,oBAAoB;IAMzB,QAAQ,CAAC,QAAQ,EAAE,eAAe,GAAG,OAAO,CAAC,cAAc,CAAC;IAwBlE,OAAO,CAAC,gBAAgB;CAWzB"}
|
|
@@ -16,7 +16,6 @@ exports.WebhookDispatcher = void 0;
|
|
|
16
16
|
const common_1 = require("@nestjs/common");
|
|
17
17
|
const webhook_signer_1 = require("./webhook.signer");
|
|
18
18
|
const webhook_constants_1 = require("./webhook.constants");
|
|
19
|
-
const webhook_constants_2 = require("./webhook.constants");
|
|
20
19
|
const webhook_url_validator_1 = require("./webhook.url-validator");
|
|
21
20
|
let WebhookDispatcher = class WebhookDispatcher {
|
|
22
21
|
signer;
|
|
@@ -26,23 +25,31 @@ let WebhookDispatcher = class WebhookDispatcher {
|
|
|
26
25
|
constructor(signer, httpClient, options) {
|
|
27
26
|
this.signer = signer;
|
|
28
27
|
this.httpClient = httpClient;
|
|
29
|
-
this.timeout = options.delivery?.timeout ??
|
|
28
|
+
this.timeout = options.delivery?.timeout ?? webhook_constants_1.DEFAULT_DELIVERY_TIMEOUT;
|
|
30
29
|
this.allowPrivateUrls = options.allowPrivateUrls ?? false;
|
|
31
30
|
}
|
|
32
31
|
async dispatch(delivery) {
|
|
32
|
+
const parsedUrl = this.parseDeliveryUrl(delivery.url);
|
|
33
33
|
// DNS rebinding defense — validate resolved IPs before every dispatch
|
|
34
34
|
if (!this.allowPrivateUrls) {
|
|
35
|
-
|
|
36
|
-
await (0, webhook_url_validator_1.resolveAndValidateHost)(hostname);
|
|
35
|
+
await (0, webhook_url_validator_1.resolveAndValidateHost)(parsedUrl.hostname, delivery.url);
|
|
37
36
|
}
|
|
38
37
|
const body = JSON.stringify({
|
|
39
|
-
type: delivery.
|
|
38
|
+
type: delivery.eventType,
|
|
40
39
|
data: delivery.payload,
|
|
41
40
|
});
|
|
42
41
|
const timestamp = Math.floor(Date.now() / 1000);
|
|
43
|
-
const headers = this.signer.signAll(delivery.
|
|
42
|
+
const headers = this.signer.signAll(delivery.eventId, timestamp, body, [delivery.secret, ...delivery.additionalSecrets]);
|
|
44
43
|
return this.httpClient.post(delivery.url, headers, body, this.timeout);
|
|
45
44
|
}
|
|
45
|
+
parseDeliveryUrl(url) {
|
|
46
|
+
try {
|
|
47
|
+
return new URL(url);
|
|
48
|
+
}
|
|
49
|
+
catch {
|
|
50
|
+
throw new webhook_url_validator_1.WebhookUrlValidationError(`Invalid webhook URL: unable to parse "${url}"`, 'parse', url);
|
|
51
|
+
}
|
|
52
|
+
}
|
|
46
53
|
};
|
|
47
54
|
exports.WebhookDispatcher = WebhookDispatcher;
|
|
48
55
|
exports.WebhookDispatcher = WebhookDispatcher = __decorate([
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"webhook.dispatcher.js","sourceRoot":"","sources":["../src/webhook.dispatcher.ts"],"names":[],"mappings":";;;;;;;;;;;;;;;AAAA,2CAAoD;AACpD,qDAAiD;AACjD,
|
|
1
|
+
{"version":3,"file":"webhook.dispatcher.js","sourceRoot":"","sources":["../src/webhook.dispatcher.ts"],"names":[],"mappings":";;;;;;;;;;;;;;;AAAA,2CAAoD;AACpD,qDAAiD;AACjD,2DAI6B;AAK7B,mEAGiC;AAG1B,IAAM,iBAAiB,GAAvB,MAAM,iBAAiB;IAKT;IAEA;IANF,OAAO,CAAS;IAChB,gBAAgB,CAAU;IAE3C,YACmB,MAAqB,EAErB,UAA6B,EAE9C,OAA6B;QAJZ,WAAM,GAAN,MAAM,CAAe;QAErB,eAAU,GAAV,UAAU,CAAmB;QAI9C,IAAI,CAAC,OAAO,GAAG,OAAO,CAAC,QAAQ,EAAE,OAAO,IAAI,4CAAwB,CAAC;QACrE,IAAI,CAAC,gBAAgB,GAAG,OAAO,CAAC,gBAAgB,IAAI,KAAK,CAAC;IAC5D,CAAC;IAED,KAAK,CAAC,QAAQ,CAAC,QAAyB;QACtC,MAAM,SAAS,GAAG,IAAI,CAAC,gBAAgB,CAAC,QAAQ,CAAC,GAAG,CAAC,CAAC;QAEtD,sEAAsE;QACtE,IAAI,CAAC,IAAI,CAAC,gBAAgB,EAAE,CAAC;YAC3B,MAAM,IAAA,8CAAsB,EAAC,SAAS,CAAC,QAAQ,EAAE,QAAQ,CAAC,GAAG,CAAC,CAAC;QACjE,CAAC;QAED,MAAM,IAAI,GAAG,IAAI,CAAC,SAAS,CAAC;YAC1B,IAAI,EAAE,QAAQ,CAAC,SAAS;YACxB,IAAI,EAAE,QAAQ,CAAC,OAAO;SACvB,CAAC,CAAC;QAEH,MAAM,SAAS,GAAG,IAAI,CAAC,KAAK,CAAC,IAAI,CAAC,GAAG,EAAE,GAAG,IAAI,CAAC,CAAC;QAChD,MAAM,OAAO,GAAG,IAAI,CAAC,MAAM,CAAC,OAAO,CACjC,QAAQ,CAAC,OAAO,EAChB,SAAS,EACT,IAAI,EACJ,CAAC,QAAQ,CAAC,MAAM,EAAE,GAAG,QAAQ,CAAC,iBAAiB,CAAC,CACjD,CAAC;QAEF,OAAO,IAAI,CAAC,UAAU,CAAC,IAAI,CAAC,QAAQ,CAAC,GAAG,EAAE,OAAO,EAAE,IAAI,EAAE,IAAI,CAAC,OAAO,CAAC,CAAC;IACzE,CAAC;IAEO,gBAAgB,CAAC,GAAW;QAClC,IAAI,CAAC;YACH,OAAO,IAAI,GAAG,CAAC,GAAG,CAAC,CAAC;QACtB,CAAC;QAAC,MAAM,CAAC;YACP,MAAM,IAAI,iDAAyB,CACjC,yCAAyC,GAAG,GAAG,EAC/C,OAAO,EACP,GAAG,CACJ,CAAC;QACJ,CAAC;IACH,CAAC;CACF,CAAA;AAlDY,8CAAiB;4BAAjB,iBAAiB;IAD7B,IAAA,mBAAU,GAAE;IAOR,WAAA,IAAA,eAAM,EAAC,uCAAmB,CAAC,CAAA;IAE3B,WAAA,IAAA,eAAM,EAAC,0CAAsB,CAAC,CAAA;qCAHN,8BAAa;GAL7B,iBAAiB,CAkD7B"}
|
|
@@ -3,7 +3,7 @@ import { WebhookModuleOptions } from './interfaces/webhook-options.interface';
|
|
|
3
3
|
import { WebhookEndpointRepository } from './ports/webhook-endpoint.repository';
|
|
4
4
|
import { WebhookEventRepository } from './ports/webhook-event.repository';
|
|
5
5
|
import { WebhookDeliveryRepository } from './ports/webhook-delivery.repository';
|
|
6
|
-
import { CreateEndpointDto, EndpointRecord, EndpointRecordWithSecret, UpdateEndpointDto } from './interfaces/webhook-endpoint.interface';
|
|
6
|
+
import { CreateEndpointDto, EndpointRecord, EndpointRecordWithSecret, RotateEndpointSecretDto, UpdateEndpointDto } from './interfaces/webhook-endpoint.interface';
|
|
7
7
|
export declare class WebhookEndpointAdminService {
|
|
8
8
|
private readonly endpointRepo;
|
|
9
9
|
private readonly eventRepo;
|
|
@@ -16,8 +16,11 @@ export declare class WebhookEndpointAdminService {
|
|
|
16
16
|
listEndpoints(tenantId?: string): Promise<EndpointRecord[]>;
|
|
17
17
|
getEndpoint(endpointId: string): Promise<EndpointRecord | null>;
|
|
18
18
|
updateEndpoint(endpointId: string, dto: UpdateEndpointDto): Promise<EndpointRecord | null>;
|
|
19
|
+
rotateSecret(endpointId: string, dto: RotateEndpointSecretDto): Promise<EndpointRecordWithSecret | null>;
|
|
19
20
|
deleteEndpoint(endpointId: string): Promise<boolean>;
|
|
20
21
|
sendTestEvent(endpointId: string): Promise<string | null>;
|
|
21
22
|
private validateBase64Secret;
|
|
23
|
+
private resolveSecret;
|
|
24
|
+
private validateRotationExpiry;
|
|
22
25
|
}
|
|
23
26
|
//# sourceMappingURL=webhook.endpoint-admin.service.d.ts.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"webhook.endpoint-admin.service.d.ts","sourceRoot":"","sources":["../src/webhook.endpoint-admin.service.ts"],"names":[],"mappings":"AACA,OAAO,EAAE,aAAa,EAAE,MAAM,kBAAkB,CAAC;AAOjD,OAAO,EAAE,oBAAoB,EAAE,MAAM,wCAAwC,CAAC;AAC9E,OAAO,EAAE,yBAAyB,EAAE,MAAM,qCAAqC,CAAC;AAChF,OAAO,EAAE,sBAAsB,EAAE,MAAM,kCAAkC,CAAC;AAC1E,OAAO,EAAE,yBAAyB,EAAE,MAAM,qCAAqC,CAAC;AAChF,OAAO,EACL,iBAAiB,EACjB,cAAc,EACd,wBAAwB,EACxB,iBAAiB,EAClB,MAAM,yCAAyC,CAAC;AAGjD,qBACa,2BAA2B;IAMpC,OAAO,CAAC,QAAQ,CAAC,YAAY;IAE7B,OAAO,CAAC,QAAQ,CAAC,SAAS;IAE1B,OAAO,CAAC,QAAQ,CAAC,YAAY;IAC7B,OAAO,CAAC,QAAQ,CAAC,MAAM;IAVzB,OAAO,CAAC,QAAQ,CAAC,MAAM,CAAgD;IACvE,OAAO,CAAC,QAAQ,CAAC,gBAAgB,CAAU;gBAIxB,YAAY,EAAE,yBAAyB,EAEvC,SAAS,EAAE,sBAAsB,EAEjC,YAAY,EAAE,yBAAyB,EACvC,MAAM,EAAE,aAAa,EAEtC,OAAO,EAAE,oBAAoB;IAKzB,cAAc,CAAC,GAAG,EAAE,iBAAiB,GAAG,OAAO,CAAC,wBAAwB,CAAC;
|
|
1
|
+
{"version":3,"file":"webhook.endpoint-admin.service.d.ts","sourceRoot":"","sources":["../src/webhook.endpoint-admin.service.ts"],"names":[],"mappings":"AACA,OAAO,EAAE,aAAa,EAAE,MAAM,kBAAkB,CAAC;AAOjD,OAAO,EAAE,oBAAoB,EAAE,MAAM,wCAAwC,CAAC;AAC9E,OAAO,EAAE,yBAAyB,EAAE,MAAM,qCAAqC,CAAC;AAChF,OAAO,EAAE,sBAAsB,EAAE,MAAM,kCAAkC,CAAC;AAC1E,OAAO,EAAE,yBAAyB,EAAE,MAAM,qCAAqC,CAAC;AAChF,OAAO,EACL,iBAAiB,EACjB,cAAc,EACd,wBAAwB,EACxB,uBAAuB,EACvB,iBAAiB,EAClB,MAAM,yCAAyC,CAAC;AAGjD,qBACa,2BAA2B;IAMpC,OAAO,CAAC,QAAQ,CAAC,YAAY;IAE7B,OAAO,CAAC,QAAQ,CAAC,SAAS;IAE1B,OAAO,CAAC,QAAQ,CAAC,YAAY;IAC7B,OAAO,CAAC,QAAQ,CAAC,MAAM;IAVzB,OAAO,CAAC,QAAQ,CAAC,MAAM,CAAgD;IACvE,OAAO,CAAC,QAAQ,CAAC,gBAAgB,CAAU;gBAIxB,YAAY,EAAE,yBAAyB,EAEvC,SAAS,EAAE,sBAAsB,EAEjC,YAAY,EAAE,yBAAyB,EACvC,MAAM,EAAE,aAAa,EAEtC,OAAO,EAAE,oBAAoB;IAKzB,cAAc,CAAC,GAAG,EAAE,iBAAiB,GAAG,OAAO,CAAC,wBAAwB,CAAC;IAoBzE,aAAa,CAAC,QAAQ,CAAC,EAAE,MAAM,GAAG,OAAO,CAAC,cAAc,EAAE,CAAC;IAI3D,WAAW,CAAC,UAAU,EAAE,MAAM,GAAG,OAAO,CAAC,cAAc,GAAG,IAAI,CAAC;IAI/D,cAAc,CAClB,UAAU,EAAE,MAAM,EAClB,GAAG,EAAE,iBAAiB,GACrB,OAAO,CAAC,cAAc,GAAG,IAAI,CAAC;IAO3B,YAAY,CAChB,UAAU,EAAE,MAAM,EAClB,GAAG,EAAE,uBAAuB,GAC3B,OAAO,CAAC,wBAAwB,GAAG,IAAI,CAAC;IAcrC,cAAc,CAAC,UAAU,EAAE,MAAM,GAAG,OAAO,CAAC,OAAO,CAAC;IAIpD,aAAa,CAAC,UAAU,EAAE,MAAM,GAAG,OAAO,CAAC,MAAM,GAAG,IAAI,CAAC;IAe/D,OAAO,CAAC,oBAAoB;IAiB5B,OAAO,CAAC,aAAa;IASrB,OAAO,CAAC,sBAAsB;CAU/B"}
|
|
@@ -36,15 +36,15 @@ let WebhookEndpointAdminService = WebhookEndpointAdminService_1 = class WebhookE
|
|
|
36
36
|
if (!this.allowPrivateUrls) {
|
|
37
37
|
await (0, webhook_url_validator_1.validateWebhookUrl)(dto.url);
|
|
38
38
|
}
|
|
39
|
-
|
|
40
|
-
|
|
41
|
-
|
|
42
|
-
|
|
43
|
-
|
|
44
|
-
|
|
45
|
-
|
|
46
|
-
|
|
47
|
-
|
|
39
|
+
const secret = this.resolveSecret(dto.secret);
|
|
40
|
+
const endpoint = await this.endpointRepo.createEndpoint({
|
|
41
|
+
url: dto.url,
|
|
42
|
+
secret,
|
|
43
|
+
events: dto.events,
|
|
44
|
+
description: dto.description ?? null,
|
|
45
|
+
metadata: dto.metadata ?? null,
|
|
46
|
+
tenantId: dto.tenantId ?? null,
|
|
47
|
+
});
|
|
48
48
|
this.logger.log(`Endpoint created: ${endpoint.id} → ${dto.url}`);
|
|
49
49
|
return endpoint;
|
|
50
50
|
}
|
|
@@ -60,6 +60,18 @@ let WebhookEndpointAdminService = WebhookEndpointAdminService_1 = class WebhookE
|
|
|
60
60
|
}
|
|
61
61
|
return this.endpointRepo.updateEndpoint(endpointId, dto);
|
|
62
62
|
}
|
|
63
|
+
async rotateSecret(endpointId, dto) {
|
|
64
|
+
this.validateRotationExpiry(dto.previousSecretExpiresAt);
|
|
65
|
+
const secret = this.resolveSecret(dto.secret);
|
|
66
|
+
const endpoint = await this.endpointRepo.rotateSecret(endpointId, {
|
|
67
|
+
secret,
|
|
68
|
+
previousSecretExpiresAt: dto.previousSecretExpiresAt,
|
|
69
|
+
});
|
|
70
|
+
if (!endpoint)
|
|
71
|
+
return null;
|
|
72
|
+
this.logger.log(`Endpoint secret rotated: ${endpointId}`);
|
|
73
|
+
return { ...endpoint, secret };
|
|
74
|
+
}
|
|
63
75
|
async deleteEndpoint(endpointId) {
|
|
64
76
|
return this.endpointRepo.deleteEndpoint(endpointId);
|
|
65
77
|
}
|
|
@@ -84,6 +96,21 @@ let WebhookEndpointAdminService = WebhookEndpointAdminService_1 = class WebhookE
|
|
|
84
96
|
'Use "auto" to generate a secure secret.');
|
|
85
97
|
}
|
|
86
98
|
}
|
|
99
|
+
resolveSecret(secret) {
|
|
100
|
+
if (!secret || secret === 'auto') {
|
|
101
|
+
return this.signer.generateSecret();
|
|
102
|
+
}
|
|
103
|
+
this.validateBase64Secret(secret);
|
|
104
|
+
return secret;
|
|
105
|
+
}
|
|
106
|
+
validateRotationExpiry(expiresAt) {
|
|
107
|
+
if (!(expiresAt instanceof Date) || Number.isNaN(expiresAt.getTime())) {
|
|
108
|
+
throw new Error('Invalid rotation expiry: previousSecretExpiresAt must be a Date.');
|
|
109
|
+
}
|
|
110
|
+
if (expiresAt.getTime() <= Date.now()) {
|
|
111
|
+
throw new Error('Invalid rotation expiry: previousSecretExpiresAt must be in the future.');
|
|
112
|
+
}
|
|
113
|
+
}
|
|
87
114
|
};
|
|
88
115
|
exports.WebhookEndpointAdminService = WebhookEndpointAdminService;
|
|
89
116
|
exports.WebhookEndpointAdminService = WebhookEndpointAdminService = WebhookEndpointAdminService_1 = __decorate([
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"webhook.endpoint-admin.service.js","sourceRoot":"","sources":["../src/webhook.endpoint-admin.service.ts"],"names":[],"mappings":";;;;;;;;;;;;;;;;AAAA,2CAA4D;AAC5D,qDAAiD;AACjD,2DAK6B;
|
|
1
|
+
{"version":3,"file":"webhook.endpoint-admin.service.js","sourceRoot":"","sources":["../src/webhook.endpoint-admin.service.ts"],"names":[],"mappings":"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"}
|