@rebasepro/common 0.22.0 → 0.24.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.
@@ -0,0 +1,33 @@
1
+ import type { CollectionConfig, ResolvedRelation } from "@rebasepro/types";
2
+ /**
3
+ * Whether a duplicate of a record may carry this relation's value.
4
+ *
5
+ * A duplicate is saved as a create, and a create writes every relation it
6
+ * carries. That is right where the link is the copy's own: a `belongsTo` key on
7
+ * the copy's row, or `manyToMany` links, which are new junction rows beside the
8
+ * original's — the targets are shared by design. It is wrong wherever the key
9
+ * lives on the other row. Writing a `hasMany` or a `hasOne` points the
10
+ * children's foreign key at the copy, which takes them away from the record
11
+ * that was copied: duplicating an author moved every one of their posts to the
12
+ * duplicate and left the original with none. A `via` is declared read-only,
13
+ * and its one-to-one writer re-points the target's key the same way.
14
+ *
15
+ * Exhaustive over the kinds, so a new one is a compile error here rather than
16
+ * a copy that quietly carries it.
17
+ */
18
+ export declare function copyCarriesRelation(relation: ResolvedRelation): boolean;
19
+ /**
20
+ * The values a duplicate of a record is created with: the original's, less
21
+ * its key and less every relation the copy cannot take without changing
22
+ * another row (see {@link copyCarriesRelation}).
23
+ *
24
+ * The key goes so the database, or the user, gives the copy its own. The
25
+ * relations go because the copy is written as a create, and a create writes
26
+ * them — for a child-held key that is a re-parent of rows the user never
27
+ * touched, with nothing on screen to say so.
28
+ *
29
+ * A relation property that does not resolve is left out as well: what writing
30
+ * it would do cannot be known here, and leaving a value out of a new record
31
+ * changes nothing that exists.
32
+ */
33
+ export declare function getCopyValues<M extends Record<string, unknown>>(collection: CollectionConfig, values: Partial<M>): Partial<M>;
@@ -99,7 +99,15 @@ export declare function applyDefaultValuesOnCreate<M extends Record<string, unkn
99
99
  * @group Driver
100
100
  */
101
101
  export declare function sanitizeData<M extends Record<string, unknown>>(values: EntityValues<M>, properties: Properties): Record<string, unknown>;
102
- export declare function getReferenceFrom<M extends Record<string, unknown>>(entity: Entity<M>): EntityReference;
102
+ /**
103
+ * A reference to `entity`.
104
+ *
105
+ * @param path where the reference points, when that is not the path the
106
+ * entity is addressed by. A Firestore or MongoDB collection may declare a
107
+ * `path` for its store other than its slug, and a reference has to carry the
108
+ * stored one, where `entity.path` is the path the admin addresses it by.
109
+ */
110
+ export declare function getReferenceFrom<M extends Record<string, unknown>>(entity: Entity<M>, path?: string): EntityReference;
103
111
  export declare function getRelationFrom<M extends Record<string, unknown>>(entity: Entity<M>): EntityRelation;
104
112
  /**
105
113
  * Normalize a value into a proper EntityRelation instance.
@@ -22,3 +22,5 @@ export * from "./pg-column-to-property.js";
22
22
  export * from "./string-column-length.js";
23
23
  export * from "./internal-tables.js";
24
24
  export * from "./sql-rows.js";
25
+ export * from "./copy.js";
26
+ export * from "./untrusted-envelope.js";
@@ -0,0 +1,32 @@
1
+ import type { CollectionConfig, SecurityOperation, SecurityRule } from "@rebasepro/types";
2
+ import { type PolicyCompileOptions } from "./policyToPostgres.js";
3
+ /**
4
+ * One Postgres policy a security rule compiles to: its name and the clauses
5
+ * `CREATE POLICY` is given for it.
6
+ */
7
+ export interface CompiledRulePolicy {
8
+ name: string;
9
+ operation: SecurityOperation;
10
+ /** `permissive` | `restrictive`, lower-case as the rule spells it. */
11
+ mode: "permissive" | "restrictive";
12
+ /** The `TO` list. Sorted, `["public"]` when the rule names none. */
13
+ roles: string[];
14
+ /** The `USING` clause, or `null` when the operation takes none. */
15
+ using: string | null;
16
+ /** The `WITH CHECK` clause, or `null` when the operation takes none. */
17
+ withCheck: string | null;
18
+ }
19
+ /**
20
+ * The policies one security rule compiles to — one per operation.
21
+ *
22
+ * The schema planner writes these into the database, and the Studio's RLS
23
+ * editor compares the database against them; both call this, so "what the code
24
+ * declares" has one meaning.
25
+ *
26
+ * The desugaring (`access` / `ownerField` / `roles` / structured condition /
27
+ * raw SQL → `PolicyExpression`) is {@link securityRuleToConditions}, and the SQL
28
+ * is {@link policyToPostgres}. What lives here is only the shape: which
29
+ * operations a rule expands to, which clauses each operation takes, and the
30
+ * deny-all fallback for a clause that compiled to nothing.
31
+ */
32
+ export declare function compileRulePolicies(collection: CollectionConfig, rule: SecurityRule, options?: PolicyCompileOptions): CompiledRulePolicy[];
@@ -2,3 +2,5 @@ export * from "./securityRuleToConditions.js";
2
2
  export * from "./sqlToPolicy.js";
3
3
  export * from "./policyToPostgres.js";
4
4
  export * from "./evaluatePolicy.js";
5
+ export * from "./policyToSecurityRule.js";
6
+ export * from "./compileRulePolicies.js";
@@ -0,0 +1,27 @@
1
+ import type { PostgresPolicy, SecurityRule } from "@rebasepro/types";
2
+ /**
3
+ * The rule a Postgres policy compiles back from — a `pg_policies` row, or what
4
+ * a policy editor produced in that shape.
5
+ *
6
+ * One definition for every place that turns a policy into a rule: Studio's RLS
7
+ * editor ("Save" and "Import to codebase"), the collection editor's RLS tab
8
+ * ("Import to codebase") and "Import from table"
9
+ * (`buildCollectionFromTableMetadata`). The rule is what `db push` compiles back
10
+ * into the database, so anything this gets wrong is a policy that changes on
11
+ * the way back:
12
+ *
13
+ * - The `TO` list names *database* roles, which is `pgRoles`. `roles` holds
14
+ * *application* roles and compiles to a `rebase.roles()` check: filed there,
15
+ * `TO public` is a check no user passes, and on a restrictive policy — which
16
+ * compiles to `NOT (roles) OR condition` — a gate every user passes.
17
+ * `pgRoles` is omitted at the `public` default, so a rule that targets every
18
+ * connection, nearly all of them, carries no advanced field it does not need.
19
+ * - The WITH CHECK is kept whether or not there is a USING beside it. Every
20
+ * INSERT policy has only a check, and a rule with neither clause compiles to
21
+ * `WITH CHECK (false)`, which stops every insert.
22
+ * - `mode` is written when the policy states one: a restrictive policy read
23
+ * back as permissive is OR'd with every grant beside it.
24
+ * - Retired RLS helpers (`auth.uid()`) are respelled, as `sqlToPolicy` does
25
+ * for what it reads, because this rule is written into the project's config.
26
+ */
27
+ export declare function policyToSecurityRule(policy: Partial<PostgresPolicy>): SecurityRule;
@@ -0,0 +1,25 @@
1
+ /**
2
+ * Wrap text that came out of an application's data in an explicit
3
+ * untrusted-data envelope, for a language model to read.
4
+ *
5
+ * A row is text somebody else wrote — a `body` column an anonymous visitor
6
+ * filled in, a support-ticket title — and an MCP tool hands it to the model on
7
+ * the same channel as the tool contract the model is following, in a session
8
+ * that also holds `update_document` and `delete_document`. So an instruction
9
+ * smuggled through a row is an instruction with reach. A fenced envelope does
10
+ * not solve prompt injection; handing the row over with no marking at all is
11
+ * below the floor.
12
+ *
13
+ * The fence has to be one the data cannot close. A fixed end marker is text any
14
+ * row can print, and whatever follows it would sit outside the block — the one
15
+ * place the envelope tells the model to trust. So each envelope's markers carry
16
+ * an id minted for this response, after the data was written, and a
17
+ * marker-like string inside the body is broken with a zero-width space so it
18
+ * does not read as one. The source is JSON-escaped (with `<` and `>` too), so
19
+ * it cannot end the opening marker early either.
20
+ *
21
+ * The remote MCP endpoint (`@rebasepro/server`) wraps with this. The local MCP
22
+ * server (`@rebasepro/mcp`) has its own copy, held to this one's output by a
23
+ * test in that package.
24
+ */
25
+ export declare function untrustedEnvelope(source: string, body: string): string;
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@rebasepro/common",
3
- "version": "0.22.0",
3
+ "version": "0.24.0",
4
4
  "description": "Rebase shared core — collection registry, data driver adapter and fluent query builder. No React dependency.",
5
5
  "keywords": [
6
6
  "rebase",
@@ -44,8 +44,8 @@
44
44
  "dependencies": {
45
45
  "fast-equals": "6.0.2",
46
46
  "json-logic-js": "^2.0.5",
47
- "@rebasepro/utils": "0.22.0",
48
- "@rebasepro/types": "0.22.0"
47
+ "@rebasepro/types": "0.24.0",
48
+ "@rebasepro/utils": "0.24.0"
49
49
  },
50
50
  "devDependencies": {
51
51
  "@jest/globals": "^30.4.1",
@@ -1 +0,0 @@
1
- export {};
@@ -1 +0,0 @@
1
- export {};
@@ -1 +0,0 @@
1
- export {};
@@ -1 +0,0 @@
1
- export {};