@everystack/model 0.4.8 → 0.4.9

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.
Files changed (2) hide show
  1. package/package.json +1 -1
  2. package/src/can.ts +20 -0
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@everystack/model",
3
- "version": "0.4.8",
3
+ "version": "0.4.9",
4
4
  "description": "Declare a table's schema, validation, and authorization once — compiled to migrations, RLS, and handler config",
5
5
  "license": "AGPL-3.0-only",
6
6
  "publishConfig": {
package/src/can.ts CHANGED
@@ -28,6 +28,26 @@ export interface AbilityCondition {
28
28
  via?: string;
29
29
  /** Field in the JWT claims holding the owner id. Default: `sub`. */
30
30
  userField?: string;
31
+ /**
32
+ * The SQL expression that yields the signed-in user's id — the RIGHT side of the owner
33
+ * comparison. Default: the JWT claim read inline,
34
+ * `((current_setting('request.jwt.claims'::text, true))::jsonb ->> '<userField>'::text)`,
35
+ * cast to the owner column's type.
36
+ *
37
+ * Declare it when the database already has its own accessor — `auth.user_id()` is the
38
+ * common brownfield shape — so the compiled policy is the one that is already live
39
+ * rather than a semantically-similar rewrite of it. That matters more than it sounds:
40
+ * predicates are diffed as TEXT, so an equivalent-but-different expression is a
41
+ * DROP + CREATE on every owner policy in the schema, which is exactly the churn a
42
+ * first plan against an existing database must not produce.
43
+ *
44
+ * Deliberately per-ability, beside `userField`, and with no project-wide default: a
45
+ * single setting that silently repoints every owner policy in a schema is a worse
46
+ * security surface than saying it where it applies. When declared, the expression is
47
+ * emitted VERBATIM — no cast is added, because the accessor already returns the
48
+ * column's type (`auth.user_id() RETURNS integer` against an integer owner).
49
+ */
50
+ ownerExpr?: unknown;
31
51
  /**
32
52
  * Column-scoped exposure for a `read` ability. Names the field keys a role may read
33
53
  * (compiled to a `GRANT SELECT (cols)` column grant, not a table grant) instead of the