@vibeorm/runtime 2.0.0-alpha.7 → 2.0.0-alpha.8
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/client.d.ts +17 -0
- package/dist/client.d.ts.map +1 -1
- package/dist/index.d.ts +4 -0
- package/dist/index.d.ts.map +1 -1
- package/dist/index.js +376 -19
- package/dist/index.js.map +8 -6
- package/dist/model-meta.d.ts +7 -0
- package/dist/model-meta.d.ts.map +1 -1
- package/dist/policy.d.ts +40 -0
- package/dist/policy.d.ts.map +1 -0
- package/dist/query-builder.d.ts.map +1 -1
- package/dist/validators.d.ts +59 -0
- package/dist/validators.d.ts.map +1 -0
- package/package.json +3 -3
package/dist/client.d.ts
CHANGED
|
@@ -22,6 +22,8 @@ import type { RelationStrategy } from "./query-builder.ts";
|
|
|
22
22
|
import type { ClientComputedOptions } from "./computed.ts";
|
|
23
23
|
import type { ClientExtensionsOptions } from "./extensions.ts";
|
|
24
24
|
import type { DefineViewFn } from "./views.ts";
|
|
25
|
+
import type { WriteValidators } from "./validators.ts";
|
|
26
|
+
import type { PolicyContextValue } from "./policy.ts";
|
|
25
27
|
/** One executed statement, reported to `ClientOptions.onQuery`. */
|
|
26
28
|
export type QueryEvent = {
|
|
27
29
|
/** Model name, or `null` for raw queries. */
|
|
@@ -52,6 +54,13 @@ export type ClientOptions = {
|
|
|
52
54
|
* v1 parity.
|
|
53
55
|
*/
|
|
54
56
|
readonly distinctOrderByPk?: boolean;
|
|
57
|
+
/**
|
|
58
|
+
* Opt-in write-boundary validators (Standard Schema, per model × field):
|
|
59
|
+
* `{ User: { settings: zodSchema } }`. Run on every write path (nested
|
|
60
|
+
* creates included) before encoding; failure throws VIBE_VALIDATION with
|
|
61
|
+
* the validator's issues in `meta`. Reads are never taxed.
|
|
62
|
+
*/
|
|
63
|
+
readonly validate?: WriteValidators;
|
|
55
64
|
};
|
|
56
65
|
/** Rows are plain objects keyed by field name; the generated client narrows them. */
|
|
57
66
|
export type ClientRow = Record<string, unknown>;
|
|
@@ -128,6 +137,14 @@ export type DynamicClient = {
|
|
|
128
137
|
* it is always present on a built client, transaction clients included.
|
|
129
138
|
*/
|
|
130
139
|
readonly $defineView?: DefineViewFn;
|
|
140
|
+
/**
|
|
141
|
+
* Row scoping (@@policy): bind a per-request context — the returned client
|
|
142
|
+
* AND-s the policy predicate into every query on policied models and forces
|
|
143
|
+
* it into creates. Attached only when the schema declares @@policy.
|
|
144
|
+
*/
|
|
145
|
+
readonly $withPolicy?: (context: Readonly<Record<string, PolicyContextValue>>) => DynamicClient;
|
|
146
|
+
/** Deliberate, greppable full-access escape from policy scoping. */
|
|
147
|
+
readonly $bypassPolicy?: () => DynamicClient;
|
|
131
148
|
};
|
|
132
149
|
/**
|
|
133
150
|
* Build a client for a schema over an adapter.
|
package/dist/client.d.ts.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"client.d.ts","sourceRoot":"","sources":["../src/client.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;;;GAiBG;AAGH,OAAO,KAAK,EAAW,QAAQ,EAAE,MAAM,iBAAiB,CAAC;AAGzD,OAAO,KAAK,EAAE,eAAe,EAAE,kBAAkB,EAAE,MAAM,cAAc,CAAC;AAMxE,OAAO,KAAK,EAAyC,gBAAgB,EAAa,MAAM,oBAAoB,CAAC;AAO7G,OAAO,KAAK,EAAE,qBAAqB,EAAE,MAAM,eAAe,CAAC;AAM3D,OAAO,KAAK,EAEV,uBAAuB,EAGxB,MAAM,iBAAiB,CAAC;AAGzB,OAAO,KAAK,EAAE,YAAY,EAAE,MAAM,YAAY,CAAC;
|
|
1
|
+
{"version":3,"file":"client.d.ts","sourceRoot":"","sources":["../src/client.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;;;GAiBG;AAGH,OAAO,KAAK,EAAW,QAAQ,EAAE,MAAM,iBAAiB,CAAC;AAGzD,OAAO,KAAK,EAAE,eAAe,EAAE,kBAAkB,EAAE,MAAM,cAAc,CAAC;AAMxE,OAAO,KAAK,EAAyC,gBAAgB,EAAa,MAAM,oBAAoB,CAAC;AAO7G,OAAO,KAAK,EAAE,qBAAqB,EAAE,MAAM,eAAe,CAAC;AAM3D,OAAO,KAAK,EAEV,uBAAuB,EAGxB,MAAM,iBAAiB,CAAC;AAGzB,OAAO,KAAK,EAAE,YAAY,EAAE,MAAM,YAAY,CAAC;AAE/C,OAAO,KAAK,EAAE,eAAe,EAAE,MAAM,iBAAiB,CAAC;AAEvD,OAAO,KAAK,EAAE,kBAAkB,EAAE,MAAM,aAAa,CAAC;AAItD,mEAAmE;AACnE,MAAM,MAAM,UAAU,GAAG;IACvB,6CAA6C;IAC7C,QAAQ,CAAC,KAAK,EAAE,MAAM,GAAG,IAAI,CAAC;IAC9B,sDAAsD;IACtD,QAAQ,CAAC,MAAM,EAAE,MAAM,CAAC;IACxB,QAAQ,CAAC,IAAI,EAAE,MAAM,CAAC;IACtB,QAAQ,CAAC,MAAM,EAAE,SAAS,OAAO,EAAE,CAAC;IACpC,QAAQ,CAAC,UAAU,EAAE,MAAM,CAAC;CAC7B,CAAC;AAEF,MAAM,MAAM,aAAa,GAAG;IAC1B,wEAAwE;IACxE,QAAQ,CAAC,OAAO,CAAC,EAAE,CAAC,KAAK,EAAE,UAAU,KAAK,IAAI,CAAC;IAC/C;;;;OAIG;IACH,QAAQ,CAAC,gBAAgB,CAAC,EAAE,gBAAgB,CAAC;IAC7C;;;OAGG;IACH,QAAQ,CAAC,gBAAgB,CAAC,EAAE,OAAO,CAAC;IACpC;;;;OAIG;IACH,QAAQ,CAAC,iBAAiB,CAAC,EAAE,OAAO,CAAC;IACrC;;;;;OAKG;IACH,QAAQ,CAAC,QAAQ,CAAC,EAAE,eAAe,CAAC;CACrC,CAAC;AAEF,qFAAqF;AACrF,MAAM,MAAM,SAAS,GAAG,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,CAAC;AAEhD,mDAAmD;AACnD,MAAM,MAAM,WAAW,GAAG;IAAE,QAAQ,CAAC,KAAK,EAAE,MAAM,CAAA;CAAE,CAAC;AAErD;;;;;GAKG;AACH,MAAM,MAAM,aAAa,GAAG;IAC1B,QAAQ,CAAC,QAAQ,EAAE,CAAC,IAAI,CAAC,EAAE,SAAS,KAAK,OAAO,CAAC,SAAS,EAAE,CAAC,CAAC;IAC9D,QAAQ,CAAC,SAAS,EAAE,CAAC,IAAI,CAAC,EAAE,SAAS,KAAK,OAAO,CAAC,SAAS,GAAG,IAAI,CAAC,CAAC;IACpE,QAAQ,CAAC,gBAAgB,EAAE,CAAC,IAAI,CAAC,EAAE,SAAS,KAAK,OAAO,CAAC,SAAS,CAAC,CAAC;IACpE,QAAQ,CAAC,UAAU,EAAE,CAAC,IAAI,EAAE,SAAS,KAAK,OAAO,CAAC,SAAS,GAAG,IAAI,CAAC,CAAC;IACpE,QAAQ,CAAC,iBAAiB,EAAE,CAAC,IAAI,EAAE,SAAS,KAAK,OAAO,CAAC,SAAS,CAAC,CAAC;IACpE,QAAQ,CAAC,MAAM,EAAE,CAAC,IAAI,EAAE,SAAS,KAAK,OAAO,CAAC,SAAS,GAAG,IAAI,CAAC,CAAC;IAChE,QAAQ,CAAC,UAAU,EAAE,CAAC,IAAI,EAAE,SAAS,KAAK,OAAO,CAAC,WAAW,CAAC,CAAC;IAC/D,QAAQ,CAAC,mBAAmB,EAAE,CAAC,IAAI,EAAE,SAAS,KAAK,OAAO,CAAC,SAAS,EAAE,CAAC,CAAC;IACxE,QAAQ,CAAC,MAAM,EAAE,CAAC,IAAI,EAAE,SAAS,KAAK,OAAO,CAAC,SAAS,CAAC,CAAC;IACzD,QAAQ,CAAC,UAAU,EAAE,CAAC,IAAI,EAAE,SAAS,KAAK,OAAO,CAAC,WAAW,CAAC,CAAC;IAC/D,QAAQ,CAAC,MAAM,EAAE,CAAC,IAAI,EAAE,SAAS,KAAK,OAAO,CAAC,SAAS,CAAC,CAAC;IACzD,QAAQ,CAAC,MAAM,EAAE,CAAC,IAAI,EAAE,SAAS,KAAK,OAAO,CAAC,SAAS,CAAC,CAAC;IACzD,QAAQ,CAAC,UAAU,EAAE,CAAC,IAAI,CAAC,EAAE,SAAS,KAAK,OAAO,CAAC,WAAW,CAAC,CAAC;IAChE,yFAAyF;IACzF,QAAQ,CAAC,KAAK,EAAE,CAAC,IAAI,CAAC,EAAE,SAAS,KAAK,OAAO,CAAC,MAAM,GAAG,MAAM,CAAC,MAAM,EAAE,MAAM,CAAC,CAAC,CAAC;IAC/E,QAAQ,CAAC,SAAS,EAAE,CAAC,IAAI,EAAE,SAAS,KAAK,OAAO,CAAC,SAAS,CAAC,CAAC;IAC5D,QAAQ,CAAC,OAAO,EAAE,CAAC,IAAI,EAAE,SAAS,KAAK,OAAO,CAAC,SAAS,EAAE,CAAC,CAAC;CAC7D,CAAC;AAEF;;;;;;GAMG;AACH,MAAM,MAAM,aAAa,GAAG;IAC1B,oEAAoE;IACpE,QAAQ,CAAC,OAAO,EAAE,QAAQ,CAAC,MAAM,CAAC,MAAM,EAAE,aAAa,CAAC,CAAC,CAAC;IAC1D;;;;OAIG;IACH,QAAQ,CAAC,GAAG,EAAE,CAAC,KAAK,EAAE,OAAO,EAAE,QAAQ,EAAE,CAAC,KAAK,EAAE,UAAU,KAAK,IAAI,KAAK,MAAM,IAAI,CAAC;IACpF;;;;;;OAMG;IACH,QAAQ,CAAC,YAAY,EAAE;QACrB,CAAC,CAAC,EAAE,EAAE,EAAE,CAAC,EAAE,EAAE,aAAa,KAAK,OAAO,CAAC,CAAC,CAAC,EAAE,OAAO,CAAC,EAAE,kBAAkB,GAAG,OAAO,CAAC,CAAC,CAAC,CAAC;QACrF,CAAC,CAAC,SAAS,SAAS,OAAO,EAAE,EAC3B,UAAU,EAAE,SAAS,CAAC,GAAG,CAAC,CAAC,EAC3B,OAAO,CAAC,EAAE,kBAAkB,GAC3B,OAAO,CAAC;YAAE,CAAC,UAAU,CAAC,IAAI,MAAM,CAAC,GAAG,OAAO,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC;SAAE,CAAC,CAAC;KACzD,CAAC;IACF,4EAA4E;IAC5E,QAAQ,CAAC,SAAS,EAAE,CAAC,OAAO,EAAE,oBAAoB,EAAE,GAAG,MAAM,EAAE,OAAO,EAAE,KAAK,OAAO,CAAC,SAAS,EAAE,CAAC,CAAC;IAClG,wDAAwD;IACxD,QAAQ,CAAC,WAAW,EAAE,CAAC,OAAO,EAAE,oBAAoB,EAAE,GAAG,MAAM,EAAE,OAAO,EAAE,KAAK,OAAO,CAAC,MAAM,CAAC,CAAC;IAC/F,QAAQ,CAAC,eAAe,EAAE,CAAC,IAAI,EAAE,MAAM,EAAE,GAAG,MAAM,EAAE,OAAO,EAAE,KAAK,OAAO,CAAC,SAAS,EAAE,CAAC,CAAC;IACvF,QAAQ,CAAC,iBAAiB,EAAE,CAAC,IAAI,EAAE,MAAM,EAAE,GAAG,MAAM,EAAE,OAAO,EAAE,KAAK,OAAO,CAAC,MAAM,CAAC,CAAC;IACpF,QAAQ,CAAC,QAAQ,EAAE,MAAM,OAAO,CAAC,IAAI,CAAC,CAAC;IACvC,QAAQ,CAAC,WAAW,EAAE,MAAM,OAAO,CAAC,IAAI,CAAC,CAAC;IAC1C;;;;;OAKG;IACH,QAAQ,CAAC,WAAW,CAAC,EAAE,YAAY,CAAC;IACpC;;;;OAIG;IACH,QAAQ,CAAC,WAAW,CAAC,EAAE,CAAC,OAAO,EAAE,QAAQ,CAAC,MAAM,CAAC,MAAM,EAAE,kBAAkB,CAAC,CAAC,KAAK,aAAa,CAAC;IAChG,oEAAoE;IACpE,QAAQ,CAAC,aAAa,CAAC,EAAE,MAAM,aAAa,CAAC;CAC9C,CAAC;AAo6CF;;;;;;;;;;GAUG;AACH,wBAAgB,YAAY,CAAC,MAAM,EAAE;IACnC,MAAM,EAAE,QAAQ,CAAC;IACjB,OAAO,EAAE,eAAe,CAAC;IACzB,OAAO,CAAC,EAAE,aAAa,CAAC;IACxB,4GAA4G;IAC5G,UAAU,CAAC,EAAE,uBAAuB,CAAC;IACrC,oGAAoG;IACpG,QAAQ,CAAC,EAAE,qBAAqB,CAAC;CAClC,GAAG,aAAa,CAyDhB"}
|
package/dist/index.d.ts
CHANGED
|
@@ -25,6 +25,10 @@ export type { ClientComputedOptions } from "./computed.ts";
|
|
|
25
25
|
export { assertExtensionManifest, buildConnectHooks, buildExtensionOperatorMap, } from "./extensions.ts";
|
|
26
26
|
export type { ClientExtensionMount, ClientExtensionsOptions, ConnectHook, ExtensionMountContext, } from "./extensions.ts";
|
|
27
27
|
export { ViewResult, attachDefineView, createView } from "./views.ts";
|
|
28
|
+
export { applyWriteValidators, validateWriteData } from "./validators.ts";
|
|
29
|
+
export type { StandardIssue, StandardSchemaV1, WriteValidators } from "./validators.ts";
|
|
30
|
+
export { attachPolicy } from "./policy.ts";
|
|
31
|
+
export type { PolicyContextValue } from "./policy.ts";
|
|
28
32
|
export type { DefineViewFn, ViewClientShape, ViewDefinition, ViewModelDelegate } from "./views.ts";
|
|
29
33
|
export { createClient } from "./client.ts";
|
|
30
34
|
export type { BatchResult, ClientOptions, ClientRow, DynamicClient, ModelDelegate, QueryEvent, } from "./client.ts";
|
package/dist/index.d.ts.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"AAAA;;;;;GAKG;AAIH,OAAO,EAAE,aAAa,EAAE,MAAM,cAAc,CAAC;AAE7C,OAAO,EAAE,KAAK,EAAE,OAAO,EAAE,MAAM,aAAa,CAAC;AAC7C,YAAY,EAAE,KAAK,EAAE,MAAM,aAAa,CAAC;AACzC,YAAY,EACV,eAAe,EACf,cAAc,EACd,WAAW,EACX,WAAW,EACX,kBAAkB,GACnB,MAAM,cAAc,CAAC;AAItB,OAAO,EACL,gBAAgB,EAChB,YAAY,EACZ,oBAAoB,EACpB,cAAc,EACd,YAAY,EACZ,YAAY,EACZ,YAAY,EACZ,YAAY,EACZ,YAAY,GACb,MAAM,iBAAiB,CAAC;AACzB,YAAY,EACV,iBAAiB,EACjB,aAAa,EACb,mBAAmB,EACnB,SAAS,EACT,SAAS,EACT,WAAW,GACZ,MAAM,iBAAiB,CAAC;AAIzB,OAAO,EACL,cAAc,EACd,YAAY,EACZ,eAAe,EACf,aAAa,EACb,oBAAoB,EACpB,YAAY,EACZ,SAAS,EACT,UAAU,EACV,WAAW,EACX,WAAW,EACX,QAAQ,GACT,MAAM,aAAa,CAAC;AACrB,YAAY,EAAE,UAAU,EAAE,WAAW,EAAE,YAAY,EAAE,MAAM,aAAa,CAAC;AAIzE,OAAO,EACL,WAAW,EACX,UAAU,EACV,cAAc,EACd,aAAa,EACb,YAAY,EACZ,kBAAkB,EAClB,kBAAkB,GACnB,MAAM,oBAAoB,CAAC;AAC5B,YAAY,EACV,YAAY,EACZ,kBAAkB,EAClB,aAAa,EACb,oBAAoB,EACpB,WAAW,EACX,SAAS,EACT,gBAAgB,GACjB,MAAM,oBAAoB,CAAC;AAI5B,OAAO,EAAE,mBAAmB,EAAE,wBAAwB,EAAE,MAAM,oBAAoB,CAAC;AACnF,YAAY,EACV,YAAY,EACZ,YAAY,EACZ,YAAY,EACZ,iBAAiB,EACjB,gBAAgB,GACjB,MAAM,oBAAoB,CAAC;AAC5B,OAAO,EAAE,sBAAsB,EAAE,eAAe,EAAE,MAAM,sBAAsB,CAAC;AAC/E,YAAY,EAAE,gBAAgB,EAAE,MAAM,sBAAsB,CAAC;AAI7D,OAAO,EAAE,gBAAgB,EAAE,eAAe,EAAE,gBAAgB,EAAE,MAAM,oBAAoB,CAAC;AACzF,YAAY,EAAE,eAAe,EAAE,YAAY,EAAE,MAAM,oBAAoB,CAAC;AAIxE,OAAO,EAAE,mBAAmB,EAAE,sBAAsB,EAAE,MAAM,eAAe,CAAC;AAC5E,YAAY,EAAE,qBAAqB,EAAE,MAAM,eAAe,CAAC;AAI3D,OAAO,EACL,uBAAuB,EACvB,iBAAiB,EACjB,yBAAyB,GAC1B,MAAM,iBAAiB,CAAC;AACzB,YAAY,EACV,oBAAoB,EACpB,uBAAuB,EACvB,WAAW,EACX,qBAAqB,GACtB,MAAM,iBAAiB,CAAC;AAIzB,OAAO,EAAE,UAAU,EAAE,gBAAgB,EAAE,UAAU,EAAE,MAAM,YAAY,CAAC;
|
|
1
|
+
{"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"AAAA;;;;;GAKG;AAIH,OAAO,EAAE,aAAa,EAAE,MAAM,cAAc,CAAC;AAE7C,OAAO,EAAE,KAAK,EAAE,OAAO,EAAE,MAAM,aAAa,CAAC;AAC7C,YAAY,EAAE,KAAK,EAAE,MAAM,aAAa,CAAC;AACzC,YAAY,EACV,eAAe,EACf,cAAc,EACd,WAAW,EACX,WAAW,EACX,kBAAkB,GACnB,MAAM,cAAc,CAAC;AAItB,OAAO,EACL,gBAAgB,EAChB,YAAY,EACZ,oBAAoB,EACpB,cAAc,EACd,YAAY,EACZ,YAAY,EACZ,YAAY,EACZ,YAAY,EACZ,YAAY,GACb,MAAM,iBAAiB,CAAC;AACzB,YAAY,EACV,iBAAiB,EACjB,aAAa,EACb,mBAAmB,EACnB,SAAS,EACT,SAAS,EACT,WAAW,GACZ,MAAM,iBAAiB,CAAC;AAIzB,OAAO,EACL,cAAc,EACd,YAAY,EACZ,eAAe,EACf,aAAa,EACb,oBAAoB,EACpB,YAAY,EACZ,SAAS,EACT,UAAU,EACV,WAAW,EACX,WAAW,EACX,QAAQ,GACT,MAAM,aAAa,CAAC;AACrB,YAAY,EAAE,UAAU,EAAE,WAAW,EAAE,YAAY,EAAE,MAAM,aAAa,CAAC;AAIzE,OAAO,EACL,WAAW,EACX,UAAU,EACV,cAAc,EACd,aAAa,EACb,YAAY,EACZ,kBAAkB,EAClB,kBAAkB,GACnB,MAAM,oBAAoB,CAAC;AAC5B,YAAY,EACV,YAAY,EACZ,kBAAkB,EAClB,aAAa,EACb,oBAAoB,EACpB,WAAW,EACX,SAAS,EACT,gBAAgB,GACjB,MAAM,oBAAoB,CAAC;AAI5B,OAAO,EAAE,mBAAmB,EAAE,wBAAwB,EAAE,MAAM,oBAAoB,CAAC;AACnF,YAAY,EACV,YAAY,EACZ,YAAY,EACZ,YAAY,EACZ,iBAAiB,EACjB,gBAAgB,GACjB,MAAM,oBAAoB,CAAC;AAC5B,OAAO,EAAE,sBAAsB,EAAE,eAAe,EAAE,MAAM,sBAAsB,CAAC;AAC/E,YAAY,EAAE,gBAAgB,EAAE,MAAM,sBAAsB,CAAC;AAI7D,OAAO,EAAE,gBAAgB,EAAE,eAAe,EAAE,gBAAgB,EAAE,MAAM,oBAAoB,CAAC;AACzF,YAAY,EAAE,eAAe,EAAE,YAAY,EAAE,MAAM,oBAAoB,CAAC;AAIxE,OAAO,EAAE,mBAAmB,EAAE,sBAAsB,EAAE,MAAM,eAAe,CAAC;AAC5E,YAAY,EAAE,qBAAqB,EAAE,MAAM,eAAe,CAAC;AAI3D,OAAO,EACL,uBAAuB,EACvB,iBAAiB,EACjB,yBAAyB,GAC1B,MAAM,iBAAiB,CAAC;AACzB,YAAY,EACV,oBAAoB,EACpB,uBAAuB,EACvB,WAAW,EACX,qBAAqB,GACtB,MAAM,iBAAiB,CAAC;AAIzB,OAAO,EAAE,UAAU,EAAE,gBAAgB,EAAE,UAAU,EAAE,MAAM,YAAY,CAAC;AAItE,OAAO,EAAE,oBAAoB,EAAE,iBAAiB,EAAE,MAAM,iBAAiB,CAAC;AAC1E,YAAY,EAAE,aAAa,EAAE,gBAAgB,EAAE,eAAe,EAAE,MAAM,iBAAiB,CAAC;AACxF,OAAO,EAAE,YAAY,EAAE,MAAM,aAAa,CAAC;AAC3C,YAAY,EAAE,kBAAkB,EAAE,MAAM,aAAa,CAAC;AACtD,YAAY,EAAE,YAAY,EAAE,eAAe,EAAE,cAAc,EAAE,iBAAiB,EAAE,MAAM,YAAY,CAAC;AAInG,OAAO,EAAE,YAAY,EAAE,MAAM,aAAa,CAAC;AAC3C,YAAY,EACV,WAAW,EACX,aAAa,EACb,SAAS,EACT,aAAa,EACb,aAAa,EACb,UAAU,GACX,MAAM,aAAa,CAAC"}
|
package/dist/index.js
CHANGED
|
@@ -133,6 +133,7 @@ function buildFieldMeta(params) {
|
|
|
133
133
|
return {
|
|
134
134
|
name: field.name,
|
|
135
135
|
columnName: field.dbName ?? field.name,
|
|
136
|
+
...field.collation === undefined ? {} : { collation: field.collation },
|
|
136
137
|
type: field.type,
|
|
137
138
|
scalarType: enumRef ? null : field.type,
|
|
138
139
|
enumName: enumRef ? field.type.enum : null,
|
|
@@ -231,6 +232,7 @@ function buildModelMeta(params) {
|
|
|
231
232
|
singleIndexUniques,
|
|
232
233
|
relations: model.relations,
|
|
233
234
|
relationByName: new Map(model.relations.map((relation) => [relation.name, relation])),
|
|
235
|
+
...model.policy === undefined ? {} : { policy: model.policy },
|
|
234
236
|
isView: model.isView,
|
|
235
237
|
computed
|
|
236
238
|
};
|
|
@@ -1440,6 +1442,7 @@ function compileOperatorFilter(params) {
|
|
|
1440
1442
|
}
|
|
1441
1443
|
const insensitive = mode === "insensitive";
|
|
1442
1444
|
const strict = mode === "strict";
|
|
1445
|
+
const ciCollated = (params2) => params2.dialect.name === "mysql" && params2.field.collation?.toLowerCase().endsWith("_ci") === true;
|
|
1443
1446
|
const requireStringOperand = (operator, operand) => {
|
|
1444
1447
|
if (typeof operand !== "string") {
|
|
1445
1448
|
throw validationError2({
|
|
@@ -1467,7 +1470,8 @@ function compileOperatorFilter(params) {
|
|
|
1467
1470
|
kind: "like",
|
|
1468
1471
|
column,
|
|
1469
1472
|
pattern: escapeLikePattern({ raw: requireStringOperand("equals", operand) }),
|
|
1470
|
-
insensitive: true
|
|
1473
|
+
insensitive: true,
|
|
1474
|
+
...ciCollated({ dialect, field }) ? { ciCollation: true } : {}
|
|
1471
1475
|
});
|
|
1472
1476
|
break;
|
|
1473
1477
|
}
|
|
@@ -1564,7 +1568,8 @@ function compileOperatorFilter(params) {
|
|
|
1564
1568
|
kind: "like",
|
|
1565
1569
|
column,
|
|
1566
1570
|
pattern: compileStringPattern({ operator, operand, field, model }),
|
|
1567
|
-
insensitive
|
|
1571
|
+
insensitive,
|
|
1572
|
+
...insensitive && ciCollated({ dialect, field }) ? { ciCollation: true } : {}
|
|
1568
1573
|
});
|
|
1569
1574
|
break;
|
|
1570
1575
|
}
|
|
@@ -5505,8 +5510,341 @@ function attachDefineView(params) {
|
|
|
5505
5510
|
const value = (options) => createView({ meta, models, name: options.name, definition: options.definition });
|
|
5506
5511
|
Object.defineProperty(client, "$defineView", { value, enumerable: true });
|
|
5507
5512
|
}
|
|
5513
|
+
// packages/runtime/src/validators.ts
|
|
5514
|
+
import { VibeError as VibeError11 } from "@vibeorm/schema";
|
|
5515
|
+
function validationFailed(params) {
|
|
5516
|
+
return new VibeError11({
|
|
5517
|
+
code: "VIBE_VALIDATION",
|
|
5518
|
+
message: `validation failed for ${params.model}.${params.field}: ${params.issues[0]?.message ?? "invalid value"}`,
|
|
5519
|
+
meta: { model: params.model, field: params.field, issues: params.issues }
|
|
5520
|
+
});
|
|
5521
|
+
}
|
|
5522
|
+
function validateValue(params) {
|
|
5523
|
+
const result = params.schema["~standard"].validate(params.value);
|
|
5524
|
+
if (result instanceof Promise) {
|
|
5525
|
+
throw new VibeError11({
|
|
5526
|
+
code: "VIBE_VALIDATION",
|
|
5527
|
+
message: `async validator on ${params.model}.${params.field} \u2014 write validators must be synchronous (validate before calling the client for async rules)`,
|
|
5528
|
+
meta: { model: params.model, field: params.field }
|
|
5529
|
+
});
|
|
5530
|
+
}
|
|
5531
|
+
if (result.issues !== undefined) {
|
|
5532
|
+
throw validationFailed({ model: params.model, field: params.field, issues: result.issues });
|
|
5533
|
+
}
|
|
5534
|
+
return result.value;
|
|
5535
|
+
}
|
|
5536
|
+
function validateWriteData(params) {
|
|
5537
|
+
const { meta, model, data, validators } = params;
|
|
5538
|
+
const fieldSchemas = validators[model.name];
|
|
5539
|
+
const out = { ...data };
|
|
5540
|
+
for (const [key, value] of Object.entries(data)) {
|
|
5541
|
+
if (value === undefined)
|
|
5542
|
+
continue;
|
|
5543
|
+
const schema = fieldSchemas?.[key];
|
|
5544
|
+
if (schema !== undefined) {
|
|
5545
|
+
const isOperator = typeof value === "object" && value !== null && !Array.isArray(value) && "set" in value;
|
|
5546
|
+
if (isOperator) {
|
|
5547
|
+
const inner = value.set;
|
|
5548
|
+
out[key] = { set: validateValue({ model: model.name, field: key, schema, value: inner }) };
|
|
5549
|
+
} else {
|
|
5550
|
+
out[key] = validateValue({ model: model.name, field: key, schema, value });
|
|
5551
|
+
}
|
|
5552
|
+
continue;
|
|
5553
|
+
}
|
|
5554
|
+
const relation = model.relationByName.get(key);
|
|
5555
|
+
if (relation === undefined || typeof value !== "object" || value === null)
|
|
5556
|
+
continue;
|
|
5557
|
+
const target = meta.modelByName.get(relation.targetModel);
|
|
5558
|
+
if (target === undefined || validators[target.name] === undefined)
|
|
5559
|
+
continue;
|
|
5560
|
+
const verbs = value;
|
|
5561
|
+
const recurse = (row) => typeof row === "object" && row !== null ? validateWriteData({ meta, model: target, data: row, validators }) : row;
|
|
5562
|
+
const next = { ...verbs };
|
|
5563
|
+
if (verbs.create !== undefined) {
|
|
5564
|
+
next.create = Array.isArray(verbs.create) ? verbs.create.map(recurse) : recurse(verbs.create);
|
|
5565
|
+
}
|
|
5566
|
+
if (verbs.connectOrCreate !== undefined) {
|
|
5567
|
+
const entries = Array.isArray(verbs.connectOrCreate) ? verbs.connectOrCreate : [verbs.connectOrCreate];
|
|
5568
|
+
const mapped = entries.map((entry) => {
|
|
5569
|
+
const pair = entry;
|
|
5570
|
+
return { ...pair, create: recurse(pair.create) };
|
|
5571
|
+
});
|
|
5572
|
+
next.connectOrCreate = Array.isArray(verbs.connectOrCreate) ? mapped : mapped[0];
|
|
5573
|
+
}
|
|
5574
|
+
if (verbs.update !== undefined && !Array.isArray(verbs.update)) {
|
|
5575
|
+
const body = verbs.update;
|
|
5576
|
+
next.update = body.data !== undefined ? { ...body, data: recurse(body.data) } : recurse(body);
|
|
5577
|
+
}
|
|
5578
|
+
if (verbs.upsert !== undefined && !Array.isArray(verbs.upsert)) {
|
|
5579
|
+
const body = verbs.upsert;
|
|
5580
|
+
next.upsert = { ...body, create: recurse(body.create), update: recurse(body.update) };
|
|
5581
|
+
}
|
|
5582
|
+
out[key] = next;
|
|
5583
|
+
}
|
|
5584
|
+
return out;
|
|
5585
|
+
}
|
|
5586
|
+
function applyWriteValidators(params) {
|
|
5587
|
+
const { meta, model, method, args, validators } = params;
|
|
5588
|
+
const validate = (row) => typeof row === "object" && row !== null ? validateWriteData({ meta, model, data: row, validators }) : row;
|
|
5589
|
+
if (method === "create" || method === "update" || method === "updateMany") {
|
|
5590
|
+
return args.data === undefined ? args : { ...args, data: validate(args.data) };
|
|
5591
|
+
}
|
|
5592
|
+
if (method === "createMany" || method === "createManyAndReturn") {
|
|
5593
|
+
return Array.isArray(args.data) ? { ...args, data: args.data.map(validate) } : args;
|
|
5594
|
+
}
|
|
5595
|
+
if (method === "upsert") {
|
|
5596
|
+
return { ...args, create: validate(args.create), update: validate(args.update) };
|
|
5597
|
+
}
|
|
5598
|
+
return args;
|
|
5599
|
+
}
|
|
5600
|
+
// packages/runtime/src/policy.ts
|
|
5601
|
+
import { VibeError as VibeError12 } from "@vibeorm/schema";
|
|
5602
|
+
function policyError(message, meta) {
|
|
5603
|
+
return new VibeError12({ code: "VIBE_VALIDATION", message, meta: meta ?? {} });
|
|
5604
|
+
}
|
|
5605
|
+
function policiedModels(meta) {
|
|
5606
|
+
return meta.models.filter((model) => model.policy !== undefined);
|
|
5607
|
+
}
|
|
5608
|
+
function mergeWhere(params) {
|
|
5609
|
+
const { where, field, value } = params;
|
|
5610
|
+
const predicate = { [field]: value };
|
|
5611
|
+
return where === undefined ? predicate : { AND: [where, predicate] };
|
|
5612
|
+
}
|
|
5613
|
+
function uniqueToFilter(params) {
|
|
5614
|
+
const out = {};
|
|
5615
|
+
for (const [key, value] of Object.entries(params.where)) {
|
|
5616
|
+
const isCompound = typeof value === "object" && value !== null && !Array.isArray(value) && params.model.compoundUniques.has(key);
|
|
5617
|
+
if (isCompound)
|
|
5618
|
+
Object.assign(out, value);
|
|
5619
|
+
else
|
|
5620
|
+
out[key] = value;
|
|
5621
|
+
}
|
|
5622
|
+
return out;
|
|
5623
|
+
}
|
|
5624
|
+
function scopeSelection(params) {
|
|
5625
|
+
const { meta, model, args, context } = params;
|
|
5626
|
+
const out = { ...args };
|
|
5627
|
+
for (const key of ["include", "select"]) {
|
|
5628
|
+
const block = args[key];
|
|
5629
|
+
if (typeof block !== "object" || block === null)
|
|
5630
|
+
continue;
|
|
5631
|
+
const next = { ...block };
|
|
5632
|
+
for (const [name, spec] of Object.entries(block)) {
|
|
5633
|
+
const relation = model.relationByName.get(name);
|
|
5634
|
+
if (relation === undefined)
|
|
5635
|
+
continue;
|
|
5636
|
+
const target = meta.modelByName.get(relation.targetModel);
|
|
5637
|
+
if (target?.policy === undefined)
|
|
5638
|
+
continue;
|
|
5639
|
+
const value = context[target.policy.context];
|
|
5640
|
+
const spec2 = spec === true ? {} : { ...spec };
|
|
5641
|
+
spec2.where = mergeWhere({ where: spec2.where, field: target.policy.field, value });
|
|
5642
|
+
next[name] = scopeSelection({ meta, model: target, args: spec2, context });
|
|
5643
|
+
}
|
|
5644
|
+
out[key] = next;
|
|
5645
|
+
}
|
|
5646
|
+
return out;
|
|
5647
|
+
}
|
|
5648
|
+
var REFERENCE_VERBS = ["connect", "connectOrCreate", "set", "disconnect", "update", "updateMany", "delete", "deleteMany", "upsert"];
|
|
5649
|
+
function forceCreateData(params) {
|
|
5650
|
+
const { meta, model, data, context } = params;
|
|
5651
|
+
const out = { ...data };
|
|
5652
|
+
if (model.policy !== undefined) {
|
|
5653
|
+
const value = context[model.policy.context];
|
|
5654
|
+
const given = data[model.policy.field];
|
|
5655
|
+
if (given !== undefined && given !== value) {
|
|
5656
|
+
throw policyError(`create on ${model.name}: data.${model.policy.field} conflicts with the bound policy context`, { model: model.name, field: model.policy.field });
|
|
5657
|
+
}
|
|
5658
|
+
out[model.policy.field] = value;
|
|
5659
|
+
}
|
|
5660
|
+
for (const [name, spec] of Object.entries(data)) {
|
|
5661
|
+
const relation = model.relationByName.get(name);
|
|
5662
|
+
if (relation === undefined || typeof spec !== "object" || spec === null)
|
|
5663
|
+
continue;
|
|
5664
|
+
const target = meta.modelByName.get(relation.targetModel);
|
|
5665
|
+
if (target?.policy === undefined)
|
|
5666
|
+
continue;
|
|
5667
|
+
const verbs = spec;
|
|
5668
|
+
for (const verb of REFERENCE_VERBS) {
|
|
5669
|
+
if (verbs[verb] !== undefined) {
|
|
5670
|
+
throw policyError(`nested ${verb} on policied model ${target.name} is not policy-safe from a scoped client \u2014 perform it in an explicit $transaction on the scoped delegate`, { model: model.name, relation: name, verb });
|
|
5671
|
+
}
|
|
5672
|
+
}
|
|
5673
|
+
if (verbs.create !== undefined) {
|
|
5674
|
+
const recurse = (row) => forceCreateData({ meta, model: target, data: row, context });
|
|
5675
|
+
out[name] = { ...verbs, create: Array.isArray(verbs.create) ? verbs.create.map(recurse) : recurse(verbs.create) };
|
|
5676
|
+
}
|
|
5677
|
+
}
|
|
5678
|
+
return out;
|
|
5679
|
+
}
|
|
5680
|
+
function scopedDelegate(params) {
|
|
5681
|
+
const { meta, model, base, context, transaction } = params;
|
|
5682
|
+
const policy = model.policy;
|
|
5683
|
+
const value = context[policy.context];
|
|
5684
|
+
const pk = model.primaryKey.map((field) => field.name);
|
|
5685
|
+
const scopeFind = (args) => {
|
|
5686
|
+
const scoped = scopeSelection({ meta, model, args: args ?? {}, context });
|
|
5687
|
+
return { ...scoped, where: mergeWhere({ where: scoped.where, field: policy.field, value }) };
|
|
5688
|
+
};
|
|
5689
|
+
const scopeUnique = (args) => {
|
|
5690
|
+
const scoped = scopeSelection({ meta, model, args, context });
|
|
5691
|
+
const flat = uniqueToFilter({ model, where: args.where ?? {} });
|
|
5692
|
+
return { ...scoped, where: mergeWhere({ where: flat, field: policy.field, value }) };
|
|
5693
|
+
};
|
|
5694
|
+
const pkClientKey = () => {
|
|
5695
|
+
for (const [key, group] of model.compoundUniques) {
|
|
5696
|
+
const names = group.fields.map((field) => field.name);
|
|
5697
|
+
if (names.length === pk.length && names.every((name) => pk.includes(name)))
|
|
5698
|
+
return key;
|
|
5699
|
+
}
|
|
5700
|
+
return pk.join("_");
|
|
5701
|
+
};
|
|
5702
|
+
const lockThen = (args, write) => transaction(async (tx) => {
|
|
5703
|
+
const raw = tx.$bypassPolicy === undefined ? tx : tx.$bypassPolicy();
|
|
5704
|
+
const target = await raw.$models[model.name].findFirst({
|
|
5705
|
+
where: scopeUnique(args).where,
|
|
5706
|
+
select: Object.fromEntries(pk.map((name) => [name, true])),
|
|
5707
|
+
lock: "update"
|
|
5708
|
+
});
|
|
5709
|
+
if (target === null)
|
|
5710
|
+
return null;
|
|
5711
|
+
const pkWhere = pk.length === 1 ? { [pk[0]]: target[pk[0]] } : { [pkClientKey()]: Object.fromEntries(pk.map((name) => [name, target[name]])) };
|
|
5712
|
+
return write(raw, pkWhere);
|
|
5713
|
+
});
|
|
5714
|
+
const notFound2 = (method) => new VibeError12({ code: "VIBE_NOT_FOUND", message: `${method} on ${model.name}: no row matches the unique where inside the bound policy context`, meta: { model: model.name, method } });
|
|
5715
|
+
return {
|
|
5716
|
+
findMany: (args) => base.findMany(scopeFind(args)),
|
|
5717
|
+
findFirst: (args) => base.findFirst(scopeFind(args)),
|
|
5718
|
+
findFirstOrThrow: (args) => base.findFirstOrThrow(scopeFind(args)),
|
|
5719
|
+
findUnique: (args) => base.findFirst(scopeUnique(args)),
|
|
5720
|
+
findUniqueOrThrow: (args) => base.findFirstOrThrow(scopeUnique(args)),
|
|
5721
|
+
create: async (args) => base.create({ ...args, data: forceCreateData({ meta, model, data: args.data ?? {}, context }) }),
|
|
5722
|
+
createMany: async (args) => base.createMany({
|
|
5723
|
+
...args,
|
|
5724
|
+
data: (args.data ?? []).map((row) => forceCreateData({ meta, model, data: row, context }))
|
|
5725
|
+
}),
|
|
5726
|
+
createManyAndReturn: async (args) => base.createManyAndReturn({
|
|
5727
|
+
...args,
|
|
5728
|
+
data: (args.data ?? []).map((row) => forceCreateData({ meta, model, data: row, context }))
|
|
5729
|
+
}),
|
|
5730
|
+
update: async (args) => {
|
|
5731
|
+
const row = await lockThen(args, (raw, pkWhere) => raw.$models[model.name].update({ ...args, where: pkWhere }));
|
|
5732
|
+
if (row === null)
|
|
5733
|
+
throw notFound2("update");
|
|
5734
|
+
return row;
|
|
5735
|
+
},
|
|
5736
|
+
updateMany: (args) => base.updateMany({ ...args, where: mergeWhere({ where: args.where, field: policy.field, value }) }),
|
|
5737
|
+
upsert: async (args) => {
|
|
5738
|
+
const row = await lockThen(args, (raw, pkWhere) => raw.$models[model.name].update({ where: pkWhere, data: args.update, ...args.select === undefined ? {} : { select: args.select } }));
|
|
5739
|
+
if (row !== null)
|
|
5740
|
+
return row;
|
|
5741
|
+
return await base.create({
|
|
5742
|
+
data: forceCreateData({ meta, model, data: args.create ?? {}, context }),
|
|
5743
|
+
...args.select === undefined ? {} : { select: args.select }
|
|
5744
|
+
});
|
|
5745
|
+
},
|
|
5746
|
+
delete: async (args) => {
|
|
5747
|
+
const row = await lockThen(args, (raw, pkWhere) => raw.$models[model.name].delete({ ...args, where: pkWhere }));
|
|
5748
|
+
if (row === null)
|
|
5749
|
+
throw notFound2("delete");
|
|
5750
|
+
return row;
|
|
5751
|
+
},
|
|
5752
|
+
deleteMany: (args) => base.deleteMany({ ...args ?? {}, where: mergeWhere({ where: args?.where, field: policy.field, value }) }),
|
|
5753
|
+
count: (args) => base.count(scopeFind(args)),
|
|
5754
|
+
aggregate: (args) => base.aggregate(scopeFind(args)),
|
|
5755
|
+
groupBy: (args) => base.groupBy(scopeFind(args))
|
|
5756
|
+
};
|
|
5757
|
+
}
|
|
5758
|
+
function scopeExtensionProps(params) {
|
|
5759
|
+
const out = {};
|
|
5760
|
+
for (const [key, prop] of Object.entries(params.base)) {
|
|
5761
|
+
if (key in params.delegate)
|
|
5762
|
+
continue;
|
|
5763
|
+
if (typeof prop === "function") {
|
|
5764
|
+
out[key] = (args) => prop({ ...args ?? {}, where: mergeWhere({ where: args?.where, field: params.field, value: params.value }) });
|
|
5765
|
+
} else if (typeof prop === "object" && prop !== null) {
|
|
5766
|
+
out[key] = scopeExtensionProps({ base: prop, delegate: {}, field: params.field, value: params.value });
|
|
5767
|
+
}
|
|
5768
|
+
}
|
|
5769
|
+
return out;
|
|
5770
|
+
}
|
|
5771
|
+
function attachPolicy(params) {
|
|
5772
|
+
const { client, meta } = params;
|
|
5773
|
+
const policied = policiedModels(meta);
|
|
5774
|
+
if (policied.length === 0)
|
|
5775
|
+
return;
|
|
5776
|
+
const originals = new Map;
|
|
5777
|
+
for (const model of policied) {
|
|
5778
|
+
const original = client.$models[model.name];
|
|
5779
|
+
originals.set(model.name, { ...original });
|
|
5780
|
+
const guard = (method) => () => Promise.reject(policyError(`model ${model.name} declares @@policy \u2014 bind a context with $withPolicy({ ${model.policy?.context}: ... }) or bypass deliberately with $bypassPolicy()`, { model: model.name, method }));
|
|
5781
|
+
const guarded = {};
|
|
5782
|
+
for (const key of Object.keys(original)) {
|
|
5783
|
+
guarded[key] = typeof original[key] === "function" ? guard(key) : original[key];
|
|
5784
|
+
}
|
|
5785
|
+
Object.assign(original, guarded);
|
|
5786
|
+
}
|
|
5787
|
+
const buildScoped = (context) => {
|
|
5788
|
+
for (const model of policied) {
|
|
5789
|
+
const key = model.policy?.context;
|
|
5790
|
+
if (context[key] === undefined || context[key] === null) {
|
|
5791
|
+
throw policyError(`$withPolicy: missing context value "${key}" (required by ${model.name})`, { context: key });
|
|
5792
|
+
}
|
|
5793
|
+
}
|
|
5794
|
+
const scoped = Object.create(client);
|
|
5795
|
+
const scopedModels = { ...client.$models };
|
|
5796
|
+
for (const model of policied) {
|
|
5797
|
+
const base = originals.get(model.name);
|
|
5798
|
+
const value = context[model.policy?.context];
|
|
5799
|
+
const delegate = scopedDelegate({ meta, model, base, context, transaction: client.$transaction });
|
|
5800
|
+
const full = { ...delegate, ...scopeExtensionProps({ base, delegate, field: model.policy?.field, value }) };
|
|
5801
|
+
scopedModels[model.name] = full;
|
|
5802
|
+
scopedModels[model.clientName] = full;
|
|
5803
|
+
Object.defineProperty(scoped, model.clientName, { value: full, enumerable: true });
|
|
5804
|
+
}
|
|
5805
|
+
Object.defineProperty(scoped, "$models", { value: scopedModels, enumerable: true });
|
|
5806
|
+
attachDefineView({ client: scoped, meta, models: scopedModels });
|
|
5807
|
+
Object.defineProperty(scoped, "$transaction", {
|
|
5808
|
+
value: (arg, options) => typeof arg === "function" ? client.$transaction((tx) => arg(buildScopedOver(tx, context)), options) : client.$transaction(arg, options),
|
|
5809
|
+
enumerable: true
|
|
5810
|
+
});
|
|
5811
|
+
return scoped;
|
|
5812
|
+
};
|
|
5813
|
+
const buildScopedOver = (tx, context) => {
|
|
5814
|
+
const rawTx = tx.$bypassPolicy === undefined ? tx : tx.$bypassPolicy();
|
|
5815
|
+
const inner = Object.create(tx);
|
|
5816
|
+
const scopedModels = { ...tx.$models };
|
|
5817
|
+
for (const model of policied) {
|
|
5818
|
+
const base = rawTx.$models[model.name];
|
|
5819
|
+
const delegate = scopedDelegate({ meta, model, base, context, transaction: tx.$transaction });
|
|
5820
|
+
scopedModels[model.name] = delegate;
|
|
5821
|
+
scopedModels[model.clientName] = delegate;
|
|
5822
|
+
Object.defineProperty(inner, model.clientName, { value: delegate, enumerable: true });
|
|
5823
|
+
}
|
|
5824
|
+
Object.defineProperty(inner, "$models", { value: scopedModels, enumerable: true });
|
|
5825
|
+
attachDefineView({ client: inner, meta, models: scopedModels });
|
|
5826
|
+
return inner;
|
|
5827
|
+
};
|
|
5828
|
+
Object.defineProperty(client, "$withPolicy", { value: (context) => buildScoped(context), enumerable: true });
|
|
5829
|
+
Object.defineProperty(client, "$bypassPolicy", {
|
|
5830
|
+
value: () => {
|
|
5831
|
+
const bypass = Object.create(client);
|
|
5832
|
+
const models = { ...client.$models };
|
|
5833
|
+
for (const model of policied) {
|
|
5834
|
+
const original = originals.get(model.name);
|
|
5835
|
+
models[model.name] = original;
|
|
5836
|
+
models[model.clientName] = original;
|
|
5837
|
+
Object.defineProperty(bypass, model.clientName, { value: original, enumerable: true });
|
|
5838
|
+
}
|
|
5839
|
+
Object.defineProperty(bypass, "$models", { value: models, enumerable: true });
|
|
5840
|
+
attachDefineView({ client: bypass, meta, models });
|
|
5841
|
+
return bypass;
|
|
5842
|
+
},
|
|
5843
|
+
enumerable: true
|
|
5844
|
+
});
|
|
5845
|
+
}
|
|
5508
5846
|
// packages/runtime/src/client.ts
|
|
5509
|
-
import { VibeError as
|
|
5847
|
+
import { VibeError as VibeError13, unsupportedCapability as unsupportedCapability2 } from "@vibeorm/schema";
|
|
5510
5848
|
import { ParamCollector, getSqlDialect } from "@vibeorm/sql";
|
|
5511
5849
|
|
|
5512
5850
|
// packages/runtime/src/render-cache.ts
|
|
@@ -5956,7 +6294,7 @@ function renderStatementCached(params) {
|
|
|
5956
6294
|
// packages/runtime/src/client.ts
|
|
5957
6295
|
function notFound2(params) {
|
|
5958
6296
|
const { model, method } = params;
|
|
5959
|
-
return new
|
|
6297
|
+
return new VibeError13({
|
|
5960
6298
|
code: "VIBE_NOT_FOUND",
|
|
5961
6299
|
message: `no ${model} record matched the where clause of ${method}()`,
|
|
5962
6300
|
meta: { model, method }
|
|
@@ -5964,7 +6302,7 @@ function notFound2(params) {
|
|
|
5964
6302
|
}
|
|
5965
6303
|
function viewIsReadOnly(params) {
|
|
5966
6304
|
const { model, method } = params;
|
|
5967
|
-
return new
|
|
6305
|
+
return new VibeError13({
|
|
5968
6306
|
code: "VIBE_VALIDATION",
|
|
5969
6307
|
message: `${model} is a view \u2014 ${method}() is not available on views (they are read-only); write to the underlying table instead`,
|
|
5970
6308
|
meta: { model, method }
|
|
@@ -6093,7 +6431,7 @@ class QueryPromise extends Promise {
|
|
|
6093
6431
|
}
|
|
6094
6432
|
claim() {
|
|
6095
6433
|
if (this.started) {
|
|
6096
|
-
throw new
|
|
6434
|
+
throw new VibeError13({
|
|
6097
6435
|
code: "VIBE_VALIDATION",
|
|
6098
6436
|
message: "$transaction([...]) needs operations that have not dispatched \u2014 pass delegate calls in the same tick they are created (this one was awaited or created earlier and already executed outside the transaction)"
|
|
6099
6437
|
});
|
|
@@ -6171,7 +6509,7 @@ async function runAffected(params) {
|
|
|
6171
6509
|
function plan(params) {
|
|
6172
6510
|
const { engine, model, method, args } = params;
|
|
6173
6511
|
if (args !== undefined && args["lock"] !== undefined && engine.inTransaction !== true) {
|
|
6174
|
-
throw new
|
|
6512
|
+
throw new VibeError13({
|
|
6175
6513
|
code: "VIBE_VALIDATION",
|
|
6176
6514
|
message: `lock on ${model}.${method}() requires a transaction \u2014 call it on the client $transaction hands its callback (outside one, the lock would release at statement end)`,
|
|
6177
6515
|
meta: { model, method }
|
|
@@ -6244,7 +6582,7 @@ async function insertedKeyWhere(params) {
|
|
|
6244
6582
|
});
|
|
6245
6583
|
const id = result.rows[0]?.id;
|
|
6246
6584
|
if (id === undefined || id === null) {
|
|
6247
|
-
throw new
|
|
6585
|
+
throw new VibeError13({
|
|
6248
6586
|
code: "VIBE_INTERNAL",
|
|
6249
6587
|
message: `could not read back the generated key for ${source.model.name}`,
|
|
6250
6588
|
meta: { model: source.model.name }
|
|
@@ -6546,7 +6884,7 @@ function createDelegate(params) {
|
|
|
6546
6884
|
const skipping = args.onConflict !== undefined;
|
|
6547
6885
|
if (hasNestedWrites({ model: modelMeta, data: args.data })) {
|
|
6548
6886
|
if (skipping) {
|
|
6549
|
-
throw new
|
|
6887
|
+
throw new VibeError13({
|
|
6550
6888
|
code: "VIBE_VALIDATION",
|
|
6551
6889
|
message: `onConflict cannot combine with nested writes on ${modelMeta.name}.create() \u2014 insert the parent row alone, then connect relations`,
|
|
6552
6890
|
meta: { model: modelMeta.name }
|
|
@@ -6630,7 +6968,7 @@ function createDelegate(params) {
|
|
|
6630
6968
|
const upsert = async (target, args) => {
|
|
6631
6969
|
const modelMeta = getModelMeta({ meta: target.meta, model });
|
|
6632
6970
|
if (hasNestedWrites({ model: modelMeta, data: args.create }) || hasNestedWrites({ model: modelMeta, data: args.update })) {
|
|
6633
|
-
throw new
|
|
6971
|
+
throw new VibeError13({
|
|
6634
6972
|
code: "VIBE_VALIDATION",
|
|
6635
6973
|
message: `nested writes are not supported inside upsert arms on ${modelMeta.name} \u2014 use create()/update() with nested data`,
|
|
6636
6974
|
meta: { model: modelMeta.name }
|
|
@@ -6638,7 +6976,7 @@ function createDelegate(params) {
|
|
|
6638
6976
|
}
|
|
6639
6977
|
if (!upsertUsesNativeStatement({ model: modelMeta, args })) {
|
|
6640
6978
|
if (args.onConflict !== undefined) {
|
|
6641
|
-
throw new
|
|
6979
|
+
throw new VibeError13({
|
|
6642
6980
|
code: "VIBE_VALIDATION",
|
|
6643
6981
|
message: `onConflict on ${modelMeta.name}.upsert() needs the native single-statement path \u2014 this shape (a guard field beyond the conflict target, or create data not binding the where's key) runs the find-then-write fallback, which cannot honor an explicit conflict target`,
|
|
6644
6982
|
meta: { model: modelMeta.name }
|
|
@@ -6765,6 +7103,17 @@ function createDelegate(params) {
|
|
|
6765
7103
|
const meta = getModelMeta({ meta: engine.meta, model });
|
|
6766
7104
|
return meta.isView ? readOnlyDelegate({ delegate, model: meta.name }) : delegate;
|
|
6767
7105
|
}
|
|
7106
|
+
var WRITE_METHODS = ["create", "createMany", "createManyAndReturn", "update", "updateMany", "upsert"];
|
|
7107
|
+
function withWriteValidation(params) {
|
|
7108
|
+
const { engine, delegate, model, validators } = params;
|
|
7109
|
+
const meta = getModelMeta({ meta: engine.meta, model });
|
|
7110
|
+
const wrapped = { ...delegate };
|
|
7111
|
+
for (const method of WRITE_METHODS) {
|
|
7112
|
+
const original = delegate[method];
|
|
7113
|
+
wrapped[method] = (args) => original(applyWriteValidators({ meta: engine.meta, model: meta, method, args, validators }));
|
|
7114
|
+
}
|
|
7115
|
+
return wrapped;
|
|
7116
|
+
}
|
|
6768
7117
|
function buildRawStatement(params) {
|
|
6769
7118
|
const { dialect, strings, values } = params;
|
|
6770
7119
|
const collector = new ParamCollector(dialect);
|
|
@@ -6778,7 +7127,11 @@ function buildClient(params) {
|
|
|
6778
7127
|
const { engine } = params;
|
|
6779
7128
|
const models = {};
|
|
6780
7129
|
for (const model of engine.meta.models) {
|
|
6781
|
-
|
|
7130
|
+
let delegate = createDelegate({ engine, model: model.name });
|
|
7131
|
+
const validators = engine.options?.validate;
|
|
7132
|
+
if (validators?.[model.name] !== undefined) {
|
|
7133
|
+
delegate = withWriteValidation({ engine, delegate, model: model.name, validators });
|
|
7134
|
+
}
|
|
6782
7135
|
models[model.name] = delegate;
|
|
6783
7136
|
models[model.clientName] = delegate;
|
|
6784
7137
|
}
|
|
@@ -6800,7 +7153,7 @@ function buildClient(params) {
|
|
|
6800
7153
|
let claimError = null;
|
|
6801
7154
|
for (const operation of operations) {
|
|
6802
7155
|
if (!(operation instanceof QueryPromise)) {
|
|
6803
|
-
claimError = new
|
|
7156
|
+
claimError = new VibeError13({
|
|
6804
7157
|
code: "VIBE_VALIDATION",
|
|
6805
7158
|
message: "$transaction([...]) takes query promises from model delegate calls \u2014 a foreign promise is already running and cannot join the transaction"
|
|
6806
7159
|
});
|
|
@@ -6839,7 +7192,7 @@ function buildClient(params) {
|
|
|
6839
7192
|
$models: models,
|
|
6840
7193
|
$on: (event, listener) => {
|
|
6841
7194
|
if (event !== "query") {
|
|
6842
|
-
throw new
|
|
7195
|
+
throw new VibeError13({
|
|
6843
7196
|
code: "VIBE_VALIDATION",
|
|
6844
7197
|
message: `unknown client event "${String(event)}" \u2014 supported: "query"`,
|
|
6845
7198
|
meta: { event }
|
|
@@ -6873,6 +7226,7 @@ function buildClient(params) {
|
|
|
6873
7226
|
}
|
|
6874
7227
|
attachExtensionMounts({ engine, client, models });
|
|
6875
7228
|
attachDefineView({ client, meta: engine.meta, models });
|
|
7229
|
+
attachPolicy({ client, meta: engine.meta });
|
|
6876
7230
|
return client;
|
|
6877
7231
|
}
|
|
6878
7232
|
function makeMountContext(params) {
|
|
@@ -6902,7 +7256,7 @@ function makeMountContext(params) {
|
|
|
6902
7256
|
compileWhere: ({ where, model: modelName, qualify }) => {
|
|
6903
7257
|
const target = modelName === undefined ? model : getModelMeta({ meta: engine.meta, model: modelName });
|
|
6904
7258
|
if (target === null) {
|
|
6905
|
-
throw new
|
|
7259
|
+
throw new VibeError13({
|
|
6906
7260
|
code: "VIBE_INTERNAL",
|
|
6907
7261
|
message: `extension "${extension}" compiled a where with no model in scope`,
|
|
6908
7262
|
meta: { extension }
|
|
@@ -6928,7 +7282,7 @@ function attachExtensionMounts(params) {
|
|
|
6928
7282
|
const model = getModelMeta({ meta: engine.meta, model: mount.model ?? "" });
|
|
6929
7283
|
const delegate = models[model.name];
|
|
6930
7284
|
if (delegate === undefined || mount.property in delegate) {
|
|
6931
|
-
throw new
|
|
7285
|
+
throw new VibeError13({
|
|
6932
7286
|
code: "VIBE_CONFIG",
|
|
6933
7287
|
message: `extension "${mount.extension}" cannot mount "${mount.property}" on ${model.name} \u2014 the name is taken`,
|
|
6934
7288
|
meta: { extension: mount.extension, model: model.name, property: mount.property }
|
|
@@ -6939,7 +7293,7 @@ function attachExtensionMounts(params) {
|
|
|
6939
7293
|
continue;
|
|
6940
7294
|
}
|
|
6941
7295
|
if (!mount.property.startsWith("$") || mount.property in client) {
|
|
6942
|
-
throw new
|
|
7296
|
+
throw new VibeError13({
|
|
6943
7297
|
code: "VIBE_CONFIG",
|
|
6944
7298
|
message: `extension "${mount.extension}" cannot mount client property "${mount.property}" \u2014 root mounts are $-prefixed and must not collide`,
|
|
6945
7299
|
meta: { extension: mount.extension, property: mount.property }
|
|
@@ -6959,7 +7313,7 @@ function createClient(params) {
|
|
|
6959
7313
|
assertComputedManifest({ manifest: computed.manifest, specs: computed.specs });
|
|
6960
7314
|
}
|
|
6961
7315
|
if (computed === undefined && options !== undefined && options["computed"] !== undefined) {
|
|
6962
|
-
throw new
|
|
7316
|
+
throw new VibeError13({
|
|
6963
7317
|
code: "VIBE_CONFIG",
|
|
6964
7318
|
message: "this client was generated without computed fields \u2014 declare them in vibeorm.config.ts and re-run vibeorm generate",
|
|
6965
7319
|
meta: {}
|
|
@@ -6987,6 +7341,7 @@ function createClient(params) {
|
|
|
6987
7341
|
});
|
|
6988
7342
|
}
|
|
6989
7343
|
export {
|
|
7344
|
+
validateWriteData,
|
|
6990
7345
|
updateWithNested,
|
|
6991
7346
|
toSqlExecutor,
|
|
6992
7347
|
toClientName,
|
|
@@ -7022,10 +7377,12 @@ export {
|
|
|
7022
7377
|
buildExtensionOperatorMap,
|
|
7023
7378
|
buildConnectHooks,
|
|
7024
7379
|
attachRelations,
|
|
7380
|
+
attachPolicy,
|
|
7025
7381
|
attachLateralRelations,
|
|
7026
7382
|
attachDefineView,
|
|
7027
7383
|
assertExtensionManifest,
|
|
7028
7384
|
assertComputedManifest,
|
|
7385
|
+
applyWriteValidators,
|
|
7029
7386
|
applyComputedFields,
|
|
7030
7387
|
ViewResult,
|
|
7031
7388
|
SQLITE_CODECS,
|
|
@@ -7035,4 +7392,4 @@ export {
|
|
|
7035
7392
|
COUNT_ALIAS
|
|
7036
7393
|
};
|
|
7037
7394
|
|
|
7038
|
-
//# debugId=
|
|
7395
|
+
//# debugId=EC61C00B9601D9AD64756E2164756E21
|