@oktis-works/database 0.5.8 → 0.7.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.
@@ -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,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,CA+B/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,CAiC/C"}
package/dist/rls/index.js CHANGED
@@ -51,5 +51,7 @@ export async function enableRLS() {
51
51
  await sql `ALTER TABLE migrations ENABLE ROW LEVEL SECURITY`;
52
52
  await sql `ALTER TABLE sessions ENABLE ROW LEVEL SECURITY`;
53
53
  await sql `ALTER TABLE webhooks ENABLE ROW LEVEL SECURITY`;
54
+ await sql `ALTER TABLE api_keys ENABLE ROW LEVEL SECURITY`;
55
+ await sql `ALTER TABLE api_keys FORCE ROW LEVEL SECURITY`;
54
56
  }
55
57
  //# sourceMappingURL=index.js.map
@@ -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,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,+CAA+C,CAAC;IACzD,MAAM,GAAG,CAAA,8CAA8C,CAAC;IACxD,MAAM,GAAG,CAAA,sDAAsD,CAAC;IAChE,MAAM,GAAG,CAAA,qDAAqD,CAAC;IAC/D,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,8CAA8C,CAAC;IACxD,MAAM,GAAG,CAAA,6CAA6C,CAAC;IACvD,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,+CAA+C,CAAC;IACzD,MAAM,GAAG,CAAA,8CAA8C,CAAC;IACxD,MAAM,GAAG,CAAA,sDAAsD,CAAC;IAChE,MAAM,GAAG,CAAA,qDAAqD,CAAC;IAC/D,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,8CAA8C,CAAC;IACxD,MAAM,GAAG,CAAA,6CAA6C,CAAC;IACvD,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;IAC1D,MAAM,GAAG,CAAA,gDAAgD,CAAC;IAC1D,MAAM,GAAG,CAAA,+CAA+C,CAAC;AAC3D,CAAC"}
@@ -568,6 +568,31 @@ CREATE INDEX IF NOT EXISTS idx_sessions_expires ON sessions(expires_at);
568
568
  CREATE INDEX IF NOT EXISTS idx_sessions_refresh_hash ON sessions(refresh_token_hash);
569
569
  CREATE INDEX IF NOT EXISTS idx_sessions_refresh_family ON sessions(refresh_family_id);
570
570
 
571
+ -- ============================================================
572
+ -- API Keys (login via API para clientes API-first)
573
+ -- A key NUNCA autoriza requests: troca por access JWT + refresh token em
574
+ -- POST /api/v1/auth/api-key-login. Guardamos só o hash sha256.
575
+ -- ============================================================
576
+ CREATE TABLE IF NOT EXISTS api_keys (
577
+ id UUID PRIMARY KEY DEFAULT gen_random_uuid(),
578
+ tenant_id UUID NOT NULL REFERENCES tenants(id) ON DELETE CASCADE,
579
+ user_id UUID NOT NULL REFERENCES users(id) ON DELETE CASCADE,
580
+ name VARCHAR(255) NOT NULL,
581
+ key_prefix VARCHAR(32) NOT NULL,
582
+ key_hash VARCHAR(128) NOT NULL,
583
+ one_time BOOLEAN NOT NULL DEFAULT false,
584
+ expires_at TIMESTAMP WITH TIME ZONE,
585
+ last_used_at TIMESTAMP WITH TIME ZONE,
586
+ use_count INTEGER NOT NULL DEFAULT 0,
587
+ revoked_at TIMESTAMP WITH TIME ZONE,
588
+ created_by UUID REFERENCES users(id) ON DELETE SET NULL,
589
+ created_at TIMESTAMP WITH TIME ZONE NOT NULL DEFAULT NOW()
590
+ );
591
+
592
+ CREATE UNIQUE INDEX IF NOT EXISTS idx_api_keys_prefix ON api_keys(tenant_id, key_prefix);
593
+ CREATE INDEX IF NOT EXISTS idx_api_keys_tenant ON api_keys(tenant_id);
594
+ CREATE INDEX IF NOT EXISTS idx_api_keys_user ON api_keys(user_id);
595
+
571
596
  -- ============================================================
572
597
  -- Custom Taxonomies (SDD ENTI-025)
573
598
  -- ============================================================
@@ -981,6 +1006,36 @@ BEGIN
981
1006
  END IF;
982
1007
  END $$;
983
1008
 
1009
+ -- Lookup da API key acontece ANTES do contexto de tenant do access token
1010
+ -- existir (é o próprio login). O app seta este hash transacional somente na
1011
+ -- operação de auth, então o RLS ainda permite exatamente UM lookup por
1012
+ -- prefixo sem expor a tabela a requisições de outro tenant.
1013
+ DO $$
1014
+ BEGIN
1015
+ IF NOT EXISTS (
1016
+ SELECT 1 FROM pg_policies
1017
+ WHERE policyname = 'api_key_prefix_lookup' AND tablename = 'api_keys'
1018
+ ) THEN
1019
+ CREATE POLICY api_key_prefix_lookup ON api_keys
1020
+ USING (
1021
+ key_prefix = NULLIF(current_setting('app.current_api_key_prefix', true), '')
1022
+ )
1023
+ WITH CHECK (
1024
+ tenant_id = current_setting('app.current_tenant_id', true)::uuid
1025
+ );
1026
+ END IF;
1027
+ END $$;
1028
+
1029
+ DO $$
1030
+ BEGIN
1031
+ IF NOT EXISTS (
1032
+ SELECT 1 FROM pg_policies
1033
+ WHERE policyname = 'tenant_isolation_api_keys' AND tablename = 'api_keys'
1034
+ ) THEN
1035
+ CREATE POLICY tenant_isolation_api_keys ON api_keys USING (tenant_id = current_setting('app.current_tenant_id', true)::uuid);
1036
+ END IF;
1037
+ END $$;
1038
+
984
1039
  -- ============================================================
985
1040
  -- Delta de dados (idempotente, best-effort): valor neutro para a
986
1041
  -- posição do field group em bancos já existentes. Falhas viram
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@oktis-works/database",
3
- "version": "0.5.8",
3
+ "version": "0.7.0",
4
4
  "private": false,
5
5
  "type": "module",
6
6
  "main": "./dist/index.js",
@@ -19,8 +19,8 @@
19
19
  "db:rollback": "node --loader ts-node/esm src/migrations/runner.ts rollback"
20
20
  },
21
21
  "dependencies": {
22
- "@oktis-works/types": "^0.5.5",
23
- "@oktis-works/config": "^0.6.0",
22
+ "@oktis-works/types": "^0.7.0",
23
+ "@oktis-works/config": "^0.6.2",
24
24
  "postgres": "3.4.0"
25
25
  },
26
26
  "devDependencies": {