@dereekb/zoho 13.3.0 → 13.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.
@@ -1,14 +1,16 @@
1
1
  {
2
2
  "name": "@dereekb/zoho/nestjs",
3
- "version": "13.3.0",
3
+ "version": "13.4.0",
4
4
  "peerDependencies": {
5
- "@dereekb/util": "13.3.0",
6
- "@dereekb/zoho": "13.3.0",
7
- "@nestjs/common": "^11.0.0",
8
- "@nestjs/config": "^4.0.0"
5
+ "@dereekb/nestjs": "13.4.0",
6
+ "@dereekb/util": "13.4.0",
7
+ "@dereekb/zoho": "13.4.0",
8
+ "@nestjs/common": "^11.1.16",
9
+ "@nestjs/config": "^4.0.3",
10
+ "express": "^5.0.0"
9
11
  },
10
12
  "devDependencies": {
11
- "@nestjs/testing": "^11.0.0",
13
+ "@nestjs/testing": "^11.1.14",
12
14
  "date-fns": "^4.0.0"
13
15
  },
14
16
  "exports": {
@@ -1,3 +1,4 @@
1
1
  export * from './sign.api';
2
2
  export * from './sign.config';
3
3
  export * from './sign.module';
4
+ export * from './webhook';
@@ -0,0 +1,6 @@
1
+ export * from './webhook.zoho.sign';
2
+ export * from './webhook.zoho.sign.config';
3
+ export * from './webhook.zoho.sign.controller';
4
+ export * from './webhook.zoho.sign.module';
5
+ export * from './webhook.zoho.sign.service';
6
+ export * from './webhook.zoho.sign.verify';
@@ -0,0 +1,11 @@
1
+ export declare const ZOHO_SIGN_WEBHOOK_SECRET_TOKEN_ENV_VAR = "ZOHO_SIGN_WEBHOOK_SECRET_TOKEN";
2
+ export interface ZohoSignWebhookConfig {
3
+ readonly webhookSecret: string;
4
+ }
5
+ /**
6
+ * Configuration for the Zoho Sign webhook service.
7
+ */
8
+ export declare abstract class ZohoSignWebhookServiceConfig {
9
+ readonly zohoSignWebhook: ZohoSignWebhookConfig;
10
+ static assertValidConfig(config: ZohoSignWebhookServiceConfig): void;
11
+ }
@@ -0,0 +1,8 @@
1
+ import { type RawBodyBuffer } from '@dereekb/nestjs';
2
+ import { type Request } from 'express';
3
+ import { ZohoSignWebhookService } from './webhook.zoho.sign.service';
4
+ export declare class ZohoSignWebhookController {
5
+ private readonly _zohoSignWebhookService;
6
+ constructor(zohoSignWebhookService: ZohoSignWebhookService);
7
+ handleZohoSignWebhook(req: Request, rawBody: RawBodyBuffer): Promise<void>;
8
+ }
@@ -0,0 +1,124 @@
1
+ import { type HandlerBindAccessor, type HandlerMappedSetFunction, type Handler, type EmailAddress } from '@dereekb/util';
2
+ import { type ZohoSignRequestId, type ZohoSignDocumentId, type ZohoSignActionId, type ZohoSignRequestStatus, type ZohoSignRequestTypeId } from '@dereekb/zoho';
3
+ /**
4
+ * Zoho Sign webhook operation type constants.
5
+ *
6
+ * These correspond to the `operation_type` field in the webhook `notifications` payload.
7
+ */
8
+ export type ZohoSignWebhookOperationType = 'RequestSubmitted' | 'RequestViewed' | 'RequestSigningSuccess' | 'RequestCompleted' | 'RequestRejected' | 'RequestRecalled' | 'RequestForwarded' | 'RequestExpired';
9
+ /**
10
+ * The `notifications` portion of a Zoho Sign webhook payload.
11
+ *
12
+ * Contains details about the action performed on the document.
13
+ */
14
+ export interface ZohoSignWebhookNotification {
15
+ /**
16
+ * Email address of the person who performed the operation.
17
+ */
18
+ readonly performed_by_email: EmailAddress;
19
+ /**
20
+ * Name of the person who performed the operation.
21
+ */
22
+ readonly performed_by_name: string;
23
+ /**
24
+ * Timestamp of the operation in Java milliseconds.
25
+ */
26
+ readonly performed_at: number;
27
+ /**
28
+ * Reason stated for the operation, if applicable.
29
+ */
30
+ readonly reason?: string;
31
+ /**
32
+ * Short description of the activity performed.
33
+ */
34
+ readonly activity: string;
35
+ /**
36
+ * The type of operation that triggered this webhook.
37
+ */
38
+ readonly operation_type: ZohoSignWebhookOperationType;
39
+ /**
40
+ * Sign action ID of the signer.
41
+ *
42
+ * Present for signer-related actions: RequestViewed, RequestSigningSuccess,
43
+ * RequestRejected, and RequestForwarded.
44
+ */
45
+ readonly action_id?: ZohoSignActionId;
46
+ /**
47
+ * IP address captured during this operation.
48
+ */
49
+ readonly ip_address?: string;
50
+ }
51
+ /**
52
+ * A document reference within the webhook request data.
53
+ */
54
+ export interface ZohoSignWebhookDocumentRef {
55
+ readonly document_name: string;
56
+ readonly document_id: ZohoSignDocumentId;
57
+ }
58
+ /**
59
+ * The `requests` portion of a Zoho Sign webhook payload.
60
+ *
61
+ * Contains details about the document for which the webhook was triggered.
62
+ */
63
+ export interface ZohoSignWebhookRequestData {
64
+ readonly request_status: ZohoSignRequestStatus;
65
+ readonly request_name: string;
66
+ readonly request_id: ZohoSignRequestId;
67
+ readonly org_id?: string;
68
+ readonly request_type_id?: ZohoSignRequestTypeId;
69
+ readonly document_ids: ZohoSignWebhookDocumentRef[];
70
+ }
71
+ /**
72
+ * The complete webhook payload from Zoho Sign.
73
+ *
74
+ * Contains two top-level keys: `notifications` (the action details) and
75
+ * `requests` (the document details).
76
+ *
77
+ * @example
78
+ * ```json
79
+ * {
80
+ * "notifications": {
81
+ * "performed_by_email": "testuser@zoho.com",
82
+ * "performed_at": 1555062604837,
83
+ * "activity": "Document has been signed",
84
+ * "operation_type": "RequestSigningSuccess",
85
+ * "action_id": "1000000000090",
86
+ * "performed_by_name": "test user"
87
+ * },
88
+ * "requests": {
89
+ * "request_name": "NDA Document",
90
+ * "request_id": "1000000000000",
91
+ * "request_status": "inprogress",
92
+ * "document_ids": [{ "document_name": "CommonNDA.pdf", "document_id": "100000000000050" }]
93
+ * }
94
+ * }
95
+ * ```
96
+ */
97
+ export interface ZohoSignWebhookPayload {
98
+ readonly notifications: ZohoSignWebhookNotification;
99
+ readonly requests: ZohoSignWebhookRequestData;
100
+ }
101
+ /**
102
+ * A parsed Zoho Sign webhook event, providing convenient access to the operation type.
103
+ */
104
+ export type ZohoSignWebhookEvent<T extends ZohoSignWebhookOperationType = ZohoSignWebhookOperationType> = ZohoSignWebhookPayload & {
105
+ readonly operationType: T;
106
+ };
107
+ /**
108
+ * Creates a {@link ZohoSignWebhookEvent} from a raw payload.
109
+ */
110
+ export declare function zohoSignWebhookEvent(payload: ZohoSignWebhookPayload): ZohoSignWebhookEvent;
111
+ export type ZohoSignEventHandler = Handler<ZohoSignWebhookEvent, ZohoSignWebhookOperationType>;
112
+ export declare const zohoSignEventHandlerFactory: import("@dereekb/util").HandlerFactory<ZohoSignWebhookEvent<ZohoSignWebhookOperationType>, ZohoSignWebhookOperationType, boolean>;
113
+ export type ZohoSignHandlerMappedSetFunction<T extends ZohoSignWebhookOperationType = ZohoSignWebhookOperationType> = HandlerMappedSetFunction<ZohoSignWebhookEvent<T>>;
114
+ export interface ZohoSignEventHandlerConfigurer extends HandlerBindAccessor<ZohoSignWebhookEvent, ZohoSignWebhookOperationType> {
115
+ readonly handleRequestSubmitted: ZohoSignHandlerMappedSetFunction<'RequestSubmitted'>;
116
+ readonly handleRequestViewed: ZohoSignHandlerMappedSetFunction<'RequestViewed'>;
117
+ readonly handleRequestSigningSuccess: ZohoSignHandlerMappedSetFunction<'RequestSigningSuccess'>;
118
+ readonly handleRequestCompleted: ZohoSignHandlerMappedSetFunction<'RequestCompleted'>;
119
+ readonly handleRequestRejected: ZohoSignHandlerMappedSetFunction<'RequestRejected'>;
120
+ readonly handleRequestRecalled: ZohoSignHandlerMappedSetFunction<'RequestRecalled'>;
121
+ readonly handleRequestForwarded: ZohoSignHandlerMappedSetFunction<'RequestForwarded'>;
122
+ readonly handleRequestExpired: ZohoSignHandlerMappedSetFunction<'RequestExpired'>;
123
+ }
124
+ export declare const zohoSignEventHandlerConfigurerFactory: import("@dereekb/util").HandlerConfigurerFactory<ZohoSignEventHandlerConfigurer, ZohoSignWebhookEvent<ZohoSignWebhookOperationType>, ZohoSignWebhookOperationType, boolean>;
@@ -0,0 +1,13 @@
1
+ import { ZohoSignWebhookServiceConfig } from './webhook.zoho.sign.config';
2
+ import { ConfigService } from '@nestjs/config';
3
+ /**
4
+ * Reads the Zoho Sign webhook secret from the NestJS ConfigService
5
+ * and returns a validated webhook service config.
6
+ *
7
+ * @param configService - NestJS config service populated with webhook environment variables
8
+ * @returns Validated Zoho Sign webhook service configuration
9
+ * @throws {Error} If the webhook secret is not configured
10
+ */
11
+ export declare function zohoSignWebhookServiceConfigFactory(configService: ConfigService): ZohoSignWebhookServiceConfig;
12
+ export declare class ZohoSignWebhookModule {
13
+ }
@@ -0,0 +1,16 @@
1
+ import { type Request } from 'express';
2
+ import { type ZohoSignWebhookEvent, type ZohoSignWebhookOperationType } from './webhook.zoho.sign';
3
+ import { type Handler } from '@dereekb/util';
4
+ import { ZohoSignWebhookServiceConfig } from './webhook.zoho.sign.config';
5
+ /**
6
+ * Service that handles Zoho Sign webhook events.
7
+ */
8
+ export declare class ZohoSignWebhookService {
9
+ private readonly logger;
10
+ private readonly _verifier;
11
+ readonly handler: Handler<ZohoSignWebhookEvent, ZohoSignWebhookOperationType>;
12
+ readonly configure: import("@dereekb/util").HandlerConfigurer<import("./webhook.zoho.sign").ZohoSignEventHandlerConfigurer, ZohoSignWebhookEvent<ZohoSignWebhookOperationType>, ZohoSignWebhookOperationType, boolean>;
13
+ constructor(zohoSignWebhookServiceConfig: ZohoSignWebhookServiceConfig);
14
+ updateForWebhook(req: Request, rawBody: Buffer): Promise<void>;
15
+ updateForZohoSignEvent(event: ZohoSignWebhookEvent): Promise<void>;
16
+ }
@@ -0,0 +1,45 @@
1
+ import { type Request } from 'express';
2
+ import { type ZohoSignWebhookEvent } from './webhook.zoho.sign';
3
+ /**
4
+ * Header name used by Zoho Sign to send the HMAC signature.
5
+ */
6
+ export declare const ZOHO_SIGN_WEBHOOK_SIGNATURE_HEADER = "x-zs-webhook-signature";
7
+ export interface ZohoSignWebhookVerificationConfig {
8
+ /**
9
+ * Secret key configured in Zoho Sign webhook settings.
10
+ */
11
+ readonly secret: string;
12
+ }
13
+ export type ZohoSignWebhookEventVerificationResult = ZohoSignWebhookEventVerificationSuccessResult | ZohoSignWebhookEventVerificationErrorResult;
14
+ export interface ZohoSignWebhookEventVerificationSuccessResult {
15
+ readonly valid: true;
16
+ readonly event: ZohoSignWebhookEvent;
17
+ }
18
+ export interface ZohoSignWebhookEventVerificationErrorResult {
19
+ readonly valid: false;
20
+ }
21
+ /**
22
+ * Function that verifies a Zoho Sign webhook event.
23
+ */
24
+ export type ZohoSignWebhookEventVerifier = (req: Request, rawBody: Buffer) => Promise<ZohoSignWebhookEventVerificationResult>;
25
+ /**
26
+ * Creates a verifier for Zoho Sign webhook events using HMAC-SHA256 signature verification.
27
+ *
28
+ * Zoho Sign computes `base64(HMAC-SHA256(payload, secret))` and sends the result
29
+ * in the `X-ZS-WEBHOOK-SIGNATURE` header. This verifier recomputes the signature
30
+ * from the raw request body and compares using timing-safe equality.
31
+ *
32
+ * @param config - Configuration containing the webhook secret key
33
+ * @returns A function that verifies webhook requests
34
+ *
35
+ * @example
36
+ * ```typescript
37
+ * const verifier = zohoSignWebhookEventVerifier({ secret: 'my-secret-key' });
38
+ * const result = await verifier(req, rawBody);
39
+ *
40
+ * if (result.valid) {
41
+ * console.log(result.event.operationType);
42
+ * }
43
+ * ```
44
+ */
45
+ export declare function zohoSignWebhookEventVerifier(config: ZohoSignWebhookVerificationConfig): ZohoSignWebhookEventVerifier;
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@dereekb/zoho",
3
- "version": "13.3.0",
3
+ "version": "13.4.0",
4
4
  "exports": {
5
5
  "./nestjs": {
6
6
  "module": "./nestjs/index.esm.js",
@@ -17,13 +17,15 @@
17
17
  }
18
18
  },
19
19
  "peerDependencies": {
20
- "@dereekb/util": "13.3.0",
21
- "@nestjs/common": "^11.0.0",
22
- "@nestjs/config": "^4.0.0",
20
+ "@dereekb/nestjs": "13.4.0",
21
+ "@dereekb/util": "13.4.0",
22
+ "@nestjs/common": "^11.1.16",
23
+ "@nestjs/config": "^4.0.3",
24
+ "express": "^5.0.0",
23
25
  "make-error": "^1.3.0"
24
26
  },
25
27
  "devDependencies": {
26
- "@nestjs/testing": "^11.0.0",
28
+ "@nestjs/testing": "^11.1.14",
27
29
  "date-fns": "^4.0.0"
28
30
  },
29
31
  "module": "./index.esm.js",