@oapiex/sdk-kit 0.1.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/dist/index.cjs ADDED
@@ -0,0 +1,802 @@
1
+ //#region rolldown:runtime
2
+ var __create = Object.create;
3
+ var __defProp = Object.defineProperty;
4
+ var __getOwnPropDesc = Object.getOwnPropertyDescriptor;
5
+ var __getOwnPropNames = Object.getOwnPropertyNames;
6
+ var __getProtoOf = Object.getPrototypeOf;
7
+ var __hasOwnProp = Object.prototype.hasOwnProperty;
8
+ var __copyProps = (to, from, except, desc) => {
9
+ if (from && typeof from === "object" || typeof from === "function") for (var keys = __getOwnPropNames(from), i = 0, n = keys.length, key; i < n; i++) {
10
+ key = keys[i];
11
+ if (!__hasOwnProp.call(to, key) && key !== except) __defProp(to, key, {
12
+ get: ((k) => from[k]).bind(null, key),
13
+ enumerable: !(desc = __getOwnPropDesc(from, key)) || desc.enumerable
14
+ });
15
+ }
16
+ return to;
17
+ };
18
+ var __toESM = (mod, isNodeMode, target) => (target = mod != null ? __create(__getProtoOf(mod)) : {}, __copyProps(isNodeMode || !mod || !mod.__esModule ? __defProp(target, "default", {
19
+ value: mod,
20
+ enumerable: true
21
+ }) : target, mod));
22
+
23
+ //#endregion
24
+ require("dotenv/config");
25
+ let axios = require("axios");
26
+ axios = __toESM(axios);
27
+ let path = require("path");
28
+ path = __toESM(path);
29
+ let crypto = require("crypto");
30
+ crypto = __toESM(crypto);
31
+
32
+ //#region src/utilities/global.ts
33
+ String.prototype.toKebabCase = function() {
34
+ return this.replace(/([a-z])([A-Z])/g, "$1-$2").replace(/[\s_]+/g, "-").toLowerCase();
35
+ };
36
+ String.prototype.toCamelCase = function() {
37
+ return this.replace(/[-_ ]+([a-zA-Z0-9])/g, (_, c) => c.toUpperCase()).replace(/^[A-Z]/, (c) => c.toLowerCase());
38
+ };
39
+ String.prototype.toPascalCase = function() {
40
+ return this.replace(/(^\w|[-_ ]+\w)/g, (match) => match.replace(/[-_ ]+/, "").toUpperCase());
41
+ };
42
+ String.prototype.toSnakeCase = function() {
43
+ return this.replace(/([a-z])([A-Z])/g, "$1_$2").replace(/[\s-]+/g, "_").toLowerCase();
44
+ };
45
+ String.prototype.toSlug = function(separator = "-") {
46
+ return this.toSnakeCase().replace(/[/__:]+/g, "_").replace(/_/g, separator);
47
+ };
48
+ String.prototype.toTitleCase = function() {
49
+ return this.toLowerCase().replace(/(^|\s)\w/g, (match) => match.toUpperCase());
50
+ };
51
+ String.prototype.toCleanCase = function() {
52
+ return this.replace(/([a-z])([A-Z])/g, "$1 $2").replace(/[_-]+/g, " ").replace(/\s+/g, " ").split(" ").map((word) => word.charAt(0).toUpperCase() + word.slice(1)).join(" ").trim().replace(/\b\w{1,3}\b/g, (match) => match.toUpperCase());
53
+ };
54
+ String.prototype.truncate = function(n, suffix = "…") {
55
+ return this.length > n ? this.slice(0, n - 1) + suffix : this.toString();
56
+ };
57
+
58
+ //#endregion
59
+ //#region src/utilities/helpers.ts
60
+ /**
61
+ * Takes a value like the one prodvided in a destructuring assignment where for instance
62
+ * a single value might have been provided as opposed to an array of values and
63
+ * normalizes it.
64
+ *
65
+ * Examples:
66
+ * Definition:
67
+ * (...value: string[]) => normalizeValue(value)
68
+ *
69
+ * Usage:
70
+ * normalizeValue('singleValue') // returns ['singleValue']
71
+ * normalizeValue('value1', 'value2') // returns ['value1', 'value2']
72
+ * normalizeValue(['value1', 'value2']) // returns ['value1', 'value2']
73
+ *
74
+ * @param value
75
+ * @returns
76
+ */
77
+ const normalizeValue = (value) => {
78
+ if (Array.isArray(value)) return value;
79
+ return [value];
80
+ };
81
+ /**
82
+ * Builds a full url based on endpoint provided
83
+ *
84
+ * @param baseUrl
85
+ * @param endpoint
86
+ *
87
+ * @returns
88
+ */
89
+ const buildUrl = (baseUrl, ...endpoint) => {
90
+ return (baseUrl + path.default.normalize(path.default.join(...normalizeValue(endpoint)))).replace(/([^:]\/)\/+/g, "$1");
91
+ };
92
+
93
+ //#endregion
94
+ //#region src/Builder.ts
95
+ var Builder = class {
96
+ static baseUrls = {
97
+ live: "https://api.flutterwave.com/v4/",
98
+ sandbox: "https://developersandbox-api.flutterwave.com/"
99
+ };
100
+ /**
101
+ * Flutterwave Environment
102
+ */
103
+ static environment;
104
+ constructor() {}
105
+ /**
106
+ * Sets the environment for the builder
107
+ *
108
+ * @param env
109
+ */
110
+ static setEnvironment(env) {
111
+ this.environment = env;
112
+ }
113
+ /**
114
+ * Gets the base url based on environment
115
+ *
116
+ * @returns
117
+ */
118
+ static baseUrl() {
119
+ if ((process.env.ENVIRONMENT || this.environment || "sandbox") === "live") return this.baseUrls.live;
120
+ return this.baseUrls.sandbox;
121
+ }
122
+ /**
123
+ * Builds a full url based on endpoint provided
124
+ *
125
+ * @param endpoint
126
+ * @returns
127
+ */
128
+ static buildUrl(...endpoint) {
129
+ return buildUrl(this.baseUrl(), ...endpoint);
130
+ }
131
+ /**
132
+ * Builds parameters for query or path
133
+ *
134
+ * @param params
135
+ * @param type
136
+ * @returns
137
+ */
138
+ static buildParams(params, type = "path") {
139
+ let built = "";
140
+ if (type === "path") built = Object.values(params).join("/");
141
+ else {
142
+ const queryParams = [];
143
+ for (const [key, value] of Object.entries(params)) queryParams.push(`${encodeURIComponent(key)}=${encodeURIComponent(String(value))}`);
144
+ built = queryParams.join("&");
145
+ }
146
+ return built;
147
+ }
148
+ /**
149
+ * Assigns parameters to url {placeholders} based on type
150
+ *
151
+ * @param url
152
+ * @param params
153
+ * @param type
154
+ *
155
+ * @returns
156
+ */
157
+ static assignParamsToUrl(url, params, type = "path") {
158
+ let builtUrl = url;
159
+ if (type === "path") for (const [key, value] of Object.entries(params)) {
160
+ builtUrl = builtUrl.replace(`{${key}}`, encodeURIComponent(String(value)));
161
+ builtUrl = builtUrl.replace(`:${key}`, encodeURIComponent(String(value)));
162
+ }
163
+ else {
164
+ if (Object.keys(params).length === 0) return builtUrl;
165
+ const queryString = this.buildParams(params, "query");
166
+ const separator = builtUrl.includes("?") ? "&" : "?";
167
+ builtUrl += `${separator}${queryString}`;
168
+ }
169
+ return builtUrl;
170
+ }
171
+ /**
172
+ * Builds the target url by assigning both path and query parameters
173
+ *
174
+ * @param path
175
+ * @param params
176
+ * @param queryParams
177
+ * @returns
178
+ */
179
+ static buildTargetUrl(path$2, params = {}, queryParams = {}) {
180
+ const url = this.buildUrl(path$2);
181
+ let builtUrl = this.assignParamsToUrl(url, params, "path");
182
+ builtUrl = this.assignParamsToUrl(builtUrl, queryParams, "query");
183
+ return builtUrl;
184
+ }
185
+ /**
186
+ * Encrypts specified keys in the input object and returns a new object with
187
+ * encrypted values.
188
+ *
189
+ * @param input The input object containing the data to be encrypted.
190
+ * @param keysToEncrypt The keys in the input object that should be encrypted.
191
+ * @param outputMapping A mapping of input keys to output keys for the encrypted values.
192
+ * @returns A new object with the specified keys encrypted.
193
+ */
194
+ static async encryptDetails(input, keysToEncrypt = [], outputMapping = {}) {
195
+ const nonce = crypto.default.randomBytes(12).toString("base64").slice(0, 12);
196
+ const encryptableKeys = keysToEncrypt.length > 0 ? keysToEncrypt : Object.keys(input);
197
+ const encrypted = Object.fromEntries(Object.entries(input).map(([key, value]) => {
198
+ if (encryptableKeys.includes(key) && typeof value === "string") return [outputMapping?.[key] || key, this.encryptAES(value, process.env.ENCRYPTION_KEY, nonce)];
199
+ return [key, value];
200
+ }));
201
+ for (const key of encryptableKeys) delete input[key];
202
+ return encrypted;
203
+ }
204
+ /**
205
+ * Encrypts data using AES-GCM encryption
206
+ * @param data
207
+ * @param token
208
+ * @param nonce
209
+ * @returns
210
+ */
211
+ static async encryptAES(data, token, nonce) {
212
+ if (nonce.length !== 12) throw new Error("Nonce must be exactly 12 characters long");
213
+ const cryptoSubtle = globalThis.crypto?.subtle || crypto.default.webcrypto?.subtle;
214
+ if (!cryptoSubtle) throw new Error("Crypto API is not available in this environment.");
215
+ const decodedKeyBytes = Uint8Array.from(atob(token), (c) => c.charCodeAt(0));
216
+ const key = await cryptoSubtle.importKey("raw", decodedKeyBytes, { name: "AES-GCM" }, false, ["encrypt"]);
217
+ const iv = new TextEncoder().encode(nonce);
218
+ const encryptedData = await cryptoSubtle.encrypt({
219
+ name: "AES-GCM",
220
+ iv
221
+ }, key, new TextEncoder().encode(data));
222
+ return btoa(String.fromCharCode(...new Uint8Array(encryptedData)));
223
+ }
224
+ };
225
+
226
+ //#endregion
227
+ //#region src/Exceptions/BadRequestException.ts
228
+ var BadRequestException = class extends Error {
229
+ statusCode = 400;
230
+ type = "INVALID_REQUEST";
231
+ code = "400";
232
+ data;
233
+ constructor(data) {
234
+ super(data?.error.message ?? data?.message ?? "Bad request. The server could not understand the request due to invalid syntax.");
235
+ if (data?.error.code) this.type = data.error.type;
236
+ if (data?.error.code) this.code = data.error.code;
237
+ this.data = data ?? {
238
+ status: "failed",
239
+ error: {
240
+ type: this.type,
241
+ code: this.code,
242
+ message: this.message,
243
+ validation_errors: []
244
+ }
245
+ };
246
+ this.name = "BadRequestException";
247
+ }
248
+ };
249
+
250
+ //#endregion
251
+ //#region src/Exceptions/ForbiddenRequestException.ts
252
+ var ForbiddenRequestException = class extends Error {
253
+ statusCode = 403;
254
+ type = "FORBIDDEN";
255
+ code = "403";
256
+ data;
257
+ constructor(data) {
258
+ super(data?.error.message ?? data?.message ?? "Forbidden request. You do not have permission to access this resource.");
259
+ if (data?.error.code) this.type = data.error.type;
260
+ if (data?.error.code) this.code = data.error.code;
261
+ this.data = data ?? {
262
+ status: "failed",
263
+ error: {
264
+ type: this.type,
265
+ code: this.code,
266
+ message: this.message
267
+ }
268
+ };
269
+ this.name = "ForbiddenRequestException";
270
+ }
271
+ };
272
+
273
+ //#endregion
274
+ //#region src/Exceptions/UnauthorizedRequestException.ts
275
+ var UnauthorizedRequestException = class extends Error {
276
+ statusCode = 401;
277
+ type = "UNAUTHORIZED";
278
+ code = "401";
279
+ data;
280
+ constructor(data) {
281
+ super(data?.error.message ?? data?.message ?? "Forbidden request. You do not have permission to access this resource.");
282
+ if (data?.error.code) this.type = data.error.type;
283
+ if (data?.error.code) this.code = data.error.code;
284
+ this.data = data ?? {
285
+ status: "failed",
286
+ error: {
287
+ type: this.type,
288
+ code: this.code,
289
+ message: this.message
290
+ }
291
+ };
292
+ this.name = "UnauthorizedRequestException";
293
+ }
294
+ };
295
+
296
+ //#endregion
297
+ //#region src/Exceptions/HttpException.ts
298
+ var HttpException = class HttpException extends Error {
299
+ statusCode = 500;
300
+ parent;
301
+ constructor(data, statusCode, parent) {
302
+ super(data.message);
303
+ this.data = data;
304
+ this.name = "HttpException";
305
+ this.parent = parent;
306
+ if (statusCode) this.statusCode = statusCode;
307
+ }
308
+ /**
309
+ * Create an exception from status code
310
+ *
311
+ * @param code
312
+ * @param data
313
+ */
314
+ static fromCode(code, data, parent) {
315
+ switch (code) {
316
+ case 400: return new BadRequestException(data);
317
+ case 401: return new UnauthorizedRequestException(data);
318
+ case 403: return new ForbiddenRequestException(data);
319
+ default: return new HttpException(data, code, parent);
320
+ }
321
+ }
322
+ };
323
+
324
+ //#endregion
325
+ //#region src/Http.ts
326
+ var Http = class Http {
327
+ /**
328
+ * Bearer token
329
+ */
330
+ static bearerToken;
331
+ /**
332
+ * Debug level
333
+ */
334
+ static debugLevel = 0;
335
+ static apiInstance;
336
+ /**
337
+ * Creates an instance of Http.
338
+ *
339
+ * @param method
340
+ * @param url
341
+ * @param headers
342
+ * @param body
343
+ */
344
+ constructor(headers = {}, body) {
345
+ this.headers = headers;
346
+ this.body = body;
347
+ }
348
+ /**
349
+ * Set the debug level
350
+ *
351
+ * @param debug
352
+ */
353
+ static setDebugLevel(level = 0) {
354
+ this.debugLevel = level ?? 0;
355
+ }
356
+ /**
357
+ * Set the API instance
358
+ *
359
+ * @param api
360
+ */
361
+ static setApiInstance(api) {
362
+ this.apiInstance = api;
363
+ }
364
+ /**
365
+ * Set the bearer token
366
+ *
367
+ * @param token
368
+ */
369
+ static setBearerToken(token) {
370
+ this.bearerToken = token;
371
+ }
372
+ setDefaultHeaders(defaults) {
373
+ this.headers = {
374
+ ...defaults,
375
+ ...this.headers
376
+ };
377
+ if (Http.bearerToken) this.headers.Authorization = `Bearer ${Http.bearerToken}`;
378
+ }
379
+ getHeaders() {
380
+ return this.headers;
381
+ }
382
+ getBody() {
383
+ return this.body;
384
+ }
385
+ axiosApi() {
386
+ this.setDefaultHeaders({
387
+ "Accept": "application/json",
388
+ "Content-Type": "application/json"
389
+ });
390
+ const instance = axios.default.create({
391
+ baseURL: Builder.baseUrl(),
392
+ headers: this.getHeaders()
393
+ });
394
+ if (Http.debugLevel > 0) {
395
+ instance.interceptors.request.use((request) => {
396
+ console.log("Starting Request", JSON.stringify({
397
+ url: request.url,
398
+ method: request.method,
399
+ headers: Http.debugLevel < 3 ? Object.fromEntries(Object.entries(request.headers || {}).filter(([key]) => key.toLowerCase() !== "authorization")) : request.headers,
400
+ params: request.params,
401
+ data: request.data
402
+ }, null, 2));
403
+ return request;
404
+ }, (error) => {
405
+ console.log("Request Error:", JSON.stringify(error, null, 2));
406
+ return Promise.reject(error);
407
+ });
408
+ instance.interceptors.response.use((response) => {
409
+ console.log("Response:", JSON.stringify({
410
+ status: response.status,
411
+ data: Http.debugLevel < 3 ? Object.fromEntries(Object.entries(response.data || {}).filter(([key]) => key.toLowerCase() !== "access_token")) : response.data
412
+ }, null, 2));
413
+ return response;
414
+ }, (error) => {
415
+ console.log("Response Error:", JSON.stringify({
416
+ status: error.response?.status,
417
+ data: Object.fromEntries(Object.entries(error.response?.data || {}).filter(([key]) => key.toLowerCase() !== "access_token"))
418
+ }, null, 2));
419
+ return Promise.reject(error);
420
+ });
421
+ }
422
+ return instance;
423
+ }
424
+ /**
425
+ * Makes a GET request
426
+ *
427
+ * @param url
428
+ * @param headers
429
+ * @param params
430
+ * @returns
431
+ */
432
+ static async get(url, params, headers = {}) {
433
+ return this.send(url, "GET", void 0, headers, params);
434
+ }
435
+ /**
436
+ *
437
+ *
438
+ * @param url
439
+ * @param headers
440
+ * @param params
441
+ * @returns
442
+ */
443
+ static async send(url, method, body, headers = {}, params) {
444
+ try {
445
+ const { data } = await new Http(headers).axiosApi()({
446
+ url,
447
+ method,
448
+ data: body,
449
+ params
450
+ });
451
+ return {
452
+ success: true,
453
+ message: data.message || "Request successful",
454
+ data: data.data ?? data,
455
+ meta: data.meta
456
+ };
457
+ } catch (e) {
458
+ const error = e.response?.data ?? {};
459
+ throw this.exception(e.response?.status ?? 500, error || e, e);
460
+ }
461
+ }
462
+ /**
463
+ * Create an HttpException from status and error
464
+ *
465
+ * @param status
466
+ * @param error
467
+ * @returns
468
+ */
469
+ static exception(status, error, originalError) {
470
+ const exception = HttpException.fromCode(status, {
471
+ success: false,
472
+ message: `Request failed: ${error.error?.message || "An error occurred"}`,
473
+ status: "failed",
474
+ data: void 0,
475
+ meta: {},
476
+ error: {
477
+ type: ((typeof error.error === "string" ? error.error : error.error?.type) ?? "UNKNOWN_ERROR").toUpperCase(),
478
+ code: error.error?.code ?? "000000",
479
+ message: error.error?.message ?? error.error_description ?? error.message,
480
+ validation_errors: error.error?.validation_errors ?? []
481
+ }
482
+ }, originalError);
483
+ if (this.apiInstance) this.apiInstance.setLastException(exception);
484
+ return exception;
485
+ }
486
+ };
487
+
488
+ //#endregion
489
+ //#region src/Apis/BaseApi.ts
490
+ var BaseApi = class {
491
+ /**
492
+ * Flutterwave instance
493
+ */
494
+ #core;
495
+ lastException;
496
+ /**
497
+ * Create a BaseApi instance
498
+ *
499
+ * @param coreInstance Core instance
500
+ */
501
+ constructor(coreInstance) {
502
+ this.#core = coreInstance;
503
+ }
504
+ /**
505
+ * Get the owning core instance for SDK-specific API bootstrapping.
506
+ */
507
+ get core() {
508
+ return this.#core;
509
+ }
510
+ /**
511
+ * Hook for SDK-specific API registration.
512
+ */
513
+ boot() {}
514
+ /**
515
+ * Set access validator function
516
+ *
517
+ * @param validator
518
+ */
519
+ setAccessValidator(validator) {
520
+ this.#core.setAccessValidator(validator);
521
+ }
522
+ /**
523
+ * Get the last exception
524
+ *
525
+ * @returns
526
+ */
527
+ getLastException() {
528
+ return this.lastException;
529
+ }
530
+ /**
531
+ * Set the last exception
532
+ *
533
+ * @param exception
534
+ */
535
+ setLastException(exception) {
536
+ this.lastException = exception;
537
+ }
538
+ /**
539
+ * Initialize BaseApi and its sub-APIs
540
+ *
541
+ * @param coreInstance Core instance
542
+ * @returns
543
+ */
544
+ static initialize(coreInstance) {
545
+ Http.setDebugLevel(coreInstance.debugLevel);
546
+ const baseApi = new this(coreInstance);
547
+ Http.setApiInstance(baseApi);
548
+ baseApi.boot();
549
+ return baseApi;
550
+ }
551
+ };
552
+
553
+ //#endregion
554
+ //#region src/RuntimeSdk.ts
555
+ const createRuntimeApi = (core, bundle) => {
556
+ const api = BaseApi.initialize(core);
557
+ for (const group of bundle.manifest.groups) {
558
+ const namespace = {};
559
+ for (const operation of group.operations) namespace[operation.methodName] = async (...args) => {
560
+ await core.validateAccess();
561
+ const [pathParams, queryParams, body, headers] = normalizeRuntimeArguments(operation, args);
562
+ validateRequiredArguments(operation.pathParams, pathParams, "path");
563
+ validateRequiredArguments(operation.queryParams, queryParams, "query");
564
+ validateRequiredArguments(operation.headerParams, headers, "header");
565
+ if (operation.hasBody && operation.bodyRequired && body == null) throw new Error(`Missing required request body for ${operation.method} ${operation.path}`);
566
+ const { data } = await Http.send(core.builder.buildTargetUrl(operation.path, pathParams, queryParams), operation.method, body ?? {}, headers);
567
+ return data;
568
+ };
569
+ api[group.propertyName] = namespace;
570
+ }
571
+ return api;
572
+ };
573
+ const createSdk = (bundle, options) => {
574
+ return new Core(options).useDocument(bundle);
575
+ };
576
+ const normalizeRuntimeArguments = (operation, args) => {
577
+ let cursor = 0;
578
+ return [
579
+ operation.pathParams.length > 0 ? toRecord(args[cursor++]) : {},
580
+ operation.queryParams.length > 0 ? toRecord(args[cursor++]) : {},
581
+ operation.hasBody ? args[cursor++] : void 0,
582
+ operation.headerParams.length > 0 ? toRecord(args[cursor++]) : {}
583
+ ];
584
+ };
585
+ const validateRequiredArguments = (parameters, values, location) => {
586
+ for (const parameter of parameters) {
587
+ if (!parameter.required) continue;
588
+ if (values[parameter.name] === void 0 && values[parameter.accessor] === void 0) throw new Error(`Missing required ${location} parameter: ${parameter.name}`);
589
+ }
590
+ };
591
+ const toRecord = (value) => {
592
+ if (typeof value === "object" && value !== null && !Array.isArray(value)) return value;
593
+ return {};
594
+ };
595
+
596
+ //#endregion
597
+ //#region src/Core.ts
598
+ var Core = class {
599
+ static apiClass = BaseApi;
600
+ debugLevel = 0;
601
+ /**
602
+ * Client ID
603
+ */
604
+ clientId;
605
+ /**
606
+ * Client Secret
607
+ */
608
+ clientSecret;
609
+ /**
610
+ * Flutterwave Environment
611
+ */
612
+ environment = "live";
613
+ accessValidator;
614
+ /**
615
+ * API Instance
616
+ */
617
+ api;
618
+ /**
619
+ * Builder Instance
620
+ */
621
+ builder = Builder;
622
+ constructor(clientId, clientSecret, encryptionKey, env) {
623
+ if (typeof clientId === "object") {
624
+ this.clientId = clientId.clientId;
625
+ this.clientSecret = clientId.clientSecret;
626
+ this.environment = clientId.environment ?? "live";
627
+ } else {
628
+ this.clientId = clientId ?? process.env.CLIENT_ID ?? "";
629
+ this.clientSecret = clientSecret ?? process.env.CLIENT_SECRET ?? "";
630
+ this.environment = env ?? process.env.ENVIRONMENT ?? "live";
631
+ }
632
+ if (!this.clientId || !this.clientSecret) throw new Error("Client ID and Client Secret are required to initialize Flutterwave instance");
633
+ this.builder.setEnvironment(this.environment);
634
+ this.api = this.createApi();
635
+ }
636
+ createApi() {
637
+ return (this.constructor.apiClass ?? BaseApi).initialize(this);
638
+ }
639
+ init(clientId, clientSecret, encryptionKey, env) {
640
+ return new this.constructor(clientId, clientSecret, encryptionKey, env);
641
+ }
642
+ /**
643
+ * Set the debug level
644
+ *
645
+ * @param level
646
+ * @returns
647
+ */
648
+ debug(level = 0) {
649
+ this.debugLevel = level;
650
+ Http.setDebugLevel(level);
651
+ return this;
652
+ }
653
+ /**
654
+ * Get the current environment
655
+ *
656
+ * @returns
657
+ */
658
+ getEnvironment() {
659
+ return this.environment;
660
+ }
661
+ /**
662
+ * Set access validator function
663
+ *
664
+ * @param validator Function to validate access
665
+ */
666
+ setAccessValidator(validator) {
667
+ this.accessValidator = validator;
668
+ }
669
+ /**
670
+ * Validates access using the provided access validator function
671
+ *
672
+ * @throws Error if validation fails
673
+ */
674
+ async validateAccess() {
675
+ const check = this.accessValidator ? await this.accessValidator(this) : true;
676
+ if (check !== true) throw new Error(typeof check === "string" ? check : "Access validation failed");
677
+ }
678
+ /**
679
+ * Use a manifest bundle to create the API instance
680
+ *
681
+ * @param bundle
682
+ * @returns
683
+ */
684
+ useDocument(bundle) {
685
+ this.api = createRuntimeApi(this, bundle);
686
+ return this;
687
+ }
688
+ /**
689
+ * Use a manifest bundle to create the API instance (alias for useDocument).
690
+ *
691
+ * @param bundle
692
+ * @returns
693
+ */
694
+ useSdk(bundle) {
695
+ return this.useDocument(bundle);
696
+ }
697
+ };
698
+
699
+ //#endregion
700
+ //#region src/utilities/Manager.ts
701
+ const defaultConfig = {
702
+ environment: "sandbox",
703
+ urls: {
704
+ live: "",
705
+ sandbox: ""
706
+ }
707
+ };
708
+ let globalConfig = defaultConfig;
709
+ const defineConfig = (config) => {
710
+ const userConfig = {
711
+ ...defaultConfig,
712
+ ...config,
713
+ urls: {
714
+ ...defaultConfig.urls,
715
+ ...config.urls
716
+ }
717
+ };
718
+ globalConfig = userConfig;
719
+ return userConfig;
720
+ };
721
+
722
+ //#endregion
723
+ //#region src/utilities/WebhookValidator.ts
724
+ var WebhookValidator = class {
725
+ algorithm = "sha256";
726
+ encoding = "base64";
727
+ /**
728
+ * @param secretHash
729
+ * @param options
730
+ */
731
+ constructor(secretHash, options) {
732
+ this.secretHash = secretHash;
733
+ this.algorithm = options?.hashAlgorithm || "sha256";
734
+ this.encoding = options?.encoding || "base64";
735
+ if (!this.secretHash || this.secretHash.length === 0) this.secretHash = process.env.SECRET_HASH;
736
+ }
737
+ /**
738
+ * Validate webhook signature
739
+ * @param rawBody - Raw request body as string
740
+ * @param signature - Signature from request header
741
+ * @returns {boolean} - True if signature is valid
742
+ */
743
+ validate(rawBody, signature) {
744
+ if (!this.secretHash) throw new Error("Secret hash is required for validation");
745
+ return crypto.default.createHmac(this.algorithm, this.secretHash).update(rawBody).digest(this.encoding) === signature;
746
+ }
747
+ /**
748
+ * Generate signature for testing/verification
749
+ * @param rawBody - Raw request body as string
750
+ * @returns {string} - Generated signature
751
+ */
752
+ generateSignature(rawBody) {
753
+ if (!this.secretHash) throw new Error("Secret hash is required to generate signature");
754
+ return crypto.default.createHmac(this.algorithm, this.secretHash).update(rawBody).digest(this.encoding);
755
+ }
756
+ /**
757
+ * Async version of validate (for large payloads)
758
+ *
759
+ * @param rawBody
760
+ * @param signature
761
+ * @returns {Promise<boolean>}
762
+ */
763
+ validateAsync(rawBody, signature) {
764
+ if (!this.secretHash) throw new Error("Secret hash is required for validation");
765
+ const hmac = crypto.default.createHmac(this.algorithm, this.secretHash);
766
+ hmac.update(rawBody);
767
+ return hmac.digest(this.encoding) === signature;
768
+ }
769
+ /**
770
+ * Get current configuration
771
+ */
772
+ getConfig() {
773
+ return {
774
+ algorithm: this.algorithm,
775
+ encoding: this.encoding,
776
+ secretHashLength: this.secretHash?.length
777
+ };
778
+ }
779
+ };
780
+
781
+ //#endregion
782
+ exports.BadRequestException = BadRequestException;
783
+ exports.BaseApi = BaseApi;
784
+ exports.Builder = Builder;
785
+ exports.Core = Core;
786
+ exports.ForbiddenRequestException = ForbiddenRequestException;
787
+ exports.Http = Http;
788
+ exports.HttpException = HttpException;
789
+ exports.UnauthorizedRequestException = UnauthorizedRequestException;
790
+ exports.WebhookValidator = WebhookValidator;
791
+ exports.buildUrl = buildUrl;
792
+ exports.createRuntimeApi = createRuntimeApi;
793
+ exports.createSdk = createSdk;
794
+ exports.defaultConfig = defaultConfig;
795
+ exports.defineConfig = defineConfig;
796
+ Object.defineProperty(exports, 'globalConfig', {
797
+ enumerable: true,
798
+ get: function () {
799
+ return globalConfig;
800
+ }
801
+ });
802
+ exports.normalizeValue = normalizeValue;