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.
Files changed (220) hide show
  1. package/LICENSE +21 -0
  2. package/README.md +950 -0
  3. package/dist/auth/credentials.d.ts +30 -0
  4. package/dist/auth/credentials.d.ts.map +1 -0
  5. package/dist/auth/credentials.js +23 -0
  6. package/dist/auth/credentials.js.map +1 -0
  7. package/dist/auth/login-client.d.ts +37 -0
  8. package/dist/auth/login-client.d.ts.map +1 -0
  9. package/dist/auth/login-client.js +8 -0
  10. package/dist/auth/login-client.js.map +1 -0
  11. package/dist/auth/rest-login-client.d.ts +17 -0
  12. package/dist/auth/rest-login-client.d.ts.map +1 -0
  13. package/dist/auth/rest-login-client.js +71 -0
  14. package/dist/auth/rest-login-client.js.map +1 -0
  15. package/dist/auth/token-provider.d.ts +123 -0
  16. package/dist/auth/token-provider.d.ts.map +1 -0
  17. package/dist/auth/token-provider.js +209 -0
  18. package/dist/auth/token-provider.js.map +1 -0
  19. package/dist/backup.d.ts +98 -0
  20. package/dist/backup.d.ts.map +1 -0
  21. package/dist/backup.js +153 -0
  22. package/dist/backup.js.map +1 -0
  23. package/dist/cache.d.ts +90 -0
  24. package/dist/cache.d.ts.map +1 -0
  25. package/dist/cache.js +121 -0
  26. package/dist/cache.js.map +1 -0
  27. package/dist/client.d.ts +406 -0
  28. package/dist/client.d.ts.map +1 -0
  29. package/dist/client.js +724 -0
  30. package/dist/client.js.map +1 -0
  31. package/dist/column-type.d.ts +33 -0
  32. package/dist/column-type.d.ts.map +1 -0
  33. package/dist/column-type.js +50 -0
  34. package/dist/column-type.js.map +1 -0
  35. package/dist/column-value.d.ts +77 -0
  36. package/dist/column-value.d.ts.map +1 -0
  37. package/dist/column-value.js +60 -0
  38. package/dist/column-value.js.map +1 -0
  39. package/dist/config.d.ts +181 -0
  40. package/dist/config.d.ts.map +1 -0
  41. package/dist/config.js +315 -0
  42. package/dist/config.js.map +1 -0
  43. package/dist/connection-string.d.ts +45 -0
  44. package/dist/connection-string.d.ts.map +1 -0
  45. package/dist/connection-string.js +170 -0
  46. package/dist/connection-string.js.map +1 -0
  47. package/dist/endpoint-pool.d.ts +70 -0
  48. package/dist/endpoint-pool.d.ts.map +1 -0
  49. package/dist/endpoint-pool.js +120 -0
  50. package/dist/endpoint-pool.js.map +1 -0
  51. package/dist/error-codes.d.ts +44 -0
  52. package/dist/error-codes.d.ts.map +1 -0
  53. package/dist/error-codes.js +43 -0
  54. package/dist/error-codes.js.map +1 -0
  55. package/dist/errors.d.ts +24 -0
  56. package/dist/errors.d.ts.map +1 -0
  57. package/dist/errors.js +33 -0
  58. package/dist/errors.js.map +1 -0
  59. package/dist/hlc.d.ts +19 -0
  60. package/dist/hlc.d.ts.map +1 -0
  61. package/dist/hlc.js +11 -0
  62. package/dist/hlc.js.map +1 -0
  63. package/dist/index.d.ts +55 -0
  64. package/dist/index.d.ts.map +1 -0
  65. package/dist/index.js +51 -0
  66. package/dist/index.js.map +1 -0
  67. package/dist/json.d.ts +41 -0
  68. package/dist/json.d.ts.map +1 -0
  69. package/dist/json.js +345 -0
  70. package/dist/json.js.map +1 -0
  71. package/dist/object-id.d.ts +39 -0
  72. package/dist/object-id.d.ts.map +1 -0
  73. package/dist/object-id.js +99 -0
  74. package/dist/object-id.js.map +1 -0
  75. package/dist/options.d.ts +77 -0
  76. package/dist/options.d.ts.map +1 -0
  77. package/dist/options.js +68 -0
  78. package/dist/options.js.map +1 -0
  79. package/dist/prepared/binder.d.ts +20 -0
  80. package/dist/prepared/binder.d.ts.map +1 -0
  81. package/dist/prepared/binder.js +32 -0
  82. package/dist/prepared/binder.js.map +1 -0
  83. package/dist/prepared/policy.d.ts +81 -0
  84. package/dist/prepared/policy.d.ts.map +1 -0
  85. package/dist/prepared/policy.js +164 -0
  86. package/dist/prepared/policy.js.map +1 -0
  87. package/dist/query-stream.d.ts +55 -0
  88. package/dist/query-stream.d.ts.map +1 -0
  89. package/dist/query-stream.js +94 -0
  90. package/dist/query-stream.js.map +1 -0
  91. package/dist/result-set.d.ts +62 -0
  92. package/dist/result-set.d.ts.map +1 -0
  93. package/dist/result-set.js +100 -0
  94. package/dist/result-set.js.map +1 -0
  95. package/dist/retry.d.ts +38 -0
  96. package/dist/retry.d.ts.map +1 -0
  97. package/dist/retry.js +93 -0
  98. package/dist/retry.js.map +1 -0
  99. package/dist/routing/advice.d.ts +63 -0
  100. package/dist/routing/advice.d.ts.map +1 -0
  101. package/dist/routing/advice.js +61 -0
  102. package/dist/routing/advice.js.map +1 -0
  103. package/dist/routing/route-cache.d.ts +53 -0
  104. package/dist/routing/route-cache.d.ts.map +1 -0
  105. package/dist/routing/route-cache.js +123 -0
  106. package/dist/routing/route-cache.js.map +1 -0
  107. package/dist/routing/router.d.ts +53 -0
  108. package/dist/routing/router.d.ts.map +1 -0
  109. package/dist/routing/router.js +89 -0
  110. package/dist/routing/router.js.map +1 -0
  111. package/dist/row-source.d.ts +48 -0
  112. package/dist/row-source.d.ts.map +1 -0
  113. package/dist/row-source.js +35 -0
  114. package/dist/row-source.js.map +1 -0
  115. package/dist/runtime.d.ts +58 -0
  116. package/dist/runtime.d.ts.map +1 -0
  117. package/dist/runtime.js +137 -0
  118. package/dist/runtime.js.map +1 -0
  119. package/dist/shared-registry.d.ts +32 -0
  120. package/dist/shared-registry.d.ts.map +1 -0
  121. package/dist/shared-registry.js +48 -0
  122. package/dist/shared-registry.js.map +1 -0
  123. package/dist/sql-syntax.d.ts +44 -0
  124. package/dist/sql-syntax.d.ts.map +1 -0
  125. package/dist/sql-syntax.js +83 -0
  126. package/dist/sql-syntax.js.map +1 -0
  127. package/dist/statements.d.ts +15 -0
  128. package/dist/statements.d.ts.map +1 -0
  129. package/dist/statements.js +90 -0
  130. package/dist/statements.js.map +1 -0
  131. package/dist/transaction.d.ts +117 -0
  132. package/dist/transaction.d.ts.map +1 -0
  133. package/dist/transaction.js +204 -0
  134. package/dist/transaction.js.map +1 -0
  135. package/dist/transport/authenticating-transport.d.ts +63 -0
  136. package/dist/transport/authenticating-transport.d.ts.map +1 -0
  137. package/dist/transport/authenticating-transport.js +119 -0
  138. package/dist/transport/authenticating-transport.js.map +1 -0
  139. package/dist/transport/branch-statements.d.ts +39 -0
  140. package/dist/transport/branch-statements.d.ts.map +1 -0
  141. package/dist/transport/branch-statements.js +74 -0
  142. package/dist/transport/branch-statements.js.map +1 -0
  143. package/dist/transport/error-text.d.ts +26 -0
  144. package/dist/transport/error-text.d.ts.map +1 -0
  145. package/dist/transport/error-text.js +75 -0
  146. package/dist/transport/error-text.js.map +1 -0
  147. package/dist/transport/grpc/batcher.d.ts +127 -0
  148. package/dist/transport/grpc/batcher.d.ts.map +1 -0
  149. package/dist/transport/grpc/batcher.js +399 -0
  150. package/dist/transport/grpc/batcher.js.map +1 -0
  151. package/dist/transport/grpc/codec.d.ts +40 -0
  152. package/dist/transport/grpc/codec.d.ts.map +1 -0
  153. package/dist/transport/grpc/codec.js +231 -0
  154. package/dist/transport/grpc/codec.js.map +1 -0
  155. package/dist/transport/grpc/grpc-transport.d.ts +115 -0
  156. package/dist/transport/grpc/grpc-transport.d.ts.map +1 -0
  157. package/dist/transport/grpc/grpc-transport.js +577 -0
  158. package/dist/transport/grpc/grpc-transport.js.map +1 -0
  159. package/dist/transport/grpc/messages.d.ts +221 -0
  160. package/dist/transport/grpc/messages.d.ts.map +1 -0
  161. package/dist/transport/grpc/messages.js +56 -0
  162. package/dist/transport/grpc/messages.js.map +1 -0
  163. package/dist/transport/grpc/proto.d.ts +71 -0
  164. package/dist/transport/grpc/proto.d.ts.map +1 -0
  165. package/dist/transport/grpc/proto.js +67 -0
  166. package/dist/transport/grpc/proto.js.map +1 -0
  167. package/dist/transport/http.d.ts +62 -0
  168. package/dist/transport/http.d.ts.map +1 -0
  169. package/dist/transport/http.js +169 -0
  170. package/dist/transport/http.js.map +1 -0
  171. package/dist/transport/ndjson-row-source.d.ts +38 -0
  172. package/dist/transport/ndjson-row-source.d.ts.map +1 -0
  173. package/dist/transport/ndjson-row-source.js +197 -0
  174. package/dist/transport/ndjson-row-source.js.map +1 -0
  175. package/dist/transport/rest-decode.d.ts +33 -0
  176. package/dist/transport/rest-decode.d.ts.map +1 -0
  177. package/dist/transport/rest-decode.js +162 -0
  178. package/dist/transport/rest-decode.js.map +1 -0
  179. package/dist/transport/rest-prepared-cache.d.ts +50 -0
  180. package/dist/transport/rest-prepared-cache.d.ts.map +1 -0
  181. package/dist/transport/rest-prepared-cache.js +101 -0
  182. package/dist/transport/rest-prepared-cache.js.map +1 -0
  183. package/dist/transport/rest-transport.d.ts +88 -0
  184. package/dist/transport/rest-transport.d.ts.map +1 -0
  185. package/dist/transport/rest-transport.js +388 -0
  186. package/dist/transport/rest-transport.js.map +1 -0
  187. package/dist/transport/transport-pool.d.ts +40 -0
  188. package/dist/transport/transport-pool.d.ts.map +1 -0
  189. package/dist/transport/transport-pool.js +48 -0
  190. package/dist/transport/transport-pool.js.map +1 -0
  191. package/dist/transport/transport.d.ts +199 -0
  192. package/dist/transport/transport.d.ts.map +1 -0
  193. package/dist/transport/transport.js +11 -0
  194. package/dist/transport/transport.js.map +1 -0
  195. package/dist/values/decode.d.ts +39 -0
  196. package/dist/values/decode.d.ts.map +1 -0
  197. package/dist/values/decode.js +75 -0
  198. package/dist/values/decode.js.map +1 -0
  199. package/dist/values/encode.d.ts +45 -0
  200. package/dist/values/encode.d.ts.map +1 -0
  201. package/dist/values/encode.js +271 -0
  202. package/dist/values/encode.js.map +1 -0
  203. package/dist/values/ticks.d.ts +31 -0
  204. package/dist/values/ticks.d.ts.map +1 -0
  205. package/dist/values/ticks.js +52 -0
  206. package/dist/values/ticks.js.map +1 -0
  207. package/dist/values/typed.d.ts +67 -0
  208. package/dist/values/typed.d.ts.map +1 -0
  209. package/dist/values/typed.js +134 -0
  210. package/dist/values/typed.js.map +1 -0
  211. package/dist/values/uuid.d.ts +27 -0
  212. package/dist/values/uuid.d.ts.map +1 -0
  213. package/dist/values/uuid.js +76 -0
  214. package/dist/values/uuid.js.map +1 -0
  215. package/dist/vector.d.ts +26 -0
  216. package/dist/vector.d.ts.map +1 -0
  217. package/dist/vector.js +48 -0
  218. package/dist/vector.js.map +1 -0
  219. package/package.json +86 -0
  220. package/proto/camus_sql.proto +566 -0
@@ -0,0 +1,30 @@
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
+ * What the driver was given to authenticate with.
9
+ *
10
+ * Either a user and password pair, which the driver exchanges for a short-lived bearer token and
11
+ * re-exchanges when the token expires, or a token the caller obtained elsewhere and hands over as
12
+ * written. A value with neither is `NO_CREDENTIALS`: the driver sends no `Authorization` header at
13
+ * all, which is correct against a server with authentication off — the default.
14
+ */
15
+ export interface CamusCredentials {
16
+ /** The user to authenticate as, or undefined when a token was supplied directly. */
17
+ readonly user?: string | undefined;
18
+ /** The user's password. It is only ever sent to `/login`, never with an ordinary statement. */
19
+ readonly password?: string | undefined;
20
+ /** A token obtained elsewhere, used as written. It excludes `user`. */
21
+ readonly accessToken?: string | undefined;
22
+ }
23
+ export declare const NO_CREDENTIALS: CamusCredentials;
24
+ export declare function credentialsFromPassword(user: string, password: string): CamusCredentials;
25
+ export declare function credentialsFromToken(accessToken: string): CamusCredentials;
26
+ /** True when there is anything to authenticate with. */
27
+ export declare function hasCredentials(credentials: CamusCredentials): boolean;
28
+ /** True when the driver can mint a fresh token on its own, because it holds the password. */
29
+ export declare function canRenew(credentials: CamusCredentials): boolean;
30
+ //# sourceMappingURL=credentials.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"credentials.d.ts","sourceRoot":"","sources":["../../src/auth/credentials.ts"],"names":[],"mappings":"AAAA;;;;;GAKG;AAEH;;;;;;;GAOG;AACH,MAAM,WAAW,gBAAgB;IAC/B,oFAAoF;IACpF,QAAQ,CAAC,IAAI,CAAC,EAAE,MAAM,GAAG,SAAS,CAAC;IAEnC,+FAA+F;IAC/F,QAAQ,CAAC,QAAQ,CAAC,EAAE,MAAM,GAAG,SAAS,CAAC;IAEvC,uEAAuE;IACvE,QAAQ,CAAC,WAAW,CAAC,EAAE,MAAM,GAAG,SAAS,CAAC;CAC3C;AAED,eAAO,MAAM,cAAc,EAAE,gBAAoC,CAAC;AAElE,wBAAgB,uBAAuB,CAAC,IAAI,EAAE,MAAM,EAAE,QAAQ,EAAE,MAAM,GAAG,gBAAgB,CAExF;AAED,wBAAgB,oBAAoB,CAAC,WAAW,EAAE,MAAM,GAAG,gBAAgB,CAE1E;AAED,wDAAwD;AACxD,wBAAgB,cAAc,CAAC,WAAW,EAAE,gBAAgB,GAAG,OAAO,CAKrE;AAED,6FAA6F;AAC7F,wBAAgB,QAAQ,CAAC,WAAW,EAAE,gBAAgB,GAAG,OAAO,CAE/D"}
@@ -0,0 +1,23 @@
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
+ export const NO_CREDENTIALS = Object.freeze({});
8
+ export function credentialsFromPassword(user, password) {
9
+ return { user, password };
10
+ }
11
+ export function credentialsFromToken(accessToken) {
12
+ return { accessToken };
13
+ }
14
+ /** True when there is anything to authenticate with. */
15
+ export function hasCredentials(credentials) {
16
+ return ((credentials.user !== undefined && credentials.user.length > 0) ||
17
+ (credentials.accessToken !== undefined && credentials.accessToken.length > 0));
18
+ }
19
+ /** True when the driver can mint a fresh token on its own, because it holds the password. */
20
+ export function canRenew(credentials) {
21
+ return credentials.user !== undefined && credentials.user.length > 0 && credentials.password !== undefined;
22
+ }
23
+ //# sourceMappingURL=credentials.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"credentials.js","sourceRoot":"","sources":["../../src/auth/credentials.ts"],"names":[],"mappings":"AAAA;;;;;GAKG;AAqBH,MAAM,CAAC,MAAM,cAAc,GAAqB,MAAM,CAAC,MAAM,CAAC,EAAE,CAAC,CAAC;AAElE,MAAM,UAAU,uBAAuB,CAAC,IAAY,EAAE,QAAgB;IACpE,OAAO,EAAE,IAAI,EAAE,QAAQ,EAAE,CAAC;AAC5B,CAAC;AAED,MAAM,UAAU,oBAAoB,CAAC,WAAmB;IACtD,OAAO,EAAE,WAAW,EAAE,CAAC;AACzB,CAAC;AAED,wDAAwD;AACxD,MAAM,UAAU,cAAc,CAAC,WAA6B;IAC1D,OAAO,CACL,CAAC,WAAW,CAAC,IAAI,KAAK,SAAS,IAAI,WAAW,CAAC,IAAI,CAAC,MAAM,GAAG,CAAC,CAAC;QAC/D,CAAC,WAAW,CAAC,WAAW,KAAK,SAAS,IAAI,WAAW,CAAC,WAAW,CAAC,MAAM,GAAG,CAAC,CAAC,CAC9E,CAAC;AACJ,CAAC;AAED,6FAA6F;AAC7F,MAAM,UAAU,QAAQ,CAAC,WAA6B;IACpD,OAAO,WAAW,CAAC,IAAI,KAAK,SAAS,IAAI,WAAW,CAAC,IAAI,CAAC,MAAM,GAAG,CAAC,IAAI,WAAW,CAAC,QAAQ,KAAK,SAAS,CAAC;AAC7G,CAAC"}
@@ -0,0 +1,37 @@
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
+ * A minted bearer token and, when the server reported one, how long it is good for.
9
+ *
10
+ * `expiresInMs` is a duration rather than an instant on purpose: the server measures it when it
11
+ * issues the reply, so a client whose clock disagrees with the server's still renews on time. It
12
+ * is `undefined` against a server that predates the field, in which case the driver falls back to
13
+ * its configured token lifetime.
14
+ */
15
+ export interface CamusLoginResult {
16
+ readonly token: string;
17
+ readonly expiresInMs?: number | undefined;
18
+ }
19
+ /**
20
+ * The credential-exchange half of the protocol.
21
+ *
22
+ * It is kept apart from the statement transport because it is the one exchange reachable without a
23
+ * token: REST serves it at `/login`, gRPC on the dedicated `CamusAuth` service, and each transport
24
+ * implements it against its own endpoint. Keeping it a separate interface makes that
25
+ * unauthenticated surface explicit, and lets the token provider be tested without a server.
26
+ */
27
+ export interface CamusLoginClient {
28
+ /**
29
+ * Exchanges a password for a short-lived bearer token.
30
+ *
31
+ * @throws {CamusError} `CADB0516` when the credentials are rejected.
32
+ */
33
+ login(endpoint: string, user: string, password: string, timeoutSeconds: number, signal?: AbortSignal): Promise<CamusLoginResult>;
34
+ /** Revokes a token on the server. */
35
+ logout(endpoint: string, token: string, timeoutSeconds: number, signal?: AbortSignal): Promise<void>;
36
+ }
37
+ //# sourceMappingURL=login-client.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"login-client.d.ts","sourceRoot":"","sources":["../../src/auth/login-client.ts"],"names":[],"mappings":"AAAA;;;;;GAKG;AAEH;;;;;;;GAOG;AACH,MAAM,WAAW,gBAAgB;IAC/B,QAAQ,CAAC,KAAK,EAAE,MAAM,CAAC;IACvB,QAAQ,CAAC,WAAW,CAAC,EAAE,MAAM,GAAG,SAAS,CAAC;CAC3C;AAED;;;;;;;GAOG;AACH,MAAM,WAAW,gBAAgB;IAC/B;;;;OAIG;IACH,KAAK,CACH,QAAQ,EAAE,MAAM,EAChB,IAAI,EAAE,MAAM,EACZ,QAAQ,EAAE,MAAM,EAChB,cAAc,EAAE,MAAM,EACtB,MAAM,CAAC,EAAE,WAAW,GACnB,OAAO,CAAC,gBAAgB,CAAC,CAAC;IAE7B,qCAAqC;IACrC,MAAM,CAAC,QAAQ,EAAE,MAAM,EAAE,KAAK,EAAE,MAAM,EAAE,cAAc,EAAE,MAAM,EAAE,MAAM,CAAC,EAAE,WAAW,GAAG,OAAO,CAAC,IAAI,CAAC,CAAC;CACtG"}
@@ -0,0 +1,8 @@
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
+ export {};
8
+ //# sourceMappingURL=login-client.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"login-client.js","sourceRoot":"","sources":["../../src/auth/login-client.ts"],"names":[],"mappings":"AAAA;;;;;GAKG"}
@@ -0,0 +1,17 @@
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 type { CamusLoginClient, CamusLoginResult } from './login-client.js';
8
+ /**
9
+ * The login client over the server's HTTP `/login` and `/logout` routes — the only routes exempt
10
+ * from the server's own authentication middleware, and the only place a password is ever put on
11
+ * the wire.
12
+ */
13
+ export declare class RestLoginClient implements CamusLoginClient {
14
+ login(endpoint: string, user: string, password: string, timeoutSeconds: number, signal?: AbortSignal): Promise<CamusLoginResult>;
15
+ logout(endpoint: string, token: string, timeoutSeconds: number, signal?: AbortSignal): Promise<void>;
16
+ }
17
+ //# sourceMappingURL=rest-login-client.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"rest-login-client.d.ts","sourceRoot":"","sources":["../../src/auth/rest-login-client.ts"],"names":[],"mappings":"AAAA;;;;;GAKG;AAMH,OAAO,KAAK,EAAE,gBAAgB,EAAE,gBAAgB,EAAE,MAAM,mBAAmB,CAAC;AAW5E;;;;GAIG;AACH,qBAAa,eAAgB,YAAW,gBAAgB;IAChD,KAAK,CACT,QAAQ,EAAE,MAAM,EAChB,IAAI,EAAE,MAAM,EACZ,QAAQ,EAAE,MAAM,EAChB,cAAc,EAAE,MAAM,EACtB,MAAM,CAAC,EAAE,WAAW,GACnB,OAAO,CAAC,gBAAgB,CAAC;IA0BtB,MAAM,CAAC,QAAQ,EAAE,MAAM,EAAE,KAAK,EAAE,MAAM,EAAE,cAAc,EAAE,MAAM,EAAE,MAAM,CAAC,EAAE,WAAW,GAAG,OAAO,CAAC,IAAI,CAAC;CAgB3G"}
@@ -0,0 +1,71 @@
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
+ import { asNumber, parseLossless } from '../json.js';
10
+ import { readBody, sendHttp, translateErrorBody } from '../transport/http.js';
11
+ /**
12
+ * The login client over the server's HTTP `/login` and `/logout` routes — the only routes exempt
13
+ * from the server's own authentication middleware, and the only place a password is ever put on
14
+ * the wire.
15
+ */
16
+ export class RestLoginClient {
17
+ async login(endpoint, user, password, timeoutSeconds, signal) {
18
+ const { response } = await sendHttp(undefined, {
19
+ endpoint,
20
+ path: ['login'],
21
+ method: 'POST',
22
+ body: { user, password },
23
+ timeoutSeconds,
24
+ signal,
25
+ });
26
+ const text = await readBody(response);
27
+ if (!response.ok)
28
+ throw translateErrorBody(response.status, text);
29
+ const body = (text.length > 0 ? parseLossless(text) : null);
30
+ if (body === null || body.status !== 'ok' || body.token === undefined || body.token.length === 0) {
31
+ throw new CamusError(body?.code ?? CamusErrorCode.AuthenticationFailed, body?.message ?? 'Authentication failed');
32
+ }
33
+ return { token: body.token, expiresInMs: readExpiryMs(body) };
34
+ }
35
+ async logout(endpoint, token, timeoutSeconds, signal) {
36
+ const { response } = await sendHttp(undefined, {
37
+ endpoint,
38
+ path: ['logout'],
39
+ method: 'POST',
40
+ token,
41
+ timeoutSeconds,
42
+ signal,
43
+ });
44
+ if (!response.ok)
45
+ throw translateErrorBody(response.status, await readBody(response));
46
+ // The body carries nothing this driver reads, but it must be drained so the connection returns
47
+ // to the pool instead of staying half-read.
48
+ await readBody(response);
49
+ }
50
+ }
51
+ /**
52
+ * How long a minted token is good for.
53
+ *
54
+ * The server-measured duration is preferred, because it is immune to clock skew between client and
55
+ * server. The absolute instant is the fallback, and it is not. A server that reports neither leaves
56
+ * the driver on its configured fallback lifetime. A value that is not positive is treated as
57
+ * absent rather than as an already-dead token.
58
+ */
59
+ function readExpiryMs(body) {
60
+ const seconds = asNumber(body.expiresInSeconds, 0);
61
+ if (seconds > 0)
62
+ return seconds * 1000;
63
+ const expiresAt = asNumber(body.expiresAtUnixMs, 0);
64
+ if (expiresAt > 0) {
65
+ const remaining = expiresAt - Date.now();
66
+ if (remaining > 0)
67
+ return remaining;
68
+ }
69
+ return undefined;
70
+ }
71
+ //# sourceMappingURL=rest-login-client.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"rest-login-client.js","sourceRoot":"","sources":["../../src/auth/rest-login-client.ts"],"names":[],"mappings":"AAAA;;;;;GAKG;AAEH,OAAO,EAAE,UAAU,EAAE,MAAM,cAAc,CAAC;AAC1C,OAAO,EAAE,cAAc,EAAE,MAAM,mBAAmB,CAAC;AACnD,OAAO,EAAE,QAAQ,EAAE,aAAa,EAAE,MAAM,YAAY,CAAC;AACrD,OAAO,EAAE,QAAQ,EAAE,QAAQ,EAAE,kBAAkB,EAAE,MAAM,sBAAsB,CAAC;AAY9E;;;;GAIG;AACH,MAAM,OAAO,eAAe;IAC1B,KAAK,CAAC,KAAK,CACT,QAAgB,EAChB,IAAY,EACZ,QAAgB,EAChB,cAAsB,EACtB,MAAoB;QAEpB,MAAM,EAAE,QAAQ,EAAE,GAAG,MAAM,QAAQ,CAAC,SAAS,EAAE;YAC7C,QAAQ;YACR,IAAI,EAAE,CAAC,OAAO,CAAC;YACf,MAAM,EAAE,MAAM;YACd,IAAI,EAAE,EAAE,IAAI,EAAE,QAAQ,EAAE;YACxB,cAAc;YACd,MAAM;SACP,CAAC,CAAC;QAEH,MAAM,IAAI,GAAG,MAAM,QAAQ,CAAC,QAAQ,CAAC,CAAC;QAEtC,IAAI,CAAC,QAAQ,CAAC,EAAE;YAAE,MAAM,kBAAkB,CAAC,QAAQ,CAAC,MAAM,EAAE,IAAI,CAAC,CAAC;QAElE,MAAM,IAAI,GAAG,CAAC,IAAI,CAAC,MAAM,GAAG,CAAC,CAAC,CAAC,CAAC,aAAa,CAAC,IAAI,CAAC,CAAC,CAAC,CAAC,IAAI,CAA6B,CAAC;QAExF,IAAI,IAAI,KAAK,IAAI,IAAI,IAAI,CAAC,MAAM,KAAK,IAAI,IAAI,IAAI,CAAC,KAAK,KAAK,SAAS,IAAI,IAAI,CAAC,KAAK,CAAC,MAAM,KAAK,CAAC,EAAE,CAAC;YACjG,MAAM,IAAI,UAAU,CAClB,IAAI,EAAE,IAAI,IAAI,cAAc,CAAC,oBAAoB,EACjD,IAAI,EAAE,OAAO,IAAI,uBAAuB,CACzC,CAAC;QACJ,CAAC;QAED,OAAO,EAAE,KAAK,EAAE,IAAI,CAAC,KAAK,EAAE,WAAW,EAAE,YAAY,CAAC,IAAI,CAAC,EAAE,CAAC;IAChE,CAAC;IAED,KAAK,CAAC,MAAM,CAAC,QAAgB,EAAE,KAAa,EAAE,cAAsB,EAAE,MAAoB;QACxF,MAAM,EAAE,QAAQ,EAAE,GAAG,MAAM,QAAQ,CAAC,SAAS,EAAE;YAC7C,QAAQ;YACR,IAAI,EAAE,CAAC,QAAQ,CAAC;YAChB,MAAM,EAAE,MAAM;YACd,KAAK;YACL,cAAc;YACd,MAAM;SACP,CAAC,CAAC;QAEH,IAAI,CAAC,QAAQ,CAAC,EAAE;YAAE,MAAM,kBAAkB,CAAC,QAAQ,CAAC,MAAM,EAAE,MAAM,QAAQ,CAAC,QAAQ,CAAC,CAAC,CAAC;QAEtF,+FAA+F;QAC/F,4CAA4C;QAC5C,MAAM,QAAQ,CAAC,QAAQ,CAAC,CAAC;IAC3B,CAAC;CACF;AAED;;;;;;;GAOG;AACH,SAAS,YAAY,CAAC,IAAuB;IAC3C,MAAM,OAAO,GAAG,QAAQ,CAAC,IAAI,CAAC,gBAAgB,EAAE,CAAC,CAAC,CAAC;IAEnD,IAAI,OAAO,GAAG,CAAC;QAAE,OAAO,OAAO,GAAG,IAAI,CAAC;IAEvC,MAAM,SAAS,GAAG,QAAQ,CAAC,IAAI,CAAC,eAAe,EAAE,CAAC,CAAC,CAAC;IAEpD,IAAI,SAAS,GAAG,CAAC,EAAE,CAAC;QAClB,MAAM,SAAS,GAAG,SAAS,GAAG,IAAI,CAAC,GAAG,EAAE,CAAC;QACzC,IAAI,SAAS,GAAG,CAAC;YAAE,OAAO,SAAS,CAAC;IACtC,CAAC;IAED,OAAO,SAAS,CAAC;AACnB,CAAC"}
@@ -0,0 +1,123 @@
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 type { CamusCredentials } from './credentials.js';
8
+ import type { CamusLoginClient } from './login-client.js';
9
+ /** The fallback token lifetime, comfortably inside the server's 15-minute default. */
10
+ export declare const DEFAULT_TOKEN_LIFETIME_MS = 600000;
11
+ /**
12
+ * Owns a client's bearer token: mints it from the configured credentials on first use, hands the
13
+ * same token to every request until it goes stale, and mints a new one when it does.
14
+ *
15
+ * One provider is shared by every client that presents the same identity to the same deployment,
16
+ * so a pool of clients performs one login rather than one each. Password verification is
17
+ * deliberately expensive on the server — PBKDF2 with 600,000 iterations by default — and rate
18
+ * limited per account, so a login stampede is exactly what must be avoided.
19
+ *
20
+ * **Single flight.** Concurrent callers that find no usable token await one promise; the winner
21
+ * logs in and the rest observe its result instead of issuing their own login.
22
+ *
23
+ * **Renewal.** The login reply reports how long the token is good for, and the provider renews at
24
+ * 80% of that. Against a server that predates the field it falls back to its own conservative
25
+ * lifetime. That proactive renewal is the primary path. `invalidate`, driven by a `CADB0516` from
26
+ * a real request, is the backstop for what a clock cannot predict: a rotated password, a dropped
27
+ * user, a logout from elsewhere, or a server whose token lifetime is shorter than the fallback.
28
+ *
29
+ * A token supplied directly is used as written and never renewed — the driver has no password to
30
+ * mint a replacement with — so a `CADB0516` on that path reaches the caller rather than a retry.
31
+ */
32
+ export declare class CamusTokenProvider {
33
+ private static readonly shared;
34
+ /**
35
+ * The process-wide provider for an identity, built on first use. Keyed by credentials rather
36
+ * than by the whole configuration, so clients that differ only in database or timeout share one
37
+ * token.
38
+ */
39
+ static forKey(key: string, factory: () => CamusTokenProvider): CamusTokenProvider;
40
+ /** @internal Test hook: drops every shared provider. */
41
+ static resetShared(): void;
42
+ /**
43
+ * A per-process random salt for `sharingKey`.
44
+ *
45
+ * The key lives in a map for the life of the process, and an unsalted hash of a password is an
46
+ * offline verifier for anyone who can read process memory. The key only has to be stable inside
47
+ * one process, so a salt costs nothing.
48
+ */
49
+ private static readonly sharingSalt;
50
+ /**
51
+ * A stable, non-reversible identity for a credential set plus a deployment. It is hashed, and
52
+ * salted per process, so a long-lived map key neither holds a plaintext password nor can be
53
+ * tested against a guessed one outside this process.
54
+ */
55
+ static sharingKey(credentials: CamusCredentials, deploymentKey: string): string;
56
+ private credentials;
57
+ private token;
58
+ private renewAfter;
59
+ private readonly resolveLoginClient;
60
+ private readonly resolveEndpoint;
61
+ private readonly resolveTimeoutSeconds;
62
+ private readonly lifetimeMs;
63
+ /** The single login in flight, if any. Every racing caller awaits this same promise. */
64
+ private inFlight;
65
+ /** @internal Test hook: the wall clock this provider reads. */
66
+ clock: () => number;
67
+ constructor(init: {
68
+ credentials: CamusCredentials;
69
+ resolveLoginClient: () => CamusLoginClient | Promise<CamusLoginClient>;
70
+ resolveEndpoint: () => string;
71
+ resolveTimeoutSeconds: () => number;
72
+ lifetimeMs?: number;
73
+ });
74
+ /**
75
+ * True when this client has anything to authenticate with. When false the driver sends no
76
+ * `Authorization` header, which is what a server with authentication off expects.
77
+ */
78
+ get isEnabled(): boolean;
79
+ /** True when the provider holds a password and can therefore replace a rejected token. */
80
+ get canRenew(): boolean;
81
+ /**
82
+ * The cached token, without triggering a login. The gRPC batch-stream factory reads it, because
83
+ * it builds a stream synchronously; every such call site awaits `getToken` first, so the cache
84
+ * is warm by then.
85
+ */
86
+ get currentToken(): string | undefined;
87
+ /**
88
+ * A usable bearer token, logging in when there is none or the cached one has aged out. Reports
89
+ * `undefined` when no credentials are configured.
90
+ */
91
+ getToken(signal?: AbortSignal): Promise<string | undefined>;
92
+ /**
93
+ * Discards a token so the next `getToken` mints a new one.
94
+ *
95
+ * Comparing against the cached value keeps a late rejection of an already-replaced token from
96
+ * throwing away the good one a concurrent caller just obtained. It does nothing when the token
97
+ * cannot be renewed, so the caller reports the failure instead of looping.
98
+ */
99
+ invalidate(staleToken: string | undefined): void;
100
+ /**
101
+ * Authenticates explicitly, replacing whatever credentials were configured, and reports the
102
+ * minted token. Any cached token is dropped.
103
+ */
104
+ login(user: string, password: string, signal?: AbortSignal): Promise<string>;
105
+ /**
106
+ * Revokes the cached token on the server and forgets it. The configured credentials are kept, so
107
+ * a later statement authenticates again on its own: this ends a session, it does not switch
108
+ * authentication off. It does nothing when no token has been minted.
109
+ */
110
+ logout(signal?: AbortSignal): Promise<void>;
111
+ private tryGetCached;
112
+ private loginOnce;
113
+ /**
114
+ * When to mint the next token.
115
+ *
116
+ * The server's reported lifetime is authoritative — its own setting is configurable and may be
117
+ * shorter than any value the driver defaults to — so the provider renews at 80% of it, leaving
118
+ * headroom for the request that carries the token to finish. Without a reported value it falls
119
+ * back to the configured lifetime, which is already conservative.
120
+ */
121
+ private renewalDelayMs;
122
+ }
123
+ //# sourceMappingURL=token-provider.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"token-provider.d.ts","sourceRoot":"","sources":["../../src/auth/token-provider.ts"],"names":[],"mappings":"AAAA;;;;;GAKG;AAOH,OAAO,KAAK,EAAE,gBAAgB,EAAE,MAAM,kBAAkB,CAAC;AAEzD,OAAO,KAAK,EAAE,gBAAgB,EAAoB,MAAM,mBAAmB,CAAC;AAE5E,sFAAsF;AACtF,eAAO,MAAM,yBAAyB,SAAU,CAAC;AAEjD;;;;;;;;;;;;;;;;;;;;GAoBG;AACH,qBAAa,kBAAkB;IAC7B,OAAO,CAAC,MAAM,CAAC,QAAQ,CAAC,MAAM,CAA4C;IAE1E;;;;OAIG;IACH,MAAM,CAAC,MAAM,CAAC,GAAG,EAAE,MAAM,EAAE,OAAO,EAAE,MAAM,kBAAkB,GAAG,kBAAkB;IAIjF,wDAAwD;IACxD,MAAM,CAAC,WAAW,IAAI,IAAI;IAI1B;;;;;;OAMG;IACH,OAAO,CAAC,MAAM,CAAC,QAAQ,CAAC,WAAW,CAAmB;IAEtD;;;;OAIG;IACH,MAAM,CAAC,UAAU,CAAC,WAAW,EAAE,gBAAgB,EAAE,aAAa,EAAE,MAAM,GAAG,MAAM;IAW/E,OAAO,CAAC,WAAW,CAAmB;IAEtC,OAAO,CAAC,KAAK,CAAqB;IAElC,OAAO,CAAC,UAAU,CAAS;IAE3B,OAAO,CAAC,QAAQ,CAAC,kBAAkB,CAAqD;IAExF,OAAO,CAAC,QAAQ,CAAC,eAAe,CAAe;IAE/C,OAAO,CAAC,QAAQ,CAAC,qBAAqB,CAAe;IAErD,OAAO,CAAC,QAAQ,CAAC,UAAU,CAAS;IAEpC,wFAAwF;IACxF,OAAO,CAAC,QAAQ,CAA8B;IAE9C,+DAA+D;IAC/D,KAAK,EAAE,MAAM,MAAM,CAAoB;gBAE3B,IAAI,EAAE;QAChB,WAAW,EAAE,gBAAgB,CAAC;QAC9B,kBAAkB,EAAE,MAAM,gBAAgB,GAAG,OAAO,CAAC,gBAAgB,CAAC,CAAC;QACvE,eAAe,EAAE,MAAM,MAAM,CAAC;QAC9B,qBAAqB,EAAE,MAAM,MAAM,CAAC;QACpC,UAAU,CAAC,EAAE,MAAM,CAAC;KACrB;IAYD;;;OAGG;IACH,IAAI,SAAS,IAAI,OAAO,CAEvB;IAED,0FAA0F;IAC1F,IAAI,QAAQ,IAAI,OAAO,CAEtB;IAED;;;;OAIG;IACH,IAAI,YAAY,IAAI,MAAM,GAAG,SAAS,CAErC;IAED;;;OAGG;IACG,QAAQ,CAAC,MAAM,CAAC,EAAE,WAAW,GAAG,OAAO,CAAC,MAAM,GAAG,SAAS,CAAC;IAajE;;;;;;OAMG;IACH,UAAU,CAAC,UAAU,EAAE,MAAM,GAAG,SAAS,GAAG,IAAI;IAShD;;;OAGG;IACG,KAAK,CAAC,IAAI,EAAE,MAAM,EAAE,QAAQ,EAAE,MAAM,EAAE,MAAM,CAAC,EAAE,WAAW,GAAG,OAAO,CAAC,MAAM,CAAC;IAalF;;;;OAIG;IACG,MAAM,CAAC,MAAM,CAAC,EAAE,WAAW,GAAG,OAAO,CAAC,IAAI,CAAC;IAYjD,OAAO,CAAC,YAAY;YAON,SAAS;IA6BvB;;;;;;;OAOG;IACH,OAAO,CAAC,cAAc;CAMvB"}
@@ -0,0 +1,209 @@
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 { createHmac, randomBytes } from 'node:crypto';
8
+ import { CamusError } from '../errors.js';
9
+ import { CamusErrorCode } from '../error-codes.js';
10
+ import { SharedRegistry } from '../shared-registry.js';
11
+ import { canRenew, credentialsFromPassword, hasCredentials } from './credentials.js';
12
+ /** The fallback token lifetime, comfortably inside the server's 15-minute default. */
13
+ export const DEFAULT_TOKEN_LIFETIME_MS = 600_000;
14
+ /**
15
+ * Owns a client's bearer token: mints it from the configured credentials on first use, hands the
16
+ * same token to every request until it goes stale, and mints a new one when it does.
17
+ *
18
+ * One provider is shared by every client that presents the same identity to the same deployment,
19
+ * so a pool of clients performs one login rather than one each. Password verification is
20
+ * deliberately expensive on the server — PBKDF2 with 600,000 iterations by default — and rate
21
+ * limited per account, so a login stampede is exactly what must be avoided.
22
+ *
23
+ * **Single flight.** Concurrent callers that find no usable token await one promise; the winner
24
+ * logs in and the rest observe its result instead of issuing their own login.
25
+ *
26
+ * **Renewal.** The login reply reports how long the token is good for, and the provider renews at
27
+ * 80% of that. Against a server that predates the field it falls back to its own conservative
28
+ * lifetime. That proactive renewal is the primary path. `invalidate`, driven by a `CADB0516` from
29
+ * a real request, is the backstop for what a clock cannot predict: a rotated password, a dropped
30
+ * user, a logout from elsewhere, or a server whose token lifetime is shorter than the fallback.
31
+ *
32
+ * A token supplied directly is used as written and never renewed — the driver has no password to
33
+ * mint a replacement with — so a `CADB0516` on that path reaches the caller rather than a retry.
34
+ */
35
+ export class CamusTokenProvider {
36
+ static shared = new SharedRegistry();
37
+ /**
38
+ * The process-wide provider for an identity, built on first use. Keyed by credentials rather
39
+ * than by the whole configuration, so clients that differ only in database or timeout share one
40
+ * token.
41
+ */
42
+ static forKey(key, factory) {
43
+ return CamusTokenProvider.shared.get(key, factory);
44
+ }
45
+ /** @internal Test hook: drops every shared provider. */
46
+ static resetShared() {
47
+ CamusTokenProvider.shared.clear();
48
+ }
49
+ /**
50
+ * A per-process random salt for `sharingKey`.
51
+ *
52
+ * The key lives in a map for the life of the process, and an unsalted hash of a password is an
53
+ * offline verifier for anyone who can read process memory. The key only has to be stable inside
54
+ * one process, so a salt costs nothing.
55
+ */
56
+ static sharingSalt = randomBytes(32);
57
+ /**
58
+ * A stable, non-reversible identity for a credential set plus a deployment. It is hashed, and
59
+ * salted per process, so a long-lived map key neither holds a plaintext password nor can be
60
+ * tested against a guessed one outside this process.
61
+ */
62
+ static sharingKey(credentials, deploymentKey) {
63
+ const material = [
64
+ credentials.user ?? '',
65
+ credentials.password ?? '',
66
+ credentials.accessToken ?? '',
67
+ deploymentKey,
68
+ ].join('\n');
69
+ return createHmac('sha256', CamusTokenProvider.sharingSalt).update(material, 'utf8').digest('hex');
70
+ }
71
+ credentials;
72
+ token;
73
+ renewAfter;
74
+ resolveLoginClient;
75
+ resolveEndpoint;
76
+ resolveTimeoutSeconds;
77
+ lifetimeMs;
78
+ /** The single login in flight, if any. Every racing caller awaits this same promise. */
79
+ inFlight;
80
+ /** @internal Test hook: the wall clock this provider reads. */
81
+ clock = () => Date.now();
82
+ constructor(init) {
83
+ this.credentials = init.credentials;
84
+ this.resolveLoginClient = init.resolveLoginClient;
85
+ this.resolveEndpoint = init.resolveEndpoint;
86
+ this.resolveTimeoutSeconds = init.resolveTimeoutSeconds;
87
+ this.lifetimeMs = init.lifetimeMs ?? DEFAULT_TOKEN_LIFETIME_MS;
88
+ // A token supplied directly is the cached token, and never ages out on this side.
89
+ this.token = init.credentials.accessToken;
90
+ this.renewAfter = Number.POSITIVE_INFINITY;
91
+ }
92
+ /**
93
+ * True when this client has anything to authenticate with. When false the driver sends no
94
+ * `Authorization` header, which is what a server with authentication off expects.
95
+ */
96
+ get isEnabled() {
97
+ return hasCredentials(this.credentials);
98
+ }
99
+ /** True when the provider holds a password and can therefore replace a rejected token. */
100
+ get canRenew() {
101
+ return canRenew(this.credentials);
102
+ }
103
+ /**
104
+ * The cached token, without triggering a login. The gRPC batch-stream factory reads it, because
105
+ * it builds a stream synchronously; every such call site awaits `getToken` first, so the cache
106
+ * is warm by then.
107
+ */
108
+ get currentToken() {
109
+ return this.token;
110
+ }
111
+ /**
112
+ * A usable bearer token, logging in when there is none or the cached one has aged out. Reports
113
+ * `undefined` when no credentials are configured.
114
+ */
115
+ async getToken(signal) {
116
+ const cached = this.tryGetCached();
117
+ if (cached !== undefined)
118
+ return cached;
119
+ if (!this.isEnabled)
120
+ return undefined;
121
+ // A caller that arrives during a login awaits that login rather than issuing its own.
122
+ this.inFlight ??= this.loginOnce(signal).finally(() => {
123
+ this.inFlight = undefined;
124
+ });
125
+ return this.inFlight;
126
+ }
127
+ /**
128
+ * Discards a token so the next `getToken` mints a new one.
129
+ *
130
+ * Comparing against the cached value keeps a late rejection of an already-replaced token from
131
+ * throwing away the good one a concurrent caller just obtained. It does nothing when the token
132
+ * cannot be renewed, so the caller reports the failure instead of looping.
133
+ */
134
+ invalidate(staleToken) {
135
+ if (staleToken === undefined || staleToken.length === 0)
136
+ return;
137
+ if (!this.canRenew)
138
+ return;
139
+ if (this.token !== staleToken)
140
+ return;
141
+ this.token = undefined;
142
+ this.renewAfter = 0;
143
+ }
144
+ /**
145
+ * Authenticates explicitly, replacing whatever credentials were configured, and reports the
146
+ * minted token. Any cached token is dropped.
147
+ */
148
+ async login(user, password, signal) {
149
+ this.credentials = credentialsFromPassword(user, password);
150
+ this.token = undefined;
151
+ this.renewAfter = 0;
152
+ const pending = this.loginOnce(signal).finally(() => {
153
+ this.inFlight = undefined;
154
+ });
155
+ this.inFlight = pending;
156
+ return pending;
157
+ }
158
+ /**
159
+ * Revokes the cached token on the server and forgets it. The configured credentials are kept, so
160
+ * a later statement authenticates again on its own: this ends a session, it does not switch
161
+ * authentication off. It does nothing when no token has been minted.
162
+ */
163
+ async logout(signal) {
164
+ const revoked = this.token;
165
+ this.token = undefined;
166
+ this.renewAfter = 0;
167
+ if (revoked === undefined || revoked.length === 0)
168
+ return;
169
+ const client = await this.resolveLoginClient();
170
+ await client.logout(this.resolveEndpoint(), revoked, this.resolveTimeoutSeconds(), signal);
171
+ }
172
+ tryGetCached() {
173
+ if (!this.isEnabled)
174
+ return undefined;
175
+ if (this.token === undefined)
176
+ return undefined;
177
+ return this.clock() < this.renewAfter ? this.token : undefined;
178
+ }
179
+ async loginOnce(signal) {
180
+ // Re-checked inside the single-flight gate: the caller that queued behind the winner finds the
181
+ // token it minted.
182
+ const cached = this.tryGetCached();
183
+ if (cached !== undefined)
184
+ return cached;
185
+ if (!this.canRenew) {
186
+ throw new CamusError(CamusErrorCode.AuthenticationFailed, 'The supplied access token was rejected and this client has no credentials to obtain a new one.');
187
+ }
188
+ const client = await this.resolveLoginClient();
189
+ const minted = await client.login(this.resolveEndpoint(), this.credentials.user, this.credentials.password, this.resolveTimeoutSeconds(), signal);
190
+ this.token = minted.token;
191
+ this.renewAfter = this.clock() + this.renewalDelayMs(minted.expiresInMs);
192
+ return minted.token;
193
+ }
194
+ /**
195
+ * When to mint the next token.
196
+ *
197
+ * The server's reported lifetime is authoritative — its own setting is configurable and may be
198
+ * shorter than any value the driver defaults to — so the provider renews at 80% of it, leaving
199
+ * headroom for the request that carries the token to finish. Without a reported value it falls
200
+ * back to the configured lifetime, which is already conservative.
201
+ */
202
+ renewalDelayMs(reported) {
203
+ if (reported === undefined)
204
+ return this.lifetimeMs;
205
+ const renewal = reported * 0.8;
206
+ return renewal > 0 ? renewal : 1000;
207
+ }
208
+ }
209
+ //# sourceMappingURL=token-provider.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"token-provider.js","sourceRoot":"","sources":["../../src/auth/token-provider.ts"],"names":[],"mappings":"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"}