@edium/halifax 2.1.0 → 2.2.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/CHANGELOG.md +64 -1
- package/README.md +102 -17
- package/README_AUTH.md +38 -0
- package/README_AUTOCRUD.md +5 -5
- package/README_CLASSES.md +322 -0
- package/README_HOOKS.md +275 -0
- package/README_INTERFACES.md +601 -0
- package/README_OPENAPI.md +471 -0
- package/README_REPO_ADAPTERS.md +77 -0
- package/README_TYPES.md +114 -0
- package/dist/adapters/orm/drizzle/DrizzleAdapter.d.ts +128 -0
- package/dist/adapters/orm/drizzle/DrizzleAdapter.js +255 -0
- package/dist/adapters/orm/drizzle/astToDrizzle.d.ts +21 -0
- package/dist/adapters/orm/drizzle/astToDrizzle.js +121 -0
- package/dist/adapters/orm/drizzle/index.d.ts +4 -0
- package/dist/adapters/orm/drizzle/index.js +2 -0
- package/dist/adapters/orm/prisma/PrismaAdapter.d.ts +1 -1
- package/dist/adapters/orm/prisma/PrismaAdapter.js +24 -1
- package/dist/adapters/orm/prisma/astToPrisma.d.ts +1 -2
- package/dist/adapters/orm/prisma/astToPrisma.js +1 -3
- package/dist/adapters/orm/prisma/helpers.js +1 -1
- package/dist/adapters/orm/prisma/types.d.ts +11 -11
- package/dist/auth/AuthStrategy.d.ts +6 -189
- package/dist/auth/AuthStrategy.js +4 -220
- package/dist/auth/strategies/AllowAllAuthStrategy.d.ts +6 -0
- package/dist/auth/strategies/AllowAllAuthStrategy.js +6 -0
- package/dist/auth/strategies/ApiKeyAuthStrategy.d.ts +25 -0
- package/dist/auth/strategies/ApiKeyAuthStrategy.js +39 -0
- package/dist/auth/strategies/JwtClaimsAuthStrategy.d.ts +32 -0
- package/dist/auth/strategies/JwtClaimsAuthStrategy.js +52 -0
- package/dist/auth/strategies/PassportStrategies.d.ts +94 -0
- package/dist/auth/strategies/PassportStrategies.js +142 -0
- package/dist/auth/strategies/types.d.ts +70 -0
- package/dist/core/crudRouter.d.ts +11 -18
- package/dist/core/crudRouter.js +95 -390
- package/dist/core/fields.d.ts +8 -0
- package/dist/core/fields.js +14 -0
- package/dist/core/handlerUtils.d.ts +70 -0
- package/dist/core/handlerUtils.js +193 -0
- package/dist/core/handlers/create.d.ts +3 -0
- package/dist/core/handlers/create.js +26 -0
- package/dist/core/handlers/deleteMany.d.ts +3 -0
- package/dist/core/handlers/deleteMany.js +24 -0
- package/dist/core/handlers/deleteOne.d.ts +3 -0
- package/dist/core/handlers/deleteOne.js +19 -0
- package/dist/core/handlers/query.d.ts +3 -0
- package/dist/core/handlers/query.js +23 -0
- package/dist/core/handlers/readMany.d.ts +3 -0
- package/dist/core/handlers/readMany.js +18 -0
- package/dist/core/handlers/readOne.d.ts +3 -0
- package/dist/core/handlers/readOne.js +23 -0
- package/dist/core/handlers/updateMany.d.ts +3 -0
- package/dist/core/handlers/updateMany.js +34 -0
- package/dist/core/handlers/updateOne.d.ts +3 -0
- package/dist/core/handlers/updateOne.js +20 -0
- package/dist/core/handlers/upsertOne.d.ts +3 -0
- package/dist/core/handlers/upsertOne.js +20 -0
- package/dist/core/hooks.d.ts +217 -0
- package/dist/core/queryString.js +1 -1
- package/dist/core/types.d.ts +38 -29
- package/dist/core/validation.d.ts +1 -2
- package/dist/core/validation.js +1 -3
- package/dist/index.d.ts +3 -6
- package/dist/index.js +3 -6
- package/dist/openapi/generateDocsHtml.d.ts +1 -0
- package/dist/openapi/generateDocsHtml.js +47 -0
- package/dist/openapi/index.d.ts +3 -0
- package/dist/openapi/index.js +2 -0
- package/dist/openapi/specGenerator.d.ts +149 -0
- package/dist/openapi/specGenerator.js +770 -0
- package/package.json +38 -22
- package/dist/enums/SqlComparison.d.ts +0 -28
- package/dist/enums/SqlComparison.js +0 -29
- package/dist/enums/SqlOperator.d.ts +0 -5
- package/dist/enums/SqlOperator.js +0 -6
- package/dist/enums/SqlOrder.d.ts +0 -5
- package/dist/enums/SqlOrder.js +0 -6
- package/dist/interfaces/IQueryFilter.d.ts +0 -17
- package/dist/interfaces/IQueryOptions.d.ts +0 -20
- package/dist/interfaces/ISort.d.ts +0 -8
- package/dist/interfaces/ISort.js +0 -1
- /package/dist/{interfaces/IQueryFilter.js → auth/strategies/types.js} +0 -0
- /package/dist/{interfaces/IQueryOptions.js → core/hooks.js} +0 -0
|
@@ -0,0 +1,94 @@
|
|
|
1
|
+
import type { HttpRequest } from '../../core/types.js';
|
|
2
|
+
import type { AuthContext, AuthorizeParams, AuthStrategy, SecurityScheme } from './types.js';
|
|
3
|
+
/** Minimal structural interface for a Passport.js instance (avoids a hard dependency on `passport`). */
|
|
4
|
+
export interface PassportLike {
|
|
5
|
+
/**
|
|
6
|
+
* Authenticates a request using the named strategy.
|
|
7
|
+
* @param strategy - Name of the registered Passport strategy.
|
|
8
|
+
* @param options - Authentication options (e.g. `{ session: false }`).
|
|
9
|
+
* @param callback - Called with the error or authenticated user on completion.
|
|
10
|
+
* @returns An Express-style middleware function that drives the authentication flow.
|
|
11
|
+
*/
|
|
12
|
+
authenticate(strategy: string, options: {
|
|
13
|
+
session: boolean;
|
|
14
|
+
}, callback: (err: unknown, user: unknown) => void): (req: unknown, res: unknown, next: (err?: unknown) => void) => void;
|
|
15
|
+
}
|
|
16
|
+
/** Options for {@link PassportJwtStrategy}. */
|
|
17
|
+
export interface PassportJwtStrategyOptions {
|
|
18
|
+
/** A Passport instance with a JWT strategy registered. */
|
|
19
|
+
passport: PassportLike;
|
|
20
|
+
/** Name of the Passport strategy to invoke (default: `'jwt'`). */
|
|
21
|
+
strategy?: string;
|
|
22
|
+
/** Maps the raw Passport user payload to an {@link AuthContext}. Defaults to reading `sub`/`id`, `roles`, and `permissions`. */
|
|
23
|
+
mapUser?: (user: unknown) => AuthContext;
|
|
24
|
+
}
|
|
25
|
+
/** Delegates authentication to a caller-provided Passport authenticate wrapper. */
|
|
26
|
+
export declare class PassportAuthStrategy implements AuthStrategy {
|
|
27
|
+
private readonly authenticateWithPassport;
|
|
28
|
+
/**
|
|
29
|
+
* @param authenticateWithPassport - Function that calls your Passport strategy
|
|
30
|
+
* and resolves to an {@link AuthContext}.
|
|
31
|
+
*/
|
|
32
|
+
constructor(authenticateWithPassport: (req: HttpRequest) => Promise<AuthContext> | AuthContext);
|
|
33
|
+
/**
|
|
34
|
+
* Delegates to the provided Passport authenticate wrapper.
|
|
35
|
+
* @param req - The incoming HTTP request.
|
|
36
|
+
* @returns The {@link AuthContext} resolved by the wrapper.
|
|
37
|
+
*/
|
|
38
|
+
authenticate(req: HttpRequest): Promise<AuthContext>;
|
|
39
|
+
}
|
|
40
|
+
/** Authenticates via Passport's JWT strategy, invoking it programmatically without Express middleware. */
|
|
41
|
+
export declare class PassportJwtStrategy implements AuthStrategy {
|
|
42
|
+
private readonly passport;
|
|
43
|
+
private readonly strategy;
|
|
44
|
+
private readonly mapUser;
|
|
45
|
+
/** @param options - Passport instance, optional strategy name, and optional user mapper. */
|
|
46
|
+
constructor(options: PassportJwtStrategyOptions);
|
|
47
|
+
/**
|
|
48
|
+
* Runs the Passport JWT authenticate handler and resolves to an {@link AuthContext}.
|
|
49
|
+
* @param req - The incoming HTTP request (must carry a `raw` property for Passport to read).
|
|
50
|
+
* @returns The resolved {@link AuthContext}.
|
|
51
|
+
* @throws {@link AuthenticationError} when Passport rejects the token or returns no user.
|
|
52
|
+
*/
|
|
53
|
+
authenticate(req: HttpRequest): Promise<AuthContext>;
|
|
54
|
+
/**
|
|
55
|
+
* Returns `true` when the auth context satisfies all required permissions.
|
|
56
|
+
* @param params - Authorization context including required permissions and the resolved auth.
|
|
57
|
+
* @returns `true` when all required permissions are satisfied, `false` otherwise.
|
|
58
|
+
*/
|
|
59
|
+
authorize(params: AuthorizeParams): boolean;
|
|
60
|
+
openApiScheme(): SecurityScheme;
|
|
61
|
+
}
|
|
62
|
+
/**
|
|
63
|
+
* Authenticates using Passport session cookies.
|
|
64
|
+
*
|
|
65
|
+
* Passport's session middleware must run before Halifax and populate `req.user`
|
|
66
|
+
* automatically — this strategy simply reads that value and maps it to an
|
|
67
|
+
* {@link AuthContext}. No passport instance is needed here.
|
|
68
|
+
*
|
|
69
|
+
* Prerequisites (add to your Express app before mounting Halifax):
|
|
70
|
+
* ```ts
|
|
71
|
+
* app.use(session({ ... }))
|
|
72
|
+
* app.use(passport.initialize())
|
|
73
|
+
* app.use(passport.session())
|
|
74
|
+
* ```
|
|
75
|
+
*/
|
|
76
|
+
export declare class PassportSessionStrategy implements AuthStrategy {
|
|
77
|
+
private readonly mapUser;
|
|
78
|
+
/** @param mapUser - Optional function to convert the raw session user to an {@link AuthContext}. */
|
|
79
|
+
constructor(mapUser?: (user: unknown) => AuthContext);
|
|
80
|
+
/**
|
|
81
|
+
* Reads `req.raw.user` (set by Passport session middleware) and maps it to an {@link AuthContext}.
|
|
82
|
+
* @param req - The incoming HTTP request whose `raw.user` property holds the session user.
|
|
83
|
+
* @returns The mapped {@link AuthContext}.
|
|
84
|
+
* @throws {@link AuthenticationError} when `req.raw.user` is absent (not authenticated).
|
|
85
|
+
*/
|
|
86
|
+
authenticate(req: HttpRequest): AuthContext;
|
|
87
|
+
/**
|
|
88
|
+
* Returns `true` when the auth context satisfies all required permissions.
|
|
89
|
+
* @param params - Authorization context including required permissions and the resolved auth.
|
|
90
|
+
* @returns `true` when all required permissions are satisfied, `false` otherwise.
|
|
91
|
+
*/
|
|
92
|
+
authorize(params: AuthorizeParams): boolean;
|
|
93
|
+
openApiScheme(): SecurityScheme;
|
|
94
|
+
}
|
|
@@ -0,0 +1,142 @@
|
|
|
1
|
+
import { AuthenticationError } from '../../errors/AuthenticationError.js';
|
|
2
|
+
/**
|
|
3
|
+
* Extracts `userId`, `roles`, `permissions`, and `claims` from a raw Passport user payload.
|
|
4
|
+
* @param user - The raw user object returned by Passport (typically a decoded JWT payload).
|
|
5
|
+
* @returns A fully populated {@link AuthContext}.
|
|
6
|
+
*/
|
|
7
|
+
function defaultMapUser(user) {
|
|
8
|
+
const p = (user ?? {});
|
|
9
|
+
const userId = typeof p.sub === 'string' ? p.sub : typeof p.id === 'string' ? p.id : undefined;
|
|
10
|
+
const ctx = {
|
|
11
|
+
isAuthenticated: true,
|
|
12
|
+
roles: Array.isArray(p.roles) ? p.roles : [],
|
|
13
|
+
permissions: Array.isArray(p.permissions) ? p.permissions : [],
|
|
14
|
+
claims: p
|
|
15
|
+
};
|
|
16
|
+
if (userId !== undefined)
|
|
17
|
+
ctx.userId = userId;
|
|
18
|
+
return ctx;
|
|
19
|
+
}
|
|
20
|
+
function checkPermissions(auth, requiredPermissions) {
|
|
21
|
+
if (!requiredPermissions.length)
|
|
22
|
+
return true;
|
|
23
|
+
const permissions = new Set(auth.permissions ?? []);
|
|
24
|
+
const roles = new Set(auth.roles ?? []);
|
|
25
|
+
return requiredPermissions.every((p) => permissions.has(p) || roles.has(p));
|
|
26
|
+
}
|
|
27
|
+
/** Delegates authentication to a caller-provided Passport authenticate wrapper. */
|
|
28
|
+
export class PassportAuthStrategy {
|
|
29
|
+
authenticateWithPassport;
|
|
30
|
+
/**
|
|
31
|
+
* @param authenticateWithPassport - Function that calls your Passport strategy
|
|
32
|
+
* and resolves to an {@link AuthContext}.
|
|
33
|
+
*/
|
|
34
|
+
constructor(authenticateWithPassport) {
|
|
35
|
+
this.authenticateWithPassport = authenticateWithPassport;
|
|
36
|
+
}
|
|
37
|
+
/**
|
|
38
|
+
* Delegates to the provided Passport authenticate wrapper.
|
|
39
|
+
* @param req - The incoming HTTP request.
|
|
40
|
+
* @returns The {@link AuthContext} resolved by the wrapper.
|
|
41
|
+
*/
|
|
42
|
+
async authenticate(req) {
|
|
43
|
+
return await this.authenticateWithPassport(req);
|
|
44
|
+
}
|
|
45
|
+
}
|
|
46
|
+
/** Authenticates via Passport's JWT strategy, invoking it programmatically without Express middleware. */
|
|
47
|
+
export class PassportJwtStrategy {
|
|
48
|
+
passport;
|
|
49
|
+
strategy;
|
|
50
|
+
mapUser;
|
|
51
|
+
/** @param options - Passport instance, optional strategy name, and optional user mapper. */
|
|
52
|
+
constructor(options) {
|
|
53
|
+
this.passport = options.passport;
|
|
54
|
+
this.strategy = options.strategy ?? 'jwt';
|
|
55
|
+
this.mapUser = options.mapUser ?? defaultMapUser;
|
|
56
|
+
}
|
|
57
|
+
/**
|
|
58
|
+
* Runs the Passport JWT authenticate handler and resolves to an {@link AuthContext}.
|
|
59
|
+
* @param req - The incoming HTTP request (must carry a `raw` property for Passport to read).
|
|
60
|
+
* @returns The resolved {@link AuthContext}.
|
|
61
|
+
* @throws {@link AuthenticationError} when Passport rejects the token or returns no user.
|
|
62
|
+
*/
|
|
63
|
+
async authenticate(req) {
|
|
64
|
+
return new Promise((resolve, reject) => {
|
|
65
|
+
const handler = this.passport.authenticate(this.strategy, { session: false }, (err, user) => {
|
|
66
|
+
if (err) {
|
|
67
|
+
reject(err instanceof Error ? err : new AuthenticationError(String(err)));
|
|
68
|
+
return;
|
|
69
|
+
}
|
|
70
|
+
if (!user) {
|
|
71
|
+
reject(new AuthenticationError('Unauthorized'));
|
|
72
|
+
return;
|
|
73
|
+
}
|
|
74
|
+
resolve(this.mapUser(user));
|
|
75
|
+
});
|
|
76
|
+
handler(req.raw, {}, (err) => {
|
|
77
|
+
if (err)
|
|
78
|
+
reject(err instanceof Error ? err : new AuthenticationError(String(err)));
|
|
79
|
+
});
|
|
80
|
+
});
|
|
81
|
+
}
|
|
82
|
+
/**
|
|
83
|
+
* Returns `true` when the auth context satisfies all required permissions.
|
|
84
|
+
* @param params - Authorization context including required permissions and the resolved auth.
|
|
85
|
+
* @returns `true` when all required permissions are satisfied, `false` otherwise.
|
|
86
|
+
*/
|
|
87
|
+
authorize(params) {
|
|
88
|
+
return checkPermissions(params.auth, params.requiredPermissions);
|
|
89
|
+
}
|
|
90
|
+
openApiScheme() {
|
|
91
|
+
return { type: 'http', scheme: 'bearer', bearerFormat: 'JWT' };
|
|
92
|
+
}
|
|
93
|
+
}
|
|
94
|
+
/**
|
|
95
|
+
* Authenticates using Passport session cookies.
|
|
96
|
+
*
|
|
97
|
+
* Passport's session middleware must run before Halifax and populate `req.user`
|
|
98
|
+
* automatically — this strategy simply reads that value and maps it to an
|
|
99
|
+
* {@link AuthContext}. No passport instance is needed here.
|
|
100
|
+
*
|
|
101
|
+
* Prerequisites (add to your Express app before mounting Halifax):
|
|
102
|
+
* ```ts
|
|
103
|
+
* app.use(session({ ... }))
|
|
104
|
+
* app.use(passport.initialize())
|
|
105
|
+
* app.use(passport.session())
|
|
106
|
+
* ```
|
|
107
|
+
*/
|
|
108
|
+
export class PassportSessionStrategy {
|
|
109
|
+
mapUser;
|
|
110
|
+
/** @param mapUser - Optional function to convert the raw session user to an {@link AuthContext}. */
|
|
111
|
+
constructor(mapUser) {
|
|
112
|
+
this.mapUser = mapUser ?? defaultMapUser;
|
|
113
|
+
}
|
|
114
|
+
/**
|
|
115
|
+
* Reads `req.raw.user` (set by Passport session middleware) and maps it to an {@link AuthContext}.
|
|
116
|
+
* @param req - The incoming HTTP request whose `raw.user` property holds the session user.
|
|
117
|
+
* @returns The mapped {@link AuthContext}.
|
|
118
|
+
* @throws {@link AuthenticationError} when `req.raw.user` is absent (not authenticated).
|
|
119
|
+
*/
|
|
120
|
+
authenticate(req) {
|
|
121
|
+
const user = req.raw != null ? req.raw['user'] : undefined;
|
|
122
|
+
if (!user)
|
|
123
|
+
throw new AuthenticationError('Not authenticated');
|
|
124
|
+
return this.mapUser(user);
|
|
125
|
+
}
|
|
126
|
+
/**
|
|
127
|
+
* Returns `true` when the auth context satisfies all required permissions.
|
|
128
|
+
* @param params - Authorization context including required permissions and the resolved auth.
|
|
129
|
+
* @returns `true` when all required permissions are satisfied, `false` otherwise.
|
|
130
|
+
*/
|
|
131
|
+
authorize(params) {
|
|
132
|
+
return checkPermissions(params.auth, params.requiredPermissions);
|
|
133
|
+
}
|
|
134
|
+
openApiScheme() {
|
|
135
|
+
return {
|
|
136
|
+
type: 'apiKey',
|
|
137
|
+
in: 'cookie',
|
|
138
|
+
name: 'connect.sid',
|
|
139
|
+
description: 'Passport session cookie.'
|
|
140
|
+
};
|
|
141
|
+
}
|
|
142
|
+
}
|
|
@@ -0,0 +1,70 @@
|
|
|
1
|
+
import type { CrudAction, HttpRequest, ResourceDefinition } from '../../core/types.js';
|
|
2
|
+
/** Resolved user identity and access information returned by {@link AuthStrategy.authenticate}. */
|
|
3
|
+
export interface AuthContext {
|
|
4
|
+
/** Unique identifier for the authenticated user. */
|
|
5
|
+
userId?: string;
|
|
6
|
+
/** Roles granted to the user (checked against `requiredPermissions`). */
|
|
7
|
+
roles?: string[];
|
|
8
|
+
/** Explicit permission strings granted to the user. */
|
|
9
|
+
permissions?: string[];
|
|
10
|
+
/** Raw claims from the token or session payload. */
|
|
11
|
+
claims?: Record<string, unknown>;
|
|
12
|
+
/** Always `true` for a successfully authenticated context. */
|
|
13
|
+
isAuthenticated: boolean;
|
|
14
|
+
}
|
|
15
|
+
/** Parameters passed to {@link AuthStrategy.authorize}. */
|
|
16
|
+
export interface AuthorizeParams {
|
|
17
|
+
/** The resolved authentication context for the current request. */
|
|
18
|
+
auth: AuthContext;
|
|
19
|
+
/** The CRUD action being performed. */
|
|
20
|
+
action: CrudAction;
|
|
21
|
+
/** The resource being accessed. */
|
|
22
|
+
resource: ResourceDefinition;
|
|
23
|
+
/** Permissions required for this action on this resource. */
|
|
24
|
+
requiredPermissions: string[];
|
|
25
|
+
/** The incoming request. */
|
|
26
|
+
req: HttpRequest;
|
|
27
|
+
}
|
|
28
|
+
/**
|
|
29
|
+
* An OpenAPI 3.1 security scheme descriptor returned by {@link AuthStrategy.openApiScheme}.
|
|
30
|
+
* The spec generator uses this to populate `components/securitySchemes` and the global
|
|
31
|
+
* `security` requirement — so the Swagger UI "Authorize" button works out of the box.
|
|
32
|
+
*/
|
|
33
|
+
export type SecurityScheme = {
|
|
34
|
+
type: 'apiKey';
|
|
35
|
+
in: 'header' | 'query' | 'cookie';
|
|
36
|
+
name: string;
|
|
37
|
+
description?: string;
|
|
38
|
+
} | {
|
|
39
|
+
type: 'http';
|
|
40
|
+
scheme: 'bearer';
|
|
41
|
+
bearerFormat?: string;
|
|
42
|
+
description?: string;
|
|
43
|
+
} | {
|
|
44
|
+
type: 'http';
|
|
45
|
+
scheme: 'basic';
|
|
46
|
+
description?: string;
|
|
47
|
+
};
|
|
48
|
+
/** Contract for pluggable authentication and authorisation strategies. */
|
|
49
|
+
export interface AuthStrategy {
|
|
50
|
+
/**
|
|
51
|
+
* Authenticate the request and return the caller's identity.
|
|
52
|
+
* @param req - The incoming HTTP request.
|
|
53
|
+
* @returns The resolved {@link AuthContext}, or a promise that resolves to one.
|
|
54
|
+
* @throws {@link AuthenticationError} when the request cannot be authenticated.
|
|
55
|
+
*/
|
|
56
|
+
authenticate(req: HttpRequest): Promise<AuthContext> | AuthContext;
|
|
57
|
+
/**
|
|
58
|
+
* Determine whether the authenticated caller may perform `action`.
|
|
59
|
+
* @param params - Authorization context including the auth, action, resource, and required permissions.
|
|
60
|
+
* @returns `true` to allow, `false` to deny.
|
|
61
|
+
*/
|
|
62
|
+
authorize?(params: AuthorizeParams): Promise<boolean> | boolean;
|
|
63
|
+
/**
|
|
64
|
+
* Describes this strategy's security scheme for OpenAPI spec generation.
|
|
65
|
+
* When implemented, the spec generator automatically wires up `components/securitySchemes`
|
|
66
|
+
* and the global `security` requirement — no manual `OpenApiOptions.securityScheme` needed.
|
|
67
|
+
* Return `undefined` (or omit the method) for unauthenticated / custom strategies.
|
|
68
|
+
*/
|
|
69
|
+
openApiScheme?(): SecurityScheme | undefined;
|
|
70
|
+
}
|
|
@@ -1,7 +1,10 @@
|
|
|
1
1
|
import { type AuthContext, type AuthStrategy } from '../auth/AuthStrategy.js';
|
|
2
2
|
import { type CacheStore } from '../core/cache/index.js';
|
|
3
|
+
import { type OpenApiOptions } from '../openapi/index.js';
|
|
3
4
|
import { type ResourceDefinition } from '../core/types.js';
|
|
4
5
|
import type { HttpRequest, HttpServer } from '../core/types.js';
|
|
6
|
+
import { normalizeError } from '../core/handlerUtils.js';
|
|
7
|
+
export { normalizeError };
|
|
5
8
|
/** Context handed to {@link TenantOptions.resolveId} for the current request. */
|
|
6
9
|
export interface TenantResolveContext {
|
|
7
10
|
/** The resolved authentication context for the request. */
|
|
@@ -22,8 +25,6 @@ export interface TenantOptions {
|
|
|
22
25
|
* derived from the authenticated session/token — never from client-supplied input.
|
|
23
26
|
* Return `null`/`undefined` to signal "no tenant"; combined with {@link TenantOptions.strict}
|
|
24
27
|
* this either denies the request (default) or serves it unscoped.
|
|
25
|
-
* @param ctx - The auth context, request, and resource being accessed.
|
|
26
|
-
* @returns The tenant key, or null/undefined when none applies.
|
|
27
28
|
*/
|
|
28
29
|
resolveId: (ctx: TenantResolveContext) => unknown | Promise<unknown>;
|
|
29
30
|
/**
|
|
@@ -51,10 +52,14 @@ export interface CrudApiOptions {
|
|
|
51
52
|
/**
|
|
52
53
|
* Wrap every success response body under a single key (e.g. `'data'` → `{ "data": <body> }`)
|
|
53
54
|
* for all resources. Per-resource {@link ResourceDefinition.envelope} takes precedence.
|
|
54
|
-
* Error responses are never enveloped.
|
|
55
|
-
* default, and backward compatible.
|
|
55
|
+
* Error responses are never enveloped.
|
|
56
56
|
*/
|
|
57
57
|
envelope?: string | null;
|
|
58
|
+
/**
|
|
59
|
+
* Enable OpenAPI 3.1 spec generation and interactive docs. When set, Halifax registers two
|
|
60
|
+
* additional routes: `GET /openapi.json` (raw spec) and `GET /docs` (Swagger UI).
|
|
61
|
+
*/
|
|
62
|
+
openapi?: OpenApiOptions;
|
|
58
63
|
/**
|
|
59
64
|
* API-wide read-through caching. Provide a `store` (defaults to an in-process
|
|
60
65
|
* {@link InMemoryCacheStore}) and/or a default `ttlSeconds` applied to every resource that
|
|
@@ -76,25 +81,13 @@ export interface CrudApiOptions {
|
|
|
76
81
|
bustHeader?: string;
|
|
77
82
|
};
|
|
78
83
|
}
|
|
79
|
-
/**
|
|
80
|
-
* Converts any thrown value to a structured `{ status, code, message, details }` object.
|
|
81
|
-
* {@link HttpError} subclasses preserve their status; all other errors become 500.
|
|
82
|
-
* @param error - The caught value to normalise (may be any type).
|
|
83
|
-
* @returns A plain object with `status`, `code`, `message`, and optional `details`.
|
|
84
|
-
*/
|
|
85
|
-
export declare function normalizeError(error: unknown): {
|
|
86
|
-
status: number;
|
|
87
|
-
code: string;
|
|
88
|
-
message: string;
|
|
89
|
-
details?: unknown;
|
|
90
|
-
};
|
|
91
84
|
/**
|
|
92
85
|
* Registers all CRUD routes for every resource on the given HTTP server.
|
|
93
86
|
*
|
|
94
87
|
* Routes are controlled by `resource.permissions` merged with {@link defaultCrudPermissions}.
|
|
95
88
|
*
|
|
96
|
-
* @param server - The HTTP server adapter to register routes on
|
|
89
|
+
* @param server - The HTTP server adapter to register routes on.
|
|
97
90
|
* @param resources - Resource definitions to wire up as CRUD endpoints.
|
|
98
|
-
* @param options - Auth strategy and
|
|
91
|
+
* @param options - Auth strategy, tenant config, envelope, caching, and OpenAPI overrides.
|
|
99
92
|
*/
|
|
100
93
|
export declare function registerCrudApi(server: HttpServer, resources: ResourceDefinition[], options?: CrudApiOptions): void;
|