@stratum-hq/mysql 0.3.0 → 0.5.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/README.md CHANGED
@@ -46,7 +46,7 @@ import { MysqlTableAdapter } from "@stratum-hq/mysql";
46
46
  const adapter = new MysqlTableAdapter({
47
47
  pool,
48
48
  databaseName: "myapp",
49
- // Every base table that has a per-tenant copy. Required by purgeTenantData.
49
+ // Every base table that has a per-tenant copy. Required by scopedTable and purgeTenantData.
50
50
  baseTables: ["users", "orders"],
51
51
  });
52
52
 
@@ -79,20 +79,27 @@ await adapter.closeAll();
79
79
 
80
80
  ## ORM Integrations
81
81
 
82
- ### TypeORM Subscriber (writes only)
82
+ ### TypeORM Subscriber (writes only; reads are not scoped)
83
83
 
84
84
  ```typescript
85
- import { StratumTypeOrmSubscriber } from "@stratum-hq/mysql";
85
+ import { registerStratumSubscriber } from "@stratum-hq/mysql";
86
86
 
87
- // Register an instance once the data source is initialized. (TypeORM's
88
- // `subscribers` option only loads @EventSubscriber()-decorated classes.)
89
87
  await dataSource.initialize();
90
- dataSource.subscribers.push(new StratumTypeOrmSubscriber());
88
+ // Adds one StratumTypeOrmSubscriber. A second call adds nothing.
89
+ registerStratumSubscriber(dataSource);
91
90
  ```
92
91
 
92
+ 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
+
93
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.
94
95
 
95
- **Limitation:** TypeORM subscribers can intercept writes but not reads. Use the shared-table adapter's structured methods for tenant-scoped reads.
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()`.
97
+
98
+ 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
+
100
+ 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
+
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.
96
103
 
97
104
  ### Knex Helper
98
105
 
@@ -104,7 +111,9 @@ const users = await tenantKnex("users").where("name", "like", q).orWhere("email"
104
111
  // Compiles to: WHERE tenant_id = 'tenant-a' AND (name LIKE ? OR email LIKE ?)
105
112
  ```
106
113
 
107
- Your where clauses are always grouped after the tenant filter, including on clones and when the builder is used as a subquery. `insert()` sets `tenant_id`, `update()` never changes it, and `onConflict().merge()`, `upsert()` and `truncate()` throw.
114
+ Your where clauses are always grouped after the tenant filter, including on clones and when the builder is used as a subquery. `insert()` sets `tenant_id`, `update()` never changes it, and `onConflict().merge()`, `upsert()`, `truncate()` and `modify()` throw (a `modify()` callback would call the builder without these rules).
115
+
116
+ Joins (`join()`, `leftJoin()`, `crossJoin()`, `joinRaw()` and the other join forms) and `union()` / `unionAll()` also throw, because the tenant filter covers only the builder's own table. To combine tables, use a tenant-scoped builder as a `whereIn()` subquery, or write the query with plain Knex and a `tenant_id` condition on every table.
108
117
 
109
118
  ### Sequelize Adapter
110
119
 
@@ -13,6 +13,9 @@ export declare class MysqlTableAdapter implements MysqlAdapter {
13
13
  /**
14
14
  * Validates slug and returns the escaped tenant-scoped table name
15
15
  * in the form `{baseTableName}_{tenantSlug}`.
16
+ *
17
+ * Throws when baseTables is not set: without the list, two tenants can get
18
+ * the same name, e.g. ("corp_acme", "orders") and ("acme", "orders_corp").
16
19
  */
17
20
  scopedTable(tenantSlug: string, baseTableName: string): string;
18
21
  /** Returns the underlying pool for raw queries against tenant tables. */
@@ -1 +1 @@
1
- {"version":3,"file":"table.d.ts","sourceRoot":"","sources":["../../src/adapters/table.ts"],"names":[],"mappings":"AACA,OAAO,KAAK,EACV,YAAY,EACZ,wBAAwB,EACxB,aAAa,EACb,WAAW,EACX,YAAY,EACb,MAAM,aAAa,CAAC;AAGrB;;;;;GAKG;AACH,qBAAa,iBAAkB,YAAW,YAAY;IACpD,OAAO,CAAC,QAAQ,CAAC,IAAI,CAAgB;IACrC,OAAO,CAAC,QAAQ,CAAC,YAAY,CAAS;IACtC,OAAO,CAAC,QAAQ,CAAC,UAAU,CAAuB;gBAEtC,OAAO,EAAE,wBAAwB;IAkB7C;;;OAGG;IACH,WAAW,CAAC,UAAU,EAAE,MAAM,EAAE,aAAa,EAAE,MAAM,GAAG,MAAM;IAS9D,yEAAyE;IACzE,OAAO,IAAI,aAAa;IAIxB;;;;OAIG;IACG,eAAe,CAAC,UAAU,EAAE,MAAM,GAAG,OAAO,CAAC,WAAW,CAAC;IAgC/D,kCAAkC;IAClC,QAAQ,IAAI,YAAY;CAGzB"}
1
+ {"version":3,"file":"table.d.ts","sourceRoot":"","sources":["../../src/adapters/table.ts"],"names":[],"mappings":"AACA,OAAO,KAAK,EACV,YAAY,EACZ,wBAAwB,EACxB,aAAa,EACb,WAAW,EACX,YAAY,EACb,MAAM,aAAa,CAAC;AAGrB;;;;;GAKG;AACH,qBAAa,iBAAkB,YAAW,YAAY;IACpD,OAAO,CAAC,QAAQ,CAAC,IAAI,CAAgB;IACrC,OAAO,CAAC,QAAQ,CAAC,YAAY,CAAS;IACtC,OAAO,CAAC,QAAQ,CAAC,UAAU,CAAuB;gBAEtC,OAAO,EAAE,wBAAwB;IAkB7C;;;;;;OAMG;IACH,WAAW,CAAC,UAAU,EAAE,MAAM,EAAE,aAAa,EAAE,MAAM,GAAG,MAAM;IAe9D,yEAAyE;IACzE,OAAO,IAAI,aAAa;IAIxB;;;;OAIG;IACG,eAAe,CAAC,UAAU,EAAE,MAAM,GAAG,OAAO,CAAC,WAAW,CAAC;IAgC/D,kCAAkC;IAClC,QAAQ,IAAI,YAAY;CAGzB"}
@@ -31,10 +31,17 @@ class MysqlTableAdapter {
31
31
  /**
32
32
  * Validates slug and returns the escaped tenant-scoped table name
33
33
  * in the form `{baseTableName}_{tenantSlug}`.
34
+ *
35
+ * Throws when baseTables is not set: without the list, two tenants can get
36
+ * the same name, e.g. ("corp_acme", "orders") and ("acme", "orders_corp").
34
37
  */
35
38
  scopedTable(tenantSlug, baseTableName) {
36
39
  (0, core_1.validateSlug)(tenantSlug);
37
- if (this.baseTables && !this.baseTables.includes(baseTableName)) {
40
+ if (!this.baseTables) {
41
+ throw new Error("MysqlTableAdapter: scopedTable requires the baseTables option, " +
42
+ "listing every base table name that has a per-tenant copy");
43
+ }
44
+ if (!this.baseTables.includes(baseTableName)) {
38
45
  throw new Error(`MysqlTableAdapter: "${baseTableName}" is not in baseTables`);
39
46
  }
40
47
  const tableName = `${baseTableName}_${tenantSlug}`;
@@ -1 +1 @@
1
- {"version":3,"file":"table.js","sourceRoot":"","sources":["../../src/adapters/table.ts"],"names":[],"mappings":";;;AAAA,2CAAgD;AAQhD,0CAA+D;AAE/D;;;;;GAKG;AACH,MAAa,iBAAiB;IACX,IAAI,CAAgB;IACpB,YAAY,CAAS;IACrB,UAAU,CAAuB;IAElD,YAAY,OAAiC;QAC3C,IAAI,CAAC,IAAI,GAAG,OAAO,CAAC,IAAI,CAAC;QACzB,IAAI,CAAC,YAAY,GAAG,OAAO,CAAC,YAAY,CAAC;QACzC,IAAI,OAAO,CAAC,UAAU,EAAE,CAAC;YACvB,KAAK,MAAM,CAAC,IAAI,OAAO,CAAC,UAAU,EAAE,CAAC;gBACnC,KAAK,MAAM,CAAC,IAAI,OAAO,CAAC,UAAU,EAAE,CAAC;oBACnC,IAAI,CAAC,CAAC,WAAW,EAAE,CAAC,UAAU,CAAC,GAAG,CAAC,CAAC,WAAW,EAAE,GAAG,CAAC,EAAE,CAAC;wBACtD,MAAM,IAAI,KAAK,CACb,mCAAmC,CAAC,UAAU,CAAC,mBAAmB;4BAChE,YAAY,CAAC,iCAAiC,CAAC,UAAU,CAC5D,CAAC;oBACJ,CAAC;gBACH,CAAC;YACH,CAAC;YACD,IAAI,CAAC,UAAU,GAAG,CAAC,GAAG,OAAO,CAAC,UAAU,CAAC,CAAC;QAC5C,CAAC;IACH,CAAC;IAED;;;OAGG;IACH,WAAW,CAAC,UAAkB,EAAE,aAAqB;QACnD,IAAA,mBAAY,EAAC,UAAU,CAAC,CAAC;QACzB,IAAI,IAAI,CAAC,UAAU,IAAI,CAAC,IAAI,CAAC,UAAU,CAAC,QAAQ,CAAC,aAAa,CAAC,EAAE,CAAC;YAChE,MAAM,IAAI,KAAK,CAAC,uBAAuB,aAAa,wBAAwB,CAAC,CAAC;QAChF,CAAC;QACD,MAAM,SAAS,GAAG,GAAG,aAAa,IAAI,UAAU,EAAE,CAAC;QACnD,OAAO,IAAA,2BAAgB,EAAC,SAAS,CAAC,CAAC;IACrC,CAAC;IAED,yEAAyE;IACzE,OAAO;QACL,OAAO,IAAI,CAAC,IAAI,CAAC;IACnB,CAAC;IAED;;;;OAIG;IACH,KAAK,CAAC,eAAe,CAAC,UAAkB;QACtC,IAAA,yBAAc,EAAC,UAAU,CAAC,CAAC;QAC3B,IAAA,mBAAY,EAAC,UAAU,CAAC,CAAC;QACzB,IAAI,CAAC,IAAI,CAAC,UAAU,EAAE,CAAC;YACrB,MAAM,IAAI,KAAK,CACb,qEAAqE;gBACnE,0DAA0D,CAC7D,CAAC;QACJ,CAAC;QAED,MAAM,SAAS,GAAG,IAAA,2BAAgB,EAAC,IAAI,CAAC,YAAY,CAAC,CAAC;QACtD,MAAM,MAAM,GAA0B,EAAE,CAAC;QACzC,IAAI,eAAe,GAAG,CAAC,CAAC;QAExB,KAAK,MAAM,IAAI,IAAI,IAAI,CAAC,UAAU,EAAE,CAAC;YACnC,MAAM,SAAS,GAAG,GAAG,IAAI,IAAI,UAAU,EAAE,CAAC;YAC1C,IAAI,CAAC;gBACH,MAAM,IAAI,CAAC,IAAI,CAAC,KAAK,CAAC,wBAAwB,SAAS,IAAI,IAAA,2BAAgB,EAAC,SAAS,CAAC,EAAE,CAAC,CAAC;gBAC1F,eAAe,EAAE,CAAC;YACpB,CAAC;YAAC,OAAO,GAAG,EAAE,CAAC;gBACb,MAAM,CAAC,IAAI,CAAC,EAAE,KAAK,EAAE,SAAS,EAAE,KAAK,EAAE,GAAY,EAAE,CAAC,CAAC;YACzD,CAAC;QACH,CAAC;QAED,OAAO;YACL,OAAO,EAAE,MAAM,CAAC,MAAM,KAAK,CAAC;YAC5B,eAAe;YACf,WAAW,EAAE,CAAC;YACd,MAAM;SACP,CAAC;IACJ,CAAC;IAED,kCAAkC;IAClC,QAAQ;QACN,OAAO,EAAE,QAAQ,EAAE,kBAAkB,EAAE,CAAC;IAC1C,CAAC;CACF;AAlFD,8CAkFC"}
1
+ {"version":3,"file":"table.js","sourceRoot":"","sources":["../../src/adapters/table.ts"],"names":[],"mappings":"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"}
package/dist/index.d.ts CHANGED
@@ -4,8 +4,8 @@ export { MysqlTableAdapter } from "./adapters/table.js";
4
4
  export { MysqlDatabaseAdapter } from "./adapters/database.js";
5
5
  export { MysqlPoolManager } from "./pool-manager.js";
6
6
  export { createTenantView, dropTenantView, setTenantSession } from "./views/manager.js";
7
- export { StratumTypeOrmSubscriber } from "./integrations/typeorm-subscriber.js";
8
- export type { InsertEvent, UpdateEvent, EntitySubscriberInterface } from "./integrations/typeorm-subscriber.js";
7
+ export { StratumTypeOrmSubscriber, registerStratumSubscriber, } from "./integrations/typeorm-subscriber.js";
8
+ export type { InsertEvent, UpdateEvent, BeforeQueryEvent, EntitySubscriberInterface, TypeOrmDataSourceLike, } from "./integrations/typeorm-subscriber.js";
9
9
  export { withTenantScope } from "./integrations/knex.js";
10
10
  export type { KnexLike, KnexQueryBuilderLike } from "./integrations/knex.js";
11
11
  export { withMysqlTenantScope } from "./integrations/sequelize.js";
@@ -1 +1 @@
1
- {"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"AACA,YAAY,EACV,mBAAmB,EACnB,aAAa,EACb,YAAY,EACZ,WAAW,EACX,YAAY,EACZ,yBAAyB,EACzB,wBAAwB,EACxB,2BAA2B,EAC3B,uBAAuB,GACxB,MAAM,YAAY,CAAC;AAGpB,OAAO,EAAE,kBAAkB,EAAE,MAAM,sBAAsB,CAAC;AAC1D,OAAO,EAAE,iBAAiB,EAAE,MAAM,qBAAqB,CAAC;AACxD,OAAO,EAAE,oBAAoB,EAAE,MAAM,wBAAwB,CAAC;AAG9D,OAAO,EAAE,gBAAgB,EAAE,MAAM,mBAAmB,CAAC;AAGrD,OAAO,EAAE,gBAAgB,EAAE,cAAc,EAAE,gBAAgB,EAAE,MAAM,oBAAoB,CAAC;AAGxF,OAAO,EAAE,wBAAwB,EAAE,MAAM,sCAAsC,CAAC;AAChF,YAAY,EAAE,WAAW,EAAE,WAAW,EAAE,yBAAyB,EAAE,MAAM,sCAAsC,CAAC;AAChH,OAAO,EAAE,eAAe,EAAE,MAAM,wBAAwB,CAAC;AACzD,YAAY,EAAE,QAAQ,EAAE,oBAAoB,EAAE,MAAM,wBAAwB,CAAC;AAC7E,OAAO,EAAE,oBAAoB,EAAE,MAAM,6BAA6B,CAAC;AACnE,YAAY,EAAE,aAAa,EAAE,MAAM,6BAA6B,CAAC;AAGjE,OAAO,EAAE,cAAc,EAAE,gBAAgB,EAAE,qBAAqB,EAAE,MAAM,YAAY,CAAC"}
1
+ {"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"AACA,YAAY,EACV,mBAAmB,EACnB,aAAa,EACb,YAAY,EACZ,WAAW,EACX,YAAY,EACZ,yBAAyB,EACzB,wBAAwB,EACxB,2BAA2B,EAC3B,uBAAuB,GACxB,MAAM,YAAY,CAAC;AAGpB,OAAO,EAAE,kBAAkB,EAAE,MAAM,sBAAsB,CAAC;AAC1D,OAAO,EAAE,iBAAiB,EAAE,MAAM,qBAAqB,CAAC;AACxD,OAAO,EAAE,oBAAoB,EAAE,MAAM,wBAAwB,CAAC;AAG9D,OAAO,EAAE,gBAAgB,EAAE,MAAM,mBAAmB,CAAC;AAGrD,OAAO,EAAE,gBAAgB,EAAE,cAAc,EAAE,gBAAgB,EAAE,MAAM,oBAAoB,CAAC;AAGxF,OAAO,EACL,wBAAwB,EACxB,yBAAyB,GAC1B,MAAM,sCAAsC,CAAC;AAC9C,YAAY,EACV,WAAW,EACX,WAAW,EACX,gBAAgB,EAChB,yBAAyB,EACzB,qBAAqB,GACtB,MAAM,sCAAsC,CAAC;AAC9C,OAAO,EAAE,eAAe,EAAE,MAAM,wBAAwB,CAAC;AACzD,YAAY,EAAE,QAAQ,EAAE,oBAAoB,EAAE,MAAM,wBAAwB,CAAC;AAC7E,OAAO,EAAE,oBAAoB,EAAE,MAAM,6BAA6B,CAAC;AACnE,YAAY,EAAE,aAAa,EAAE,MAAM,6BAA6B,CAAC;AAGjE,OAAO,EAAE,cAAc,EAAE,gBAAgB,EAAE,qBAAqB,EAAE,MAAM,YAAY,CAAC"}
package/dist/index.js CHANGED
@@ -1,6 +1,6 @@
1
1
  "use strict";
2
2
  Object.defineProperty(exports, "__esModule", { value: true });
3
- exports.aggregatePurgeResults = exports.escapeIdentifier = exports.assertTenantId = exports.withMysqlTenantScope = exports.withTenantScope = exports.StratumTypeOrmSubscriber = exports.setTenantSession = exports.dropTenantView = exports.createTenantView = exports.MysqlPoolManager = exports.MysqlDatabaseAdapter = exports.MysqlTableAdapter = exports.MysqlSharedAdapter = void 0;
3
+ exports.aggregatePurgeResults = exports.escapeIdentifier = exports.assertTenantId = exports.withMysqlTenantScope = exports.withTenantScope = exports.registerStratumSubscriber = exports.StratumTypeOrmSubscriber = exports.setTenantSession = exports.dropTenantView = exports.createTenantView = exports.MysqlPoolManager = exports.MysqlDatabaseAdapter = exports.MysqlTableAdapter = exports.MysqlSharedAdapter = void 0;
4
4
  // Adapters
5
5
  var shared_js_1 = require("./adapters/shared.js");
6
6
  Object.defineProperty(exports, "MysqlSharedAdapter", { enumerable: true, get: function () { return shared_js_1.MysqlSharedAdapter; } });
@@ -19,6 +19,7 @@ Object.defineProperty(exports, "setTenantSession", { enumerable: true, get: func
19
19
  // Integrations
20
20
  var typeorm_subscriber_js_1 = require("./integrations/typeorm-subscriber.js");
21
21
  Object.defineProperty(exports, "StratumTypeOrmSubscriber", { enumerable: true, get: function () { return typeorm_subscriber_js_1.StratumTypeOrmSubscriber; } });
22
+ Object.defineProperty(exports, "registerStratumSubscriber", { enumerable: true, get: function () { return typeorm_subscriber_js_1.registerStratumSubscriber; } });
22
23
  var knex_js_1 = require("./integrations/knex.js");
23
24
  Object.defineProperty(exports, "withTenantScope", { enumerable: true, get: function () { return knex_js_1.withTenantScope; } });
24
25
  var sequelize_js_1 = require("./integrations/sequelize.js");
package/dist/index.js.map CHANGED
@@ -1 +1 @@
1
- {"version":3,"file":"index.js","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":";;;AAaA,WAAW;AACX,kDAA0D;AAAjD,+GAAA,kBAAkB,OAAA;AAC3B,gDAAwD;AAA/C,6GAAA,iBAAiB,OAAA;AAC1B,sDAA8D;AAArD,mHAAA,oBAAoB,OAAA;AAE7B,eAAe;AACf,qDAAqD;AAA5C,mHAAA,gBAAgB,OAAA;AAEzB,QAAQ;AACR,iDAAwF;AAA/E,8GAAA,gBAAgB,OAAA;AAAE,4GAAA,cAAc,OAAA;AAAE,8GAAA,gBAAgB,OAAA;AAE3D,eAAe;AACf,8EAAgF;AAAvE,iIAAA,wBAAwB,OAAA;AAEjC,kDAAyD;AAAhD,0GAAA,eAAe,OAAA;AAExB,4DAAmE;AAA1D,oHAAA,oBAAoB,OAAA;AAG7B,YAAY;AACZ,uCAAqF;AAA5E,0GAAA,cAAc,OAAA;AAAE,4GAAA,gBAAgB,OAAA;AAAE,iHAAA,qBAAqB,OAAA"}
1
+ {"version":3,"file":"index.js","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":";;;AAaA,WAAW;AACX,kDAA0D;AAAjD,+GAAA,kBAAkB,OAAA;AAC3B,gDAAwD;AAA/C,6GAAA,iBAAiB,OAAA;AAC1B,sDAA8D;AAArD,mHAAA,oBAAoB,OAAA;AAE7B,eAAe;AACf,qDAAqD;AAA5C,mHAAA,gBAAgB,OAAA;AAEzB,QAAQ;AACR,iDAAwF;AAA/E,8GAAA,gBAAgB,OAAA;AAAE,4GAAA,cAAc,OAAA;AAAE,8GAAA,gBAAgB,OAAA;AAE3D,eAAe;AACf,8EAG8C;AAF5C,iIAAA,wBAAwB,OAAA;AACxB,kIAAA,yBAAyB,OAAA;AAS3B,kDAAyD;AAAhD,0GAAA,eAAe,OAAA;AAExB,4DAAmE;AAA1D,oHAAA,oBAAoB,OAAA;AAG7B,YAAY;AACZ,uCAAqF;AAA5E,0GAAA,cAAc,OAAA;AAAE,4GAAA,gBAAgB,OAAA;AAAE,iHAAA,qBAAqB,OAAA"}
@@ -26,6 +26,15 @@ export interface KnexLike {
26
26
  * UPDATE never changes tenant_id: the column is dropped from the update data.
27
27
  * onConflict().merge(), upsert() and truncate() throw, because MySQL applies
28
28
  * none of them through the WHERE clause. onConflict().ignore() is allowed.
29
+ *
30
+ * modify() throws, because its callback would call the builder's methods
31
+ * without the insert, update and onConflict rules above.
32
+ *
33
+ * Joins (join, innerJoin, leftJoin, crossJoin, joinRaw and the other forms)
34
+ * and union() / unionAll() throw, because the tenant filter covers only this
35
+ * builder's table, not the joined or unioned rows. To combine tenant data, use
36
+ * a tenant-scoped builder as a whereIn subquery, or write the query with an
37
+ * explicit tenant_id condition on every table.
29
38
  */
30
39
  export declare function withTenantScope(knex: KnexLike, tenantId: string): (tableName: string) => KnexQueryBuilderLike;
31
40
  //# sourceMappingURL=knex.d.ts.map
@@ -1 +1 @@
1
- {"version":3,"file":"knex.d.ts","sourceRoot":"","sources":["../../src/integrations/knex.ts"],"names":[],"mappings":"AAEA,MAAM,WAAW,oBAAoB;IACnC,KAAK,CAAC,GAAG,EAAE,MAAM,EAAE,GAAG,EAAE,OAAO,GAAG,IAAI,CAAC;IACvC,MAAM,CAAC,GAAG,IAAI,EAAE,MAAM,EAAE,GAAG,IAAI,CAAC;IAChC,MAAM,CAAC,IAAI,EAAE,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,GAAG,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,EAAE,GAAG,OAAO,CAAC,OAAO,CAAC,CAAC;IACpF,MAAM,CAAC,IAAI,EAAE,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,GAAG,IAAI,CAAC;IAC5C,MAAM,IAAI,IAAI,CAAC;IACf,KAAK,IAAI,OAAO,CAAC,OAAO,CAAC,CAAC;CAC3B;AAED,MAAM,WAAW,QAAQ;IACvB,CAAC,SAAS,EAAE,MAAM,GAAG,oBAAoB,CAAC;CAC3C;AA8BD;;;;;;;;;;;;;;;;;GAiBG;AACH,wBAAgB,eAAe,CAC7B,IAAI,EAAE,QAAQ,EACd,QAAQ,EAAE,MAAM,GACf,CAAC,SAAS,EAAE,MAAM,KAAK,oBAAoB,CAwI7C"}
1
+ {"version":3,"file":"knex.d.ts","sourceRoot":"","sources":["../../src/integrations/knex.ts"],"names":[],"mappings":"AAEA,MAAM,WAAW,oBAAoB;IACnC,KAAK,CAAC,GAAG,EAAE,MAAM,EAAE,GAAG,EAAE,OAAO,GAAG,IAAI,CAAC;IACvC,MAAM,CAAC,GAAG,IAAI,EAAE,MAAM,EAAE,GAAG,IAAI,CAAC;IAChC,MAAM,CAAC,IAAI,EAAE,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,GAAG,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,EAAE,GAAG,OAAO,CAAC,OAAO,CAAC,CAAC;IACpF,MAAM,CAAC,IAAI,EAAE,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,GAAG,IAAI,CAAC;IAC5C,MAAM,IAAI,IAAI,CAAC;IACf,KAAK,IAAI,OAAO,CAAC,OAAO,CAAC,CAAC;CAC3B;AAED,MAAM,WAAW,QAAQ;IACvB,CAAC,SAAS,EAAE,MAAM,GAAG,oBAAoB,CAAC;CAC3C;AAsDD;;;;;;;;;;;;;;;;;;;;;;;;;;GA0BG;AACH,wBAAgB,eAAe,CAC7B,IAAI,EAAE,QAAQ,EACd,QAAQ,EAAE,MAAM,GACf,CAAC,SAAS,EAAE,MAAM,KAAK,oBAAoB,CAwI7C"}
@@ -3,8 +3,32 @@
3
3
  Object.defineProperty(exports, "__esModule", { value: true });
4
4
  exports.withTenantScope = withTenantScope;
5
5
  const TENANT_COLUMN = "tenant_id";
6
- /** Builder methods that would write or destroy rows without the tenant filter. */
7
- const REFUSED_METHODS = new Set(["upsert", "truncate"]);
6
+ /**
7
+ * Builder methods the tenant filter cannot cover, mapped to the reason given
8
+ * in the error: writes that MySQL does not apply through the WHERE clause, and
9
+ * joins and unions, whose other rows the filter does not reach.
10
+ */
11
+ const NOT_FILTERED = "because MySQL does not apply the tenant filter to it";
12
+ const NOT_SCOPED = "because the tenant filter does not apply to the rows it adds";
13
+ const REFUSED_METHODS = new Map([
14
+ ["upsert", NOT_FILTERED],
15
+ ["truncate", NOT_FILTERED],
16
+ ["modify", "because the tenant rules for insert, update and onConflict do not apply inside its callback"],
17
+ ...[
18
+ "join",
19
+ "innerJoin",
20
+ "leftJoin",
21
+ "leftOuterJoin",
22
+ "rightJoin",
23
+ "rightOuterJoin",
24
+ "outerJoin",
25
+ "fullOuterJoin",
26
+ "crossJoin",
27
+ "joinRaw",
28
+ "union",
29
+ "unionAll",
30
+ ].map((method) => [method, NOT_SCOPED]),
31
+ ]);
8
32
  function isTenantColumn(name) {
9
33
  return name.toLowerCase() === TENANT_COLUMN;
10
34
  }
@@ -33,6 +57,15 @@ function withoutTenantColumn(row) {
33
57
  * UPDATE never changes tenant_id: the column is dropped from the update data.
34
58
  * onConflict().merge(), upsert() and truncate() throw, because MySQL applies
35
59
  * none of them through the WHERE clause. onConflict().ignore() is allowed.
60
+ *
61
+ * modify() throws, because its callback would call the builder's methods
62
+ * without the insert, update and onConflict rules above.
63
+ *
64
+ * Joins (join, innerJoin, leftJoin, crossJoin, joinRaw and the other forms)
65
+ * and union() / unionAll() throw, because the tenant filter covers only this
66
+ * builder's table, not the joined or unioned rows. To combine tenant data, use
67
+ * a tenant-scoped builder as a whereIn subquery, or write the query with an
68
+ * explicit tenant_id condition on every table.
36
69
  */
37
70
  function withTenantScope(knex, tenantId) {
38
71
  // Statement objects this module created, so they can be recognized again on
@@ -96,10 +129,10 @@ function withTenantScope(knex, tenantId) {
96
129
  if (typeof value !== "function" || typeof prop !== "string" || prop === "constructor") {
97
130
  return value;
98
131
  }
99
- if (REFUSED_METHODS.has(prop)) {
132
+ const refusal = REFUSED_METHODS.get(prop);
133
+ if (refusal) {
100
134
  return () => {
101
- throw new Error(`withTenantScope: ${prop}() is not allowed on a tenant-scoped builder, ` +
102
- `because MySQL does not apply the tenant filter to it`);
135
+ throw new Error(`withTenantScope: ${prop}() is not allowed on a tenant-scoped builder, ${refusal}`);
103
136
  };
104
137
  }
105
138
  if (depth > 0) {
@@ -1 +1 @@
1
- {"version":3,"file":"knex.js","sourceRoot":"","sources":["../../src/integrations/knex.ts"],"names":[],"mappings":"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"}
1
+ {"version":3,"file":"knex.js","sourceRoot":"","sources":["../../src/integrations/knex.ts"],"names":[],"mappings":"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"}
@@ -13,21 +13,47 @@ export interface UpdateEvent {
13
13
  }[];
14
14
  };
15
15
  }
16
+ export interface BeforeQueryEvent {
17
+ /** The SQL text that TypeORM is about to send to MySQL. */
18
+ query: string;
19
+ /** The query runner that is about to send the query. */
20
+ queryRunner?: {
21
+ query(sql: string, parameters?: unknown[]): Promise<unknown>;
22
+ };
23
+ /** The data source that is about to send the query. */
24
+ dataSource?: object;
25
+ }
16
26
  export interface EntitySubscriberInterface {
17
27
  beforeInsert?(event: InsertEvent): void | Promise<void>;
18
28
  beforeUpdate?(event: UpdateEvent): void | Promise<void>;
29
+ beforeQuery?(event: BeforeQueryEvent): void | Promise<void>;
30
+ }
31
+ /** The part of a TypeORM `DataSource` that the registration helper uses. */
32
+ export interface TypeOrmDataSourceLike {
33
+ readonly isInitialized: boolean;
34
+ readonly subscribers: unknown[];
35
+ /** Used once to reach TypeORM's update, delete and soft-delete query builder classes. */
36
+ createQueryBuilder(): {
37
+ update(): object;
38
+ delete(): object;
39
+ softDelete(): object;
40
+ };
19
41
  }
20
42
  /**
21
43
  * TypeORM subscriber that injects tenant_id into inserted entities via ALS and
22
44
  * never lets an update change tenant_id.
23
45
  *
24
- * Register an instance after the data source is initialized:
25
- * `dataSource.subscribers.push(new StratumTypeOrmSubscriber())`. TypeORM's
26
- * `subscribers` option only loads classes decorated with `@EventSubscriber()`.
46
+ * Register it with `registerStratumSubscriber(dataSource)` after
47
+ * `dataSource.initialize()`. TypeORM's `subscribers` option only loads classes
48
+ * decorated with `@EventSubscriber()`, so it does not load this class.
49
+ * Registration also scopes TypeORM's update, delete and soft-delete query
50
+ * builders (repository update(), delete(), save() of an existing row, remove(),
51
+ * softDelete(), restore()) to the current tenant: `tenant_id = <tenant>` is
52
+ * ANDed to their WHERE clause, and they are refused outside a tenant context.
27
53
  *
28
- * Known limitation: TypeORM subscribers cannot intercept query filtering.
29
- * This subscriber handles writes only. Use the shared-table adapter's
30
- * structured methods for tenant-scoped reads.
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.
31
57
  */
32
58
  export declare class StratumTypeOrmSubscriber implements EntitySubscriberInterface {
33
59
  /** Injects the current tenant's ID into the entity before insert. */
@@ -37,7 +63,44 @@ export declare class StratumTypeOrmSubscriber implements EntitySubscriberInterfa
37
63
  * so the column is unchanged; on a repository or query builder update the
38
64
  * column is dropped from the SET values (MySQL column names are
39
65
  * case-insensitive, so any letter case is dropped).
66
+ *
67
+ * @throws Error when save() loaded a row whose tenant_id is not the current
68
+ * tenant's. The loaded tenant_id is not copied onto the entity.
40
69
  */
41
70
  beforeUpdate(event: UpdateEvent): void;
71
+ /**
72
+ * Rejects an upsert that could update another tenant's row.
73
+ *
74
+ * A conflict update must never change the tenant of an existing row. A
75
+ * subscriber cannot remove one column from the conflict update, so the
76
+ * statement fails before it runs.
77
+ *
78
+ * MySQL runs ON DUPLICATE KEY UPDATE on a conflict with any unique key of
79
+ * the table, whatever conflict columns were passed to upsert() or
80
+ * orUpdate(). The upsert is therefore allowed only when every unique key
81
+ * (including the primary key) of the target table contains tenant_id, so a
82
+ * conflict can only ever be with a row of the same tenant. The keys are read
83
+ * from information_schema through the same query runner.
84
+ *
85
+ * @throws Error when the ON DUPLICATE KEY UPDATE clause assigns tenant_id.
86
+ * @returns A promise that rejects when a unique key of the table does not
87
+ * include tenant_id, or when the table cannot be determined.
88
+ */
89
+ beforeQuery(event: BeforeQueryEvent): void | Promise<void>;
42
90
  }
91
+ /**
92
+ * Returns the one StratumTypeOrmSubscriber on the data source, and adds it first when it is missing.
93
+ *
94
+ * A second call returns the subscriber that the first call added, so the
95
+ * data source never runs the subscriber twice.
96
+ *
97
+ * It also scopes TypeORM's update, delete and soft-delete query builders to the
98
+ * current tenant (see StratumTypeOrmSubscriber). The subscriber refuses an
99
+ * UPDATE or DELETE on a data source that was not registered this way.
100
+ *
101
+ * @param dataSource - An initialized TypeORM `DataSource`.
102
+ * @throws Error when the data source is not initialized. `initialize()` replaces
103
+ * the subscriber list, so an earlier registration has no effect.
104
+ */
105
+ export declare function registerStratumSubscriber(dataSource: TypeOrmDataSourceLike): StratumTypeOrmSubscriber;
43
106
  //# 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,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;CACzD;AAED;;;;;;;;;;;GAWG;AACH,qBAAa,wBAAyB,YAAW,yBAAyB;IACxE,qEAAqE;IACrE,YAAY,CAAC,KAAK,EAAE,WAAW,GAAG,IAAI;IAMtC;;;;;OAKG;IACH,YAAY,CAAC,KAAK,EAAE,WAAW,GAAG,IAAI;CAsBvC"}
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,19 +1,42 @@
1
1
  "use strict";
2
2
  Object.defineProperty(exports, "__esModule", { value: true });
3
3
  exports.StratumTypeOrmSubscriber = void 0;
4
+ exports.registerStratumSubscriber = registerStratumSubscriber;
4
5
  const sdk_1 = require("@stratum-hq/sdk");
5
6
  const utils_js_1 = require("../utils.js");
7
+ // TypeORM writes an upsert on MySQL as INSERT ... ON DUPLICATE KEY UPDATE and
8
+ // quotes each column with backticks.
9
+ const UPSERT_CLAUSE = /\bON\s+DUPLICATE\s+KEY\s+UPDATE\b/i;
10
+ const TENANT_ASSIGNMENT = /`tenant_id`\s*=/i;
11
+ // The target of an INSERT, as TypeORM writes it: `table` or `schema`.`table`.
12
+ const INSERT_TARGET = /^\s*INSERT\s+(?:IGNORE\s+)?INTO\s+(?:`((?:[^`]|``)+)`\.)?`((?:[^`]|``)+)`/i;
13
+ const UPDATE_OR_DELETE = /^\s*(?:UPDATE|DELETE)\b/i;
14
+ // The target of a TRUNCATE, as TypeORM writes it: `table` or `schema`.`table`.
15
+ const TRUNCATE_TARGET = /^\s*TRUNCATE\s+(?:TABLE\s+)?(?:`((?:[^`]|``)+)`\.)?`?((?:[^`\s;]|``)+)`?/i;
16
+ const TENANT_COLUMN_SQL = "SELECT COUNT(*) AS n FROM information_schema.COLUMNS " +
17
+ "WHERE TABLE_SCHEMA = COALESCE(?, DATABASE()) AND TABLE_NAME = ? AND LOWER(COLUMN_NAME) = 'tenant_id'";
18
+ const TENANT_PARAMETER = "stratumTenantId";
19
+ const SCOPED_EXECUTE = Symbol("stratum.tenantScopedExecute");
20
+ /** Data sources whose update and delete query builders are tenant-scoped. */
21
+ const scopedDataSources = new WeakSet();
22
+ const UNIQUE_KEYS_SQL = "SELECT INDEX_NAME AS index_name, COLUMN_NAME AS column_name " +
23
+ "FROM information_schema.STATISTICS " +
24
+ "WHERE TABLE_SCHEMA = COALESCE(?, DATABASE()) AND TABLE_NAME = ? AND NON_UNIQUE = 0";
6
25
  /**
7
26
  * TypeORM subscriber that injects tenant_id into inserted entities via ALS and
8
27
  * never lets an update change tenant_id.
9
28
  *
10
- * Register an instance after the data source is initialized:
11
- * `dataSource.subscribers.push(new StratumTypeOrmSubscriber())`. TypeORM's
12
- * `subscribers` option only loads classes decorated with `@EventSubscriber()`.
29
+ * Register it with `registerStratumSubscriber(dataSource)` after
30
+ * `dataSource.initialize()`. TypeORM's `subscribers` option only loads classes
31
+ * decorated with `@EventSubscriber()`, so it does not load this class.
32
+ * Registration also scopes TypeORM's update, delete and soft-delete query
33
+ * builders (repository update(), delete(), save() of an existing row, remove(),
34
+ * softDelete(), restore()) to the current tenant: `tenant_id = <tenant>` is
35
+ * ANDed to their WHERE clause, and they are refused outside a tenant context.
13
36
  *
14
- * Known limitation: TypeORM subscribers cannot intercept query filtering.
15
- * This subscriber handles writes only. Use the shared-table adapter's
16
- * structured methods for tenant-scoped reads.
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.
17
40
  */
18
41
  class StratumTypeOrmSubscriber {
19
42
  /** Injects the current tenant's ID into the entity before insert. */
@@ -27,11 +50,32 @@ class StratumTypeOrmSubscriber {
27
50
  * so the column is unchanged; on a repository or query builder update the
28
51
  * column is dropped from the SET values (MySQL column names are
29
52
  * case-insensitive, so any letter case is dropped).
53
+ *
54
+ * @throws Error when save() loaded a row whose tenant_id is not the current
55
+ * tenant's. The loaded tenant_id is not copied onto the entity.
30
56
  */
31
57
  beforeUpdate(event) {
32
58
  const entity = event.entity;
33
59
  if (!entity)
34
60
  return;
61
+ const loaded = event.databaseEntity;
62
+ if (loaded) {
63
+ const loadedProps = new Set(Object.keys(loaded).filter((key) => key.toLowerCase() === "tenant_id"));
64
+ for (const column of event.metadata?.columns ?? []) {
65
+ if (column.databaseName.toLowerCase() === "tenant_id" && column.propertyName in loaded) {
66
+ loadedProps.add(column.propertyName);
67
+ }
68
+ }
69
+ if (loadedProps.size > 0) {
70
+ const context = (0, sdk_1.getTenantContext)();
71
+ (0, utils_js_1.assertTenantId)(context.tenant_id);
72
+ for (const prop of loadedProps) {
73
+ if (loaded[prop] !== context.tenant_id) {
74
+ throw new Error("Stratum: save() refused, because the row belongs to another tenant.");
75
+ }
76
+ }
77
+ }
78
+ }
35
79
  const tenantProps = new Set(Object.keys(entity).filter((key) => key.toLowerCase() === "tenant_id"));
36
80
  for (const column of event.metadata?.columns ?? []) {
37
81
  if (column.databaseName.toLowerCase() === "tenant_id" && column.propertyName in entity) {
@@ -48,6 +92,160 @@ class StratumTypeOrmSubscriber {
48
92
  }
49
93
  }
50
94
  }
95
+ /**
96
+ * Rejects an upsert that could update another tenant's row.
97
+ *
98
+ * A conflict update must never change the tenant of an existing row. A
99
+ * subscriber cannot remove one column from the conflict update, so the
100
+ * statement fails before it runs.
101
+ *
102
+ * MySQL runs ON DUPLICATE KEY UPDATE on a conflict with any unique key of
103
+ * the table, whatever conflict columns were passed to upsert() or
104
+ * orUpdate(). The upsert is therefore allowed only when every unique key
105
+ * (including the primary key) of the target table contains tenant_id, so a
106
+ * conflict can only ever be with a row of the same tenant. The keys are read
107
+ * from information_schema through the same query runner.
108
+ *
109
+ * @throws Error when the ON DUPLICATE KEY UPDATE clause assigns tenant_id.
110
+ * @returns A promise that rejects when a unique key of the table does not
111
+ * include tenant_id, or when the table cannot be determined.
112
+ */
113
+ beforeQuery(event) {
114
+ if (event.dataSource &&
115
+ !scopedDataSources.has(event.dataSource) &&
116
+ UPDATE_OR_DELETE.test(event.query)) {
117
+ throw new Error("Stratum: register the subscriber with registerStratumSubscriber(dataSource), " +
118
+ "which scopes updates and deletes to the current tenant.");
119
+ }
120
+ if (/^\s*TRUNCATE\b/i.test(event.query))
121
+ return assertNotTenantTable(event);
122
+ const clause = event.query.split(UPSERT_CLAUSE)[1];
123
+ if (clause === undefined)
124
+ return;
125
+ if (TENANT_ASSIGNMENT.test(clause)) {
126
+ throw new Error("Stratum: an upsert must not update tenant_id on conflict. " +
127
+ "Remove tenant_id from the entity values or from the orUpdate() columns.");
128
+ }
129
+ return assertUniqueKeysIncludeTenant(event);
130
+ }
51
131
  }
52
132
  exports.StratumTypeOrmSubscriber = StratumTypeOrmSubscriber;
133
+ /**
134
+ * ANDs `tenant_id = <current tenant>` to the WHERE clause of an update, delete
135
+ * or soft-delete builder whose data source has the subscriber. Entities without
136
+ * a tenant_id column are left alone; a target without metadata (a table name)
137
+ * is treated as a tenant table.
138
+ */
139
+ function addTenantCondition(builder) {
140
+ if (!builder.connection.subscribers.some((s) => s instanceof StratumTypeOrmSubscriber))
141
+ return;
142
+ const alias = builder.expressionMap.mainAlias;
143
+ let column = "tenant_id";
144
+ if (alias?.hasMetadata) {
145
+ const tenantColumn = alias.metadata.columns.find((c) => c.databaseName.toLowerCase() === "tenant_id");
146
+ if (!tenantColumn)
147
+ return;
148
+ column = tenantColumn.databaseName;
149
+ }
150
+ const context = (0, sdk_1.getTenantContext)();
151
+ (0, utils_js_1.assertTenantId)(context.tenant_id);
152
+ const qualified = builder.expressionMap.aliasNamePrefixingEnabled && alias
153
+ ? `${builder.escape(alias.name)}.${builder.escape(column)}`
154
+ : builder.escape(column);
155
+ const condition = `${qualified} = :${TENANT_PARAMETER}`;
156
+ 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;
162
+ builder.setParameter(TENANT_PARAMETER, context.tenant_id);
163
+ }
164
+ /** Wraps execute() of TypeORM's update, delete and soft-delete query builder classes, once. */
165
+ function scopeWriteBuilders(dataSource) {
166
+ const builders = [
167
+ dataSource.createQueryBuilder().update(),
168
+ dataSource.createQueryBuilder().delete(),
169
+ dataSource.createQueryBuilder().softDelete(),
170
+ ];
171
+ for (const builder of builders) {
172
+ const proto = Object.getPrototypeOf(builder);
173
+ if (proto[SCOPED_EXECUTE])
174
+ continue;
175
+ const original = proto.execute;
176
+ proto.execute = function () {
177
+ addTenantCondition(this);
178
+ return original.call(this);
179
+ };
180
+ proto[SCOPED_EXECUTE] = true;
181
+ }
182
+ scopedDataSources.add(dataSource);
183
+ }
184
+ /**
185
+ * Refuses a TRUNCATE (Repository.clear(), QueryRunner.clearTable()) of a table
186
+ * with a tenant_id column, because it would empty the table for every tenant.
187
+ * A TRUNCATE whose table cannot be checked is refused too.
188
+ */
189
+ async function assertNotTenantTable(event) {
190
+ const target = TRUNCATE_TARGET.exec(event.query);
191
+ const unquote = (name) => (name === undefined ? null : name.replace(/``/g, "`"));
192
+ const table = target ? unquote(target[2]) : null;
193
+ let isTenantTable = true;
194
+ if (table && event.queryRunner) {
195
+ const rows = (await event.queryRunner.query(TENANT_COLUMN_SQL, [unquote(target?.[1]), table]));
196
+ isTenantTable = Number(rows[0]?.n ?? 1) > 0;
197
+ }
198
+ if (isTenantTable) {
199
+ throw new Error(`Stratum: TRUNCATE of "${table ?? "unknown table"}" is refused, because it would remove every tenant's rows. ` +
200
+ "Delete the current tenant's rows instead.");
201
+ }
202
+ }
203
+ async function assertUniqueKeysIncludeTenant(event) {
204
+ const target = INSERT_TARGET.exec(event.query);
205
+ if (!target || !event.queryRunner) {
206
+ throw new Error("Stratum: an upsert is refused because its table's unique keys cannot be checked for tenant_id.");
207
+ }
208
+ const unquote = (name) => (name === undefined ? null : name.replace(/``/g, "`"));
209
+ const table = unquote(target[2]);
210
+ const rows = (await event.queryRunner.query(UNIQUE_KEYS_SQL, [unquote(target[1]), table]));
211
+ const keys = new Map();
212
+ for (const row of rows) {
213
+ const hasTenant = row.column_name.toLowerCase() === "tenant_id";
214
+ keys.set(row.index_name, (keys.get(row.index_name) ?? false) || hasTenant);
215
+ }
216
+ for (const [key, hasTenant] of keys) {
217
+ if (!hasTenant) {
218
+ throw new Error(`Stratum: an upsert on "${table}" is refused, because its unique key "${key}" does not include tenant_id, ` +
219
+ "so a conflict could update another tenant's row. Add tenant_id to every unique key of the table, " +
220
+ "or look the row up by tenant before writing it.");
221
+ }
222
+ }
223
+ }
224
+ /**
225
+ * Returns the one StratumTypeOrmSubscriber on the data source, and adds it first when it is missing.
226
+ *
227
+ * A second call returns the subscriber that the first call added, so the
228
+ * data source never runs the subscriber twice.
229
+ *
230
+ * It also scopes TypeORM's update, delete and soft-delete query builders to the
231
+ * current tenant (see StratumTypeOrmSubscriber). The subscriber refuses an
232
+ * UPDATE or DELETE on a data source that was not registered this way.
233
+ *
234
+ * @param dataSource - An initialized TypeORM `DataSource`.
235
+ * @throws Error when the data source is not initialized. `initialize()` replaces
236
+ * the subscriber list, so an earlier registration has no effect.
237
+ */
238
+ function registerStratumSubscriber(dataSource) {
239
+ if (!dataSource.isInitialized) {
240
+ throw new Error("Stratum: call registerStratumSubscriber() after dataSource.initialize(). " +
241
+ "initialize() replaces the subscriber list.");
242
+ }
243
+ scopeWriteBuilders(dataSource);
244
+ const existing = dataSource.subscribers.find((subscriber) => subscriber instanceof StratumTypeOrmSubscriber);
245
+ if (existing)
246
+ return existing;
247
+ const subscriber = new StratumTypeOrmSubscriber();
248
+ dataSource.subscribers.push(subscriber);
249
+ return subscriber;
250
+ }
53
251
  //# sourceMappingURL=typeorm-subscriber.js.map
@@ -1 +1 @@
1
- {"version":3,"file":"typeorm-subscriber.js","sourceRoot":"","sources":["../../src/integrations/typeorm-subscriber.ts"],"names":[],"mappings":";;;AAAA,yCAAmD;AACnD,0CAA6C;AAqB7C;;;;;;;;;;;GAWG;AACH,MAAa,wBAAwB;IACnC,qEAAqE;IACrE,YAAY,CAAC,KAAkB;QAC7B,MAAM,OAAO,GAAG,IAAA,sBAAgB,GAAE,CAAC;QACnC,IAAA,yBAAc,EAAC,OAAO,CAAC,SAAS,CAAC,CAAC;QAClC,KAAK,CAAC,MAAM,CAAC,WAAW,CAAC,GAAG,OAAO,CAAC,SAAS,CAAC;IAChD,CAAC;IAED;;;;;OAKG;IACH,YAAY,CAAC,KAAkB;QAC7B,MAAM,MAAM,GAAG,KAAK,CAAC,MAAM,CAAC;QAC5B,IAAI,CAAC,MAAM;YAAE,OAAO;QAEpB,MAAM,WAAW,GAAG,IAAI,GAAG,CACzB,MAAM,CAAC,IAAI,CAAC,MAAM,CAAC,CAAC,MAAM,CAAC,CAAC,GAAG,EAAE,EAAE,CAAC,GAAG,CAAC,WAAW,EAAE,KAAK,WAAW,CAAC,CACvE,CAAC;QACF,KAAK,MAAM,MAAM,IAAI,KAAK,CAAC,QAAQ,EAAE,OAAO,IAAI,EAAE,EAAE,CAAC;YACnD,IAAI,MAAM,CAAC,YAAY,CAAC,WAAW,EAAE,KAAK,WAAW,IAAI,MAAM,CAAC,YAAY,IAAI,MAAM,EAAE,CAAC;gBACvF,WAAW,CAAC,GAAG,CAAC,MAAM,CAAC,YAAY,CAAC,CAAC;YACvC,CAAC;QACH,CAAC;QAED,KAAK,MAAM,IAAI,IAAI,WAAW,EAAE,CAAC;YAC/B,MAAM,MAAM,GAAG,KAAK,CAAC,cAAc,CAAC;YACpC,IAAI,MAAM,IAAI,IAAI,IAAI,MAAM,EAAE,CAAC;gBAC7B,MAAM,CAAC,IAAI,CAAC,GAAG,MAAM,CAAC,IAAI,CAAC,CAAC;YAC9B,CAAC;iBAAM,CAAC;gBACN,OAAO,MAAM,CAAC,IAAI,CAAC,CAAC;YACtB,CAAC;QACH,CAAC;IACH,CAAC;CACF;AApCD,4DAoCC"}
1
+ {"version":3,"file":"typeorm-subscriber.js","sourceRoot":"","sources":["../../src/integrations/typeorm-subscriber.ts"],"names":[],"mappings":"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"}
@@ -10,7 +10,8 @@ import type { MysqlPoolLike, MysqlPoolManagerOptions } from "./types.js";
10
10
  */
11
11
  export declare class MysqlPoolManager {
12
12
  private readonly pools;
13
- private readonly pending;
13
+ /** Pools that closePool or closeAll removed while a caller held them, by slug. */
14
+ private readonly closedEntries;
14
15
  private readonly createPool;
15
16
  private readonly baseUri;
16
17
  private readonly maxPools;
@@ -38,8 +39,17 @@ export declare class MysqlPoolManager {
38
39
  getStats(): {
39
40
  poolCount: number;
40
41
  };
41
- /** Evicts the pool that has been idle the longest and has no active references. */
42
- private evictLRU;
42
+ /** Keeps a removed pool that callers still hold, so that their releases do not reach a later pool for the slug. */
43
+ private recordClosedHolds;
44
+ /** Stops tracking a removed pool after its last hold ends. */
45
+ private forgetClosedIfReleased;
46
+ /** Ends the evicted pool first, then creates the pool for the slug. */
47
+ private openPool;
48
+ /**
49
+ * Removes the least-recently-used pool that no caller holds from the map and
50
+ * returns its entry. The caller ends it. Returns undefined when every pool is held.
51
+ */
52
+ private takeLRU;
43
53
  /** Closes pools that have been idle longer than idleTimeoutMs and have no active references. */
44
54
  private closeIdlePools;
45
55
  /** Builds the MySQL connection URI with the given database name. */
@@ -1 +1 @@
1
- {"version":3,"file":"pool-manager.d.ts","sourceRoot":"","sources":["../src/pool-manager.ts"],"names":[],"mappings":"AACA,OAAO,KAAK,EAAE,aAAa,EAAE,uBAAuB,EAAE,MAAM,YAAY,CAAC;AASzE;;;;;;;;GAQG;AACH,qBAAa,gBAAgB;IAC3B,OAAO,CAAC,QAAQ,CAAC,KAAK,CAAqC;IAC3D,OAAO,CAAC,QAAQ,CAAC,OAAO,CAAkD;IAC1E,OAAO,CAAC,QAAQ,CAAC,UAAU,CAA0D;IACrF,OAAO,CAAC,QAAQ,CAAC,OAAO,CAAS;IACjC,OAAO,CAAC,QAAQ,CAAC,QAAQ,CAAS;IAClC,OAAO,CAAC,QAAQ,CAAC,aAAa,CAAS;IACvC,OAAO,CAAC,QAAQ,CAAC,SAAS,CAAiC;IAC3D,0EAA0E;IAC1E,YAAY,EAAE,OAAO,CAAC,IAAI,CAAC,CAAqB;gBAEpC,OAAO,EAAE,uBAAuB;IAgB5C;;;;OAIG;IACG,OAAO,CAAC,IAAI,EAAE,MAAM,GAAG,OAAO,CAAC,aAAa,CAAC;IAwCnD;;;OAGG;IACH,WAAW,CAAC,IAAI,EAAE,MAAM,GAAG,IAAI;IAQ/B,0EAA0E;IACpE,SAAS,CAAC,IAAI,EAAE,MAAM,GAAG,OAAO,CAAC,IAAI,CAAC;IAO5C,2FAA2F;IACrF,QAAQ,IAAI,OAAO,CAAC,IAAI,CAAC;IAO/B,qDAAqD;IACrD,QAAQ,IAAI;QAAE,SAAS,EAAE,MAAM,CAAA;KAAE;IAIjC,mFAAmF;YACrE,QAAQ;IAgBtB,gGAAgG;YAClF,cAAc;IAa5B,oEAAoE;IACpE,OAAO,CAAC,QAAQ;CAYjB"}
1
+ {"version":3,"file":"pool-manager.d.ts","sourceRoot":"","sources":["../src/pool-manager.ts"],"names":[],"mappings":"AACA,OAAO,KAAK,EAAE,aAAa,EAAE,uBAAuB,EAAE,MAAM,YAAY,CAAC;AAUzE;;;;;;;;GAQG;AACH,qBAAa,gBAAgB;IAC3B,OAAO,CAAC,QAAQ,CAAC,KAAK,CAAqC;IAC3D,kFAAkF;IAClF,OAAO,CAAC,QAAQ,CAAC,aAAa,CAA0C;IACxE,OAAO,CAAC,QAAQ,CAAC,UAAU,CAA0D;IACrF,OAAO,CAAC,QAAQ,CAAC,OAAO,CAAS;IACjC,OAAO,CAAC,QAAQ,CAAC,QAAQ,CAAS;IAClC,OAAO,CAAC,QAAQ,CAAC,aAAa,CAAS;IACvC,OAAO,CAAC,QAAQ,CAAC,SAAS,CAAiC;IAC3D,0EAA0E;IAC1E,YAAY,EAAE,OAAO,CAAC,IAAI,CAAC,CAAqB;gBAEpC,OAAO,EAAE,uBAAuB;IAgB5C;;;;OAIG;IACG,OAAO,CAAC,IAAI,EAAE,MAAM,GAAG,OAAO,CAAC,aAAa,CAAC;IA2BnD;;;OAGG;IACH,WAAW,CAAC,IAAI,EAAE,MAAM,GAAG,IAAI;IAqB/B,0EAA0E;IACpE,SAAS,CAAC,IAAI,EAAE,MAAM,GAAG,OAAO,CAAC,IAAI,CAAC;IAQ5C,2FAA2F;IACrF,QAAQ,IAAI,OAAO,CAAC,IAAI,CAAC;IAQ/B,qDAAqD;IACrD,QAAQ,IAAI;QAAE,SAAS,EAAE,MAAM,CAAA;KAAE;IAIjC,mHAAmH;IACnH,OAAO,CAAC,iBAAiB;IAUzB,8DAA8D;IAC9D,OAAO,CAAC,sBAAsB;IAO9B,uEAAuE;YACzD,QAAQ;IAOtB;;;OAGG;IACH,OAAO,CAAC,OAAO;IAiBf,gGAAgG;YAClF,cAAc;IAe5B,oEAAoE;IACpE,OAAO,CAAC,QAAQ;CAYjB"}
@@ -13,7 +13,8 @@ const core_1 = require("@stratum-hq/core");
13
13
  */
14
14
  class MysqlPoolManager {
15
15
  pools = new Map();
16
- pending = new Map();
16
+ /** Pools that closePool or closeAll removed while a caller held them, by slug. */
17
+ closedEntries = new Map();
17
18
  createPool;
18
19
  baseUri;
19
20
  maxPools;
@@ -41,37 +42,28 @@ class MysqlPoolManager {
41
42
  */
42
43
  async getPool(slug) {
43
44
  (0, core_1.validateSlug)(slug);
44
- const existing = this.pools.get(slug);
45
- if (existing) {
46
- existing.lastUsed = Date.now();
47
- existing.refCount++;
48
- return existing.pool;
45
+ // The lookup, the eviction choice and the insert run with no await between
46
+ // them. Thus a concurrent call for the same slug always finds this entry and
47
+ // waits for the same pool.
48
+ let entry = this.pools.get(slug);
49
+ if (!entry) {
50
+ const victim = this.pools.size >= this.maxPools ? this.takeLRU() : undefined;
51
+ entry = { ready: this.openPool(slug, victim), lastUsed: Date.now(), refCount: 0 };
52
+ this.pools.set(slug, entry);
49
53
  }
50
- // Deduplicate concurrent creation requests for the same slug.
51
- const inflight = this.pending.get(slug);
52
- if (inflight) {
53
- const pool = await inflight;
54
- const entry = this.pools.get(slug);
55
- if (entry) {
56
- entry.refCount++;
57
- }
58
- return pool;
59
- }
60
- // Evict before adding so we never exceed maxPools.
61
- if (this.pools.size >= this.maxPools) {
62
- await this.evictLRU();
63
- }
64
- const dbName = `stratum_tenant_${slug}`;
65
- const uri = this.buildUri(dbName);
66
- const createPromise = Promise.resolve(this.createPool(uri));
67
- this.pending.set(slug, createPromise);
54
+ entry.lastUsed = Date.now();
55
+ entry.refCount++;
68
56
  try {
69
- const pool = await createPromise;
70
- this.pools.set(slug, { pool, lastUsed: Date.now(), refCount: 1 });
71
- return pool;
57
+ return await entry.ready;
72
58
  }
73
- finally {
74
- this.pending.delete(slug);
59
+ catch (err) {
60
+ // Remove the failed entry so that the next call tries again. The caller
61
+ // gets no pool, so it will not call releasePool.
62
+ if (this.pools.get(slug) === entry)
63
+ this.pools.delete(slug);
64
+ entry.refCount--;
65
+ this.forgetClosedIfReleased(slug, entry);
66
+ throw err;
75
67
  }
76
68
  }
77
69
  /**
@@ -79,12 +71,24 @@ class MysqlPoolManager {
79
71
  * No-op if the slug is not tracked.
80
72
  */
81
73
  releasePool(slug) {
74
+ // The caller passes a slug, not the pool, so the manager cannot tell a
75
+ // hold on a closed pool from a hold on its replacement. It ends holds on
76
+ // closed pools first. The replacement then counts as held for longer than
77
+ // it is, which is safe: eviction never ends a pool in use.
78
+ const closed = this.closedEntries.get(slug)?.values().next().value;
79
+ if (closed) {
80
+ closed.refCount--;
81
+ this.forgetClosedIfReleased(slug, closed);
82
+ return;
83
+ }
82
84
  const entry = this.pools.get(slug);
83
85
  if (!entry)
84
86
  return;
85
87
  if (entry.refCount > 0) {
86
88
  entry.refCount--;
87
89
  }
90
+ // The idle timeout counts from the end of the last use, not from its start.
91
+ entry.lastUsed = Date.now();
88
92
  }
89
93
  /** Closes and removes the pool for the given slug. No-op if not found. */
90
94
  async closePool(slug) {
@@ -92,21 +96,55 @@ class MysqlPoolManager {
92
96
  if (!entry)
93
97
  return;
94
98
  this.pools.delete(slug);
95
- await entry.pool.end();
99
+ this.recordClosedHolds(slug, entry);
100
+ await endEntry(entry);
96
101
  }
97
102
  /** Closes all managed pools and stops the idle timer. Call during application shutdown. */
98
103
  async closeAll() {
99
104
  clearInterval(this.idleTimer);
100
105
  const entries = Array.from(this.pools.entries());
101
106
  this.pools.clear();
102
- await Promise.all(entries.map(([, entry]) => entry.pool.end()));
107
+ for (const [slug, entry] of entries)
108
+ this.recordClosedHolds(slug, entry);
109
+ await Promise.all(entries.map(([, entry]) => endEntry(entry)));
103
110
  }
104
111
  /** Returns a snapshot of current pool statistics. */
105
112
  getStats() {
106
113
  return { poolCount: this.pools.size };
107
114
  }
108
- /** Evicts the pool that has been idle the longest and has no active references. */
109
- async evictLRU() {
115
+ /** Keeps a removed pool that callers still hold, so that their releases do not reach a later pool for the slug. */
116
+ recordClosedHolds(slug, entry) {
117
+ if (entry.refCount === 0)
118
+ return;
119
+ let closed = this.closedEntries.get(slug);
120
+ if (!closed) {
121
+ closed = new Set();
122
+ this.closedEntries.set(slug, closed);
123
+ }
124
+ closed.add(entry);
125
+ }
126
+ /** Stops tracking a removed pool after its last hold ends. */
127
+ forgetClosedIfReleased(slug, entry) {
128
+ const closed = this.closedEntries.get(slug);
129
+ if (!closed || entry.refCount > 0)
130
+ return;
131
+ closed.delete(entry);
132
+ if (closed.size === 0)
133
+ this.closedEntries.delete(slug);
134
+ }
135
+ /** Ends the evicted pool first, then creates the pool for the slug. */
136
+ async openPool(slug, victim) {
137
+ // The evicted pool belongs to a different tenant. Its end error must not
138
+ // fail this request.
139
+ if (victim)
140
+ await endEntry(victim).catch(() => undefined);
141
+ return this.createPool(this.buildUri(`stratum_tenant_${slug}`));
142
+ }
143
+ /**
144
+ * Removes the least-recently-used pool that no caller holds from the map and
145
+ * returns its entry. The caller ends it. Returns undefined when every pool is held.
146
+ */
147
+ takeLRU() {
110
148
  let oldestKey;
111
149
  let oldestTime = Infinity;
112
150
  for (const [key, entry] of this.pools.entries()) {
@@ -115,9 +153,11 @@ class MysqlPoolManager {
115
153
  oldestKey = key;
116
154
  }
117
155
  }
118
- if (oldestKey !== undefined) {
119
- await this.closePool(oldestKey);
120
- }
156
+ if (oldestKey === undefined)
157
+ return undefined;
158
+ const entry = this.pools.get(oldestKey);
159
+ this.pools.delete(oldestKey);
160
+ return entry;
121
161
  }
122
162
  /** Closes pools that have been idle longer than idleTimeoutMs and have no active references. */
123
163
  async closeIdlePools() {
@@ -128,7 +168,9 @@ class MysqlPoolManager {
128
168
  toClose.push(key);
129
169
  }
130
170
  }
131
- await Promise.all(toClose.map((slug) => this.closePool(slug)));
171
+ // The timer awaits nothing, so a rejection here would be unhandled. One
172
+ // pool that fails to end must not stop the others from closing.
173
+ await Promise.allSettled(toClose.map((slug) => this.closePool(slug)));
132
174
  }
133
175
  /** Builds the MySQL connection URI with the given database name. */
134
176
  buildUri(dbName) {
@@ -146,4 +188,9 @@ class MysqlPoolManager {
146
188
  }
147
189
  }
148
190
  exports.MysqlPoolManager = MysqlPoolManager;
191
+ /** Ends the entry's pool. A pool that failed to be created has nothing to end. */
192
+ async function endEntry(entry) {
193
+ const pool = await entry.ready.catch(() => undefined);
194
+ await pool?.end();
195
+ }
149
196
  //# sourceMappingURL=pool-manager.js.map
@@ -1 +1 @@
1
- {"version":3,"file":"pool-manager.js","sourceRoot":"","sources":["../src/pool-manager.ts"],"names":[],"mappings":"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"}
1
+ {"version":3,"file":"pool-manager.js","sourceRoot":"","sources":["../src/pool-manager.ts"],"names":[],"mappings":"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"}
package/dist/types.d.ts CHANGED
@@ -39,8 +39,9 @@ export interface MysqlTableAdapterOptions {
39
39
  databaseName: string;
40
40
  /**
41
41
  * Every base table name that has a per-tenant copy. Required by
42
+ * scopedTable, which only accepts these base names, and by
42
43
  * purgeTenantData, which drops exactly `{base}_{slug}` for each entry and
43
- * nothing else. When set, scopedTable only accepts these base names.
44
+ * nothing else.
44
45
  * No entry may be another entry followed by `_`, since `{base}_{slug}` would
45
46
  * then be ambiguous between two tenants.
46
47
  */
@@ -1 +1 @@
1
- {"version":3,"file":"types.d.ts","sourceRoot":"","sources":["../src/types.ts"],"names":[],"mappings":"AAEA,MAAM,WAAW,mBAAmB;IAClC,KAAK,CAAC,GAAG,EAAE,MAAM,EAAE,MAAM,CAAC,EAAE,OAAO,EAAE,GAAG,OAAO,CAAC,OAAO,CAAC,CAAC;IACzD,OAAO,CAAC,GAAG,EAAE,MAAM,EAAE,MAAM,CAAC,EAAE,OAAO,EAAE,GAAG,OAAO,CAAC,OAAO,CAAC,CAAC;IAC3D,OAAO,IAAI,IAAI,CAAC;IAChB,GAAG,IAAI,OAAO,CAAC,IAAI,CAAC,CAAC;CACtB;AAED,MAAM,WAAW,aAAa;IAC5B,aAAa,IAAI,OAAO,CAAC,mBAAmB,CAAC,CAAC;IAC9C,KAAK,CAAC,GAAG,EAAE,MAAM,EAAE,MAAM,CAAC,EAAE,OAAO,EAAE,GAAG,OAAO,CAAC,OAAO,CAAC,CAAC;IACzD,GAAG,IAAI,OAAO,CAAC,IAAI,CAAC,CAAC;CACtB;AAID,MAAM,WAAW,YAAY;IAC3B,eAAe,CAAC,UAAU,EAAE,MAAM,GAAG,OAAO,CAAC,WAAW,CAAC,CAAC;IAC1D,QAAQ,IAAI,YAAY,CAAC;CAC1B;AAED,MAAM,WAAW,WAAW;IAC1B,OAAO,EAAE,OAAO,CAAC;IACjB,eAAe,EAAE,MAAM,CAAC;IACxB,WAAW,EAAE,MAAM,CAAC;IACpB,MAAM,EAAE,KAAK,CAAC;QAAE,KAAK,EAAE,MAAM,CAAC;QAAC,KAAK,EAAE,KAAK,CAAA;KAAE,CAAC,CAAC;CAChD;AAED,MAAM,WAAW,YAAY;IAC3B,QAAQ,EAAE,MAAM,CAAC;IACjB,CAAC,GAAG,EAAE,MAAM,GAAG,OAAO,CAAC;CACxB;AAID,MAAM,WAAW,yBAAyB;IACxC,yCAAyC;IACzC,IAAI,EAAE,aAAa,CAAC;IACpB,gCAAgC;IAChC,YAAY,EAAE,MAAM,CAAC;CACtB;AAED,MAAM,WAAW,wBAAwB;IACvC,yCAAyC;IACzC,IAAI,EAAE,aAAa,CAAC;IACpB,gCAAgC;IAChC,YAAY,EAAE,MAAM,CAAC;IACrB;;;;;;OAMG;IACH,UAAU,CAAC,EAAE,MAAM,EAAE,CAAC;CACvB;AAED,MAAM,WAAW,2BAA2B;IAC1C,kEAAkE;IAClE,UAAU,EAAE,CAAC,GAAG,EAAE,MAAM,KAAK,aAAa,GAAG,OAAO,CAAC,aAAa,CAAC,CAAC;IACpE,uEAAuE;IACvE,OAAO,EAAE,MAAM,CAAC;IAChB,mDAAmD;IACnD,QAAQ,CAAC,EAAE,MAAM,CAAC;IAClB,oDAAoD;IACpD,aAAa,CAAC,EAAE,MAAM,CAAC;CACxB;AAED,MAAM,WAAW,uBAAuB;IACtC,kEAAkE;IAClE,UAAU,EAAE,CAAC,GAAG,EAAE,MAAM,KAAK,aAAa,GAAG,OAAO,CAAC,aAAa,CAAC,CAAC;IACpE,2BAA2B;IAC3B,OAAO,EAAE,MAAM,CAAC;IAChB,mDAAmD;IACnD,QAAQ,CAAC,EAAE,MAAM,CAAC;IAClB,oDAAoD;IACpD,aAAa,CAAC,EAAE,MAAM,CAAC;CACxB"}
1
+ {"version":3,"file":"types.d.ts","sourceRoot":"","sources":["../src/types.ts"],"names":[],"mappings":"AAEA,MAAM,WAAW,mBAAmB;IAClC,KAAK,CAAC,GAAG,EAAE,MAAM,EAAE,MAAM,CAAC,EAAE,OAAO,EAAE,GAAG,OAAO,CAAC,OAAO,CAAC,CAAC;IACzD,OAAO,CAAC,GAAG,EAAE,MAAM,EAAE,MAAM,CAAC,EAAE,OAAO,EAAE,GAAG,OAAO,CAAC,OAAO,CAAC,CAAC;IAC3D,OAAO,IAAI,IAAI,CAAC;IAChB,GAAG,IAAI,OAAO,CAAC,IAAI,CAAC,CAAC;CACtB;AAED,MAAM,WAAW,aAAa;IAC5B,aAAa,IAAI,OAAO,CAAC,mBAAmB,CAAC,CAAC;IAC9C,KAAK,CAAC,GAAG,EAAE,MAAM,EAAE,MAAM,CAAC,EAAE,OAAO,EAAE,GAAG,OAAO,CAAC,OAAO,CAAC,CAAC;IACzD,GAAG,IAAI,OAAO,CAAC,IAAI,CAAC,CAAC;CACtB;AAID,MAAM,WAAW,YAAY;IAC3B,eAAe,CAAC,UAAU,EAAE,MAAM,GAAG,OAAO,CAAC,WAAW,CAAC,CAAC;IAC1D,QAAQ,IAAI,YAAY,CAAC;CAC1B;AAED,MAAM,WAAW,WAAW;IAC1B,OAAO,EAAE,OAAO,CAAC;IACjB,eAAe,EAAE,MAAM,CAAC;IACxB,WAAW,EAAE,MAAM,CAAC;IACpB,MAAM,EAAE,KAAK,CAAC;QAAE,KAAK,EAAE,MAAM,CAAC;QAAC,KAAK,EAAE,KAAK,CAAA;KAAE,CAAC,CAAC;CAChD;AAED,MAAM,WAAW,YAAY;IAC3B,QAAQ,EAAE,MAAM,CAAC;IACjB,CAAC,GAAG,EAAE,MAAM,GAAG,OAAO,CAAC;CACxB;AAID,MAAM,WAAW,yBAAyB;IACxC,yCAAyC;IACzC,IAAI,EAAE,aAAa,CAAC;IACpB,gCAAgC;IAChC,YAAY,EAAE,MAAM,CAAC;CACtB;AAED,MAAM,WAAW,wBAAwB;IACvC,yCAAyC;IACzC,IAAI,EAAE,aAAa,CAAC;IACpB,gCAAgC;IAChC,YAAY,EAAE,MAAM,CAAC;IACrB;;;;;;;OAOG;IACH,UAAU,CAAC,EAAE,MAAM,EAAE,CAAC;CACvB;AAED,MAAM,WAAW,2BAA2B;IAC1C,kEAAkE;IAClE,UAAU,EAAE,CAAC,GAAG,EAAE,MAAM,KAAK,aAAa,GAAG,OAAO,CAAC,aAAa,CAAC,CAAC;IACpE,uEAAuE;IACvE,OAAO,EAAE,MAAM,CAAC;IAChB,mDAAmD;IACnD,QAAQ,CAAC,EAAE,MAAM,CAAC;IAClB,oDAAoD;IACpD,aAAa,CAAC,EAAE,MAAM,CAAC;CACxB;AAED,MAAM,WAAW,uBAAuB;IACtC,kEAAkE;IAClE,UAAU,EAAE,CAAC,GAAG,EAAE,MAAM,KAAK,aAAa,GAAG,OAAO,CAAC,aAAa,CAAC,CAAC;IACpE,2BAA2B;IAC3B,OAAO,EAAE,MAAM,CAAC;IAChB,mDAAmD;IACnD,QAAQ,CAAC,EAAE,MAAM,CAAC;IAClB,oDAAoD;IACpD,aAAa,CAAC,EAAE,MAAM,CAAC;CACxB"}
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@stratum-hq/mysql",
3
- "version": "0.3.0",
3
+ "version": "0.5.0",
4
4
  "description": "MySQL tenant isolation for Stratum — shared table, table-per-tenant, and database-per-tenant strategies",
5
5
  "keywords": [
6
6
  "multi-tenancy",
@@ -38,12 +38,14 @@
38
38
  "clean": "rm -rf dist"
39
39
  },
40
40
  "dependencies": {
41
- "@stratum-hq/core": "*",
42
- "@stratum-hq/sdk": "*"
41
+ "@stratum-hq/core": "^1.5.0",
42
+ "@stratum-hq/sdk": "^1.3.0"
43
43
  },
44
44
  "peerDependencies": {
45
45
  "mysql2": "^3.0.0",
46
- "knex": ">=3.0.0"
46
+ "knex": ">=3.0.0",
47
+ "typeorm": "^1.0.0",
48
+ "sequelize": "^6.0.0"
47
49
  },
48
50
  "peerDependenciesMeta": {
49
51
  "typeorm": {