@rebasepro/server 0.9.1-canary.29ed165 → 0.9.1-canary.437af5f
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/api/errors.d.ts +1 -16
- package/dist/api/rest/write-validation.d.ts +0 -3
- package/dist/index.es.js +5 -43
- package/dist/index.es.js.map +1 -1
- package/package.json +5 -5
package/dist/api/errors.d.ts
CHANGED
|
@@ -9,24 +9,9 @@ export declare class ApiError extends Error {
|
|
|
9
9
|
readonly statusCode: number;
|
|
10
10
|
readonly code: string;
|
|
11
11
|
readonly details?: unknown;
|
|
12
|
-
|
|
13
|
-
* Whether this outcome is a routine part of normal operation rather than
|
|
14
|
-
* something an operator should look at. Expected errors log at debug; every
|
|
15
|
-
* other operational error logs at warn.
|
|
16
|
-
*
|
|
17
|
-
* The motivating case is `POST /auth/refresh` with no session: clients
|
|
18
|
-
* refresh on page load before they know whether one exists, so every
|
|
19
|
-
* anonymous page view is a 401 — correct, and not worth a warning line.
|
|
20
|
-
*/
|
|
21
|
-
readonly expected: boolean;
|
|
22
|
-
constructor(statusCode: number, code: string, message: string, details?: unknown, expected?: boolean);
|
|
12
|
+
constructor(statusCode: number, code: string, message: string, details?: unknown);
|
|
23
13
|
static badRequest(message: string, code?: string, details?: unknown): ApiError;
|
|
24
14
|
static unauthorized(message: string, code?: string): ApiError;
|
|
25
|
-
/**
|
|
26
|
-
* A 401 that is a normal outcome, not an incident — logged at debug.
|
|
27
|
-
* See {@link ApiError.expected}.
|
|
28
|
-
*/
|
|
29
|
-
static unauthenticated(message: string, code?: string): ApiError;
|
|
30
15
|
static forbidden(message: string, code?: string): ApiError;
|
|
31
16
|
static notFound(message: string, code?: string): ApiError;
|
|
32
17
|
static conflict(message: string, code?: string): ApiError;
|
|
@@ -12,11 +12,8 @@ import { CollectionConfig } from "@rebasepro/types";
|
|
|
12
12
|
* columns, so the set is exact);
|
|
13
13
|
* - the foreign-key column behind an owning relation, which callers may write
|
|
14
14
|
* directly instead of through the relation property;
|
|
15
|
-
* - anything named in `options.extraKnownFields` — for an auth collection the
|
|
16
|
-
* credential keys the auth adapter consumes before a row is ever built;
|
|
17
15
|
* - nothing else. `id` in particular is not automatically known — see below.
|
|
18
16
|
*/
|
|
19
17
|
export declare function assertKnownWriteFields(values: Record<string, unknown>, collection: CollectionConfig, options?: {
|
|
20
18
|
rowIndex?: number;
|
|
21
|
-
extraKnownFields?: readonly string[];
|
|
22
19
|
}): void;
|
package/dist/index.es.js
CHANGED
|
@@ -3539,23 +3539,12 @@ var ApiError = class ApiError extends Error {
|
|
|
3539
3539
|
statusCode;
|
|
3540
3540
|
code;
|
|
3541
3541
|
details;
|
|
3542
|
-
|
|
3543
|
-
* Whether this outcome is a routine part of normal operation rather than
|
|
3544
|
-
* something an operator should look at. Expected errors log at debug; every
|
|
3545
|
-
* other operational error logs at warn.
|
|
3546
|
-
*
|
|
3547
|
-
* The motivating case is `POST /auth/refresh` with no session: clients
|
|
3548
|
-
* refresh on page load before they know whether one exists, so every
|
|
3549
|
-
* anonymous page view is a 401 — correct, and not worth a warning line.
|
|
3550
|
-
*/
|
|
3551
|
-
expected;
|
|
3552
|
-
constructor(statusCode, code, message, details, expected = false) {
|
|
3542
|
+
constructor(statusCode, code, message, details) {
|
|
3553
3543
|
super(message);
|
|
3554
3544
|
this.name = "ApiError";
|
|
3555
3545
|
this.statusCode = statusCode;
|
|
3556
3546
|
this.code = code;
|
|
3557
3547
|
this.details = details;
|
|
3558
|
-
this.expected = expected;
|
|
3559
3548
|
}
|
|
3560
3549
|
static badRequest(message, code = "BAD_REQUEST", details) {
|
|
3561
3550
|
return new ApiError(400, code, message, details);
|
|
@@ -3563,13 +3552,6 @@ var ApiError = class ApiError extends Error {
|
|
|
3563
3552
|
static unauthorized(message, code = "UNAUTHORIZED") {
|
|
3564
3553
|
return new ApiError(401, code, message);
|
|
3565
3554
|
}
|
|
3566
|
-
/**
|
|
3567
|
-
* A 401 that is a normal outcome, not an incident — logged at debug.
|
|
3568
|
-
* See {@link ApiError.expected}.
|
|
3569
|
-
*/
|
|
3570
|
-
static unauthenticated(message, code = "UNAUTHORIZED") {
|
|
3571
|
-
return new ApiError(401, code, message, void 0, true);
|
|
3572
|
-
}
|
|
3573
3555
|
static forbidden(message, code = "FORBIDDEN") {
|
|
3574
3556
|
return new ApiError(403, code, message);
|
|
3575
3557
|
}
|
|
@@ -3602,10 +3584,7 @@ var errorHandler = (err, c) => {
|
|
|
3602
3584
|
const error = err;
|
|
3603
3585
|
const reqId = typeof c.get === "function" ? c.get("requestId") : void 0;
|
|
3604
3586
|
if (error instanceof ApiError || error.name === "ApiError") {
|
|
3605
|
-
|
|
3606
|
-
const line = `[API] ${c.req.method} ${c.req.path} → ${error.statusCode} ${error.code}: ${error.message}` + (reqId ? ` [${reqId}]` : "");
|
|
3607
|
-
if (expected) logger.debug(line);
|
|
3608
|
-
else logger.warn(`⚠️ ${line}`);
|
|
3587
|
+
logger.warn(`⚠️ [API] ${c.req.method} ${c.req.path} → ${error.statusCode} ${error.code}: ${error.message}` + (reqId ? ` [${reqId}]` : ""));
|
|
3609
3588
|
return c.json({ error: {
|
|
3610
3589
|
message: error.message,
|
|
3611
3590
|
code: error.code || "INTERNAL_ERROR",
|
|
@@ -3847,8 +3826,6 @@ function parseQueryOptions(query) {
|
|
|
3847
3826
|
* columns, so the set is exact);
|
|
3848
3827
|
* - the foreign-key column behind an owning relation, which callers may write
|
|
3849
3828
|
* directly instead of through the relation property;
|
|
3850
|
-
* - anything named in `options.extraKnownFields` — for an auth collection the
|
|
3851
|
-
* credential keys the auth adapter consumes before a row is ever built;
|
|
3852
3829
|
* - nothing else. `id` in particular is not automatically known — see below.
|
|
3853
3830
|
*/
|
|
3854
3831
|
function assertKnownWriteFields(values, collection, options) {
|
|
@@ -3856,7 +3833,6 @@ function assertKnownWriteFields(values, collection, options) {
|
|
|
3856
3833
|
if (!collection.properties || Object.keys(collection.properties).length === 0) return;
|
|
3857
3834
|
const known = new Set(Object.keys(collection.properties));
|
|
3858
3835
|
for (const relation of Object.values(resolveCollectionRelations(collection))) if (relation.localKey) known.add(relation.localKey);
|
|
3859
|
-
for (const field of options?.extraKnownFields ?? []) known.add(field);
|
|
3860
3836
|
const unknown = Object.keys(values).filter((key) => !known.has(key));
|
|
3861
3837
|
if (unknown.length === 0) return;
|
|
3862
3838
|
const where = options?.rowIndex !== void 0 ? `Row ${options.rowIndex}: ` : "";
|
|
@@ -4105,13 +4081,9 @@ var RestApiGenerator = class {
|
|
|
4105
4081
|
const body = await parseJsonBody(c);
|
|
4106
4082
|
const isAuth = collection.auth;
|
|
4107
4083
|
const isAuthCollection = isAuth === true || isAuth && typeof isAuth === "object" && isAuth.enabled === true;
|
|
4108
|
-
const collectionAuthConfig = typeof isAuth === "object" ? isAuth : void 0;
|
|
4109
4084
|
if (!isAuthCollection) assertKnownWriteFields(body, resolvedCollection);
|
|
4110
|
-
else {
|
|
4111
|
-
const contract = this.authAdapter?.describeUserCreationContract?.(collectionAuthConfig);
|
|
4112
|
-
if (contract?.validate) assertKnownWriteFields(body, resolvedCollection, { extraKnownFields: contract.extraFields });
|
|
4113
|
-
}
|
|
4114
4085
|
if (isAuthCollection && this.authAdapter?.prepareUserCreation) {
|
|
4086
|
+
const collectionAuthConfig = typeof isAuth === "object" ? isAuth : void 0;
|
|
4115
4087
|
const prepared = await this.authAdapter.prepareUserCreation(body, collectionAuthConfig);
|
|
4116
4088
|
const entity = await driver.save({
|
|
4117
4089
|
path,
|
|
@@ -10375,7 +10347,7 @@ function createAuthRoutes(config) {
|
|
|
10375
10347
|
oldPassword: string().min(1, "Old password is required").max(128),
|
|
10376
10348
|
newPassword: string().min(1, "New password is required").max(128)
|
|
10377
10349
|
});
|
|
10378
|
-
const refreshSchema = object({ refreshToken: string().
|
|
10350
|
+
const refreshSchema = object({ refreshToken: config.cookieAuth ? string().optional() : string().min(1, "Refresh token is required") });
|
|
10379
10351
|
object({ refreshToken: string().optional() });
|
|
10380
10352
|
object({
|
|
10381
10353
|
displayName: string().max(255).optional(),
|
|
@@ -10759,7 +10731,7 @@ function createAuthRoutes(config) {
|
|
|
10759
10731
|
*/
|
|
10760
10732
|
router.post("/refresh", async (c) => {
|
|
10761
10733
|
const refreshToken = readRefreshToken(c, parseBody(refreshSchema, await c.req.json().catch(() => ({}))), config.cookieAuth);
|
|
10762
|
-
if (!refreshToken) throw ApiError.
|
|
10734
|
+
if (!refreshToken) throw ApiError.badRequest("Refresh token is required", "INVALID_INPUT");
|
|
10763
10735
|
const tokenHash = hashRefreshToken(refreshToken);
|
|
10764
10736
|
const storedToken = await authRepo.findRefreshTokenByHash(tokenHash);
|
|
10765
10737
|
if (!storedToken) {
|
|
@@ -11281,16 +11253,6 @@ function createBuiltinAuthAdapter(config) {
|
|
|
11281
11253
|
collectionAuthConfig: collectionAuth ?? collectionAuthConfig
|
|
11282
11254
|
});
|
|
11283
11255
|
},
|
|
11284
|
-
describeUserCreationContract(collectionAuth) {
|
|
11285
|
-
if ((collectionAuth ?? collectionAuthConfig)?.onCreateUser || resolvedOps.onAdminCreateUser) return {
|
|
11286
|
-
validate: false,
|
|
11287
|
-
extraFields: []
|
|
11288
|
-
};
|
|
11289
|
-
return {
|
|
11290
|
-
validate: true,
|
|
11291
|
-
extraFields: ["password"]
|
|
11292
|
-
};
|
|
11293
|
-
},
|
|
11294
11256
|
async finalizeUserCreation(entity, clearPassword) {
|
|
11295
11257
|
return finalizeAdminUserCreation(entity, clearPassword, {
|
|
11296
11258
|
authRepo: authRepository,
|