Skip to content

Commit 3fe9732

Browse files
committed
feat(server): migrate rpc api handler and express adapter
1 parent 68e0072 commit 3fe9732

File tree

30 files changed

+2166
-27
lines changed

30 files changed

+2166
-27
lines changed

BREAKINGCHANGES.md

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -1,3 +1,3 @@
1-
1. `auth()` cannot be directly compared with a relation anymore
2-
2. `update` and `delete` policy rejection throws `NotFoundError`
3-
3. non-optional to-one relation doesn't automatically filter parent read when evaluating access policies
1+
1. `update` and `delete` policy rejection throws `NotFoundError`
2+
1. `check()` ORM api has been removed
3+
1. non-optional to-one relation doesn't automatically filter parent read when evaluating access policies

TODO.md

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -86,7 +86,7 @@
8686
- [ ] DbNull vs JsonNull
8787
- [ ] Migrate to tsdown
8888
- [x] @default validation
89-
- [ ] Benchmark
89+
- [x] Benchmark
9090
- [x] Plugin
9191
- [x] Post-mutation hooks should be called after transaction is committed
9292
- [x] TypeDef and mixin

packages/common-helpers/src/index.ts

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,7 @@
11
export * from './is-plain-object';
22
export * from './lower-case-first';
33
export * from './param-case';
4+
export * from './safe-json-stringify';
45
export * from './sleep';
56
export * from './tiny-invariant';
67
export * from './upper-case-first';
Lines changed: 12 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,12 @@
1+
/**
2+
* A safe JSON stringify that handles bigint values.
3+
*/
4+
export function safeJSONStringify(value: unknown) {
5+
return JSON.stringify(value, (_, v) => {
6+
if (typeof v === 'bigint') {
7+
return v.toString();
8+
} else {
9+
return v;
10+
}
11+
});
12+
}

packages/plugins/policy/src/policy-handler.ts

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -104,7 +104,7 @@ export class PolicyHandler<Schema extends SchemaDef> extends OperationNodeTransf
104104
if (constCondition === true) {
105105
needCheckPreCreate = false;
106106
} else if (constCondition === false) {
107-
throw new RejectedByPolicyError(mutationModel);
107+
throw new RejectedByPolicyError(mutationModel, RejectedByPolicyReason.NO_ACCESS);
108108
}
109109
}
110110

@@ -621,7 +621,7 @@ export class PolicyHandler<Schema extends SchemaDef> extends OperationNodeTransf
621621

622622
const result = await proceed(preCreateCheck);
623623
if (!result.rows[0]?.$condition) {
624-
throw new RejectedByPolicyError(model);
624+
throw new RejectedByPolicyError(model, RejectedByPolicyReason.NO_ACCESS);
625625
}
626626
}
627627

packages/runtime/package.json

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -64,7 +64,7 @@
6464
"dependencies": {
6565
"@paralleldrive/cuid2": "^2.2.2",
6666
"@zenstackhq/common-helpers": "workspace:*",
67-
"decimal.js": "^10.4.3",
67+
"decimal.js": "catalog:",
6868
"json-stable-stringify": "^1.3.0",
6969
"nanoid": "^5.0.9",
7070
"toposort": "^2.0.2",

packages/runtime/src/client/crud/dialects/postgresql.ts

Lines changed: 6 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -111,7 +111,12 @@ export class PostgresCrudDialect<Schema extends SchemaDef> extends BaseCrudDiale
111111
}
112112

113113
private transformOutputBytes(value: unknown) {
114-
return Buffer.isBuffer(value) ? Uint8Array.from(value) : value;
114+
return Buffer.isBuffer(value)
115+
? Uint8Array.from(value)
116+
: // node-pg encode bytea as hex string prefixed with \x when embedded in JSON
117+
typeof value === 'string' && value.startsWith('\\x')
118+
? Uint8Array.from(Buffer.from(value.slice(2), 'hex'))
119+
: value;
115120
}
116121

117122
override buildRelationSelection(

packages/runtime/src/client/crud/validator/index.ts

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -232,6 +232,7 @@ export class InputValidator<Schema extends SchemaDef> {
232232
const { error, data } = schema.safeParse(args);
233233
if (error) {
234234
throw new InputValidationError(
235+
model,
235236
`Invalid ${operation} args for model "${model}": ${formatError(error)}`,
236237
error,
237238
);

packages/runtime/src/client/errors.ts

Lines changed: 9 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -7,7 +7,11 @@ export class ZenStackError extends Error {}
77
* Error thrown when input validation fails.
88
*/
99
export class InputValidationError extends ZenStackError {
10-
constructor(message: string, cause?: unknown) {
10+
constructor(
11+
public readonly model: string,
12+
message: string,
13+
cause?: unknown,
14+
) {
1115
super(message, { cause });
1216
}
1317
}
@@ -30,7 +34,10 @@ export class InternalError extends ZenStackError {}
3034
* Error thrown when an entity is not found.
3135
*/
3236
export class NotFoundError extends ZenStackError {
33-
constructor(model: string, details?: string) {
37+
constructor(
38+
public readonly model: string,
39+
details?: string,
40+
) {
3441
super(`Entity not found for model "${model}"${details ? `: ${details}` : ''}`);
3542
}
3643
}

packages/runtime/src/client/helpers/schema-db-pusher.ts

Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -294,9 +294,16 @@ export class SchemaDbPusher<Schema extends SchemaDef> {
294294
(cb) => {
295295
if (fieldDef.relation?.onDelete) {
296296
cb = cb.onDelete(this.mapCascadeAction(fieldDef.relation.onDelete));
297+
} else if (fieldDef.optional) {
298+
cb = cb.onDelete('set null');
299+
} else {
300+
cb = cb.onDelete('restrict');
297301
}
302+
298303
if (fieldDef.relation?.onUpdate) {
299304
cb = cb.onUpdate(this.mapCascadeAction(fieldDef.relation.onUpdate));
305+
} else {
306+
cb = cb.onUpdate('cascade');
300307
}
301308
return cb;
302309
},

0 commit comments

Comments
 (0)