@oktis-works/database 0.4.22 → 0.4.24

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.
@@ -13,6 +13,14 @@ export declare function createConnection(config: DatabaseConfig): RepoSql;
13
13
  export declare function getConnection(): RepoSql;
14
14
  /** Conexão de leitura — usa replica se configurada, senão primary (transparente). */
15
15
  export declare function getReadConnection(): RepoSql;
16
+ /**
17
+ * Executa uma requisição dentro de uma transação e fixa o tenant com SET LOCAL.
18
+ * Todas as camadas que chamam getConnection() passam a usar a mesma conexão
19
+ * durante o callback, evitando vazamento de contexto entre conexões do pool.
20
+ */
21
+ export declare function runWithTenantTransaction<T>(tenantId: string, fn: () => Promise<T>): Promise<T>;
22
+ /** Indica se a execução atual já está presa à transação de uma requisição. */
23
+ export declare function isTenantTransactionActive(): boolean;
16
24
  export declare function getDriver(): DatabaseConfig['driver'];
17
25
  export declare function closeConnection(): Promise<void>;
18
26
  export declare function healthCheck(): Promise<boolean>;
@@ -1 +1 @@
1
- {"version":3,"file":"connection.d.ts","sourceRoot":"","sources":["../src/connection.ts"],"names":[],"mappings":"AAKA,OAAO,QAAQ,MAAM,UAAU,CAAC;AAChC,OAAO,KAAK,EAAE,cAAc,EAAE,MAAM,qBAAqB,CAAC;AAE1D;;;;;GAKG;AACH,MAAM,MAAM,OAAO,GAAG,QAAQ,CAAC,GAAG,GAAG;IACnC,MAAM,CAAC,CAAC,SAAS,GAAG,EAAE,GAAG,QAAQ,CAAC,GAAG,EAAE,EACrC,KAAK,EAAE,MAAM,EACb,UAAU,CAAC,EAAE,GAAG,EAAE,EAClB,YAAY,CAAC,EAAE,GAAG,GACjB,QAAQ,CAAC,YAAY,CAAC,CAAC,CAAC,CAAC;CAC7B,CAAC;AAMF,wBAAgB,gBAAgB,CAAC,MAAM,EAAE,cAAc,GAAG,OAAO,CAsChE;AAED,wBAAgB,aAAa,IAAI,OAAO,CAGvC;AAED,qFAAqF;AACrF,wBAAgB,iBAAiB,IAAI,OAAO,CAE3C;AAED,wBAAgB,SAAS,IAAI,cAAc,CAAC,QAAQ,CAAC,CAAoB;AAEzE,wBAAsB,eAAe,IAAI,OAAO,CAAC,IAAI,CAAC,CAKrD;AAED,wBAAsB,WAAW,IAAI,OAAO,CAAC,OAAO,CAAC,CAQpD"}
1
+ {"version":3,"file":"connection.d.ts","sourceRoot":"","sources":["../src/connection.ts"],"names":[],"mappings":"AAKA,OAAO,QAAQ,MAAM,UAAU,CAAC;AAEhC,OAAO,KAAK,EAAE,cAAc,EAAE,MAAM,qBAAqB,CAAC;AAE1D;;;;;GAKG;AACH,MAAM,MAAM,OAAO,GAAG,QAAQ,CAAC,GAAG,GAAG;IACnC,MAAM,CAAC,CAAC,SAAS,GAAG,EAAE,GAAG,QAAQ,CAAC,GAAG,EAAE,EACrC,KAAK,EAAE,MAAM,EACb,UAAU,CAAC,EAAE,GAAG,EAAE,EAClB,YAAY,CAAC,EAAE,GAAG,GACjB,QAAQ,CAAC,YAAY,CAAC,CAAC,CAAC,CAAC;CAC7B,CAAC;AAOF,wBAAgB,gBAAgB,CAAC,MAAM,EAAE,cAAc,GAAG,OAAO,CAsChE;AAED,wBAAgB,aAAa,IAAI,OAAO,CAGvC;AAED,qFAAqF;AACrF,wBAAgB,iBAAiB,IAAI,OAAO,CAE3C;AAED;;;;GAIG;AACH,wBAAsB,wBAAwB,CAAC,CAAC,EAAE,QAAQ,EAAE,MAAM,EAAE,EAAE,EAAE,MAAM,OAAO,CAAC,CAAC,CAAC,GAAG,OAAO,CAAC,CAAC,CAAC,CAOpG;AAED,8EAA8E;AAC9E,wBAAgB,yBAAyB,IAAI,OAAO,CAEnD;AAED,wBAAgB,SAAS,IAAI,cAAc,CAAC,QAAQ,CAAC,CAAoB;AAEzE,wBAAsB,eAAe,IAAI,OAAO,CAAC,IAAI,CAAC,CAKrD;AAED,wBAAsB,WAAW,IAAI,OAAO,CAAC,OAAO,CAAC,CAQpD"}
@@ -3,9 +3,11 @@
3
3
  // Replica opcional via DB_REPLICA_HOST — leituras podem usar replica quando enabled
4
4
  // Para MySQL, usa mysql2/promise com mesma interface sql.unsafe(); para Postgres mantém 'postgres' lib.
5
5
  import postgres from 'postgres';
6
+ import { AsyncLocalStorage } from 'node:async_hooks';
6
7
  let _sql = null;
7
8
  let _replicaSql = null;
8
9
  let _driver = 'postgres';
10
+ const requestConnection = new AsyncLocalStorage();
9
11
  export function createConnection(config) {
10
12
  if (_sql)
11
13
  return _sql;
@@ -45,11 +47,28 @@ export function createConnection(config) {
45
47
  export function getConnection() {
46
48
  if (!_sql)
47
49
  throw new Error('Database connection not initialized. Call createConnection() first.');
48
- return _sql;
50
+ return requestConnection.getStore() ?? _sql;
49
51
  }
50
52
  /** Conexão de leitura — usa replica se configurada, senão primary (transparente). */
51
53
  export function getReadConnection() {
52
- return _replicaSql ?? getConnection();
54
+ return requestConnection.getStore() ?? _replicaSql ?? getConnection();
55
+ }
56
+ /**
57
+ * Executa uma requisição dentro de uma transação e fixa o tenant com SET LOCAL.
58
+ * Todas as camadas que chamam getConnection() passam a usar a mesma conexão
59
+ * durante o callback, evitando vazamento de contexto entre conexões do pool.
60
+ */
61
+ export async function runWithTenantTransaction(tenantId, fn) {
62
+ const sql = getConnection();
63
+ return sql.begin(async (transaction) => {
64
+ const tx = transaction;
65
+ await tx `SELECT set_config('app.current_tenant_id', ${tenantId}, true)`;
66
+ return requestConnection.run(tx, fn);
67
+ });
68
+ }
69
+ /** Indica se a execução atual já está presa à transação de uma requisição. */
70
+ export function isTenantTransactionActive() {
71
+ return Boolean(requestConnection.getStore());
53
72
  }
54
73
  export function getDriver() { return _driver; }
55
74
  export async function closeConnection() {
@@ -1 +1 @@
1
- {"version":3,"file":"connection.js","sourceRoot":"","sources":["../src/connection.ts"],"names":[],"mappings":"AAAA,0FAA0F;AAC1F,sEAAsE;AACtE,oFAAoF;AACpF,wGAAwG;AAExG,OAAO,QAAQ,MAAM,UAAU,CAAC;AAiBhC,IAAI,IAAI,GAAmB,IAAI,CAAC;AAChC,IAAI,WAAW,GAAmB,IAAI,CAAC;AACvC,IAAI,OAAO,GAA6B,UAAU,CAAC;AAEnD,MAAM,UAAU,gBAAgB,CAAC,MAAsB;IACrD,IAAI,IAAI;QAAE,OAAO,IAAI,CAAC;IACtB,OAAO,GAAG,MAAM,CAAC,MAAM,CAAC;IAExB,IAAI,MAAM,CAAC,MAAM,KAAK,OAAO,EAAE,CAAC;QAC9B,8EAA8E;QAC9E,kFAAkF;QAClF,OAAO,CAAC,IAAI,CAAC,uIAAuI,CAAC,CAAC;IACxJ,CAAC;IAED,IAAI,GAAG,QAAQ,CAAC;QACd,IAAI,EAAE,MAAM,CAAC,IAAI;QACjB,IAAI,EAAE,MAAM,CAAC,IAAI;QACjB,QAAQ,EAAE,MAAM,CAAC,QAAQ;QACzB,QAAQ,EAAE,MAAM,CAAC,IAAI;QACrB,QAAQ,EAAE,MAAM,CAAC,QAAQ;QACzB,GAAG,EAAE,MAAM,CAAC,GAAG;QACf,GAAG,EAAE,MAAM,CAAC,cAAc;QAC1B,YAAY,EAAE,EAAE;QAChB,eAAe,EAAE,EAAE;QACnB,SAAS,EAAE,EAAE,SAAS,EAAE,IAAI,EAAE;KAC/B,CAAY,CAAC;IAEd,IAAI,MAAM,CAAC,OAAO,EAAE,OAAO,EAAE,CAAC;QAC5B,WAAW,GAAG,QAAQ,CAAC;YACrB,IAAI,EAAE,MAAM,CAAC,OAAO,CAAC,IAAI;YACzB,IAAI,EAAE,MAAM,CAAC,OAAO,CAAC,IAAI;YACzB,QAAQ,EAAE,MAAM,CAAC,QAAQ;YACzB,QAAQ,EAAE,MAAM,CAAC,IAAI;YACrB,QAAQ,EAAE,MAAM,CAAC,QAAQ;YACzB,GAAG,EAAE,MAAM,CAAC,GAAG;YACf,GAAG,EAAE,MAAM,CAAC,cAAc;YAC1B,YAAY,EAAE,EAAE;YAChB,eAAe,EAAE,EAAE;SACpB,CAAY,CAAC;IAChB,CAAC;IAED,OAAO,IAAI,CAAC;AACd,CAAC;AAED,MAAM,UAAU,aAAa;IAC3B,IAAI,CAAC,IAAI;QAAE,MAAM,IAAI,KAAK,CAAC,qEAAqE,CAAC,CAAC;IAClG,OAAO,IAAI,CAAC;AACd,CAAC;AAED,qFAAqF;AACrF,MAAM,UAAU,iBAAiB;IAC/B,OAAO,WAAW,IAAI,aAAa,EAAE,CAAC;AACxC,CAAC;AAED,MAAM,UAAU,SAAS,KAA+B,OAAO,OAAO,CAAC,CAAC,CAAC;AAEzE,MAAM,CAAC,KAAK,UAAU,eAAe;IACnC,IAAI,IAAI,EAAE,CAAC;QACT,MAAM,IAAI,CAAC,GAAG,EAAE,CAAC;QACjB,IAAI,GAAG,IAAI,CAAC;IACd,CAAC;AACH,CAAC;AAED,MAAM,CAAC,KAAK,UAAU,WAAW;IAC/B,IAAI,CAAC;QACH,MAAM,GAAG,GAAG,aAAa,EAAE,CAAC;QAC5B,MAAM,MAAM,GAAG,MAAM,GAAG,CAAA,gBAAgB,CAAC;QACzC,OAAO,MAAM,CAAC,CAAC,CAAC,EAAE,CAAC,IAAI,CAAC,KAAK,CAAC,CAAC;IACjC,CAAC;IAAC,MAAM,CAAC;QACP,OAAO,KAAK,CAAC;IACf,CAAC;AACH,CAAC"}
1
+ {"version":3,"file":"connection.js","sourceRoot":"","sources":["../src/connection.ts"],"names":[],"mappings":"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"}
package/dist/index.d.ts CHANGED
@@ -1,4 +1,4 @@
1
- export { createConnection, getConnection, closeConnection, healthCheck } from './connection.js';
1
+ export { createConnection, getConnection, getReadConnection, closeConnection, healthCheck, runWithTenantTransaction, isTenantTransactionActive, } from './connection.js';
2
2
  export { setTenantContext, clearTenantContext, getCurrentTenantId, enableRLS } from './rls/index.js';
3
3
  export { loadMigrationsFromDir, getAppliedMigrations, applyMigration, rollbackMigration, runMigrations, runPluginMigrations, rollbackPluginMigrations, type MigrationFile, } from './migrations/runner.js';
4
4
  export { ensureCoreSchema, resolveTenantId } from './migrations/bootstrap.js';
@@ -1 +1 @@
1
- {"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"AAEA,OAAO,EAAE,gBAAgB,EAAE,aAAa,EAAE,eAAe,EAAE,WAAW,EAAE,MAAM,iBAAiB,CAAC;AAChG,OAAO,EAAE,gBAAgB,EAAE,kBAAkB,EAAE,kBAAkB,EAAE,SAAS,EAAE,MAAM,gBAAgB,CAAC;AACrG,OAAO,EACL,qBAAqB,EACrB,oBAAoB,EACpB,cAAc,EACd,iBAAiB,EACjB,aAAa,EACb,mBAAmB,EACnB,wBAAwB,EACxB,KAAK,aAAa,GACnB,MAAM,wBAAwB,CAAC;AAChC,OAAO,EAAE,gBAAgB,EAAE,eAAe,EAAE,MAAM,2BAA2B,CAAC;AAC9E,OAAO,EACL,YAAY,EACZ,gBAAgB,EAChB,mBAAmB,EACnB,aAAa,EACb,gBAAgB,GACjB,MAAM,sBAAsB,CAAC;AAC9B,OAAO,EAAE,MAAM,EAAE,SAAS,EAAE,MAAM,mBAAmB,CAAC"}
1
+ {"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"AAEA,OAAO,EACL,gBAAgB,EAChB,aAAa,EACb,iBAAiB,EACjB,eAAe,EACf,WAAW,EACX,wBAAwB,EACxB,yBAAyB,GAC1B,MAAM,iBAAiB,CAAC;AACzB,OAAO,EAAE,gBAAgB,EAAE,kBAAkB,EAAE,kBAAkB,EAAE,SAAS,EAAE,MAAM,gBAAgB,CAAC;AACrG,OAAO,EACL,qBAAqB,EACrB,oBAAoB,EACpB,cAAc,EACd,iBAAiB,EACjB,aAAa,EACb,mBAAmB,EACnB,wBAAwB,EACxB,KAAK,aAAa,GACnB,MAAM,wBAAwB,CAAC;AAChC,OAAO,EAAE,gBAAgB,EAAE,eAAe,EAAE,MAAM,2BAA2B,CAAC;AAC9E,OAAO,EACL,YAAY,EACZ,gBAAgB,EAChB,mBAAmB,EACnB,aAAa,EACb,gBAAgB,GACjB,MAAM,sBAAsB,CAAC;AAC9B,OAAO,EAAE,MAAM,EAAE,SAAS,EAAE,MAAM,mBAAmB,CAAC"}
package/dist/index.js CHANGED
@@ -1,5 +1,5 @@
1
1
  // @oktis-works/database - Main Entry Point
2
- export { createConnection, getConnection, closeConnection, healthCheck } from './connection.js';
2
+ export { createConnection, getConnection, getReadConnection, closeConnection, healthCheck, runWithTenantTransaction, isTenantTransactionActive, } from './connection.js';
3
3
  export { setTenantContext, clearTenantContext, getCurrentTenantId, enableRLS } from './rls/index.js';
4
4
  export { loadMigrationsFromDir, getAppliedMigrations, applyMigration, rollbackMigration, runMigrations, runPluginMigrations, rollbackPluginMigrations, } from './migrations/runner.js';
5
5
  export { ensureCoreSchema, resolveTenantId } from './migrations/bootstrap.js';
package/dist/index.js.map CHANGED
@@ -1 +1 @@
1
- {"version":3,"file":"index.js","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"AAAA,2CAA2C;AAE3C,OAAO,EAAE,gBAAgB,EAAE,aAAa,EAAE,eAAe,EAAE,WAAW,EAAE,MAAM,iBAAiB,CAAC;AAChG,OAAO,EAAE,gBAAgB,EAAE,kBAAkB,EAAE,kBAAkB,EAAE,SAAS,EAAE,MAAM,gBAAgB,CAAC;AACrG,OAAO,EACL,qBAAqB,EACrB,oBAAoB,EACpB,cAAc,EACd,iBAAiB,EACjB,aAAa,EACb,mBAAmB,EACnB,wBAAwB,GAEzB,MAAM,wBAAwB,CAAC;AAChC,OAAO,EAAE,gBAAgB,EAAE,eAAe,EAAE,MAAM,2BAA2B,CAAC;AAC9E,OAAO,EACL,YAAY,EACZ,gBAAgB,EAChB,mBAAmB,EACnB,aAAa,EACb,gBAAgB,GACjB,MAAM,sBAAsB,CAAC;AAC9B,OAAO,EAAE,MAAM,EAAE,SAAS,EAAE,MAAM,mBAAmB,CAAC"}
1
+ {"version":3,"file":"index.js","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"AAAA,2CAA2C;AAE3C,OAAO,EACL,gBAAgB,EAChB,aAAa,EACb,iBAAiB,EACjB,eAAe,EACf,WAAW,EACX,wBAAwB,EACxB,yBAAyB,GAC1B,MAAM,iBAAiB,CAAC;AACzB,OAAO,EAAE,gBAAgB,EAAE,kBAAkB,EAAE,kBAAkB,EAAE,SAAS,EAAE,MAAM,gBAAgB,CAAC;AACrG,OAAO,EACL,qBAAqB,EACrB,oBAAoB,EACpB,cAAc,EACd,iBAAiB,EACjB,aAAa,EACb,mBAAmB,EACnB,wBAAwB,GAEzB,MAAM,wBAAwB,CAAC;AAChC,OAAO,EAAE,gBAAgB,EAAE,eAAe,EAAE,MAAM,2BAA2B,CAAC;AAC9E,OAAO,EACL,YAAY,EACZ,gBAAgB,EAChB,mBAAmB,EACnB,aAAa,EACb,gBAAgB,GACjB,MAAM,sBAAsB,CAAC;AAC9B,OAAO,EAAE,MAAM,EAAE,SAAS,EAAE,MAAM,mBAAmB,CAAC"}
@@ -1 +1 @@
1
- {"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../src/rls/index.ts"],"names":[],"mappings":"AAIA,wBAAsB,gBAAgB,CAAC,QAAQ,EAAE,MAAM,GAAG,OAAO,CAAC,IAAI,CAAC,CAKtE;AAED,wBAAsB,kBAAkB,IAAI,OAAO,CAAC,IAAI,CAAC,CAGxD;AAED,wBAAsB,kBAAkB,IAAI,OAAO,CAAC,MAAM,GAAG,IAAI,CAAC,CAMjE;AAED,wBAAsB,SAAS,IAAI,OAAO,CAAC,IAAI,CAAC,CAiB/C"}
1
+ {"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../src/rls/index.ts"],"names":[],"mappings":"AAIA,wBAAsB,gBAAgB,CAAC,QAAQ,EAAE,MAAM,GAAG,OAAO,CAAC,IAAI,CAAC,CAQtE;AAED,wBAAsB,kBAAkB,IAAI,OAAO,CAAC,IAAI,CAAC,CAGxD;AAED,wBAAsB,kBAAkB,IAAI,OAAO,CAAC,MAAM,GAAG,IAAI,CAAC,CAMjE;AAED,wBAAsB,SAAS,IAAI,OAAO,CAAC,IAAI,CAAC,CA2B/C"}
package/dist/rls/index.js CHANGED
@@ -4,6 +4,9 @@ export async function setTenantContext(tenantId) {
4
4
  const sql = getConnection();
5
5
  // `SET` do Postgres não aceita placeholder (syntax error 42601); set_config
6
6
  // parametriza com segurança — o tenantId pode vir do header X-Tenant-ID.
7
+ // A transação de requisição usa SET LOCAL diretamente no helper
8
+ // runWithTenantTransaction; este método preserva a API de contexto global
9
+ // usada por CLI/worker legados.
7
10
  await sql `SELECT set_config('app.current_tenant_id', ${tenantId}, false)`;
8
11
  }
9
12
  export async function clearTenantContext() {
@@ -20,11 +23,21 @@ export async function getCurrentTenantId() {
20
23
  export async function enableRLS() {
21
24
  const sql = getConnection();
22
25
  await sql `ALTER TABLE content ENABLE ROW LEVEL SECURITY`;
26
+ await sql `ALTER TABLE content FORCE ROW LEVEL SECURITY`;
23
27
  await sql `ALTER TABLE media ENABLE ROW LEVEL SECURITY`;
28
+ await sql `ALTER TABLE media FORCE ROW LEVEL SECURITY`;
24
29
  await sql `ALTER TABLE categories ENABLE ROW LEVEL SECURITY`;
25
30
  await sql `ALTER TABLE tags ENABLE ROW LEVEL SECURITY`;
26
31
  await sql `ALTER TABLE menus ENABLE ROW LEVEL SECURITY`;
32
+ await sql `ALTER TABLE menus FORCE ROW LEVEL SECURITY`;
27
33
  await sql `ALTER TABLE settings ENABLE ROW LEVEL SECURITY`;
34
+ await sql `ALTER TABLE settings FORCE ROW LEVEL SECURITY`;
35
+ await sql `ALTER TABLE taxonomies ENABLE ROW LEVEL SECURITY`;
36
+ await sql `ALTER TABLE taxonomies FORCE ROW LEVEL SECURITY`;
37
+ await sql `ALTER TABLE taxonomy_terms ENABLE ROW LEVEL SECURITY`;
38
+ await sql `ALTER TABLE taxonomy_terms FORCE ROW LEVEL SECURITY`;
39
+ await sql `ALTER TABLE content_taxonomy_terms ENABLE ROW LEVEL SECURITY`;
40
+ await sql `ALTER TABLE content_taxonomy_terms FORCE ROW LEVEL SECURITY`;
28
41
  await sql `ALTER TABLE plugins ENABLE ROW LEVEL SECURITY`;
29
42
  await sql `ALTER TABLE themes ENABLE ROW LEVEL SECURITY`;
30
43
  await sql `ALTER TABLE builds ENABLE ROW LEVEL SECURITY`;
@@ -1 +1 @@
1
- {"version":3,"file":"index.js","sourceRoot":"","sources":["../../src/rls/index.ts"],"names":[],"mappings":"AAAA,6CAA6C;AAE7C,OAAO,EAAE,aAAa,EAAE,MAAM,kBAAkB,CAAC;AAEjD,MAAM,CAAC,KAAK,UAAU,gBAAgB,CAAC,QAAgB;IACrD,MAAM,GAAG,GAAG,aAAa,EAAE,CAAC;IAC5B,4EAA4E;IAC5E,yEAAyE;IACzE,MAAM,GAAG,CAAA,8CAA8C,QAAQ,UAAU,CAAC;AAC5E,CAAC;AAED,MAAM,CAAC,KAAK,UAAU,kBAAkB;IACtC,MAAM,GAAG,GAAG,aAAa,EAAE,CAAC;IAC5B,MAAM,GAAG,CAAA,6BAA6B,CAAC;AACzC,CAAC;AAED,MAAM,CAAC,KAAK,UAAU,kBAAkB;IACtC,MAAM,GAAG,GAAG,aAAa,EAAE,CAAC;IAC5B,MAAM,MAAM,GAAG,MAAM,GAAG,CAA4C;;GAEnE,CAAC;IACF,OAAO,MAAM,CAAC,CAAC,CAAC,EAAE,qBAAqB,IAAI,IAAI,CAAC;AAClD,CAAC;AAED,MAAM,CAAC,KAAK,UAAU,SAAS;IAC7B,MAAM,GAAG,GAAG,aAAa,EAAE,CAAC;IAC5B,MAAM,GAAG,CAAA,+CAA+C,CAAC;IACzD,MAAM,GAAG,CAAA,6CAA6C,CAAC;IACvD,MAAM,GAAG,CAAA,kDAAkD,CAAC;IAC5D,MAAM,GAAG,CAAA,4CAA4C,CAAC;IACtD,MAAM,GAAG,CAAA,6CAA6C,CAAC;IACvD,MAAM,GAAG,CAAA,gDAAgD,CAAC;IAC1D,MAAM,GAAG,CAAA,+CAA+C,CAAC;IACzD,MAAM,GAAG,CAAA,8CAA8C,CAAC;IACxD,MAAM,GAAG,CAAA,8CAA8C,CAAC;IACxD,MAAM,GAAG,CAAA,mDAAmD,CAAC;IAC7D,MAAM,GAAG,CAAA,8CAA8C,CAAC;IACxD,MAAM,GAAG,CAAA,kDAAkD,CAAC;IAC5D,MAAM,GAAG,CAAA,kDAAkD,CAAC;IAC5D,MAAM,GAAG,CAAA,gDAAgD,CAAC;IAC1D,MAAM,GAAG,CAAA,gDAAgD,CAAC;AAC5D,CAAC"}
1
+ {"version":3,"file":"index.js","sourceRoot":"","sources":["../../src/rls/index.ts"],"names":[],"mappings":"AAAA,6CAA6C;AAE7C,OAAO,EAAE,aAAa,EAAE,MAAM,kBAAkB,CAAC;AAEjD,MAAM,CAAC,KAAK,UAAU,gBAAgB,CAAC,QAAgB;IACrD,MAAM,GAAG,GAAG,aAAa,EAAE,CAAC;IAC5B,4EAA4E;IAC5E,yEAAyE;IACzE,gEAAgE;IAChE,0EAA0E;IAC1E,gCAAgC;IAChC,MAAM,GAAG,CAAA,8CAA8C,QAAQ,UAAU,CAAC;AAC5E,CAAC;AAED,MAAM,CAAC,KAAK,UAAU,kBAAkB;IACtC,MAAM,GAAG,GAAG,aAAa,EAAE,CAAC;IAC5B,MAAM,GAAG,CAAA,6BAA6B,CAAC;AACzC,CAAC;AAED,MAAM,CAAC,KAAK,UAAU,kBAAkB;IACtC,MAAM,GAAG,GAAG,aAAa,EAAE,CAAC;IAC5B,MAAM,MAAM,GAAG,MAAM,GAAG,CAA4C;;GAEnE,CAAC;IACF,OAAO,MAAM,CAAC,CAAC,CAAC,EAAE,qBAAqB,IAAI,IAAI,CAAC;AAClD,CAAC;AAED,MAAM,CAAC,KAAK,UAAU,SAAS;IAC7B,MAAM,GAAG,GAAG,aAAa,EAAE,CAAC;IAC5B,MAAM,GAAG,CAAA,+CAA+C,CAAC;IACzD,MAAM,GAAG,CAAA,8CAA8C,CAAC;IACxD,MAAM,GAAG,CAAA,6CAA6C,CAAC;IACvD,MAAM,GAAG,CAAA,4CAA4C,CAAC;IACtD,MAAM,GAAG,CAAA,kDAAkD,CAAC;IAC5D,MAAM,GAAG,CAAA,4CAA4C,CAAC;IACtD,MAAM,GAAG,CAAA,6CAA6C,CAAC;IACvD,MAAM,GAAG,CAAA,4CAA4C,CAAC;IACtD,MAAM,GAAG,CAAA,gDAAgD,CAAC;IAC1D,MAAM,GAAG,CAAA,+CAA+C,CAAC;IACzD,MAAM,GAAG,CAAA,kDAAkD,CAAC;IAC5D,MAAM,GAAG,CAAA,iDAAiD,CAAC;IAC3D,MAAM,GAAG,CAAA,sDAAsD,CAAC;IAChE,MAAM,GAAG,CAAA,qDAAqD,CAAC;IAC/D,MAAM,GAAG,CAAA,8DAA8D,CAAC;IACxE,MAAM,GAAG,CAAA,6DAA6D,CAAC;IACvE,MAAM,GAAG,CAAA,+CAA+C,CAAC;IACzD,MAAM,GAAG,CAAA,8CAA8C,CAAC;IACxD,MAAM,GAAG,CAAA,8CAA8C,CAAC;IACxD,MAAM,GAAG,CAAA,mDAAmD,CAAC;IAC7D,MAAM,GAAG,CAAA,8CAA8C,CAAC;IACxD,MAAM,GAAG,CAAA,kDAAkD,CAAC;IAC5D,MAAM,GAAG,CAAA,kDAAkD,CAAC;IAC5D,MAAM,GAAG,CAAA,gDAAgD,CAAC;IAC1D,MAAM,GAAG,CAAA,gDAAgD,CAAC;AAC5D,CAAC"}
@@ -153,18 +153,26 @@ CREATE TABLE IF NOT EXISTS media (
153
153
  id UUID PRIMARY KEY DEFAULT gen_random_uuid(),
154
154
  tenant_id UUID NOT NULL REFERENCES tenants(id) ON DELETE CASCADE,
155
155
  filename VARCHAR(500) NOT NULL,
156
+ title VARCHAR(500),
156
157
  mime_type VARCHAR(255) NOT NULL,
157
158
  size INTEGER NOT NULL,
158
159
  path VARCHAR(1000) NOT NULL,
159
160
  url VARCHAR(1000) NOT NULL,
160
161
  alt VARCHAR(500),
161
162
  caption TEXT,
163
+ description TEXT,
162
164
  metadata JSONB,
163
165
  uploaded_by UUID NOT NULL REFERENCES users(id) ON DELETE CASCADE,
164
166
  created_at TIMESTAMP WITH TIME ZONE NOT NULL DEFAULT NOW(),
165
167
  updated_at TIMESTAMP WITH TIME ZONE NOT NULL DEFAULT NOW()
166
168
  );
167
169
 
170
+ -- Idempotent upgrade path for databases created before attachment titles and
171
+ -- descriptions were added (CREATE TABLE IF NOT EXISTS does not alter them).
172
+ ALTER TABLE media ADD COLUMN IF NOT EXISTS title VARCHAR(500);
173
+ ALTER TABLE media ADD COLUMN IF NOT EXISTS description TEXT;
174
+ UPDATE media SET title = filename WHERE title IS NULL;
175
+
168
176
  CREATE INDEX IF NOT EXISTS idx_media_tenant ON media(tenant_id);
169
177
  CREATE INDEX IF NOT EXISTS idx_media_mime ON media(mime_type);
170
178
  CREATE INDEX IF NOT EXISTS idx_media_uploaded_by ON media(uploaded_by);
@@ -232,6 +240,7 @@ CREATE TABLE IF NOT EXISTS menus (
232
240
  name VARCHAR(255) NOT NULL,
233
241
  slug VARCHAR(255) NOT NULL,
234
242
  items JSONB NOT NULL DEFAULT '[]'::jsonb,
243
+ settings JSONB NOT NULL DEFAULT '{}'::jsonb,
235
244
  created_at TIMESTAMP WITH TIME ZONE NOT NULL DEFAULT NOW(),
236
245
  updated_at TIMESTAMP WITH TIME ZONE NOT NULL DEFAULT NOW()
237
246
  );
@@ -717,17 +726,48 @@ CREATE TABLE IF NOT EXISTS content_taxonomy_terms (
717
726
  CREATE INDEX IF NOT EXISTS idx_content_terms_content ON content_taxonomy_terms(content_id);
718
727
  CREATE INDEX IF NOT EXISTS idx_content_terms_term ON content_taxonomy_terms(term_id);
719
728
 
729
+ ALTER TABLE taxonomy_terms ENABLE ROW LEVEL SECURITY;
730
+ ALTER TABLE taxonomy_terms FORCE ROW LEVEL SECURITY;
731
+ ALTER TABLE content_taxonomy_terms ENABLE ROW LEVEL SECURITY;
732
+ ALTER TABLE content_taxonomy_terms FORCE ROW LEVEL SECURITY;
733
+
734
+ DO $$
735
+ BEGIN
736
+ IF NOT EXISTS (
737
+ SELECT 1 FROM pg_policies
738
+ WHERE policyname = 'tenant_isolation_taxonomy_terms' AND tablename = 'taxonomy_terms'
739
+ ) THEN
740
+ CREATE POLICY tenant_isolation_taxonomy_terms ON taxonomy_terms
741
+ USING (tenant_id = current_setting('app.current_tenant_id', true)::uuid OR tenant_id IS NULL);
742
+ END IF;
743
+ IF NOT EXISTS (
744
+ SELECT 1 FROM pg_policies
745
+ WHERE policyname = 'tenant_isolation_content_taxonomy_terms' AND tablename = 'content_taxonomy_terms'
746
+ ) THEN
747
+ CREATE POLICY tenant_isolation_content_taxonomy_terms ON content_taxonomy_terms
748
+ USING (EXISTS (
749
+ SELECT 1 FROM content c
750
+ WHERE c.id = content_taxonomy_terms.content_id
751
+ AND c.tenant_id = current_setting('app.current_tenant_id', true)::uuid
752
+ ));
753
+ END IF;
754
+ END $$;
755
+
720
756
  -- ============================================================
721
757
  -- Row Level Security Policies
722
758
  -- ============================================================
723
759
 
724
760
  -- Enable RLS on all tenant-scoped tables
725
761
  ALTER TABLE content ENABLE ROW LEVEL SECURITY;
762
+ ALTER TABLE content FORCE ROW LEVEL SECURITY;
726
763
  ALTER TABLE media ENABLE ROW LEVEL SECURITY;
764
+ ALTER TABLE media FORCE ROW LEVEL SECURITY;
727
765
  ALTER TABLE categories ENABLE ROW LEVEL SECURITY;
728
766
  ALTER TABLE tags ENABLE ROW LEVEL SECURITY;
729
767
  ALTER TABLE menus ENABLE ROW LEVEL SECURITY;
768
+ ALTER TABLE menus FORCE ROW LEVEL SECURITY;
730
769
  ALTER TABLE settings ENABLE ROW LEVEL SECURITY;
770
+ ALTER TABLE settings FORCE ROW LEVEL SECURITY;
731
771
  ALTER TABLE plugins ENABLE ROW LEVEL SECURITY;
732
772
  ALTER TABLE themes ENABLE ROW LEVEL SECURITY;
733
773
  ALTER TABLE builds ENABLE ROW LEVEL SECURITY;
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@oktis-works/database",
3
- "version": "0.4.22",
3
+ "version": "0.4.24",
4
4
  "private": false,
5
5
  "type": "module",
6
6
  "main": "./dist/index.js",