@sudhi_s_developer_123/communicate-server 0.0.1

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 ADDED
@@ -0,0 +1,102 @@
1
+ # @sudhi_s_developer_123/communicate-server
2
+
3
+ Official SDK for communicating with Our API. Modern, lightweight, and zero-dependency, featuring a **Secret Hashing** architecture for enhanced security.
4
+
5
+ ## Installation
6
+
7
+ ```bash
8
+ npm install @sudhi_s_developer_123/communicate-server
9
+ ```
10
+
11
+ ## Key Management
12
+
13
+ The SDK provides a utility to generate secure API credentials. In this model, the **Server** only needs to store a **hash** of the secret, while the **Client** uses the **raw** secret.
14
+
15
+ ```typescript
16
+ import { generateKeyPair } from "@sudhi_s_developer_123/communicate-server";
17
+
18
+ const { apiKey, apiSecret, secretHash } = generateKeyPair();
19
+
20
+ console.log(`API Key (Public): ${apiKey}`); // e.g. sk_...
21
+ console.log(`API Secret (Client-side usage): ${apiSecret}`); // e.g. ss_...
22
+ console.log(`Secret Hash (Server-side storage): ${secretHash}`);
23
+ ```
24
+
25
+ ---
26
+
27
+ ## Client Usage
28
+
29
+ The `ApiClient` is used to make secure, signed requests. It uses the raw `apiSecret` and automatically derives the HMAC key for signing.
30
+
31
+ ### Initializing the Client
32
+
33
+ ```typescript
34
+ import {
35
+ ApiClient,
36
+ asApiKey,
37
+ asApiSecret,
38
+ asBaseURL
39
+ } from "@sudhi_s_developer_123/communicate-server";
40
+
41
+ const client = new ApiClient({
42
+ apiKey: asApiKey("sk_your-api-key"),
43
+ apiSecret: asApiSecret("ss_your-raw-api-secret"),
44
+ baseURL: asBaseURL("https://api.yourcompany.com"),
45
+ serverSecret: asServerSecret("optional-server-side-secret"),
46
+ timeout: 5000,
47
+ });
48
+ ```
49
+
50
+ ### Making Requests
51
+
52
+ ```typescript
53
+ // GET Request
54
+ const user = await client.get("/users/me");
55
+
56
+ // POST Request
57
+ const newItem = await client.post("/items", { name: "New Product" });
58
+ ```
59
+
60
+ ---
61
+
62
+ ## Server Usage
63
+
64
+ The `ApiServer` is used to verify incoming requests. For maximum security, the server initialized with the **Secret Hash**, never needing to know the original raw secret.
65
+
66
+ ### Initializing the Server
67
+
68
+ ```typescript
69
+ import { ApiServer, asSecretHash } from "@sudhi_s_developer_123/communicate-server";
70
+
71
+ const server = new ApiServer({
72
+ serverSecret: asServerSecret("optional-server-side-secret"),
73
+ tolerance: 300000, // 5 minutes drift allowed (default)
74
+ });
75
+ ```
76
+
77
+ ### Verifying a Request
78
+
79
+ ```typescript
80
+ const verification = server.verifyRequest({
81
+ signature: req.headers["x-signature"],
82
+ timestamp: req.headers["x-timestamp"],
83
+ requestId: req.headers["x-request-id"],
84
+ body: JSON.stringify(req.body),
85
+ secretHash: asSecretHash("your-stored-secret-hash"),
86
+ });
87
+
88
+ if (verification.isValid) {
89
+ console.log("Request verified! Securely authenticated.");
90
+ } else {
91
+ console.error(`Verification failed: ${verification.error}`);
92
+ }
93
+ ```
94
+
95
+ ## Features
96
+
97
+ - **🛡️ Secret Hashing**: Server-side storage of secrets is limited to SHA-256 hashes.
98
+ - **🛡️ Type-Safe**: Branded types prevent mixing up sensitive strings like keys and secrets.
99
+ - **🚀 Lightweight**: Zero runtime dependencies, utilizing native `fetch` and `crypto`.
100
+ - **💻 Modern**: Built with TypeScript and supports ESM and CJS.
101
+
102
+
@@ -0,0 +1,22 @@
1
+ import type { ApiClientOptions, ApiHeaders, ApiPath, RequestData } from "./types.js";
2
+ export declare class ApiClient {
3
+ #private;
4
+ constructor(options: ApiClientOptions);
5
+ /**
6
+ * Send a GET request
7
+ */
8
+ get<T>(path: ApiPath, headers?: ApiHeaders): Promise<T>;
9
+ /**
10
+ * Send a POST request
11
+ */
12
+ post<T>(path: ApiPath, data?: RequestData, headers?: ApiHeaders): Promise<T>;
13
+ /**
14
+ * Send a PUT request
15
+ */
16
+ put<T>(path: ApiPath, data?: RequestData, headers?: ApiHeaders): Promise<T>;
17
+ /**
18
+ * Send a DELETE request
19
+ */
20
+ delete<T>(path: ApiPath, headers?: ApiHeaders): Promise<T>;
21
+ }
22
+ //# sourceMappingURL=client.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"client.d.ts","sourceRoot":"","sources":["../src/client.ts"],"names":[],"mappings":"AAGA,OAAO,KAAK,EACV,gBAAgB,EAMhB,UAAU,EACV,OAAO,EAMP,WAAW,EAIZ,MAAM,YAAY,CAAC;AAEpB,qBAAa,SAAS;;gBAQR,OAAO,EAAE,gBAAgB;IAWrC;;OAEG;IACU,GAAG,CAAC,CAAC,EAAE,IAAI,EAAE,OAAO,EAAE,OAAO,CAAC,EAAE,UAAU,GAAG,OAAO,CAAC,CAAC,CAAC;IAIpE;;OAEG;IACU,IAAI,CAAC,CAAC,EAAE,IAAI,EAAE,OAAO,EAAE,IAAI,CAAC,EAAE,WAAW,EAAE,OAAO,CAAC,EAAE,UAAU,GAAG,OAAO,CAAC,CAAC,CAAC;IAIzF;;OAEG;IACU,GAAG,CAAC,CAAC,EAAE,IAAI,EAAE,OAAO,EAAE,IAAI,CAAC,EAAE,WAAW,EAAE,OAAO,CAAC,EAAE,UAAU,GAAG,OAAO,CAAC,CAAC,CAAC;IAIxF;;OAEG;IACU,MAAM,CAAC,CAAC,EAAE,IAAI,EAAE,OAAO,EAAE,OAAO,CAAC,EAAE,UAAU,GAAG,OAAO,CAAC,CAAC,CAAC;CAkExE"}
package/dist/index.cjs ADDED
@@ -0,0 +1,250 @@
1
+ "use strict";
2
+ var __defProp = Object.defineProperty;
3
+ var __getOwnPropDesc = Object.getOwnPropertyDescriptor;
4
+ var __getOwnPropNames = Object.getOwnPropertyNames;
5
+ var __hasOwnProp = Object.prototype.hasOwnProperty;
6
+ var __export = (target, all) => {
7
+ for (var name in all)
8
+ __defProp(target, name, { get: all[name], enumerable: true });
9
+ };
10
+ var __copyProps = (to, from, except, desc) => {
11
+ if (from && typeof from === "object" || typeof from === "function") {
12
+ for (let key of __getOwnPropNames(from))
13
+ if (!__hasOwnProp.call(to, key) && key !== except)
14
+ __defProp(to, key, { get: () => from[key], enumerable: !(desc = __getOwnPropDesc(from, key)) || desc.enumerable });
15
+ }
16
+ return to;
17
+ };
18
+ var __toCommonJS = (mod) => __copyProps(__defProp({}, "__esModule", { value: true }), mod);
19
+
20
+ // src/index.ts
21
+ var index_exports = {};
22
+ __export(index_exports, {
23
+ ApiClient: () => ApiClient,
24
+ ApiServer: () => ApiServer,
25
+ asApiKey: () => asApiKey,
26
+ asApiPath: () => asApiPath,
27
+ asApiSecret: () => asApiSecret,
28
+ asBaseURL: () => asBaseURL,
29
+ asSecretHash: () => asSecretHash,
30
+ asServerSecret: () => asServerSecret,
31
+ asTimeout: () => asTimeout,
32
+ deriveSecretHash: () => deriveSecretHash,
33
+ generateKeyPair: () => generateKeyPair
34
+ });
35
+ module.exports = __toCommonJS(index_exports);
36
+
37
+ // src/client.ts
38
+ var import_node_crypto3 = require("crypto");
39
+
40
+ // src/signer.ts
41
+ var import_node_crypto = require("crypto");
42
+ function generateSignature({
43
+ hashKey,
44
+ timestamp,
45
+ requestId,
46
+ body,
47
+ serverSecret
48
+ }) {
49
+ const payload = serverSecret ? `${timestamp}.${requestId}.${body}.${serverSecret}` : `${timestamp}.${requestId}.${body}`;
50
+ return (0, import_node_crypto.createHmac)("sha256", hashKey).update(payload).digest("hex");
51
+ }
52
+ function verifySignature(received, options) {
53
+ const computed = generateSignature(options);
54
+ const receivedBuffer = Buffer.from(received, "hex");
55
+ const computedBuffer = Buffer.from(computed, "hex");
56
+ if (receivedBuffer.length !== computedBuffer.length) {
57
+ return false;
58
+ }
59
+ return (0, import_node_crypto.timingSafeEqual)(receivedBuffer, computedBuffer);
60
+ }
61
+
62
+ // src/utils.ts
63
+ var import_node_crypto2 = require("crypto");
64
+
65
+ // src/types.ts
66
+ var asApiKey = (v) => v;
67
+ var asApiSecret = (v) => v;
68
+ var asBaseURL = (v) => v;
69
+ var asTimeout = (v) => v;
70
+ var asApiPath = (v) => v;
71
+ var asSecretHash = (v) => v;
72
+ var asServerSecret = (v) => v;
73
+
74
+ // src/utils.ts
75
+ function generateKeyPair() {
76
+ const apiKey = asApiKey(`sk_${(0, import_node_crypto2.randomUUID)().replace(/-/g, "")}`);
77
+ const apiSecret = asApiSecret(`ss_${(0, import_node_crypto2.randomBytes)(32).toString("hex")}`);
78
+ const secretHash = deriveSecretHash(apiSecret);
79
+ return { apiKey, apiSecret, secretHash };
80
+ }
81
+ function deriveSecretHash(apiSecret) {
82
+ return asSecretHash(
83
+ (0, import_node_crypto2.createHash)("sha256").update(apiSecret).digest("hex")
84
+ );
85
+ }
86
+
87
+ // src/client.ts
88
+ var ApiClient = class {
89
+ #apiKey;
90
+ #apiSecret;
91
+ #baseURL;
92
+ #timeout;
93
+ #headers;
94
+ #serverSecret;
95
+ constructor(options) {
96
+ this.#apiKey = options.apiKey;
97
+ this.#apiSecret = options.apiSecret;
98
+ this.#baseURL = options.baseURL.endsWith("/") ? options.baseURL.slice(0, -1) : options.baseURL;
99
+ this.#timeout = options.timeout ?? 1e4;
100
+ this.#headers = options.headers ?? {};
101
+ this.#serverSecret = options.serverSecret;
102
+ }
103
+ /**
104
+ * Send a GET request
105
+ */
106
+ async get(path, headers) {
107
+ return this.#request("GET", path, void 0, headers);
108
+ }
109
+ /**
110
+ * Send a POST request
111
+ */
112
+ async post(path, data, headers) {
113
+ return this.#request("POST", path, data, headers);
114
+ }
115
+ /**
116
+ * Send a PUT request
117
+ */
118
+ async put(path, data, headers) {
119
+ return this.#request("PUT", path, data, headers);
120
+ }
121
+ /**
122
+ * Send a DELETE request
123
+ */
124
+ async delete(path, headers) {
125
+ return this.#request("DELETE", path, void 0, headers);
126
+ }
127
+ /**
128
+ * Internal request handler using native fetch
129
+ */
130
+ async #request(method, path, data, headers) {
131
+ const timestamp = Date.now().toString();
132
+ const requestId = (0, import_node_crypto3.randomUUID)();
133
+ const body = data ? JSON.stringify(data) : "";
134
+ const url = path.startsWith("/") ? `${this.#baseURL}${path}` : `${this.#baseURL}/${path}`;
135
+ const hashKey = deriveSecretHash(this.#apiSecret);
136
+ const signature = generateSignature({
137
+ hashKey,
138
+ timestamp,
139
+ requestId,
140
+ body,
141
+ serverSecret: this.#serverSecret
142
+ });
143
+ const controller = new AbortController();
144
+ const timeoutId = setTimeout(() => controller.abort(), this.#timeout);
145
+ try {
146
+ const response = await fetch(url, {
147
+ method,
148
+ headers: {
149
+ ...this.#headers,
150
+ ...headers,
151
+ "Content-Type": "application/json",
152
+ "Accept": "application/json",
153
+ "x-api-key": this.#apiKey,
154
+ "x-signature": signature,
155
+ "x-timestamp": timestamp,
156
+ "x-request-id": requestId
157
+ },
158
+ body: method !== "GET" && method !== "HEAD" && body ? body : void 0,
159
+ signal: controller.signal
160
+ });
161
+ clearTimeout(timeoutId);
162
+ if (!response.ok) {
163
+ const errorData = await response.json().catch(() => ({}));
164
+ const status = response.status;
165
+ const message = errorData.message || response.statusText;
166
+ throw new Error(`API Request failed (${status}): ${message}`);
167
+ }
168
+ return await response.json();
169
+ } catch (error) {
170
+ clearTimeout(timeoutId);
171
+ if (error instanceof Error && error.name === "AbortError") {
172
+ const timeoutMsg = `API Request timed out after ${this.#timeout}ms`;
173
+ throw new Error(timeoutMsg);
174
+ }
175
+ throw error;
176
+ }
177
+ }
178
+ };
179
+
180
+ // src/server.ts
181
+ var ApiServer = class {
182
+ #serverSecret;
183
+ #tolerance;
184
+ constructor(options) {
185
+ this.#serverSecret = options.serverSecret;
186
+ this.#tolerance = options.tolerance ?? 3e5;
187
+ }
188
+ /**
189
+ * Verify an incoming request's signature and timestamp.
190
+ *
191
+ * @param options - The extracted headers and body from the request
192
+ * @returns VerificationResult - object containing isValid and details
193
+ */
194
+ verifyRequest(options) {
195
+ const { signature, timestamp, requestId, body, secretHash } = options;
196
+ if (!signature || !timestamp || !requestId) {
197
+ return {
198
+ isValid: false,
199
+ error: "MISSING_HEADERS",
200
+ message: "Missing one or more required auth headers (x-signature, x-timestamp, x-request-id)"
201
+ };
202
+ }
203
+ const now = Date.now();
204
+ const requestTime = parseInt(timestamp, 10);
205
+ if (isNaN(requestTime)) {
206
+ return {
207
+ isValid: false,
208
+ error: "TIMESTAMP_OUT_OF_RANGE",
209
+ message: "Invalid timestamp format"
210
+ };
211
+ }
212
+ const diff = Math.abs(now - requestTime);
213
+ if (diff > this.#tolerance) {
214
+ return {
215
+ isValid: false,
216
+ error: "TIMESTAMP_OUT_OF_RANGE",
217
+ message: `Request timestamp is outside the allowed drift window (drift: ${diff}ms, tolerance: ${this.#tolerance}ms)`
218
+ };
219
+ }
220
+ const isSignatureValid = verifySignature(signature, {
221
+ hashKey: secretHash,
222
+ timestamp,
223
+ requestId,
224
+ body,
225
+ serverSecret: this.#serverSecret
226
+ });
227
+ if (!isSignatureValid) {
228
+ return {
229
+ isValid: false,
230
+ error: "SIGNATURE_MISMATCH",
231
+ message: "The provided signature does not match the computed one"
232
+ };
233
+ }
234
+ return { isValid: true };
235
+ }
236
+ };
237
+ // Annotate the CommonJS export names for ESM import in node:
238
+ 0 && (module.exports = {
239
+ ApiClient,
240
+ ApiServer,
241
+ asApiKey,
242
+ asApiPath,
243
+ asApiSecret,
244
+ asBaseURL,
245
+ asSecretHash,
246
+ asServerSecret,
247
+ asTimeout,
248
+ deriveSecretHash,
249
+ generateKeyPair
250
+ });
@@ -0,0 +1,5 @@
1
+ export * from "./client.js";
2
+ export * from "./server.js";
3
+ export * from "./types.js";
4
+ export * from "./utils.js";
5
+ //# sourceMappingURL=index.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"AAAA,cAAc,aAAa,CAAA;AAC3B,cAAc,aAAa,CAAA;AAC3B,cAAc,YAAY,CAAA;AAC1B,cAAc,YAAY,CAAA"}
package/dist/index.js ADDED
@@ -0,0 +1,213 @@
1
+ // src/client.ts
2
+ import { randomUUID as randomUUID2 } from "crypto";
3
+
4
+ // src/signer.ts
5
+ import { createHmac, timingSafeEqual } from "crypto";
6
+ function generateSignature({
7
+ hashKey,
8
+ timestamp,
9
+ requestId,
10
+ body,
11
+ serverSecret
12
+ }) {
13
+ const payload = serverSecret ? `${timestamp}.${requestId}.${body}.${serverSecret}` : `${timestamp}.${requestId}.${body}`;
14
+ return createHmac("sha256", hashKey).update(payload).digest("hex");
15
+ }
16
+ function verifySignature(received, options) {
17
+ const computed = generateSignature(options);
18
+ const receivedBuffer = Buffer.from(received, "hex");
19
+ const computedBuffer = Buffer.from(computed, "hex");
20
+ if (receivedBuffer.length !== computedBuffer.length) {
21
+ return false;
22
+ }
23
+ return timingSafeEqual(receivedBuffer, computedBuffer);
24
+ }
25
+
26
+ // src/utils.ts
27
+ import { randomUUID, randomBytes, createHash } from "crypto";
28
+
29
+ // src/types.ts
30
+ var asApiKey = (v) => v;
31
+ var asApiSecret = (v) => v;
32
+ var asBaseURL = (v) => v;
33
+ var asTimeout = (v) => v;
34
+ var asApiPath = (v) => v;
35
+ var asSecretHash = (v) => v;
36
+ var asServerSecret = (v) => v;
37
+
38
+ // src/utils.ts
39
+ function generateKeyPair() {
40
+ const apiKey = asApiKey(`sk_${randomUUID().replace(/-/g, "")}`);
41
+ const apiSecret = asApiSecret(`ss_${randomBytes(32).toString("hex")}`);
42
+ const secretHash = deriveSecretHash(apiSecret);
43
+ return { apiKey, apiSecret, secretHash };
44
+ }
45
+ function deriveSecretHash(apiSecret) {
46
+ return asSecretHash(
47
+ createHash("sha256").update(apiSecret).digest("hex")
48
+ );
49
+ }
50
+
51
+ // src/client.ts
52
+ var ApiClient = class {
53
+ #apiKey;
54
+ #apiSecret;
55
+ #baseURL;
56
+ #timeout;
57
+ #headers;
58
+ #serverSecret;
59
+ constructor(options) {
60
+ this.#apiKey = options.apiKey;
61
+ this.#apiSecret = options.apiSecret;
62
+ this.#baseURL = options.baseURL.endsWith("/") ? options.baseURL.slice(0, -1) : options.baseURL;
63
+ this.#timeout = options.timeout ?? 1e4;
64
+ this.#headers = options.headers ?? {};
65
+ this.#serverSecret = options.serverSecret;
66
+ }
67
+ /**
68
+ * Send a GET request
69
+ */
70
+ async get(path, headers) {
71
+ return this.#request("GET", path, void 0, headers);
72
+ }
73
+ /**
74
+ * Send a POST request
75
+ */
76
+ async post(path, data, headers) {
77
+ return this.#request("POST", path, data, headers);
78
+ }
79
+ /**
80
+ * Send a PUT request
81
+ */
82
+ async put(path, data, headers) {
83
+ return this.#request("PUT", path, data, headers);
84
+ }
85
+ /**
86
+ * Send a DELETE request
87
+ */
88
+ async delete(path, headers) {
89
+ return this.#request("DELETE", path, void 0, headers);
90
+ }
91
+ /**
92
+ * Internal request handler using native fetch
93
+ */
94
+ async #request(method, path, data, headers) {
95
+ const timestamp = Date.now().toString();
96
+ const requestId = randomUUID2();
97
+ const body = data ? JSON.stringify(data) : "";
98
+ const url = path.startsWith("/") ? `${this.#baseURL}${path}` : `${this.#baseURL}/${path}`;
99
+ const hashKey = deriveSecretHash(this.#apiSecret);
100
+ const signature = generateSignature({
101
+ hashKey,
102
+ timestamp,
103
+ requestId,
104
+ body,
105
+ serverSecret: this.#serverSecret
106
+ });
107
+ const controller = new AbortController();
108
+ const timeoutId = setTimeout(() => controller.abort(), this.#timeout);
109
+ try {
110
+ const response = await fetch(url, {
111
+ method,
112
+ headers: {
113
+ ...this.#headers,
114
+ ...headers,
115
+ "Content-Type": "application/json",
116
+ "Accept": "application/json",
117
+ "x-api-key": this.#apiKey,
118
+ "x-signature": signature,
119
+ "x-timestamp": timestamp,
120
+ "x-request-id": requestId
121
+ },
122
+ body: method !== "GET" && method !== "HEAD" && body ? body : void 0,
123
+ signal: controller.signal
124
+ });
125
+ clearTimeout(timeoutId);
126
+ if (!response.ok) {
127
+ const errorData = await response.json().catch(() => ({}));
128
+ const status = response.status;
129
+ const message = errorData.message || response.statusText;
130
+ throw new Error(`API Request failed (${status}): ${message}`);
131
+ }
132
+ return await response.json();
133
+ } catch (error) {
134
+ clearTimeout(timeoutId);
135
+ if (error instanceof Error && error.name === "AbortError") {
136
+ const timeoutMsg = `API Request timed out after ${this.#timeout}ms`;
137
+ throw new Error(timeoutMsg);
138
+ }
139
+ throw error;
140
+ }
141
+ }
142
+ };
143
+
144
+ // src/server.ts
145
+ var ApiServer = class {
146
+ #serverSecret;
147
+ #tolerance;
148
+ constructor(options) {
149
+ this.#serverSecret = options.serverSecret;
150
+ this.#tolerance = options.tolerance ?? 3e5;
151
+ }
152
+ /**
153
+ * Verify an incoming request's signature and timestamp.
154
+ *
155
+ * @param options - The extracted headers and body from the request
156
+ * @returns VerificationResult - object containing isValid and details
157
+ */
158
+ verifyRequest(options) {
159
+ const { signature, timestamp, requestId, body, secretHash } = options;
160
+ if (!signature || !timestamp || !requestId) {
161
+ return {
162
+ isValid: false,
163
+ error: "MISSING_HEADERS",
164
+ message: "Missing one or more required auth headers (x-signature, x-timestamp, x-request-id)"
165
+ };
166
+ }
167
+ const now = Date.now();
168
+ const requestTime = parseInt(timestamp, 10);
169
+ if (isNaN(requestTime)) {
170
+ return {
171
+ isValid: false,
172
+ error: "TIMESTAMP_OUT_OF_RANGE",
173
+ message: "Invalid timestamp format"
174
+ };
175
+ }
176
+ const diff = Math.abs(now - requestTime);
177
+ if (diff > this.#tolerance) {
178
+ return {
179
+ isValid: false,
180
+ error: "TIMESTAMP_OUT_OF_RANGE",
181
+ message: `Request timestamp is outside the allowed drift window (drift: ${diff}ms, tolerance: ${this.#tolerance}ms)`
182
+ };
183
+ }
184
+ const isSignatureValid = verifySignature(signature, {
185
+ hashKey: secretHash,
186
+ timestamp,
187
+ requestId,
188
+ body,
189
+ serverSecret: this.#serverSecret
190
+ });
191
+ if (!isSignatureValid) {
192
+ return {
193
+ isValid: false,
194
+ error: "SIGNATURE_MISMATCH",
195
+ message: "The provided signature does not match the computed one"
196
+ };
197
+ }
198
+ return { isValid: true };
199
+ }
200
+ };
201
+ export {
202
+ ApiClient,
203
+ ApiServer,
204
+ asApiKey,
205
+ asApiPath,
206
+ asApiSecret,
207
+ asBaseURL,
208
+ asSecretHash,
209
+ asServerSecret,
210
+ asTimeout,
211
+ deriveSecretHash,
212
+ generateKeyPair
213
+ };
@@ -0,0 +1,13 @@
1
+ import type { ApiServerOptions, VerificationResult, VerifyRequestOptions } from "./types.js";
2
+ export declare class ApiServer {
3
+ #private;
4
+ constructor(options: ApiServerOptions);
5
+ /**
6
+ * Verify an incoming request's signature and timestamp.
7
+ *
8
+ * @param options - The extracted headers and body from the request
9
+ * @returns VerificationResult - object containing isValid and details
10
+ */
11
+ verifyRequest(options: VerifyRequestOptions): VerificationResult;
12
+ }
13
+ //# sourceMappingURL=server.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"server.d.ts","sourceRoot":"","sources":["../src/server.ts"],"names":[],"mappings":"AACA,OAAO,KAAK,EACV,gBAAgB,EAChB,kBAAkB,EAClB,oBAAoB,EAIrB,MAAM,YAAY,CAAC;AAEpB,qBAAa,SAAS;;gBAIR,OAAO,EAAE,gBAAgB;IAKrC;;;;;OAKG;IACI,aAAa,CAAC,OAAO,EAAE,oBAAoB,GAAG,kBAAkB;CAoDxE"}
@@ -0,0 +1,10 @@
1
+ import type { SignerOptions, Signature } from "./types.js";
2
+ /**
3
+ * Generate a signature using the derived HMAC key (the secret hash).
4
+ */
5
+ export declare function generateSignature({ hashKey, timestamp, requestId, body, serverSecret, }: SignerOptions): Signature;
6
+ /**
7
+ * Verify a received signature matches the computed one
8
+ */
9
+ export declare function verifySignature(received: Signature, options: SignerOptions): boolean;
10
+ //# sourceMappingURL=signer.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"signer.d.ts","sourceRoot":"","sources":["../src/signer.ts"],"names":[],"mappings":"AACA,OAAO,KAAK,EAAE,aAAa,EAAE,SAAS,EAAiB,MAAM,YAAY,CAAC;AAE1E;;GAEG;AACH,wBAAgB,iBAAiB,CAAC,EAChC,OAAO,EACP,SAAS,EACT,SAAS,EACT,IAAI,EACJ,YAAY,GACb,EAAE,aAAa,GAAG,SAAS,CAQ3B;AAED;;GAEG;AACH,wBAAgB,eAAe,CAAC,QAAQ,EAAE,SAAS,EAAE,OAAO,EAAE,aAAa,GAAG,OAAO,CAWpF"}
@@ -0,0 +1,89 @@
1
+ declare const brand: unique symbol;
2
+ /**
3
+ * Utility for creating branded types.
4
+ * Makes it impossible to use one string in place of another (nominal typing).
5
+ */
6
+ export type Brand<T, TBrand extends string> = T & {
7
+ [brand]: TBrand;
8
+ };
9
+ /** HTTP configuration */
10
+ export type HttpMethod = "GET" | "POST" | "PUT" | "PATCH" | "DELETE" | "HEAD";
11
+ /** Identity and Secret types (Branded) */
12
+ export type ApiKey = Brand<string, "ApiKey">;
13
+ export type ApiSecret = Brand<string, "ApiSecret">;
14
+ /** Network and Timing types (Branded) */
15
+ export type BaseURL = Brand<string, "BaseURL">;
16
+ export type Timeout = Brand<number, "Timeout">;
17
+ export type ApiHeaders = Record<string, string>;
18
+ export type ApiPath = Brand<string, "ApiPath">;
19
+ export type RequestURL = Brand<string, "RequestURL">;
20
+ /** Signature and Auth types (Branded) */
21
+ export type Timestamp = Brand<string, "Timestamp">;
22
+ export type RequestId = Brand<string, "RequestId">;
23
+ export type RequestBody = Brand<string, "RequestBody">;
24
+ export type Signature = Brand<string, "Signature">;
25
+ export type SecretHash = Brand<string, "SecretHash">;
26
+ export type ServerSecret = Brand<string, "ServerSecret">;
27
+ export type SignerPayload = Brand<string, "SignerPayload">;
28
+ /** Data and Error types (Branded) */
29
+ export type RequestData = unknown;
30
+ export type StatusCode = Brand<number, "StatusCode">;
31
+ export type ErrorMessage = Brand<string, "ErrorMessage">;
32
+ export type StatusText = Brand<string, "StatusText">;
33
+ /** Casting helpers for creating branded types safely */
34
+ export declare const asApiKey: (v: string) => ApiKey;
35
+ export declare const asApiSecret: (v: string) => ApiSecret;
36
+ export declare const asBaseURL: (v: string) => BaseURL;
37
+ export declare const asTimeout: (v: number) => Timeout;
38
+ export declare const asApiPath: (v: string) => ApiPath;
39
+ export declare const asSecretHash: (v: string) => SecretHash;
40
+ export declare const asServerSecret: (v: string) => ServerSecret;
41
+ /** Client Configuration */
42
+ export interface ApiClientOptions {
43
+ apiKey: ApiKey;
44
+ apiSecret: ApiSecret;
45
+ baseURL: BaseURL;
46
+ /** Optional server-side secret for extra security layer */
47
+ serverSecret?: ServerSecret;
48
+ timeout?: Timeout;
49
+ headers?: ApiHeaders;
50
+ }
51
+ /** Server Configuration */
52
+ export interface ApiServerOptions {
53
+ /** Optional server-side secret for extra security layer */
54
+ serverSecret?: ServerSecret;
55
+ /** Max allowed clock drift in milliseconds. Defaults to 300,000 (5 mins). */
56
+ tolerance?: number;
57
+ }
58
+ /** Request Verification inputs */
59
+ export interface VerifyRequestOptions {
60
+ signature: Signature;
61
+ timestamp: Timestamp;
62
+ requestId: RequestId;
63
+ body: RequestBody;
64
+ /** The SHA-256 hash of the API secret for the user/client making the request */
65
+ secretHash: SecretHash;
66
+ }
67
+ /** Verification Success Result */
68
+ export interface VerificationSuccess {
69
+ isValid: true;
70
+ }
71
+ /** Verification Error Result */
72
+ export interface VerificationFailure {
73
+ isValid: false;
74
+ error: "SIGNATURE_MISMATCH" | "TIMESTAMP_OUT_OF_RANGE" | "MISSING_HEADERS";
75
+ message: ErrorMessage;
76
+ }
77
+ export type VerificationResult = VerificationSuccess | VerificationFailure;
78
+ /** Signature Engine inputs */
79
+ export interface SignerOptions {
80
+ /** The derived key for HMAC (the secret hash) */
81
+ hashKey: SecretHash;
82
+ timestamp: Timestamp;
83
+ requestId: RequestId;
84
+ body: RequestBody;
85
+ /** Optional server-side secret for extra security layer */
86
+ serverSecret?: ServerSecret;
87
+ }
88
+ export {};
89
+ //# sourceMappingURL=types.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"types.d.ts","sourceRoot":"","sources":["../src/types.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,19 @@
1
+ import { type ApiKey, type ApiSecret, type SecretHash } from "./types.js";
2
+ /**
3
+ * Generate a new API Key Pair.
4
+ *
5
+ * Returns:
6
+ * - apiKey: Public identifier
7
+ * - apiSecret: Private secret (should only be shown once)
8
+ * - secretHash: SHA-256 hash of the secret (stored on the server)
9
+ */
10
+ export declare function generateKeyPair(): {
11
+ apiKey: ApiKey;
12
+ apiSecret: ApiSecret;
13
+ secretHash: SecretHash;
14
+ };
15
+ /**
16
+ * Derives a SecretHash from an ApiSecret using SHA-256
17
+ */
18
+ export declare function deriveSecretHash(apiSecret: ApiSecret): SecretHash;
19
+ //# sourceMappingURL=utils.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"utils.d.ts","sourceRoot":"","sources":["../src/utils.ts"],"names":[],"mappings":"AACA,OAAO,EAKL,KAAK,MAAM,EACX,KAAK,SAAS,EACd,KAAK,UAAU,EAEhB,MAAM,YAAY,CAAC;AAEpB;;;;;;;GAOG;AACH,wBAAgB,eAAe,IAAI;IACjC,MAAM,EAAE,MAAM,CAAC;IACf,SAAS,EAAE,SAAS,CAAC;IACrB,UAAU,EAAE,UAAU,CAAC;CACxB,CAMA;AAED;;GAEG;AACH,wBAAgB,gBAAgB,CAAC,SAAS,EAAE,SAAS,GAAG,UAAU,CAMjE"}
package/package.json ADDED
@@ -0,0 +1,27 @@
1
+ {
2
+ "name": "@sudhi_s_developer_123/communicate-server",
3
+ "version": "0.0.1",
4
+ "description": "Official SDK for communicating with Our API",
5
+ "type": "module",
6
+ "main": "./dist/index.cjs",
7
+ "module": "./dist/index.js",
8
+ "types": "./dist/index.d.ts",
9
+ "exports": {
10
+ ".": {
11
+ "types": "./dist/index.d.ts",
12
+ "import": "./dist/index.js",
13
+ "require": "./dist/index.cjs"
14
+ }
15
+ },
16
+ "files": [
17
+ "dist"
18
+ ],
19
+ "scripts": {
20
+ "build": "tsup src/index.ts --format esm,cjs --clean && tsc --emitDeclarationOnly"
21
+ },
22
+ "devDependencies": {
23
+ "@types/node": "^25.5.2",
24
+ "tsup": "^8.5.1",
25
+ "typescript": "^6.0.2"
26
+ }
27
+ }