@conduitplatform/module-tools 0.17.0-alpha.8 → 0.17.0-alpha.9
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 +598 -114
- package/dist/index.cjs.map +1 -1
- package/dist/index.d.cts +185 -4
- package/dist/index.d.ts +185 -4
- package/dist/index.esm.js +559 -83
- package/dist/index.esm.js.map +1 -1
- package/package.json +4 -4
package/dist/index.d.cts
CHANGED
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import { ConduitSchema, DatabaseProvider, ConduitModel, ConduitSchemaOptions, Query, FindOneOptions, FindManyOptions, AuthzOptions, PopulateAuthzOptions, CountDocumentsOptions, ConduitGrpcSdk, HealthCheckStatus, GrpcRequest, HealthCheckRequest, GrpcCallback, HealthCheckResponse, SetConfigRequest, GrpcResponse, SetConfigResponse, GetExportableResourcesRequest, GetExportableResourcesResponse, ExportResourcesRequest, ExportResourcesResponse, ImportResourcesRequest, ImportResourcesResponse, PeerWatchEdge, TYPE, ConduitNumberValidation, ConduitStringValidation, Params, Context, Cookies, ParsedRouterRequest, UnparsedRouterResponse, ConduitSocketParamTypes, ConduitRouteReturnDefinition, ParsedSocketRequest, UnparsedSocketResponse,
|
|
1
|
+
import { ConduitSchema, DatabaseProvider, ConduitModel, ConduitSchemaOptions, Query, FindOneOptions, FindManyOptions, AuthzOptions, PopulateAuthzOptions, CountDocumentsOptions, ConduitGrpcSdk, HealthCheckStatus, GrpcRequest, HealthCheckRequest, GrpcCallback, HealthCheckResponse, SetConfigRequest, GrpcResponse, SetConfigResponse, GetExportableResourcesRequest, GetExportableResourcesResponse, ExportResourcesRequest, ExportResourcesResponse, ImportResourcesRequest, ImportResourcesResponse, PeerWatchEdge, TYPE, ConduitNumberValidation, ConduitStringValidation, Params, Context, Cookies, ParsedRouterRequest, Indexable, UnparsedRouterResponse, ConduitSocketParamTypes, ConduitRouteReturnDefinition, ParsedSocketRequest, UnparsedSocketResponse, Router, Admin, ConduitMiddlewareOptions, ConduitRouteOptions, ConduitSocketOptions, ConduitRouteActions, ConduitQueryParams, ConduitUrlParams, ConduitReturn, ConduitRoute, AccessTokenClaims, GrpcError, ModuleErrorDefinition } from '@conduitplatform/grpc-sdk';
|
|
2
2
|
import { EventEmitter } from 'events';
|
|
3
3
|
import { ServerWritableStream, Server } from '@grpc/grpc-js';
|
|
4
4
|
import convict from 'convict';
|
|
@@ -345,6 +345,49 @@ declare function wrapGrpcFunctions(functions: {
|
|
|
345
345
|
|
|
346
346
|
declare function createParsedRouterRequest(params: Params, urlParams?: Params, queryParams?: Params, bodyParams?: Params, path?: string, headers?: Headers, context?: Context, cookies?: Cookies, rawHeaders?: string[], rawBody?: Buffer): ParsedRouterRequest;
|
|
347
347
|
|
|
348
|
+
/**
|
|
349
|
+
* User hydration.
|
|
350
|
+
*
|
|
351
|
+
* Client routes guarded by `authMiddleware` / `authMiddleware?` receive `context.user`.
|
|
352
|
+
* In "session" mode the authentication middleware already sets it. In "jwt" mode the
|
|
353
|
+
* router only knows the user id (`context.userId`, from a verified access token), so
|
|
354
|
+
* module-tools fetches the user (through grpcSdk.authentication.getUser, which reads
|
|
355
|
+
* through a 5s Redis cache) before invoking the handler.
|
|
356
|
+
*
|
|
357
|
+
* Opt out per route with `hydrateUser: false` (RouteBuilder.hydrateUser(false)).
|
|
358
|
+
*
|
|
359
|
+
* @deprecated The default flips to off in the next major version. Modules are then
|
|
360
|
+
* expected to call `grpcSdk.authentication.getUser(context.userId)` explicitly.
|
|
361
|
+
*/
|
|
362
|
+
interface UserHydrator {
|
|
363
|
+
/** True for `authMiddleware?`: a failed lookup leaves the context untouched. */
|
|
364
|
+
optional: boolean;
|
|
365
|
+
getUser: (userId: string) => Promise<Indexable>;
|
|
366
|
+
}
|
|
367
|
+
/** Whether the route is guarded by an auth middleware, and if so whether it is the optional form. */
|
|
368
|
+
declare function getAuthMiddlewareKind(routeOptions: Indexable): 'required' | 'optional' | undefined;
|
|
369
|
+
/**
|
|
370
|
+
* Pure hydration decision: the route has an auth middleware, `hydrateUser` is not false,
|
|
371
|
+
* and the context carries a `userId` but no `user`. Admin routes must not call this.
|
|
372
|
+
*/
|
|
373
|
+
declare function shouldHydrateUser(routeOptions: Indexable | undefined, context: Indexable | undefined): boolean;
|
|
374
|
+
type UserResolver = (userId: string) => Promise<Indexable>;
|
|
375
|
+
/**
|
|
376
|
+
* Builds the per-route hydrator for client routes, or undefined when the route never hydrates.
|
|
377
|
+
* `resolve` is consulted per request (so a resolver registered after route registration still
|
|
378
|
+
* applies) and returns the lookup function to use, if any.
|
|
379
|
+
*/
|
|
380
|
+
declare function createUserHydrator(routeOptions: Indexable | undefined, resolve: () => UserResolver | undefined): UserHydrator | undefined;
|
|
381
|
+
/** Maps a failed user lookup to the gRPC code returned to the caller. */
|
|
382
|
+
declare function mapHydrationErrorCode(error: unknown): number;
|
|
383
|
+
/**
|
|
384
|
+
* Sets context.user when needed. For the mandatory form a failed lookup throws a GrpcError:
|
|
385
|
+
* NOT_FOUND becomes UNAUTHENTICATED; PERMISSION_DENIED and every other gRPC code
|
|
386
|
+
* (UNAVAILABLE, DEADLINE_EXCEEDED, INTERNAL, ...) pass through. The optional form
|
|
387
|
+
* swallows the failure and leaves the context untouched. Failures are logged at warn level.
|
|
388
|
+
*/
|
|
389
|
+
declare function hydrateContextUser(routeOptions: Indexable, context: Indexable, hydrator: UserHydrator): Promise<void>;
|
|
390
|
+
|
|
348
391
|
type RouterRequestHandler = (call: ParsedRouterRequest) => Promise<UnparsedRouterResponse>;
|
|
349
392
|
type RouterRequestHandlerCallback = (call: ParsedRouterRequest, callback: (response: UnparsedRouterResponse) => void) => Promise<UnparsedRouterResponse | undefined | void>;
|
|
350
393
|
type SocketRequestHandler = (call: ParsedSocketRequest) => Promise<UnparsedSocketResponse>;
|
|
@@ -356,7 +399,10 @@ interface SocketEventHandler {
|
|
|
356
399
|
returnType?: ConduitRouteReturnDefinition;
|
|
357
400
|
handler: SocketRequestHandlers;
|
|
358
401
|
}
|
|
359
|
-
declare function wrapRouterGrpcFunction(fun: RequestHandlers | SocketRequestHandlers, routerType: string
|
|
402
|
+
declare function wrapRouterGrpcFunction(fun: RequestHandlers | SocketRequestHandlers, routerType: string, hydration?: {
|
|
403
|
+
options: Indexable;
|
|
404
|
+
hydrator: UserHydrator;
|
|
405
|
+
}): (call: Indexable, callback: any) => void;
|
|
360
406
|
|
|
361
407
|
declare class RoutingController {
|
|
362
408
|
private _routeHandlers;
|
|
@@ -372,6 +418,17 @@ declare class RoutingManager {
|
|
|
372
418
|
private _moduleRoutes;
|
|
373
419
|
static ClientController: RoutingController;
|
|
374
420
|
static AdminController: RoutingController;
|
|
421
|
+
/** Set by ManagedModule; used to hydrate context.user on client routes. */
|
|
422
|
+
static grpcSdk?: ConduitGrpcSdk;
|
|
423
|
+
private static userResolver?;
|
|
424
|
+
private static warnedNoResolver;
|
|
425
|
+
/**
|
|
426
|
+
* Overrides how users are fetched for hydration (default: grpcSdk.authentication.getUser).
|
|
427
|
+
* Intended for the module that owns the users: the authentication module has no gRPC
|
|
428
|
+
* client to itself and will register a local resolver here.
|
|
429
|
+
*/
|
|
430
|
+
static setUserResolver(resolver: UserResolver | undefined): void;
|
|
431
|
+
private static resolveUser;
|
|
375
432
|
private _routeHandlers;
|
|
376
433
|
private readonly isAdmin;
|
|
377
434
|
constructor(_router: Router | Admin, _server: GrpcServer);
|
|
@@ -409,6 +466,13 @@ declare class RouteBuilder {
|
|
|
409
466
|
rateLimit(maxRequests: number, resetInterval: number): RouteBuilder;
|
|
410
467
|
captureRawBody(capture: boolean): RouteBuilder;
|
|
411
468
|
captureRawHeaders(capture: boolean): RouteBuilder;
|
|
469
|
+
/**
|
|
470
|
+
* Whether module-tools hydrates `context.user` from `context.userId` on routes with
|
|
471
|
+
* `authMiddleware` / `authMiddleware?` (default true).
|
|
472
|
+
* @deprecated The default flips to false in the next major; call
|
|
473
|
+
* `grpcSdk.authentication.getUser(userId)` explicitly instead.
|
|
474
|
+
*/
|
|
475
|
+
hydrateUser(hydrate: boolean): RouteBuilder;
|
|
412
476
|
return(name: string, fields: ConduitReturn): RouteBuilder;
|
|
413
477
|
handler(fn: RequestHandlers): RouteBuilder;
|
|
414
478
|
add(): void;
|
|
@@ -417,7 +481,12 @@ declare class RouteBuilder {
|
|
|
417
481
|
|
|
418
482
|
declare function wrapFunctionsAsync(functions: {
|
|
419
483
|
[name: string]: RequestHandlers | SocketRequestHandlers;
|
|
420
|
-
}, routerType: 'admin' | 'client'
|
|
484
|
+
}, routerType: 'admin' | 'client', hydrations?: {
|
|
485
|
+
[name: string]: {
|
|
486
|
+
options: Indexable;
|
|
487
|
+
hydrator: UserHydrator;
|
|
488
|
+
};
|
|
489
|
+
}): {
|
|
421
490
|
[name: string]: (call: Indexable, callback?: Indexable) => void;
|
|
422
491
|
};
|
|
423
492
|
|
|
@@ -502,9 +571,121 @@ declare function reconcileStoredModuleConfig<T>(args: {
|
|
|
502
571
|
persisted: boolean;
|
|
503
572
|
}>;
|
|
504
573
|
|
|
574
|
+
interface AccessTokenSigningKeys {
|
|
575
|
+
kid: string;
|
|
576
|
+
/** PEM (SPKI) Ed25519 public key. */
|
|
577
|
+
publicKey: string;
|
|
578
|
+
previousKid?: string;
|
|
579
|
+
previousPublicKey?: string;
|
|
580
|
+
/** Epoch ms until which the previous key is still accepted. 0 (or unset) means no previous key. */
|
|
581
|
+
previousRetiredAt?: number;
|
|
582
|
+
}
|
|
583
|
+
interface AccessTokenVerifierState {
|
|
584
|
+
tokenVersion: number;
|
|
585
|
+
signing: AccessTokenSigningKeys;
|
|
586
|
+
}
|
|
587
|
+
interface AccessTokenVerifyOptions {
|
|
588
|
+
/** Client id of the request. When set, it must equal the token's `cid`. */
|
|
589
|
+
clientId?: string;
|
|
590
|
+
/** Current time in epoch milliseconds. Defaults to Date.now(). */
|
|
591
|
+
now?: number;
|
|
592
|
+
/** Clock skew tolerance for `exp`. Defaults to 5 seconds. */
|
|
593
|
+
leewaySeconds?: number;
|
|
594
|
+
}
|
|
595
|
+
declare const DEFAULT_LEEWAY_SECONDS = 5;
|
|
596
|
+
/** Picks the public key for `kid`: the current key, or the previous one while its retirement is in the future. */
|
|
597
|
+
declare function selectVerificationKey(kid: string | undefined, signing: AccessTokenSigningKeys, now: number): string | undefined;
|
|
598
|
+
/**
|
|
599
|
+
* Verifies an Ed25519 access token. Throws GrpcError(UNAUTHENTICATED) with a short,
|
|
600
|
+
* key-material-free reason on any failure.
|
|
601
|
+
*/
|
|
602
|
+
declare function verifyAccessToken(token: string, state: AccessTokenVerifierState, options?: AccessTokenVerifyOptions): AccessTokenClaims;
|
|
603
|
+
|
|
604
|
+
type AccessTokenMode = 'session' | 'jwt';
|
|
605
|
+
interface AccessTokenVerifierSnapshot {
|
|
606
|
+
mode: AccessTokenMode;
|
|
607
|
+
strictRevocation: boolean;
|
|
608
|
+
ready: boolean;
|
|
609
|
+
tokenVersion: number;
|
|
610
|
+
/** Current signing key id, if keys are loaded. */
|
|
611
|
+
kid?: string;
|
|
612
|
+
}
|
|
613
|
+
declare const AUTHENTICATION_CONFIG_UPDATE_CHANNEL = "authentication:config:update";
|
|
614
|
+
declare class AccessTokenVerifier {
|
|
615
|
+
private readonly grpcSdk;
|
|
616
|
+
private static instance?;
|
|
617
|
+
private _mode;
|
|
618
|
+
private _strictRevocation;
|
|
619
|
+
private _tokenVersion;
|
|
620
|
+
private _signing?;
|
|
621
|
+
private _loaded;
|
|
622
|
+
private _subscribed;
|
|
623
|
+
private _generation;
|
|
624
|
+
private _running;
|
|
625
|
+
private _retryTimer?;
|
|
626
|
+
private _refreshTimer?;
|
|
627
|
+
private _lastRefetch;
|
|
628
|
+
private _refetching;
|
|
629
|
+
private _warned;
|
|
630
|
+
private _listeners;
|
|
631
|
+
private constructor();
|
|
632
|
+
static getInstance(grpcSdk: ConduitGrpcSdk): AccessTokenVerifier;
|
|
633
|
+
/**
|
|
634
|
+
* Internal, for tests only: stops the verifier, clears all state and drops the singleton.
|
|
635
|
+
*/
|
|
636
|
+
static resetForTests(): void;
|
|
637
|
+
private resetState;
|
|
638
|
+
/** Snapshot of the verifier's observable state. */
|
|
639
|
+
get state(): AccessTokenVerifierSnapshot;
|
|
640
|
+
/**
|
|
641
|
+
* Registers a listener fired synchronously at the end of every applyConfig that changed
|
|
642
|
+
* anything (including the first successful load). Returns an unsubscribe function.
|
|
643
|
+
*/
|
|
644
|
+
onChange(listener: (state: AccessTokenVerifierSnapshot) => void): () => void;
|
|
645
|
+
private fingerprint;
|
|
646
|
+
get mode(): AccessTokenMode;
|
|
647
|
+
get strictRevocation(): boolean;
|
|
648
|
+
/** True once signing keys have been loaded. */
|
|
649
|
+
get ready(): boolean;
|
|
650
|
+
get tokenVersion(): number;
|
|
651
|
+
/**
|
|
652
|
+
* Loads the authentication config, subscribes to its updates and starts a slow periodic
|
|
653
|
+
* refresh. The first attempt is awaited; if it fails, retries continue in the background
|
|
654
|
+
* with capped backoff until the config is loaded and the subscription is acknowledged.
|
|
655
|
+
* Idempotent while running; never throws.
|
|
656
|
+
*/
|
|
657
|
+
start(): Promise<void>;
|
|
658
|
+
stop(): void;
|
|
659
|
+
private attempt;
|
|
660
|
+
private subscribe;
|
|
661
|
+
/** Refetches the config from the authentication module; failures keep the previous state. */
|
|
662
|
+
private refetch;
|
|
663
|
+
private warnOnce;
|
|
664
|
+
private static validPem;
|
|
665
|
+
/**
|
|
666
|
+
* Validates and normalizes the signing keys. Returns undefined when no signing block is
|
|
667
|
+
* configured, null when the public key is invalid (the caller keeps the previous state).
|
|
668
|
+
*/
|
|
669
|
+
private normalizeSigning;
|
|
670
|
+
private validPreviousKey;
|
|
671
|
+
private parseTokenVersion;
|
|
672
|
+
private notifyListeners;
|
|
673
|
+
/**
|
|
674
|
+
* Applies an authentication module config object (full config). Invalid input is ignored
|
|
675
|
+
* and the previous state is kept; invalid keys are logged once.
|
|
676
|
+
*/
|
|
677
|
+
applyConfig(config: unknown): void;
|
|
678
|
+
/**
|
|
679
|
+
* Verifies an access token, throwing GrpcError(UNAUTHENTICATED) with a short reason on failure.
|
|
680
|
+
* `options.now` is epoch milliseconds. An `unknown kid` triggers a throttled (at most once
|
|
681
|
+
* per 10 s) background refetch of the config, to pick up a rotation sooner.
|
|
682
|
+
*/
|
|
683
|
+
verify(token: string, options?: AccessTokenVerifyOptions): AccessTokenClaims;
|
|
684
|
+
}
|
|
685
|
+
|
|
505
686
|
declare class ModuleError extends GrpcError {
|
|
506
687
|
debugLogInfo?: string;
|
|
507
688
|
constructor(errorDefinition: ModuleErrorDefinition, debugLogInfo?: string);
|
|
508
689
|
}
|
|
509
690
|
|
|
510
|
-
export { ConduitActiveSchema, ConduitBoolean, ConduitDate, ConduitJson, ConduitNumber, ConduitObjectId, type ConduitPackageJson, type ConduitPeerWatchEntry, type ConduitPeersManifest, ConduitRelation, type ConduitService, ConduitServiceModule, ConduitString, ConfigController, DEFAULT_STRIP_FIELDS, type ExportModelAdapter, type ExportResult, type ExportableResource, GrpcServer, type ImportModelAdapter, type ImportResult, type ImportResultEntry, ManagedModule, ModuleError, ModuleLifecycleStage, type RequestHandlers, RouteBuilder, type RouterRequestHandler, type RouterRequestHandlerCallback, RoutingManager, type SanitizeForExportOptions, type SocketEventHandler, type SocketRequestHandler, type SocketRequestHandlerCallback, type SocketRequestHandlers, addServiceToServer, containsRedactedMarker, convictConfigParser, createParsedRouterRequest, createServer, exportModel, importModel, initializeSdk, linearBackoffTimeout, linearBackoffTimeoutAsync, merge, readConduitPeersManifest, reconcileStoredModuleConfig, redactSensitiveConfig, restoreRedactedSecrets, sanitizeDocumentsForExport, stableConfigJson, storedConfigsEquivalent, stripInternalFields, wrapFunctionsAsync, wrapGrpcFunctions, wrapRouterGrpcFunction };
|
|
691
|
+
export { AUTHENTICATION_CONFIG_UPDATE_CHANNEL, type AccessTokenMode, type AccessTokenSigningKeys, AccessTokenVerifier, type AccessTokenVerifierSnapshot, type AccessTokenVerifierState, type AccessTokenVerifyOptions, ConduitActiveSchema, ConduitBoolean, ConduitDate, ConduitJson, ConduitNumber, ConduitObjectId, type ConduitPackageJson, type ConduitPeerWatchEntry, type ConduitPeersManifest, ConduitRelation, type ConduitService, ConduitServiceModule, ConduitString, ConfigController, DEFAULT_LEEWAY_SECONDS, DEFAULT_STRIP_FIELDS, type ExportModelAdapter, type ExportResult, type ExportableResource, GrpcServer, type ImportModelAdapter, type ImportResult, type ImportResultEntry, ManagedModule, ModuleError, ModuleLifecycleStage, type RequestHandlers, RouteBuilder, type RouterRequestHandler, type RouterRequestHandlerCallback, RoutingManager, type SanitizeForExportOptions, type SocketEventHandler, type SocketRequestHandler, type SocketRequestHandlerCallback, type SocketRequestHandlers, type UserHydrator, type UserResolver, addServiceToServer, containsRedactedMarker, convictConfigParser, createParsedRouterRequest, createServer, createUserHydrator, exportModel, getAuthMiddlewareKind, hydrateContextUser, importModel, initializeSdk, linearBackoffTimeout, linearBackoffTimeoutAsync, mapHydrationErrorCode, merge, readConduitPeersManifest, reconcileStoredModuleConfig, redactSensitiveConfig, restoreRedactedSecrets, sanitizeDocumentsForExport, selectVerificationKey, shouldHydrateUser, stableConfigJson, storedConfigsEquivalent, stripInternalFields, verifyAccessToken, wrapFunctionsAsync, wrapGrpcFunctions, wrapRouterGrpcFunction };
|
package/dist/index.d.ts
CHANGED
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import { ConduitSchema, DatabaseProvider, ConduitModel, ConduitSchemaOptions, Query, FindOneOptions, FindManyOptions, AuthzOptions, PopulateAuthzOptions, CountDocumentsOptions, ConduitGrpcSdk, HealthCheckStatus, GrpcRequest, HealthCheckRequest, GrpcCallback, HealthCheckResponse, SetConfigRequest, GrpcResponse, SetConfigResponse, GetExportableResourcesRequest, GetExportableResourcesResponse, ExportResourcesRequest, ExportResourcesResponse, ImportResourcesRequest, ImportResourcesResponse, PeerWatchEdge, TYPE, ConduitNumberValidation, ConduitStringValidation, Params, Context, Cookies, ParsedRouterRequest, UnparsedRouterResponse, ConduitSocketParamTypes, ConduitRouteReturnDefinition, ParsedSocketRequest, UnparsedSocketResponse,
|
|
1
|
+
import { ConduitSchema, DatabaseProvider, ConduitModel, ConduitSchemaOptions, Query, FindOneOptions, FindManyOptions, AuthzOptions, PopulateAuthzOptions, CountDocumentsOptions, ConduitGrpcSdk, HealthCheckStatus, GrpcRequest, HealthCheckRequest, GrpcCallback, HealthCheckResponse, SetConfigRequest, GrpcResponse, SetConfigResponse, GetExportableResourcesRequest, GetExportableResourcesResponse, ExportResourcesRequest, ExportResourcesResponse, ImportResourcesRequest, ImportResourcesResponse, PeerWatchEdge, TYPE, ConduitNumberValidation, ConduitStringValidation, Params, Context, Cookies, ParsedRouterRequest, Indexable, UnparsedRouterResponse, ConduitSocketParamTypes, ConduitRouteReturnDefinition, ParsedSocketRequest, UnparsedSocketResponse, Router, Admin, ConduitMiddlewareOptions, ConduitRouteOptions, ConduitSocketOptions, ConduitRouteActions, ConduitQueryParams, ConduitUrlParams, ConduitReturn, ConduitRoute, AccessTokenClaims, GrpcError, ModuleErrorDefinition } from '@conduitplatform/grpc-sdk';
|
|
2
2
|
import { EventEmitter } from 'events';
|
|
3
3
|
import { ServerWritableStream, Server } from '@grpc/grpc-js';
|
|
4
4
|
import convict from 'convict';
|
|
@@ -345,6 +345,49 @@ declare function wrapGrpcFunctions(functions: {
|
|
|
345
345
|
|
|
346
346
|
declare function createParsedRouterRequest(params: Params, urlParams?: Params, queryParams?: Params, bodyParams?: Params, path?: string, headers?: Headers, context?: Context, cookies?: Cookies, rawHeaders?: string[], rawBody?: Buffer): ParsedRouterRequest;
|
|
347
347
|
|
|
348
|
+
/**
|
|
349
|
+
* User hydration.
|
|
350
|
+
*
|
|
351
|
+
* Client routes guarded by `authMiddleware` / `authMiddleware?` receive `context.user`.
|
|
352
|
+
* In "session" mode the authentication middleware already sets it. In "jwt" mode the
|
|
353
|
+
* router only knows the user id (`context.userId`, from a verified access token), so
|
|
354
|
+
* module-tools fetches the user (through grpcSdk.authentication.getUser, which reads
|
|
355
|
+
* through a 5s Redis cache) before invoking the handler.
|
|
356
|
+
*
|
|
357
|
+
* Opt out per route with `hydrateUser: false` (RouteBuilder.hydrateUser(false)).
|
|
358
|
+
*
|
|
359
|
+
* @deprecated The default flips to off in the next major version. Modules are then
|
|
360
|
+
* expected to call `grpcSdk.authentication.getUser(context.userId)` explicitly.
|
|
361
|
+
*/
|
|
362
|
+
interface UserHydrator {
|
|
363
|
+
/** True for `authMiddleware?`: a failed lookup leaves the context untouched. */
|
|
364
|
+
optional: boolean;
|
|
365
|
+
getUser: (userId: string) => Promise<Indexable>;
|
|
366
|
+
}
|
|
367
|
+
/** Whether the route is guarded by an auth middleware, and if so whether it is the optional form. */
|
|
368
|
+
declare function getAuthMiddlewareKind(routeOptions: Indexable): 'required' | 'optional' | undefined;
|
|
369
|
+
/**
|
|
370
|
+
* Pure hydration decision: the route has an auth middleware, `hydrateUser` is not false,
|
|
371
|
+
* and the context carries a `userId` but no `user`. Admin routes must not call this.
|
|
372
|
+
*/
|
|
373
|
+
declare function shouldHydrateUser(routeOptions: Indexable | undefined, context: Indexable | undefined): boolean;
|
|
374
|
+
type UserResolver = (userId: string) => Promise<Indexable>;
|
|
375
|
+
/**
|
|
376
|
+
* Builds the per-route hydrator for client routes, or undefined when the route never hydrates.
|
|
377
|
+
* `resolve` is consulted per request (so a resolver registered after route registration still
|
|
378
|
+
* applies) and returns the lookup function to use, if any.
|
|
379
|
+
*/
|
|
380
|
+
declare function createUserHydrator(routeOptions: Indexable | undefined, resolve: () => UserResolver | undefined): UserHydrator | undefined;
|
|
381
|
+
/** Maps a failed user lookup to the gRPC code returned to the caller. */
|
|
382
|
+
declare function mapHydrationErrorCode(error: unknown): number;
|
|
383
|
+
/**
|
|
384
|
+
* Sets context.user when needed. For the mandatory form a failed lookup throws a GrpcError:
|
|
385
|
+
* NOT_FOUND becomes UNAUTHENTICATED; PERMISSION_DENIED and every other gRPC code
|
|
386
|
+
* (UNAVAILABLE, DEADLINE_EXCEEDED, INTERNAL, ...) pass through. The optional form
|
|
387
|
+
* swallows the failure and leaves the context untouched. Failures are logged at warn level.
|
|
388
|
+
*/
|
|
389
|
+
declare function hydrateContextUser(routeOptions: Indexable, context: Indexable, hydrator: UserHydrator): Promise<void>;
|
|
390
|
+
|
|
348
391
|
type RouterRequestHandler = (call: ParsedRouterRequest) => Promise<UnparsedRouterResponse>;
|
|
349
392
|
type RouterRequestHandlerCallback = (call: ParsedRouterRequest, callback: (response: UnparsedRouterResponse) => void) => Promise<UnparsedRouterResponse | undefined | void>;
|
|
350
393
|
type SocketRequestHandler = (call: ParsedSocketRequest) => Promise<UnparsedSocketResponse>;
|
|
@@ -356,7 +399,10 @@ interface SocketEventHandler {
|
|
|
356
399
|
returnType?: ConduitRouteReturnDefinition;
|
|
357
400
|
handler: SocketRequestHandlers;
|
|
358
401
|
}
|
|
359
|
-
declare function wrapRouterGrpcFunction(fun: RequestHandlers | SocketRequestHandlers, routerType: string
|
|
402
|
+
declare function wrapRouterGrpcFunction(fun: RequestHandlers | SocketRequestHandlers, routerType: string, hydration?: {
|
|
403
|
+
options: Indexable;
|
|
404
|
+
hydrator: UserHydrator;
|
|
405
|
+
}): (call: Indexable, callback: any) => void;
|
|
360
406
|
|
|
361
407
|
declare class RoutingController {
|
|
362
408
|
private _routeHandlers;
|
|
@@ -372,6 +418,17 @@ declare class RoutingManager {
|
|
|
372
418
|
private _moduleRoutes;
|
|
373
419
|
static ClientController: RoutingController;
|
|
374
420
|
static AdminController: RoutingController;
|
|
421
|
+
/** Set by ManagedModule; used to hydrate context.user on client routes. */
|
|
422
|
+
static grpcSdk?: ConduitGrpcSdk;
|
|
423
|
+
private static userResolver?;
|
|
424
|
+
private static warnedNoResolver;
|
|
425
|
+
/**
|
|
426
|
+
* Overrides how users are fetched for hydration (default: grpcSdk.authentication.getUser).
|
|
427
|
+
* Intended for the module that owns the users: the authentication module has no gRPC
|
|
428
|
+
* client to itself and will register a local resolver here.
|
|
429
|
+
*/
|
|
430
|
+
static setUserResolver(resolver: UserResolver | undefined): void;
|
|
431
|
+
private static resolveUser;
|
|
375
432
|
private _routeHandlers;
|
|
376
433
|
private readonly isAdmin;
|
|
377
434
|
constructor(_router: Router | Admin, _server: GrpcServer);
|
|
@@ -409,6 +466,13 @@ declare class RouteBuilder {
|
|
|
409
466
|
rateLimit(maxRequests: number, resetInterval: number): RouteBuilder;
|
|
410
467
|
captureRawBody(capture: boolean): RouteBuilder;
|
|
411
468
|
captureRawHeaders(capture: boolean): RouteBuilder;
|
|
469
|
+
/**
|
|
470
|
+
* Whether module-tools hydrates `context.user` from `context.userId` on routes with
|
|
471
|
+
* `authMiddleware` / `authMiddleware?` (default true).
|
|
472
|
+
* @deprecated The default flips to false in the next major; call
|
|
473
|
+
* `grpcSdk.authentication.getUser(userId)` explicitly instead.
|
|
474
|
+
*/
|
|
475
|
+
hydrateUser(hydrate: boolean): RouteBuilder;
|
|
412
476
|
return(name: string, fields: ConduitReturn): RouteBuilder;
|
|
413
477
|
handler(fn: RequestHandlers): RouteBuilder;
|
|
414
478
|
add(): void;
|
|
@@ -417,7 +481,12 @@ declare class RouteBuilder {
|
|
|
417
481
|
|
|
418
482
|
declare function wrapFunctionsAsync(functions: {
|
|
419
483
|
[name: string]: RequestHandlers | SocketRequestHandlers;
|
|
420
|
-
}, routerType: 'admin' | 'client'
|
|
484
|
+
}, routerType: 'admin' | 'client', hydrations?: {
|
|
485
|
+
[name: string]: {
|
|
486
|
+
options: Indexable;
|
|
487
|
+
hydrator: UserHydrator;
|
|
488
|
+
};
|
|
489
|
+
}): {
|
|
421
490
|
[name: string]: (call: Indexable, callback?: Indexable) => void;
|
|
422
491
|
};
|
|
423
492
|
|
|
@@ -502,9 +571,121 @@ declare function reconcileStoredModuleConfig<T>(args: {
|
|
|
502
571
|
persisted: boolean;
|
|
503
572
|
}>;
|
|
504
573
|
|
|
574
|
+
interface AccessTokenSigningKeys {
|
|
575
|
+
kid: string;
|
|
576
|
+
/** PEM (SPKI) Ed25519 public key. */
|
|
577
|
+
publicKey: string;
|
|
578
|
+
previousKid?: string;
|
|
579
|
+
previousPublicKey?: string;
|
|
580
|
+
/** Epoch ms until which the previous key is still accepted. 0 (or unset) means no previous key. */
|
|
581
|
+
previousRetiredAt?: number;
|
|
582
|
+
}
|
|
583
|
+
interface AccessTokenVerifierState {
|
|
584
|
+
tokenVersion: number;
|
|
585
|
+
signing: AccessTokenSigningKeys;
|
|
586
|
+
}
|
|
587
|
+
interface AccessTokenVerifyOptions {
|
|
588
|
+
/** Client id of the request. When set, it must equal the token's `cid`. */
|
|
589
|
+
clientId?: string;
|
|
590
|
+
/** Current time in epoch milliseconds. Defaults to Date.now(). */
|
|
591
|
+
now?: number;
|
|
592
|
+
/** Clock skew tolerance for `exp`. Defaults to 5 seconds. */
|
|
593
|
+
leewaySeconds?: number;
|
|
594
|
+
}
|
|
595
|
+
declare const DEFAULT_LEEWAY_SECONDS = 5;
|
|
596
|
+
/** Picks the public key for `kid`: the current key, or the previous one while its retirement is in the future. */
|
|
597
|
+
declare function selectVerificationKey(kid: string | undefined, signing: AccessTokenSigningKeys, now: number): string | undefined;
|
|
598
|
+
/**
|
|
599
|
+
* Verifies an Ed25519 access token. Throws GrpcError(UNAUTHENTICATED) with a short,
|
|
600
|
+
* key-material-free reason on any failure.
|
|
601
|
+
*/
|
|
602
|
+
declare function verifyAccessToken(token: string, state: AccessTokenVerifierState, options?: AccessTokenVerifyOptions): AccessTokenClaims;
|
|
603
|
+
|
|
604
|
+
type AccessTokenMode = 'session' | 'jwt';
|
|
605
|
+
interface AccessTokenVerifierSnapshot {
|
|
606
|
+
mode: AccessTokenMode;
|
|
607
|
+
strictRevocation: boolean;
|
|
608
|
+
ready: boolean;
|
|
609
|
+
tokenVersion: number;
|
|
610
|
+
/** Current signing key id, if keys are loaded. */
|
|
611
|
+
kid?: string;
|
|
612
|
+
}
|
|
613
|
+
declare const AUTHENTICATION_CONFIG_UPDATE_CHANNEL = "authentication:config:update";
|
|
614
|
+
declare class AccessTokenVerifier {
|
|
615
|
+
private readonly grpcSdk;
|
|
616
|
+
private static instance?;
|
|
617
|
+
private _mode;
|
|
618
|
+
private _strictRevocation;
|
|
619
|
+
private _tokenVersion;
|
|
620
|
+
private _signing?;
|
|
621
|
+
private _loaded;
|
|
622
|
+
private _subscribed;
|
|
623
|
+
private _generation;
|
|
624
|
+
private _running;
|
|
625
|
+
private _retryTimer?;
|
|
626
|
+
private _refreshTimer?;
|
|
627
|
+
private _lastRefetch;
|
|
628
|
+
private _refetching;
|
|
629
|
+
private _warned;
|
|
630
|
+
private _listeners;
|
|
631
|
+
private constructor();
|
|
632
|
+
static getInstance(grpcSdk: ConduitGrpcSdk): AccessTokenVerifier;
|
|
633
|
+
/**
|
|
634
|
+
* Internal, for tests only: stops the verifier, clears all state and drops the singleton.
|
|
635
|
+
*/
|
|
636
|
+
static resetForTests(): void;
|
|
637
|
+
private resetState;
|
|
638
|
+
/** Snapshot of the verifier's observable state. */
|
|
639
|
+
get state(): AccessTokenVerifierSnapshot;
|
|
640
|
+
/**
|
|
641
|
+
* Registers a listener fired synchronously at the end of every applyConfig that changed
|
|
642
|
+
* anything (including the first successful load). Returns an unsubscribe function.
|
|
643
|
+
*/
|
|
644
|
+
onChange(listener: (state: AccessTokenVerifierSnapshot) => void): () => void;
|
|
645
|
+
private fingerprint;
|
|
646
|
+
get mode(): AccessTokenMode;
|
|
647
|
+
get strictRevocation(): boolean;
|
|
648
|
+
/** True once signing keys have been loaded. */
|
|
649
|
+
get ready(): boolean;
|
|
650
|
+
get tokenVersion(): number;
|
|
651
|
+
/**
|
|
652
|
+
* Loads the authentication config, subscribes to its updates and starts a slow periodic
|
|
653
|
+
* refresh. The first attempt is awaited; if it fails, retries continue in the background
|
|
654
|
+
* with capped backoff until the config is loaded and the subscription is acknowledged.
|
|
655
|
+
* Idempotent while running; never throws.
|
|
656
|
+
*/
|
|
657
|
+
start(): Promise<void>;
|
|
658
|
+
stop(): void;
|
|
659
|
+
private attempt;
|
|
660
|
+
private subscribe;
|
|
661
|
+
/** Refetches the config from the authentication module; failures keep the previous state. */
|
|
662
|
+
private refetch;
|
|
663
|
+
private warnOnce;
|
|
664
|
+
private static validPem;
|
|
665
|
+
/**
|
|
666
|
+
* Validates and normalizes the signing keys. Returns undefined when no signing block is
|
|
667
|
+
* configured, null when the public key is invalid (the caller keeps the previous state).
|
|
668
|
+
*/
|
|
669
|
+
private normalizeSigning;
|
|
670
|
+
private validPreviousKey;
|
|
671
|
+
private parseTokenVersion;
|
|
672
|
+
private notifyListeners;
|
|
673
|
+
/**
|
|
674
|
+
* Applies an authentication module config object (full config). Invalid input is ignored
|
|
675
|
+
* and the previous state is kept; invalid keys are logged once.
|
|
676
|
+
*/
|
|
677
|
+
applyConfig(config: unknown): void;
|
|
678
|
+
/**
|
|
679
|
+
* Verifies an access token, throwing GrpcError(UNAUTHENTICATED) with a short reason on failure.
|
|
680
|
+
* `options.now` is epoch milliseconds. An `unknown kid` triggers a throttled (at most once
|
|
681
|
+
* per 10 s) background refetch of the config, to pick up a rotation sooner.
|
|
682
|
+
*/
|
|
683
|
+
verify(token: string, options?: AccessTokenVerifyOptions): AccessTokenClaims;
|
|
684
|
+
}
|
|
685
|
+
|
|
505
686
|
declare class ModuleError extends GrpcError {
|
|
506
687
|
debugLogInfo?: string;
|
|
507
688
|
constructor(errorDefinition: ModuleErrorDefinition, debugLogInfo?: string);
|
|
508
689
|
}
|
|
509
690
|
|
|
510
|
-
export { ConduitActiveSchema, ConduitBoolean, ConduitDate, ConduitJson, ConduitNumber, ConduitObjectId, type ConduitPackageJson, type ConduitPeerWatchEntry, type ConduitPeersManifest, ConduitRelation, type ConduitService, ConduitServiceModule, ConduitString, ConfigController, DEFAULT_STRIP_FIELDS, type ExportModelAdapter, type ExportResult, type ExportableResource, GrpcServer, type ImportModelAdapter, type ImportResult, type ImportResultEntry, ManagedModule, ModuleError, ModuleLifecycleStage, type RequestHandlers, RouteBuilder, type RouterRequestHandler, type RouterRequestHandlerCallback, RoutingManager, type SanitizeForExportOptions, type SocketEventHandler, type SocketRequestHandler, type SocketRequestHandlerCallback, type SocketRequestHandlers, addServiceToServer, containsRedactedMarker, convictConfigParser, createParsedRouterRequest, createServer, exportModel, importModel, initializeSdk, linearBackoffTimeout, linearBackoffTimeoutAsync, merge, readConduitPeersManifest, reconcileStoredModuleConfig, redactSensitiveConfig, restoreRedactedSecrets, sanitizeDocumentsForExport, stableConfigJson, storedConfigsEquivalent, stripInternalFields, wrapFunctionsAsync, wrapGrpcFunctions, wrapRouterGrpcFunction };
|
|
691
|
+
export { AUTHENTICATION_CONFIG_UPDATE_CHANNEL, type AccessTokenMode, type AccessTokenSigningKeys, AccessTokenVerifier, type AccessTokenVerifierSnapshot, type AccessTokenVerifierState, type AccessTokenVerifyOptions, ConduitActiveSchema, ConduitBoolean, ConduitDate, ConduitJson, ConduitNumber, ConduitObjectId, type ConduitPackageJson, type ConduitPeerWatchEntry, type ConduitPeersManifest, ConduitRelation, type ConduitService, ConduitServiceModule, ConduitString, ConfigController, DEFAULT_LEEWAY_SECONDS, DEFAULT_STRIP_FIELDS, type ExportModelAdapter, type ExportResult, type ExportableResource, GrpcServer, type ImportModelAdapter, type ImportResult, type ImportResultEntry, ManagedModule, ModuleError, ModuleLifecycleStage, type RequestHandlers, RouteBuilder, type RouterRequestHandler, type RouterRequestHandlerCallback, RoutingManager, type SanitizeForExportOptions, type SocketEventHandler, type SocketRequestHandler, type SocketRequestHandlerCallback, type SocketRequestHandlers, type UserHydrator, type UserResolver, addServiceToServer, containsRedactedMarker, convictConfigParser, createParsedRouterRequest, createServer, createUserHydrator, exportModel, getAuthMiddlewareKind, hydrateContextUser, importModel, initializeSdk, linearBackoffTimeout, linearBackoffTimeoutAsync, mapHydrationErrorCode, merge, readConduitPeersManifest, reconcileStoredModuleConfig, redactSensitiveConfig, restoreRedactedSecrets, sanitizeDocumentsForExport, selectVerificationKey, shouldHydrateUser, stableConfigJson, storedConfigsEquivalent, stripInternalFields, verifyAccessToken, wrapFunctionsAsync, wrapGrpcFunctions, wrapRouterGrpcFunction };
|