@stratum-hq/mysql 0.5.0 → 0.6.1

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/README.md CHANGED
@@ -2,6 +2,8 @@
2
2
 
3
3
  MySQL tenant isolation for [Stratum](https://github.com/stratum-hq/Stratum). Three isolation strategies, ORM integrations, and MySQL View utilities.
4
4
 
5
+ Read the documentation at [docs.stratum-hq.org/packages/mysql](https://docs.stratum-hq.org/packages/mysql/).
6
+
5
7
  ## Isolation Strategies
6
8
 
7
9
  | Strategy | Mechanism | Security Level |
@@ -79,7 +81,7 @@ await adapter.closeAll();
79
81
 
80
82
  ## ORM Integrations
81
83
 
82
- ### TypeORM Subscriber (writes only; reads are not scoped)
84
+ ### TypeORM Subscriber
83
85
 
84
86
  ```typescript
85
87
  import { registerStratumSubscriber } from "@stratum-hq/mysql";
@@ -91,15 +93,21 @@ registerStratumSubscriber(dataSource);
91
93
 
92
94
  Call `registerStratumSubscriber()` after `dataSource.initialize()`. It throws before that, because `initialize()` replaces the subscriber list. Do not put `StratumTypeOrmSubscriber` in the `subscribers` option: TypeORM only loads classes decorated with `@EventSubscriber()` from that option.
93
95
 
94
- Inserts get the current tenant's `tenant_id`. Updates never change `tenant_id`: `save()` keeps the loaded value, and `update()` / query builder updates drop it from the SET values.
96
+ Inserts get the current tenant's `tenant_id`, in whichever entity property maps to the `tenant_id` column (a relation whose join column is `tenant_id` cannot set or change it). Updates never change `tenant_id`: `save()` keeps the loaded value, and `update()` / query builder updates drop it from the SET values. The insert and update query builders enforce both, so `save(entity, { listeners: false })` and `.callListeners(false)` do not skip them.
95
97
 
96
- `registerStratumSubscriber()` also scopes updates and deletes to the current tenant: repository `update()`, `delete()`, `softDelete()`, `restore()`, `save()` of an existing row, `remove()`, and query builder updates and deletes get `tenant_id = <current tenant>` ANDed to their WHERE clause. A row of another tenant is left unchanged, `save()` of a row that belongs to another tenant throws, and an update or delete of a tenant table outside a tenant context is refused. An update or delete builder aimed at a raw table name (not an entity) is treated as a tenant table and always gets the tenant condition, so it fails on a table without `tenant_id`. `TRUNCATE` of a table with a `tenant_id` column (`repository.clear()`, `queryRunner.clearTable()`) is refused, because it would remove every tenant's rows. A subscriber added to `dataSource.subscribers` by hand refuses every UPDATE and DELETE, so always register it with `registerStratumSubscriber()`.
98
+ `registerStratumSubscriber()` also scopes updates and deletes to the current tenant: repository `update()`, `delete()`, `softDelete()`, `restore()`, `save()` of an existing row, `remove()`, and query builder updates and deletes get `tenant_id = <current tenant>` ANDed to their WHERE clause. A row of another tenant is left unchanged, and an update or delete of a tenant table outside a tenant context is refused. `save()` of a row that belongs to another tenant throws: before an insert (other than an upsert) whose entity supplies its whole primary key, the subscriber looks that key up without the read scope, uses the result only for this check, and refuses the insert when the row belongs to another tenant. An update or delete builder aimed at a raw table name (not an entity) is treated as a tenant table and always gets the tenant condition, so it fails on a table without `tenant_id`. `TRUNCATE` of a table with a `tenant_id` column (`repository.clear()`, `queryRunner.clearTable()`) is refused, because it would remove every tenant's rows. A subscriber added to `dataSource.subscribers` by hand refuses every UPDATE and DELETE, so always register it with `registerStratumSubscriber()`.
97
99
 
98
100
  Upserts (`repository.upsert()` and `.orUpdate()`) also get the current tenant's `tenant_id` on insert. If the conflict update writes `tenant_id`, the subscriber rejects the statement before it runs. To upsert, leave `tenant_id` out of the entity values and out of the `orUpdate()` columns.
99
101
 
102
+ `INSERT ... SELECT` (`valuesFromSelect()`) into a tenant entity is refused, because the tenant of the selected rows cannot be set. Into another table it is allowed, and a SELECT of a tenant entity keeps its tenant condition.
103
+
100
104
  MySQL applies `ON DUPLICATE KEY UPDATE` on a conflict with any unique key of the table, whatever conflict columns you pass. The subscriber therefore allows an upsert only when every unique key of the target table, including the primary key, contains `tenant_id` (for example `PRIMARY KEY (tenant_id, id)`). It reads the keys from `information_schema` before the statement runs, and rejects the upsert otherwise.
101
105
 
102
- **Limitation:** reads (`find()`, `findOne()`, query builder selects, and the row that `save()` loads before it updates), raw SQL (`dataSource.query()`), and SQL taken from `getQuery()` / `getQueryAndParameters()` and run by hand are not scoped; the tenant condition is added only when a builder's `execute()` runs. Add the tenant condition yourself, or use the shared-table adapter's structured methods for tenant-scoped reads.
106
+ `registerStratumSubscriber()` also scopes reads. Every query that TypeORM's select query builder builds on the data source gets `tenant_id = <current tenant>`: repository `find*()`, `findOne*()`, `count*()`, `exists*()`, `sum()` / `average()` / `minimum()` / `maximum()` and `preload()`, query builder `getMany()`, `getOne()`, `getRawMany()`, `getRawOne()`, `getCount()`, `getManyAndCount()`, `getExists()` and `stream()`, relation loading (joins, eager relations, `relationLoadStrategy: "query"`), the row that `save()` loads before it writes, subqueries, and the count and pagination queries TypeORM builds internally. The condition is ANDed to the WHERE clause for the entity in FROM, so an `orWhere()` cannot widen the read, and it is added to the ON condition of every joined entity with a `tenant_id` column, so `leftJoinAndSelect()` still returns the parent row and leaves another tenant's related row out. A read of an entity with a `tenant_id` column outside a tenant context is refused. Entities without a `tenant_id` column, and data sources without the subscriber, are not affected.
107
+
108
+ A view entity whose `expression` is a query builder is created by `synchronize()` without the tenant condition, because the view definition is one schema object shared by all tenants. Reads from a view entity are scoped like reads from a table when the view has a `tenant_id` column. A view without a `tenant_id` column is read unscoped.
109
+
110
+ **Limitation:** raw SQL (`dataSource.query()`, `queryRunner.query()`), SQL taken from `getQuery()` / `getQueryAndParameters()` and run by hand (a select builder's SQL includes the tenant condition, but an update or delete builder adds it only when its `execute()` runs), reads from and inserts into a table name that does not exactly match (including letter case) the name or table name of an entity on the data source (such inserts are not given a tenant_id), and many-to-many junction tables are not scoped. Add the tenant condition to those yourself, or use the shared-table adapter's structured methods.
103
111
 
104
112
  ### Knex Helper
105
113
 
@@ -121,13 +129,29 @@ Joins (`join()`, `leftJoin()`, `crossJoin()`, `joinRaw()` and the other join for
121
129
  import { withMysqlTenantScope } from "@stratum-hq/mysql";
122
130
 
123
131
  await withMysqlTenantScope(sequelize, "tenant-a", async (scoped, transaction) => {
124
- // @stratum_tenant_id is set on the transaction's connection only.
125
- // Pass the transaction to every query, or it runs on another connection.
126
- // Guaranteed cleanup via try/finally, even on errors
127
- const [rows] = await scoped.query("SELECT @stratum_tenant_id", { transaction });
132
+ // Models with a tenant_id attribute see and change only this tenant's rows.
133
+ const notes = await Note.findAll({ include: ["owner"], transaction });
134
+ await Note.create({ name: "new" }, { transaction }); // tenant_id is set for you
128
135
  });
129
136
  ```
130
137
 
138
+ Inside the callback, for every model with a `tenant_id` attribute:
139
+
140
+ - `findAll()`, `findOne()`, `findByPk()`, `findAndCountAll()`, `count()`, `sum()`, `min()`, `max()` and `reload()` return only the tenant's rows. Every include of a tenant model is filtered in its join condition, including includes added by default and named scopes, by an included model's own default scope, by `include: { all: true }` and by hooks, so an include that is not `required` still returns the parent row. A scope's own where clause is kept.
141
+ - `update()`, `destroy()`, `restore()`, `increment()` and `decrement()` change only the tenant's rows. Updates never write `tenant_id`, whether it is given by attribute name or column name, in any letter case, and `increment()` / `decrement()` of `tenant_id` are refused. As outside the helper, `update()`, `destroy()` and `increment()` without a `where` are refused by Sequelize.
142
+ - `create()`, `save()` of a new instance and `bulkCreate()` write the tenant's `tenant_id`, whatever value the caller passed, and add it to a `fields` list that leaves it out.
143
+ - `save()`, `destroy()` and `restore()` of an instance whose row belongs to another tenant throw, and so do they for an existing instance of a model without a primary key, whose row cannot be checked.
144
+ - `upsert()`, `bulkCreate()` with `updateOnDuplicate`, `truncate()`, and `or: true` or `right: true` on an include of a tenant model are refused.
145
+ - Right before each query, the tenant condition is checked again on the where clause and on every include of a tenant model. A query whose condition a hook removed (for example a `beforeFind` hook that replaces `options.where`, or a `beforeFindAfterOptions` hook that adds includes) is refused.
146
+ - A query whose options name a tenant model or instance but that did not go through these methods throws, also when it runs inside a model hook. This covers, for example, `queryInterface.select(Note, ...)`. `queryInterface` calls that take only a table name, such as `bulkInsert()`, `bulkUpdate()` and `bulkDelete()`, carry no model and are not scoped, like raw SQL.
147
+ - `hooks: false` does not skip the filter.
148
+
149
+ `upsert()` on a model with a `tenant_id` attribute is always refused inside the callback, because MySQL applies `ON DUPLICATE KEY UPDATE` on any unique key, so a conflict could update another tenant's row. Look the row up with `findOne()` and then `update()` or `create()` it instead.
150
+
151
+ The helper also sets `@stratum_tenant_id` on the transaction's connection and clears it in a `finally` block. Pass the transaction to queries that must run in it.
152
+
153
+ **Not scoped:** raw `sequelize.query()`, `queryInterface` calls by table name, models without a `tenant_id` attribute, the through (junction) model of a many-to-many include, and any code outside the callback. The helper throws when it is given something other than a Sequelize v6 instance.
154
+
131
155
  ## MySQL Views (not supported)
132
156
 
133
157
  `createTenantView()` is deprecated and always throws. MySQL does not allow a view to read a session variable (`ER_VIEW_SELECT_VARIABLE`), so a view filtered on `@stratum_tenant_id` cannot be created. Use the shared-table adapter's scoped methods. `setTenantSession()` and `dropTenantView()` remain available.
@@ -3,14 +3,36 @@ export interface SequelizeLike {
3
3
  transaction<T>(fn: (t: unknown) => Promise<T>): Promise<T>;
4
4
  }
5
5
  /**
6
- * Runs fn inside a session-variable scope for MySQL tenant isolation.
7
- * Sets @stratum_tenant_id inside a Sequelize transaction and clears it in a
8
- * finally block, even if fn throws.
6
+ * Runs fn with the tenant's rows scoped for Sequelize models, inside a
7
+ * transaction that also sets the @stratum_tenant_id session variable.
9
8
  *
10
- * The variable exists only on the transaction's connection. fn receives that
11
- * transaction as its second argument, and every query inside fn must pass it
12
- * (`{ transaction }`); a query without it runs on another pooled connection
13
- * where the variable is not set.
9
+ * Inside fn, for every model with a tenant_id attribute:
10
+ * - findAll, findOne, findByPk, findAndCountAll, count, sum, min, max and
11
+ * reload() see only the tenant's rows, and every include of a tenant model
12
+ * (including those that scopes and hooks add) is filtered in its join
13
+ * condition, so a non-required include keeps the parent;
14
+ * - update, destroy, restore and increment/decrement change only the tenant's
15
+ * rows; updates never write tenant_id (by attribute or column name), and
16
+ * increment/decrement of tenant_id is refused. update, destroy and increment
17
+ * without a where clause are still refused by Sequelize;
18
+ * - create, save of a new instance and bulkCreate write the tenant's tenant_id;
19
+ * - save, destroy and restore of an instance whose row belongs to another
20
+ * tenant, or of a model without a primary key, throw;
21
+ * - upsert, bulkCreate with updateOnDuplicate, truncate, and `or` / `right`
22
+ * on an include of a tenant model are refused, and a query that carries a
23
+ * tenant model but bypasses these methods throws, also inside model hooks;
24
+ * - right before each query the tenant condition is checked again, so a query
25
+ * whose condition a hook removed is refused.
26
+ * Hooks passed `hooks: false` do not skip the filter. Raw `sequelize.query()`
27
+ * and models without a tenant_id attribute are not scoped. Outside fn,
28
+ * Sequelize behaves as usual.
29
+ *
30
+ * The session variable exists only on the transaction's connection. fn
31
+ * receives that transaction as its second argument; pass it to queries that
32
+ * must run in the transaction.
33
+ *
34
+ * @throws Error when sequelize is not a Sequelize v6 instance, because the
35
+ * tenant scope could not be applied.
14
36
  */
15
37
  export declare function withMysqlTenantScope<T>(sequelize: SequelizeLike, tenantId: string, fn: (sequelize: SequelizeLike, transaction: unknown) => Promise<T>): Promise<T>;
16
38
  //# sourceMappingURL=sequelize.d.ts.map
@@ -1 +1 @@
1
- {"version":3,"file":"sequelize.d.ts","sourceRoot":"","sources":["../../src/integrations/sequelize.ts"],"names":[],"mappings":"AAEA,MAAM,WAAW,aAAa;IAC5B,KAAK,CAAC,GAAG,EAAE,MAAM,EAAE,OAAO,CAAC,EAAE,OAAO,GAAG,OAAO,CAAC,OAAO,CAAC,CAAC;IACxD,WAAW,CAAC,CAAC,EAAE,EAAE,EAAE,CAAC,CAAC,EAAE,OAAO,KAAK,OAAO,CAAC,CAAC,CAAC,GAAG,OAAO,CAAC,CAAC,CAAC,CAAC;CAC5D;AAED;;;;;;;;;GASG;AACH,wBAAsB,oBAAoB,CAAC,CAAC,EAC1C,SAAS,EAAE,aAAa,EACxB,QAAQ,EAAE,MAAM,EAChB,EAAE,EAAE,CAAC,SAAS,EAAE,aAAa,EAAE,WAAW,EAAE,OAAO,KAAK,OAAO,CAAC,CAAC,CAAC,GACjE,OAAO,CAAC,CAAC,CAAC,CAYZ"}
1
+ {"version":3,"file":"sequelize.d.ts","sourceRoot":"","sources":["../../src/integrations/sequelize.ts"],"names":[],"mappings":"AAKA,MAAM,WAAW,aAAa;IAC5B,KAAK,CAAC,GAAG,EAAE,MAAM,EAAE,OAAO,CAAC,EAAE,OAAO,GAAG,OAAO,CAAC,OAAO,CAAC,CAAC;IACxD,WAAW,CAAC,CAAC,EAAE,EAAE,EAAE,CAAC,CAAC,EAAE,OAAO,KAAK,OAAO,CAAC,CAAC,CAAC,GAAG,OAAO,CAAC,CAAC,CAAC,CAAC;CAC5D;AA+CD;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;GA+BG;AACH,wBAAsB,oBAAoB,CAAC,CAAC,EAC1C,SAAS,EAAE,aAAa,EACxB,QAAQ,EAAE,MAAM,EAChB,EAAE,EAAE,CAAC,SAAS,EAAE,aAAa,EAAE,WAAW,EAAE,OAAO,KAAK,OAAO,CAAC,CAAC,CAAC,GACjE,OAAO,CAAC,CAAC,CAAC,CAcZ"}
@@ -1,29 +1,420 @@
1
1
  "use strict";
2
- // ─── Structural types (no hard dependency on sequelize) ───
3
2
  Object.defineProperty(exports, "__esModule", { value: true });
4
3
  exports.withMysqlTenantScope = withMysqlTenantScope;
4
+ const node_async_hooks_1 = require("node:async_hooks");
5
+ const utils_js_1 = require("../utils.js");
6
+ const REFUSED = "Stratum: withMysqlTenantScope";
7
+ /** The tenant scope of the running withMysqlTenantScope callback. */
8
+ const scopeStorage = new node_async_hooks_1.AsyncLocalStorage();
9
+ /** True inside a model call that tenant scoping has already handled (but not inside its hooks). */
10
+ const scopedCall = new node_async_hooks_1.AsyncLocalStorage();
5
11
  /**
6
- * Runs fn inside a session-variable scope for MySQL tenant isolation.
7
- * Sets @stratum_tenant_id inside a Sequelize transaction and clears it in a
8
- * finally block, even if fn throws.
12
+ * The model method whose own options the next top-level _injectScope call
13
+ * scopes, and whether that method requires a where clause (update, destroy,
14
+ * increment), in which case a missing where is left for Sequelize to refuse.
15
+ */
16
+ const topLevelCall = new node_async_hooks_1.AsyncLocalStorage();
17
+ const PATCHED = Symbol("stratum.sequelizeTenantScope");
18
+ const guardedInstances = new WeakSet();
19
+ /**
20
+ * Runs fn with the tenant's rows scoped for Sequelize models, inside a
21
+ * transaction that also sets the @stratum_tenant_id session variable.
22
+ *
23
+ * Inside fn, for every model with a tenant_id attribute:
24
+ * - findAll, findOne, findByPk, findAndCountAll, count, sum, min, max and
25
+ * reload() see only the tenant's rows, and every include of a tenant model
26
+ * (including those that scopes and hooks add) is filtered in its join
27
+ * condition, so a non-required include keeps the parent;
28
+ * - update, destroy, restore and increment/decrement change only the tenant's
29
+ * rows; updates never write tenant_id (by attribute or column name), and
30
+ * increment/decrement of tenant_id is refused. update, destroy and increment
31
+ * without a where clause are still refused by Sequelize;
32
+ * - create, save of a new instance and bulkCreate write the tenant's tenant_id;
33
+ * - save, destroy and restore of an instance whose row belongs to another
34
+ * tenant, or of a model without a primary key, throw;
35
+ * - upsert, bulkCreate with updateOnDuplicate, truncate, and `or` / `right`
36
+ * on an include of a tenant model are refused, and a query that carries a
37
+ * tenant model but bypasses these methods throws, also inside model hooks;
38
+ * - right before each query the tenant condition is checked again, so a query
39
+ * whose condition a hook removed is refused.
40
+ * Hooks passed `hooks: false` do not skip the filter. Raw `sequelize.query()`
41
+ * and models without a tenant_id attribute are not scoped. Outside fn,
42
+ * Sequelize behaves as usual.
9
43
  *
10
- * The variable exists only on the transaction's connection. fn receives that
11
- * transaction as its second argument, and every query inside fn must pass it
12
- * (`{ transaction }`); a query without it runs on another pooled connection
13
- * where the variable is not set.
44
+ * The session variable exists only on the transaction's connection. fn
45
+ * receives that transaction as its second argument; pass it to queries that
46
+ * must run in the transaction.
47
+ *
48
+ * @throws Error when sequelize is not a Sequelize v6 instance, because the
49
+ * tenant scope could not be applied.
14
50
  */
15
51
  async function withMysqlTenantScope(sequelize, tenantId, fn) {
52
+ (0, utils_js_1.assertTenantId)(tenantId);
53
+ installTenantScoping(sequelize);
16
54
  return sequelize.transaction(async (transaction) => {
17
55
  await sequelize.query("SET @stratum_tenant_id = ?", {
18
56
  replacements: [tenantId],
19
57
  transaction,
20
58
  });
21
59
  try {
22
- return await fn(sequelize, transaction);
60
+ return await scopeStorage.run({ sequelize, tenantId }, () => fn(sequelize, transaction));
23
61
  }
24
62
  finally {
25
63
  await sequelize.query("SET @stratum_tenant_id = NULL", { transaction });
26
64
  }
27
65
  });
28
66
  }
67
+ /** Patches Sequelize's Model class once and guards this instance's queries. */
68
+ function installTenantScoping(sequelize) {
69
+ const candidate = sequelize;
70
+ const Model = candidate.constructor?.Model;
71
+ const Op = candidate.constructor?.Op;
72
+ if (typeof Model !== "function" || !Op || typeof candidate.addHook !== "function") {
73
+ throw new Error(`${REFUSED} needs a Sequelize v6 instance, because it scopes the tenant's rows through Sequelize's models.`);
74
+ }
75
+ const statics = Model;
76
+ if (!statics[PATCHED]) {
77
+ patchModel(statics, Op.and);
78
+ statics[PATCHED] = true;
79
+ }
80
+ if (!guardedInstances.has(sequelize)) {
81
+ // Any model query that did not go through the scoped methods is refused.
82
+ candidate.addHook("beforeQuery", (options) => {
83
+ const scope = scopeStorage.getStore();
84
+ if (!scope || scope.sequelize !== sequelize || scopedCall.getStore())
85
+ return;
86
+ const instance = options.instance;
87
+ const model = options.model ?? instance?.constructor;
88
+ if (model && tenantAttribute(model)) {
89
+ throw new Error(`${REFUSED}: this query on a tenant model is not tenant-scoped and was refused.`);
90
+ }
91
+ });
92
+ guardQueryInterface(candidate, Op.and);
93
+ guardedInstances.add(sequelize);
94
+ }
95
+ }
96
+ /**
97
+ * Checks the statements that Sequelize's query interface is about to build for
98
+ * a tenant model inside the callback. Hooks run after the tenant condition is
99
+ * added and can replace a where clause or add includes, so the condition is
100
+ * verified here, right before the query, and the query is refused when it is
101
+ * missing. Values written to tenant_id (by attribute or column name, in any
102
+ * letter case) are dropped from updates and replaced on inserts.
103
+ */
104
+ function guardQueryInterface(sequelize, and) {
105
+ const queryInterface = sequelize.getQueryInterface();
106
+ const active = (model) => {
107
+ const scope = scopeStorage.getStore();
108
+ if (!model || !scope || scope.sequelize !== sequelize || !tenantAttribute(model))
109
+ return undefined;
110
+ return scope.tenantId;
111
+ };
112
+ const hasTenantCondition = (where, names, tenantId) => {
113
+ if (!where || typeof where !== "object")
114
+ return false;
115
+ if (Array.isArray(where))
116
+ return where.some((part) => hasTenantCondition(part, names, tenantId));
117
+ const record = where;
118
+ if (Object.keys(record).some((key) => names.has(key.toLowerCase()) && record[key] === tenantId))
119
+ return true;
120
+ // Only AND positions count; a condition under OR does not scope the query.
121
+ return record[and] !== undefined && hasTenantCondition(record[and], names, tenantId);
122
+ };
123
+ const requireTenantCondition = (model, where, tenantId) => {
124
+ if (!hasTenantCondition(where, tenantNames(model), tenantId)) {
125
+ throw new Error(`${REFUSED}: this query is not tenant-scoped, because its tenant condition is missing ` +
126
+ "(a hook may have replaced the where clause or added an include), and was refused.");
127
+ }
128
+ };
129
+ const checkIncludes = (include, tenantId) => {
130
+ for (const item of Array.isArray(include) ? include : include ? [include] : []) {
131
+ const entry = item;
132
+ const model = entry.model;
133
+ if (!entry._pseudo && model && tenantAttribute(model)) {
134
+ if (entry.or || entry.right) {
135
+ throw new Error(`${REFUSED}: "or" and "right" are refused on an include of a tenant model.`);
136
+ }
137
+ requireTenantCondition(model, entry.where, tenantId);
138
+ }
139
+ checkIncludes(entry.include, tenantId);
140
+ }
141
+ };
142
+ const withoutTenantKeys = (model, values) => {
143
+ const names = tenantNames(model);
144
+ return Object.fromEntries(Object.entries(values ?? {}).filter(([key]) => !names.has(key.toLowerCase())));
145
+ };
146
+ const withTenantValue = (model, values, tenantId) => ({
147
+ ...withoutTenantKeys(model, values),
148
+ [tenantField(model)]: tenantId,
149
+ });
150
+ const wrap = (name, check) => {
151
+ const original = queryInterface[name];
152
+ queryInterface[name] = function (...args) {
153
+ try {
154
+ check(args);
155
+ }
156
+ catch (error) {
157
+ return Promise.reject(error);
158
+ }
159
+ return original.apply(this, args);
160
+ };
161
+ };
162
+ wrap("select", (args) => {
163
+ const model = args[0];
164
+ const options = args[2];
165
+ const tenantId = active(model);
166
+ if (tenantId)
167
+ requireTenantCondition(model, options.where, tenantId);
168
+ const scope = scopeStorage.getStore();
169
+ if (scope && scope.sequelize === sequelize)
170
+ checkIncludes(options.include, scope.tenantId);
171
+ });
172
+ wrap("rawSelect", (args) => {
173
+ const options = args[1];
174
+ const model = args[3];
175
+ const tenantId = active(model);
176
+ if (tenantId)
177
+ requireTenantCondition(model, options.where, tenantId);
178
+ const scope = scopeStorage.getStore();
179
+ if (scope && scope.sequelize === sequelize)
180
+ checkIncludes(options.include, scope.tenantId);
181
+ });
182
+ wrap("bulkUpdate", (args) => {
183
+ const model = args[3]?.model;
184
+ const tenantId = active(model);
185
+ if (!tenantId)
186
+ return;
187
+ requireTenantCondition(model, args[2], tenantId);
188
+ args[1] = withoutTenantKeys(model, args[1]);
189
+ });
190
+ wrap("bulkDelete", (args) => {
191
+ const model = args[3];
192
+ const tenantId = active(model);
193
+ if (tenantId)
194
+ requireTenantCondition(model, args[1], tenantId);
195
+ });
196
+ for (const name of ["increment", "decrement"]) {
197
+ wrap(name, (args) => {
198
+ const model = args[0];
199
+ const tenantId = active(model);
200
+ if (!tenantId)
201
+ return;
202
+ const names = tenantNames(model);
203
+ const touched = [...Object.keys(args[3] ?? {}), ...Object.keys(args[4] ?? {})];
204
+ if (touched.some((key) => names.has(key.toLowerCase()))) {
205
+ throw new Error(`${REFUSED}: increment or decrement of tenant_id is refused.`);
206
+ }
207
+ requireTenantCondition(model, args[2], tenantId);
208
+ });
209
+ }
210
+ wrap("update", (args) => {
211
+ const model = args[0].constructor;
212
+ if (active(model))
213
+ args[2] = withoutTenantKeys(model, args[2]);
214
+ });
215
+ wrap("insert", (args) => {
216
+ const model = args[0]?.constructor;
217
+ const tenantId = active(model);
218
+ if (tenantId)
219
+ args[2] = withTenantValue(model, args[2], tenantId);
220
+ });
221
+ wrap("bulkInsert", (args) => {
222
+ const model = args[2]?.model;
223
+ const tenantId = active(model);
224
+ if (tenantId) {
225
+ args[1] = args[1].map((record) => withTenantValue(model, record, tenantId));
226
+ }
227
+ });
228
+ }
229
+ /** The tenant attribute's name and column name, lower-cased. */
230
+ function tenantNames(model) {
231
+ const attribute = tenantAttribute(model);
232
+ if (!attribute)
233
+ return new Set();
234
+ return new Set([attribute.toLowerCase(), tenantField(model).toLowerCase()]);
235
+ }
236
+ /** The column name of the tenant attribute. */
237
+ function tenantField(model) {
238
+ const attribute = tenantAttribute(model);
239
+ return model.rawAttributes?.[attribute]?.field ?? attribute;
240
+ }
241
+ /** Returns the attribute that maps to the tenant_id column, if the model has one. */
242
+ function tenantAttribute(model) {
243
+ for (const [name, attribute] of Object.entries(model.rawAttributes ?? {})) {
244
+ if ((attribute.field ?? name).toLowerCase() === "tenant_id")
245
+ return name;
246
+ }
247
+ return undefined;
248
+ }
249
+ /** Returns the running scope when it belongs to this model's Sequelize instance. */
250
+ function scopeFor(model) {
251
+ const scope = scopeStorage.getStore();
252
+ return scope && scope.sequelize === model.sequelize ? scope : undefined;
253
+ }
254
+ function patchModel(Model, and) {
255
+ const withTenant = (where, attribute, tenantId) => where === undefined || where === null
256
+ ? { [attribute]: tenantId }
257
+ : { [and]: [where, { [attribute]: tenantId }] };
258
+ // Sequelize merges scopes into a call's options, and into each include, in
259
+ // _injectScope. The tenant condition is added after that merge, so scope
260
+ // includes, scope where clauses and includes added by hooks are all covered.
261
+ const originalInject = Model._injectScope;
262
+ Model._injectScope = function (options) {
263
+ const result = originalInject.call(this, options);
264
+ const active = scopeFor(this);
265
+ const attribute = tenantAttribute(this);
266
+ if (!active || !attribute)
267
+ return result;
268
+ if (options.association !== undefined) {
269
+ // An include being validated (_validateIncludedElement).
270
+ if (options.or || options.right) {
271
+ throw new Error(`${REFUSED}: "or" and "right" are refused on an include of a tenant model.`);
272
+ }
273
+ // An include with a where clause defaults to required; keep the
274
+ // caller's join type so a LEFT JOIN still returns the parent row.
275
+ if (options.required === undefined)
276
+ options.required = !!options.where;
277
+ options.where = withTenant(options.where, attribute, active.tenantId);
278
+ return result;
279
+ }
280
+ const call = topLevelCall.getStore();
281
+ if (call?.model === this && call.requiresWhere && (options.where === undefined || options.where === null)) {
282
+ return result;
283
+ }
284
+ options.where = withTenant(options.where, attribute, active.tenantId);
285
+ return result;
286
+ };
287
+ // Model hooks run user code; the beforeQuery guard applies there again.
288
+ const originalRunHooks = Model.runHooks;
289
+ Model.runHooks = function (...args) {
290
+ return scopedCall.run(false, () => originalRunHooks.apply(this, args));
291
+ };
292
+ const wrapStatic = (name, requiresWhere, scope) => {
293
+ const original = Model[name];
294
+ Model[name] = function (...args) {
295
+ const active = scopeFor(this);
296
+ if (!active)
297
+ return original.apply(this, args);
298
+ const scopedArgs = scope(this, args, active.tenantId);
299
+ const run = () => scopedCall.run(true, () => original.apply(this, scopedArgs));
300
+ return requiresWhere === undefined ? run() : topLevelCall.run({ model: this, requiresWhere }, run);
301
+ };
302
+ };
303
+ const unchanged = (_model, args) => args;
304
+ const refuseForTenantModel = (what) => (model, args) => {
305
+ if (tenantAttribute(model))
306
+ throw new Error(`${REFUSED}: ${what} on a tenant model is refused.`);
307
+ return args;
308
+ };
309
+ wrapStatic("findAll", false, unchanged);
310
+ wrapStatic("aggregate", false, unchanged);
311
+ wrapStatic("increment", true, unchanged);
312
+ wrapStatic("update", true, (model, [values, options]) => {
313
+ // Drop tenant_id by attribute or column name, in any letter case.
314
+ const names = tenantNames(model);
315
+ const isTenantKey = (key) => typeof key === "string" && names.has(key.toLowerCase());
316
+ const scopedValues = Object.fromEntries(Object.entries(values ?? {}).filter(([key]) => !isTenantKey(key)));
317
+ const scopedOptions = { ...(options ?? {}) };
318
+ if (Array.isArray(scopedOptions.fields))
319
+ scopedOptions.fields = scopedOptions.fields.filter((f) => !isTenantKey(f));
320
+ return [scopedValues, scopedOptions];
321
+ });
322
+ wrapStatic("destroy", true, (model, args) => {
323
+ if (tenantAttribute(model) && args[0]?.truncate) {
324
+ throw new Error(`${REFUSED}: truncate on a tenant model is refused, because it removes every tenant's rows.`);
325
+ }
326
+ return args;
327
+ });
328
+ // restore() does not go through _injectScope; Sequelize does not require a
329
+ // where clause for it, so the tenant condition is always added.
330
+ wrapStatic("restore", undefined, (model, [options], tenantId) => {
331
+ const attribute = tenantAttribute(model);
332
+ const scoped = { ...(options ?? {}) };
333
+ if (attribute)
334
+ scoped.where = withTenant(scoped.where, attribute, tenantId);
335
+ return [scoped];
336
+ });
337
+ wrapStatic("upsert", undefined, refuseForTenantModel("upsert"));
338
+ wrapStatic("bulkCreate", undefined, (model, [records, options], tenantId) => {
339
+ const attribute = tenantAttribute(model);
340
+ if (!attribute)
341
+ return [records, options];
342
+ const scopedOptions = { ...(options ?? {}) };
343
+ if (scopedOptions.updateOnDuplicate) {
344
+ throw new Error(`${REFUSED}: bulkCreate with updateOnDuplicate on a tenant model is refused.`);
345
+ }
346
+ if (Array.isArray(scopedOptions.fields) && !scopedOptions.fields.includes(attribute)) {
347
+ scopedOptions.fields = [...scopedOptions.fields, attribute];
348
+ }
349
+ const scopedRecords = records.map((record) => {
350
+ if (record instanceof Model) {
351
+ record.setDataValue(attribute, tenantId);
352
+ return record;
353
+ }
354
+ return { ...record, [attribute]: tenantId };
355
+ });
356
+ return [scopedRecords, scopedOptions];
357
+ });
358
+ const proto = Model.prototype;
359
+ const wrapInstance = (name) => {
360
+ const original = proto[name];
361
+ proto[name] = async function (...args) {
362
+ const model = this.constructor;
363
+ const active = scopeFor(model);
364
+ const attribute = tenantAttribute(model);
365
+ if (!active || !attribute)
366
+ return original.apply(this, args);
367
+ const options = { ...(args[0] ?? {}) };
368
+ const names = tenantNames(model);
369
+ const isTenantKey = (key) => typeof key === "string" && names.has(key.toLowerCase());
370
+ if (name === "save" && this.isNewRecord) {
371
+ if (Array.isArray(options.fields) && !options.fields.includes(attribute)) {
372
+ options.fields = [...options.fields, attribute];
373
+ }
374
+ }
375
+ else {
376
+ await assertRowOfTenant(this, attribute, active.tenantId, options.transaction);
377
+ // An existing row keeps its tenant: tenant_id is not written.
378
+ if (name === "save" && Array.isArray(options.fields)) {
379
+ options.fields = options.fields.filter((f) => !isTenantKey(f));
380
+ }
381
+ }
382
+ if (name === "save")
383
+ this.setDataValue(attribute, active.tenantId);
384
+ return scopedCall.run(true, () => original.apply(this, [options, ...args.slice(1)]));
385
+ };
386
+ };
387
+ wrapInstance("save");
388
+ wrapInstance("destroy");
389
+ wrapInstance("restore");
390
+ }
391
+ /**
392
+ * Throws when the row that an instance's primary key identifies belongs to
393
+ * another tenant. The lookup is raw SQL, so it is not tenant-scoped, and its
394
+ * result is used only for this decision.
395
+ */
396
+ async function assertRowOfTenant(instance, attribute, tenantId, transaction) {
397
+ const model = instance.constructor;
398
+ const sequelize = model.sequelize;
399
+ // Without a primary key, Sequelize identifies the row by the where clause
400
+ // of the query that loaded it, which cannot be checked here.
401
+ const key = (model.primaryKeyAttributes ?? []).length > 0 ? instance.where() : null;
402
+ const columns = key && typeof key === "object" ? Object.keys(key) : [];
403
+ if (!key || columns.length === 0) {
404
+ throw new Error(`${REFUSED}: the row's tenant cannot be checked, because the model has no primary key.`);
405
+ }
406
+ const tenantColumn = model.rawAttributes?.[attribute]?.field ?? attribute;
407
+ const sql = `SELECT ${(0, utils_js_1.escapeIdentifier)(tenantColumn)} AS tenant_id ` +
408
+ `FROM ${sequelize.getQueryInterface().queryGenerator.quoteTable(model.getTableName())} ` +
409
+ `WHERE ${columns.map((column) => `${(0, utils_js_1.escapeIdentifier)(column)} = ?`).join(" AND ")} LIMIT 1`;
410
+ const rows = (await sequelize.query(sql, {
411
+ replacements: columns.map((column) => key[column]),
412
+ transaction,
413
+ type: "SELECT",
414
+ raw: true,
415
+ }));
416
+ if (rows.length > 0 && rows[0].tenant_id !== tenantId) {
417
+ throw new Error(`${REFUSED}: the row belongs to another tenant.`);
418
+ }
419
+ }
29
420
  //# sourceMappingURL=sequelize.js.map
@@ -1 +1 @@
1
- {"version":3,"file":"sequelize.js","sourceRoot":"","sources":["../../src/integrations/sequelize.ts"],"names":[],"mappings":";AAAA,6DAA6D;;AAiB7D,oDAgBC;AA1BD;;;;;;;;;GASG;AACI,KAAK,UAAU,oBAAoB,CACxC,SAAwB,EACxB,QAAgB,EAChB,EAAkE;IAElE,OAAO,SAAS,CAAC,WAAW,CAAC,KAAK,EAAE,WAAW,EAAE,EAAE;QACjD,MAAM,SAAS,CAAC,KAAK,CAAC,4BAA4B,EAAE;YAClD,YAAY,EAAE,CAAC,QAAQ,CAAC;YACxB,WAAW;SACZ,CAAC,CAAC;QACH,IAAI,CAAC;YACH,OAAO,MAAM,EAAE,CAAC,SAAS,EAAE,WAAW,CAAC,CAAC;QAC1C,CAAC;gBAAS,CAAC;YACT,MAAM,SAAS,CAAC,KAAK,CAAC,+BAA+B,EAAE,EAAE,WAAW,EAAE,CAAC,CAAC;QAC1E,CAAC;IACH,CAAC,CAAC,CAAC;AACL,CAAC"}
1
+ {"version":3,"file":"sequelize.js","sourceRoot":"","sources":["../../src/integrations/sequelize.ts"],"names":[],"mappings":"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"}
@@ -1,5 +1,33 @@
1
+ /** The part of a TypeORM column's metadata that tenant scoping uses. */
2
+ interface ColumnLike {
3
+ propertyName: string;
4
+ databaseName: string;
5
+ getEntityValue?(entity: Record<string, unknown>): unknown;
6
+ setEntityValue?(entity: Record<string, unknown>, value: unknown): void;
7
+ }
8
+ /** The part of a TypeORM entity's metadata that tenant scoping uses. */
9
+ /** The part of a TypeORM relation's metadata that tenant scoping uses. */
10
+ interface RelationLike {
11
+ propertyName: string;
12
+ joinColumns?: {
13
+ databaseName: string;
14
+ }[];
15
+ }
16
+ interface EntityMetadataLike {
17
+ tablePath: string;
18
+ columns: ColumnLike[];
19
+ primaryColumns: ColumnLike[];
20
+ relations?: RelationLike[];
21
+ }
22
+ interface QueryRunnerLike {
23
+ query(sql: string, parameters?: unknown[]): Promise<unknown>;
24
+ }
1
25
  export interface InsertEvent {
2
26
  entity: Record<string, unknown>;
27
+ /** The inserted entity's metadata, when TypeORM has it. */
28
+ metadata?: EntityMetadataLike;
29
+ /** The query runner that will run the insert. */
30
+ queryRunner?: QueryRunnerLike;
3
31
  }
4
32
  export interface UpdateEvent {
5
33
  /** The entity being saved, or the SET values of a query builder / repository update. */
@@ -11,6 +39,7 @@ export interface UpdateEvent {
11
39
  propertyName: string;
12
40
  databaseName: string;
13
41
  }[];
42
+ relations?: RelationLike[];
14
43
  };
15
44
  }
16
45
  export interface BeforeQueryEvent {
@@ -32,12 +61,20 @@ export interface EntitySubscriberInterface {
32
61
  export interface TypeOrmDataSourceLike {
33
62
  readonly isInitialized: boolean;
34
63
  readonly subscribers: unknown[];
35
- /** Used once to reach TypeORM's update, delete and soft-delete query builder classes. */
64
+ /**
65
+ * Used once to reach TypeORM's select, insert, update, delete and soft-delete
66
+ * query builder classes. The returned builder is itself the select query builder.
67
+ */
36
68
  createQueryBuilder(): {
69
+ insert(): object;
37
70
  update(): object;
38
71
  delete(): object;
39
72
  softDelete(): object;
40
73
  };
74
+ /** Entity and view metadata; view expressions built by a query builder are exempt from the read scope. */
75
+ readonly entityMetadatas?: readonly {
76
+ expression?: unknown;
77
+ }[];
41
78
  }
42
79
  /**
43
80
  * TypeORM subscriber that injects tenant_id into inserted entities via ALS and
@@ -51,13 +88,35 @@ export interface TypeOrmDataSourceLike {
51
88
  * softDelete(), restore()) to the current tenant: `tenant_id = <tenant>` is
52
89
  * ANDed to their WHERE clause, and they are refused outside a tenant context.
53
90
  *
54
- * Not scoped: reads (find, findOne, query builder selects) and raw SQL
55
- * (`dataSource.query()`). Add the tenant condition to those yourself, or use
56
- * the shared-table adapter's structured methods.
91
+ * Registration scopes reads the same way. Every SQL statement that TypeORM's
92
+ * select query builder produces (repository find*, findOne*, count*, exists*,
93
+ * sum/average/min/max, preload(), query builder getMany/getOne/getRawMany/
94
+ * getRawOne/getCount/getManyAndCount/getExists/stream, relation loading, the
95
+ * row that save() loads, and the count and pagination queries TypeORM builds
96
+ * internally) ANDs `tenant_id = <tenant>` for the FROM entity to its WHERE
97
+ * clause and adds it to the ON condition of each joined entity, so a LEFT JOIN
98
+ * still returns the parent row. Reads of an entity with a tenant_id column are
99
+ * refused outside a tenant context.
100
+ *
101
+ * Not scoped: raw SQL (`dataSource.query()`, `queryRunner.query()`), SQL taken
102
+ * from a builder's getQuery() / getQueryAndParameters() and run by hand, reads
103
+ * from a table that has no entity on the data source, and many-to-many junction
104
+ * tables. Add the tenant condition to those yourself, or use the shared-table
105
+ * adapter's structured methods.
57
106
  */
58
107
  export declare class StratumTypeOrmSubscriber implements EntitySubscriberInterface {
59
- /** Injects the current tenant's ID into the entity before insert. */
60
- beforeInsert(event: InsertEvent): void;
108
+ /**
109
+ * Injects the current tenant's ID into the entity before insert, into the
110
+ * property mapped to the tenant_id column.
111
+ *
112
+ * When the entity supplies its whole primary key and the insert builder has
113
+ * not checked it yet (save() runs this hook before the builder), the key is
114
+ * checked against the table first, so a save() with another tenant's key is
115
+ * refused rather than inserted. See checkKeyIsFree.
116
+ *
117
+ * @returns A promise that rejects when the key belongs to another tenant's row.
118
+ */
119
+ beforeInsert(event: InsertEvent): void | Promise<void>;
61
120
  /**
62
121
  * Keeps tenant_id out of an update. On save() the loaded value is restored,
63
122
  * so the column is unchanged; on a repository or query builder update the
@@ -94,8 +153,8 @@ export declare class StratumTypeOrmSubscriber implements EntitySubscriberInterfa
94
153
  * A second call returns the subscriber that the first call added, so the
95
154
  * data source never runs the subscriber twice.
96
155
  *
97
- * It also scopes TypeORM's update, delete and soft-delete query builders to the
98
- * current tenant (see StratumTypeOrmSubscriber). The subscriber refuses an
156
+ * It also scopes TypeORM's select, update, delete and soft-delete query
157
+ * builders to the current tenant (see StratumTypeOrmSubscriber). The subscriber refuses an
99
158
  * UPDATE or DELETE on a data source that was not registered this way.
100
159
  *
101
160
  * @param dataSource - An initialized TypeORM `DataSource`.
@@ -103,4 +162,5 @@ export declare class StratumTypeOrmSubscriber implements EntitySubscriberInterfa
103
162
  * the subscriber list, so an earlier registration has no effect.
104
163
  */
105
164
  export declare function registerStratumSubscriber(dataSource: TypeOrmDataSourceLike): StratumTypeOrmSubscriber;
165
+ export {};
106
166
  //# sourceMappingURL=typeorm-subscriber.d.ts.map
@@ -1 +1 @@
1
- {"version":3,"file":"typeorm-subscriber.d.ts","sourceRoot":"","sources":["../../src/integrations/typeorm-subscriber.ts"],"names":[],"mappings":"AAKA,MAAM,WAAW,WAAW;IAC1B,MAAM,EAAE,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,CAAC;CACjC;AAED,MAAM,WAAW,WAAW;IAC1B,wFAAwF;IACxF,MAAM,CAAC,EAAE,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,GAAG,IAAI,CAAC;IACxC,yEAAyE;IACzE,cAAc,CAAC,EAAE,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,GAAG,IAAI,CAAC;IAChD,QAAQ,CAAC,EAAE;QAAE,OAAO,EAAE;YAAE,YAAY,EAAE,MAAM,CAAC;YAAC,YAAY,EAAE,MAAM,CAAA;SAAE,EAAE,CAAA;KAAE,CAAC;CAC1E;AAED,MAAM,WAAW,gBAAgB;IAC/B,2DAA2D;IAC3D,KAAK,EAAE,MAAM,CAAC;IACd,wDAAwD;IACxD,WAAW,CAAC,EAAE;QAAE,KAAK,CAAC,GAAG,EAAE,MAAM,EAAE,UAAU,CAAC,EAAE,OAAO,EAAE,GAAG,OAAO,CAAC,OAAO,CAAC,CAAA;KAAE,CAAC;IAC/E,uDAAuD;IACvD,UAAU,CAAC,EAAE,MAAM,CAAC;CACrB;AAED,MAAM,WAAW,yBAAyB;IACxC,YAAY,CAAC,CAAC,KAAK,EAAE,WAAW,GAAG,IAAI,GAAG,OAAO,CAAC,IAAI,CAAC,CAAC;IACxD,YAAY,CAAC,CAAC,KAAK,EAAE,WAAW,GAAG,IAAI,GAAG,OAAO,CAAC,IAAI,CAAC,CAAC;IACxD,WAAW,CAAC,CAAC,KAAK,EAAE,gBAAgB,GAAG,IAAI,GAAG,OAAO,CAAC,IAAI,CAAC,CAAC;CAC7D;AAED,4EAA4E;AAC5E,MAAM,WAAW,qBAAqB;IACpC,QAAQ,CAAC,aAAa,EAAE,OAAO,CAAC;IAChC,QAAQ,CAAC,WAAW,EAAE,OAAO,EAAE,CAAC;IAChC,yFAAyF;IACzF,kBAAkB,IAAI;QAAE,MAAM,IAAI,MAAM,CAAC;QAAC,MAAM,IAAI,MAAM,CAAC;QAAC,UAAU,IAAI,MAAM,CAAA;KAAE,CAAC;CACpF;AAyCD;;;;;;;;;;;;;;;GAeG;AACH,qBAAa,wBAAyB,YAAW,yBAAyB;IACxE,qEAAqE;IACrE,YAAY,CAAC,KAAK,EAAE,WAAW,GAAG,IAAI;IAMtC;;;;;;;;OAQG;IACH,YAAY,CAAC,KAAK,EAAE,WAAW,GAAG,IAAI;IA4CtC;;;;;;;;;;;;;;;;;OAiBG;IACH,WAAW,CAAC,KAAK,EAAE,gBAAgB,GAAG,IAAI,GAAG,OAAO,CAAC,IAAI,CAAC;CAsB3D;AA+GD;;;;;;;;;;;;;GAaG;AACH,wBAAgB,yBAAyB,CACvC,UAAU,EAAE,qBAAqB,GAChC,wBAAwB,CAiB1B"}
1
+ {"version":3,"file":"typeorm-subscriber.d.ts","sourceRoot":"","sources":["../../src/integrations/typeorm-subscriber.ts"],"names":[],"mappings":"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"}
@@ -2,6 +2,7 @@
2
2
  Object.defineProperty(exports, "__esModule", { value: true });
3
3
  exports.StratumTypeOrmSubscriber = void 0;
4
4
  exports.registerStratumSubscriber = registerStratumSubscriber;
5
+ const node_async_hooks_1 = require("node:async_hooks");
5
6
  const sdk_1 = require("@stratum-hq/sdk");
6
7
  const utils_js_1 = require("../utils.js");
7
8
  // TypeORM writes an upsert on MySQL as INSERT ... ON DUPLICATE KEY UPDATE and
@@ -17,6 +18,19 @@ const TENANT_COLUMN_SQL = "SELECT COUNT(*) AS n FROM information_schema.COLUMNS
17
18
  "WHERE TABLE_SCHEMA = COALESCE(?, DATABASE()) AND TABLE_NAME = ? AND LOWER(COLUMN_NAME) = 'tenant_id'";
18
19
  const TENANT_PARAMETER = "stratumTenantId";
19
20
  const SCOPED_EXECUTE = Symbol("stratum.tenantScopedExecute");
21
+ const SCOPED_GET_QUERY = Symbol("stratum.tenantScopedGetQuery");
22
+ const SCOPED_INSERT = Symbol("stratum.tenantScopedInsert");
23
+ const EXEMPT_VIEW_EXPRESSION = Symbol("stratum.exemptViewExpression");
24
+ /** Inserted values whose primary key was already checked. */
25
+ const keyChecked = new WeakSet();
26
+ /** Values of an upsert while its builder runs; their keys are checked in beforeQuery instead. */
27
+ const upsertValues = new WeakSet();
28
+ /** True while a view entity's query builder expression is being built. */
29
+ const buildingViewExpression = new node_async_hooks_1.AsyncLocalStorage();
30
+ /** Select query builders returned by a view entity's expression. */
31
+ const viewExpressionBuilders = new WeakSet();
32
+ /** The WHERE addition that addTenantCondition set on each write builder's expression map. */
33
+ const scopedWriteConditions = new WeakMap();
20
34
  /** Data sources whose update and delete query builders are tenant-scoped. */
21
35
  const scopedDataSources = new WeakSet();
22
36
  const UNIQUE_KEYS_SQL = "SELECT INDEX_NAME AS index_name, COLUMN_NAME AS column_name " +
@@ -34,16 +48,46 @@ const UNIQUE_KEYS_SQL = "SELECT INDEX_NAME AS index_name, COLUMN_NAME AS column_
34
48
  * softDelete(), restore()) to the current tenant: `tenant_id = <tenant>` is
35
49
  * ANDed to their WHERE clause, and they are refused outside a tenant context.
36
50
  *
37
- * Not scoped: reads (find, findOne, query builder selects) and raw SQL
38
- * (`dataSource.query()`). Add the tenant condition to those yourself, or use
39
- * the shared-table adapter's structured methods.
51
+ * Registration scopes reads the same way. Every SQL statement that TypeORM's
52
+ * select query builder produces (repository find*, findOne*, count*, exists*,
53
+ * sum/average/min/max, preload(), query builder getMany/getOne/getRawMany/
54
+ * getRawOne/getCount/getManyAndCount/getExists/stream, relation loading, the
55
+ * row that save() loads, and the count and pagination queries TypeORM builds
56
+ * internally) ANDs `tenant_id = <tenant>` for the FROM entity to its WHERE
57
+ * clause and adds it to the ON condition of each joined entity, so a LEFT JOIN
58
+ * still returns the parent row. Reads of an entity with a tenant_id column are
59
+ * refused outside a tenant context.
60
+ *
61
+ * Not scoped: raw SQL (`dataSource.query()`, `queryRunner.query()`), SQL taken
62
+ * from a builder's getQuery() / getQueryAndParameters() and run by hand, reads
63
+ * from a table that has no entity on the data source, and many-to-many junction
64
+ * tables. Add the tenant condition to those yourself, or use the shared-table
65
+ * adapter's structured methods.
40
66
  */
41
67
  class StratumTypeOrmSubscriber {
42
- /** Injects the current tenant's ID into the entity before insert. */
68
+ /**
69
+ * Injects the current tenant's ID into the entity before insert, into the
70
+ * property mapped to the tenant_id column.
71
+ *
72
+ * When the entity supplies its whole primary key and the insert builder has
73
+ * not checked it yet (save() runs this hook before the builder), the key is
74
+ * checked against the table first, so a save() with another tenant's key is
75
+ * refused rather than inserted. See checkKeyIsFree.
76
+ *
77
+ * @returns A promise that rejects when the key belongs to another tenant's row.
78
+ */
43
79
  beforeInsert(event) {
44
80
  const context = (0, sdk_1.getTenantContext)();
45
81
  (0, utils_js_1.assertTenantId)(context.tenant_id);
46
- event.entity["tenant_id"] = context.tenant_id;
82
+ let key;
83
+ if (event.metadata && !keyChecked.has(event.entity) && !upsertValues.has(event.entity)) {
84
+ keyChecked.add(event.entity);
85
+ key = primaryKeyOf(event.metadata, event.entity);
86
+ }
87
+ setTenant(event.entity, event.metadata, context.tenant_id);
88
+ if (key && event.metadata && event.queryRunner) {
89
+ return checkKeyIsFree(event.queryRunner, event.metadata, key, context.tenant_id);
90
+ }
47
91
  }
48
92
  /**
49
93
  * Keeps tenant_id out of an update. On save() the loaded value is restored,
@@ -82,6 +126,11 @@ class StratumTypeOrmSubscriber {
82
126
  tenantProps.add(column.propertyName);
83
127
  }
84
128
  }
129
+ // A relation whose join column is tenant_id writes that column too.
130
+ for (const prop of tenantRelationProps(event.metadata)) {
131
+ if (prop in entity)
132
+ tenantProps.add(prop);
133
+ }
85
134
  for (const prop of tenantProps) {
86
135
  const loaded = event.databaseEntity;
87
136
  if (loaded && prop in loaded) {
@@ -149,18 +198,44 @@ function addTenantCondition(builder) {
149
198
  }
150
199
  const context = (0, sdk_1.getTenantContext)();
151
200
  (0, utils_js_1.assertTenantId)(context.tenant_id);
201
+ stripTenantFromUpdateValues(builder);
152
202
  const qualified = builder.expressionMap.aliasNamePrefixingEnabled && alias
153
203
  ? `${builder.escape(alias.name)}.${builder.escape(column)}`
154
204
  : builder.escape(column);
155
205
  const condition = `${qualified} = :${TENANT_PARAMETER}`;
156
206
  const existing = builder.expressionMap.extraAppendedAndWhereCondition;
157
- // TypeORM ANDs this condition, in its own parentheses, to the caller's
158
- // WHERE clause, so an orWhere() cannot widen the statement past the tenant.
159
- builder.expressionMap.extraAppendedAndWhereCondition = existing
160
- ? `(${existing}) AND ${condition}`
161
- : condition;
207
+ // A builder that is executed again already carries the condition set here.
208
+ if (scopedWriteConditions.get(builder.expressionMap) !== existing) {
209
+ // TypeORM ANDs this condition, in its own parentheses, to the caller's
210
+ // WHERE clause, so an orWhere() cannot widen the statement past the tenant.
211
+ builder.expressionMap.extraAppendedAndWhereCondition = existing
212
+ ? `(${existing}) AND ${condition}`
213
+ : condition;
214
+ scopedWriteConditions.set(builder.expressionMap, builder.expressionMap.extraAppendedAndWhereCondition);
215
+ }
162
216
  builder.setParameter(TENANT_PARAMETER, context.tenant_id);
163
217
  }
218
+ /**
219
+ * Drops tenant_id from the SET values of an update builder, so an update never
220
+ * moves a row to another tenant, with or without listeners (beforeUpdate).
221
+ */
222
+ function stripTenantFromUpdateValues(builder) {
223
+ const map = builder.expressionMap;
224
+ const values = map.valuesSet;
225
+ if (map.queryType !== "update" || !values || typeof values !== "object")
226
+ return;
227
+ const alias = map.mainAlias;
228
+ const metadata = alias?.hasMetadata ? alias.metadata : undefined;
229
+ const tenantProps = new Set([
230
+ ...(metadata?.columns ?? []).filter((c) => c.databaseName.toLowerCase() === "tenant_id").map((c) => c.propertyName),
231
+ ...tenantRelationProps(metadata),
232
+ ]);
233
+ const keys = Object.keys(values);
234
+ const isTenantKey = (key) => key.toLowerCase() === "tenant_id" || tenantProps.has(key);
235
+ if (!keys.some(isTenantKey))
236
+ return;
237
+ map.valuesSet = Object.fromEntries(keys.filter((key) => !isTenantKey(key)).map((key) => [key, values[key]]));
238
+ }
164
239
  /** Wraps execute() of TypeORM's update, delete and soft-delete query builder classes, once. */
165
240
  function scopeWriteBuilders(dataSource) {
166
241
  const builders = [
@@ -181,6 +256,237 @@ function scopeWriteBuilders(dataSource) {
181
256
  }
182
257
  scopedDataSources.add(dataSource);
183
258
  }
259
+ /** Returns the tenant_id column of an entity's metadata, if it has one. */
260
+ function tenantColumnIn(metadata) {
261
+ return metadata?.columns.find((c) => c.databaseName.toLowerCase() === "tenant_id");
262
+ }
263
+ /** Returns the properties of relations whose join columns include tenant_id. */
264
+ function tenantRelationProps(metadata) {
265
+ return (metadata?.relations ?? [])
266
+ .filter((r) => (r.joinColumns ?? []).some((c) => c.databaseName.toLowerCase() === "tenant_id"))
267
+ .map((r) => r.propertyName);
268
+ }
269
+ /**
270
+ * Writes the tenant into the property mapped to the tenant_id column, and
271
+ * removes any relation whose join column is tenant_id, because TypeORM reads
272
+ * the column's value from such a relation first.
273
+ */
274
+ function setTenant(entity, metadata, tenantId) {
275
+ for (const prop of tenantRelationProps(metadata))
276
+ delete entity[prop];
277
+ const column = tenantColumnIn(metadata);
278
+ if (!column) {
279
+ entity["tenant_id"] = tenantId;
280
+ }
281
+ else if (column.setEntityValue) {
282
+ column.setEntityValue(entity, tenantId);
283
+ }
284
+ else {
285
+ entity[column.propertyName] = tenantId;
286
+ }
287
+ }
288
+ /**
289
+ * Returns the primary key values that an entity supplies, keyed by column
290
+ * name. Returns undefined when the entity has no tenant_id column or any part
291
+ * of its primary key is missing or computed by SQL.
292
+ */
293
+ function primaryKeyOf(metadata, entity) {
294
+ if (metadata.primaryColumns.length === 0 || !tenantColumnIn(metadata))
295
+ return undefined;
296
+ const key = new Map();
297
+ for (const column of metadata.primaryColumns) {
298
+ const value = column.getEntityValue ? column.getEntityValue(entity) : entity[column.propertyName];
299
+ if (value === undefined || value === null || typeof value === "function")
300
+ return undefined;
301
+ key.set(column.databaseName, value);
302
+ }
303
+ return key;
304
+ }
305
+ /**
306
+ * Refuses an insert whose primary key belongs to another tenant's row. The
307
+ * lookup is raw SQL, so it is not tenant-scoped, and its result is used only
308
+ * for this decision.
309
+ */
310
+ async function checkKeyIsFree(runner, metadata, key, tenantId) {
311
+ const quote = (name) => "`" + name.replace(/`/g, "``") + "`";
312
+ const tenantColumn = tenantColumnIn(metadata);
313
+ const table = metadata.tablePath.split(".").map(quote).join(".");
314
+ const where = [...key.keys()].map((column) => `${quote(column)} = ?`).join(" AND ");
315
+ const rows = (await runner.query(`SELECT ${quote(tenantColumn.databaseName)} AS tenant_id FROM ${table} WHERE ${where} LIMIT 1`, [...key.values()]));
316
+ if (rows.length > 0 && rows[0].tenant_id !== tenantId) {
317
+ throw new Error("Stratum: insert refused, because a row with this primary key belongs to another tenant.");
318
+ }
319
+ }
320
+ /**
321
+ * Prepares an insert builder whose data source has the subscriber.
322
+ *
323
+ * - INSERT ... SELECT into a tenant entity is refused, because the tenant of
324
+ * the selected rows cannot be set. Into other tables, the tenant parameter
325
+ * of a scoped SELECT is copied to the insert.
326
+ * - Each value of a tenant entity gets the current tenant, whether or not
327
+ * listeners (beforeInsert) run.
328
+ * - A plain insert whose value supplies its whole primary key is refused when
329
+ * a row with that key belongs to another tenant. The lookup is raw SQL, so it
330
+ * is not tenant-scoped, and its result is used only for this decision.
331
+ * Upserts are checked in beforeQuery against the table's unique keys.
332
+ */
333
+ async function prepareInsert(builder) {
334
+ if (!builder.connection.subscribers.some((s) => s instanceof StratumTypeOrmSubscriber))
335
+ return [];
336
+ const map = builder.expressionMap;
337
+ const metadata = map.mainAlias?.hasMetadata ? map.mainAlias.metadata : undefined;
338
+ const tenantColumn = tenantColumnIn(metadata);
339
+ if (map.insertFromSelect) {
340
+ if (tenantColumn) {
341
+ throw new Error("Stratum: INSERT ... SELECT into a tenant table is refused, because the tenant of the selected rows " +
342
+ "cannot be set. Load the rows and insert them as entities instead.");
343
+ }
344
+ if (map.insertFromSelect.getQuery().includes(`:${TENANT_PARAMETER}`)) {
345
+ const context = (0, sdk_1.getTenantContext)();
346
+ (0, utils_js_1.assertTenantId)(context.tenant_id);
347
+ builder.setParameter(TENANT_PARAMETER, context.tenant_id);
348
+ }
349
+ return [];
350
+ }
351
+ if (!metadata || !tenantColumn)
352
+ return [];
353
+ const context = (0, sdk_1.getTenantContext)();
354
+ (0, utils_js_1.assertTenantId)(context.tenant_id);
355
+ const values = (Array.isArray(map.valuesSet) ? map.valuesSet : [map.valuesSet]).filter((value) => !!value && typeof value === "object");
356
+ const runner = builder.queryRunner ?? builder.connection;
357
+ for (const value of values) {
358
+ if (map.onUpdate || map.onIgnore) {
359
+ upsertValues.add(value);
360
+ }
361
+ else if (!keyChecked.has(value)) {
362
+ keyChecked.add(value);
363
+ const key = primaryKeyOf(metadata, value);
364
+ if (key)
365
+ await checkKeyIsFree(runner, metadata, key, context.tenant_id);
366
+ }
367
+ setTenant(value, metadata, context.tenant_id);
368
+ }
369
+ return values;
370
+ }
371
+ /** Returns the tenant_id column of an entity alias, or undefined when it has none. */
372
+ function tenantColumnOf(alias) {
373
+ if (!alias || alias.subQuery || !alias.hasMetadata)
374
+ return undefined;
375
+ return alias.metadata.columns.find((c) => c.databaseName.toLowerCase() === "tenant_id")?.databaseName;
376
+ }
377
+ /**
378
+ * Builds the SQL of a select query builder whose data source has the
379
+ * subscriber, with `tenant_id = <current tenant>` ANDed to the WHERE clause for
380
+ * the FROM entity and to the ON condition of each joined entity that has a
381
+ * tenant_id column. The conditions are added only while the SQL is built and
382
+ * removed afterwards, so a builder that is built again, cloned, or used as a
383
+ * subquery never carries the condition twice.
384
+ */
385
+ function buildScopedSelect(builder, build) {
386
+ if (!builder.connection.subscribers.some((s) => s instanceof StratumTypeOrmSubscriber))
387
+ return build();
388
+ // A view's definition is a schema object, built by synchronize() outside any
389
+ // tenant context. Reads from the view entity are scoped like any entity.
390
+ if (buildingViewExpression.getStore() || viewExpressionBuilders.has(builder))
391
+ return build();
392
+ const map = builder.expressionMap;
393
+ const condition = (alias, column) => `${builder.escape(alias.name)}.${builder.escape(column)} = :${TENANT_PARAMETER}`;
394
+ const mainColumn = tenantColumnOf(map.mainAlias);
395
+ const joins = map.joinAttributes
396
+ .map((join) => ({ join, column: tenantColumnOf(join.alias) }))
397
+ .filter((entry) => entry.column !== undefined);
398
+ const setTenantParameter = () => {
399
+ const context = (0, sdk_1.getTenantContext)();
400
+ (0, utils_js_1.assertTenantId)(context.tenant_id);
401
+ builder.setParameter(TENANT_PARAMETER, context.tenant_id);
402
+ };
403
+ if (mainColumn === undefined && joins.length === 0) {
404
+ const sql = build();
405
+ // SQL built by another scoped builder can be embedded here, for example
406
+ // TypeORM's pagination query, which selects from a clone of the builder.
407
+ if (sql.includes(`:${TENANT_PARAMETER}`))
408
+ setTenantParameter();
409
+ return sql;
410
+ }
411
+ setTenantParameter();
412
+ const extra = map.extraAppendedAndWhereCondition;
413
+ const joinConditions = joins.map(({ join }) => join.condition);
414
+ try {
415
+ if (mainColumn !== undefined) {
416
+ const main = condition(map.mainAlias, mainColumn);
417
+ // TypeORM ANDs this condition, in its own parentheses, to the caller's
418
+ // WHERE clause, so an orWhere() cannot widen the read past the tenant.
419
+ map.extraAppendedAndWhereCondition = extra ? `(${extra}) AND ${main}` : main;
420
+ }
421
+ for (const { join, column } of joins) {
422
+ // In the ON condition rather than the WHERE clause, so a LEFT JOIN keeps
423
+ // the parent row and only drops the other tenant's joined row.
424
+ const own = condition(join.alias, column);
425
+ join.condition = join.condition ? `(${join.condition}) AND ${own}` : own;
426
+ }
427
+ return build();
428
+ }
429
+ finally {
430
+ map.extraAppendedAndWhereCondition = extra;
431
+ joins.forEach(({ join }, i) => {
432
+ join.condition = joinConditions[i];
433
+ });
434
+ }
435
+ }
436
+ /**
437
+ * Wraps getQuery() of TypeORM's select query builder class, once. Every read
438
+ * the builder runs (loadRawResults, stream, the count, exists and pagination
439
+ * queries, and subqueries) builds its SQL through getQuery().
440
+ */
441
+ function scopeSelectBuilder(dataSource) {
442
+ const proto = Object.getPrototypeOf(dataSource.createQueryBuilder());
443
+ if (proto[SCOPED_GET_QUERY])
444
+ return;
445
+ if (!Object.prototype.hasOwnProperty.call(proto, "getQuery") || typeof proto.getQuery !== "function") {
446
+ throw new Error("Stratum: this TypeORM version's select query builder is not supported, so reads cannot be tenant-scoped.");
447
+ }
448
+ const original = proto.getQuery;
449
+ proto.getQuery = function () {
450
+ return buildScopedSelect(this, () => original.call(this));
451
+ };
452
+ proto[SCOPED_GET_QUERY] = true;
453
+ }
454
+ /** Wraps execute() of TypeORM's insert query builder class, once (see prepareInsert). */
455
+ function scopeInsertBuilder(dataSource) {
456
+ const proto = Object.getPrototypeOf(dataSource.createQueryBuilder().insert());
457
+ if (proto[SCOPED_INSERT])
458
+ return;
459
+ const original = proto.execute;
460
+ proto.execute = async function () {
461
+ const values = await prepareInsert(this);
462
+ try {
463
+ return await original.call(this);
464
+ }
465
+ finally {
466
+ // An upsert's values are exempt from the key check only while it runs.
467
+ for (const value of values)
468
+ upsertValues.delete(value);
469
+ }
470
+ };
471
+ proto[SCOPED_INSERT] = true;
472
+ }
473
+ /**
474
+ * Marks the query builders that view entity expressions return, so that
475
+ * synchronize() can build the view definition without the read scope.
476
+ */
477
+ function exemptViewExpressions(dataSource) {
478
+ for (const metadata of dataSource.entityMetadatas ?? []) {
479
+ const expression = metadata.expression;
480
+ if (typeof expression !== "function" || expression[EXEMPT_VIEW_EXPRESSION])
481
+ continue;
482
+ const exempt = Object.assign((source) => buildingViewExpression.run(true, () => {
483
+ const builder = expression(source);
484
+ viewExpressionBuilders.add(builder);
485
+ return builder;
486
+ }), { [EXEMPT_VIEW_EXPRESSION]: true });
487
+ metadata.expression = exempt;
488
+ }
489
+ }
184
490
  /**
185
491
  * Refuses a TRUNCATE (Repository.clear(), QueryRunner.clearTable()) of a table
186
492
  * with a tenant_id column, because it would empty the table for every tenant.
@@ -227,8 +533,8 @@ async function assertUniqueKeysIncludeTenant(event) {
227
533
  * A second call returns the subscriber that the first call added, so the
228
534
  * data source never runs the subscriber twice.
229
535
  *
230
- * It also scopes TypeORM's update, delete and soft-delete query builders to the
231
- * current tenant (see StratumTypeOrmSubscriber). The subscriber refuses an
536
+ * It also scopes TypeORM's select, update, delete and soft-delete query
537
+ * builders to the current tenant (see StratumTypeOrmSubscriber). The subscriber refuses an
232
538
  * UPDATE or DELETE on a data source that was not registered this way.
233
539
  *
234
540
  * @param dataSource - An initialized TypeORM `DataSource`.
@@ -240,7 +546,10 @@ function registerStratumSubscriber(dataSource) {
240
546
  throw new Error("Stratum: call registerStratumSubscriber() after dataSource.initialize(). " +
241
547
  "initialize() replaces the subscriber list.");
242
548
  }
549
+ scopeSelectBuilder(dataSource);
243
550
  scopeWriteBuilders(dataSource);
551
+ scopeInsertBuilder(dataSource);
552
+ exemptViewExpressions(dataSource);
244
553
  const existing = dataSource.subscribers.find((subscriber) => subscriber instanceof StratumTypeOrmSubscriber);
245
554
  if (existing)
246
555
  return existing;
@@ -1 +1 @@
1
- {"version":3,"file":"typeorm-subscriber.js","sourceRoot":"","sources":["../../src/integrations/typeorm-subscriber.ts"],"names":[],"mappings":"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"}
1
+ {"version":3,"file":"typeorm-subscriber.js","sourceRoot":"","sources":["../../src/integrations/typeorm-subscriber.ts"],"names":[],"mappings":"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"}
package/package.json CHANGED
@@ -1,9 +1,10 @@
1
1
  {
2
2
  "name": "@stratum-hq/mysql",
3
- "version": "0.5.0",
4
- "description": "MySQL tenant isolation for Stratum — shared table, table-per-tenant, and database-per-tenant strategies",
3
+ "version": "0.6.1",
4
+ "description": "MySQL tenant isolation for Stratum: shared table, table-per-tenant, and database-per-tenant strategies",
5
5
  "keywords": [
6
6
  "multi-tenancy",
7
+ "multitenancy",
7
8
  "multi-tenant",
8
9
  "saas",
9
10
  "tenant",
@@ -38,8 +39,8 @@
38
39
  "clean": "rm -rf dist"
39
40
  },
40
41
  "dependencies": {
41
- "@stratum-hq/core": "^1.5.0",
42
- "@stratum-hq/sdk": "^1.3.0"
42
+ "@stratum-hq/core": "^1.5.1",
43
+ "@stratum-hq/sdk": "^1.3.1"
43
44
  },
44
45
  "peerDependencies": {
45
46
  "mysql2": "^3.0.0",
@@ -61,6 +62,7 @@
61
62
  "devDependencies": {
62
63
  "knex": "^3.3.0",
63
64
  "mysql2": "^3.24.4",
65
+ "sequelize": "^6.37.8",
64
66
  "typeorm": "^1.1.1",
65
67
  "typescript": "^5.9.0",
66
68
  "vitest": "^4.1.11"
@@ -70,7 +72,7 @@
70
72
  },
71
73
  "license": "MIT",
72
74
  "author": "Christian Crank",
73
- "homepage": "https://github.com/stratum-hq/Stratum/tree/main/packages/mysql#readme",
75
+ "homepage": "https://docs.stratum-hq.org/packages/mysql/",
74
76
  "bugs": "https://github.com/stratum-hq/Stratum/issues",
75
77
  "engines": {
76
78
  "node": ">=20.0.0"