@jantstack/adonis-authz 1.1.0 → 2.4.0-alpha.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.
Files changed (236) hide show
  1. package/LICENSE +1 -1
  2. package/README.md +837 -51
  3. package/build/commands/authz_catalog_diff.d.ts +28 -0
  4. package/build/commands/authz_catalog_diff.d.ts.map +1 -0
  5. package/build/commands/authz_catalog_diff.js +67 -0
  6. package/build/commands/authz_catalog_diff.js.map +1 -0
  7. package/build/commands/authz_catalog_prune_orphans.d.ts +78 -0
  8. package/build/commands/authz_catalog_prune_orphans.d.ts.map +1 -0
  9. package/build/commands/authz_catalog_prune_orphans.js +136 -0
  10. package/build/commands/authz_catalog_prune_orphans.js.map +1 -0
  11. package/build/commands/authz_catalog_sync.d.ts +37 -0
  12. package/build/commands/authz_catalog_sync.d.ts.map +1 -0
  13. package/build/commands/authz_catalog_sync.js +81 -0
  14. package/build/commands/authz_catalog_sync.js.map +1 -0
  15. package/build/commands/authz_freeze.d.ts +44 -0
  16. package/build/commands/authz_freeze.d.ts.map +1 -0
  17. package/build/commands/authz_freeze.js +95 -0
  18. package/build/commands/authz_freeze.js.map +1 -0
  19. package/build/commands/authz_reconcile.d.ts +102 -0
  20. package/build/commands/authz_reconcile.d.ts.map +1 -0
  21. package/build/commands/authz_reconcile.js +294 -0
  22. package/build/commands/authz_reconcile.js.map +1 -0
  23. package/build/commands/authz_relations_reconcile.d.ts +73 -0
  24. package/build/commands/authz_relations_reconcile.d.ts.map +1 -0
  25. package/build/commands/authz_relations_reconcile.js +225 -0
  26. package/build/commands/authz_relations_reconcile.js.map +1 -0
  27. package/build/commands/authz_scopes_relay.d.ts +47 -0
  28. package/build/commands/authz_scopes_relay.d.ts.map +1 -0
  29. package/build/commands/authz_scopes_relay.js +141 -0
  30. package/build/commands/authz_scopes_relay.js.map +1 -0
  31. package/build/commands/authz_unfreeze.d.ts +37 -0
  32. package/build/commands/authz_unfreeze.d.ts.map +1 -0
  33. package/build/commands/authz_unfreeze.js +92 -0
  34. package/build/commands/authz_unfreeze.js.map +1 -0
  35. package/build/commands/main.d.ts +8 -1
  36. package/build/commands/main.d.ts.map +1 -1
  37. package/build/commands/main.js +8 -1
  38. package/build/commands/main.js.map +1 -1
  39. package/build/commands/openfga_provision.d.ts +46 -4
  40. package/build/commands/openfga_provision.d.ts.map +1 -1
  41. package/build/commands/openfga_provision.js +91 -7
  42. package/build/commands/openfga_provision.js.map +1 -1
  43. package/build/configure.d.ts +11 -0
  44. package/build/configure.d.ts.map +1 -1
  45. package/build/configure.js +37 -1
  46. package/build/configure.js.map +1 -1
  47. package/build/index.d.ts +75 -7
  48. package/build/index.d.ts.map +1 -1
  49. package/build/index.js +67 -5
  50. package/build/index.js.map +1 -1
  51. package/build/providers/authz_provider.d.ts +26 -2
  52. package/build/providers/authz_provider.d.ts.map +1 -1
  53. package/build/providers/authz_provider.js +48 -2
  54. package/build/providers/authz_provider.js.map +1 -1
  55. package/build/services/relations.d.ts +14 -0
  56. package/build/services/relations.d.ts.map +1 -0
  57. package/build/services/relations.js +17 -0
  58. package/build/services/relations.js.map +1 -0
  59. package/build/src/catalog/catalog.d.ts +289 -0
  60. package/build/src/catalog/catalog.d.ts.map +1 -0
  61. package/build/src/catalog/catalog.js +859 -0
  62. package/build/src/catalog/catalog.js.map +1 -0
  63. package/build/src/catalog/catalog_cache.d.ts +324 -0
  64. package/build/src/catalog/catalog_cache.d.ts.map +1 -0
  65. package/build/src/catalog/catalog_cache.js +666 -0
  66. package/build/src/catalog/catalog_cache.js.map +1 -0
  67. package/build/src/clock.d.ts +24 -0
  68. package/build/src/clock.d.ts.map +1 -0
  69. package/build/src/clock.js +7 -0
  70. package/build/src/clock.js.map +1 -0
  71. package/build/src/define_config.d.ts +201 -7
  72. package/build/src/define_config.d.ts.map +1 -1
  73. package/build/src/define_config.js.map +1 -1
  74. package/build/src/drivers/database_driver.d.ts +324 -15
  75. package/build/src/drivers/database_driver.d.ts.map +1 -1
  76. package/build/src/drivers/database_driver.js +1107 -128
  77. package/build/src/drivers/database_driver.js.map +1 -1
  78. package/build/src/drivers/database_relations_driver.d.ts +75 -0
  79. package/build/src/drivers/database_relations_driver.d.ts.map +1 -0
  80. package/build/src/drivers/database_relations_driver.js +450 -0
  81. package/build/src/drivers/database_relations_driver.js.map +1 -0
  82. package/build/src/drivers/openfga_driver.d.ts +963 -55
  83. package/build/src/drivers/openfga_driver.d.ts.map +1 -1
  84. package/build/src/drivers/openfga_driver.js +2693 -372
  85. package/build/src/drivers/openfga_driver.js.map +1 -1
  86. package/build/src/drivers/openfga_facts.d.ts +369 -0
  87. package/build/src/drivers/openfga_facts.d.ts.map +1 -0
  88. package/build/src/drivers/openfga_facts.js +813 -0
  89. package/build/src/drivers/openfga_facts.js.map +1 -0
  90. package/build/src/drivers/openfga_relations_driver.d.ts +120 -0
  91. package/build/src/drivers/openfga_relations_driver.d.ts.map +1 -0
  92. package/build/src/drivers/openfga_relations_driver.js +466 -0
  93. package/build/src/drivers/openfga_relations_driver.js.map +1 -0
  94. package/build/src/errors.d.ts +586 -0
  95. package/build/src/errors.d.ts.map +1 -1
  96. package/build/src/errors.js +583 -0
  97. package/build/src/errors.js.map +1 -1
  98. package/build/src/expiry.d.ts +27 -0
  99. package/build/src/expiry.d.ts.map +1 -0
  100. package/build/src/expiry.js +50 -0
  101. package/build/src/expiry.js.map +1 -0
  102. package/build/src/freeze.d.ts +120 -0
  103. package/build/src/freeze.d.ts.map +1 -0
  104. package/build/src/freeze.js +172 -0
  105. package/build/src/freeze.js.map +1 -0
  106. package/build/src/hierarchical_resolver.d.ts +56 -0
  107. package/build/src/hierarchical_resolver.d.ts.map +1 -0
  108. package/build/src/hierarchical_resolver.js +87 -0
  109. package/build/src/hierarchical_resolver.js.map +1 -0
  110. package/build/src/{middleware → http}/app_access_middleware.d.ts +8 -6
  111. package/build/src/http/app_access_middleware.d.ts.map +1 -0
  112. package/build/src/{middleware → http}/app_access_middleware.js +10 -26
  113. package/build/src/http/app_access_middleware.js.map +1 -0
  114. package/build/src/http/resource_access_middleware.d.ts +105 -0
  115. package/build/src/http/resource_access_middleware.d.ts.map +1 -0
  116. package/build/src/http/resource_access_middleware.js +81 -0
  117. package/build/src/http/resource_access_middleware.js.map +1 -0
  118. package/build/src/identity.d.ts +228 -0
  119. package/build/src/identity.d.ts.map +1 -0
  120. package/build/src/identity.js +457 -0
  121. package/build/src/identity.js.map +1 -0
  122. package/build/src/manager.d.ts +536 -7
  123. package/build/src/manager.d.ts.map +1 -1
  124. package/build/src/manager.js +2676 -23
  125. package/build/src/manager.js.map +1 -1
  126. package/build/src/memoize_ancestors.d.ts +23 -0
  127. package/build/src/memoize_ancestors.d.ts.map +1 -0
  128. package/build/src/memoize_ancestors.js +42 -0
  129. package/build/src/memoize_ancestors.js.map +1 -0
  130. package/build/src/models/authz_assignment.d.ts +11 -11
  131. package/build/src/models/authz_assignment.d.ts.map +1 -1
  132. package/build/src/models/authz_deny.d.ts +11 -11
  133. package/build/src/models/authz_deny.d.ts.map +1 -1
  134. package/build/src/models/authz_permission.d.ts +17 -11
  135. package/build/src/models/authz_permission.d.ts.map +1 -1
  136. package/build/src/models/authz_permission.js +4 -0
  137. package/build/src/models/authz_permission.js.map +1 -1
  138. package/build/src/models/authz_role.d.ts +19 -12
  139. package/build/src/models/authz_role.d.ts.map +1 -1
  140. package/build/src/models/authz_role.js +6 -1
  141. package/build/src/models/authz_role.js.map +1 -1
  142. package/build/src/models/authz_role_permission.d.ts +11 -11
  143. package/build/src/models/authz_role_permission.d.ts.map +1 -1
  144. package/build/src/openfga.d.ts +29 -0
  145. package/build/src/openfga.d.ts.map +1 -0
  146. package/build/src/openfga.js +26 -0
  147. package/build/src/openfga.js.map +1 -0
  148. package/build/src/reconcile.d.ts +37 -0
  149. package/build/src/reconcile.d.ts.map +1 -0
  150. package/build/src/reconcile.js +69 -0
  151. package/build/src/reconcile.js.map +1 -0
  152. package/build/src/relation_partition_trigger.d.ts +8 -0
  153. package/build/src/relation_partition_trigger.d.ts.map +1 -0
  154. package/build/src/relation_partition_trigger.js +85 -0
  155. package/build/src/relation_partition_trigger.js.map +1 -0
  156. package/build/src/relations/define_relations_config.d.ts +58 -0
  157. package/build/src/relations/define_relations_config.d.ts.map +1 -0
  158. package/build/src/relations/define_relations_config.js +144 -0
  159. package/build/src/relations/define_relations_config.js.map +1 -0
  160. package/build/src/relations/manager.d.ts +38 -0
  161. package/build/src/relations/manager.d.ts.map +1 -0
  162. package/build/src/relations/manager.js +156 -0
  163. package/build/src/relations/manager.js.map +1 -0
  164. package/build/src/relations/reconcile.d.ts +62 -0
  165. package/build/src/relations/reconcile.d.ts.map +1 -0
  166. package/build/src/relations/reconcile.js +138 -0
  167. package/build/src/relations/reconcile.js.map +1 -0
  168. package/build/src/relations_config_store.d.ts +22 -0
  169. package/build/src/relations_config_store.d.ts.map +1 -0
  170. package/build/src/relations_config_store.js +74 -0
  171. package/build/src/relations_config_store.js.map +1 -0
  172. package/build/src/scope_outbox.d.ts +69 -0
  173. package/build/src/scope_outbox.d.ts.map +1 -0
  174. package/build/src/scope_outbox.js +291 -0
  175. package/build/src/scope_outbox.js.map +1 -0
  176. package/build/src/shared/backend_guard.d.ts +106 -0
  177. package/build/src/shared/backend_guard.d.ts.map +1 -0
  178. package/build/src/shared/backend_guard.js +246 -0
  179. package/build/src/shared/backend_guard.js.map +1 -0
  180. package/build/src/shared/sql_expiry.d.ts +53 -0
  181. package/build/src/shared/sql_expiry.d.ts.map +1 -0
  182. package/build/src/shared/sql_expiry.js +66 -0
  183. package/build/src/shared/sql_expiry.js.map +1 -0
  184. package/build/src/sql_descendants.d.ts +97 -0
  185. package/build/src/sql_descendants.d.ts.map +1 -0
  186. package/build/src/sql_descendants.js +203 -0
  187. package/build/src/sql_descendants.js.map +1 -0
  188. package/build/src/testing/contract.d.ts +212 -7
  189. package/build/src/testing/contract.d.ts.map +1 -1
  190. package/build/src/testing/contract.js +3449 -24
  191. package/build/src/testing/contract.js.map +1 -1
  192. package/build/src/testing/main.d.ts +10 -2
  193. package/build/src/testing/main.d.ts.map +1 -1
  194. package/build/src/testing/main.js +5 -1
  195. package/build/src/testing/main.js.map +1 -1
  196. package/build/src/testing/migration_contract.d.ts +284 -0
  197. package/build/src/testing/migration_contract.d.ts.map +1 -0
  198. package/build/src/testing/migration_contract.js +586 -0
  199. package/build/src/testing/migration_contract.js.map +1 -0
  200. package/build/src/testing/relations_contract.d.ts +51 -0
  201. package/build/src/testing/relations_contract.d.ts.map +1 -0
  202. package/build/src/testing/relations_contract.js +654 -0
  203. package/build/src/testing/relations_contract.js.map +1 -0
  204. package/build/src/testing/relations_reconcile_contract.d.ts +24 -0
  205. package/build/src/testing/relations_reconcile_contract.d.ts.map +1 -0
  206. package/build/src/testing/relations_reconcile_contract.js +172 -0
  207. package/build/src/testing/relations_reconcile_contract.js.map +1 -0
  208. package/build/src/testing/scope_tree.d.ts +65 -0
  209. package/build/src/testing/scope_tree.d.ts.map +1 -0
  210. package/build/src/testing/scope_tree.js +145 -0
  211. package/build/src/testing/scope_tree.js.map +1 -0
  212. package/build/src/traits/authz_scopes.d.ts +30 -6
  213. package/build/src/traits/authz_scopes.d.ts.map +1 -1
  214. package/build/src/traits/authz_scopes.js +30 -18
  215. package/build/src/traits/authz_scopes.js.map +1 -1
  216. package/build/src/traits/has_uuid.d.ts +12 -12
  217. package/build/src/traits/has_uuid.d.ts.map +1 -1
  218. package/build/src/types.d.ts +1313 -28
  219. package/build/src/types.d.ts.map +1 -1
  220. package/build/src/types.js +20 -4
  221. package/build/src/types.js.map +1 -1
  222. package/build/stubs/config/app_acl.stub +4 -2
  223. package/build/stubs/config/authorization.stub +168 -14
  224. package/build/stubs/migration.stub +183 -13
  225. package/build/stubs/scopes_outbox_migration.stub +57 -0
  226. package/package.json +14 -7
  227. package/build/commands/openfga_import.d.ts +0 -28
  228. package/build/commands/openfga_import.d.ts.map +0 -1
  229. package/build/commands/openfga_import.js +0 -74
  230. package/build/commands/openfga_import.js.map +0 -1
  231. package/build/src/catalog.d.ts +0 -3
  232. package/build/src/catalog.d.ts.map +0 -1
  233. package/build/src/catalog.js +0 -103
  234. package/build/src/catalog.js.map +0 -1
  235. package/build/src/middleware/app_access_middleware.d.ts.map +0 -1
  236. package/build/src/middleware/app_access_middleware.js.map +0 -1
@@ -0,0 +1,457 @@
1
+ import { InvalidIdentityError, InvalidSlugError } from './errors.js';
2
+ import { APP_SCOPE_TYPE } from './types.js';
3
+ /**
4
+ * Validación de identidad del motor: holder, scope, rol y permiso.
5
+ *
6
+ * Vive en un solo sitio y la aplican el manager (una vez por llamada) Y los
7
+ * drivers (defensa en profundidad: el juez del contrato habla con el driver
8
+ * directamente, y un driver de terceros puede usarse sin manager). Nadie
9
+ * duplica la regla: se importa.
10
+ *
11
+ * Por qué es 422 y no "se acepta lo que venga":
12
+ * - `uuid: undefined` en el driver openfga escribía `user:undefined`, y a
13
+ * partir de ahí CUALQUIER holder sin uuid heredaba ese permiso (L0.5).
14
+ * - `{ type: 'app', uuid: 'X' }` colapsaba a la raíz global en openfga y no
15
+ * en database: escalada de tenant a plataforma en un driver y `false` en
16
+ * el otro (L0.10).
17
+ * - `#`, `:`, `|`, `~`, `*` y espacios son sintaxis de FGA o separadores de
18
+ * los ids de binding: un componente que los contenga puede fabricar un
19
+ * userset, un comodín o la clave de OTRO scope (L0.5, L0.8). Desde 3A
20
+ * (2.2) el slug ya NO viaja en los ids de FGA (van por uuid de catálogo),
21
+ * pero los tipos y uuids de scope sí, y los slugs serán relaciones del
22
+ * modelo `facts` (3b): la lista blanca se mantiene entera.
23
+ * - Las longitudes son las de las columnas `authz_*`: lo que no cabe se
24
+ * truncaría o fallaría con un error de SQL ilegible.
25
+ */
26
+ /**
27
+ * Longitudes de columna del esquema publicado (`stubs/migration.stub`) que
28
+ * la identidad aplica tal cual. El slug NO está aquí: su límite es
29
+ * `MAX_SLUG_LENGTH` (42), más estricto que la columna (100) para que el
30
+ * catálogo sea publicable en FGA (E2).
31
+ */
32
+ export const IDENTITY_LIMITS = Object.freeze({
33
+ holderType: 50,
34
+ scopeType: 20,
35
+ uuid: 36,
36
+ });
37
+ /**
38
+ * Centinela con el que el driver `database` almacena el uuid del scope `app`
39
+ * (NOT NULL + unique). Fuera de `app` sería una identidad de scope que
40
+ * colisiona con la raíz: se rechaza (L0.15).
41
+ */
42
+ export const SENTINEL_UUID = '00000000-0000-0000-0000-000000000000';
43
+ /**
44
+ * UUID del CATÁLOGO (rol o permiso): la columna `uuid` de `authz_roles` y
45
+ * `authz_permissions` es `uuid` real, y desde 3A (2.2) es lo que viaja en
46
+ * los ids de binding de FGA (`role_binding:<scopeKey>|<roleUuid>`). Se exige
47
+ * canónico y en MINÚSCULAS (RFC 9562, 8-4-4-4-12 hex): PostgreSQL lo
48
+ * normaliza así y MySQL/SQLite lo guardan tal cual, así que un uuid en
49
+ * mayúsculas del spec produciría dos identidades para el mismo rol según el
50
+ * motor, y un id de binding que el propio driver no leería de vuelta. Es más
51
+ * estricto que la gramática de los uuids de holder/scope (esos son del
52
+ * consumidor, `[a-z0-9._-]{1,36}`): un id 1.x con slug (`app|editor`) no
53
+ * puede parecer un id 2.2 (`app|<uuid>`).
54
+ */
55
+ const CATALOG_UUID_FORMAT = /^[0-9a-f]{8}-[0-9a-f]{4}-[0-9a-f]{4}-[0-9a-f]{4}-[0-9a-f]{12}$/;
56
+ /** El uuid de un rol o permiso del catálogo (opcional en el spec): canónico y en minúsculas, o 422. */
57
+ export function assertCatalogUuid(kind, value) {
58
+ if (typeof value !== 'string' || !CATALOG_UUID_FORMAT.test(value)) {
59
+ throw new InvalidIdentityError(`UUID del ${kind} inválido: se esperaba un UUID canónico en minúsculas (8-4-4-4-12 hex) y llegó ${describe(value)}`);
60
+ }
61
+ }
62
+ /** Versión booleana para caminos de LECTURA (ids que vienen del backend): no lanza. */
63
+ export function isCatalogUuid(value) {
64
+ return typeof value === 'string' && CATALOG_UUID_FORMAT.test(value);
65
+ }
66
+ /**
67
+ * Un componente de identidad: MINÚSCULAS, dígitos, `_`, `.` y `-`. Lista
68
+ * blanca y no negra: lo que no está aquí no se serializa a ningún backend.
69
+ * Excluye por construcción `#`, `:`, `|`, `~`, `*`, `@`, espacios y control.
70
+ *
71
+ * Los TIPOS (de holder y de scope) van en minúsculas desde E4 (auditor H14):
72
+ * en un motor SQL con collation `*_ci` `Users` y `users` serían la misma fila
73
+ * y en FGA dos holders distintos. Los UUIDs también desde 2.5-B · K1
74
+ * (auditor 🔴 1): el árbol del consumidor (tipo `uuid` de PG, `char(36)`
75
+ * `*_ci` de MySQL) fundía `BBBB…` con `bbbb…`, la cadena resolvía con el
76
+ * alias y el deny —escrito canónico en `authz_*`, `utf8mb4_bin`— no casaba.
77
+ * La cadena canónica del resolutor cierra el alias por guiones; el alias por
78
+ * mayúsculas muere aquí, en la puerta, antes de tocar nada. Un id en
79
+ * mayúsculas del consumidor se pasa en minúsculas (`uuid.toLowerCase()`) en
80
+ * su borde: un UUID es el mismo id en cualquier caja.
81
+ */
82
+ const COMPONENT_FORMAT = /^[a-z0-9_.-]+$/;
83
+ const TYPE_FORMAT = COMPONENT_FORMAT;
84
+ function assertComponent(kind, value, maxLength, format = COMPONENT_FORMAT) {
85
+ if (typeof value !== 'string' || value.length === 0) {
86
+ throw new InvalidIdentityError(`${kind} inválido: se esperaba una cadena no vacía y llegó ${describe(value)}`);
87
+ }
88
+ if (value.length > maxLength) {
89
+ throw new InvalidIdentityError(`${kind} inválido: '${value}' supera los ${maxLength} caracteres de la columna`);
90
+ }
91
+ if (!format.test(value)) {
92
+ throw new InvalidIdentityError(`${kind} inválido: '${value}'. Solo se admiten minúsculas, dígitos y . _ - ` +
93
+ `(ni mayúsculas, '#', ':', '|', '~', '*', espacios ni caracteres de control)`);
94
+ }
95
+ }
96
+ function describe(value) {
97
+ if (value === undefined)
98
+ return 'undefined';
99
+ if (value === null)
100
+ return 'null';
101
+ if (typeof value === 'string')
102
+ return `'${value}'`;
103
+ return typeof value;
104
+ }
105
+ /** `SubjectRef` bien formado: type y uuid presentes, con formato y longitud. */
106
+ export function assertSubject(subject) {
107
+ if (!subject || typeof subject !== 'object') {
108
+ throw new InvalidIdentityError(`Holder inválido: llegó ${describe(subject)}`);
109
+ }
110
+ assertComponent('Tipo de holder', subject.type, IDENTITY_LIMITS.holderType, TYPE_FORMAT);
111
+ assertComponent(`UUID del holder '${subject.type}'`, subject.uuid, IDENTITY_LIMITS.uuid);
112
+ }
113
+ /**
114
+ * `ScopeRef` bien formado. `app` es la raíz y NO admite uuid (L0.10): un
115
+ * `{ app, 'X' }` no es "otro app", es una identidad que un driver colapsaría
116
+ * a la global. Fuera de `app` el uuid es obligatorio y no puede ser el
117
+ * centinela con el que `database` representa la raíz (L0.15).
118
+ */
119
+ export function assertScope(scope) {
120
+ if (!scope || typeof scope !== 'object') {
121
+ throw new InvalidIdentityError(`Scope inválido: llegó ${describe(scope)}`);
122
+ }
123
+ assertComponent('Tipo de scope', scope.type, IDENTITY_LIMITS.scopeType, TYPE_FORMAT);
124
+ if (scope.type === APP_SCOPE_TYPE) {
125
+ if (scope.uuid !== null) {
126
+ throw new InvalidIdentityError(`Scope inválido: el scope '${APP_SCOPE_TYPE}' es la raíz y no admite uuid ` +
127
+ `(llegó ${describe(scope.uuid)}). Usa APP_SCOPE.`);
128
+ }
129
+ return;
130
+ }
131
+ assertComponent(`UUID del scope '${scope.type}'`, scope.uuid, IDENTITY_LIMITS.uuid);
132
+ if (scope.uuid === SENTINEL_UUID) {
133
+ throw new InvalidIdentityError(`Scope inválido: '${SENTINEL_UUID}' está reservado para la raíz y no puede ` +
134
+ `identificar un scope de tipo '${scope.type}'`);
135
+ }
136
+ }
137
+ /** Tipo de scope suelto (el de `listRoleScopes`). */
138
+ export function assertScopeType(scopeType) {
139
+ assertComponent('Tipo de scope', scopeType, IDENTITY_LIMITS.scopeType, TYPE_FORMAT);
140
+ }
141
+ /**
142
+ * Longitud máxima del id de un objeto/holder de RELACIÓN (columna
143
+ * `varchar(64)` de `authz_relations`). Más ancha que `IDENTITY_LIMITS.uuid`
144
+ * (36): el `object.id` de ReBAC lo elige el consumidor y no tiene por qué ser
145
+ * un uuid.
146
+ */
147
+ export const RELATION_ID_LIMIT = 64;
148
+ /**
149
+ * **La gramática del id de un objeto de RELACIÓN** (R-16, Fase 4 · lote 4-7).
150
+ *
151
+ * Un `object.id` de relaciones va en la columna `varchar(64)` de
152
+ * `authz_relations` y, en el store compartido, en el id de objeto de FGA
153
+ * (`document:<partitionKey>|<object.id>`). El driver `database` ya lo validaba
154
+ * (`RELATION_ID_FORMAT`), pero ni el manager ni el driver `openfga` lo hacían:
155
+ * el `openfga` solo medía la LONGITUD. Un `object.id` con un `|` dentro
156
+ * (`'a|b'`) se ESCRIBÍA y `check` lo honraba, pero al parsear de vuelta (corte
157
+ * por el ÚLTIMO `|`) la partición salía mal, así que `listObjects` lo filtraba
158
+ * y `enumerateRelations` lo descartaba: una relación que concede y que NO se ve
159
+ * en la enumeración ni migra —pérdida SILENCIOSA en `reconcile`, justo lo que
160
+ * el driver promete que no pasa— y una divergencia con `database`, que lo
161
+ * rechaza con 422. Y los caracteres estructurales (`:`/`#`/espacio) salían como
162
+ * 503 mal clasificado, cuando por invariante 5 una entrada malformada es 422.
163
+ *
164
+ * Misma lista blanca que el resto de la identidad (`COMPONENT_FORMAT`):
165
+ * minúsculas, dígitos y `._-`; excluye `|`, `#`, `:`, `@`, `*`, `~`, espacios y
166
+ * control. La aplican el manager (una vez por llamada) Y cada driver (defensa
167
+ * en profundidad), como el resto de la gramática.
168
+ */
169
+ export function assertRelationId(kind, value) {
170
+ assertComponent(kind, value, RELATION_ID_LIMIT);
171
+ }
172
+ /** Versión booleana para caminos de LECTURA (ids que vienen del backend): no lanza. */
173
+ export function isValidRelationId(value) {
174
+ try {
175
+ assertRelationId('id de relación', value);
176
+ return true;
177
+ }
178
+ catch {
179
+ return false;
180
+ }
181
+ }
182
+ /* ── Clave de scope ─────────────────────────────────────────────────────── */
183
+ /**
184
+ * Clave textual de un scope: `app` para la raíz, `<tipo>|<uuid>` para el
185
+ * resto (≤ 57 caracteres). Es la MISMA en todo el paquete: el id de los
186
+ * bindings de FGA (`role_binding:<scopeKey>|<roleUuid>`) y el owner de un
187
+ * rol local (`authz_roles.owner_scope_key`, 3B · B1). `|` es el separador:
188
+ * como ningún componente lo admite (`assertScope`), dos scopes distintos no
189
+ * pueden producir la misma clave, y la clave reservada `global` (el catálogo
190
+ * del config) no la produce ningún scope — la raíz da `app` y todo lo demás
191
+ * lleva `|`. Un scope mal formado (`{app, uuid}`, centinela, mayúsculas) es
192
+ * 422 aquí, antes de serializarse a nada.
193
+ */
194
+ export function scopeKey(scope) {
195
+ assertScope(scope);
196
+ if (scope.type === APP_SCOPE_TYPE)
197
+ return APP_SCOPE_TYPE;
198
+ return `${scope.type}|${scope.uuid}`;
199
+ }
200
+ /** Un uuid canónico escrito SIN guiones: 32 dígitos hexadecimales. */
201
+ const DASHLESS_UUID = /^[0-9a-f]{32}$/;
202
+ /**
203
+ * **Las ORTOGRAFÍAS de un scope con las que hay que limpiar cuando ya no hay
204
+ * cadena con la que canonizar** (3b-2h · 🟠 3, auditor R2).
205
+ *
206
+ * La identidad de un scope es la canónica que devuelve el resolutor
207
+ * (invariante 17) y el paquete la usa para TODOS los hechos… mientras la fila
208
+ * del consumidor existe. `scopes.detached` es justo la operación que admite
209
+ * que ya NO exista (3F · S1: se purga igual, con el scope tal cual), y ahí no
210
+ * hay con qué canonizar: se usa la ortografía del llamante. Medido contra
211
+ * PostgreSQL: el tipo `uuid` funde `01a0…-…` con el mismo uuid SIN guiones,
212
+ * así que el `DELETE` del controlador acierta con el alias, el `detached`
213
+ * llega con el alias, `purgeScope` demuestra cero sobre un objeto que no
214
+ * existe y el scope REAL conserva su `parent` y su `binding`: en modo
215
+ * `facts`, **concede para siempre**. En lectura el mismo alias es
216
+ * fail-closed; en escritura era fail-OPEN.
217
+ *
218
+ * La salida es no elegir: una purga sin cadena limpia la ortografía del
219
+ * llamante **y** la canónica de la que puede ser alias. Solo se expande el
220
+ * alias SIN guiones (32 hex ⇒ también la forma 8-4-4-4-12), que es la única
221
+ * que un motor produce fundiendo —PostgreSQL canoniza CON guiones; el alias
222
+ * por mayúsculas ya muere en la puerta (`assertScope`)—; así el consumidor
223
+ * que guarda sus uuids con guiones (el caso normal) no paga NADA, y el que
224
+ * los guarda sin guiones sigue purgando su clave y, además, una que nunca
225
+ * tiene hechos. Normalizar en vez de expandir no vale: sin la fila no se sabe
226
+ * cuál de las dos es la buena, y elegir mal deja los hechos vivos, que es el
227
+ * fallo que se está cerrando.
228
+ */
229
+ export function scopeSpellings(scope) {
230
+ assertScope(scope);
231
+ const uuid = scope.uuid;
232
+ if (uuid === null || !DASHLESS_UUID.test(uuid))
233
+ return [scope];
234
+ const dashed = `${uuid.slice(0, 8)}-${uuid.slice(8, 12)}-${uuid.slice(12, 16)}-${uuid.slice(16, 20)}-${uuid.slice(20)}`;
235
+ return [scope, { type: scope.type, uuid: dashed }];
236
+ }
237
+ /**
238
+ * La inversa de `scopeKey` para claves que vienen de la BASE (el owner de un
239
+ * rol): `app` ⇒ la raíz; `<tipo>|<uuid>` ⇒ el scope; cualquier otra forma
240
+ * (incluida `global`, que no es un scope) ⇒ `null`. No lanza: es camino de
241
+ * lectura, y una clave que no es un scope simplemente no resuelve.
242
+ */
243
+ export function scopeFromKey(key) {
244
+ if (key === APP_SCOPE_TYPE)
245
+ return { type: APP_SCOPE_TYPE, uuid: null };
246
+ const parts = key.split('|');
247
+ if (parts.length !== 2)
248
+ return null;
249
+ const scope = { type: parts[0], uuid: parts[1] };
250
+ return isValidScope(scope) ? scope : null;
251
+ }
252
+ /* ── Slugs del catálogo ─────────────────────────────────────────────────── */
253
+ /**
254
+ * Gramática de un slug: minúsculas, dígitos y . _ - ; los permisos admiten UN
255
+ * `:` (`recurso:accion`), los roles ninguno.
256
+ */
257
+ const PERMISSION_FORMAT = /^[a-z0-9][a-z0-9_.-]*(:[a-z0-9][a-z0-9_.-]*)?$/;
258
+ const ROLE_FORMAT = /^[a-z0-9][a-z0-9_.-]*$/;
259
+ /**
260
+ * Nombres que el modelo FGA del modo `facts` usa como relaciones propias
261
+ * (`scope#parent`, `role_binding#assignee`, `scope#denied_<P>`…). Un
262
+ * permiso llamado `parent` invalidaría el modelo entero (S14): se rechaza en
263
+ * el núcleo, para ambos drivers, no el día de la migración.
264
+ */
265
+ export const RESERVED_SLUGS = new Set([
266
+ 'parent',
267
+ 'binding',
268
+ 'ancestor',
269
+ 'rooted',
270
+ 'role',
271
+ 'assignee',
272
+ 'denied',
273
+ ]);
274
+ /**
275
+ * Familias de relaciones derivadas del modelo (`can_<P>`, `denied_<P>`,
276
+ * `permits_<P>`). Un slug que EMPIECE por una de ellas colisiona con la
277
+ * relación derivada de otro permiso y el generador la colapsaría en silencio
278
+ * (S4: `can_docs_write` anulaba el deny de `docs:write`).
279
+ */
280
+ export const RESERVED_SLUG_PREFIXES = Object.freeze(['can_', 'denied_', 'permits_']);
281
+ /**
282
+ * **Los TIPOS de objeto que el modelo `facts` (y el `group` de relaciones) YA
283
+ * declaran** (Fase 4 · ⚪4). Un tipo de objeto de relaciones que se llame como
284
+ * uno de estos DUPLICARÍA un tipo del store compartido: `role_binding` sobre
285
+ * todo —si el driver de relaciones pudiera declararlo, podría componer el id
286
+ * de un binding real y `relate` sería una escalada a `roles.authorize`—. Vive
287
+ * en `identity.ts` (la gramática compartida) porque lo consumen DOS módulos
288
+ * que la frontera de pureza mantiene disjuntos: el generador del modelo
289
+ * (`src/drivers/openfga_facts.ts`, que no puede depender de `relations/`) y
290
+ * `defineRelationsConfig` (`src/relations/`, que no puede depender de
291
+ * `drivers/`). `deny_binding` sigue reservado aunque el modelo (c2r) ya no lo
292
+ * emita: un catálogo migrado del modo `resolver` no puede resucitarlo.
293
+ */
294
+ export const RESERVED_FACTS_TYPES = Object.freeze(new Set(['scope', 'role', 'role_binding', 'deny_binding', 'group']));
295
+ /**
296
+ * Longitud máxima de un slug. Un nombre de relación en FGA admite 50
297
+ * caracteres y el modelo deriva `permits_<slug>` (el prefijo más largo, 8):
298
+ * 42 es lo que cabe con cualquier prefijo. Es más estricto que la columna
299
+ * (100) a propósito: un catálogo legal en `database` tiene que ser publicable
300
+ * en `openfga` (S13), o el cambio de driver no es una migración de hechos.
301
+ */
302
+ export const MAX_SLUG_LENGTH = 50 - Math.max(...RESERVED_SLUG_PREFIXES.map((p) => p.length));
303
+ /** Slug de rol o permiso válido para AMBOS drivers (formato, longitud, reservados). */
304
+ export function assertValidSlug(kind, slug) {
305
+ if (typeof slug !== 'string' || slug.length === 0) {
306
+ throw new InvalidSlugError(`Slug de ${kind} inválido: se esperaba una cadena no vacía y llegó ${describe(slug)}`);
307
+ }
308
+ if (slug.length > MAX_SLUG_LENGTH) {
309
+ // 3b-2a · A4: se nombra el prefijo que lo desborda y la relación que
310
+ // saldría. La cota es del modo `facts`, y quien lee el error tiene que
311
+ // saber por qué 42 y no 100 (que es lo que admite la columna).
312
+ const longest = RESERVED_SLUG_PREFIXES.reduce((a, b) => (a.length >= b.length ? a : b));
313
+ throw new InvalidSlugError(`Slug de ${kind} inválido: '${slug}' supera los ${MAX_SLUG_LENGTH} caracteres ` +
314
+ `(50 de una relación FGA menos el prefijo derivado más largo, '${longest}': ` +
315
+ `'${longest}${slug}' serían ${longest.length + slug.length})`);
316
+ }
317
+ const format = kind === 'permiso' ? PERMISSION_FORMAT : ROLE_FORMAT;
318
+ if (!format.test(slug)) {
319
+ throw new InvalidSlugError(`Slug de ${kind} inválido: '${slug}'. Formato: minúsculas/dígitos/._-` +
320
+ (kind === 'permiso' ? " con ':' único opcional (recurso:accion)" : ' (sin ":")') +
321
+ "; '~', '|', '#', '*' y espacios están prohibidos");
322
+ }
323
+ if (RESERVED_SLUGS.has(slug)) {
324
+ throw new InvalidSlugError(`Slug de ${kind} inválido: '${slug}' es un nombre reservado del modelo ` +
325
+ `(${[...RESERVED_SLUGS].join(', ')})`);
326
+ }
327
+ const family = RESERVED_SLUG_PREFIXES.find((prefix) => slug.startsWith(prefix));
328
+ if (family) {
329
+ throw new InvalidSlugError(`Slug de ${kind} inválido: '${slug}' empieza por '${family}', prefijo reservado ` +
330
+ `de las relaciones derivadas (${RESERVED_SLUG_PREFIXES.join(', ')})`);
331
+ }
332
+ }
333
+ /**
334
+ * Cómo se proyecta un slug a un nombre de relación FGA (`:` → `_`). Dos slugs
335
+ * distintos con la misma proyección (`docs:write` / `docs_write`) serían UNA
336
+ * relación: el catálogo los rechaza juntos (L0.8a).
337
+ */
338
+ export function slugAsRelation(slug) {
339
+ return slug.replaceAll(':', '_');
340
+ }
341
+ /** Ningún par de slugs del conjunto colisiona tras proyectarse a relación. */
342
+ export function assertNoSlugCollisions(kind, slugs) {
343
+ const seen = new Map();
344
+ for (const slug of slugs) {
345
+ const relation = slugAsRelation(slug);
346
+ const other = seen.get(relation);
347
+ if (other !== undefined && other !== slug) {
348
+ throw new InvalidSlugError(`Slugs de ${kind} en colisión: '${other}' y '${slug}' se proyectan a la misma ` +
349
+ `relación '${relation}' (':' y '_' son equivalentes en el modelo)`);
350
+ }
351
+ seen.set(relation, slug);
352
+ }
353
+ }
354
+ /** Versiones booleanas para caminos de LECTURA que no deben lanzar (ids que vienen del backend). */
355
+ export function isValidScope(scope) {
356
+ try {
357
+ assertScope(scope);
358
+ return true;
359
+ }
360
+ catch {
361
+ return false;
362
+ }
363
+ }
364
+ export function isValidScopeType(scopeType) {
365
+ try {
366
+ assertScopeType(scopeType);
367
+ return true;
368
+ }
369
+ catch {
370
+ return false;
371
+ }
372
+ }
373
+ export function isValidSlug(kind, slug) {
374
+ try {
375
+ assertValidSlug(kind, slug);
376
+ return true;
377
+ }
378
+ catch {
379
+ return false;
380
+ }
381
+ }
382
+ /**
383
+ * La pregunta de `hasRole`, validada: string ⇒ `{ slug }`; objeto ⇒
384
+ * `{ slug, scopeType }` (ambos con la gramática del motor).
385
+ */
386
+ export function normalizeRoleQuery(role) {
387
+ if (typeof role === 'string') {
388
+ assertValidSlug('rol', role);
389
+ return { slug: role };
390
+ }
391
+ if (!role || typeof role !== 'object') {
392
+ throw new InvalidIdentityError(`Rol inválido: llegó ${describe(role)}`);
393
+ }
394
+ // 3D · M1(c): `{ uuid }` es la forma EXACTA (sin ambigüedad posible). No se
395
+ // mezcla con `{ slug, scopeType }`: la pregunta es por identidad o por
396
+ // nombre, nunca por las dos a la vez (un `{ uuid, slug }` que no casaran
397
+ // sería una pregunta con dos respuestas).
398
+ if ('uuid' in role) {
399
+ const query = role;
400
+ if (query.slug !== undefined || query.scopeType !== undefined) {
401
+ throw new InvalidIdentityError(`Rol inválido: { uuid } es la forma exacta y no se combina con 'slug'/'scopeType' (llegó ${describe(role)})`);
402
+ }
403
+ assertCatalogUuid('rol', query.uuid);
404
+ return { uuid: query.uuid };
405
+ }
406
+ assertValidSlug('rol', role.slug);
407
+ assertScopeType(role.scopeType);
408
+ return { slug: role.slug, scopeType: role.scopeType };
409
+ }
410
+ /**
411
+ * Las claves de la cadena desde cada nivel hacia la raíz (3B · B2; movida
412
+ * aquí en 3D · N5 para que exista UNA sola codificación de clave de scope):
413
+ * `keysFrom[i]` = `chain.slice(i).map(scopeKey)`. Un rol es visible en el
414
+ * nivel `i` si es global o su owner está en `keysFrom[i]` — el owner tiene
415
+ * que ser ancestro-o-igual del scope de la ASIGNACIÓN, no de la pregunta.
416
+ */
417
+ export function chainKeysFrom(chain) {
418
+ const keys = chain.map(scopeKey);
419
+ return keys.map((_, i) => keys.slice(i));
420
+ }
421
+ /* ── Punto de entrada único ─────────────────────────────────────────────── */
422
+ /**
423
+ * `expiresAt` de un `grant`, en sus tres estados legales: omitido, `null` o
424
+ * una `Date` válida. Una cadena, un número o un `Invalid Date` no son una
425
+ * caducidad: un driver lanzaba un TypeError al serializar y el otro persistía
426
+ * basura (D7). Se rechaza como identidad mal formada (422).
427
+ */
428
+ export function assertExpiresAt(value) {
429
+ if (value === undefined || value === null)
430
+ return;
431
+ if (!(value instanceof Date) || Number.isNaN(value.getTime())) {
432
+ throw new InvalidIdentityError(`expiresAt inválido: se esperaba una Date válida, null (sin caducidad) u omitido ` +
433
+ `(preservar la vigente) y llegó ${value instanceof Date ? 'Invalid Date' : describe(value)}`);
434
+ }
435
+ }
436
+ /**
437
+ * Valida en un solo paso los componentes que recibe una operación. Se llama
438
+ * ANTES de tocar catálogo, árbol o backend: una pregunta mal formada no
439
+ * cuesta una consulta ni deja rastro.
440
+ */
441
+ export function assertIdentity(parts) {
442
+ if ('subject' in parts)
443
+ assertSubject(parts.subject);
444
+ if ('scope' in parts)
445
+ assertScope(parts.scope);
446
+ if ('scopeType' in parts)
447
+ assertScopeType(parts.scopeType);
448
+ if ('role' in parts)
449
+ normalizeRoleQuery(parts.role);
450
+ if ('roleSlug' in parts)
451
+ assertValidSlug('rol', parts.roleSlug);
452
+ if ('permission' in parts)
453
+ assertValidSlug('permiso', parts.permission);
454
+ if ('expiresAt' in parts)
455
+ assertExpiresAt(parts.expiresAt);
456
+ }
457
+ //# sourceMappingURL=identity.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"identity.js","sourceRoot":"","sources":["../../src/identity.ts"],"names":[],"mappings":"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"}