@typedb/driver-http 3.8.4-rc0 → 3.11.0-rc1

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 CHANGED
@@ -1,4 +1,4 @@
1
- "use strict";Object.defineProperty(exports, "__esModule", {value: true}); async function _asyncNullishCoalesce(lhs, rhsFn) { if (lhs != null) { return lhs; } else { return await rhsFn(); } } function _optionalChain(ops) { let lastAccessLHS = undefined; let value = ops[0]; let i = 1; while (i < ops.length) { const op = ops[i]; const fn = ops[i + 1]; i += 2; if ((op === 'optionalAccess' || op === 'optionalCall') && value == null) { return undefined; } if (op === 'access' || op === 'optionalAccess') { lastAccessLHS = value; value = fn(value); } else if (op === 'call' || op === 'optionalCall') { value = fn((...args) => value.call(lastAccessLHS, ...args)); lastAccessLHS = undefined; } } return value; }// ../../../../../../../../../execroot/_main/bazel-out/k8-opt/bin/http-ts/src/params.ts
1
+ "use strict";Object.defineProperty(exports, "__esModule", {value: true}); function _nullishCoalesce(lhs, rhsFn) { if (lhs != null) { return lhs; } else { return rhsFn(); } } async function _asyncNullishCoalesce(lhs, rhsFn) { if (lhs != null) { return lhs; } else { return await rhsFn(); } } function _optionalChain(ops) { let lastAccessLHS = undefined; let value = ops[0]; let i = 1; while (i < ops.length) { const op = ops[i]; const fn = ops[i + 1]; i += 2; if ((op === 'optionalAccess' || op === 'optionalCall') && value == null) { return undefined; } if (op === 'access' || op === 'optionalAccess') { lastAccessLHS = value; value = fn(value); } else if (op === 'call' || op === 'optionalCall') { value = fn((...args) => value.call(lastAccessLHS, ...args)); lastAccessLHS = undefined; } } return value; }// ../../../../../../../../../execroot/_main/bazel-out/k8-opt/bin/http-ts/src/params.ts
2
2
  function isBasicParams(params) {
3
3
  return `addresses` in params;
4
4
  }
@@ -9,11 +9,52 @@ function remoteOrigin(params) {
9
9
  if (isBasicParams(params)) return `${params.addresses[0]}`;
10
10
  else return `${params.translatedAddresses[0].external}`;
11
11
  }
12
+ function hostPortFromOrigin(origin) {
13
+ try {
14
+ const url = new URL(origin);
15
+ return url.host;
16
+ } catch (e) {
17
+ return origin;
18
+ }
19
+ }
20
+ function resolveOrigin(params, primaryAddress) {
21
+ if (isBasicParams(params)) {
22
+ for (const addr of params.addresses) {
23
+ if (hostPortFromOrigin(addr) === primaryAddress) return addr;
24
+ }
25
+ return deriveOriginWithScheme(params.addresses[0], primaryAddress);
26
+ } else {
27
+ for (const ta of params.translatedAddresses) {
28
+ if (hostPortFromOrigin(ta.internal) === primaryAddress || hostPortFromOrigin(ta.external) === primaryAddress) {
29
+ return ta.external;
30
+ }
31
+ }
32
+ return deriveOriginWithScheme(params.translatedAddresses[0].external, primaryAddress);
33
+ }
34
+ }
35
+ function deriveOriginWithScheme(referenceUrl, hostPort) {
36
+ try {
37
+ const url = new URL(referenceUrl);
38
+ return `${url.protocol}//${hostPort}`;
39
+ } catch (e2) {
40
+ return `https://${hostPort}`;
41
+ }
42
+ }
43
+ function allOrigins(params) {
44
+ if (isBasicParams(params)) return params.addresses;
45
+ else return params.translatedAddresses.map((ta) => ta.external);
46
+ }
12
47
 
13
48
  // ../../../../../../../../../execroot/_main/bazel-out/k8-opt/bin/http-ts/src/response.ts
14
49
  function isApiError(err) {
15
50
  return err != null && typeof err.code === "string" && typeof err.message === "string";
16
51
  }
52
+ function isMisdirectedError(err) {
53
+ return err != null && typeof err.code === "string" && typeof err.message === "string" && typeof err.primaryAddress === "string";
54
+ }
55
+ function driverError(code, message) {
56
+ return { err: { code, message }, status: 503 };
57
+ }
17
58
  function isOkResponse(res) {
18
59
  return typeof res === "object" && "ok" in res;
19
60
  }
@@ -31,9 +72,18 @@ function getVariableName(structure, variable) {
31
72
 
32
73
  // ../../../../../../../../../execroot/_main/bazel-out/k8-opt/bin/http-ts/src/index.ts
33
74
  var HTTP_UNAUTHORIZED = 401;
75
+ var HTTP_MISDIRECTED = 421;
76
+ var TRANSIENT_SIGNIN_ERROR_CODES = /* @__PURE__ */ new Set(["HDR2", "SRV14"]);
77
+ function isApiErrResp(value) {
78
+ return value !== null && "err" in value;
79
+ }
80
+ function tokenErrToResult(tokenResp) {
81
+ return TRANSIENT_SIGNIN_ERROR_CODES.has(tokenResp.err.code) ? null : tokenResp;
82
+ }
34
83
  var TypeDBHttpDriver = class {
35
84
  constructor(params) {
36
85
  this.params = params;
86
+ this.currentOrigin = remoteOrigin(params);
37
87
  }
38
88
  getDatabases() {
39
89
  return this.apiGet(`/v1/databases`);
@@ -98,6 +148,9 @@ var TypeDBHttpDriver = class {
98
148
  version() {
99
149
  return this.apiGet(`/v1/version`);
100
150
  }
151
+ getServers() {
152
+ return this.apiGet(`/v1/servers`);
153
+ }
101
154
  async apiGetString(path, options) {
102
155
  return this.stringApiReq("GET", path, options);
103
156
  }
@@ -135,21 +188,98 @@ var TypeDBHttpDriver = class {
135
188
  }
136
189
  }
137
190
  async apiReq(method, path, body, options) {
138
- const url = `${remoteOrigin(this.params)}${path}`;
191
+ const initial = await this.tryApiReq(method, path, body, options);
192
+ if (isApiErrResp(initial)) return initial;
193
+ let result = initial;
194
+ if (result !== null && result.status === HTTP_MISDIRECTED) {
195
+ const redirected = await this.followMisdirected(result, method, path, body, options);
196
+ if (isApiErrResp(redirected)) return redirected;
197
+ result = redirected;
198
+ }
199
+ if (result === null || !result.ok) {
200
+ const startOrigin = this.currentOrigin;
201
+ const fallback = await this.tryFallbackOrigins(method, path, body, options);
202
+ if (isApiErrResp(fallback)) return fallback;
203
+ if (fallback !== null && (result === null || fallback.ok)) {
204
+ result = fallback;
205
+ } else if (result !== null) {
206
+ this.switchOrigin(startOrigin);
207
+ }
208
+ }
209
+ return _nullishCoalesce(result, () => ( driverError("HDR1", "Cannot connect to any server")));
210
+ }
211
+ async tryApiReq(method, path, body, options) {
212
+ const url = `${this.currentOrigin}${path}`;
139
213
  let tokenResp = await this.getToken();
140
- if ("err" in tokenResp) return tokenResp;
141
- let bodyString = void 0;
142
- if (body !== void 0) bodyString = JSON.stringify(body);
143
- let headers = Object.assign({ "Authorization": `Bearer ${tokenResp.ok.token}`, "Content-Type": "application/json" }, _optionalChain([options, 'optionalAccess', _4 => _4.headers]) || {});
144
- let resp = await fetch(url, { method, body: bodyString, headers });
214
+ if ("err" in tokenResp) return tokenErrToResult(tokenResp);
215
+ const bodyString = body !== void 0 ? JSON.stringify(body) : void 0;
216
+ let headers = this.authHeaders(tokenResp.ok.token, options);
217
+ let resp;
218
+ try {
219
+ resp = await fetch(url, { method, body: bodyString, headers });
220
+ } catch (e3) {
221
+ return null;
222
+ }
145
223
  if (resp.status === HTTP_UNAUTHORIZED) {
146
224
  tokenResp = await this.refreshToken();
147
- if ("err" in tokenResp) return tokenResp;
148
- headers = Object.assign({ "Authorization": `Bearer ${tokenResp.ok.token}`, "Content-Type": "application/json" }, _optionalChain([options, 'optionalAccess', _5 => _5.headers]) || {});
149
- resp = await fetch(url, { method, body: bodyString, headers });
225
+ if ("err" in tokenResp) return tokenErrToResult(tokenResp);
226
+ headers = this.authHeaders(tokenResp.ok.token, options);
227
+ try {
228
+ resp = await fetch(url, { method, body: bodyString, headers });
229
+ } catch (e4) {
230
+ return null;
231
+ }
150
232
  }
151
233
  return resp;
152
234
  }
235
+ async followMisdirected(resp, method, path, body, options) {
236
+ if (await this.switchToRedirectTarget(resp)) {
237
+ return await this.tryApiReq(method, path, body, options);
238
+ }
239
+ return null;
240
+ }
241
+ async switchToRedirectTarget(resp) {
242
+ let json;
243
+ try {
244
+ json = await resp.json();
245
+ } catch (e5) {
246
+ return false;
247
+ }
248
+ if (!isMisdirectedError(json)) return false;
249
+ const newOrigin = resolveOrigin(this.params, json.primaryAddress);
250
+ if (newOrigin === this.currentOrigin) return false;
251
+ this.switchOrigin(newOrigin);
252
+ return true;
253
+ }
254
+ async tryFallbackOrigins(method, path, body, options) {
255
+ const origins = allOrigins(this.params);
256
+ const failedOrigin = this.currentOrigin;
257
+ let lastError = null;
258
+ for (const origin of origins) {
259
+ if (origin === failedOrigin) continue;
260
+ this.switchOrigin(origin);
261
+ const initial = await this.tryApiReq(method, path, body, options);
262
+ if (initial === null) continue;
263
+ if (isApiErrResp(initial)) return initial;
264
+ let result = initial;
265
+ if (result.status === HTTP_MISDIRECTED) {
266
+ const redirected = await this.followMisdirected(result, method, path, body, options);
267
+ if (redirected === null) continue;
268
+ if (isApiErrResp(redirected)) return redirected;
269
+ result = redirected;
270
+ }
271
+ if (result.ok) return result;
272
+ lastError = result;
273
+ }
274
+ return lastError;
275
+ }
276
+ switchOrigin(origin) {
277
+ this.currentOrigin = origin;
278
+ this.token = void 0;
279
+ }
280
+ authHeaders(token, options) {
281
+ return { "Authorization": `Bearer ${token}`, "Content-Type": "application/json", ..._optionalChain([options, 'optionalAccess', _4 => _4.headers]) };
282
+ }
153
283
  getToken() {
154
284
  if (this.token) {
155
285
  const resp = { ok: { token: this.token } };
@@ -157,16 +287,24 @@ var TypeDBHttpDriver = class {
157
287
  } else return this.refreshToken();
158
288
  }
159
289
  async refreshToken() {
160
- const url = `${remoteOrigin(this.params)}/v1/signin`;
290
+ return this.signinOnce();
291
+ }
292
+ async signinOnce() {
293
+ const url = `${this.currentOrigin}/v1/signin`;
161
294
  const body = { username: this.params.username, password: this.params.password };
162
- const resp = await fetch(url, { method: "POST", body: JSON.stringify(body), headers: { "Content-Type": "application/json" } });
295
+ let resp;
296
+ try {
297
+ resp = await fetch(url, { method: "POST", body: JSON.stringify(body), headers: { "Content-Type": "application/json" } });
298
+ } catch (e6) {
299
+ return driverError("HDR2", `Cannot connect to server at ${this.currentOrigin}`);
300
+ }
163
301
  const json = await this.jsonOrNull(resp);
164
302
  if (resp.ok) {
165
303
  this.token = json.token;
166
304
  return { ok: json };
167
- } else if (isApiError(json)) {
168
- return { err: json, status: resp.status };
169
- } else throw resp;
305
+ }
306
+ if (isApiError(json)) return { err: json, status: resp.status };
307
+ throw resp;
170
308
  }
171
309
  async jsonOrNull(resp) {
172
310
  const contentLengthRaw = resp.headers.get("Content-Length");
@@ -193,5 +331,10 @@ var TypeDBHttpDriver = class {
193
331
 
194
332
 
195
333
 
196
- exports.TypeDBHttpDriver = TypeDBHttpDriver; exports.getVariableName = getVariableName; exports.isApiError = isApiError; exports.isApiErrorResponse = isApiErrorResponse; exports.isBasicParams = isBasicParams; exports.isOkResponse = isOkResponse; exports.isQueryResponseLegacy = isQueryResponseLegacy; exports.isTranslatedParams = isTranslatedParams; exports.remoteOrigin = remoteOrigin;
334
+
335
+
336
+
337
+
338
+
339
+ exports.TypeDBHttpDriver = TypeDBHttpDriver; exports.allOrigins = allOrigins; exports.driverError = driverError; exports.getVariableName = getVariableName; exports.hostPortFromOrigin = hostPortFromOrigin; exports.isApiError = isApiError; exports.isApiErrorResponse = isApiErrorResponse; exports.isBasicParams = isBasicParams; exports.isMisdirectedError = isMisdirectedError; exports.isOkResponse = isOkResponse; exports.isQueryResponseLegacy = isQueryResponseLegacy; exports.isTranslatedParams = isTranslatedParams; exports.remoteOrigin = remoteOrigin; exports.resolveOrigin = resolveOrigin;
197
340
  //# sourceMappingURL=index.cjs.map
package/dist/index.d.ts CHANGED
@@ -16,6 +16,12 @@ type DriverParams = DriverParamsBasic | DriverParamsTranslated;
16
16
  declare function isBasicParams(params: DriverParams): params is DriverParamsBasic;
17
17
  declare function isTranslatedParams(params: DriverParams): params is DriverParamsTranslated;
18
18
  declare function remoteOrigin(params: DriverParams): string;
19
+ /** Extract host:port from a URL string. "https://127.0.0.1:18000" → "127.0.0.1:18000" */
20
+ declare function hostPortFromOrigin(origin: string): string;
21
+ /** Resolve a bare primaryAddress (host:port) to a full URL using configured params. */
22
+ declare function resolveOrigin(params: DriverParams, primaryAddress: string): string;
23
+ /** Return all configured origins for connection error fallback. */
24
+ declare function allOrigins(params: DriverParams): string[];
19
25
 
20
26
  type TypeKind = "entityType" | "relationType" | "attributeType" | "roleType";
21
27
  type ThingKind = "entity" | "relation" | "attribute";
@@ -374,6 +380,19 @@ interface DatabasesListResponse {
374
380
  interface UsersListResponse {
375
381
  users: User[];
376
382
  }
383
+ type ReplicationRole = "primary" | "candidate" | "secondary";
384
+ interface ReplicationStatus {
385
+ id: number;
386
+ role: ReplicationRole | null;
387
+ term: number | null;
388
+ }
389
+ interface Server {
390
+ address: string | null;
391
+ replicationStatus: ReplicationStatus | null;
392
+ }
393
+ interface ServersListResponse {
394
+ servers: Server[];
395
+ }
377
396
  interface TransactionOpenResponse {
378
397
  transactionId: string;
379
398
  }
@@ -424,6 +443,13 @@ interface ApiErrorResponse {
424
443
  status: number;
425
444
  }
426
445
  declare function isApiError(err: any): err is ApiError;
446
+ interface MisdirectedError {
447
+ code: string;
448
+ message: string;
449
+ primaryAddress: string;
450
+ }
451
+ declare function isMisdirectedError(err: any): err is MisdirectedError;
452
+ declare function driverError(code: string, message: string): ApiErrorResponse;
427
453
  type ApiResponse<OK_RES = {} | null> = ApiOkResponse<OK_RES> | ApiErrorResponse;
428
454
  declare function isOkResponse<OK_RES>(res: ApiResponse<OK_RES>): res is ApiOkResponse<OK_RES>;
429
455
  declare function isApiErrorResponse(res: ApiResponse): res is ApiErrorResponse;
@@ -432,6 +458,7 @@ declare function isQueryResponseLegacy(res: ConceptRowsQueryResponse | ConceptRo
432
458
  declare class TypeDBHttpDriver {
433
459
  private params;
434
460
  private token?;
461
+ private currentOrigin;
435
462
  constructor(params: DriverParams);
436
463
  getDatabases(): Promise<ApiResponse<DatabasesListResponse>>;
437
464
  getDatabase(name: string): Promise<ApiResponse<Database>>;
@@ -454,6 +481,7 @@ declare class TypeDBHttpDriver {
454
481
  oneShotQuery(query: string, commit: boolean, databaseName: string, transactionType: TransactionType, transactionOptions?: TransactionOptions, queryOptions?: QueryOptions): Promise<ApiResponse<QueryResponse>>;
455
482
  health(): Promise<ApiResponse>;
456
483
  version(): Promise<ApiResponse<VersionResponse>>;
484
+ getServers(): Promise<ApiResponse<ServersListResponse>>;
457
485
  private apiGetString;
458
486
  private apiGet;
459
487
  private apiDelete;
@@ -463,8 +491,15 @@ declare class TypeDBHttpDriver {
463
491
  private jsonApiReq;
464
492
  private stringApiReq;
465
493
  private apiReq;
494
+ private tryApiReq;
495
+ private followMisdirected;
496
+ private switchToRedirectTarget;
497
+ private tryFallbackOrigins;
498
+ private switchOrigin;
499
+ private authHeaders;
466
500
  private getToken;
467
501
  private refreshToken;
502
+ private signinOnce;
468
503
  private jsonOrNull;
469
504
  private stringOrNull;
470
505
  }
@@ -488,4 +523,4 @@ interface User {
488
523
  username: string;
489
524
  }
490
525
 
491
- export { type AnalyzeOptions, type AnalyzeResponse, type AnalyzedConjunction, type AnalyzedFetch, type AnalyzedFunction, type AnalyzedPipeline, type Answer, type AnswerType, type ApiError, type ApiErrorResponse, type ApiOkResponse, type ApiResponse, type Attribute, type AttributeType, type Concept, type ConceptDocument, type ConceptDocumentsQueryResponse, type ConceptRow, type ConceptRowAnswer, type ConceptRowsQueryResponse, type ConceptRowsQueryResponseLegacy, type ConjunctionAnnotations, type ConstraintAny, type ConstraintComparison, type ConstraintExpression, type ConstraintExpressionLegacy, type ConstraintFunction, type ConstraintHas, type ConstraintIid, type ConstraintIs, type ConstraintIsa, type ConstraintIsaExact, type ConstraintKind, type ConstraintLabel, type ConstraintLinks, type ConstraintLinksLegacy, type ConstraintNot, type ConstraintOr, type ConstraintOwns, type ConstraintPlays, type ConstraintRelates, type ConstraintSpan, type ConstraintSub, type ConstraintSubExact, type ConstraintTry, type ConstraintValue, type ConstraintVertexAny, type ConstraintVertexLabel, type ConstraintVertexNamedRole, type ConstraintVertexValue, type ConstraintVertexVariable, type Database, type DatabasesListResponse, type Distribution, type DriverParams, type DriverParamsBasic, type DriverParamsTranslated, type EdgeKind, type Entity, type EntityType, type FetchAnnotationFieldEntry, type FunctionReturnStructure, type FunctionSingleReturnSelector, type InstantiableType, type OkQueryResponse, type PipelineStage, type QueryConjunctionLegacy, type QueryOptions, type QueryResponse, type QueryResponseBase, type QueryStructureLegacy, type QueryType, type Reducer, type Relation, type RelationType, type RoleType, type SignInResponse, type ThingKind, type TransactionOpenResponse, type TransactionOptions, type TransactionType, type TranslatedAddress, type Type, TypeDBHttpDriver, type TypeKind, type User, type UsersListResponse, type Value, type ValueKind, type ValueType, type VariableAnnotations, type VariableId, type VariableInfo, type VersionResponse, getVariableName, isApiError, isApiErrorResponse, isBasicParams, isOkResponse, isQueryResponseLegacy, isTranslatedParams, remoteOrigin };
526
+ export { type AnalyzeOptions, type AnalyzeResponse, type AnalyzedConjunction, type AnalyzedFetch, type AnalyzedFunction, type AnalyzedPipeline, type Answer, type AnswerType, type ApiError, type ApiErrorResponse, type ApiOkResponse, type ApiResponse, type Attribute, type AttributeType, type Concept, type ConceptDocument, type ConceptDocumentsQueryResponse, type ConceptRow, type ConceptRowAnswer, type ConceptRowsQueryResponse, type ConceptRowsQueryResponseLegacy, type ConjunctionAnnotations, type ConstraintAny, type ConstraintComparison, type ConstraintExpression, type ConstraintExpressionLegacy, type ConstraintFunction, type ConstraintHas, type ConstraintIid, type ConstraintIs, type ConstraintIsa, type ConstraintIsaExact, type ConstraintKind, type ConstraintLabel, type ConstraintLinks, type ConstraintLinksLegacy, type ConstraintNot, type ConstraintOr, type ConstraintOwns, type ConstraintPlays, type ConstraintRelates, type ConstraintSpan, type ConstraintSub, type ConstraintSubExact, type ConstraintTry, type ConstraintValue, type ConstraintVertexAny, type ConstraintVertexLabel, type ConstraintVertexNamedRole, type ConstraintVertexValue, type ConstraintVertexVariable, type Database, type DatabasesListResponse, type Distribution, type DriverParams, type DriverParamsBasic, type DriverParamsTranslated, type EdgeKind, type Entity, type EntityType, type FetchAnnotationFieldEntry, type FunctionReturnStructure, type FunctionSingleReturnSelector, type InstantiableType, type MisdirectedError, type OkQueryResponse, type PipelineStage, type QueryConjunctionLegacy, type QueryOptions, type QueryResponse, type QueryResponseBase, type QueryStructureLegacy, type QueryType, type Reducer, type Relation, type RelationType, type ReplicationRole, type ReplicationStatus, type RoleType, type Server, type ServersListResponse, type SignInResponse, type ThingKind, type TransactionOpenResponse, type TransactionOptions, type TransactionType, type TranslatedAddress, type Type, TypeDBHttpDriver, type TypeKind, type User, type UsersListResponse, type Value, type ValueKind, type ValueType, type VariableAnnotations, type VariableId, type VariableInfo, type VersionResponse, allOrigins, driverError, getVariableName, hostPortFromOrigin, isApiError, isApiErrorResponse, isBasicParams, isMisdirectedError, isOkResponse, isQueryResponseLegacy, isTranslatedParams, remoteOrigin, resolveOrigin };
package/dist/index.mjs CHANGED
@@ -9,11 +9,52 @@ function remoteOrigin(params) {
9
9
  if (isBasicParams(params)) return `${params.addresses[0]}`;
10
10
  else return `${params.translatedAddresses[0].external}`;
11
11
  }
12
+ function hostPortFromOrigin(origin) {
13
+ try {
14
+ const url = new URL(origin);
15
+ return url.host;
16
+ } catch {
17
+ return origin;
18
+ }
19
+ }
20
+ function resolveOrigin(params, primaryAddress) {
21
+ if (isBasicParams(params)) {
22
+ for (const addr of params.addresses) {
23
+ if (hostPortFromOrigin(addr) === primaryAddress) return addr;
24
+ }
25
+ return deriveOriginWithScheme(params.addresses[0], primaryAddress);
26
+ } else {
27
+ for (const ta of params.translatedAddresses) {
28
+ if (hostPortFromOrigin(ta.internal) === primaryAddress || hostPortFromOrigin(ta.external) === primaryAddress) {
29
+ return ta.external;
30
+ }
31
+ }
32
+ return deriveOriginWithScheme(params.translatedAddresses[0].external, primaryAddress);
33
+ }
34
+ }
35
+ function deriveOriginWithScheme(referenceUrl, hostPort) {
36
+ try {
37
+ const url = new URL(referenceUrl);
38
+ return `${url.protocol}//${hostPort}`;
39
+ } catch {
40
+ return `https://${hostPort}`;
41
+ }
42
+ }
43
+ function allOrigins(params) {
44
+ if (isBasicParams(params)) return params.addresses;
45
+ else return params.translatedAddresses.map((ta) => ta.external);
46
+ }
12
47
 
13
48
  // ../../../../../../../../../execroot/_main/bazel-out/k8-opt/bin/http-ts/src/response.ts
14
49
  function isApiError(err) {
15
50
  return err != null && typeof err.code === "string" && typeof err.message === "string";
16
51
  }
52
+ function isMisdirectedError(err) {
53
+ return err != null && typeof err.code === "string" && typeof err.message === "string" && typeof err.primaryAddress === "string";
54
+ }
55
+ function driverError(code, message) {
56
+ return { err: { code, message }, status: 503 };
57
+ }
17
58
  function isOkResponse(res) {
18
59
  return typeof res === "object" && "ok" in res;
19
60
  }
@@ -31,9 +72,18 @@ function getVariableName(structure, variable) {
31
72
 
32
73
  // ../../../../../../../../../execroot/_main/bazel-out/k8-opt/bin/http-ts/src/index.ts
33
74
  var HTTP_UNAUTHORIZED = 401;
75
+ var HTTP_MISDIRECTED = 421;
76
+ var TRANSIENT_SIGNIN_ERROR_CODES = /* @__PURE__ */ new Set(["HDR2", "SRV14"]);
77
+ function isApiErrResp(value) {
78
+ return value !== null && "err" in value;
79
+ }
80
+ function tokenErrToResult(tokenResp) {
81
+ return TRANSIENT_SIGNIN_ERROR_CODES.has(tokenResp.err.code) ? null : tokenResp;
82
+ }
34
83
  var TypeDBHttpDriver = class {
35
84
  constructor(params) {
36
85
  this.params = params;
86
+ this.currentOrigin = remoteOrigin(params);
37
87
  }
38
88
  getDatabases() {
39
89
  return this.apiGet(`/v1/databases`);
@@ -98,6 +148,9 @@ var TypeDBHttpDriver = class {
98
148
  version() {
99
149
  return this.apiGet(`/v1/version`);
100
150
  }
151
+ getServers() {
152
+ return this.apiGet(`/v1/servers`);
153
+ }
101
154
  async apiGetString(path, options) {
102
155
  return this.stringApiReq("GET", path, options);
103
156
  }
@@ -135,21 +188,98 @@ var TypeDBHttpDriver = class {
135
188
  }
136
189
  }
137
190
  async apiReq(method, path, body, options) {
138
- const url = `${remoteOrigin(this.params)}${path}`;
191
+ const initial = await this.tryApiReq(method, path, body, options);
192
+ if (isApiErrResp(initial)) return initial;
193
+ let result = initial;
194
+ if (result !== null && result.status === HTTP_MISDIRECTED) {
195
+ const redirected = await this.followMisdirected(result, method, path, body, options);
196
+ if (isApiErrResp(redirected)) return redirected;
197
+ result = redirected;
198
+ }
199
+ if (result === null || !result.ok) {
200
+ const startOrigin = this.currentOrigin;
201
+ const fallback = await this.tryFallbackOrigins(method, path, body, options);
202
+ if (isApiErrResp(fallback)) return fallback;
203
+ if (fallback !== null && (result === null || fallback.ok)) {
204
+ result = fallback;
205
+ } else if (result !== null) {
206
+ this.switchOrigin(startOrigin);
207
+ }
208
+ }
209
+ return result ?? driverError("HDR1", "Cannot connect to any server");
210
+ }
211
+ async tryApiReq(method, path, body, options) {
212
+ const url = `${this.currentOrigin}${path}`;
139
213
  let tokenResp = await this.getToken();
140
- if ("err" in tokenResp) return tokenResp;
141
- let bodyString = void 0;
142
- if (body !== void 0) bodyString = JSON.stringify(body);
143
- let headers = Object.assign({ "Authorization": `Bearer ${tokenResp.ok.token}`, "Content-Type": "application/json" }, options?.headers || {});
144
- let resp = await fetch(url, { method, body: bodyString, headers });
214
+ if ("err" in tokenResp) return tokenErrToResult(tokenResp);
215
+ const bodyString = body !== void 0 ? JSON.stringify(body) : void 0;
216
+ let headers = this.authHeaders(tokenResp.ok.token, options);
217
+ let resp;
218
+ try {
219
+ resp = await fetch(url, { method, body: bodyString, headers });
220
+ } catch {
221
+ return null;
222
+ }
145
223
  if (resp.status === HTTP_UNAUTHORIZED) {
146
224
  tokenResp = await this.refreshToken();
147
- if ("err" in tokenResp) return tokenResp;
148
- headers = Object.assign({ "Authorization": `Bearer ${tokenResp.ok.token}`, "Content-Type": "application/json" }, options?.headers || {});
149
- resp = await fetch(url, { method, body: bodyString, headers });
225
+ if ("err" in tokenResp) return tokenErrToResult(tokenResp);
226
+ headers = this.authHeaders(tokenResp.ok.token, options);
227
+ try {
228
+ resp = await fetch(url, { method, body: bodyString, headers });
229
+ } catch {
230
+ return null;
231
+ }
150
232
  }
151
233
  return resp;
152
234
  }
235
+ async followMisdirected(resp, method, path, body, options) {
236
+ if (await this.switchToRedirectTarget(resp)) {
237
+ return await this.tryApiReq(method, path, body, options);
238
+ }
239
+ return null;
240
+ }
241
+ async switchToRedirectTarget(resp) {
242
+ let json;
243
+ try {
244
+ json = await resp.json();
245
+ } catch {
246
+ return false;
247
+ }
248
+ if (!isMisdirectedError(json)) return false;
249
+ const newOrigin = resolveOrigin(this.params, json.primaryAddress);
250
+ if (newOrigin === this.currentOrigin) return false;
251
+ this.switchOrigin(newOrigin);
252
+ return true;
253
+ }
254
+ async tryFallbackOrigins(method, path, body, options) {
255
+ const origins = allOrigins(this.params);
256
+ const failedOrigin = this.currentOrigin;
257
+ let lastError = null;
258
+ for (const origin of origins) {
259
+ if (origin === failedOrigin) continue;
260
+ this.switchOrigin(origin);
261
+ const initial = await this.tryApiReq(method, path, body, options);
262
+ if (initial === null) continue;
263
+ if (isApiErrResp(initial)) return initial;
264
+ let result = initial;
265
+ if (result.status === HTTP_MISDIRECTED) {
266
+ const redirected = await this.followMisdirected(result, method, path, body, options);
267
+ if (redirected === null) continue;
268
+ if (isApiErrResp(redirected)) return redirected;
269
+ result = redirected;
270
+ }
271
+ if (result.ok) return result;
272
+ lastError = result;
273
+ }
274
+ return lastError;
275
+ }
276
+ switchOrigin(origin) {
277
+ this.currentOrigin = origin;
278
+ this.token = void 0;
279
+ }
280
+ authHeaders(token, options) {
281
+ return { "Authorization": `Bearer ${token}`, "Content-Type": "application/json", ...options?.headers };
282
+ }
153
283
  getToken() {
154
284
  if (this.token) {
155
285
  const resp = { ok: { token: this.token } };
@@ -157,16 +287,24 @@ var TypeDBHttpDriver = class {
157
287
  } else return this.refreshToken();
158
288
  }
159
289
  async refreshToken() {
160
- const url = `${remoteOrigin(this.params)}/v1/signin`;
290
+ return this.signinOnce();
291
+ }
292
+ async signinOnce() {
293
+ const url = `${this.currentOrigin}/v1/signin`;
161
294
  const body = { username: this.params.username, password: this.params.password };
162
- const resp = await fetch(url, { method: "POST", body: JSON.stringify(body), headers: { "Content-Type": "application/json" } });
295
+ let resp;
296
+ try {
297
+ resp = await fetch(url, { method: "POST", body: JSON.stringify(body), headers: { "Content-Type": "application/json" } });
298
+ } catch {
299
+ return driverError("HDR2", `Cannot connect to server at ${this.currentOrigin}`);
300
+ }
163
301
  const json = await this.jsonOrNull(resp);
164
302
  if (resp.ok) {
165
303
  this.token = json.token;
166
304
  return { ok: json };
167
- } else if (isApiError(json)) {
168
- return { err: json, status: resp.status };
169
- } else throw resp;
305
+ }
306
+ if (isApiError(json)) return { err: json, status: resp.status };
307
+ throw resp;
170
308
  }
171
309
  async jsonOrNull(resp) {
172
310
  const contentLengthRaw = resp.headers.get("Content-Length");
@@ -185,13 +323,18 @@ var TypeDBHttpDriver = class {
185
323
  };
186
324
  export {
187
325
  TypeDBHttpDriver,
326
+ allOrigins,
327
+ driverError,
188
328
  getVariableName,
329
+ hostPortFromOrigin,
189
330
  isApiError,
190
331
  isApiErrorResponse,
191
332
  isBasicParams,
333
+ isMisdirectedError,
192
334
  isOkResponse,
193
335
  isQueryResponseLegacy,
194
336
  isTranslatedParams,
195
- remoteOrigin
337
+ remoteOrigin,
338
+ resolveOrigin
196
339
  };
197
340
  //# sourceMappingURL=index.mjs.map
package/package.json CHANGED
@@ -1 +1 @@
1
- {"name": "@typedb/driver-http", "version": "3.8.4-rc0", "description": "TypeDB HTTP Driver", "author": "TypeDB Community <community@typedb.com>", "license": "Apache-2.0", "homepage": "https://typedb.com", "repository": {"type": "git", "url": "https://github.com/typedb/typedb-driver"}, "bugs": {"url": "https://github.com/typedb/typedb-driver/issues"}, "keywords": ["database", "typedb"], "main": "dist/index.cjs", "module": "dist/index.mjs", "types": "dist/index.d.ts", "type": "module", "exports": {".": {"types": "./dist/index.d.ts", "import": "./dist/index.mjs", "require": "./dist/index.cjs"}}, "scripts": {"build:dev": "tsc", "build": "tsup", "test": "cucumber-js", "docs": "typedoc"}, "packageManager": "pnpm@8.15.9", "packageConfig": {"access": "public"}, "devDependencies": {"@cucumber/cucumber": "9.0.0", "@types/node": "24.0.12", "tsup": "8.5.0", "typedoc": "^0.28.7", "typescript": "5.8.3"}}
1
+ {"name": "@typedb/driver-http", "version": "3.11.0-rc1", "description": "TypeDB HTTP Driver", "author": "TypeDB Community <community@typedb.com>", "license": "Apache-2.0", "homepage": "https://typedb.com", "repository": {"type": "git", "url": "https://github.com/typedb/typedb-driver"}, "bugs": {"url": "https://github.com/typedb/typedb-driver/issues"}, "keywords": ["database", "typedb"], "main": "dist/index.cjs", "module": "dist/index.mjs", "types": "dist/index.d.ts", "type": "module", "exports": {".": {"types": "./dist/index.d.ts", "import": "./dist/index.mjs", "require": "./dist/index.cjs"}}, "scripts": {"build:dev": "tsc", "build": "tsup", "test": "cucumber-js", "docs": "typedoc"}, "packageManager": "pnpm@8.15.9", "packageConfig": {"access": "public"}, "devDependencies": {"@cucumber/cucumber": "9.0.0", "@types/node": "24.0.12", "tsup": "8.5.0", "typedoc": "^0.28.7", "typescript": "5.8.3"}}