@codixus/server 0.1.2 → 0.1.4
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 +393 -82
- package/dist/index.cjs.map +1 -1
- package/dist/index.d.cts +97 -4
- package/dist/index.d.ts +97 -4
- package/dist/index.js +392 -82
- package/dist/index.js.map +1 -1
- package/package.json +1 -1
package/dist/index.d.ts
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
import { Request, Response, NextFunction, Router } from 'express';
|
|
2
2
|
import * as mongodb from 'mongodb';
|
|
3
|
-
import { Document, Collection, Filter, Sort,
|
|
3
|
+
import { Db, Document, Collection, Filter, Sort, ClientSession, UpdateFilter, AnyBulkWriteOperation, BulkWriteOptions } from 'mongodb';
|
|
4
4
|
import { TokenPair, AuthUser } from '@codixus/shared';
|
|
5
5
|
export { ApiResponse, AuthTokenRequest, AuthTokenResponse, AuthUser, CodixusError, DeviceInfo, DeviceMetadata, ErrorCodes, TokenPair, TokenPayload } from '@codixus/shared';
|
|
6
6
|
import { JWTPayload } from 'jose';
|
|
@@ -28,6 +28,24 @@ declare class JwtService {
|
|
|
28
28
|
static hashToken(token: string): string;
|
|
29
29
|
}
|
|
30
30
|
|
|
31
|
+
interface BannedDevice {
|
|
32
|
+
_id: string;
|
|
33
|
+
reason?: string;
|
|
34
|
+
bannedAt: Date;
|
|
35
|
+
}
|
|
36
|
+
declare class BanService {
|
|
37
|
+
private collection;
|
|
38
|
+
private refreshTokensCol;
|
|
39
|
+
constructor(db: Db);
|
|
40
|
+
ban(deviceId: string, reason?: string): Promise<void>;
|
|
41
|
+
unban(deviceId: string): Promise<void>;
|
|
42
|
+
isBanned(deviceId: string): Promise<boolean>;
|
|
43
|
+
list(options?: {
|
|
44
|
+
limit?: number;
|
|
45
|
+
offset?: number;
|
|
46
|
+
}): Promise<BannedDevice[]>;
|
|
47
|
+
}
|
|
48
|
+
|
|
31
49
|
declare global {
|
|
32
50
|
namespace Express {
|
|
33
51
|
interface Request {
|
|
@@ -38,7 +56,7 @@ declare global {
|
|
|
38
56
|
interface GuardOptions {
|
|
39
57
|
optional?: boolean;
|
|
40
58
|
}
|
|
41
|
-
declare function createGuard(jwt: JwtService): (options?: GuardOptions) => (req: Request, res: Response, next: NextFunction) => Promise<void>;
|
|
59
|
+
declare function createGuard(jwt: JwtService, banService?: BanService): (options?: GuardOptions) => (req: Request, res: Response, next: NextFunction) => Promise<void>;
|
|
42
60
|
|
|
43
61
|
interface AuthRouterConfig {
|
|
44
62
|
usersCollection: string;
|
|
@@ -163,13 +181,88 @@ interface RateLimitConfig {
|
|
|
163
181
|
message?: string;
|
|
164
182
|
}
|
|
165
183
|
|
|
184
|
+
/**
|
|
185
|
+
* A Request on which `req.user` has been populated by `auth.guard()`. Used in
|
|
186
|
+
* `allowRead` / `allowWrite` / `allowDelete` hook signatures so consumers
|
|
187
|
+
* don't need `req.user!` non-null assertions at the call site.
|
|
188
|
+
*/
|
|
189
|
+
type AuthenticatedRequest = Request & {
|
|
190
|
+
user: AuthUser;
|
|
191
|
+
};
|
|
192
|
+
type HookResult = boolean | Promise<boolean>;
|
|
193
|
+
/**
|
|
194
|
+
* Stable machine-readable codes returned alongside human-readable `error`
|
|
195
|
+
* strings. Consumers should switch on `code`, not the message.
|
|
196
|
+
*/
|
|
197
|
+
declare const RestErrorCode: {
|
|
198
|
+
readonly CreateDisabled: "CREATE_DISABLED";
|
|
199
|
+
readonly UpdateDisabled: "UPDATE_DISABLED";
|
|
200
|
+
readonly DeleteDisabled: "DELETE_DISABLED";
|
|
201
|
+
readonly ReadForbidden: "READ_FORBIDDEN";
|
|
202
|
+
readonly WriteForbidden: "WRITE_FORBIDDEN";
|
|
203
|
+
readonly DeleteForbidden: "DELETE_FORBIDDEN";
|
|
204
|
+
readonly NotFound: "NOT_FOUND";
|
|
205
|
+
readonly InvalidFilter: "INVALID_FILTER";
|
|
206
|
+
readonly InvalidSort: "INVALID_SORT";
|
|
207
|
+
readonly InvalidCursor: "INVALID_CURSOR";
|
|
208
|
+
readonly InvalidUpdate: "INVALID_UPDATE";
|
|
209
|
+
readonly InvalidBody: "INVALID_BODY";
|
|
210
|
+
readonly AuthRequired: "AUTH_REQUIRED";
|
|
211
|
+
};
|
|
212
|
+
type RestErrorCode = (typeof RestErrorCode)[keyof typeof RestErrorCode];
|
|
166
213
|
interface RestOptions {
|
|
167
214
|
allowCreate?: boolean;
|
|
168
215
|
allowUpdate?: boolean;
|
|
169
|
-
|
|
216
|
+
/**
|
|
217
|
+
* `true`/`false` toggles delete. A function form receives the current doc
|
|
218
|
+
* and returns whether the caller is allowed to delete it (useful for
|
|
219
|
+
* "author can delete own post" rules).
|
|
220
|
+
*/
|
|
221
|
+
allowDelete?: boolean | ((req: AuthenticatedRequest, doc: Record<string, unknown>) => HookResult);
|
|
170
222
|
maxLimit?: number;
|
|
171
223
|
defaultLimit?: number;
|
|
172
224
|
defaultSort?: Record<string, 1 | -1>;
|
|
225
|
+
/**
|
|
226
|
+
* Field used to scope rows to a tenant/owner. When set, every
|
|
227
|
+
* GET /:id, PATCH /:id, DELETE /:id, and list/count filter is forced
|
|
228
|
+
* to include `{ [ownershipField]: req.user.deviceId }`. Without this
|
|
229
|
+
* option the handlers are unscoped (IDOR-prone). Set to `"_id"` for
|
|
230
|
+
* self-only collections (like users), or `"authorId"` for per-author data.
|
|
231
|
+
*
|
|
232
|
+
* @example
|
|
233
|
+
* // Users can only read/update/delete themselves
|
|
234
|
+
* codixus.rest(User, { ownershipField: "_id" })
|
|
235
|
+
*
|
|
236
|
+
* // Posts are scoped by authorId
|
|
237
|
+
* codixus.rest(Post, { ownershipField: "authorId" })
|
|
238
|
+
*/
|
|
239
|
+
ownershipField?: string;
|
|
240
|
+
/** Top-level keys allowed inside the filter query parameter. */
|
|
241
|
+
queryableFields?: string[];
|
|
242
|
+
/** Field names allowed as sort keys (for `?sort=` and cursor pagination). */
|
|
243
|
+
sortableFields?: string[];
|
|
244
|
+
/** Whitelist of fields writable through PATCH. Reject any others. */
|
|
245
|
+
writableFields?: string[];
|
|
246
|
+
/** Projection for GET responses. Only these fields are returned (plus `_id`). */
|
|
247
|
+
publicFields?: string[];
|
|
248
|
+
/**
|
|
249
|
+
* Comparison operators allowed inside filter values. Defaults to a safe set:
|
|
250
|
+
* `$eq, $ne, $in, $nin, $gt, $gte, $lt, $lte`. Dangerous operators like
|
|
251
|
+
* `$where`, `$regex`, `$expr` are rejected by default.
|
|
252
|
+
*/
|
|
253
|
+
allowedOperators?: string[];
|
|
254
|
+
/**
|
|
255
|
+
* Optional hook — return `false` (or a Promise resolving to `false`) to deny
|
|
256
|
+
* GET /:id after ownership passes. Async is supported so consumers can do
|
|
257
|
+
* role/team lookups against the DB. Note: if guard middleware didn't run,
|
|
258
|
+
* `req.user` may be undefined; check before relying on it.
|
|
259
|
+
*/
|
|
260
|
+
allowRead?: (req: AuthenticatedRequest, doc: Record<string, unknown>) => HookResult;
|
|
261
|
+
/**
|
|
262
|
+
* Optional hook — return `false` (or a Promise resolving to `false`) to deny
|
|
263
|
+
* PATCH /:id after ownership passes. See `allowRead` for async notes.
|
|
264
|
+
*/
|
|
265
|
+
allowWrite?: (req: AuthenticatedRequest, doc: Record<string, unknown>, patch: Record<string, unknown>) => HookResult;
|
|
173
266
|
}
|
|
174
267
|
|
|
175
268
|
interface CodixusServerConfig {
|
|
@@ -237,4 +330,4 @@ declare class CodixusServer {
|
|
|
237
330
|
|
|
238
331
|
declare function validate<T extends z.ZodType>(schema: T): (req: Request, res: Response, next: NextFunction) => void;
|
|
239
332
|
|
|
240
|
-
export { type AuthRouterConfig, CodixusServer, type CodixusServerConfig, type GuardOptions, Model, type ModelDefinition, type ModelType, Query, type RateLimitConfig, type RestOptions, type SigningConfig, SubCollection, model, validate };
|
|
333
|
+
export { type AuthRouterConfig, type AuthenticatedRequest, CodixusServer, type CodixusServerConfig, type GuardOptions, Model, type ModelDefinition, type ModelType, Query, type RateLimitConfig, RestErrorCode, type RestOptions, type SigningConfig, SubCollection, model, validate };
|