bridgex 1.0.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.
@@ -0,0 +1,12 @@
1
+ interface HttpClientOptions {
2
+ baseUrl: string;
3
+ apiKey: string;
4
+ projectKey: string;
5
+ timeout?: number;
6
+ }
7
+ export default class HttpClient {
8
+ private options;
9
+ constructor(options: HttpClientOptions);
10
+ post(endpoint: string, body: unknown): Promise<any>;
11
+ }
12
+ export {};
@@ -0,0 +1,38 @@
1
+ import { NetworkError, ServerError } from "./errors.js";
2
+ export default class HttpClient {
3
+ constructor(options) {
4
+ this.options = options;
5
+ }
6
+ async post(endpoint, body) {
7
+ const { baseUrl, apiKey, projectKey, timeout = 5000 } = this.options;
8
+ const controller = new AbortController();
9
+ const timeoutId = setTimeout(() => controller.abort(), timeout);
10
+ try {
11
+ const response = await fetch(`${baseUrl}${endpoint}`, {
12
+ method: "POST",
13
+ headers: {
14
+ "Content-Type": "application/json",
15
+ "x-api-key": apiKey,
16
+ "x-project-key": projectKey,
17
+ },
18
+ body: JSON.stringify(body),
19
+ signal: controller.signal,
20
+ });
21
+ clearTimeout(timeoutId);
22
+ if (!response.ok) {
23
+ const text = await response.text();
24
+ throw new ServerError(`Server responded with ${response.status}`, text);
25
+ }
26
+ return await response.json();
27
+ }
28
+ catch (error) {
29
+ if (error.name === "AbortError") {
30
+ throw new NetworkError("Request timed out");
31
+ }
32
+ if (error instanceof ServerError) {
33
+ throw error;
34
+ }
35
+ throw new NetworkError("Network request failed", error);
36
+ }
37
+ }
38
+ }
@@ -0,0 +1,4 @@
1
+ export default class MessageFormatter {
2
+ format(template: string, params?: Record<string, unknown>): string;
3
+ fromObject(obj: Record<string, unknown>): string;
4
+ }
@@ -0,0 +1,21 @@
1
+ import { TemplateError, ValidationError } from "./errors.js";
2
+ import { isObject } from "./help.js";
3
+ export default class MessageFormatter {
4
+ format(template, params = {}) {
5
+ if (typeof template !== "string" || template.trim() === "") {
6
+ throw new ValidationError("Message template must be a non-empty string");
7
+ }
8
+ return template.replace(/\{(\w+)\}/g, (_, key) => {
9
+ if (!(key in params)) {
10
+ throw new TemplateError(`Missing template variable: ${key}`);
11
+ }
12
+ return String(params[key]);
13
+ });
14
+ }
15
+ fromObject(obj) {
16
+ if (!isObject(obj)) {
17
+ throw new ValidationError("Message object must be a valid object");
18
+ }
19
+ return JSON.stringify(obj);
20
+ }
21
+ }
@@ -0,0 +1,10 @@
1
+ export interface RetryOptions {
2
+ maxAttempts?: number;
3
+ delay?: number;
4
+ strategy?: "fixed" | "exponential";
5
+ }
6
+ export default class RetryHandler {
7
+ private options;
8
+ constructor(options?: RetryOptions);
9
+ execute<T>(operation: () => Promise<T>): Promise<T>;
10
+ }
@@ -0,0 +1,24 @@
1
+ import { setTimeout } from "node:timers/promises";
2
+ export default class RetryHandler {
3
+ constructor(options = {}) {
4
+ this.options = options;
5
+ }
6
+ async execute(operation) {
7
+ const { maxAttempts = 3, delay = 500, strategy = "fixed" } = this.options;
8
+ let attempt = 0;
9
+ while (attempt < maxAttempts) {
10
+ try {
11
+ return await operation();
12
+ }
13
+ catch (error) {
14
+ attempt++;
15
+ if (attempt >= maxAttempts) {
16
+ throw error;
17
+ }
18
+ const waitTime = strategy === "exponential" ? delay * 2 ** (attempt - 1) : delay;
19
+ await setTimeout(waitTime);
20
+ }
21
+ }
22
+ throw new Error("Retry failed unexpectedly");
23
+ }
24
+ }
@@ -0,0 +1,21 @@
1
+ import { type RetryOptions } from "../RetryHandler.js";
2
+ interface SMSClientOptions {
3
+ baseUrl: string;
4
+ apiKey: string;
5
+ projectKey: string;
6
+ retry?: RetryOptions;
7
+ }
8
+ export declare class SMSClient {
9
+ private options;
10
+ private http;
11
+ private retry;
12
+ private formatter;
13
+ constructor(options: SMSClientOptions);
14
+ private validateOptions;
15
+ send(params: {
16
+ to: string;
17
+ template: string;
18
+ variables?: Record<string, unknown>;
19
+ }): Promise<any>;
20
+ }
21
+ export {};
@@ -0,0 +1,41 @@
1
+ import HttpClient from "../HttpClient.js";
2
+ import RetryHandler from "../RetryHandler.js";
3
+ import MessageFormatter from "../MessageFormatter.js";
4
+ import { ValidationError } from "../errors.js";
5
+ export class SMSClient {
6
+ constructor(options) {
7
+ this.options = options;
8
+ this.validateOptions(options);
9
+ this.http = new HttpClient({
10
+ baseUrl: options.baseUrl,
11
+ apiKey: options.apiKey,
12
+ projectKey: options.projectKey,
13
+ });
14
+ this.retry = new RetryHandler(options.retry);
15
+ this.formatter = new MessageFormatter();
16
+ }
17
+ validateOptions(options) {
18
+ const { baseUrl, apiKey, projectKey } = options;
19
+ if (!baseUrl) {
20
+ throw new ValidationError("baseUrl is required");
21
+ }
22
+ if (!apiKey) {
23
+ throw new ValidationError("apiKey is required");
24
+ }
25
+ if (!projectKey) {
26
+ throw new ValidationError("projectKey is required");
27
+ }
28
+ }
29
+ async send(params) {
30
+ const { to, template, variables = {} } = params;
31
+ if (!to) {
32
+ throw new ValidationError("Recipient phone number is required");
33
+ }
34
+ const message = this.formatter.format(template, variables);
35
+ const payload = {
36
+ to,
37
+ message,
38
+ };
39
+ return this.retry.execute(() => this.http.post("/sms/send", payload));
40
+ }
41
+ }
@@ -0,0 +1,18 @@
1
+ type SMSClientConfigMode = "BASE" | "FAULT_TOLERANT";
2
+ type RetryOptions = {};
3
+ type CircuitBreakerOptions = {};
4
+ type BatchingOptions = {};
5
+ type QueueOptions = {};
6
+ export default class SMSClientConfig {
7
+ baseUrl: string;
8
+ apiKey: string;
9
+ mode: SMSClientConfigMode;
10
+ timeout: number;
11
+ retryOptions: RetryOptions;
12
+ circuitBreakerOptions: CircuitBreakerOptions;
13
+ batchingOptions: BatchingOptions;
14
+ queueOptions: QueueOptions;
15
+ constructor(baseUrl: string, apiKey: string, mode: SMSClientConfigMode, timeout: number, retryOptions: RetryOptions, circuitBreakerOptions: CircuitBreakerOptions, batchingOptions: BatchingOptions, queueOptions: QueueOptions);
16
+ }
17
+ export type Result = [string, Error | null];
18
+ export {};
@@ -0,0 +1,12 @@
1
+ export default class SMSClientConfig {
2
+ constructor(baseUrl, apiKey, mode, timeout, retryOptions, circuitBreakerOptions, batchingOptions, queueOptions) {
3
+ this.baseUrl = baseUrl;
4
+ this.apiKey = apiKey;
5
+ this.mode = mode;
6
+ this.timeout = timeout;
7
+ this.retryOptions = retryOptions;
8
+ this.circuitBreakerOptions = circuitBreakerOptions;
9
+ this.batchingOptions = batchingOptions;
10
+ this.queueOptions = queueOptions;
11
+ }
12
+ }
@@ -0,0 +1,18 @@
1
+ declare class SMSClientError extends Error {
2
+ code: string;
3
+ details?: unknown;
4
+ constructor(message: string, code: string, details?: unknown);
5
+ }
6
+ export declare class ServerError extends SMSClientError {
7
+ constructor(message: string, details?: unknown);
8
+ }
9
+ export declare class ValidationError extends SMSClientError {
10
+ constructor(message: string, details?: unknown);
11
+ }
12
+ export declare class TemplateError extends SMSClientError {
13
+ constructor(message: string, details?: unknown);
14
+ }
15
+ export declare class NetworkError extends SMSClientError {
16
+ constructor(message: string, details?: unknown);
17
+ }
18
+ export {};
package/dist/errors.js ADDED
@@ -0,0 +1,29 @@
1
+ class SMSClientError extends Error {
2
+ constructor(message, code, details) {
3
+ super(message);
4
+ this.name = this.constructor.name;
5
+ this.code = code;
6
+ this.details = details;
7
+ Object.setPrototypeOf(this, new.target.prototype);
8
+ }
9
+ }
10
+ export class ServerError extends SMSClientError {
11
+ constructor(message, details) {
12
+ super(message, "SERVER_ERROR", details);
13
+ }
14
+ }
15
+ export class ValidationError extends SMSClientError {
16
+ constructor(message, details) {
17
+ super(message, "VALIDATION_ERROR", details);
18
+ }
19
+ }
20
+ export class TemplateError extends SMSClientError {
21
+ constructor(message, details) {
22
+ super(message, "TEMPLATE_ERROR", details);
23
+ }
24
+ }
25
+ export class NetworkError extends SMSClientError {
26
+ constructor(message, details) {
27
+ super(message, "NETWORK_ERROR", details);
28
+ }
29
+ }
package/dist/help.d.ts ADDED
@@ -0,0 +1 @@
1
+ export declare function isObject(value: unknown): value is Record<string, unknown>;
package/dist/help.js ADDED
@@ -0,0 +1,3 @@
1
+ export function isObject(value) {
2
+ return typeof value === "object" && value !== null && !Array.isArray(value);
3
+ }
package/dist/main.d.ts ADDED
@@ -0,0 +1 @@
1
+ export { SMSClient } from "./client/SMSManager.js";
package/dist/main.js ADDED
@@ -0,0 +1 @@
1
+ export { SMSClient } from "./client/SMSManager.js";
package/package.json ADDED
@@ -0,0 +1,20 @@
1
+ {
2
+ "name": "bridgex",
3
+ "version": "1.0.0",
4
+ "description": "a library for mazz app or a bridge for messaging that allow and automate the use of our service",
5
+ "keywords": [
6
+ "messaging",
7
+ "sms"
8
+ ],
9
+ "license": "ISC",
10
+ "author": "MouadhBNB7741",
11
+ "type": "module",
12
+ "main": "main.ts",
13
+ "scripts": {
14
+ "test": "echo \"Error: no test specified\" && exit 1",
15
+ "build": "tsc"
16
+ },
17
+ "devDependencies": {
18
+ "typescript": "^5.9.3"
19
+ }
20
+ }
@@ -0,0 +1,51 @@
1
+ import { NetworkError, ServerError } from "./errors.js";
2
+
3
+ interface HttpClientOptions {
4
+ baseUrl: string;
5
+ apiKey: string;
6
+ projectKey: string;
7
+ timeout?: number;
8
+ }
9
+
10
+ export default class HttpClient {
11
+ constructor(private options: HttpClientOptions) {}
12
+
13
+ async post(endpoint: string, body: unknown): Promise<any> {
14
+ const { baseUrl, apiKey, projectKey, timeout = 5000 } = this.options;
15
+
16
+ const controller = new AbortController();
17
+ const timeoutId = setTimeout(() => controller.abort(), timeout);
18
+
19
+ try {
20
+ const response = await fetch(`${baseUrl}${endpoint}`, {
21
+ method: "POST",
22
+ headers: {
23
+ "Content-Type": "application/json",
24
+ "x-api-key": apiKey,
25
+ "x-project-key": projectKey,
26
+ },
27
+ body: JSON.stringify(body),
28
+ signal: controller.signal,
29
+ });
30
+
31
+ clearTimeout(timeoutId);
32
+
33
+ if (!response.ok) {
34
+ const text = await response.text();
35
+ throw new ServerError(`Server responded with ${response.status}`, text);
36
+ }
37
+
38
+ return await response.json();
39
+ } catch (error: any) {
40
+ if (error.name === "AbortError") {
41
+ throw new NetworkError("Request timed out");
42
+ }
43
+
44
+ if (error instanceof ServerError) {
45
+ throw error;
46
+ }
47
+
48
+ throw new NetworkError("Network request failed", error);
49
+ }
50
+ }
51
+ }
@@ -0,0 +1,26 @@
1
+ import { TemplateError, ValidationError } from "./errors.js";
2
+ import { isObject } from "./help.js";
3
+
4
+ export default class MessageFormatter {
5
+ format(template: string, params: Record<string, unknown> = {}): string {
6
+ if (typeof template !== "string" || template.trim() === "") {
7
+ throw new ValidationError("Message template must be a non-empty string");
8
+ }
9
+
10
+ return template.replace(/\{(\w+)\}/g, (_, key) => {
11
+ if (!(key in params)) {
12
+ throw new TemplateError(`Missing template variable: ${key}`);
13
+ }
14
+
15
+ return String(params[key]);
16
+ });
17
+ }
18
+
19
+ fromObject(obj: Record<string, unknown>): string {
20
+ if (!isObject(obj)) {
21
+ throw new ValidationError("Message object must be a valid object");
22
+ }
23
+
24
+ return JSON.stringify(obj);
25
+ }
26
+ }
@@ -0,0 +1,36 @@
1
+ import { setTimeout } from "node:timers/promises";
2
+
3
+ export interface RetryOptions {
4
+ maxAttempts?: number;
5
+ delay?: number;
6
+ strategy?: "fixed" | "exponential";
7
+ }
8
+
9
+ export default class RetryHandler {
10
+ constructor(private options: RetryOptions = {}) {}
11
+
12
+ async execute<T>(operation: () => Promise<T>): Promise<T> {
13
+ const { maxAttempts = 3, delay = 500, strategy = "fixed" } = this.options;
14
+
15
+ let attempt = 0;
16
+
17
+ while (attempt < maxAttempts) {
18
+ try {
19
+ return await operation();
20
+ } catch (error) {
21
+ attempt++;
22
+
23
+ if (attempt >= maxAttempts) {
24
+ throw error;
25
+ }
26
+
27
+ const waitTime =
28
+ strategy === "exponential" ? delay * 2 ** (attempt - 1) : delay;
29
+
30
+ await setTimeout(waitTime);
31
+ }
32
+ }
33
+
34
+ throw new Error("Retry failed unexpectedly");
35
+ }
36
+ }
@@ -0,0 +1,67 @@
1
+ import HttpClient from "../HttpClient.js";
2
+ import RetryHandler, { type RetryOptions } from "../RetryHandler.js";
3
+ import MessageFormatter from "../MessageFormatter.js";
4
+ import { ValidationError } from "../errors.js";
5
+
6
+ interface SMSClientOptions {
7
+ baseUrl: string;
8
+ apiKey: string;
9
+ projectKey: string;
10
+ retry?: RetryOptions;
11
+ }
12
+
13
+ export class SMSClient {
14
+ private http: HttpClient;
15
+ private retry: RetryHandler;
16
+ private formatter: MessageFormatter;
17
+
18
+ constructor(private options: SMSClientOptions) {
19
+ this.validateOptions(options);
20
+
21
+ this.http = new HttpClient({
22
+ baseUrl: options.baseUrl,
23
+ apiKey: options.apiKey,
24
+ projectKey: options.projectKey,
25
+ });
26
+
27
+ this.retry = new RetryHandler(options.retry);
28
+ this.formatter = new MessageFormatter();
29
+ }
30
+
31
+ private validateOptions(options: SMSClientOptions): void {
32
+ const { baseUrl, apiKey, projectKey } = options;
33
+
34
+ if (!baseUrl) {
35
+ throw new ValidationError("baseUrl is required");
36
+ }
37
+
38
+ if (!apiKey) {
39
+ throw new ValidationError("apiKey is required");
40
+ }
41
+
42
+ if (!projectKey) {
43
+ throw new ValidationError("projectKey is required");
44
+ }
45
+ }
46
+
47
+ async send(params: {
48
+ to: string;
49
+ template: string;
50
+ variables?: Record<string, unknown>;
51
+ }): Promise<any> {
52
+ const { to, template, variables = {} } = params;
53
+
54
+ if (!to) {
55
+ throw new ValidationError("Recipient phone number is required");
56
+ }
57
+
58
+ const message = this.formatter.format(template, variables);
59
+
60
+ const payload = {
61
+ to,
62
+ message,
63
+ };
64
+
65
+ return this.retry.execute(() => this.http.post("/sms/send", payload));
66
+ }
67
+ }
@@ -0,0 +1,24 @@
1
+ type SMSClientConfigMode = "BASE" | "FAULT_TOLERANT";
2
+
3
+ type RetryOptions = {};
4
+
5
+ type CircuitBreakerOptions = {};
6
+
7
+ type BatchingOptions = {};
8
+
9
+ type QueueOptions = {};
10
+
11
+ export default class SMSClientConfig {
12
+ constructor(
13
+ public baseUrl: string,
14
+ public apiKey: string,
15
+ public mode: SMSClientConfigMode,
16
+ public timeout: number,
17
+ public retryOptions: RetryOptions,
18
+ public circuitBreakerOptions: CircuitBreakerOptions,
19
+ public batchingOptions: BatchingOptions,
20
+ public queueOptions: QueueOptions,
21
+ ) {}
22
+ }
23
+
24
+ export type Result = [string, Error | null];
package/src/errors.ts ADDED
@@ -0,0 +1,37 @@
1
+ class SMSClientError extends Error {
2
+ public code: string;
3
+ public details?: unknown;
4
+
5
+ constructor(message: string, code: string, details?: unknown) {
6
+ super(message);
7
+ this.name = this.constructor.name;
8
+ this.code = code;
9
+ this.details = details;
10
+
11
+ Object.setPrototypeOf(this, new.target.prototype);
12
+ }
13
+ }
14
+
15
+ export class ServerError extends SMSClientError {
16
+ constructor(message: string, details?: unknown) {
17
+ super(message, "SERVER_ERROR", details);
18
+ }
19
+ }
20
+
21
+ export class ValidationError extends SMSClientError {
22
+ constructor(message: string, details?: unknown) {
23
+ super(message, "VALIDATION_ERROR", details);
24
+ }
25
+ }
26
+
27
+ export class TemplateError extends SMSClientError {
28
+ constructor(message: string, details?: unknown) {
29
+ super(message, "TEMPLATE_ERROR", details);
30
+ }
31
+ }
32
+
33
+ export class NetworkError extends SMSClientError {
34
+ constructor(message: string, details?: unknown) {
35
+ super(message, "NETWORK_ERROR", details);
36
+ }
37
+ }
package/src/help.ts ADDED
@@ -0,0 +1,3 @@
1
+ export function isObject(value: unknown): value is Record<string, unknown> {
2
+ return typeof value === "object" && value !== null && !Array.isArray(value);
3
+ }
package/src/main.ts ADDED
@@ -0,0 +1 @@
1
+ export { SMSClient } from "./client/SMSManager.js";
package/tsconfig.json ADDED
@@ -0,0 +1,14 @@
1
+ {
2
+ "compilerOptions": {
3
+ "target": "ES2020",
4
+ "module": "ESNext",
5
+ "moduleResolution": "Node",
6
+ "declaration": true,
7
+ "outDir": "dist",
8
+ "rootDir": "src",
9
+ "strict": true,
10
+ "esModuleInterop": true,
11
+ "skipLibCheck": true
12
+ },
13
+ "include": ["src"]
14
+ }