camusdb 0.1.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.
- package/LICENSE +21 -0
- package/README.md +950 -0
- package/dist/auth/credentials.d.ts +30 -0
- package/dist/auth/credentials.d.ts.map +1 -0
- package/dist/auth/credentials.js +23 -0
- package/dist/auth/credentials.js.map +1 -0
- package/dist/auth/login-client.d.ts +37 -0
- package/dist/auth/login-client.d.ts.map +1 -0
- package/dist/auth/login-client.js +8 -0
- package/dist/auth/login-client.js.map +1 -0
- package/dist/auth/rest-login-client.d.ts +17 -0
- package/dist/auth/rest-login-client.d.ts.map +1 -0
- package/dist/auth/rest-login-client.js +71 -0
- package/dist/auth/rest-login-client.js.map +1 -0
- package/dist/auth/token-provider.d.ts +123 -0
- package/dist/auth/token-provider.d.ts.map +1 -0
- package/dist/auth/token-provider.js +209 -0
- package/dist/auth/token-provider.js.map +1 -0
- package/dist/backup.d.ts +98 -0
- package/dist/backup.d.ts.map +1 -0
- package/dist/backup.js +153 -0
- package/dist/backup.js.map +1 -0
- package/dist/cache.d.ts +90 -0
- package/dist/cache.d.ts.map +1 -0
- package/dist/cache.js +121 -0
- package/dist/cache.js.map +1 -0
- package/dist/client.d.ts +406 -0
- package/dist/client.d.ts.map +1 -0
- package/dist/client.js +724 -0
- package/dist/client.js.map +1 -0
- package/dist/column-type.d.ts +33 -0
- package/dist/column-type.d.ts.map +1 -0
- package/dist/column-type.js +50 -0
- package/dist/column-type.js.map +1 -0
- package/dist/column-value.d.ts +77 -0
- package/dist/column-value.d.ts.map +1 -0
- package/dist/column-value.js +60 -0
- package/dist/column-value.js.map +1 -0
- package/dist/config.d.ts +181 -0
- package/dist/config.d.ts.map +1 -0
- package/dist/config.js +315 -0
- package/dist/config.js.map +1 -0
- package/dist/connection-string.d.ts +45 -0
- package/dist/connection-string.d.ts.map +1 -0
- package/dist/connection-string.js +170 -0
- package/dist/connection-string.js.map +1 -0
- package/dist/endpoint-pool.d.ts +70 -0
- package/dist/endpoint-pool.d.ts.map +1 -0
- package/dist/endpoint-pool.js +120 -0
- package/dist/endpoint-pool.js.map +1 -0
- package/dist/error-codes.d.ts +44 -0
- package/dist/error-codes.d.ts.map +1 -0
- package/dist/error-codes.js +43 -0
- package/dist/error-codes.js.map +1 -0
- package/dist/errors.d.ts +24 -0
- package/dist/errors.d.ts.map +1 -0
- package/dist/errors.js +33 -0
- package/dist/errors.js.map +1 -0
- package/dist/hlc.d.ts +19 -0
- package/dist/hlc.d.ts.map +1 -0
- package/dist/hlc.js +11 -0
- package/dist/hlc.js.map +1 -0
- package/dist/index.d.ts +55 -0
- package/dist/index.d.ts.map +1 -0
- package/dist/index.js +51 -0
- package/dist/index.js.map +1 -0
- package/dist/json.d.ts +41 -0
- package/dist/json.d.ts.map +1 -0
- package/dist/json.js +345 -0
- package/dist/json.js.map +1 -0
- package/dist/object-id.d.ts +39 -0
- package/dist/object-id.d.ts.map +1 -0
- package/dist/object-id.js +99 -0
- package/dist/object-id.js.map +1 -0
- package/dist/options.d.ts +77 -0
- package/dist/options.d.ts.map +1 -0
- package/dist/options.js +68 -0
- package/dist/options.js.map +1 -0
- package/dist/prepared/binder.d.ts +20 -0
- package/dist/prepared/binder.d.ts.map +1 -0
- package/dist/prepared/binder.js +32 -0
- package/dist/prepared/binder.js.map +1 -0
- package/dist/prepared/policy.d.ts +81 -0
- package/dist/prepared/policy.d.ts.map +1 -0
- package/dist/prepared/policy.js +164 -0
- package/dist/prepared/policy.js.map +1 -0
- package/dist/query-stream.d.ts +55 -0
- package/dist/query-stream.d.ts.map +1 -0
- package/dist/query-stream.js +94 -0
- package/dist/query-stream.js.map +1 -0
- package/dist/result-set.d.ts +62 -0
- package/dist/result-set.d.ts.map +1 -0
- package/dist/result-set.js +100 -0
- package/dist/result-set.js.map +1 -0
- package/dist/retry.d.ts +38 -0
- package/dist/retry.d.ts.map +1 -0
- package/dist/retry.js +93 -0
- package/dist/retry.js.map +1 -0
- package/dist/routing/advice.d.ts +63 -0
- package/dist/routing/advice.d.ts.map +1 -0
- package/dist/routing/advice.js +61 -0
- package/dist/routing/advice.js.map +1 -0
- package/dist/routing/route-cache.d.ts +53 -0
- package/dist/routing/route-cache.d.ts.map +1 -0
- package/dist/routing/route-cache.js +123 -0
- package/dist/routing/route-cache.js.map +1 -0
- package/dist/routing/router.d.ts +53 -0
- package/dist/routing/router.d.ts.map +1 -0
- package/dist/routing/router.js +89 -0
- package/dist/routing/router.js.map +1 -0
- package/dist/row-source.d.ts +48 -0
- package/dist/row-source.d.ts.map +1 -0
- package/dist/row-source.js +35 -0
- package/dist/row-source.js.map +1 -0
- package/dist/runtime.d.ts +58 -0
- package/dist/runtime.d.ts.map +1 -0
- package/dist/runtime.js +137 -0
- package/dist/runtime.js.map +1 -0
- package/dist/shared-registry.d.ts +32 -0
- package/dist/shared-registry.d.ts.map +1 -0
- package/dist/shared-registry.js +48 -0
- package/dist/shared-registry.js.map +1 -0
- package/dist/sql-syntax.d.ts +44 -0
- package/dist/sql-syntax.d.ts.map +1 -0
- package/dist/sql-syntax.js +83 -0
- package/dist/sql-syntax.js.map +1 -0
- package/dist/statements.d.ts +15 -0
- package/dist/statements.d.ts.map +1 -0
- package/dist/statements.js +90 -0
- package/dist/statements.js.map +1 -0
- package/dist/transaction.d.ts +117 -0
- package/dist/transaction.d.ts.map +1 -0
- package/dist/transaction.js +204 -0
- package/dist/transaction.js.map +1 -0
- package/dist/transport/authenticating-transport.d.ts +63 -0
- package/dist/transport/authenticating-transport.d.ts.map +1 -0
- package/dist/transport/authenticating-transport.js +119 -0
- package/dist/transport/authenticating-transport.js.map +1 -0
- package/dist/transport/branch-statements.d.ts +39 -0
- package/dist/transport/branch-statements.d.ts.map +1 -0
- package/dist/transport/branch-statements.js +74 -0
- package/dist/transport/branch-statements.js.map +1 -0
- package/dist/transport/error-text.d.ts +26 -0
- package/dist/transport/error-text.d.ts.map +1 -0
- package/dist/transport/error-text.js +75 -0
- package/dist/transport/error-text.js.map +1 -0
- package/dist/transport/grpc/batcher.d.ts +127 -0
- package/dist/transport/grpc/batcher.d.ts.map +1 -0
- package/dist/transport/grpc/batcher.js +399 -0
- package/dist/transport/grpc/batcher.js.map +1 -0
- package/dist/transport/grpc/codec.d.ts +40 -0
- package/dist/transport/grpc/codec.d.ts.map +1 -0
- package/dist/transport/grpc/codec.js +231 -0
- package/dist/transport/grpc/codec.js.map +1 -0
- package/dist/transport/grpc/grpc-transport.d.ts +115 -0
- package/dist/transport/grpc/grpc-transport.d.ts.map +1 -0
- package/dist/transport/grpc/grpc-transport.js +577 -0
- package/dist/transport/grpc/grpc-transport.js.map +1 -0
- package/dist/transport/grpc/messages.d.ts +221 -0
- package/dist/transport/grpc/messages.d.ts.map +1 -0
- package/dist/transport/grpc/messages.js +56 -0
- package/dist/transport/grpc/messages.js.map +1 -0
- package/dist/transport/grpc/proto.d.ts +71 -0
- package/dist/transport/grpc/proto.d.ts.map +1 -0
- package/dist/transport/grpc/proto.js +67 -0
- package/dist/transport/grpc/proto.js.map +1 -0
- package/dist/transport/http.d.ts +62 -0
- package/dist/transport/http.d.ts.map +1 -0
- package/dist/transport/http.js +169 -0
- package/dist/transport/http.js.map +1 -0
- package/dist/transport/ndjson-row-source.d.ts +38 -0
- package/dist/transport/ndjson-row-source.d.ts.map +1 -0
- package/dist/transport/ndjson-row-source.js +197 -0
- package/dist/transport/ndjson-row-source.js.map +1 -0
- package/dist/transport/rest-decode.d.ts +33 -0
- package/dist/transport/rest-decode.d.ts.map +1 -0
- package/dist/transport/rest-decode.js +162 -0
- package/dist/transport/rest-decode.js.map +1 -0
- package/dist/transport/rest-prepared-cache.d.ts +50 -0
- package/dist/transport/rest-prepared-cache.d.ts.map +1 -0
- package/dist/transport/rest-prepared-cache.js +101 -0
- package/dist/transport/rest-prepared-cache.js.map +1 -0
- package/dist/transport/rest-transport.d.ts +88 -0
- package/dist/transport/rest-transport.d.ts.map +1 -0
- package/dist/transport/rest-transport.js +388 -0
- package/dist/transport/rest-transport.js.map +1 -0
- package/dist/transport/transport-pool.d.ts +40 -0
- package/dist/transport/transport-pool.d.ts.map +1 -0
- package/dist/transport/transport-pool.js +48 -0
- package/dist/transport/transport-pool.js.map +1 -0
- package/dist/transport/transport.d.ts +199 -0
- package/dist/transport/transport.d.ts.map +1 -0
- package/dist/transport/transport.js +11 -0
- package/dist/transport/transport.js.map +1 -0
- package/dist/values/decode.d.ts +39 -0
- package/dist/values/decode.d.ts.map +1 -0
- package/dist/values/decode.js +75 -0
- package/dist/values/decode.js.map +1 -0
- package/dist/values/encode.d.ts +45 -0
- package/dist/values/encode.d.ts.map +1 -0
- package/dist/values/encode.js +271 -0
- package/dist/values/encode.js.map +1 -0
- package/dist/values/ticks.d.ts +31 -0
- package/dist/values/ticks.d.ts.map +1 -0
- package/dist/values/ticks.js +52 -0
- package/dist/values/ticks.js.map +1 -0
- package/dist/values/typed.d.ts +67 -0
- package/dist/values/typed.d.ts.map +1 -0
- package/dist/values/typed.js +134 -0
- package/dist/values/typed.js.map +1 -0
- package/dist/values/uuid.d.ts +27 -0
- package/dist/values/uuid.d.ts.map +1 -0
- package/dist/values/uuid.js +76 -0
- package/dist/values/uuid.js.map +1 -0
- package/dist/vector.d.ts +26 -0
- package/dist/vector.d.ts.map +1 -0
- package/dist/vector.js +48 -0
- package/dist/vector.js.map +1 -0
- package/package.json +86 -0
- package/proto/camus_sql.proto +566 -0
package/dist/config.js
ADDED
|
@@ -0,0 +1,315 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* This file is part of CamusDB
|
|
3
|
+
*
|
|
4
|
+
* For the full copyright and license information, please view the LICENSE.txt
|
|
5
|
+
* file that was distributed with this source code.
|
|
6
|
+
*/
|
|
7
|
+
import { NO_CREDENTIALS, credentialsFromPassword, credentialsFromToken, hasCredentials, } from './auth/credentials.js';
|
|
8
|
+
import { parseConnectionString, redactConnectionString } from './connection-string.js';
|
|
9
|
+
import { CamusEndpointPool } from './endpoint-pool.js';
|
|
10
|
+
import { CamusError } from './errors.js';
|
|
11
|
+
import { CamusErrorCode } from './error-codes.js';
|
|
12
|
+
import { CamusIsolationLevel, CamusLocking, CamusTransactionMode } from './options.js';
|
|
13
|
+
/** The wire protocol a client speaks. */
|
|
14
|
+
export const CamusProtocol = {
|
|
15
|
+
/** The REST and JSON HTTP API. This is the default. */
|
|
16
|
+
Rest: 'rest',
|
|
17
|
+
/** The gRPC API. The endpoint must address the server's gRPC port. */
|
|
18
|
+
Grpc: 'grpc',
|
|
19
|
+
};
|
|
20
|
+
/** How a client uses learned statement routing. */
|
|
21
|
+
export const CamusRoutingMode = {
|
|
22
|
+
/** Rotate over the configured endpoints. Never negotiate, never learn. */
|
|
23
|
+
Off: 'off',
|
|
24
|
+
/** Negotiate routing metadata and prefer a learned destination for an unpinned statement. */
|
|
25
|
+
Learned: 'learned',
|
|
26
|
+
/**
|
|
27
|
+
* Behave as `learned` when `routingNodes` maps at least two distinct configured endpoints, and
|
|
28
|
+
* as `off` otherwise. One destination is not a routing decision, and a single load-balancer URL
|
|
29
|
+
* is not a set of routable database nodes. This is the default: the trust map is the opt-in, not
|
|
30
|
+
* a second switch.
|
|
31
|
+
*/
|
|
32
|
+
Auto: 'auto',
|
|
33
|
+
};
|
|
34
|
+
export const DEFAULT_BATCH_OPTIONS = Object.freeze({
|
|
35
|
+
channelPoolSize: 2,
|
|
36
|
+
coalescingThreshold: 10,
|
|
37
|
+
coalescingDelayMs: 0,
|
|
38
|
+
});
|
|
39
|
+
/** How many statements a client keeps prepared, and how hot a statement must be first. */
|
|
40
|
+
export const DEFAULT_MAX_AUTO_PREPARE = 128;
|
|
41
|
+
export const DEFAULT_AUTO_PREPARE_MIN_USAGES = 2;
|
|
42
|
+
/** Fallback token lifetime, comfortably inside the server's 15-minute default. */
|
|
43
|
+
export const DEFAULT_TOKEN_LIFETIME_MS = 600_000;
|
|
44
|
+
/** The backup admin API's own timeout. Taking a full backup routinely outlasts a statement. */
|
|
45
|
+
export const DEFAULT_BACKUP_TIMEOUT_SECONDS = 300;
|
|
46
|
+
/** The connection-string key that waives the refusal to send credentials in the clear. */
|
|
47
|
+
export const ALLOW_INSECURE_CREDENTIALS_KEY = 'AllowInsecureCredentials';
|
|
48
|
+
/** Resolves an options object. */
|
|
49
|
+
export function resolveOptions(options) {
|
|
50
|
+
const endpointList = Array.isArray(options.endpoint)
|
|
51
|
+
? options.endpoint.join(',')
|
|
52
|
+
: options.endpoint;
|
|
53
|
+
if (typeof endpointList !== 'string' || endpointList.trim().length === 0) {
|
|
54
|
+
throw new CamusError(CamusErrorCode.Generic, 'Endpoint is required.');
|
|
55
|
+
}
|
|
56
|
+
if (typeof options.database !== 'string' || options.database.trim().length === 0) {
|
|
57
|
+
throw new CamusError(CamusErrorCode.Generic, 'Database is required.');
|
|
58
|
+
}
|
|
59
|
+
const config = {
|
|
60
|
+
endpointList,
|
|
61
|
+
database: options.database,
|
|
62
|
+
timeoutSeconds: positiveOr(options.timeoutSeconds, 10),
|
|
63
|
+
protocol: options.protocol ?? CamusProtocol.Rest,
|
|
64
|
+
credentials: resolveCredentials(options),
|
|
65
|
+
tokenLifetimeMs: positiveOr(options.tokenLifetimeSeconds, 0) * 1000 || DEFAULT_TOKEN_LIFETIME_MS,
|
|
66
|
+
maxAutoPrepare: nonNegativeOr(options.maxAutoPrepare, DEFAULT_MAX_AUTO_PREPARE),
|
|
67
|
+
autoPrepareMinUsages: positiveOr(options.autoPrepareMinUsages, DEFAULT_AUTO_PREPARE_MIN_USAGES),
|
|
68
|
+
batch: {
|
|
69
|
+
channelPoolSize: atLeastOr(options.channelPoolSize, 1, DEFAULT_BATCH_OPTIONS.channelPoolSize),
|
|
70
|
+
coalescingThreshold: atLeastOr(options.coalescingThreshold, 1, DEFAULT_BATCH_OPTIONS.coalescingThreshold),
|
|
71
|
+
coalescingDelayMs: atLeastOr(options.coalescingDelayMs, 0, DEFAULT_BATCH_OPTIONS.coalescingDelayMs),
|
|
72
|
+
},
|
|
73
|
+
backupEndpoint: options.backupEndpoint,
|
|
74
|
+
backupTimeoutSeconds: positiveOr(options.backupTimeoutSeconds, DEFAULT_BACKUP_TIMEOUT_SECONDS),
|
|
75
|
+
allowInsecureCredentials: options.allowInsecureCredentials === true,
|
|
76
|
+
routingMode: options.routingMode ?? CamusRoutingMode.Auto,
|
|
77
|
+
routingNodes: resolveRoutingNodes(options.routingNodes, endpointList),
|
|
78
|
+
routingMaxHintAgeMs: atLeastOr(options.routingMaxHintAgeMs, 1, 5000),
|
|
79
|
+
defaultTransactionOptions: options.defaultTransactionOptions ?? {},
|
|
80
|
+
decode: { int64: options.int64 ?? 'auto' },
|
|
81
|
+
connectionString: undefined,
|
|
82
|
+
};
|
|
83
|
+
ensureCredentialsAreNotSentInClear(config);
|
|
84
|
+
return config;
|
|
85
|
+
}
|
|
86
|
+
/** Resolves a connection string. */
|
|
87
|
+
export function resolveConnectionString(connectionString) {
|
|
88
|
+
const settings = parseConnectionString(connectionString);
|
|
89
|
+
const endpointList = settings.get('Endpoint');
|
|
90
|
+
if (endpointList === undefined || endpointList.trim().length === 0) {
|
|
91
|
+
throw new CamusError(CamusErrorCode.Generic, 'Endpoint is required.');
|
|
92
|
+
}
|
|
93
|
+
const database = settings.get('Database');
|
|
94
|
+
if (database === undefined) {
|
|
95
|
+
throw new CamusError(CamusErrorCode.Generic, 'Database is required.');
|
|
96
|
+
}
|
|
97
|
+
const config = {
|
|
98
|
+
endpointList,
|
|
99
|
+
database,
|
|
100
|
+
timeoutSeconds: parsePositiveInt(settings.get('Timeout'), 10),
|
|
101
|
+
protocol: parseEnum(settings.get('Protocol'), CamusProtocol, CamusProtocol.Rest),
|
|
102
|
+
credentials: credentialsFromSettings(settings),
|
|
103
|
+
tokenLifetimeMs: parsePositiveInt(settings.get('TokenLifetime'), 0) * 1000 || DEFAULT_TOKEN_LIFETIME_MS,
|
|
104
|
+
maxAutoPrepare: parseNonNegativeInt(settings.get('MaxAutoPrepare'), DEFAULT_MAX_AUTO_PREPARE),
|
|
105
|
+
autoPrepareMinUsages: parsePositiveInt(settings.get('AutoPrepareMinUsages'), DEFAULT_AUTO_PREPARE_MIN_USAGES),
|
|
106
|
+
batch: {
|
|
107
|
+
channelPoolSize: parseIntAtLeast(settings.get('ChannelPoolSize'), 1, DEFAULT_BATCH_OPTIONS.channelPoolSize),
|
|
108
|
+
coalescingThreshold: parseIntAtLeast(settings.get('CoalescingThreshold'), 1, DEFAULT_BATCH_OPTIONS.coalescingThreshold),
|
|
109
|
+
coalescingDelayMs: parseIntAtLeast(settings.get('CoalescingDelay'), 0, DEFAULT_BATCH_OPTIONS.coalescingDelayMs),
|
|
110
|
+
},
|
|
111
|
+
backupEndpoint: settings.first('BackupEndpoint'),
|
|
112
|
+
backupTimeoutSeconds: parsePositiveInt(settings.get('BackupTimeout'), DEFAULT_BACKUP_TIMEOUT_SECONDS),
|
|
113
|
+
allowInsecureCredentials: settings.get(ALLOW_INSECURE_CREDENTIALS_KEY)?.toLowerCase() === 'true',
|
|
114
|
+
routingMode: parseEnum(settings.get('RoutingMode'), CamusRoutingMode, CamusRoutingMode.Auto),
|
|
115
|
+
routingNodes: resolveRoutingNodes(settings.get('RoutingNodes'), endpointList),
|
|
116
|
+
routingMaxHintAgeMs: parseIntAtLeast(settings.get('RoutingMaxHintAge'), 1, 5000),
|
|
117
|
+
defaultTransactionOptions: {
|
|
118
|
+
isolationLevel: parseEnum(settings.get('IsolationLevel'), CamusIsolationLevel, undefined),
|
|
119
|
+
mode: parseEnum(settings.get('TransactionMode'), CamusTransactionMode, undefined),
|
|
120
|
+
locking: parseEnum(settings.get('Locking'), CamusLocking, undefined),
|
|
121
|
+
},
|
|
122
|
+
decode: { int64: parseInt64Mode(settings.get('Int64')) },
|
|
123
|
+
connectionString,
|
|
124
|
+
};
|
|
125
|
+
ensureCredentialsAreNotSentInClear(config);
|
|
126
|
+
return config;
|
|
127
|
+
}
|
|
128
|
+
/**
|
|
129
|
+
* Where the backup admin API lives.
|
|
130
|
+
*
|
|
131
|
+
* The backup routes are REST and JSON only — they have no SQL form and no gRPC service — so a gRPC
|
|
132
|
+
* client, whose endpoint addresses the gRPC port, must say where the HTTP port is. Rather than
|
|
133
|
+
* send HTTP at a gRPC port and fail obscurely, that case is refused with a message naming the
|
|
134
|
+
* setting to fill in.
|
|
135
|
+
*
|
|
136
|
+
* A configured backup endpoint is used as written, with no rotation: backups are node-level, and a
|
|
137
|
+
* coordinated backup must reach the coordinator specifically.
|
|
138
|
+
*/
|
|
139
|
+
export function resolveBackupEndpoint(config, pool) {
|
|
140
|
+
if (config.backupEndpoint !== undefined && config.backupEndpoint.trim().length > 0) {
|
|
141
|
+
return config.backupEndpoint;
|
|
142
|
+
}
|
|
143
|
+
if (config.protocol !== CamusProtocol.Rest) {
|
|
144
|
+
throw new CamusError(CamusErrorCode.Generic, 'The backup admin API is REST-only; a gRPC client must set backupEndpoint to the server’s HTTP endpoint.');
|
|
145
|
+
}
|
|
146
|
+
return pool.next();
|
|
147
|
+
}
|
|
148
|
+
/**
|
|
149
|
+
* Identifies the deployment when deciding which clients may share a token or a transport: the
|
|
150
|
+
* endpoint list plus the protocol. The same credentials against two different servers never share
|
|
151
|
+
* a token, and a REST client and a gRPC client each hold the token their own transport minted.
|
|
152
|
+
*/
|
|
153
|
+
export function deploymentKey(config) {
|
|
154
|
+
return `${config.endpointList}|${config.protocol}`;
|
|
155
|
+
}
|
|
156
|
+
/** The connection string with every secret masked, or a rebuilt summary for an options object. */
|
|
157
|
+
export function describeConfig(config) {
|
|
158
|
+
if (config.connectionString !== undefined)
|
|
159
|
+
return redactConnectionString(config.connectionString);
|
|
160
|
+
const parts = [`Endpoint=${config.endpointList}`, `Database=${config.database}`];
|
|
161
|
+
if (config.protocol !== CamusProtocol.Rest)
|
|
162
|
+
parts.push(`Protocol=${config.protocol}`);
|
|
163
|
+
if (config.credentials.user !== undefined)
|
|
164
|
+
parts.push(`User=${config.credentials.user};Password=***`);
|
|
165
|
+
if (config.credentials.accessToken !== undefined)
|
|
166
|
+
parts.push('AccessToken=***');
|
|
167
|
+
return parts.join(';');
|
|
168
|
+
}
|
|
169
|
+
/**
|
|
170
|
+
* Refuses to carry credentials to an endpoint that cannot protect them.
|
|
171
|
+
*
|
|
172
|
+
* A password is posted to `/login` and a bearer token rides every later request. On an `http://`
|
|
173
|
+
* endpoint both cross the network in the clear, and the server's own `CADB0519` check — which a
|
|
174
|
+
* deployment can switch off — only fires after the password has already been sent. So the client
|
|
175
|
+
* refuses first, before anything leaves the process.
|
|
176
|
+
*
|
|
177
|
+
* A loopback endpoint is allowed: the traffic never reaches a network, and that is how the
|
|
178
|
+
* documented local examples and the test suite connect. Everything else must be `https://`, unless
|
|
179
|
+
* `allowInsecureCredentials` is set — for a deployment reached over a private link that terminates
|
|
180
|
+
* TLS elsewhere.
|
|
181
|
+
*
|
|
182
|
+
* The backup endpoint is held to the same rule, and deliberately: the token it receives is the
|
|
183
|
+
* client's own, which the backup admin API requires to be superuser-grade.
|
|
184
|
+
*/
|
|
185
|
+
export function ensureCredentialsAreNotSentInClear(config) {
|
|
186
|
+
if (!hasCredentials(config.credentials))
|
|
187
|
+
return;
|
|
188
|
+
if (config.allowInsecureCredentials)
|
|
189
|
+
return;
|
|
190
|
+
for (const endpoint of config.endpointList.split(',')) {
|
|
191
|
+
const trimmed = endpoint.trim();
|
|
192
|
+
if (trimmed.length > 0)
|
|
193
|
+
ensureEndpointIsSecure(trimmed, 'Endpoint');
|
|
194
|
+
}
|
|
195
|
+
if (config.backupEndpoint !== undefined && config.backupEndpoint.trim().length > 0) {
|
|
196
|
+
ensureEndpointIsSecure(config.backupEndpoint.trim(), 'BackupEndpoint');
|
|
197
|
+
}
|
|
198
|
+
}
|
|
199
|
+
function ensureEndpointIsSecure(endpoint, key) {
|
|
200
|
+
let url;
|
|
201
|
+
try {
|
|
202
|
+
url = new URL(endpoint);
|
|
203
|
+
}
|
|
204
|
+
catch {
|
|
205
|
+
throw new CamusError(CamusErrorCode.Generic, `The ${key} '${endpoint}' is not an absolute URL.`);
|
|
206
|
+
}
|
|
207
|
+
if (url.protocol === 'https:' || isLoopback(url.hostname))
|
|
208
|
+
return;
|
|
209
|
+
throw new CamusError(CamusErrorCode.InsecureTransport, `This configuration sends credentials to the ${key} '${endpoint}', which is neither https nor loopback. ` +
|
|
210
|
+
'The password and the bearer token would cross the network in the clear. Use https, or set ' +
|
|
211
|
+
`${ALLOW_INSECURE_CREDENTIALS_KEY} when the endpoint is reached over a link that protects them.`);
|
|
212
|
+
}
|
|
213
|
+
function isLoopback(hostname) {
|
|
214
|
+
const host = hostname.replace(/^\[|\]$/g, '').toLowerCase();
|
|
215
|
+
return host === 'localhost' || host === '::1' || host === '0:0:0:0:0:0:0:1' || /^127\./.test(host);
|
|
216
|
+
}
|
|
217
|
+
function resolveCredentials(options) {
|
|
218
|
+
if (options.accessToken !== undefined && options.accessToken.length > 0) {
|
|
219
|
+
return credentialsFromToken(options.accessToken);
|
|
220
|
+
}
|
|
221
|
+
if (options.user !== undefined && options.user.length > 0) {
|
|
222
|
+
return credentialsFromPassword(options.user, options.password ?? '');
|
|
223
|
+
}
|
|
224
|
+
return NO_CREDENTIALS;
|
|
225
|
+
}
|
|
226
|
+
function credentialsFromSettings(settings) {
|
|
227
|
+
const token = settings.first('AccessToken');
|
|
228
|
+
if (token !== undefined)
|
|
229
|
+
return credentialsFromToken(token);
|
|
230
|
+
const user = settings.first('User', 'UserId', 'Uid', 'Username');
|
|
231
|
+
if (user !== undefined) {
|
|
232
|
+
return credentialsFromPassword(user, settings.get('Password') ?? settings.get('Pwd') ?? '');
|
|
233
|
+
}
|
|
234
|
+
return NO_CREDENTIALS;
|
|
235
|
+
}
|
|
236
|
+
/**
|
|
237
|
+
* The trust map, filtered to addresses the endpoint pool actually lists.
|
|
238
|
+
*
|
|
239
|
+
* Advice becomes a destination only through this map, and only when the mapped address is a member
|
|
240
|
+
* of the endpoint pool. An entry naming any other address is dropped, so a response can never
|
|
241
|
+
* steer traffic at an address the operator did not list. Malformed entries are skipped rather than
|
|
242
|
+
* thrown on, the way the other tuning settings treat unusable input.
|
|
243
|
+
*/
|
|
244
|
+
function resolveRoutingNodes(nodes, endpointList) {
|
|
245
|
+
const map = new Map();
|
|
246
|
+
if (nodes === undefined)
|
|
247
|
+
return map;
|
|
248
|
+
const pool = CamusEndpointPool.forEndpoints(endpointList);
|
|
249
|
+
const pairs = [];
|
|
250
|
+
if (typeof nodes === 'string') {
|
|
251
|
+
for (const entry of nodes.split(',')) {
|
|
252
|
+
const trimmed = entry.trim();
|
|
253
|
+
if (trimmed.length === 0)
|
|
254
|
+
continue;
|
|
255
|
+
// The node identity is `host:port` and the address is a URL, so the first '=' is the only
|
|
256
|
+
// separator that is not ambiguous.
|
|
257
|
+
const separator = trimmed.indexOf('=');
|
|
258
|
+
if (separator <= 0 || separator === trimmed.length - 1)
|
|
259
|
+
continue;
|
|
260
|
+
pairs.push([trimmed.slice(0, separator).trim(), trimmed.slice(separator + 1).trim()]);
|
|
261
|
+
}
|
|
262
|
+
}
|
|
263
|
+
else {
|
|
264
|
+
for (const [nodeId, address] of Object.entries(nodes)) {
|
|
265
|
+
pairs.push([nodeId.trim(), address.trim()]);
|
|
266
|
+
}
|
|
267
|
+
}
|
|
268
|
+
for (const [nodeId, address] of pairs) {
|
|
269
|
+
if (nodeId.length > 0 && pool.contains(address))
|
|
270
|
+
map.set(nodeId, address);
|
|
271
|
+
}
|
|
272
|
+
return map;
|
|
273
|
+
}
|
|
274
|
+
function parseEnum(raw, members, fallback) {
|
|
275
|
+
if (raw === undefined)
|
|
276
|
+
return fallback;
|
|
277
|
+
const wanted = raw.trim().toLowerCase();
|
|
278
|
+
for (const value of Object.values(members)) {
|
|
279
|
+
if (value.toLowerCase() === wanted)
|
|
280
|
+
return value;
|
|
281
|
+
}
|
|
282
|
+
return fallback;
|
|
283
|
+
}
|
|
284
|
+
function parseInt64Mode(raw) {
|
|
285
|
+
switch (raw?.trim().toLowerCase()) {
|
|
286
|
+
case 'number':
|
|
287
|
+
return 'number';
|
|
288
|
+
case 'bigint':
|
|
289
|
+
return 'bigint';
|
|
290
|
+
default:
|
|
291
|
+
return 'auto';
|
|
292
|
+
}
|
|
293
|
+
}
|
|
294
|
+
function parsePositiveInt(raw, fallback) {
|
|
295
|
+
const parsed = Number.parseInt(raw ?? '', 10);
|
|
296
|
+
return Number.isInteger(parsed) && parsed > 0 ? parsed : fallback;
|
|
297
|
+
}
|
|
298
|
+
function parseNonNegativeInt(raw, fallback) {
|
|
299
|
+
const parsed = Number.parseInt(raw ?? '', 10);
|
|
300
|
+
return Number.isInteger(parsed) && parsed >= 0 ? parsed : fallback;
|
|
301
|
+
}
|
|
302
|
+
function parseIntAtLeast(raw, minimum, fallback) {
|
|
303
|
+
const parsed = Number.parseInt(raw ?? '', 10);
|
|
304
|
+
return Number.isInteger(parsed) && parsed >= minimum ? parsed : fallback;
|
|
305
|
+
}
|
|
306
|
+
function positiveOr(value, fallback) {
|
|
307
|
+
return value !== undefined && Number.isFinite(value) && value > 0 ? Math.floor(value) : fallback;
|
|
308
|
+
}
|
|
309
|
+
function nonNegativeOr(value, fallback) {
|
|
310
|
+
return value !== undefined && Number.isFinite(value) && value >= 0 ? Math.floor(value) : fallback;
|
|
311
|
+
}
|
|
312
|
+
function atLeastOr(value, minimum, fallback) {
|
|
313
|
+
return value !== undefined && Number.isFinite(value) && value >= minimum ? Math.floor(value) : fallback;
|
|
314
|
+
}
|
|
315
|
+
//# sourceMappingURL=config.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"config.js","sourceRoot":"","sources":["../src/config.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1,45 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* This file is part of CamusDB
|
|
3
|
+
*
|
|
4
|
+
* For the full copyright and license information, please view the LICENSE.txt
|
|
5
|
+
* file that was distributed with this source code.
|
|
6
|
+
*/
|
|
7
|
+
/**
|
|
8
|
+
* The parsed settings, keyed by lowercase key name. The original spelling of each key is kept so a
|
|
9
|
+
* diagnostic can name the key the way the caller wrote it.
|
|
10
|
+
*/
|
|
11
|
+
export declare class ConnectionStringSettings {
|
|
12
|
+
private readonly entries;
|
|
13
|
+
constructor(entries: Iterable<{
|
|
14
|
+
key: string;
|
|
15
|
+
value: string;
|
|
16
|
+
}>);
|
|
17
|
+
/** The value for a key, or `undefined`. Matching ignores case. */
|
|
18
|
+
get(key: string): string | undefined;
|
|
19
|
+
/** The first key of `keys` that has a value that is not blank. */
|
|
20
|
+
first(...keys: string[]): string | undefined;
|
|
21
|
+
/** True when the key is present, even with an empty value. */
|
|
22
|
+
has(key: string): boolean;
|
|
23
|
+
/** Replaces or adds a value. Used by `changeDatabase`. */
|
|
24
|
+
set(key: string, value: string): void;
|
|
25
|
+
/** Every key and value, in insertion order. */
|
|
26
|
+
[Symbol.iterator](): IterableIterator<{
|
|
27
|
+
key: string;
|
|
28
|
+
value: string;
|
|
29
|
+
}>;
|
|
30
|
+
}
|
|
31
|
+
/**
|
|
32
|
+
* Parses a connection string.
|
|
33
|
+
*
|
|
34
|
+
* @throws {CamusError} `CADB0000` when a key appears twice, or a quoted value is not closed.
|
|
35
|
+
*/
|
|
36
|
+
export declare function parseConnectionString(connectionString: string): ConnectionStringSettings;
|
|
37
|
+
/**
|
|
38
|
+
* The connection string with every secret replaced by `***`. Everything else, including the
|
|
39
|
+
* original spelling and order of the keys, is left as written, so the result still identifies the
|
|
40
|
+
* connection.
|
|
41
|
+
*
|
|
42
|
+
* Use it for anything that is logged, printed, or reported as diagnostics.
|
|
43
|
+
*/
|
|
44
|
+
export declare function redactConnectionString(connectionString: string | undefined | null): string;
|
|
45
|
+
//# sourceMappingURL=connection-string.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"connection-string.d.ts","sourceRoot":"","sources":["../src/connection-string.ts"],"names":[],"mappings":"AAAA;;;;;GAKG;AA4BH;;;GAGG;AACH,qBAAa,wBAAwB;IACnC,OAAO,CAAC,QAAQ,CAAC,OAAO,CAAqD;gBAEjE,OAAO,EAAE,QAAQ,CAAC;QAAE,GAAG,EAAE,MAAM,CAAC;QAAC,KAAK,EAAE,MAAM,CAAA;KAAE,CAAC;IAM7D,kEAAkE;IAClE,GAAG,CAAC,GAAG,EAAE,MAAM,GAAG,MAAM,GAAG,SAAS;IAIpC,kEAAkE;IAClE,KAAK,CAAC,GAAG,IAAI,EAAE,MAAM,EAAE,GAAG,MAAM,GAAG,SAAS;IAS5C,8DAA8D;IAC9D,GAAG,CAAC,GAAG,EAAE,MAAM,GAAG,OAAO;IAIzB,0DAA0D;IAC1D,GAAG,CAAC,GAAG,EAAE,MAAM,EAAE,KAAK,EAAE,MAAM,GAAG,IAAI;IAKrC,+CAA+C;IAC9C,CAAC,MAAM,CAAC,QAAQ,CAAC,IAAI,gBAAgB,CAAC;QAAE,GAAG,EAAE,MAAM,CAAC;QAAC,KAAK,EAAE,MAAM,CAAA;KAAE,CAAC;CAGvE;AAED;;;;GAIG;AACH,wBAAgB,qBAAqB,CAAC,gBAAgB,EAAE,MAAM,GAAG,wBAAwB,CAoBxF;AAWD;;;;;;GAMG;AACH,wBAAgB,sBAAsB,CAAC,gBAAgB,EAAE,MAAM,GAAG,SAAS,GAAG,IAAI,GAAG,MAAM,CA4B1F"}
|
|
@@ -0,0 +1,170 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* This file is part of CamusDB
|
|
3
|
+
*
|
|
4
|
+
* For the full copyright and license information, please view the LICENSE.txt
|
|
5
|
+
* file that was distributed with this source code.
|
|
6
|
+
*/
|
|
7
|
+
import { CamusError } from './errors.js';
|
|
8
|
+
import { CamusErrorCode } from './error-codes.js';
|
|
9
|
+
/**
|
|
10
|
+
* The parsed settings, keyed by lowercase key name. The original spelling of each key is kept so a
|
|
11
|
+
* diagnostic can name the key the way the caller wrote it.
|
|
12
|
+
*/
|
|
13
|
+
export class ConnectionStringSettings {
|
|
14
|
+
entries = new Map();
|
|
15
|
+
constructor(entries) {
|
|
16
|
+
for (const entry of entries) {
|
|
17
|
+
this.entries.set(entry.key.toLowerCase(), entry);
|
|
18
|
+
}
|
|
19
|
+
}
|
|
20
|
+
/** The value for a key, or `undefined`. Matching ignores case. */
|
|
21
|
+
get(key) {
|
|
22
|
+
return this.entries.get(key.toLowerCase())?.value;
|
|
23
|
+
}
|
|
24
|
+
/** The first key of `keys` that has a value that is not blank. */
|
|
25
|
+
first(...keys) {
|
|
26
|
+
for (const key of keys) {
|
|
27
|
+
const value = this.get(key);
|
|
28
|
+
if (value !== undefined && value.trim().length > 0)
|
|
29
|
+
return value;
|
|
30
|
+
}
|
|
31
|
+
return undefined;
|
|
32
|
+
}
|
|
33
|
+
/** True when the key is present, even with an empty value. */
|
|
34
|
+
has(key) {
|
|
35
|
+
return this.entries.has(key.toLowerCase());
|
|
36
|
+
}
|
|
37
|
+
/** Replaces or adds a value. Used by `changeDatabase`. */
|
|
38
|
+
set(key, value) {
|
|
39
|
+
const existing = this.entries.get(key.toLowerCase());
|
|
40
|
+
this.entries.set(key.toLowerCase(), { key: existing?.key ?? key, value });
|
|
41
|
+
}
|
|
42
|
+
/** Every key and value, in insertion order. */
|
|
43
|
+
*[Symbol.iterator]() {
|
|
44
|
+
yield* this.entries.values();
|
|
45
|
+
}
|
|
46
|
+
}
|
|
47
|
+
/**
|
|
48
|
+
* Parses a connection string.
|
|
49
|
+
*
|
|
50
|
+
* @throws {CamusError} `CADB0000` when a key appears twice, or a quoted value is not closed.
|
|
51
|
+
*/
|
|
52
|
+
export function parseConnectionString(connectionString) {
|
|
53
|
+
const seen = new Set();
|
|
54
|
+
const entries = [];
|
|
55
|
+
for (const setting of enumerateSettings(connectionString)) {
|
|
56
|
+
const lowercase = setting.key.toLowerCase();
|
|
57
|
+
if (seen.has(lowercase)) {
|
|
58
|
+
throw new CamusError(CamusErrorCode.Generic, `The connection string sets '${setting.key}' more than once. Keys are matched without regard ` +
|
|
59
|
+
'to case; remove the duplicate.');
|
|
60
|
+
}
|
|
61
|
+
seen.add(lowercase);
|
|
62
|
+
entries.push({ key: setting.key, value: setting.value });
|
|
63
|
+
}
|
|
64
|
+
return new ConnectionStringSettings(entries);
|
|
65
|
+
}
|
|
66
|
+
/** The keys whose values a redacted string masks. */
|
|
67
|
+
const SECRET_KEYS = new Set(['password', 'pwd', 'accesstoken']);
|
|
68
|
+
/**
|
|
69
|
+
* What a masked secret is replaced with. Not the empty string: an empty value reads as "no
|
|
70
|
+
* password was configured", which is a different fact.
|
|
71
|
+
*/
|
|
72
|
+
const REDACTED = '***';
|
|
73
|
+
/**
|
|
74
|
+
* The connection string with every secret replaced by `***`. Everything else, including the
|
|
75
|
+
* original spelling and order of the keys, is left as written, so the result still identifies the
|
|
76
|
+
* connection.
|
|
77
|
+
*
|
|
78
|
+
* Use it for anything that is logged, printed, or reported as diagnostics.
|
|
79
|
+
*/
|
|
80
|
+
export function redactConnectionString(connectionString) {
|
|
81
|
+
if (connectionString === undefined || connectionString === null || connectionString.trim().length === 0) {
|
|
82
|
+
return connectionString ?? '';
|
|
83
|
+
}
|
|
84
|
+
let settings;
|
|
85
|
+
try {
|
|
86
|
+
settings = enumerateSettings(connectionString);
|
|
87
|
+
}
|
|
88
|
+
catch {
|
|
89
|
+
// A string that cannot be parsed cannot be masked reliably, and printing it might disclose the
|
|
90
|
+
// secret it failed to parse. Report nothing rather than guess.
|
|
91
|
+
return REDACTED;
|
|
92
|
+
}
|
|
93
|
+
let out = '';
|
|
94
|
+
let copied = 0;
|
|
95
|
+
for (const setting of settings) {
|
|
96
|
+
if (!SECRET_KEYS.has(setting.key.toLowerCase()))
|
|
97
|
+
continue;
|
|
98
|
+
// The value's text is replaced in place, keeping any quotes around it, so the shape of the
|
|
99
|
+
// string does not change.
|
|
100
|
+
out += connectionString.slice(copied, setting.valueStart) + REDACTED;
|
|
101
|
+
copied = setting.valueStart + setting.valueLength;
|
|
102
|
+
}
|
|
103
|
+
return out + connectionString.slice(copied);
|
|
104
|
+
}
|
|
105
|
+
function enumerateSettings(source) {
|
|
106
|
+
const settings = [];
|
|
107
|
+
let position = 0;
|
|
108
|
+
while (position < source.length) {
|
|
109
|
+
// The key runs to the next '=' or ';'.
|
|
110
|
+
const keyStart = position;
|
|
111
|
+
while (position < source.length && source[position] !== '=' && source[position] !== ';') {
|
|
112
|
+
position++;
|
|
113
|
+
}
|
|
114
|
+
if (position >= source.length || source[position] === ';') {
|
|
115
|
+
// A segment with no '=' carries nothing to set. Skip it and take the next one.
|
|
116
|
+
position++;
|
|
117
|
+
continue;
|
|
118
|
+
}
|
|
119
|
+
const key = source.slice(keyStart, position).trim();
|
|
120
|
+
position++; // past the '='
|
|
121
|
+
while (position < source.length && (source[position] === ' ' || source[position] === '\t')) {
|
|
122
|
+
position++;
|
|
123
|
+
}
|
|
124
|
+
let valueStart;
|
|
125
|
+
let valueLength;
|
|
126
|
+
let value;
|
|
127
|
+
const quote = source[position];
|
|
128
|
+
if (quote === "'" || quote === '"') {
|
|
129
|
+
position++;
|
|
130
|
+
valueStart = position;
|
|
131
|
+
for (;;) {
|
|
132
|
+
if (position >= source.length) {
|
|
133
|
+
throw new CamusError(CamusErrorCode.Generic, `The connection string has an unclosed ${quote} quoted value. Double the quote character ` +
|
|
134
|
+
'to include one in a value.');
|
|
135
|
+
}
|
|
136
|
+
if (source[position] === quote) {
|
|
137
|
+
// A doubled quote is one literal quote, not the end of the value.
|
|
138
|
+
if (source[position + 1] === quote) {
|
|
139
|
+
position += 2;
|
|
140
|
+
continue;
|
|
141
|
+
}
|
|
142
|
+
break;
|
|
143
|
+
}
|
|
144
|
+
position++;
|
|
145
|
+
}
|
|
146
|
+
valueLength = position - valueStart;
|
|
147
|
+
value = source.slice(valueStart, position).replaceAll(quote + quote, quote);
|
|
148
|
+
position++; // past the closing quote
|
|
149
|
+
// Anything between the closing quote and the ';' is whitespace or a typo. Skip to the ';'.
|
|
150
|
+
while (position < source.length && source[position] !== ';')
|
|
151
|
+
position++;
|
|
152
|
+
}
|
|
153
|
+
else {
|
|
154
|
+
const rawStart = position;
|
|
155
|
+
while (position < source.length && source[position] !== ';')
|
|
156
|
+
position++;
|
|
157
|
+
const raw = source.slice(rawStart, position);
|
|
158
|
+
const leading = raw.length - raw.trimStart().length;
|
|
159
|
+
value = raw.trim();
|
|
160
|
+
valueStart = rawStart + leading;
|
|
161
|
+
valueLength = value.length;
|
|
162
|
+
}
|
|
163
|
+
position++; // past the ';'
|
|
164
|
+
if (key.length > 0) {
|
|
165
|
+
settings.push({ key, value, valueStart, valueLength });
|
|
166
|
+
}
|
|
167
|
+
}
|
|
168
|
+
return settings;
|
|
169
|
+
}
|
|
170
|
+
//# sourceMappingURL=connection-string.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"connection-string.js","sourceRoot":"","sources":["../src/connection-string.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1,70 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* This file is part of CamusDB
|
|
3
|
+
*
|
|
4
|
+
* For the full copyright and license information, please view the LICENSE.txt
|
|
5
|
+
* file that was distributed with this source code.
|
|
6
|
+
*/
|
|
7
|
+
/**
|
|
8
|
+
* The endpoints one deployment's clients rotate through, and which of them are set aside after
|
|
9
|
+
* failing to answer at all.
|
|
10
|
+
*
|
|
11
|
+
* A pool is shared per endpoint list rather than owned by one client. The rotation and the health
|
|
12
|
+
* it depends on are properties of the deployment; a per-client pool would restart its rotation at
|
|
13
|
+
* the first endpoint on every request.
|
|
14
|
+
*
|
|
15
|
+
* Quarantine expires. A pool that outlives the request that marked an endpoint cannot mark it
|
|
16
|
+
* forever: with a single endpoint configured — the common case — the first refused connection
|
|
17
|
+
* would otherwise end the process's ability to reach the database at all, long after the node came
|
|
18
|
+
* back. An endpoint is set aside for `QUARANTINE_PERIOD_MS` and then drawn again; a node that is
|
|
19
|
+
* still down is simply marked again by the request that draws it, at a cost of one failed request
|
|
20
|
+
* per period.
|
|
21
|
+
*/
|
|
22
|
+
export declare class CamusEndpointPool {
|
|
23
|
+
/** How long an endpoint that failed at the transport level is passed over. */
|
|
24
|
+
static readonly QUARANTINE_PERIOD_MS = 30000;
|
|
25
|
+
private static readonly shared;
|
|
26
|
+
/**
|
|
27
|
+
* The process-wide pool for an endpoint list, built on first use. Keyed by the list alone, so
|
|
28
|
+
* clients that differ only in database, credentials, or timeout share one rotation and one view
|
|
29
|
+
* of which nodes are answering.
|
|
30
|
+
*/
|
|
31
|
+
static forEndpoints(endpointList: string): CamusEndpointPool;
|
|
32
|
+
/** @internal Test hook: drops every shared pool. */
|
|
33
|
+
static resetShared(): void;
|
|
34
|
+
private readonly endpoints;
|
|
35
|
+
/**
|
|
36
|
+
* Monotonic-clock deadlines, indexed alongside `endpoints`. Zero — the initial value — is in the
|
|
37
|
+
* past, so an endpoint that has never failed needs no special case.
|
|
38
|
+
*/
|
|
39
|
+
private readonly quarantinedUntil;
|
|
40
|
+
private nextIndex;
|
|
41
|
+
/** @internal Test hook: the monotonic clock this pool reads. */
|
|
42
|
+
clock: () => number;
|
|
43
|
+
constructor(endpointList: string);
|
|
44
|
+
/** Every configured endpoint, in the order it was written. */
|
|
45
|
+
get members(): readonly string[];
|
|
46
|
+
/**
|
|
47
|
+
* The next endpoint to send to, skipping those in quarantine.
|
|
48
|
+
*
|
|
49
|
+
* When every endpoint is quarantined the one closest to leaving is returned rather than an
|
|
50
|
+
* error. The deployment is evidently down, and letting the request go and fail against the real
|
|
51
|
+
* node reports why, where a synthetic "no endpoints" would replace the server's diagnosis with
|
|
52
|
+
* the driver's bookkeeping.
|
|
53
|
+
*/
|
|
54
|
+
next(): string;
|
|
55
|
+
/**
|
|
56
|
+
* Whether an endpoint is currently set aside. Learned routing reads it before preferring an
|
|
57
|
+
* endpoint, so a route pointing at a node that stopped answering falls back to rotation. An
|
|
58
|
+
* address the pool does not know reports as not quarantined.
|
|
59
|
+
*/
|
|
60
|
+
isQuarantined(endpoint: string): boolean;
|
|
61
|
+
/**
|
|
62
|
+
* Whether an address is one of the configured endpoints. The routing trust map uses it to refuse
|
|
63
|
+
* mapping a node identity to any address the operator did not list.
|
|
64
|
+
*/
|
|
65
|
+
contains(endpoint: string): boolean;
|
|
66
|
+
/** Sets an endpoint aside, so the endpoints that are answering carry the traffic meanwhile. */
|
|
67
|
+
markUnreachable(endpoint: string): void;
|
|
68
|
+
private indexOf;
|
|
69
|
+
}
|
|
70
|
+
//# sourceMappingURL=endpoint-pool.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"endpoint-pool.d.ts","sourceRoot":"","sources":["../src/endpoint-pool.ts"],"names":[],"mappings":"AAAA;;;;;GAKG;AAMH;;;;;;;;;;;;;;GAcG;AACH,qBAAa,iBAAiB;IAC5B,8EAA8E;IAC9E,MAAM,CAAC,QAAQ,CAAC,oBAAoB,SAAU;IAE9C,OAAO,CAAC,MAAM,CAAC,QAAQ,CAAC,MAAM,CAA2C;IAEzE;;;;OAIG;IACH,MAAM,CAAC,YAAY,CAAC,YAAY,EAAE,MAAM,GAAG,iBAAiB;IAI5D,oDAAoD;IACpD,MAAM,CAAC,WAAW,IAAI,IAAI;IAI1B,OAAO,CAAC,QAAQ,CAAC,SAAS,CAAW;IAErC;;;OAGG;IACH,OAAO,CAAC,QAAQ,CAAC,gBAAgB,CAAW;IAE5C,OAAO,CAAC,SAAS,CAAK;IAEtB,gEAAgE;IAChE,KAAK,EAAE,MAAM,MAAM,CAA2B;gBAElC,YAAY,EAAE,MAAM;IAahC,8DAA8D;IAC9D,IAAI,OAAO,IAAI,SAAS,MAAM,EAAE,CAE/B;IAED;;;;;;;OAOG;IACH,IAAI,IAAI,MAAM;IAkBd;;;;OAIG;IACH,aAAa,CAAC,QAAQ,EAAE,MAAM,GAAG,OAAO;IAOxC;;;OAGG;IACH,QAAQ,CAAC,QAAQ,EAAE,MAAM,GAAG,OAAO;IAInC,+FAA+F;IAC/F,eAAe,CAAC,QAAQ,EAAE,MAAM,GAAG,IAAI;IAOvC,OAAO,CAAC,OAAO;CAShB"}
|