@burdenoff/be-sdk 2026.510.79
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 +173 -0
- package/configs/eslint/index.js +492 -0
- package/configs/tsconfig/tsconfig.json +53 -0
- package/dist/EventQueueFactory-6NMSGECR.js +8 -0
- package/dist/EventQueueFactory-6NMSGECR.js.map +1 -0
- package/dist/auth/index.d.ts +66 -0
- package/dist/auth/index.js +8 -0
- package/dist/auth/index.js.map +1 -0
- package/dist/cache/index.d.ts +2 -0
- package/dist/cache/index.js +6 -0
- package/dist/cache/index.js.map +1 -0
- package/dist/captcha/index.d.ts +1 -0
- package/dist/captcha/index.js +4 -0
- package/dist/captcha/index.js.map +1 -0
- package/dist/chunk-2HANKZZM.js +245 -0
- package/dist/chunk-2HANKZZM.js.map +1 -0
- package/dist/chunk-2SD5L2F2.js +816 -0
- package/dist/chunk-2SD5L2F2.js.map +1 -0
- package/dist/chunk-3O2RQOPV.js +1068 -0
- package/dist/chunk-3O2RQOPV.js.map +1 -0
- package/dist/chunk-4B43DZIS.js +560 -0
- package/dist/chunk-4B43DZIS.js.map +1 -0
- package/dist/chunk-4XAEES25.js +2444 -0
- package/dist/chunk-4XAEES25.js.map +1 -0
- package/dist/chunk-4XGGWW36.js +1405 -0
- package/dist/chunk-4XGGWW36.js.map +1 -0
- package/dist/chunk-5LXDPGDH.js +245 -0
- package/dist/chunk-5LXDPGDH.js.map +1 -0
- package/dist/chunk-AI7L22ZJ.js +472 -0
- package/dist/chunk-AI7L22ZJ.js.map +1 -0
- package/dist/chunk-CBZNP6RF.js +286 -0
- package/dist/chunk-CBZNP6RF.js.map +1 -0
- package/dist/chunk-ELLX3K54.js +613 -0
- package/dist/chunk-ELLX3K54.js.map +1 -0
- package/dist/chunk-F5XEAGHQ.js +1875 -0
- package/dist/chunk-F5XEAGHQ.js.map +1 -0
- package/dist/chunk-FNZEQOJY.js +628 -0
- package/dist/chunk-FNZEQOJY.js.map +1 -0
- package/dist/chunk-GTEMQXCA.js +516 -0
- package/dist/chunk-GTEMQXCA.js.map +1 -0
- package/dist/chunk-HIWTWIGQ.js +226 -0
- package/dist/chunk-HIWTWIGQ.js.map +1 -0
- package/dist/chunk-IYE2NTRX.js +764 -0
- package/dist/chunk-IYE2NTRX.js.map +1 -0
- package/dist/chunk-J26YGR2U.js +1484 -0
- package/dist/chunk-J26YGR2U.js.map +1 -0
- package/dist/chunk-JG2FTZPI.js +509 -0
- package/dist/chunk-JG2FTZPI.js.map +1 -0
- package/dist/chunk-JVBTNSPG.js +1551 -0
- package/dist/chunk-JVBTNSPG.js.map +1 -0
- package/dist/chunk-L7ZMN2FJ.js +12 -0
- package/dist/chunk-L7ZMN2FJ.js.map +1 -0
- package/dist/chunk-M5IMU3US.js +473 -0
- package/dist/chunk-M5IMU3US.js.map +1 -0
- package/dist/chunk-MLW2HPS5.js +1267 -0
- package/dist/chunk-MLW2HPS5.js.map +1 -0
- package/dist/chunk-MNCGUYLJ.js +269 -0
- package/dist/chunk-MNCGUYLJ.js.map +1 -0
- package/dist/chunk-MOCUBSTW.js +373 -0
- package/dist/chunk-MOCUBSTW.js.map +1 -0
- package/dist/chunk-NGMEI42S.js +103 -0
- package/dist/chunk-NGMEI42S.js.map +1 -0
- package/dist/chunk-NUB5GQTU.js +270 -0
- package/dist/chunk-NUB5GQTU.js.map +1 -0
- package/dist/chunk-OVSYMNCI.js +145 -0
- package/dist/chunk-OVSYMNCI.js.map +1 -0
- package/dist/chunk-QLVKMWFA.js +94 -0
- package/dist/chunk-QLVKMWFA.js.map +1 -0
- package/dist/chunk-SAG6ZYWQ.js +89 -0
- package/dist/chunk-SAG6ZYWQ.js.map +1 -0
- package/dist/chunk-SAK2JCA7.js +198 -0
- package/dist/chunk-SAK2JCA7.js.map +1 -0
- package/dist/chunk-SBS4S2PJ.js +100 -0
- package/dist/chunk-SBS4S2PJ.js.map +1 -0
- package/dist/chunk-SNEOLWXT.js +148 -0
- package/dist/chunk-SNEOLWXT.js.map +1 -0
- package/dist/chunk-TKBD2ONF.js +564 -0
- package/dist/chunk-TKBD2ONF.js.map +1 -0
- package/dist/chunk-UBXFIIAW.js +127 -0
- package/dist/chunk-UBXFIIAW.js.map +1 -0
- package/dist/chunk-VI4VSNTI.js +57 -0
- package/dist/chunk-VI4VSNTI.js.map +1 -0
- package/dist/chunk-VWCN5PMD.js +268 -0
- package/dist/chunk-VWCN5PMD.js.map +1 -0
- package/dist/chunk-XC2YD6CF.js +913 -0
- package/dist/chunk-XC2YD6CF.js.map +1 -0
- package/dist/chunk-XE4OXN2W.js +10 -0
- package/dist/chunk-XE4OXN2W.js.map +1 -0
- package/dist/chunk-YMZEUTD2.js +110 -0
- package/dist/chunk-YMZEUTD2.js.map +1 -0
- package/dist/chunk-Z4IRLBWO.js +758 -0
- package/dist/chunk-Z4IRLBWO.js.map +1 -0
- package/dist/client/internal-client.d.ts +7 -0
- package/dist/client/internal-client.js +5 -0
- package/dist/client/internal-client.js.map +1 -0
- package/dist/client-CSjIrYKS.d.ts +77 -0
- package/dist/config-UKE2E3BW.js +4 -0
- package/dist/config-UKE2E3BW.js.map +1 -0
- package/dist/crypto/index.d.ts +1 -0
- package/dist/crypto/index.js +4 -0
- package/dist/crypto/index.js.map +1 -0
- package/dist/database/index.d.ts +117 -0
- package/dist/database/index.js +7 -0
- package/dist/database/index.js.map +1 -0
- package/dist/dataloader/index.d.ts +1 -0
- package/dist/dataloader/index.js +4 -0
- package/dist/dataloader/index.js.map +1 -0
- package/dist/esm-K6H7EIWK.js +1450 -0
- package/dist/esm-K6H7EIWK.js.map +1 -0
- package/dist/event-queue/index.d.ts +6 -0
- package/dist/event-queue/index.js +10 -0
- package/dist/event-queue/index.js.map +1 -0
- package/dist/export/index.d.ts +2 -0
- package/dist/export/index.js +9 -0
- package/dist/export/index.js.map +1 -0
- package/dist/feature-flags/index.d.ts +1 -0
- package/dist/feature-flags/index.js +4 -0
- package/dist/feature-flags/index.js.map +1 -0
- package/dist/gateway/index.d.ts +4 -0
- package/dist/gateway/index.js +8 -0
- package/dist/gateway/index.js.map +1 -0
- package/dist/gateway/security/index.d.ts +2 -0
- package/dist/gateway/security/index.js +5 -0
- package/dist/gateway/security/index.js.map +1 -0
- package/dist/graph/index.d.ts +9 -0
- package/dist/graph/index.js +13 -0
- package/dist/graph/index.js.map +1 -0
- package/dist/graph-emitter-Bk0FqD53.d.ts +47 -0
- package/dist/graphql/index.d.ts +2 -0
- package/dist/graphql/index.js +7 -0
- package/dist/graphql/index.js.map +1 -0
- package/dist/graphql/services/index.d.ts +24 -0
- package/dist/graphql/services/index.js +5 -0
- package/dist/graphql/services/index.js.map +1 -0
- package/dist/graphql-BAVrUgBF.d.ts +22 -0
- package/dist/i18n/index.d.ts +2 -0
- package/dist/i18n/index.js +5 -0
- package/dist/i18n/index.js.map +1 -0
- package/dist/i18n-DA6IPnYy.d.ts +101 -0
- package/dist/index-4gKQKZ2B.d.ts +71 -0
- package/dist/index-B18rrFru.d.ts +42 -0
- package/dist/index-B70b5mYS.d.ts +33 -0
- package/dist/index-BMq3lFjj.d.ts +247 -0
- package/dist/index-BODgvRtL.d.ts +316 -0
- package/dist/index-BS2idbnr.d.ts +874 -0
- package/dist/index-BV3G48cH.d.ts +124 -0
- package/dist/index-CHbVw5M7.d.ts +73 -0
- package/dist/index-Cq_xNjcv.d.ts +602 -0
- package/dist/index-CrQgidpx.d.ts +77 -0
- package/dist/index-CyVEg86m.d.ts +309 -0
- package/dist/index-DOcBnmMe.d.ts +166 -0
- package/dist/index-DSOpj8DI.d.ts +17 -0
- package/dist/index-DW9q22GH.d.ts +75 -0
- package/dist/index-DlFDFyWD.d.ts +55 -0
- package/dist/index-DoK0bjhH.d.ts +607 -0
- package/dist/index-Dtf6FBaD.d.ts +199 -0
- package/dist/index-KVWGHMbS.d.ts +415 -0
- package/dist/index-PaojfSdd.d.ts +71 -0
- package/dist/index-RU_M5c74.d.ts +163 -0
- package/dist/index-UhkH2eaB.d.ts +192 -0
- package/dist/index-e_18DzAg.d.ts +18 -0
- package/dist/index-jOuh_TKn.d.ts +59 -0
- package/dist/index.d.ts +584 -0
- package/dist/index.js +2626 -0
- package/dist/index.js.map +1 -0
- package/dist/init/index.d.ts +2 -0
- package/dist/init/index.js +12 -0
- package/dist/init/index.js.map +1 -0
- package/dist/instrumentation/index.d.ts +3 -0
- package/dist/instrumentation/index.js +5 -0
- package/dist/instrumentation/index.js.map +1 -0
- package/dist/layer/index.d.ts +2 -0
- package/dist/layer/index.js +6 -0
- package/dist/layer/index.js.map +1 -0
- package/dist/layer-DDip18KY.d.ts +67 -0
- package/dist/logger/index.d.ts +2 -0
- package/dist/logger/index.js +4 -0
- package/dist/logger/index.js.map +1 -0
- package/dist/middleware/index.d.ts +3 -0
- package/dist/middleware/index.js +5 -0
- package/dist/middleware/index.js.map +1 -0
- package/dist/notifications/index.d.ts +4 -0
- package/dist/notifications/index.js +7 -0
- package/dist/notifications/index.js.map +1 -0
- package/dist/observability/index.d.ts +3 -0
- package/dist/observability/index.js +5 -0
- package/dist/observability/index.js.map +1 -0
- package/dist/pino-logger-RYLGXPHZ.js +5 -0
- package/dist/pino-logger-RYLGXPHZ.js.map +1 -0
- package/dist/prisma/generator/index.d.ts +1 -0
- package/dist/prisma/generator/index.js +228 -0
- package/dist/prisma/generator/index.js.map +1 -0
- package/dist/prisma/index.d.ts +5 -0
- package/dist/prisma/index.js +12 -0
- package/dist/prisma/index.js.map +1 -0
- package/dist/prisma-extension-krXnYnrN.d.ts +30 -0
- package/dist/rbac/index.d.ts +116 -0
- package/dist/rbac/index.js +7 -0
- package/dist/rbac/index.js.map +1 -0
- package/dist/sdk-THO3IWEE.js +136 -0
- package/dist/sdk-THO3IWEE.js.map +1 -0
- package/dist/server/index.d.ts +359 -0
- package/dist/server/index.js +884 -0
- package/dist/server/index.js.map +1 -0
- package/dist/telemetry/index.d.ts +83 -0
- package/dist/telemetry/index.js +209 -0
- package/dist/telemetry/index.js.map +1 -0
- package/dist/temporal/index.d.ts +148 -0
- package/dist/temporal/index.js +6 -0
- package/dist/temporal/index.js.map +1 -0
- package/dist/tracker/index.d.ts +5 -0
- package/dist/tracker/index.js +9 -0
- package/dist/tracker/index.js.map +1 -0
- package/dist/types-Bo2wkjSP.d.ts +35 -0
- package/dist/utils/index.d.ts +1 -0
- package/dist/utils/index.js +4 -0
- package/dist/utils/index.js.map +1 -0
- package/dist/workspace-guard-LHBNK4TG.js +5 -0
- package/dist/workspace-guard-LHBNK4TG.js.map +1 -0
- package/package.json +241 -0
|
@@ -0,0 +1,560 @@
|
|
|
1
|
+
import { security_exports } from './chunk-MLW2HPS5.js';
|
|
2
|
+
import { LayerManager } from './chunk-HIWTWIGQ.js';
|
|
3
|
+
import { DEFAULT_CIRCUIT_BREAKER_CONFIG, DEFAULT_GATEWAY_RETRY_CONFIG } from './chunk-NGMEI42S.js';
|
|
4
|
+
import { logger } from './chunk-CBZNP6RF.js';
|
|
5
|
+
import { __export, __name } from './chunk-XE4OXN2W.js';
|
|
6
|
+
|
|
7
|
+
// src/gateway/index.ts
|
|
8
|
+
var gateway_exports = {};
|
|
9
|
+
__export(gateway_exports, {
|
|
10
|
+
CircuitState: () => CircuitState,
|
|
11
|
+
GatewayClient: () => GatewayClient,
|
|
12
|
+
GatewayError: () => GatewayError,
|
|
13
|
+
GatewayErrorType: () => GatewayErrorType,
|
|
14
|
+
Security: () => security_exports,
|
|
15
|
+
createGatewayClient: () => createGatewayClient,
|
|
16
|
+
createGatewayClientFromEnv: () => createGatewayClientFromEnv
|
|
17
|
+
});
|
|
18
|
+
|
|
19
|
+
// src/gateway/service-jwt.ts
|
|
20
|
+
var SIGNING_ENV_VAR = "SERVICE_JWT_SECRET";
|
|
21
|
+
var KEY_ID = "service-v1";
|
|
22
|
+
var DEFAULT_TTL_SECONDS = 60;
|
|
23
|
+
var REFRESH_BEFORE_EXP_MS = 1e4;
|
|
24
|
+
var joseModule = null;
|
|
25
|
+
async function getJose() {
|
|
26
|
+
if (!joseModule) {
|
|
27
|
+
joseModule = await import('jose');
|
|
28
|
+
}
|
|
29
|
+
return joseModule;
|
|
30
|
+
}
|
|
31
|
+
__name(getJose, "getJose");
|
|
32
|
+
var cache = /* @__PURE__ */ new Map();
|
|
33
|
+
function cacheKey(actorId, ttlSeconds) {
|
|
34
|
+
return `${actorId}:${ttlSeconds}`;
|
|
35
|
+
}
|
|
36
|
+
__name(cacheKey, "cacheKey");
|
|
37
|
+
async function signServiceJwt(actorId, ttlSeconds = DEFAULT_TTL_SECONDS) {
|
|
38
|
+
const secret = process.env[SIGNING_ENV_VAR];
|
|
39
|
+
if (!secret) {
|
|
40
|
+
return null;
|
|
41
|
+
}
|
|
42
|
+
const key = cacheKey(actorId, ttlSeconds);
|
|
43
|
+
const cached = cache.get(key);
|
|
44
|
+
if (cached && cached.expiresAtMs - REFRESH_BEFORE_EXP_MS > Date.now()) {
|
|
45
|
+
return cached.token;
|
|
46
|
+
}
|
|
47
|
+
const joseLib = await getJose();
|
|
48
|
+
const encoder = new TextEncoder();
|
|
49
|
+
const keyBytes = encoder.encode(secret);
|
|
50
|
+
const nowSec = Math.floor(Date.now() / 1e3);
|
|
51
|
+
const expSec = nowSec + ttlSeconds;
|
|
52
|
+
const token = await new joseLib.SignJWT({
|
|
53
|
+
actor_type: "service"
|
|
54
|
+
}).setProtectedHeader({
|
|
55
|
+
alg: "HS256",
|
|
56
|
+
typ: "JWT",
|
|
57
|
+
kid: KEY_ID
|
|
58
|
+
}).setSubject(actorId).setIssuer(actorId).setIssuedAt(nowSec).setExpirationTime(expSec).sign(keyBytes);
|
|
59
|
+
cache.set(key, {
|
|
60
|
+
token,
|
|
61
|
+
expiresAtMs: expSec * 1e3
|
|
62
|
+
});
|
|
63
|
+
return token;
|
|
64
|
+
}
|
|
65
|
+
__name(signServiceJwt, "signServiceJwt");
|
|
66
|
+
|
|
67
|
+
// src/gateway/types.ts
|
|
68
|
+
var CircuitState = /* @__PURE__ */ (function(CircuitState2) {
|
|
69
|
+
CircuitState2["CLOSED"] = "CLOSED";
|
|
70
|
+
CircuitState2["OPEN"] = "OPEN";
|
|
71
|
+
CircuitState2["HALF_OPEN"] = "HALF_OPEN";
|
|
72
|
+
return CircuitState2;
|
|
73
|
+
})({});
|
|
74
|
+
var GatewayErrorType = /* @__PURE__ */ (function(GatewayErrorType2) {
|
|
75
|
+
GatewayErrorType2["NETWORK_ERROR"] = "NETWORK_ERROR";
|
|
76
|
+
GatewayErrorType2["TIMEOUT_ERROR"] = "TIMEOUT_ERROR";
|
|
77
|
+
GatewayErrorType2["CIRCUIT_OPEN"] = "CIRCUIT_OPEN";
|
|
78
|
+
GatewayErrorType2["GRAPHQL_ERROR"] = "GRAPHQL_ERROR";
|
|
79
|
+
GatewayErrorType2["UNKNOWN_ERROR"] = "UNKNOWN_ERROR";
|
|
80
|
+
return GatewayErrorType2;
|
|
81
|
+
})({});
|
|
82
|
+
var GatewayError = class _GatewayError extends Error {
|
|
83
|
+
static {
|
|
84
|
+
__name(this, "GatewayError");
|
|
85
|
+
}
|
|
86
|
+
type;
|
|
87
|
+
gatewayUrl;
|
|
88
|
+
statusCode;
|
|
89
|
+
graphqlErrors;
|
|
90
|
+
cause;
|
|
91
|
+
constructor(message, type, gatewayUrl, options) {
|
|
92
|
+
super(message);
|
|
93
|
+
this.name = "GatewayError";
|
|
94
|
+
this.type = type;
|
|
95
|
+
this.gatewayUrl = gatewayUrl;
|
|
96
|
+
this.statusCode = options?.statusCode;
|
|
97
|
+
this.graphqlErrors = options?.graphqlErrors;
|
|
98
|
+
this.cause = options?.cause;
|
|
99
|
+
Object.setPrototypeOf(this, _GatewayError.prototype);
|
|
100
|
+
}
|
|
101
|
+
};
|
|
102
|
+
|
|
103
|
+
// src/gateway/client.ts
|
|
104
|
+
var uuidv4 = /* @__PURE__ */ __name(() => crypto.randomUUID(), "uuidv4");
|
|
105
|
+
function hasAuthorizationHeader(headers) {
|
|
106
|
+
for (const key of Object.keys(headers)) {
|
|
107
|
+
if (key.toLowerCase() === "authorization") return true;
|
|
108
|
+
}
|
|
109
|
+
return false;
|
|
110
|
+
}
|
|
111
|
+
__name(hasAuthorizationHeader, "hasAuthorizationHeader");
|
|
112
|
+
function resolveBypassPermissionValue(token = process.env["INTERNAL_SERVICE_TOKEN"]) {
|
|
113
|
+
const normalizedToken = token?.trim();
|
|
114
|
+
if (!normalizedToken) {
|
|
115
|
+
throw new Error("INTERNAL_SERVICE_TOKEN must be configured for bypass-enabled gateway calls");
|
|
116
|
+
}
|
|
117
|
+
return normalizedToken;
|
|
118
|
+
}
|
|
119
|
+
__name(resolveBypassPermissionValue, "resolveBypassPermissionValue");
|
|
120
|
+
var CircuitBreaker = class CircuitBreaker2 {
|
|
121
|
+
static {
|
|
122
|
+
__name(this, "CircuitBreaker");
|
|
123
|
+
}
|
|
124
|
+
state = CircuitState.CLOSED;
|
|
125
|
+
failures = 0;
|
|
126
|
+
successes = 0;
|
|
127
|
+
consecutiveFailures = 0;
|
|
128
|
+
lastFailureTime = null;
|
|
129
|
+
lastSuccessTime = null;
|
|
130
|
+
openedAt = null;
|
|
131
|
+
failureTimestamps = [];
|
|
132
|
+
config;
|
|
133
|
+
constructor(config) {
|
|
134
|
+
this.config = config;
|
|
135
|
+
}
|
|
136
|
+
getState() {
|
|
137
|
+
this.checkStateTransition();
|
|
138
|
+
return this.state;
|
|
139
|
+
}
|
|
140
|
+
recordSuccess() {
|
|
141
|
+
this.successes++;
|
|
142
|
+
this.consecutiveFailures = 0;
|
|
143
|
+
this.lastSuccessTime = Date.now();
|
|
144
|
+
if (this.state === CircuitState.HALF_OPEN) {
|
|
145
|
+
this.state = CircuitState.CLOSED;
|
|
146
|
+
this.failures = 0;
|
|
147
|
+
this.failureTimestamps = [];
|
|
148
|
+
this.openedAt = null;
|
|
149
|
+
logger.info("[CircuitBreaker] Circuit closed after successful test");
|
|
150
|
+
}
|
|
151
|
+
}
|
|
152
|
+
recordFailure() {
|
|
153
|
+
this.failures++;
|
|
154
|
+
this.consecutiveFailures++;
|
|
155
|
+
this.lastFailureTime = Date.now();
|
|
156
|
+
this.failureTimestamps.push(Date.now());
|
|
157
|
+
const windowStart = Date.now() - this.config.failureWindow;
|
|
158
|
+
this.failureTimestamps = this.failureTimestamps.filter((t) => t > windowStart);
|
|
159
|
+
if (this.state === CircuitState.CLOSED && this.failureTimestamps.length >= this.config.failureThreshold) {
|
|
160
|
+
this.state = CircuitState.OPEN;
|
|
161
|
+
this.openedAt = Date.now();
|
|
162
|
+
logger.warn("[CircuitBreaker] Circuit opened due to failures", {
|
|
163
|
+
failures: this.failureTimestamps.length,
|
|
164
|
+
threshold: this.config.failureThreshold
|
|
165
|
+
});
|
|
166
|
+
}
|
|
167
|
+
if (this.state === CircuitState.HALF_OPEN) {
|
|
168
|
+
this.state = CircuitState.OPEN;
|
|
169
|
+
this.openedAt = Date.now();
|
|
170
|
+
logger.warn("[CircuitBreaker] Circuit re-opened after failed test");
|
|
171
|
+
}
|
|
172
|
+
}
|
|
173
|
+
allowRequest() {
|
|
174
|
+
this.checkStateTransition();
|
|
175
|
+
switch (this.state) {
|
|
176
|
+
case CircuitState.CLOSED:
|
|
177
|
+
return true;
|
|
178
|
+
case CircuitState.OPEN:
|
|
179
|
+
return false;
|
|
180
|
+
case CircuitState.HALF_OPEN:
|
|
181
|
+
return true;
|
|
182
|
+
default:
|
|
183
|
+
return true;
|
|
184
|
+
}
|
|
185
|
+
}
|
|
186
|
+
forceOpen() {
|
|
187
|
+
this.state = CircuitState.OPEN;
|
|
188
|
+
this.openedAt = Date.now();
|
|
189
|
+
logger.info("[CircuitBreaker] Circuit force-opened");
|
|
190
|
+
}
|
|
191
|
+
forceClose() {
|
|
192
|
+
this.state = CircuitState.CLOSED;
|
|
193
|
+
this.failures = 0;
|
|
194
|
+
this.consecutiveFailures = 0;
|
|
195
|
+
this.failureTimestamps = [];
|
|
196
|
+
this.openedAt = null;
|
|
197
|
+
logger.info("[CircuitBreaker] Circuit force-closed");
|
|
198
|
+
}
|
|
199
|
+
getStats() {
|
|
200
|
+
return {
|
|
201
|
+
state: this.state,
|
|
202
|
+
failures: this.failures,
|
|
203
|
+
successes: this.successes,
|
|
204
|
+
consecutiveFailures: this.consecutiveFailures,
|
|
205
|
+
lastFailureTime: this.lastFailureTime,
|
|
206
|
+
lastSuccessTime: this.lastSuccessTime,
|
|
207
|
+
openedAt: this.openedAt
|
|
208
|
+
};
|
|
209
|
+
}
|
|
210
|
+
checkStateTransition() {
|
|
211
|
+
if (this.state === CircuitState.OPEN && this.openedAt) {
|
|
212
|
+
const elapsed = Date.now() - this.openedAt;
|
|
213
|
+
if (elapsed >= this.config.resetTimeout) {
|
|
214
|
+
this.state = CircuitState.HALF_OPEN;
|
|
215
|
+
logger.info("[CircuitBreaker] Circuit transitioning to half-open");
|
|
216
|
+
}
|
|
217
|
+
}
|
|
218
|
+
}
|
|
219
|
+
};
|
|
220
|
+
var GatewayClient = class {
|
|
221
|
+
static {
|
|
222
|
+
__name(this, "GatewayClient");
|
|
223
|
+
}
|
|
224
|
+
config;
|
|
225
|
+
layerManager;
|
|
226
|
+
internalCircuitBreaker;
|
|
227
|
+
crossLayerCircuitBreaker;
|
|
228
|
+
retryConfig;
|
|
229
|
+
defaultHeaders;
|
|
230
|
+
constructor(config) {
|
|
231
|
+
this.config = {
|
|
232
|
+
timeout: 3e4,
|
|
233
|
+
enableLogging: true,
|
|
234
|
+
...config
|
|
235
|
+
};
|
|
236
|
+
this.layerManager = new LayerManager({
|
|
237
|
+
layer: config.layer,
|
|
238
|
+
serviceName: config.serviceName,
|
|
239
|
+
serviceIdentity: config.serviceIdentity
|
|
240
|
+
});
|
|
241
|
+
if (config.internalGatewayUrl) ;
|
|
242
|
+
if (config.crossLayerGatewayUrl) ;
|
|
243
|
+
const cbConfig = {
|
|
244
|
+
...DEFAULT_CIRCUIT_BREAKER_CONFIG,
|
|
245
|
+
...config.circuitBreaker
|
|
246
|
+
};
|
|
247
|
+
this.internalCircuitBreaker = new CircuitBreaker(cbConfig);
|
|
248
|
+
this.crossLayerCircuitBreaker = new CircuitBreaker(cbConfig);
|
|
249
|
+
this.retryConfig = {
|
|
250
|
+
...DEFAULT_GATEWAY_RETRY_CONFIG,
|
|
251
|
+
...config.retry
|
|
252
|
+
};
|
|
253
|
+
this.defaultHeaders = {
|
|
254
|
+
"x-service-identity": this.layerManager.getServiceIdentity(),
|
|
255
|
+
"x-actor-type": "service",
|
|
256
|
+
...config.defaultHeaders
|
|
257
|
+
};
|
|
258
|
+
logger.debug("[GatewayClient] Initialized", {
|
|
259
|
+
layer: config.layer,
|
|
260
|
+
serviceName: config.serviceName,
|
|
261
|
+
internalUrl: this.getInternalUrl(),
|
|
262
|
+
crossLayerUrl: this.getCrossLayerUrl()
|
|
263
|
+
});
|
|
264
|
+
}
|
|
265
|
+
getInternalUrl() {
|
|
266
|
+
return this.config.internalGatewayUrl || this.layerManager.getInternalGatewayUrl();
|
|
267
|
+
}
|
|
268
|
+
getCrossLayerUrl() {
|
|
269
|
+
return this.config.crossLayerGatewayUrl || this.layerManager.getCrossLayerGatewayUrl();
|
|
270
|
+
}
|
|
271
|
+
/**
|
|
272
|
+
* Execute internal (same layer) GraphQL query/mutation
|
|
273
|
+
*/
|
|
274
|
+
async internalQuery(options) {
|
|
275
|
+
const context = this.createRequestContext("internal", options);
|
|
276
|
+
return this.executeWithRetry(this.getInternalUrl(), options, this.internalCircuitBreaker, context, {
|
|
277
|
+
bypassPermission: true
|
|
278
|
+
});
|
|
279
|
+
}
|
|
280
|
+
/**
|
|
281
|
+
* Execute cross-layer GraphQL query/mutation
|
|
282
|
+
*/
|
|
283
|
+
async crossLayerQuery(options) {
|
|
284
|
+
const context = this.createRequestContext("cross-layer", options);
|
|
285
|
+
return this.executeWithRetry(
|
|
286
|
+
this.getCrossLayerUrl(),
|
|
287
|
+
options,
|
|
288
|
+
this.crossLayerCircuitBreaker,
|
|
289
|
+
context,
|
|
290
|
+
{
|
|
291
|
+
bypassPermission: false
|
|
292
|
+
}
|
|
293
|
+
// Cross-layer calls go through public gateway
|
|
294
|
+
);
|
|
295
|
+
}
|
|
296
|
+
/**
|
|
297
|
+
* Execute GraphQL query/mutation with explicit gateway URL
|
|
298
|
+
*/
|
|
299
|
+
async query(gatewayUrl, options) {
|
|
300
|
+
const context = this.createRequestContext("direct", options);
|
|
301
|
+
return this.executeWithRetry(gatewayUrl, options, this.internalCircuitBreaker, context, {
|
|
302
|
+
bypassPermission: false
|
|
303
|
+
});
|
|
304
|
+
}
|
|
305
|
+
getInternalCircuitBreaker() {
|
|
306
|
+
return this.internalCircuitBreaker;
|
|
307
|
+
}
|
|
308
|
+
getCrossLayerCircuitBreaker() {
|
|
309
|
+
return this.crossLayerCircuitBreaker;
|
|
310
|
+
}
|
|
311
|
+
getHealthStatus() {
|
|
312
|
+
return {
|
|
313
|
+
internal: {
|
|
314
|
+
url: this.getInternalUrl(),
|
|
315
|
+
circuitState: this.internalCircuitBreaker.getState(),
|
|
316
|
+
stats: this.internalCircuitBreaker.getStats()
|
|
317
|
+
},
|
|
318
|
+
crossLayer: {
|
|
319
|
+
url: this.getCrossLayerUrl(),
|
|
320
|
+
circuitState: this.crossLayerCircuitBreaker.getState(),
|
|
321
|
+
stats: this.crossLayerCircuitBreaker.getStats()
|
|
322
|
+
}
|
|
323
|
+
};
|
|
324
|
+
}
|
|
325
|
+
updateDefaultHeaders(headers) {
|
|
326
|
+
this.defaultHeaders = {
|
|
327
|
+
...this.defaultHeaders,
|
|
328
|
+
...headers
|
|
329
|
+
};
|
|
330
|
+
}
|
|
331
|
+
createRequestContext(callType, options) {
|
|
332
|
+
return {
|
|
333
|
+
requestId: uuidv4(),
|
|
334
|
+
actorId: options.headers?.["x-actor-id"] || this.defaultHeaders["x-actor-id"],
|
|
335
|
+
workspaceId: options.headers?.["x-workspace-id"] || this.defaultHeaders["x-workspace-id"],
|
|
336
|
+
startTime: Date.now(),
|
|
337
|
+
callType
|
|
338
|
+
};
|
|
339
|
+
}
|
|
340
|
+
/**
|
|
341
|
+
* Check if an error should be retried
|
|
342
|
+
*/
|
|
343
|
+
shouldRetryError(error) {
|
|
344
|
+
if (!(error instanceof GatewayError)) {
|
|
345
|
+
return true;
|
|
346
|
+
}
|
|
347
|
+
return error.type !== GatewayErrorType.GRAPHQL_ERROR && error.type !== GatewayErrorType.CIRCUIT_OPEN;
|
|
348
|
+
}
|
|
349
|
+
/**
|
|
350
|
+
* Calculate retry delay with exponential backoff
|
|
351
|
+
*/
|
|
352
|
+
calculateRetryDelay(attempt) {
|
|
353
|
+
return Math.min(this.retryConfig.initialDelay * Math.pow(this.retryConfig.backoffMultiplier, attempt - 1), this.retryConfig.maxDelay);
|
|
354
|
+
}
|
|
355
|
+
/**
|
|
356
|
+
* Log retry attempt if logging is enabled
|
|
357
|
+
*/
|
|
358
|
+
logRetryAttempt(context, attempt, maxAttempts, delay, error) {
|
|
359
|
+
if (this.config.enableLogging) {
|
|
360
|
+
logger.warn("[GatewayClient] Request failed, retrying", {
|
|
361
|
+
requestId: context.requestId,
|
|
362
|
+
attempt,
|
|
363
|
+
maxAttempts,
|
|
364
|
+
delay,
|
|
365
|
+
error: error.message
|
|
366
|
+
});
|
|
367
|
+
}
|
|
368
|
+
}
|
|
369
|
+
async executeWithRetry(gatewayUrl, options, circuitBreaker, context, settings) {
|
|
370
|
+
if (!options.skipCircuitBreaker && !circuitBreaker.allowRequest()) {
|
|
371
|
+
throw new GatewayError(`Circuit breaker is open for ${gatewayUrl}`, GatewayErrorType.CIRCUIT_OPEN, gatewayUrl);
|
|
372
|
+
}
|
|
373
|
+
const maxAttempts = options.skipRetry ? 1 : this.retryConfig.maxAttempts;
|
|
374
|
+
let lastError = null;
|
|
375
|
+
for (let attempt = 1; attempt <= maxAttempts; attempt++) {
|
|
376
|
+
try {
|
|
377
|
+
const result = await this.executeRequest(gatewayUrl, options, context, settings.bypassPermission);
|
|
378
|
+
if (!options.skipCircuitBreaker) {
|
|
379
|
+
circuitBreaker.recordSuccess();
|
|
380
|
+
}
|
|
381
|
+
return result;
|
|
382
|
+
} catch (error) {
|
|
383
|
+
lastError = error instanceof Error ? error : new Error(String(error));
|
|
384
|
+
if (!options.skipCircuitBreaker) {
|
|
385
|
+
circuitBreaker.recordFailure();
|
|
386
|
+
}
|
|
387
|
+
if (!this.shouldRetryError(error)) {
|
|
388
|
+
throw error;
|
|
389
|
+
}
|
|
390
|
+
if (attempt < maxAttempts) {
|
|
391
|
+
const delay = this.calculateRetryDelay(attempt);
|
|
392
|
+
this.logRetryAttempt(context, attempt, maxAttempts, delay, lastError);
|
|
393
|
+
await this.sleep(delay);
|
|
394
|
+
}
|
|
395
|
+
}
|
|
396
|
+
}
|
|
397
|
+
throw lastError || new GatewayError("Request failed after retries", GatewayErrorType.UNKNOWN_ERROR, gatewayUrl);
|
|
398
|
+
}
|
|
399
|
+
/**
|
|
400
|
+
* Build headers for a request
|
|
401
|
+
*/
|
|
402
|
+
buildRequestHeaders(context, options, bypassPermission) {
|
|
403
|
+
const headers = {
|
|
404
|
+
"Content-Type": "application/json",
|
|
405
|
+
"x-request-id": context.requestId,
|
|
406
|
+
"x-call-type": context.callType
|
|
407
|
+
};
|
|
408
|
+
for (const [key, value] of Object.entries(this.defaultHeaders)) {
|
|
409
|
+
if (value !== void 0) {
|
|
410
|
+
headers[key] = String(value);
|
|
411
|
+
}
|
|
412
|
+
}
|
|
413
|
+
if (options.headers) {
|
|
414
|
+
for (const [key, value] of Object.entries(options.headers)) {
|
|
415
|
+
if (value !== void 0) {
|
|
416
|
+
headers[key] = String(value);
|
|
417
|
+
}
|
|
418
|
+
}
|
|
419
|
+
}
|
|
420
|
+
if (bypassPermission) {
|
|
421
|
+
headers["x-bypass-permission"] = resolveBypassPermissionValue();
|
|
422
|
+
headers["x-bypass-source"] = this.layerManager.getServiceIdentity();
|
|
423
|
+
headers["x-bypass-timestamp"] = Date.now().toString();
|
|
424
|
+
}
|
|
425
|
+
return headers;
|
|
426
|
+
}
|
|
427
|
+
/**
|
|
428
|
+
* Handle GraphQL errors in response
|
|
429
|
+
*/
|
|
430
|
+
handleGraphQLErrors(result, context, gatewayUrl, duration) {
|
|
431
|
+
if (!result.errors || result.errors.length === 0) {
|
|
432
|
+
return;
|
|
433
|
+
}
|
|
434
|
+
const errorMessages = result.errors.map((e) => e.message).join(", ");
|
|
435
|
+
if (this.config.enableLogging) {
|
|
436
|
+
logger.warn("[GatewayClient] GraphQL errors", {
|
|
437
|
+
requestId: context.requestId,
|
|
438
|
+
errors: result.errors,
|
|
439
|
+
duration
|
|
440
|
+
});
|
|
441
|
+
}
|
|
442
|
+
throw new GatewayError(`GraphQL error: ${errorMessages}`, GatewayErrorType.GRAPHQL_ERROR, gatewayUrl, {
|
|
443
|
+
graphqlErrors: result.errors
|
|
444
|
+
});
|
|
445
|
+
}
|
|
446
|
+
/**
|
|
447
|
+
* Handle fetch errors
|
|
448
|
+
*/
|
|
449
|
+
handleFetchError(error, context, gatewayUrl, timeout, duration) {
|
|
450
|
+
if (error instanceof GatewayError) {
|
|
451
|
+
throw error;
|
|
452
|
+
}
|
|
453
|
+
if (error instanceof Error) {
|
|
454
|
+
if (error.name === "AbortError") {
|
|
455
|
+
throw new GatewayError(`Request timed out after ${timeout}ms`, GatewayErrorType.TIMEOUT_ERROR, gatewayUrl, {
|
|
456
|
+
cause: error
|
|
457
|
+
});
|
|
458
|
+
}
|
|
459
|
+
if (this.config.enableLogging) {
|
|
460
|
+
logger.error("[GatewayClient] Request failed", {
|
|
461
|
+
requestId: context.requestId,
|
|
462
|
+
error: error.message,
|
|
463
|
+
duration
|
|
464
|
+
});
|
|
465
|
+
}
|
|
466
|
+
throw new GatewayError(error.message, GatewayErrorType.NETWORK_ERROR, gatewayUrl, {
|
|
467
|
+
cause: error
|
|
468
|
+
});
|
|
469
|
+
}
|
|
470
|
+
throw new GatewayError(String(error), GatewayErrorType.UNKNOWN_ERROR, gatewayUrl);
|
|
471
|
+
}
|
|
472
|
+
async executeRequest(gatewayUrl, options, context, bypassPermission) {
|
|
473
|
+
const timeout = options.timeout || this.config.timeout || 3e4;
|
|
474
|
+
const headers = this.buildRequestHeaders(context, options, bypassPermission);
|
|
475
|
+
if (context.callType === "cross-layer" && !hasAuthorizationHeader(headers)) {
|
|
476
|
+
const serviceActorId = this.layerManager.getServiceIdentity();
|
|
477
|
+
const serviceJwt = await signServiceJwt(serviceActorId);
|
|
478
|
+
if (serviceJwt) {
|
|
479
|
+
headers["Authorization"] = `Bearer ${serviceJwt}`;
|
|
480
|
+
} else if (this.config.enableLogging) {
|
|
481
|
+
logger.debug("[GatewayClient] SERVICE_JWT_SECRET not configured \u2014 cross-layer call will proceed without service JWT", {
|
|
482
|
+
requestId: context.requestId,
|
|
483
|
+
gatewayUrl
|
|
484
|
+
});
|
|
485
|
+
}
|
|
486
|
+
}
|
|
487
|
+
const body = JSON.stringify({
|
|
488
|
+
query: options.query,
|
|
489
|
+
variables: options.variables || {},
|
|
490
|
+
operationName: options.operationName
|
|
491
|
+
});
|
|
492
|
+
if (this.config.enableLogging) {
|
|
493
|
+
logger.debug("[GatewayClient] Executing request", {
|
|
494
|
+
requestId: context.requestId,
|
|
495
|
+
gatewayUrl,
|
|
496
|
+
operationName: options.operationName,
|
|
497
|
+
callType: context.callType,
|
|
498
|
+
bypassPermission
|
|
499
|
+
});
|
|
500
|
+
}
|
|
501
|
+
try {
|
|
502
|
+
const controller = new AbortController();
|
|
503
|
+
const timeoutId = setTimeout(() => controller.abort(), timeout);
|
|
504
|
+
const response = await fetch(gatewayUrl, {
|
|
505
|
+
method: "POST",
|
|
506
|
+
headers,
|
|
507
|
+
body,
|
|
508
|
+
signal: controller.signal
|
|
509
|
+
});
|
|
510
|
+
clearTimeout(timeoutId);
|
|
511
|
+
const duration = Date.now() - context.startTime;
|
|
512
|
+
if (!response.ok) {
|
|
513
|
+
throw new GatewayError(`HTTP ${response.status}: ${response.statusText}`, GatewayErrorType.NETWORK_ERROR, gatewayUrl, {
|
|
514
|
+
statusCode: response.status
|
|
515
|
+
});
|
|
516
|
+
}
|
|
517
|
+
const result = await response.json();
|
|
518
|
+
this.handleGraphQLErrors(result, context, gatewayUrl, duration);
|
|
519
|
+
if (this.config.enableLogging) {
|
|
520
|
+
logger.debug("[GatewayClient] Request completed", {
|
|
521
|
+
requestId: context.requestId,
|
|
522
|
+
duration,
|
|
523
|
+
hasData: !!result.data
|
|
524
|
+
});
|
|
525
|
+
}
|
|
526
|
+
return result;
|
|
527
|
+
} catch (error) {
|
|
528
|
+
const duration = Date.now() - context.startTime;
|
|
529
|
+
this.handleFetchError(error, context, gatewayUrl, timeout, duration);
|
|
530
|
+
}
|
|
531
|
+
}
|
|
532
|
+
sleep(ms) {
|
|
533
|
+
return new Promise((resolve) => setTimeout(resolve, ms));
|
|
534
|
+
}
|
|
535
|
+
};
|
|
536
|
+
function createGatewayClient(config) {
|
|
537
|
+
return new GatewayClient(config);
|
|
538
|
+
}
|
|
539
|
+
__name(createGatewayClient, "createGatewayClient");
|
|
540
|
+
function createGatewayClientFromEnv() {
|
|
541
|
+
const layer = process.env["SERVICE_LAYER"];
|
|
542
|
+
if (!layer || layer !== "wspace" && layer !== "global") {
|
|
543
|
+
throw new Error(`[GatewayClient] Invalid or missing SERVICE_LAYER. Expected 'wspace' or 'global', got '${layer}'`);
|
|
544
|
+
}
|
|
545
|
+
const serviceName = process.env["SERVICE_NAME"];
|
|
546
|
+
if (!serviceName) {
|
|
547
|
+
throw new Error("[GatewayClient] SERVICE_NAME environment variable is required");
|
|
548
|
+
}
|
|
549
|
+
const serviceIdentity = process.env["SERVICE_IDENTITY"] || serviceName;
|
|
550
|
+
return new GatewayClient({
|
|
551
|
+
layer,
|
|
552
|
+
serviceName,
|
|
553
|
+
serviceIdentity
|
|
554
|
+
});
|
|
555
|
+
}
|
|
556
|
+
__name(createGatewayClientFromEnv, "createGatewayClientFromEnv");
|
|
557
|
+
|
|
558
|
+
export { CircuitState, GatewayClient, GatewayError, GatewayErrorType, createGatewayClient, createGatewayClientFromEnv, gateway_exports };
|
|
559
|
+
//# sourceMappingURL=chunk-4B43DZIS.js.map
|
|
560
|
+
//# sourceMappingURL=chunk-4B43DZIS.js.map
|