@jantstack/adonis-authz 2.0.0-alpha.1 → 2.4.0-alpha.2

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 (214) hide show
  1. package/README.md +693 -36
  2. package/build/commands/authz_catalog_diff.js +1 -1
  3. package/build/commands/authz_catalog_diff.js.map +1 -1
  4. package/build/commands/authz_catalog_prune_orphans.d.ts +78 -0
  5. package/build/commands/authz_catalog_prune_orphans.d.ts.map +1 -0
  6. package/build/commands/authz_catalog_prune_orphans.js +136 -0
  7. package/build/commands/authz_catalog_prune_orphans.js.map +1 -0
  8. package/build/commands/authz_catalog_sync.d.ts +17 -0
  9. package/build/commands/authz_catalog_sync.d.ts.map +1 -1
  10. package/build/commands/authz_catalog_sync.js +27 -4
  11. package/build/commands/authz_catalog_sync.js.map +1 -1
  12. package/build/commands/authz_freeze.d.ts +44 -0
  13. package/build/commands/authz_freeze.d.ts.map +1 -0
  14. package/build/commands/authz_freeze.js +95 -0
  15. package/build/commands/authz_freeze.js.map +1 -0
  16. package/build/commands/authz_reconcile.d.ts +102 -0
  17. package/build/commands/authz_reconcile.d.ts.map +1 -0
  18. package/build/commands/authz_reconcile.js +294 -0
  19. package/build/commands/authz_reconcile.js.map +1 -0
  20. package/build/commands/authz_relations_reconcile.d.ts +97 -0
  21. package/build/commands/authz_relations_reconcile.d.ts.map +1 -0
  22. package/build/commands/authz_relations_reconcile.js +313 -0
  23. package/build/commands/authz_relations_reconcile.js.map +1 -0
  24. package/build/commands/authz_scopes_relay.d.ts +47 -0
  25. package/build/commands/authz_scopes_relay.d.ts.map +1 -0
  26. package/build/commands/authz_scopes_relay.js +141 -0
  27. package/build/commands/authz_scopes_relay.js.map +1 -0
  28. package/build/commands/authz_unfreeze.d.ts +37 -0
  29. package/build/commands/authz_unfreeze.d.ts.map +1 -0
  30. package/build/commands/authz_unfreeze.js +92 -0
  31. package/build/commands/authz_unfreeze.js.map +1 -0
  32. package/build/commands/main.d.ts +6 -1
  33. package/build/commands/main.d.ts.map +1 -1
  34. package/build/commands/main.js +6 -1
  35. package/build/commands/main.js.map +1 -1
  36. package/build/commands/openfga_provision.d.ts +46 -4
  37. package/build/commands/openfga_provision.d.ts.map +1 -1
  38. package/build/commands/openfga_provision.js +90 -7
  39. package/build/commands/openfga_provision.js.map +1 -1
  40. package/build/configure.d.ts +11 -0
  41. package/build/configure.d.ts.map +1 -1
  42. package/build/configure.js +37 -1
  43. package/build/configure.js.map +1 -1
  44. package/build/index.d.ts +50 -10
  45. package/build/index.d.ts.map +1 -1
  46. package/build/index.js +45 -6
  47. package/build/index.js.map +1 -1
  48. package/build/providers/authz_provider.d.ts +26 -2
  49. package/build/providers/authz_provider.d.ts.map +1 -1
  50. package/build/providers/authz_provider.js +55 -2
  51. package/build/providers/authz_provider.js.map +1 -1
  52. package/build/services/relations.d.ts +14 -0
  53. package/build/services/relations.d.ts.map +1 -0
  54. package/build/services/relations.js +17 -0
  55. package/build/services/relations.js.map +1 -0
  56. package/build/src/{catalog.d.ts → catalog/catalog.d.ts} +41 -2
  57. package/build/src/catalog/catalog.d.ts.map +1 -0
  58. package/build/src/{catalog.js → catalog/catalog.js} +120 -14
  59. package/build/src/catalog/catalog.js.map +1 -0
  60. package/build/src/{catalog_cache.d.ts → catalog/catalog_cache.d.ts} +46 -22
  61. package/build/src/catalog/catalog_cache.d.ts.map +1 -0
  62. package/build/src/{catalog_cache.js → catalog/catalog_cache.js} +53 -43
  63. package/build/src/catalog/catalog_cache.js.map +1 -0
  64. package/build/src/define_config.d.ts +137 -3
  65. package/build/src/define_config.d.ts.map +1 -1
  66. package/build/src/define_config.js.map +1 -1
  67. package/build/src/drivers/database_driver.d.ts +128 -7
  68. package/build/src/drivers/database_driver.d.ts.map +1 -1
  69. package/build/src/drivers/database_driver.js +510 -24
  70. package/build/src/drivers/database_driver.js.map +1 -1
  71. package/build/src/drivers/database_relations_driver.d.ts +113 -0
  72. package/build/src/drivers/database_relations_driver.d.ts.map +1 -0
  73. package/build/src/drivers/database_relations_driver.js +679 -0
  74. package/build/src/drivers/database_relations_driver.js.map +1 -0
  75. package/build/src/drivers/openfga_driver.d.ts +729 -122
  76. package/build/src/drivers/openfga_driver.d.ts.map +1 -1
  77. package/build/src/drivers/openfga_driver.js +2083 -476
  78. package/build/src/drivers/openfga_driver.js.map +1 -1
  79. package/build/src/drivers/openfga_facts.d.ts +384 -0
  80. package/build/src/drivers/openfga_facts.d.ts.map +1 -0
  81. package/build/src/drivers/openfga_facts.js +836 -0
  82. package/build/src/drivers/openfga_facts.js.map +1 -0
  83. package/build/src/drivers/openfga_relations_driver.d.ts +141 -0
  84. package/build/src/drivers/openfga_relations_driver.d.ts.map +1 -0
  85. package/build/src/drivers/openfga_relations_driver.js +590 -0
  86. package/build/src/drivers/openfga_relations_driver.js.map +1 -0
  87. package/build/src/errors.d.ts +290 -5
  88. package/build/src/errors.d.ts.map +1 -1
  89. package/build/src/errors.js +296 -7
  90. package/build/src/errors.js.map +1 -1
  91. package/build/src/freeze.d.ts +141 -0
  92. package/build/src/freeze.d.ts.map +1 -0
  93. package/build/src/freeze.js +217 -0
  94. package/build/src/freeze.js.map +1 -0
  95. package/build/src/http/app_access_middleware.d.ts.map +1 -0
  96. package/build/src/http/app_access_middleware.js.map +1 -0
  97. package/build/src/http/resource_access_middleware.d.ts +105 -0
  98. package/build/src/http/resource_access_middleware.d.ts.map +1 -0
  99. package/build/src/http/resource_access_middleware.js +81 -0
  100. package/build/src/http/resource_access_middleware.js.map +1 -0
  101. package/build/src/identity.d.ts +74 -1
  102. package/build/src/identity.d.ts.map +1 -1
  103. package/build/src/identity.js +100 -2
  104. package/build/src/identity.js.map +1 -1
  105. package/build/src/manager.d.ts +330 -4
  106. package/build/src/manager.d.ts.map +1 -1
  107. package/build/src/manager.js +1285 -188
  108. package/build/src/manager.js.map +1 -1
  109. package/build/src/models/authz_assignment.d.ts +7 -7
  110. package/build/src/models/authz_assignment.d.ts.map +1 -1
  111. package/build/src/models/authz_deny.d.ts +7 -7
  112. package/build/src/models/authz_deny.d.ts.map +1 -1
  113. package/build/src/models/authz_permission.d.ts +7 -7
  114. package/build/src/models/authz_permission.d.ts.map +1 -1
  115. package/build/src/models/authz_role.d.ts +7 -7
  116. package/build/src/models/authz_role.d.ts.map +1 -1
  117. package/build/src/models/authz_role_permission.d.ts +7 -7
  118. package/build/src/models/authz_role_permission.d.ts.map +1 -1
  119. package/build/src/openfga.d.ts +18 -2
  120. package/build/src/openfga.d.ts.map +1 -1
  121. package/build/src/openfga.js +15 -1
  122. package/build/src/openfga.js.map +1 -1
  123. package/build/src/reconcile.d.ts +37 -0
  124. package/build/src/reconcile.d.ts.map +1 -0
  125. package/build/src/reconcile.js +69 -0
  126. package/build/src/reconcile.js.map +1 -0
  127. package/build/src/relation_partition_trigger.d.ts +8 -0
  128. package/build/src/relation_partition_trigger.d.ts.map +1 -0
  129. package/build/src/relation_partition_trigger.js +93 -0
  130. package/build/src/relation_partition_trigger.js.map +1 -0
  131. package/build/src/relations/define_relations_config.d.ts +75 -0
  132. package/build/src/relations/define_relations_config.d.ts.map +1 -0
  133. package/build/src/relations/define_relations_config.js +173 -0
  134. package/build/src/relations/define_relations_config.js.map +1 -0
  135. package/build/src/relations/manager.d.ts +60 -0
  136. package/build/src/relations/manager.d.ts.map +1 -0
  137. package/build/src/relations/manager.js +213 -0
  138. package/build/src/relations/manager.js.map +1 -0
  139. package/build/src/relations/reconcile.d.ts +111 -0
  140. package/build/src/relations/reconcile.d.ts.map +1 -0
  141. package/build/src/relations/reconcile.js +200 -0
  142. package/build/src/relations/reconcile.js.map +1 -0
  143. package/build/src/relations_config_store.d.ts +22 -0
  144. package/build/src/relations_config_store.d.ts.map +1 -0
  145. package/build/src/relations_config_store.js +74 -0
  146. package/build/src/relations_config_store.js.map +1 -0
  147. package/build/src/scope_outbox.d.ts +69 -0
  148. package/build/src/scope_outbox.d.ts.map +1 -0
  149. package/build/src/scope_outbox.js +298 -0
  150. package/build/src/scope_outbox.js.map +1 -0
  151. package/build/src/{drivers → shared}/backend_guard.d.ts +42 -0
  152. package/build/src/shared/backend_guard.d.ts.map +1 -0
  153. package/build/src/{drivers → shared}/backend_guard.js +78 -1
  154. package/build/src/shared/backend_guard.js.map +1 -0
  155. package/build/src/shared/sql_expiry.d.ts.map +1 -0
  156. package/build/src/shared/sql_expiry.js.map +1 -0
  157. package/build/src/shared/transaction_guard.d.ts +50 -0
  158. package/build/src/shared/transaction_guard.d.ts.map +1 -0
  159. package/build/src/shared/transaction_guard.js +60 -0
  160. package/build/src/shared/transaction_guard.js.map +1 -0
  161. package/build/src/sql_descendants.d.ts +47 -1
  162. package/build/src/sql_descendants.d.ts.map +1 -1
  163. package/build/src/sql_descendants.js +75 -1
  164. package/build/src/sql_descendants.js.map +1 -1
  165. package/build/src/testing/contract.d.ts +129 -4
  166. package/build/src/testing/contract.d.ts.map +1 -1
  167. package/build/src/testing/contract.js +912 -177
  168. package/build/src/testing/contract.js.map +1 -1
  169. package/build/src/testing/main.d.ts +8 -2
  170. package/build/src/testing/main.d.ts.map +1 -1
  171. package/build/src/testing/main.js +4 -1
  172. package/build/src/testing/main.js.map +1 -1
  173. package/build/src/testing/migration_contract.d.ts +284 -0
  174. package/build/src/testing/migration_contract.d.ts.map +1 -0
  175. package/build/src/testing/migration_contract.js +586 -0
  176. package/build/src/testing/migration_contract.js.map +1 -0
  177. package/build/src/testing/relations_contract.d.ts +73 -0
  178. package/build/src/testing/relations_contract.d.ts.map +1 -0
  179. package/build/src/testing/relations_contract.js +1069 -0
  180. package/build/src/testing/relations_contract.js.map +1 -0
  181. package/build/src/testing/relations_reconcile_contract.d.ts +24 -0
  182. package/build/src/testing/relations_reconcile_contract.d.ts.map +1 -0
  183. package/build/src/testing/relations_reconcile_contract.js +220 -0
  184. package/build/src/testing/relations_reconcile_contract.js.map +1 -0
  185. package/build/src/traits/authz_scopes.js +1 -1
  186. package/build/src/traits/authz_scopes.js.map +1 -1
  187. package/build/src/traits/has_uuid.d.ts +8 -8
  188. package/build/src/traits/has_uuid.d.ts.map +1 -1
  189. package/build/src/types.d.ts +1053 -83
  190. package/build/src/types.d.ts.map +1 -1
  191. package/build/src/types.js +10 -0
  192. package/build/src/types.js.map +1 -1
  193. package/build/stubs/config/authorization.stub +104 -4
  194. package/build/stubs/migration.stub +136 -0
  195. package/build/stubs/scopes_outbox_migration.stub +57 -0
  196. package/package.json +4 -2
  197. package/build/commands/openfga_import.d.ts +0 -34
  198. package/build/commands/openfga_import.d.ts.map +0 -1
  199. package/build/commands/openfga_import.js +0 -97
  200. package/build/commands/openfga_import.js.map +0 -1
  201. package/build/src/catalog.d.ts.map +0 -1
  202. package/build/src/catalog.js.map +0 -1
  203. package/build/src/catalog_cache.d.ts.map +0 -1
  204. package/build/src/catalog_cache.js.map +0 -1
  205. package/build/src/drivers/backend_guard.d.ts.map +0 -1
  206. package/build/src/drivers/backend_guard.js.map +0 -1
  207. package/build/src/drivers/sql_expiry.d.ts.map +0 -1
  208. package/build/src/drivers/sql_expiry.js.map +0 -1
  209. package/build/src/middleware/app_access_middleware.d.ts.map +0 -1
  210. package/build/src/middleware/app_access_middleware.js.map +0 -1
  211. /package/build/src/{middleware → http}/app_access_middleware.d.ts +0 -0
  212. /package/build/src/{middleware → http}/app_access_middleware.js +0 -0
  213. /package/build/src/{drivers → shared}/sql_expiry.d.ts +0 -0
  214. /package/build/src/{drivers → shared}/sql_expiry.js +0 -0
@@ -0,0 +1,384 @@
1
+ import type { CatalogProjectionRole, HolderTypeMap } from '../types.js';
2
+ /**
3
+ * `holderTypes` tiene que ser INYECTIVO. Si dos morph names caen en el mismo
4
+ * tipo FGA, para el store son un solo holder: un grant a `users:U` autoriza a
5
+ * `integrations:U`, `listSubjects` devuelve el morph equivocado y un revoke
6
+ * borra al otro (invariante 4, L0.2). El generador del modelo lo "sabía"
7
+ * (deduplicaba con un Set) y publicaba sin quejarse: ahora lanza aquí, al
8
+ * construir el driver y al generar cualquiera de los dos modelos, antes de
9
+ * tocar nada.
10
+ */
11
+ export declare function assertHolderTypes(holderTypes: HolderTypeMap): void;
12
+ /**
13
+ * Longitud máxima de un nombre de relación en FGA. `MAX_SLUG_LENGTH` (42) es
14
+ * justo esto menos el prefijo derivado más largo (`permits_`), así que un
15
+ * slug legal siempre cabe: la comprobación de aquí es la red del generador,
16
+ * que también lo llaman herramientas con listas de permisos que no pasaron
17
+ * por `assertValidSlug` (una base sincronizada por otra versión, un driver
18
+ * de terceros).
19
+ */
20
+ export declare const FGA_MAX_RELATION_NAME = 50;
21
+ /**
22
+ * Longitud máxima del id de un objeto FGA. Con la gramática publicada nada
23
+ * se acerca (`role_binding:<tipo>|<uuid>|<roleUuid>` son 107 como mucho),
24
+ * pero el id se compone de partes que vienen de la BASE: un catálogo
25
+ * corrupto no puede fabricar un objeto que el store no pueda leer de vuelta.
26
+ */
27
+ export declare const FGA_MAX_OBJECT_ID = 256;
28
+ /**
29
+ * Techo del authorization model (default de
30
+ * `OPENFGA_MAX_AUTHORIZATION_MODEL_SIZE_IN_BYTES`). **El techo son BYTES; el
31
+ * número de permisos que caben NO es una propiedad del modelo** (3b-4 · C3):
32
+ * depende de cuántos holder types declaras, de cuánto miden sus NOMBRES en el
33
+ * modelo y de cuánto miden los slugs de tus permisos. Medido con
34
+ * `factsModelBytes` —que cuenta los mismos bytes que el servidor, contrastado
35
+ * contra un `:8101` real— y fijado por un caso (`3b-4 · C3`):
36
+ *
37
+ * | catálogo | permisos que caben |
38
+ * |---|---|
39
+ * | 1 holder type, slugs `p0`…`pN` | **800** |
40
+ * | 3 holder types (`user`/`admin`/`integration`), slugs `p0`…`pN` | **691** |
41
+ * | 1 holder type, slugs `docs:readN` | **576** |
42
+ * | 3 holder types, slugs `recursoN:accion` (REALISTAS) | **447** |
43
+ * | 3 holder types, slugs de 40 caracteres | **272** |
44
+ *
45
+ * O sea: el «≈691» que se publicó es la cifra de un catálogo cuyos permisos se
46
+ * llaman `p0`, `p1`, `p2`…; **con nombres de permiso normales el techo está en
47
+ * ~450**. Y los mismos tres holder types con nombres más cortos (`bot` en vez
48
+ * de `integration`) dan 721: no basta con decir «tres holder types».
49
+ *
50
+ * Se valida en `syncAuthzCatalog` ANTES de escribir el catálogo: un catálogo
51
+ * que no se puede publicar no se escribe a medias en un entorno y entero en
52
+ * otro. El gate por bytes es exacto y salta antes de escribir, así que
53
+ * equivocarse con la cifra derivada no concede nada: solo sorprende.
54
+ */
55
+ export declare const FACTS_MODEL_MAX_BYTES = 262144;
56
+ /**
57
+ * **Profundidad máxima de cadena que el modelo (c2) resuelve** (3b-2e · E5),
58
+ * MEDIDA contra OpenFGA v1.19 con el `--resolve-node-limit` por defecto (25).
59
+ * Con el grant en la RAÍZ y el `Check` a profundidad creciente, 25
60
+ * repeticiones por punto:
61
+ *
62
+ * | saltos `parent` | `can_<P>` |
63
+ * |---|---|
64
+ * | 21 | 25/25 resuelve |
65
+ * | **22** | **25/25 resuelve** ← la cota que se declara |
66
+ * | 23 | resuelve casi siempre y **falla entre un 4 % y un 26 %** de las veces según la carga — el borde NO es nítido |
67
+ * | 24 | 0/25: siempre falla |
68
+ *
69
+ * (Remedido en 3b-4 · C4 sobre 50 hojas a la misma profundidad: a 22, 200 de
70
+ * 200 resuelven en cuatro lotes; a 23, entre 6 y 13 errores por lote de 50, y
71
+ * 15 de 100 en checks sueltos; a 24, 100 de 100 fallan.)
72
+ *
73
+ * Las otras dos ramas del modelo llegan más lejos (`denied_<P>` hasta 25,
74
+ * `ancestor` hasta 26): manda la más baja, y es `can_<P>` porque es una resta
75
+ * (`difference`) sobre una unión con DOS TTU (`binding` y `parent`), o sea dos
76
+ * reescrituras más que las otras.
77
+ *
78
+ * **Lo importante del hallazgo no es el número, es que el borde es
79
+ * PROBABILÍSTICO**: a 23 saltos la misma pregunta responde casi siempre y
80
+ * falla de vez en cuando (el presupuesto de nodos se consume de forma no
81
+ * determinista al resolver la unión). Por eso se declara **22**, que es la
82
+ * profundidad que resuelve SIEMPRE, y no el primer valor que falló. Un caso
83
+ * de la suite apoyado en 23 habría sido flaky en el artefacto publicado —la
84
+ * misma lección que 3G · Y1—, y de hecho lo fue una vez antes de medirlo.
85
+ *
86
+ * **Y por eso la constante se clava con REPETICIONES, no con una tirada**
87
+ * (3b-4 · C4): el par de casos original —positivo en la cota, negativo en la
88
+ * cota + 2— sujetaba el intervalo [22, 23] y no el 22 (con la constante a 23
89
+ * la suite seguía verde 3 corridas de 3, tester Fase 3b · M12b). El caso que
90
+ * lo cierra hace **500 resoluciones por lado** (10 lotes de 50 con
91
+ * `authorizeMany`): en la cota tienen que resolver las 500, y un salto más
92
+ * tiene que fallar al menos una vez. Con la tasa de fallo más baja jamás
93
+ * medida (4 %) un verde falso es 0,96^500 ≈ 1e-9.
94
+ *
95
+ * Los «~23» que citaba el panel (riesgo S9) eran de un modelo MÁS SIMPLE y
96
+ * estaban sin medir sobre (c2).
97
+ *
98
+ * Pasado el techo el servidor responde 400 («resolution required too many
99
+ * rewrite rules») y el paquete lo propaga como 503, **nunca como un `false`**
100
+ * (invariante 5): es fail-closed, pero es un DoS al alcance de quien pueda
101
+ * crear sub-scopes anidados, y `database` no tiene ese techo — el mismo árbol
102
+ * es legal en un driver y una caída en el otro. Sube
103
+ * `OPENFGA_RESOLVE_NODE_LIMIT` en el servidor si tu árbol es más profundo.
104
+ */
105
+ export declare const FACTS_MAX_RESOLVE_DEPTH = 22;
106
+ /** Tope de checks por `batchCheck` en OpenFGA (el driver trocea en lotes de este tamaño). */
107
+ export declare const FGA_MAX_BATCH_CHECK = 50;
108
+ /** Fracción del techo a partir de la cual se avisa (cruce 9: "aviso al 80 %"). */
109
+ export declare const FACTS_MODEL_WARN_RATIO = 0.8;
110
+ /** El tipo FGA cuyo id es el uuid del rol del catálogo. */
111
+ export declare const FACTS_ROLE_TYPE = "role";
112
+ /** Prefijo de la familia que materializa el catálogo (`role:<uuid>#permits_<P>`). */
113
+ export declare const FACTS_PERMITS_PREFIX = "permits_";
114
+ /**
115
+ * **La relación de (c2r)**: «desde este scope se llega a la raíz `app`»
116
+ * (3b-2i). Es una relación PROPIA del modelo, como `parent` o `ancestor`, y
117
+ * la única que se escribe una vez por STORE en vez de por hecho: el marcador
118
+ * de raíz (`factsRootTuples`).
119
+ */
120
+ export declare const FACTS_ROOTED_RELATION = "rooted";
121
+ /**
122
+ * La condición de caducidad del modelo (`current_time < valid_until`): la de
123
+ * `role_binding#assignee` desde el modo `facts`, y desde R-15 también la de
124
+ * cada sujeto de una relación ReBAC (`document#viewer`, `group#member`…).
125
+ */
126
+ export declare const FACTS_EXPIRY_CONDITION = "not_expired";
127
+ /** Las CUATRO familias de (c2) para un permiso: `<P>`, `can_<P>`, `denied_<P>`, `permits_<P>`. */
128
+ export interface FactsRelations {
129
+ permission: string;
130
+ /** `<P>` en `role_binding` y en `scope`. */
131
+ base: string;
132
+ /** `can_<P>`: lo que responde `authorize`. */
133
+ can: string;
134
+ /** `denied_<P>`: el deny explícito, heredado hacia abajo. */
135
+ denied: string;
136
+ /** `permits_<P>`: la proyección del catálogo (qué permisos vincula un rol). */
137
+ permits: string;
138
+ }
139
+ /** Las cuatro relaciones que un permiso genera, sin validar nada. */
140
+ export declare function factsRelationsOf(permission: string): FactsRelations;
141
+ /**
142
+ * **S4, bloqueante del juez.** Con CUATRO familias, dos permisos distintos
143
+ * pueden generar el mismo nombre de relación: `can_x` sale del permiso
144
+ * `can_x` y también del permiso `x`. El generador de antes las colapsaba en
145
+ * silencio y el modelo publicado anulaba un deny (el auditor lo reprodujo de
146
+ * punta a punta con `allowed: true`). Se detecta con un `Map` nombre→origen
147
+ * y se LANZA: nunca se escribe un modelo ambiguo.
148
+ *
149
+ * Es un espacio de nombres plano a propósito (aunque las relaciones vivan en
150
+ * tipos distintos): las familias tienen prefijos disjuntos, así que dos
151
+ * permisos legales jamás chocan aquí, y lo que sí choca es exactamente lo que
152
+ * `RESERVED_SLUGS`/`RESERVED_SLUG_PREFIXES` prohíben en el núcleo.
153
+ */
154
+ export declare function factsRelationMap(permissions: readonly string[]): FactsRelations[];
155
+ /**
156
+ * El authorization model del modo `facts` en el JSON del API de FGA. El mismo
157
+ * `holderTypes` y el mismo conjunto de permisos deben usarse al construir el
158
+ * driver: si difieren, los checks no encuentran las tuplas y `permits_<P>` de
159
+ * un permiso que el modelo no declara es un 400 del servidor.
160
+ *
161
+ * `permissions` son los slugs del CATÁLOGO (`authz_permissions`), que sigue
162
+ * siendo propiedad local: esto es una proyección derivada y reconstruible, no
163
+ * una fuente de verdad (regla del catálogo reescrita, cruce 7 del panel).
164
+ */
165
+ export declare function openFgaFactsModel(holderTypeMap: HolderTypeMap, permissions: readonly string[], relationsConfig?: FactsRelationsConfig): any;
166
+ /**
167
+ * Los bytes que el servidor contará para este modelo. Incluye el id (un ULID
168
+ * de 26 caracteres) porque el servidor lo asigna ANTES de medir: sin él la
169
+ * cuenta se queda 28 bytes corta.
170
+ */
171
+ export declare function factsModelBytes(model: any): number;
172
+ /**
173
+ * ¿Este catálogo se puede PUBLICAR como modelo `facts`? Se responde ANTES de
174
+ * escribir nada (`syncAuthzCatalog`), no en runtime: un catálogo que rebasa
175
+ * el techo del servidor entra en la base y deja el store sin poder
176
+ * regenerarse, que es la avería silenciosa.
177
+ *
178
+ * Pasado el 80 % del techo se AVISA por el canal de log del driver: quien
179
+ * declara permisos a ese ritmo tiene que enterarse antes de chocar, no el día
180
+ * del deploy que no arranca.
181
+ */
182
+ export declare function assertFactsModelPublishable(holderTypeMap: HolderTypeMap, permissions: readonly string[], warn?: (message: string) => void, relationsConfig?: FactsRelationsConfig): {
183
+ bytes: number;
184
+ permissions: number;
185
+ };
186
+ /** Cota de id de objeto (A4): lo que el store no podría leer de vuelta no se escribe. */
187
+ export declare function assertFgaObjectId(kind: string, id: string): void;
188
+ /** Una tupla de la proyección: `role:<uuid>#permits_<P>@<holder>:*`. */
189
+ export interface FactsCatalogTuple {
190
+ user: string;
191
+ relation: string;
192
+ object: string;
193
+ }
194
+ /**
195
+ * Las tuplas que materializan los vínculos rol→permiso del catálogo. Una por
196
+ * (rol, permiso, holder): el comodín de USUARIO es lo que hace (c2) barato
197
+ * —quitar un permiso de un rol son `holders` deletes en un solo `Write`, no
198
+ * una escritura por scope—.
199
+ *
200
+ * NO es catálogo: es una proyección derivada, reconstruible desde `authz_*`,
201
+ * que ningún camino de lectura del driver consulta para responder qué
202
+ * permisos tiene un rol (cruce 7 del panel; A6).
203
+ */
204
+ export declare function factsCatalogTuples(roles: readonly CatalogProjectionRole[], holderTypeMap: HolderTypeMap): FactsCatalogTuple[];
205
+ /** Clave textual de una tupla de la proyección, para comparar conjuntos. */
206
+ export declare function factsTupleId(tuple: FactsCatalogTuple): string;
207
+ /** El tipo FGA cuyo id es la `scopeKey` del paquete (`app` o `<tipo>|<uuid>`). */
208
+ export declare const FACTS_SCOPE_TYPE = "scope";
209
+ /** La arista del árbol: `scope:<hijo>#parent@scope:<padre>` (una por nodo). */
210
+ export declare const FACTS_PARENT_RELATION = "parent";
211
+ /** Una tupla del modo `facts` (misma forma que la del SDK, sin depender de él). */
212
+ export interface FactsTuple {
213
+ user: string;
214
+ relation: string;
215
+ object: string;
216
+ }
217
+ /**
218
+ * El objeto FGA de un scope. La `scopeKey` es la MISMA codificación que ya
219
+ * usan los ids de binding (`identity.ts`), así que el árbol y los hechos
220
+ * hablan del mismo nodo con la misma cadena; el scope tiene que venir ya
221
+ * CANÓNICO (invariante 17: `chain[0]`), o se abriría una segunda rama para
222
+ * el alias del uuid.
223
+ */
224
+ export declare function factsScopeObject(key: string): string;
225
+ /**
226
+ * La arista `hijo → padre` del árbol. Una sola tupla por nodo (c2): mover un
227
+ * subárbol es reescribir ESA tupla, no recorrer nada — por eso el `moved`
228
+ * del cruce 8 cabe en un `Write` atómico.
229
+ */
230
+ export declare function factsParentTuple(childKey: string, parentKey: string): FactsTuple;
231
+ /**
232
+ * **El marcador de raíz** (3b-2i): `scope:app#rooted@<holder>:*`, una tupla
233
+ * por holder type en TODO el store — cero por scope.
234
+ *
235
+ * Es lo que hace verdadera la premisa de `rooted`: solo la raíz la tiene
236
+ * directa. `attached`/`moved`/`detached` no escriben ni una tupla más por su
237
+ * culpa (la outbox y el relay no llevan entradas nuevas), y a cambio lo
238
+ * escribe quien toca el CATÁLOGO —`projectCatalog`, en cada
239
+ * `syncAuthzCatalog` con proyección, de forma idempotente— porque ése es el
240
+ * momento en el que un holderType nuevo del config aparece.
241
+ *
242
+ * ⚠️ **Modo de fallo que hay que conocer: sin marcador, todo el store
243
+ * DENIEGA** (medido: `can_<P>` es `false` en `app`, en la org y en la unit).
244
+ * Es fail-closed —no es una fuga— y ruidoso a la primera pregunta, pero es
245
+ * una caída total silenciosa desde el punto de vista del log. Por eso el
246
+ * marcador se repone en cada sync y `authz:reconcile` (3b-3) tiene que
247
+ * reportarlo como deriva cuando falte.
248
+ */
249
+ export declare function factsRootTuples(holderTypeMap: HolderTypeMap): FactsTuple[];
250
+ /** El tipo FGA de una asignación: `role_binding:<scopeKey>|<roleUuid>`. */
251
+ export declare const FACTS_BINDING_TYPE = "role_binding";
252
+ /** `scope:<key>#binding@role_binding:…` — qué asignaciones cuelgan del scope. */
253
+ export declare const FACTS_BINDING_RELATION = "binding";
254
+ /** `role_binding:…#role@role:<roleUuid>` — qué rol vincula la asignación. */
255
+ export declare const FACTS_ROLE_RELATION = "role";
256
+ /** `role_binding:…#assignee@<holder>` — quién está asignado (con la caducidad). */
257
+ export declare const FACTS_ASSIGNEE_RELATION = "assignee";
258
+ /**
259
+ * El objeto de una asignación. Mismo id que en el modo `resolver`
260
+ * (`<scopeKey>|<roleUuid>`, 3A · A1: uuid del catálogo, nunca el slug), y por
261
+ * eso el cambio de modelo no renombra un solo binding: lo que (c2) añade son
262
+ * las DOS aristas de abajo, no una identidad nueva.
263
+ */
264
+ export declare function factsBindingObject(scopeKeyValue: string, roleUuid: string): string;
265
+ /**
266
+ * Las dos aristas que hacen ALCANZABLE una asignación en (c2): el binding
267
+ * cuelga del scope (`scope#binding`) y apunta a su rol (`role_binding#role`).
268
+ * Sin ellas el `assignee` es un hecho huérfano que `can_<P>` no ve — es la
269
+ * diferencia entre el modo `resolver` (donde la cadena la expande el paquete
270
+ * y basta con el `assignee`) y el modo `facts`.
271
+ *
272
+ * Son ESTRUCTURA, no concesión: no llevan caducidad y no dicen quién está
273
+ * asignado. Por eso `revoke` no las borra (otro holder puede seguir usando el
274
+ * mismo binding) y re-escribirlas es idempotente.
275
+ */
276
+ export declare function factsBindingTuples(scopeKeyValue: string, roleUuid: string): FactsTuple[];
277
+ /**
278
+ * La arista `scope:<key>#binding@role_binding:<key>|<rol>` sola, que es la
279
+ * que hace ALCANZABLE la asignación desde el scope.
280
+ *
281
+ * **Qué significa** (3b-2g · R1, decisión del dueño del 2026-08-30 (2)): desde
282
+ * el barrido, «**el rol es visible aquí**» — no «esta asignación existe». El
283
+ * hecho de la asignación es el `assignee`, que el barrido no toca; esta arista
284
+ * la escribe y la borra el paquete cada vez que la REGLA DE VISIBILIDAD cambia
285
+ * de respuesta para ese `(rol, scope)`: el árbol se mueve y el owner deja de
286
+ * estar en la cadena (`scopes.moved`, 3b-2e · E1) o el catálogo cambia el
287
+ * NIVEL declarado del rol (`projectCatalogRole`, 3b-2g · R1). Es lo que en
288
+ * `database` se evalúa en cada pregunta con `declaredRoleAt`, y aquí hay que
289
+ * materializar porque el modelo (c2) no lleva ni el owner ni el nivel.
290
+ */
291
+ export declare function factsScopeBindingTuple(scopeKeyValue: string, roleUuid: string): FactsTuple;
292
+ /**
293
+ * El deny explícito de (c2): `scope:<key>#denied_<P>@<holder>`. Ya no existe
294
+ * el tipo `deny_binding` — el deny es una relación DEL SCOPE, que es lo que
295
+ * permite que `denied_<P>` se herede hacia abajo por `parent` dentro del
296
+ * propio modelo y que `can_<P>` sea la resta (invariante 2) en un solo Check.
297
+ */
298
+ export declare function factsDenyTuple(scopeKeyValue: string, permission: string, user: string): FactsTuple;
299
+ /** Prefijo de la familia del deny (`denied_<P>`), para leer denies por relación. */
300
+ export declare const FACTS_DENIED_PREFIX = "denied_";
301
+ /**
302
+ * El tipo `group` de las relaciones ReBAC: el portador de los usersets
303
+ * (`group:eng#member`) que hace que un `viewer` valga para todos los miembros
304
+ * de un grupo. Lo emite SIEMPRE el generador de relaciones (no lo declara el
305
+ * consumidor), y por eso es un tipo RESERVADO igual que los de `facts`.
306
+ */
307
+ export declare const FACTS_GROUP_TYPE = "group";
308
+ /** La relación de pertenencia del grupo: `group:<id>#member@<holder>` y `@group:<otro>#member`. */
309
+ export declare const FACTS_GROUP_MEMBER_RELATION = "member";
310
+ /**
311
+ * Los tipos reservados del modelo compartido (⚪4). La fuente única está en
312
+ * `src/identity.ts` (la gramática compartida), porque también la consume
313
+ * `defineRelationsConfig` en `src/relations/`, que la frontera de pureza
314
+ * mantiene disjunto de `drivers/`. Se re-exporta aquí para no romper el
315
+ * subpath `/openfga` (`src/openfga.ts` la publica desde este módulo).
316
+ */
317
+ export { RESERVED_FACTS_TYPES } from '../identity.js';
318
+ /** Una relación de un tipo de objeto de relaciones (`document#viewer`). */
319
+ export interface RelationObjectRelation {
320
+ /** El nombre de la relación (`owner`, `editor`, `viewer`). */
321
+ name: string;
322
+ /**
323
+ * Otras relaciones del MISMO tipo que ésta INCLUYE (`viewer or editor`): un
324
+ * `relate(u, editor, doc)` concede también `viewer`. Un nivel, SIN `from` en
325
+ * v1 (la herencia cross-objeto `viewer from parent` metería un TTU entre
326
+ * tipos y habría que re-medir profundidad — diferido a 2.6+).
327
+ */
328
+ includes?: readonly string[];
329
+ }
330
+ /** Un tipo de objeto de relaciones (`document`, `folder`, `space`…). */
331
+ export interface RelationObjectType {
332
+ /** El tipo FGA del objeto. */
333
+ type: string;
334
+ /** Sus relaciones, en orden de declaración. */
335
+ relations: readonly RelationObjectRelation[];
336
+ }
337
+ /**
338
+ * La config de relaciones que el generador FUSIONA en el modelo `facts`
339
+ * (Fase 4-1). Es la forma MÍNIMA que consume el generador; el puerto
340
+ * `RelationsDriver` y `defineRelationsConfig` completos son 4-2.
341
+ */
342
+ export interface FactsRelationsConfig {
343
+ /** Los tipos de objeto declarados por el consumidor. */
344
+ objectTypes: readonly RelationObjectType[];
345
+ }
346
+ /**
347
+ * **⚪4 + F-04, a nivel de MODELO.** Antes de emitir un solo `type_definition`
348
+ * de relaciones, el generador comprueba que la config es FUSIONABLE en el
349
+ * modelo compartido:
350
+ *
351
+ * - ningún `objectType` duplica un tipo reservado de `facts`/`group` ni un
352
+ * holder type (⚪4 · tipo), ni se repite;
353
+ * - ningún NOMBRE de relación (deduplicado entre tipos: `document#viewer` y
354
+ * `folder#viewer` son la misma relación lógica y se permiten) empieza por
355
+ * una familia derivada (`can_`/`denied_`/`permits_`) ni coincide con una
356
+ * relación PROPIA del modelo (`parent`/`rooted`/`assignee`… — ⚪4 · familia)
357
+ * ni con un permiso del catálogo (F-04);
358
+ * - los `includes` refieren relaciones del MISMO tipo (un nivel).
359
+ *
360
+ * Lanza 422 `E_AUTHZ_RELATION_CONFIG` del PAQUETE (no el 400 opaco del
361
+ * servidor), nombrando qué choca con qué.
362
+ */
363
+ export declare function assertRelationsConfigPublishable(permissionRelations: readonly FactsRelations[], config: FactsRelationsConfig, holderTypes: readonly string[]): void;
364
+ /**
365
+ * Los `type_definitions` de relaciones que el generador AÑADE al modelo
366
+ * `facts`: el tipo `group` (usersets) + un tipo por objeto declarado. El
367
+ * literal medido contra el `:8101` está en la §1 del plan de la Fase 4.
368
+ *
369
+ * `group.member` admite holders directos y `group#member` (grupos anidan un
370
+ * nivel); cada relación de objeto admite `[holders, group#member]` directos y,
371
+ * si declara `includes`, se une a las relaciones incluidas del mismo tipo
372
+ * (`viewer or editor`), sin una sola tupla extra.
373
+ *
374
+ * **R-15 (2.4.0-alpha.2) · la caducidad de la tupla de relación**: cada
375
+ * sujeto admitido va ADEMÁS `with not_expired` —los holders Y el userset
376
+ * `group#member`—, la MISMA condición que `role_binding#assignee` (invariante
377
+ * 3: la expiración es una *condition* del modelo, sin scheduler). Así
378
+ * `relate(…, { expiresAt })` escribe la tupla con `valid_until` y el `Check`
379
+ * (con `current_time`) la respeta; una tupla sin condición sigue siendo
380
+ * válida (no caduca). Coste medido en el gate de bytes: la condición añade
381
+ * `(holders + 1) × (tipo + 'not_expired')` bytes por relación declarada.
382
+ */
383
+ export declare function factsRelationTypeDefinitions(permissionRelations: readonly FactsRelations[], config: FactsRelationsConfig, holderTypes: readonly string[]): any[];
384
+ //# sourceMappingURL=openfga_facts.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"openfga_facts.d.ts","sourceRoot":"","sources":["../../../src/drivers/openfga_facts.ts"],"names":[],"mappings":"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"}