@omnitronix/rng-client-core 1.0.10 → 1.1.2

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.
Files changed (88) hide show
  1. package/dist/core/rng-client-core.d.ts +0 -1
  2. package/dist/core/rng-client-core.js +1 -1
  3. package/dist/errors/rng-errors.d.ts +0 -1
  4. package/dist/errors/rng-errors.js +1 -1
  5. package/dist/grpc/grpc-rng-client.d.ts +0 -1
  6. package/dist/grpc/grpc-rng-client.js +1 -1
  7. package/dist/grpc/grpc-rng-interface.d.ts +0 -1
  8. package/dist/grpc/grpc-rng-interface.js +1 -1
  9. package/dist/http/http-client.types.d.ts +0 -1
  10. package/dist/http/http-client.types.js +1 -1
  11. package/dist/http/http-rng-client.d.ts +0 -1
  12. package/dist/http/http-rng-client.js +1 -1
  13. package/dist/http/rest-client.d.ts +0 -1
  14. package/dist/http/rest-client.js +1 -1
  15. package/dist/http/rng-client.interface.d.ts +0 -1
  16. package/dist/http/rng-client.interface.js +1 -1
  17. package/dist/index.d.ts +6 -6
  18. package/dist/index.js +1 -1
  19. package/dist/interfaces/client-interfaces.d.ts +6 -3
  20. package/dist/interfaces/client-interfaces.js +1 -1
  21. package/dist/interfaces/metrics.d.ts +30 -0
  22. package/dist/interfaces/metrics.js +3 -0
  23. package/dist/metrics/default-metrics-handlers.d.ts +2 -0
  24. package/dist/metrics/default-metrics-handlers.js +23 -0
  25. package/dist/ring-buffer/interfaces.d.ts +0 -38
  26. package/dist/ring-buffer/interfaces.js +1 -1
  27. package/dist/ring-buffer/ring-buffer.d.ts +7 -14
  28. package/dist/ring-buffer/ring-buffer.js +63 -207
  29. package/dist/ring-buffer/ring-storage-memory.d.ts +1 -3
  30. package/dist/ring-buffer/ring-storage-memory.js +1 -25
  31. package/dist/ring-buffer/ring-storage.d.ts +1 -3
  32. package/dist/ring-buffer/ring-storage.js +1 -7
  33. package/dist/rng-client.d.ts +2 -5
  34. package/dist/rng-client.js +6 -4
  35. package/package.json +3 -2
  36. package/src/__tests__/grpc-rng-client.test.ts +167 -0
  37. package/src/__tests__/rng-client-core.integration.test.ts +117 -0
  38. package/src/__tests__/rng-client-core.test.ts +249 -0
  39. package/src/__tests__/rng-client-grpc.test.ts +324 -0
  40. package/src/__tests__/rng-client.test.ts +296 -0
  41. package/src/core/rng-client-core.ts +80 -0
  42. package/src/errors/rng-errors.ts +96 -0
  43. package/src/grpc/grpc-rng-client.ts +162 -0
  44. package/src/grpc/grpc-rng-interface.ts +36 -0
  45. package/src/http/http-client.types.ts +48 -0
  46. package/src/http/http-rng-client.ts +140 -0
  47. package/src/http/rest-client.ts +151 -0
  48. package/src/http/rng-client.interface.ts +22 -0
  49. package/src/index.ts +21 -0
  50. package/src/interfaces/client-interfaces.ts +15 -0
  51. package/src/interfaces/metrics.ts +38 -0
  52. package/src/metrics/default-metrics-handlers.ts +29 -0
  53. package/src/ring-buffer/interfaces.ts +9 -0
  54. package/src/ring-buffer/ring-buffer.ts +214 -0
  55. package/src/ring-buffer/ring-storage-memory.ts +48 -0
  56. package/src/ring-buffer/ring-storage.ts +59 -0
  57. package/src/rng-client.ts +190 -0
  58. package/src/rng.proto +102 -0
  59. package/dist/core/rng-client-core.d.ts.map +0 -1
  60. package/dist/core/rng-client-core.js.map +0 -1
  61. package/dist/errors/rng-errors.d.ts.map +0 -1
  62. package/dist/errors/rng-errors.js.map +0 -1
  63. package/dist/grpc/grpc-rng-client.d.ts.map +0 -1
  64. package/dist/grpc/grpc-rng-client.js.map +0 -1
  65. package/dist/grpc/grpc-rng-interface.d.ts.map +0 -1
  66. package/dist/grpc/grpc-rng-interface.js.map +0 -1
  67. package/dist/http/http-client.types.d.ts.map +0 -1
  68. package/dist/http/http-client.types.js.map +0 -1
  69. package/dist/http/http-rng-client.d.ts.map +0 -1
  70. package/dist/http/http-rng-client.js.map +0 -1
  71. package/dist/http/rest-client.d.ts.map +0 -1
  72. package/dist/http/rest-client.js.map +0 -1
  73. package/dist/http/rng-client.interface.d.ts.map +0 -1
  74. package/dist/http/rng-client.interface.js.map +0 -1
  75. package/dist/index.d.ts.map +0 -1
  76. package/dist/index.js.map +0 -1
  77. package/dist/interfaces/client-interfaces.d.ts.map +0 -1
  78. package/dist/interfaces/client-interfaces.js.map +0 -1
  79. package/dist/ring-buffer/interfaces.d.ts.map +0 -1
  80. package/dist/ring-buffer/interfaces.js.map +0 -1
  81. package/dist/ring-buffer/ring-buffer.d.ts.map +0 -1
  82. package/dist/ring-buffer/ring-buffer.js.map +0 -1
  83. package/dist/ring-buffer/ring-storage-memory.d.ts.map +0 -1
  84. package/dist/ring-buffer/ring-storage-memory.js.map +0 -1
  85. package/dist/ring-buffer/ring-storage.d.ts.map +0 -1
  86. package/dist/ring-buffer/ring-storage.js.map +0 -1
  87. package/dist/rng-client.d.ts.map +0 -1
  88. package/dist/rng-client.js.map +0 -1
@@ -0,0 +1,96 @@
1
+ import * as grpc from "@grpc/grpc-js";
2
+
3
+ export class RngServiceError extends Error {
4
+ constructor(
5
+ message: string,
6
+ public readonly code: string,
7
+ public readonly originalError?: unknown
8
+ ) {
9
+ super(message);
10
+ this.name = "RngServiceError";
11
+ }
12
+ }
13
+
14
+ export class RngConnectionError extends RngServiceError {
15
+ constructor(
16
+ message: string = "Unable to connect to RNG service",
17
+ originalError?: unknown
18
+ ) {
19
+ super(message, "SERVICE_UNAVAILABLE", originalError);
20
+ this.name = "RngConnectionError";
21
+ }
22
+ }
23
+
24
+ export class HttpConnectionError extends Error {
25
+ constructor(
26
+ message: string = "Unable to connect to RNG service",
27
+ public readonly originalError?: unknown
28
+ ) {
29
+ super(message);
30
+ this.name = "HttpConnectionError";
31
+ }
32
+ }
33
+
34
+ export class HttpServiceError extends Error {
35
+ constructor(
36
+ message: string,
37
+ public readonly statusCode: number,
38
+ public readonly originalError?: unknown
39
+ ) {
40
+ super(message);
41
+ this.name = "HttpServiceError";
42
+ }
43
+ }
44
+
45
+ export function handleGrpcError(
46
+ err: unknown,
47
+ operation: string,
48
+ grpcUrl?: string
49
+ ): never {
50
+ console.log(`RNG Client gRPC Error in ${operation}:`, err);
51
+
52
+ if (err && typeof err === "object" && "code" in err) {
53
+ const grpcError = err as grpc.ServiceError;
54
+
55
+ if (
56
+ grpcError.code === grpc.status.UNAVAILABLE ||
57
+ grpcError.code === grpc.status.DEADLINE_EXCEEDED ||
58
+ grpcError.code === grpc.status.UNKNOWN ||
59
+ grpcError.code === grpc.status.INTERNAL
60
+ ) {
61
+ throw new RngConnectionError(
62
+ grpcUrl
63
+ ? `Unable to connect to RNG service at ${grpcUrl}`
64
+ : "Unable to connect to RNG service",
65
+ err
66
+ );
67
+ }
68
+
69
+ throw new RngServiceError(
70
+ grpcError.details || grpcError.message || "Unknown gRPC error occurred",
71
+ grpcError.code?.toString() || "UNKNOWN",
72
+ err
73
+ );
74
+ }
75
+
76
+ if (err instanceof Error) {
77
+ if (
78
+ err.message.includes("ECONNREFUSED") ||
79
+ err.message.includes("ENOTFOUND") ||
80
+ err.message.includes("timeout")
81
+ ) {
82
+ throw new RngConnectionError(
83
+ grpcUrl
84
+ ? `Unable to connect to RNG service at ${grpcUrl}`
85
+ : "Unable to connect to RNG service",
86
+ err
87
+ );
88
+ }
89
+ }
90
+
91
+ throw new RngServiceError(
92
+ "An unexpected error occurred while communicating with the RNG service",
93
+ "UNKNOWN",
94
+ err
95
+ );
96
+ }
@@ -0,0 +1,162 @@
1
+ import * as grpc from "@grpc/grpc-js";
2
+ import * as protoLoader from "@grpc/proto-loader";
3
+ import { RngClientInterface } from "../http/rng-client.interface";
4
+ import {
5
+ RngBatchFloatRequest,
6
+ RngBatchRequest,
7
+ RngBatchResponse,
8
+ RngBatchResponseWithSeeds,
9
+ RngSingleFloatRequest,
10
+ RngSingleRequest,
11
+ RngSingleResponse,
12
+ } from "../http/http-client.types";
13
+ import { GrpcRngClientInterface } from "./grpc-rng-interface";
14
+ import { handleGrpcError } from "../errors/rng-errors";
15
+
16
+ const PROTO_PATH = __dirname + "/../rng.proto";
17
+
18
+ export class GrpcRngClient implements RngClientInterface {
19
+ private readonly client: GrpcRngClientInterface;
20
+ private readonly grpcUrl: string;
21
+
22
+ constructor(grpcUrl: string) {
23
+ this.grpcUrl = grpcUrl;
24
+
25
+ const packageDefinition = protoLoader.loadSync(PROTO_PATH, {
26
+ keepCase: true,
27
+ longs: String,
28
+ enums: String,
29
+ defaults: true,
30
+ oneofs: true,
31
+ });
32
+
33
+ const rngProto = grpc.loadPackageDefinition(packageDefinition)
34
+ .rng as grpc.GrpcObject;
35
+ this.client = new (rngProto as any).RngService(
36
+ this.grpcUrl,
37
+ grpc.credentials.createInsecure()
38
+ );
39
+ }
40
+
41
+ async getSingleNumber(request: RngSingleRequest): Promise<RngSingleResponse> {
42
+ return new Promise((resolve, reject) => {
43
+ this.client.Single(
44
+ request,
45
+ (err: unknown, response: RngSingleResponse) => {
46
+ if (err) {
47
+ try {
48
+ handleGrpcError(err, "getSingleNumber", this.grpcUrl);
49
+ } catch (error) {
50
+ reject(error);
51
+ }
52
+ } else {
53
+ resolve(response);
54
+ }
55
+ }
56
+ );
57
+ });
58
+ }
59
+
60
+ async getBatchNumbers(request: RngBatchRequest): Promise<RngBatchResponse> {
61
+ return new Promise((resolve, reject) => {
62
+ this.client.SingleBatch(
63
+ request,
64
+ (err: unknown, response: RngBatchResponse) => {
65
+ if (err) {
66
+ try {
67
+ handleGrpcError(err, "getBatchNumbers", this.grpcUrl);
68
+ } catch (error) {
69
+ reject(error);
70
+ }
71
+ } else {
72
+ resolve(response);
73
+ }
74
+ }
75
+ );
76
+ });
77
+ }
78
+
79
+ async getSingleFloat(
80
+ request: RngSingleFloatRequest
81
+ ): Promise<RngSingleResponse> {
82
+ return new Promise((resolve, reject) => {
83
+ this.client.Float(
84
+ request,
85
+ (err: unknown, response: RngSingleResponse) => {
86
+ if (err) {
87
+ try {
88
+ handleGrpcError(err, "getSingleFloat", this.grpcUrl);
89
+ } catch (error) {
90
+ reject(error);
91
+ }
92
+ } else {
93
+ resolve(response);
94
+ }
95
+ }
96
+ );
97
+ });
98
+ }
99
+
100
+ async getBatchFloats(
101
+ request: RngBatchFloatRequest
102
+ ): Promise<RngBatchResponse> {
103
+ return new Promise((resolve, reject) => {
104
+ this.client.FloatBatch(
105
+ request,
106
+ (err: unknown, response: RngBatchResponse) => {
107
+ if (err) {
108
+ try {
109
+ handleGrpcError(err, "getBatchFloats", this.grpcUrl);
110
+ } catch (error) {
111
+ reject(error);
112
+ }
113
+ } else {
114
+ resolve(response);
115
+ }
116
+ }
117
+ );
118
+ });
119
+ }
120
+
121
+ async getBatchNumbersWithSeeds(
122
+ request: RngBatchRequest
123
+ ): Promise<RngBatchResponseWithSeeds> {
124
+ return new Promise((resolve, reject) => {
125
+ this.client.SingleBatchWithSeeds(
126
+ request,
127
+ (err: unknown, response: RngBatchResponseWithSeeds) => {
128
+ if (err) {
129
+ try {
130
+ handleGrpcError(err, "getBatchNumbersWithSeeds", this.grpcUrl);
131
+ } catch (error) {
132
+ reject(error);
133
+ }
134
+ } else {
135
+ resolve(response);
136
+ }
137
+ }
138
+ );
139
+ });
140
+ }
141
+
142
+ async getBatchFloatWithSeeds(
143
+ request: RngSingleFloatRequest
144
+ ): Promise<RngBatchResponseWithSeeds> {
145
+ return new Promise((resolve, reject) => {
146
+ this.client.FloatBatchWithSeeds(
147
+ request,
148
+ (err: unknown, response: RngBatchResponseWithSeeds) => {
149
+ if (err) {
150
+ try {
151
+ handleGrpcError(err, "getBatchFloatWithSeeds", this.grpcUrl);
152
+ } catch (error) {
153
+ reject(error);
154
+ }
155
+ } else {
156
+ resolve(response);
157
+ }
158
+ }
159
+ );
160
+ });
161
+ }
162
+ }
@@ -0,0 +1,36 @@
1
+ import {
2
+ RngBatchFloatRequest,
3
+ RngBatchRequest,
4
+ RngBatchResponse,
5
+ RngBatchResponseWithSeeds,
6
+ RngSingleFloatRequest,
7
+ RngSingleRequest,
8
+ RngSingleResponse,
9
+ } from "../http/http-client.types";
10
+
11
+ export interface GrpcRngClientInterface {
12
+ Single(
13
+ request: RngSingleRequest,
14
+ callback: (err: unknown, response: RngSingleResponse) => void
15
+ ): Promise<RngSingleResponse>;
16
+ SingleBatch(
17
+ request: RngBatchRequest,
18
+ callback: (err: unknown, response: RngBatchResponse) => void
19
+ ): Promise<RngBatchResponse>;
20
+ Float(
21
+ request: RngSingleFloatRequest,
22
+ callback: (err: unknown, response: RngSingleResponse) => void
23
+ ): Promise<RngSingleResponse>;
24
+ FloatBatch(
25
+ request: RngBatchFloatRequest,
26
+ callback: (err: unknown, response: RngBatchResponse) => void
27
+ ): Promise<RngBatchResponse>;
28
+ SingleBatchWithSeeds(
29
+ request: RngBatchRequest,
30
+ callback: (err: unknown, response: RngBatchResponseWithSeeds) => void
31
+ ): Promise<RngBatchResponseWithSeeds>;
32
+ FloatBatchWithSeeds(
33
+ request: RngSingleFloatRequest,
34
+ callback: (err: unknown, response: RngBatchResponseWithSeeds) => void
35
+ ): Promise<RngBatchResponseWithSeeds>;
36
+ }
@@ -0,0 +1,48 @@
1
+ export interface RngSingleRequest {
2
+ min: number;
3
+ max: number;
4
+ seed?: number;
5
+ }
6
+
7
+ export interface RngBatchRequest {
8
+ min: number;
9
+ max: number;
10
+ count: number;
11
+ seed?: number;
12
+ }
13
+
14
+ export interface RngSingleFloatRequest {
15
+ seed?: number;
16
+ }
17
+
18
+ export interface RngBatchFloatRequest {
19
+ count: number;
20
+ seed?: number;
21
+ }
22
+
23
+ export interface RngSingleResponse {
24
+ id: string;
25
+ seed: number;
26
+ result: number;
27
+ min: number;
28
+ max: number;
29
+ createdAt: string;
30
+ }
31
+
32
+ export interface RngBatchResponse {
33
+ id: string;
34
+ seed: number;
35
+ result: number[];
36
+ min: number;
37
+ max: number;
38
+ createdAt: string;
39
+ }
40
+
41
+ export interface RngBatchResponseWithSeeds {
42
+ id: string;
43
+ seed: number;
44
+ result: { value: number; seed: number }[];
45
+ min: number;
46
+ max: number;
47
+ createdAt: string;
48
+ }
@@ -0,0 +1,140 @@
1
+ import { RngClientInterface } from "./rng-client.interface";
2
+ import {
3
+ RngBatchFloatRequest,
4
+ RngBatchRequest,
5
+ RngBatchResponse,
6
+ RngBatchResponseWithSeeds,
7
+ RngSingleFloatRequest,
8
+ RngSingleRequest,
9
+ RngSingleResponse,
10
+ } from "./http-client.types";
11
+ import { RestClient } from "./rest-client";
12
+ import { HttpConnectionError, HttpServiceError } from "../errors/rng-errors";
13
+
14
+ export class HttpRngClient extends RestClient implements RngClientInterface {
15
+ constructor(baseUrl: string) {
16
+ super(baseUrl);
17
+ }
18
+
19
+ async getSingleNumber(request: RngSingleRequest): Promise<RngSingleResponse> {
20
+ const response = await this.post<RngSingleResponse>(
21
+ "/api/rng/single",
22
+ request
23
+ );
24
+
25
+ if (!response.success) {
26
+ if (response.error === "ConnectionError" || response.statusCode === 503) {
27
+ throw new HttpConnectionError(response.message);
28
+ }
29
+ throw new HttpServiceError(
30
+ response.message || `HTTP error! status: ${response.statusCode}`,
31
+ response.statusCode
32
+ );
33
+ }
34
+
35
+ return response.data;
36
+ }
37
+
38
+ async getBatchNumbers(request: RngBatchRequest): Promise<RngBatchResponse> {
39
+ const response = await this.post<RngBatchResponse>(
40
+ "/api/rng/batch",
41
+ request
42
+ );
43
+
44
+ if (!response.success) {
45
+ if (response.error === "ConnectionError" || response.statusCode === 503) {
46
+ throw new HttpConnectionError(response.message);
47
+ }
48
+ throw new HttpServiceError(
49
+ response.message || `HTTP error! status: ${response.statusCode}`,
50
+ response.statusCode
51
+ );
52
+ }
53
+
54
+ return response.data;
55
+ }
56
+
57
+ async getSingleFloat(
58
+ request: RngSingleFloatRequest
59
+ ): Promise<RngSingleResponse> {
60
+ const response = await this.post<RngSingleResponse>(
61
+ "/api/rng/float",
62
+ request
63
+ );
64
+
65
+ if (!response.success) {
66
+ if (response.error === "ConnectionError" || response.statusCode === 503) {
67
+ throw new HttpConnectionError(response.message);
68
+ }
69
+ throw new HttpServiceError(
70
+ response.message || `HTTP error! status: ${response.statusCode}`,
71
+ response.statusCode
72
+ );
73
+ }
74
+
75
+ return response.data;
76
+ }
77
+
78
+ async getBatchFloats(
79
+ request: RngBatchFloatRequest
80
+ ): Promise<RngBatchResponse> {
81
+ const response = await this.post<RngBatchResponse>(
82
+ "/api/rng/batch/float",
83
+ request
84
+ );
85
+
86
+ if (!response.success) {
87
+ if (response.error === "ConnectionError" || response.statusCode === 503) {
88
+ throw new HttpConnectionError(response.message);
89
+ }
90
+ throw new HttpServiceError(
91
+ response.message || `HTTP error! status: ${response.statusCode}`,
92
+ response.statusCode
93
+ );
94
+ }
95
+
96
+ return response.data;
97
+ }
98
+
99
+ async getBatchNumbersWithSeeds(
100
+ request: RngBatchRequest
101
+ ): Promise<RngBatchResponseWithSeeds> {
102
+ const response = await this.post<RngBatchResponseWithSeeds>(
103
+ "/api/rng/batch/with-seeds",
104
+ request
105
+ );
106
+
107
+ if (!response.success) {
108
+ if (response.error === "ConnectionError" || response.statusCode === 503) {
109
+ throw new HttpConnectionError(response.message);
110
+ }
111
+ throw new HttpServiceError(
112
+ response.message || `HTTP error! status: ${response.statusCode}`,
113
+ response.statusCode
114
+ );
115
+ }
116
+
117
+ return response.data;
118
+ }
119
+
120
+ async getBatchFloatWithSeeds(
121
+ request: RngSingleFloatRequest
122
+ ): Promise<RngBatchResponseWithSeeds> {
123
+ const response = await this.post<RngBatchResponseWithSeeds>(
124
+ "/api/rng/batch/float/with-seeds",
125
+ request
126
+ );
127
+
128
+ if (!response.success) {
129
+ if (response.error === "ConnectionError" || response.statusCode === 503) {
130
+ throw new HttpConnectionError(response.message);
131
+ }
132
+ throw new HttpServiceError(
133
+ response.message || `HTTP error! status: ${response.statusCode}`,
134
+ response.statusCode
135
+ );
136
+ }
137
+
138
+ return response.data;
139
+ }
140
+ }
@@ -0,0 +1,151 @@
1
+ import axios, { AxiosError, AxiosInstance } from "axios";
2
+
3
+ export interface ApiErrorData {
4
+ internalCode?: number;
5
+ message?: string;
6
+ }
7
+
8
+ export interface ApiSuccessResponse<T> {
9
+ success: true;
10
+ data: T;
11
+ }
12
+
13
+ export interface ApiErrorResponse<E = null> {
14
+ success: false;
15
+ error: string;
16
+ message: string;
17
+ statusCode: number;
18
+ internalCode?: number;
19
+ data?: E;
20
+ }
21
+
22
+ export type ApiResponse<T, E = null> =
23
+ | ApiSuccessResponse<T>
24
+ | ApiErrorResponse<E>;
25
+
26
+ export class RestClient {
27
+ private httpClient: AxiosInstance;
28
+
29
+ constructor(baseUrl: string) {
30
+ this.httpClient = axios.create({
31
+ baseURL: baseUrl,
32
+ timeout: 5000,
33
+ headers: {
34
+ "Content-Type": "application/json",
35
+ },
36
+ });
37
+ }
38
+
39
+ private isApiErrorData(data: any): data is ApiErrorData {
40
+ return data && typeof data === "object" && "internalCode" in data;
41
+ }
42
+
43
+ private mapSuccessResponse<T>(data: T): ApiSuccessResponse<T> {
44
+ return { success: true, data };
45
+ }
46
+
47
+ private mapErrorResponse<E>(error: unknown): ApiErrorResponse<E> {
48
+ if (axios.isAxiosError(error)) {
49
+ const axiosError = error as AxiosError;
50
+ const status = axiosError.response?.status || 500;
51
+ const data = axiosError.response?.data ?? {};
52
+
53
+ if (
54
+ axiosError.code === "ECONNREFUSED" ||
55
+ axiosError.code === "ENOTFOUND" ||
56
+ axiosError.code === "ETIMEDOUT" ||
57
+ axiosError.message.includes("timeout") ||
58
+ axiosError.message.includes("ECONNREFUSED") ||
59
+ axiosError.message.includes("ENOTFOUND")
60
+ ) {
61
+ return {
62
+ success: false,
63
+ error: "ConnectionError",
64
+ message: "Unable to connect to RNG service",
65
+ statusCode: 503,
66
+ };
67
+ }
68
+
69
+ if (this.isApiErrorData(data)) {
70
+ return {
71
+ success: false,
72
+ error: "ApiError",
73
+ message: data.message ?? "An unexpected error occurred.",
74
+ statusCode: status,
75
+ internalCode: data.internalCode,
76
+ data: data as E,
77
+ };
78
+ }
79
+
80
+ return {
81
+ success: false,
82
+ error: "UnknownError",
83
+ message: "An unexpected error occurred.",
84
+ statusCode: status,
85
+ };
86
+ } else if (error instanceof Error) {
87
+ if (
88
+ error.message.includes("ECONNREFUSED") ||
89
+ error.message.includes("ENOTFOUND") ||
90
+ error.message.includes("timeout")
91
+ ) {
92
+ return {
93
+ success: false,
94
+ error: "ConnectionError",
95
+ message: "Unable to connect to RNG service",
96
+ statusCode: 503,
97
+ };
98
+ }
99
+
100
+ return {
101
+ success: false,
102
+ error: "UnexpectedError",
103
+ message: error.message || "An unknown error occurred.",
104
+ statusCode: 500,
105
+ };
106
+ }
107
+
108
+ return {
109
+ success: false,
110
+ error: "UnknownError",
111
+ message: "An unknown error occurred.",
112
+ statusCode: 500,
113
+ };
114
+ }
115
+
116
+ private async handleRequest<T, E = null>(
117
+ request: Promise<{ data: T }>
118
+ ): Promise<ApiResponse<T, E>> {
119
+ try {
120
+ const response = await request;
121
+ return this.mapSuccessResponse(response.data);
122
+ } catch (error) {
123
+ return this.mapErrorResponse<E>(error);
124
+ }
125
+ }
126
+
127
+ public async get<T, E = null>(
128
+ url: string,
129
+ params?: object
130
+ ): Promise<ApiResponse<T, E>> {
131
+ return this.handleRequest(this.httpClient.get<T>(url, { params }));
132
+ }
133
+
134
+ public async post<T, E = null>(
135
+ url: string,
136
+ data?: object
137
+ ): Promise<ApiResponse<T, E>> {
138
+ return this.handleRequest(this.httpClient.post<T>(url, data));
139
+ }
140
+
141
+ public async put<T, E = null>(
142
+ url: string,
143
+ data?: object
144
+ ): Promise<ApiResponse<T, E>> {
145
+ return this.handleRequest(this.httpClient.put<T>(url, data));
146
+ }
147
+
148
+ public async delete<T, E = null>(url: string): Promise<ApiResponse<T, E>> {
149
+ return this.handleRequest(this.httpClient.delete<T>(url));
150
+ }
151
+ }
@@ -0,0 +1,22 @@
1
+ import {
2
+ RngBatchFloatRequest,
3
+ RngBatchRequest,
4
+ RngBatchResponse,
5
+ RngBatchResponseWithSeeds,
6
+ RngSingleFloatRequest,
7
+ RngSingleRequest,
8
+ RngSingleResponse,
9
+ } from "./http-client.types";
10
+
11
+ export interface RngClientInterface {
12
+ getSingleNumber(request: RngSingleRequest): Promise<RngSingleResponse>;
13
+ getBatchNumbers(request: RngBatchRequest): Promise<RngBatchResponse>;
14
+ getSingleFloat(request: RngSingleFloatRequest): Promise<RngSingleResponse>;
15
+ getBatchFloats(request: RngBatchFloatRequest): Promise<RngBatchResponse>;
16
+ getBatchNumbersWithSeeds(
17
+ request: RngBatchRequest
18
+ ): Promise<RngBatchResponseWithSeeds>;
19
+ getBatchFloatWithSeeds(
20
+ request: RngSingleFloatRequest
21
+ ): Promise<RngBatchResponseWithSeeds>;
22
+ }
package/src/index.ts ADDED
@@ -0,0 +1,21 @@
1
+ // Main API
2
+ export { RngClient } from './rng-client';
3
+
4
+ // Clients
5
+ export { HttpRngClient } from './http/http-rng-client';
6
+ export { GrpcRngClient } from './grpc/grpc-rng-client';
7
+
8
+ export {
9
+ RngServiceError,
10
+ RngConnectionError,
11
+ HttpConnectionError,
12
+ HttpServiceError,
13
+ handleGrpcError,
14
+ } from './errors/rng-errors';
15
+
16
+ // Configuration
17
+ export type {
18
+ RngClientConfig,
19
+ ClientMethod,
20
+ } from './interfaces/client-interfaces';
21
+ export type { RngClientMetricsHandlers as MetricsHandlers } from './interfaces/metrics';
@@ -0,0 +1,15 @@
1
+ import { StorageType } from '../ring-buffer/ring-storage';
2
+ import { RngClientMetricsHandlers } from './metrics';
3
+
4
+ export type ClientMethod = 'rest' | 'grpc';
5
+
6
+ export interface RngClientConfig {
7
+ readonly serverUrl: string;
8
+ readonly grpcUrl: string;
9
+ readonly clientMethod: ClientMethod;
10
+ readonly poolingSize?: number;
11
+ readonly storageType?: StorageType;
12
+ readonly metrics?: {
13
+ handlers?: Partial<RngClientMetricsHandlers>;
14
+ };
15
+ }