@vibeorm/schema 5.6.0 → 5.8.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/dist/errors.d.ts CHANGED
@@ -194,7 +194,11 @@ export declare const SCOPED_REFUSAL_REASONS: readonly [
194
194
  /** A create leaves out a column a list scope restricts — the handle never picks a value from the list. */
195
195
  "scope_value_required",
196
196
  /** `$scoped({ scopes: {} })` — the named form binds at least one scope. */
197
- "no_scope_bound"];
197
+ "no_scope_bound",
198
+ /** A { through } relation's effective onDelete/onUpdate is SetDefault, or SetNull on an all-nullable key: the database could detach the row from its parent. */
199
+ "through_detachable",
200
+ /** A { column } entry's column is part of a foreign key declaring SetDefault: the database could write another tenant's value into it. */
201
+ "column_set_default"];
198
202
  export type ScopedRefusalReason = (typeof SCOPED_REFUSAL_REASONS)[number];
199
203
  /**
200
204
  * A refusal from a tenant-scoped handle (`$scoped`). Carries the model, the
package/dist/index.d.ts CHANGED
@@ -21,7 +21,7 @@ export { PREDICATE_COMPARISON_OPS, assertPredicateCapabilities, inspectPredicate
21
21
  export type { PredicateBooleanUsage, PredicateCapabilityInput, PredicateCapabilityIssue, PredicateCapabilityTable, PredicateComparisonOp, PredicateExpression, PredicateFieldRef, PredicateInspection, PredicateIR, PredicateNodeKind, PredicateNumericType, PredicateOperand, PredicateResultType, PredicateUsage, PredicateValue } from "./predicate.ts";
22
22
  export { CHECK_RULE_GROUP_MAX, checkRulePredicate } from "./check-rules.ts";
23
23
  export type { CheckRule, CheckRuleGroupKind, CheckRuleLiteral } from "./check-rules.ts";
24
- export { resolveOnDelete, resolveOnUpdate, resolveReferentialActions } from "./referential-actions.ts";
24
+ export { resolveOnDelete, resolveOnUpdate, resolveReferentialActions, setDefaultRelationOf } from "./referential-actions.ts";
25
25
  export { assertMigrationObjects, isSqlObjectDefinition, isSqlObjectIdentity, sqlObjectKey, sqlObjectNamespace } from "./migration-objects.ts";
26
26
  export type { MigrationObjectIR, QualifiedSqlName, SqlObjectDefinition, SqlObjectDefinitionFormat, SqlObjectFacts, SqlObjectIdentity } from "./migration-objects.ts";
27
27
  export type { AdvisoryLockMode, DialectCapabilities, FullTextEngine, RowLockStrength, RowLockWaitPolicy, TimeOfDayType, } from "./capabilities.ts";
package/dist/index.js CHANGED
@@ -109,7 +109,9 @@ var SCOPED_REFUSAL_REASONS = [
109
109
  "conflict_target_unscoped",
110
110
  "model_denied",
111
111
  "scope_value_required",
112
- "no_scope_bound"
112
+ "no_scope_bound",
113
+ "through_detachable",
114
+ "column_set_default"
113
115
  ];
114
116
 
115
117
  class ScopedQueryError extends VibeError {
@@ -1596,6 +1598,9 @@ function resolveReferentialActions(params) {
1596
1598
  const required = (relation.fields ?? []).every((name) => params.field(name)?.isOptional !== true);
1597
1599
  return { onDelete: resolveOnDelete({ explicit: relation.onDelete, required }), onUpdate: resolveOnUpdate({ explicit: relation.onUpdate }) };
1598
1600
  }
1601
+ function setDefaultRelationOf(params) {
1602
+ return params.relations.find((relation) => !relation.isList && (relation.fields ?? []).includes(params.field) && (relation.onDelete === "SetDefault" || relation.onUpdate === "SetDefault"));
1603
+ }
1599
1604
 
1600
1605
  // packages/schema/src/generated-columns.ts
1601
1606
  function declarationIssue(params) {
@@ -2855,6 +2860,11 @@ var RESERVED_ENUM_NAMES = [
2855
2860
  "IncludedRelation",
2856
2861
  "IncludedCount",
2857
2862
  "ViewDelegateMap",
2863
+ "__VibeObjects",
2864
+ "__VibeKeys",
2865
+ "__VibeAt",
2866
+ "__VibeItem",
2867
+ "__VibeExact",
2858
2868
  "extensionManifest",
2859
2869
  "extensionMounts",
2860
2870
  "computedManifest",
@@ -2874,6 +2884,7 @@ var RESERVED_ENUM_NAMES = [
2874
2884
  "Date",
2875
2885
  "Uint8Array",
2876
2886
  "schema",
2887
+ "jsonSchemas",
2877
2888
  "VibeClient",
2878
2889
  "VibeClientInstance",
2879
2890
  "VibeQueryPromise",
@@ -3932,6 +3943,14 @@ function validateModel(params) {
3932
3943
  field: field.name
3933
3944
  });
3934
3945
  }
3946
+ if (field.bigIntMode !== undefined && (field.type !== "BigInt" || field.bigIntMode !== "number")) {
3947
+ issues.push({
3948
+ rule: "bigint-mode",
3949
+ message: `@number on "${model.name}.${field.name}" \u2014 a number read mode is only valid on BigInt fields, and its one value is "number"`,
3950
+ model: model.name,
3951
+ field: field.name
3952
+ });
3953
+ }
3935
3954
  }
3936
3955
  if (model.policy !== undefined) {
3937
3956
  const policyField = model.fields.find((field) => field.name === model.policy?.field);
@@ -3955,6 +3974,16 @@ function validateModel(params) {
3955
3974
  model: model.name,
3956
3975
  field: policyField.name
3957
3976
  });
3977
+ } else {
3978
+ const repointing = setDefaultRelationOf({ relations: model.relations, field: policyField.name });
3979
+ if (repointing !== undefined) {
3980
+ issues.push({
3981
+ rule: "policy-set-default",
3982
+ message: `@@policy field "${model.name}.${policyField.name}" is a foreign key the database can re-point: relation "${repointing.name}" declares SetDefault, so deleting or re-keying its ${repointing.targetModel} writes the column's default, which can be another tenant's value. Declare onDelete and onUpdate as Cascade, Restrict or NoAction`,
3983
+ model: model.name,
3984
+ field: policyField.name
3985
+ });
3986
+ }
3958
3987
  }
3959
3988
  }
3960
3989
  const checkNames = new Set;
@@ -4448,6 +4477,10 @@ function validateNativeRls(params) {
4448
4477
  else if (slot.type !== field.type)
4449
4478
  add({ rule: "rls-context-type-mismatch", message: `Context ${ref.context} does not match ${model.name}.${field.name}`, field: field.name });
4450
4479
  }
4480
+ const repointing = field === undefined ? undefined : setDefaultRelationOf({ relations: model.relations, field: field.name });
4481
+ if (repointing !== undefined) {
4482
+ add({ rule: "rls-where-set-default", message: `Native RLS ownership column ${model.name}.${String(fieldName)} is a foreign key the database can re-point: relation "${repointing.name}" declares SetDefault, and referential actions bypass row security, so deleting or re-keying its ${repointing.targetModel} writes the column's default, which can be another tenant's value. Declare onDelete and onUpdate as Cascade, Restrict, NoAction or SetNull`, field: String(fieldName) });
4483
+ }
4451
4484
  }
4452
4485
  continue;
4453
4486
  }
@@ -4462,6 +4495,11 @@ function validateNativeRls(params) {
4462
4495
  add({ rule: "rls-nullable-through", message: "Native RLS through requires a non-nullable parent relation and foreign key; NULL parent links cannot satisfy WITH CHECK. Make the link required or use a direct ownership rule", field: relation.name });
4463
4496
  continue;
4464
4497
  }
4498
+ const actions = resolveReferentialActions({ relation, field: (name) => model.fields.find((field) => field.name === name) });
4499
+ if (actions.onDelete === "SetDefault" || actions.onUpdate === "SetDefault") {
4500
+ add({ rule: "rls-through-set-default", message: `Native RLS through requires a foreign key the database cannot re-point: ON ${actions.onDelete === "SetDefault" ? "DELETE" : "UPDATE"} SET DEFAULT moves the row to its key's default parent, which can belong to another tenant, and referential actions bypass row security. Declare onDelete and onUpdate as Cascade, Restrict or NoAction`, field: relation.name });
4501
+ continue;
4502
+ }
4465
4503
  if (table === "parent")
4466
4504
  add({ rule: "rls-through-alias-conflict", message: "A through table mapped to parent would shadow the fixed policy parent alias; use another table name" });
4467
4505
  throughTargets.set(model.name, target.name);
@@ -4627,6 +4665,7 @@ export {
4627
4665
  scalarListDefault,
4628
4666
  schemaRowRuleIdentities,
4629
4667
  serializeJsonDefault,
4668
+ setDefaultRelationOf,
4630
4669
  sqlNamespaceIssue,
4631
4670
  sqlObjectKey,
4632
4671
  sqlObjectNamespace,
@@ -4642,4 +4681,4 @@ export {
4642
4681
  validatorRefIssue
4643
4682
  };
4644
4683
 
4645
- //# debugId=908B9801B15F7FB564756E2164756E21
4684
+ //# debugId=16597011ACA85C7264756E2164756E21