@jantstack/adonis-authz 2.4.0-alpha.1 → 2.4.0-alpha.10

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 (158) hide show
  1. package/README.md +496 -29
  2. package/build/commands/authz_catalog_diff.d.ts.map +1 -1
  3. package/build/commands/authz_catalog_diff.js +0 -1
  4. package/build/commands/authz_catalog_diff.js.map +1 -1
  5. package/build/commands/authz_catalog_prune_orphans.d.ts.map +1 -1
  6. package/build/commands/authz_catalog_prune_orphans.js +0 -1
  7. package/build/commands/authz_catalog_prune_orphans.js.map +1 -1
  8. package/build/commands/authz_freeze.d.ts.map +1 -1
  9. package/build/commands/authz_freeze.js +1 -2
  10. package/build/commands/authz_freeze.js.map +1 -1
  11. package/build/commands/authz_reconcile.d.ts +15 -6
  12. package/build/commands/authz_reconcile.d.ts.map +1 -1
  13. package/build/commands/authz_reconcile.js +143 -20
  14. package/build/commands/authz_reconcile.js.map +1 -1
  15. package/build/commands/authz_relations_reconcile.d.ts +72 -1
  16. package/build/commands/authz_relations_reconcile.d.ts.map +1 -1
  17. package/build/commands/authz_relations_reconcile.js +234 -21
  18. package/build/commands/authz_relations_reconcile.js.map +1 -1
  19. package/build/commands/authz_scopes_relay.d.ts +50 -0
  20. package/build/commands/authz_scopes_relay.d.ts.map +1 -1
  21. package/build/commands/authz_scopes_relay.js +213 -10
  22. package/build/commands/authz_scopes_relay.js.map +1 -1
  23. package/build/commands/authz_scopes_requeue.d.ts +80 -0
  24. package/build/commands/authz_scopes_requeue.d.ts.map +1 -0
  25. package/build/commands/authz_scopes_requeue.js +230 -0
  26. package/build/commands/authz_scopes_requeue.js.map +1 -0
  27. package/build/commands/authz_unfreeze.d.ts +12 -4
  28. package/build/commands/authz_unfreeze.d.ts.map +1 -1
  29. package/build/commands/authz_unfreeze.js +74 -9
  30. package/build/commands/authz_unfreeze.js.map +1 -1
  31. package/build/commands/main.d.ts +16 -13
  32. package/build/commands/main.d.ts.map +1 -1
  33. package/build/commands/main.js +59 -11
  34. package/build/commands/main.js.map +1 -1
  35. package/build/commands/openfga_provision.d.ts +49 -3
  36. package/build/commands/openfga_provision.d.ts.map +1 -1
  37. package/build/commands/openfga_provision.js +72 -7
  38. package/build/commands/openfga_provision.js.map +1 -1
  39. package/build/index.d.ts +15 -5
  40. package/build/index.d.ts.map +1 -1
  41. package/build/index.js +16 -3
  42. package/build/index.js.map +1 -1
  43. package/build/providers/authz_provider.d.ts +7 -2
  44. package/build/providers/authz_provider.d.ts.map +1 -1
  45. package/build/providers/authz_provider.js +20 -3
  46. package/build/providers/authz_provider.js.map +1 -1
  47. package/build/src/define_config.d.ts +106 -1
  48. package/build/src/define_config.d.ts.map +1 -1
  49. package/build/src/define_config.js +11 -0
  50. package/build/src/define_config.js.map +1 -1
  51. package/build/src/drivers/database_driver.d.ts +53 -14
  52. package/build/src/drivers/database_driver.d.ts.map +1 -1
  53. package/build/src/drivers/database_driver.js +104 -32
  54. package/build/src/drivers/database_driver.js.map +1 -1
  55. package/build/src/drivers/database_relations_driver.d.ts +74 -9
  56. package/build/src/drivers/database_relations_driver.d.ts.map +1 -1
  57. package/build/src/drivers/database_relations_driver.js +391 -93
  58. package/build/src/drivers/database_relations_driver.js.map +1 -1
  59. package/build/src/drivers/openfga_driver.d.ts +71 -10
  60. package/build/src/drivers/openfga_driver.d.ts.map +1 -1
  61. package/build/src/drivers/openfga_driver.js +195 -16
  62. package/build/src/drivers/openfga_driver.js.map +1 -1
  63. package/build/src/drivers/openfga_facts.d.ts +15 -0
  64. package/build/src/drivers/openfga_facts.d.ts.map +1 -1
  65. package/build/src/drivers/openfga_facts.js +25 -2
  66. package/build/src/drivers/openfga_facts.js.map +1 -1
  67. package/build/src/drivers/openfga_relations_driver.d.ts +72 -6
  68. package/build/src/drivers/openfga_relations_driver.d.ts.map +1 -1
  69. package/build/src/drivers/openfga_relations_driver.js +308 -50
  70. package/build/src/drivers/openfga_relations_driver.js.map +1 -1
  71. package/build/src/errors.d.ts +175 -4
  72. package/build/src/errors.d.ts.map +1 -1
  73. package/build/src/errors.js +219 -3
  74. package/build/src/errors.js.map +1 -1
  75. package/build/src/freeze.d.ts +100 -20
  76. package/build/src/freeze.d.ts.map +1 -1
  77. package/build/src/freeze.js +159 -25
  78. package/build/src/freeze.js.map +1 -1
  79. package/build/src/manager.d.ts +239 -7
  80. package/build/src/manager.d.ts.map +1 -1
  81. package/build/src/manager.js +1192 -148
  82. package/build/src/manager.js.map +1 -1
  83. package/build/src/models/authz_assignment.d.ts +2 -2
  84. package/build/src/models/authz_assignment.d.ts.map +1 -1
  85. package/build/src/models/authz_deny.d.ts +2 -2
  86. package/build/src/models/authz_deny.d.ts.map +1 -1
  87. package/build/src/models/authz_permission.d.ts +2 -2
  88. package/build/src/models/authz_permission.d.ts.map +1 -1
  89. package/build/src/models/authz_role.d.ts +2 -2
  90. package/build/src/models/authz_role.d.ts.map +1 -1
  91. package/build/src/models/authz_role_permission.d.ts +2 -2
  92. package/build/src/models/authz_role_permission.d.ts.map +1 -1
  93. package/build/src/relation_partition_trigger.d.ts.map +1 -1
  94. package/build/src/relation_partition_trigger.js +11 -3
  95. package/build/src/relation_partition_trigger.js.map +1 -1
  96. package/build/src/relations/define_relations_config.d.ts +51 -0
  97. package/build/src/relations/define_relations_config.d.ts.map +1 -1
  98. package/build/src/relations/define_relations_config.js +68 -1
  99. package/build/src/relations/define_relations_config.js.map +1 -1
  100. package/build/src/relations/manager.d.ts +106 -6
  101. package/build/src/relations/manager.d.ts.map +1 -1
  102. package/build/src/relations/manager.js +368 -30
  103. package/build/src/relations/manager.js.map +1 -1
  104. package/build/src/relations/reconcile.d.ts +81 -6
  105. package/build/src/relations/reconcile.d.ts.map +1 -1
  106. package/build/src/relations/reconcile.js +233 -77
  107. package/build/src/relations/reconcile.js.map +1 -1
  108. package/build/src/scope_outbox.d.ts +54 -0
  109. package/build/src/scope_outbox.d.ts.map +1 -1
  110. package/build/src/scope_outbox.js +274 -33
  111. package/build/src/scope_outbox.js.map +1 -1
  112. package/build/src/shared/backend_guard.d.ts +28 -0
  113. package/build/src/shared/backend_guard.d.ts.map +1 -1
  114. package/build/src/shared/backend_guard.js +52 -0
  115. package/build/src/shared/backend_guard.js.map +1 -1
  116. package/build/src/shared/sql_expiry.d.ts +2 -0
  117. package/build/src/shared/sql_expiry.d.ts.map +1 -1
  118. package/build/src/shared/sql_expiry.js +4 -0
  119. package/build/src/shared/sql_expiry.js.map +1 -1
  120. package/build/src/shared/transaction_guard.d.ts +53 -0
  121. package/build/src/shared/transaction_guard.d.ts.map +1 -0
  122. package/build/src/shared/transaction_guard.js +74 -0
  123. package/build/src/shared/transaction_guard.js.map +1 -0
  124. package/build/src/sql_descendants.d.ts +8 -0
  125. package/build/src/sql_descendants.d.ts.map +1 -1
  126. package/build/src/sql_descendants.js.map +1 -1
  127. package/build/src/testing/contract.d.ts +55 -4
  128. package/build/src/testing/contract.d.ts.map +1 -1
  129. package/build/src/testing/contract.js +244 -9
  130. package/build/src/testing/contract.js.map +1 -1
  131. package/build/src/testing/main.d.ts +6 -4
  132. package/build/src/testing/main.d.ts.map +1 -1
  133. package/build/src/testing/main.js +3 -2
  134. package/build/src/testing/main.js.map +1 -1
  135. package/build/src/testing/migration_contract.d.ts +9 -0
  136. package/build/src/testing/migration_contract.d.ts.map +1 -1
  137. package/build/src/testing/migration_contract.js +5 -2
  138. package/build/src/testing/migration_contract.js.map +1 -1
  139. package/build/src/testing/relations_contract.d.ts +23 -1
  140. package/build/src/testing/relations_contract.d.ts.map +1 -1
  141. package/build/src/testing/relations_contract.js +603 -19
  142. package/build/src/testing/relations_contract.js.map +1 -1
  143. package/build/src/testing/relations_reconcile_contract.d.ts.map +1 -1
  144. package/build/src/testing/relations_reconcile_contract.js +49 -1
  145. package/build/src/testing/relations_reconcile_contract.js.map +1 -1
  146. package/build/src/testing/scope_outbox_contract.d.ts +98 -0
  147. package/build/src/testing/scope_outbox_contract.d.ts.map +1 -0
  148. package/build/src/testing/scope_outbox_contract.js +677 -0
  149. package/build/src/testing/scope_outbox_contract.js.map +1 -0
  150. package/build/src/traits/has_uuid.d.ts +2 -2
  151. package/build/src/traits/has_uuid.d.ts.map +1 -1
  152. package/build/src/types.d.ts +708 -38
  153. package/build/src/types.d.ts.map +1 -1
  154. package/build/src/types.js +55 -0
  155. package/build/src/types.js.map +1 -1
  156. package/build/stubs/config/authorization.stub +45 -1
  157. package/build/stubs/migration.stub +20 -10
  158. package/package.json +1 -1
@@ -21,41 +21,199 @@
21
21
  * Pureza (regla 2): solo depende del puerto, los errores, la gramática
22
22
  * compartida y `defineRelationsConfig`. Nada de `manager`/`drivers/*`.
23
23
  */
24
- import { ActorRequiredError, RelationTypeUnknownError, RelationUnknownError, UnsupportedOperationError, } from '../errors.js';
25
- import { assertScope, assertSubject, assertRelationId } from '../identity.js';
26
- import { isRelUserset } from '../types.js';
24
+ import { ActorRequiredError, AuthorizationBackendTimeoutError, AuthorizationConfigError, UnsupportedOperationError, isPartialWrite, } from '../errors.js';
25
+ import { assertScope, assertSubject, assertRelationId, assertExpiresAt, scopeKey } from '../identity.js';
26
+ import { isClock, systemClock } from '../clock.js';
27
+ import { assertNotFrozenRow } from '../freeze.js';
28
+ import { isRelUserset, normalizeRelationsCapabilities } from '../types.js';
29
+ import { assertRelationDeclared, assertObjectTypeDeclared } from './define_relations_config.js';
27
30
  export class RelationsManager {
28
31
  #driver;
29
32
  #config;
30
33
  #options;
31
34
  constructor(driver, config, options = {}) {
35
+ if (options.clock !== undefined) {
36
+ if (!isClock(options.clock)) {
37
+ throw new AuthorizationConfigError(`RelationsManager: clock debe ser una función () => Date (llegó ${typeof options.clock})`);
38
+ }
39
+ if (typeof driver.withClock !== 'function') {
40
+ throw new AuthorizationConfigError(`RelationsManager: el driver de relaciones no implementa withClock(now) y la config declara clock: ` +
41
+ `sin él la caducidad de las relaciones se decidiría con otro reloj que el declarado.`);
42
+ }
43
+ driver = driver.withClock(options.clock);
44
+ }
45
+ if (options.requireTransactionalWrites === true && driver.capabilities?.transactionalWrites !== true) {
46
+ throw new AuthorizationConfigError(`requireTransactionalWrites está en true y el driver de relaciones '${options.driverName ?? 'relations'}' ` +
47
+ `declara transactionalWrites: ${driver.capabilities ? String(driver.capabilities.transactionalWrites) : 'nada (sin capabilities)'}: ` +
48
+ `no puede inscribir relate/unrelate/purge* en la transacción del consumidor («los dos o ninguno»), así que ` +
49
+ `el RelationsManager no se construye. Usa un driver que la declare (database) o quita el flag ` +
50
+ `(relations.requireTransactionalWrites, o el del raíz).`);
51
+ }
32
52
  this.#driver = driver;
33
53
  this.#config = config;
34
54
  this.#options = options;
35
55
  }
56
+ /**
57
+ * **Puerta 1 de `{ transaction }`** (L-2, siempre activa): una escritura con
58
+ * `{ transaction }` a un driver que no declara `transactionalWrites: true`
59
+ * es 500 `E_AUTHZ_UNSUPPORTED` nombrando driver y operación, ANTES de la
60
+ * barrera, de F-05 y del driver (cero llamadas). Encolar ≠ escribir: aquí
61
+ * la transacción ESCRIBE la tupla dentro de ella, no hay outbox.
62
+ */
63
+ #assertTransactional(options, operation) {
64
+ if (options?.transaction === undefined || options.transaction === null)
65
+ return;
66
+ if (this.#driver.capabilities?.transactionalWrites === true)
67
+ return;
68
+ throw UnsupportedOperationError.transactional(`relations.${operation}`, this.#options.driverName ?? 'relations', 'relations');
69
+ }
70
+ /**
71
+ * La marca del evento de una escritura inscrita en la transacción del
72
+ * llamante (2.4.0-alpha.3 · B, paridad literal con `#transactional` de
73
+ * roles, L-3): `onRelationWrite` se dispara cuando el DRIVER vuelve, y en
74
+ * ese momento la tupla existe solo dentro de esa transacción — es un hecho
75
+ * si y solo si el llamante confirma, cosa que el paquete nunca ve. Quien
76
+ * audita lo necesita para no registrar como firme lo que un rollback
77
+ * deshace (`trx.after('commit')`). `undefined`/`null` cuentan como SIN
78
+ * transacción (lo mismo que `#assertTransactional`); sin ella la marca está
79
+ * AUSENTE, nunca `false`.
80
+ */
81
+ #transactional(options) {
82
+ return options?.transaction === undefined || options.transaction === null ? {} : { transactional: true };
83
+ }
84
+ /** `{ actor }` listo para fundir en el evento, o `{}`: el evento no inventa autores (como `#writeOptions` de roles). */
85
+ #actorOf(options) {
86
+ return options?.actor ? { actor: options.actor } : {};
87
+ }
88
+ /**
89
+ * **Invariante 13 en relaciones** (2.4.0-alpha.3 · C; el MISMO `#write` de
90
+ * roles, `manager.ts:3257`): una escritura que vence el deadline (503
91
+ * `E_AUTHZ_BACKEND_TIMEOUT`) es INDETERMINADA — la sentencia/el `Write`
92
+ * puede aterrizar después de que el llamante reciba el error—. Antes de
93
+ * propagar se notifica el mismo evento con `indeterminate: true`, para que
94
+ * quien audita registre «puede haber ocurrido» en vez de nada. Cualquier
95
+ * otro fallo (422, `assertWrite`, freeze, conexión rechazada) significa que
96
+ * la escritura no ocurrió y se propaga SIN evento. Con `{ transaction }` el
97
+ * evento lleva además `transactional: true` (el rollback del llamante
98
+ * determina el resultado, pero es suyo y el paquete no lo ve). Envuelve las
99
+ * CUATRO escrituras.
100
+ *
101
+ * **Y una escritura PARCIAL también es indeterminada** (cierre del 🟡 6 del
102
+ * auditor de alpha.3): la purga de `openfga` es multi-request (ortografías
103
+ * × tipos, cada una `Read`+`deleteTuples`+`Read`), así que un 503 que NO es
104
+ * timeout —o el 500 `E_AUTHZ_PURGE_INCOMPLETE`— puede llegar DESPUÉS de haber
105
+ * borrado parte. Ahí «esa escritura no ocurrió» sería falso; el driver marca
106
+ * el error con `markPartialWrite` (`src/errors.ts`) y aquí se notifica
107
+ * `indeterminate: true` igual que con el deadline. La frase «no ocurrió y no
108
+ * hay evento» queda para los fallos ANTES de la primera sentencia/`Write`.
109
+ */
110
+ async #write(event, fn) {
111
+ try {
112
+ return await fn();
113
+ }
114
+ catch (error) {
115
+ if (error instanceof AuthorizationBackendTimeoutError || isPartialWrite(error)) {
116
+ await this.#notify({ ...event, indeterminate: true });
117
+ }
118
+ throw error;
119
+ }
120
+ }
121
+ /**
122
+ * **El evento es una COPIA, no un alias** (⚪ 8 del auditor de alpha.3): el
123
+ * sink lo guarda y el llamante (o el propio sink, ahora que se `await`ea)
124
+ * puede mutar después `object.id`, `partition.uuid` o el `actor`. Copia por
125
+ * nivel de identidad (spread: el `actor` conserva los campos de más que
126
+ * traiga, como en roles — se documenta, no se poda); `expiresAt` es un
127
+ * `Date` inmutable por convención y se copia como instante.
128
+ */
129
+ #copyEvent(event) {
130
+ const copy = { ...event, partition: { ...event.partition } };
131
+ if (event.subject !== undefined) {
132
+ copy.subject = isRelUserset(event.subject)
133
+ ? { ...event.subject, object: { ...event.subject.object } }
134
+ : { ...event.subject };
135
+ }
136
+ if (event.object !== undefined)
137
+ copy.object = { ...event.object };
138
+ if (event.actor !== undefined)
139
+ copy.actor = { ...event.actor };
140
+ if (event.expiresAt instanceof Date)
141
+ copy.expiresAt = new Date(event.expiresAt.getTime());
142
+ return copy;
143
+ }
144
+ /**
145
+ * Notifica al consumidor (2.4.0-alpha.3 · D1/D2, hallazgo H1; el MISMO
146
+ * `#notify` de roles, `manager.ts:3276`). El hook es un side-effect
147
+ * (auditar, emitir un evento): cuando falla, la escritura YA está aplicada,
148
+ * así que propagar su error le daría al llamante un fallo por una operación
149
+ * que sí ocurrió — y le invitaría a reintentar algo ya hecho. Se ESPERA (un
150
+ * hook `async` que rechaza ya no es un unhandled rejection), se registra y
151
+ * se sigue. Hasta alpha.3 se llamaba sin `await` ni `try/catch`.
152
+ */
153
+ async #notify(event) {
154
+ try {
155
+ await this.#options.onRelationWrite?.(event);
156
+ }
157
+ catch (error) {
158
+ await this.#logHookFailure(event, error);
159
+ }
160
+ }
161
+ async #logHookFailure(event, error) {
162
+ const context = `authz: el hook onRelationWrite falló tras '${event.operation}' (la escritura sí se aplicó)`;
163
+ try {
164
+ const { default: logger } = await import('@adonisjs/core/services/logger');
165
+ logger.error({ err: error, event }, context);
166
+ }
167
+ catch {
168
+ // Fuera de una app booteada (tests, scripts sueltos) no hay logger.
169
+ console.error(context, error);
170
+ }
171
+ }
36
172
  /** El driver crudo — salida documentada de las barreras (plataforma y tests). */
37
173
  driver() {
38
174
  return this.#driver;
39
175
  }
176
+ /**
177
+ * **Lo que el driver de relaciones ACTIVO declara, de solo lectura**
178
+ * (2.4.0-alpha.4; pregunta 1 de COGNITIV). Para que el código de tenant
179
+ * ramifique —`if (relations.capabilities().transactionalWrites) relate(…,
180
+ * { transaction }) else relate(…)`— sin llamar a `driver()`, que sigue
181
+ * siendo API de PLATAFORMA. Síncrono, a diferencia del de roles: aquí el
182
+ * driver es eager (la puerta 2 ya corrió en el constructor) y no hay nada
183
+ * que resolver. Copia CONGELADA y NORMALIZADA (todas las claves de
184
+ * `RelationsDriverCapabilities`, `undefined` → `false`): mutarla no toca
185
+ * lo que lee la puerta 1.
186
+ */
187
+ capabilities() {
188
+ return normalizeRelationsCapabilities(this.#driver.capabilities);
189
+ }
40
190
  /**
41
191
  * **F-05**: rechaza un tipo/relación no declarado ANTES de tocar el driver.
42
192
  * La gramática de identidad no basta: `role_binding`/`assignee` son
43
193
  * gramaticalmente válidos y en el store compartido componen el id de un
44
- * binding real.
194
+ * binding real. Es la MISMA función que aplican los dos drivers (L-0,
195
+ * `assertRelationDeclared`): el manager corta primero; el driver es la red
196
+ * para quien entra por `manager.driver()` o por `reconcileRelations`.
197
+ *
198
+ * **En las OCHO operaciones** (2.4.0-alpha.3, 🔴 1 / 🟠 2 del auditor;
199
+ * cierre-2 · 🟡 3 `membersOf`): hasta alpha.3 solo `relate`/`unrelate`
200
+ * pasaban por aquí, y `purgeObject({ type: 'role_binding', id: R }, S)`
201
+ * componía en el driver `openfga` el id EXACTO del binding real y lo
202
+ * borraba con demostración de cero (`authorize` de `true` a `false`), con
203
+ * un evento de auditoría limpio; `listSubjects('assignee', role_binding)`
204
+ * enumeraba sus asignados. **Dos funciones, no un opcional** (cierre-2,
205
+ * 🟠 1: la `relation?` opcional apagó F-05 en `relate`/`unrelate` sin
206
+ * relación): `#assertDeclared` es ESTRICTA —la relación es obligatoria— y
207
+ * la usan `relate`/`unrelate`/`check`/`listObjects`/`listSubjects`/
208
+ * `membersOf` y el userset del sujeto; `#assertTypeDeclared` (solo el tipo)
209
+ * la usa `purgeObject`. `purgeSubject` no nombra objeto: su F-05 es la del
210
+ * userset (`#assertSubject`).
45
211
  */
46
212
  #assertDeclared(object, relation) {
47
- if (!object || typeof object !== 'object' || typeof object.type !== 'string') {
48
- throw new RelationTypeUnknownError(`Objeto de relación inválido: se esperaba { type, id } y llegó ${JSON.stringify(object)}.`);
49
- }
50
- if (!this.#config.hasType(object.type)) {
51
- throw new RelationTypeUnknownError(`El tipo de objeto '${object.type}' no está declarado en defineRelationsConfig (F-05): ` +
52
- `relate/unrelate solo aceptan tipos declarados. En el store compartido un tipo no declarado ` +
53
- `podría componer el id de un 'role_binding' real y escalar a roles.authorize.`);
54
- }
55
- if (!this.#config.isDeclared(object.type, relation)) {
56
- throw new RelationUnknownError(`La relación '${relation}' no está declarada para el tipo '${object.type}' en ` +
57
- `defineRelationsConfig (F-05).`);
58
- }
213
+ assertRelationDeclared(this.#config, object, relation);
214
+ }
215
+ #assertTypeDeclared(object) {
216
+ assertObjectTypeDeclared(this.#config, object);
59
217
  }
60
218
  /**
61
219
  * **R-16**: el `object.id` con la gramática estricta de relaciones ANTES del
@@ -68,55 +226,176 @@ export class RelationsManager {
68
226
  #assertObjectId(object) {
69
227
  assertRelationId(`el id del objeto '${object?.type}'`, object?.id);
70
228
  }
71
- #assertActor(options) {
229
+ /**
230
+ * El `actor` de una escritura (2.4.0-alpha.3 · D4, hallazgo H3; paridad con
231
+ * `#writeOptions` de roles, `manager.ts:1512`): **validar-si-viene y después
232
+ * exigir-si-falta**. Hasta alpha.3 solo se comprobaba la PRESENCIA: un
233
+ * `actor: { uuid: 'A#B' }` viajaba al evento (envenena el rastro) y un
234
+ * `actor: {}` truthy satisfacía `requireActor`. Ahora un actor mal formado
235
+ * es 422 `E_AUTHZ_INVALID_IDENTITY` ANTES del driver, en las CUATRO
236
+ * escrituras (purgas incluidas, D-3).
237
+ */
238
+ #assertActor(options, operation) {
239
+ if (options?.actor !== undefined)
240
+ assertSubject(options.actor);
72
241
  if (this.#options.requireActor && !options?.actor) {
73
- throw new ActorRequiredError(`Escritura de relación sin 'actor' y la config exige uno (requireActor).`);
242
+ throw new ActorRequiredError(`relations.${operation}: escritura de relación sin 'actor' y la config exige uno (requireActor).`);
243
+ }
244
+ }
245
+ /**
246
+ * **R-13 con dientes** (2.4.0-alpha.3 · D3, hallazgo H2; cierre 🟠 3 / 🟡 4
247
+ * del auditor): `assertWrite` es síncrono y puro, y **no devuelve
248
+ * veredictos: lanza o no lanza**. TODO retorno distinto de `undefined` es
249
+ * 500 `E_AUTHZ_CONFIG` antes de tocar el driver — una promesa (H2: la
250
+ * promesa se descarta con el rechazo quitado para que no salga como
251
+ * unhandled rejection), una FUNCIÓN con `.then` (esquivaba la guarda
252
+ * `typeof 'object'`), un `false` (compila bajo `--strict` y hasta el cierre
253
+ * la escritura ENTRABA: fail-open) y también un `true` (el mismo error de
254
+ * modelo). Un `assertWrite` que LANZA propaga tal cual (es su forma de
255
+ * rechazar). La policy con actor/BD/await va en el servicio del consumidor.
256
+ */
257
+ #assertWrite(ref, operation) {
258
+ const result = this.#options.assertWrite?.(ref);
259
+ if (result === undefined)
260
+ return;
261
+ if (result !== null && typeof result.then === 'function') {
262
+ Promise.resolve(result).then(undefined, () => { });
74
263
  }
264
+ throw AuthorizationConfigError.assertWriteReturned(`relations.${operation}`, result);
265
+ }
266
+ /**
267
+ * **La barrera del freeze, la MISMA que la de roles** (L-1 · J1, juez del
268
+ * panel `{trx}`): hasta L-1 no había una sola referencia al freeze en
269
+ * `relations/`, así que durante un cutover las escrituras de roles recibían
270
+ * 503 y las de relaciones ENTRABAN, y `authz:relations:reconcile`
271
+ * certificaba un estado que podía cambiar debajo. Es la fila `id = 2` de
272
+ * `authz_catalog_version` leída por la conexión del motor (`assertNotFrozenRow`,
273
+ * `src/freeze.ts` — raíz de `src/`, así que la regla 2 de pureza se cumple),
274
+ * delante de las CUATRO escrituras y antes de validar nada: 503
275
+ * `E_AUTHZ_FROZEN` reintentable. Las lecturas no pasan por aquí.
276
+ * `manager.driver()` sigue siendo la salida documentada.
277
+ */
278
+ #assertNotFrozen(operation) {
279
+ return assertNotFrozenRow(`relations.${operation}`, {
280
+ driver: 'relations',
281
+ nowMs: (this.#options.clock ?? systemClock)().getTime(),
282
+ timeoutMs: this.#options.freezeTimeoutMs,
283
+ });
75
284
  }
76
285
  async relate(subject, relation, object, partition, options) {
286
+ this.#assertTransactional(options, 'relate');
287
+ await this.#assertNotFrozen('relate');
77
288
  this.#assertDeclared(object, relation);
78
289
  this.#assertObjectId(object);
79
- this.#assertActor(options);
290
+ this.#assertActor(options, 'relate');
80
291
  assertScope(partition);
81
292
  this.#assertSubject(subject, partition);
293
+ // R-15: `expiresAt` en sus tres estados legales (omitido / null / Date
294
+ // válida); cualquier otra cosa es 422 ANTES del driver (invariante 5).
295
+ assertExpiresAt(options?.expiresAt);
82
296
  const ref = { operation: 'relate', subject, relation, object, partition };
83
- this.#options.assertWrite?.(ref);
84
- await this.#driver.relate(subject, relation, object, partition, options);
85
- this.#options.onRelationWrite?.({ ...ref, actor: options?.actor });
297
+ if (options && 'expiresAt' in options)
298
+ ref.expiresAt = options.expiresAt;
299
+ this.#assertWrite(ref, 'relate');
300
+ const event = this.#copyEvent({ ...ref, ...this.#actorOf(options), ...this.#transactional(options) });
301
+ await this.#write(event, () => this.#driver.relate(subject, relation, object, partition, options));
302
+ await this.#notify(event);
86
303
  }
87
304
  async unrelate(subject, relation, object, partition, options) {
305
+ this.#assertTransactional(options, 'unrelate');
306
+ await this.#assertNotFrozen('unrelate');
88
307
  this.#assertDeclared(object, relation);
89
308
  this.#assertObjectId(object);
90
- this.#assertActor(options);
309
+ this.#assertActor(options, 'unrelate');
91
310
  assertScope(partition);
92
311
  this.#assertSubject(subject, partition);
93
312
  const ref = { operation: 'unrelate', subject, relation, object, partition };
94
- this.#options.assertWrite?.(ref);
95
- await this.#driver.unrelate(subject, relation, object, partition, options);
96
- this.#options.onRelationWrite?.({ ...ref, actor: options?.actor });
313
+ this.#assertWrite(ref, 'unrelate');
314
+ const event = this.#copyEvent({ ...ref, ...this.#actorOf(options), ...this.#transactional(options) });
315
+ await this.#write(event, () => this.#driver.unrelate(subject, relation, object, partition, options));
316
+ await this.#notify(event);
97
317
  }
318
+ /**
319
+ * **Las lecturas también pasan por F-05** (2.4.0-alpha.3, 🟠 2 del auditor):
320
+ * el `objectId` lleva la partición, así que `listSubjects('assignee',
321
+ * { type: 'role_binding', id: R }, S)` era la lista de asignados de un rol
322
+ * en un scope, por el puerto de relaciones, sin catálogo, sin `within`, sin
323
+ * `requireActor` (las lecturas no lo tienen) y sin visibilidad de rol
324
+ * (invariante 18). `check`/`listSubjects` validan el par (tipo, relación);
325
+ * `listObjects` el tipo; el userset del sujeto, su par. PRIMERA línea,
326
+ * cero llamadas al driver; el driver re-valida (defensa en profundidad).
327
+ */
98
328
  async check(subject, relation, object, partition) {
329
+ this.#assertDeclared(object, relation);
99
330
  assertScope(partition);
100
331
  this.#assertObjectId(object);
332
+ this.#assertSubject(subject, partition);
101
333
  return this.#driver.check(subject, relation, object, partition);
102
334
  }
103
335
  async listObjects(subject, relation, objectType, partition, page) {
336
+ this.#assertDeclared({ type: objectType }, relation);
104
337
  assertScope(partition);
338
+ this.#assertSubject(subject, partition);
105
339
  return this.#driver.listObjects(subject, relation, objectType, partition, page);
106
340
  }
107
341
  async listSubjects(relation, object, partition, page) {
342
+ this.#assertDeclared(object, relation);
108
343
  assertScope(partition);
109
344
  this.#assertObjectId(object);
110
345
  return this.#driver.listSubjects(relation, object, partition, page);
111
346
  }
112
- async purgeObject(object, partition) {
347
+ /**
348
+ * **Las purgas notifican** (2.4.0-alpha.3 · E, hallazgo #4; D-1/D-3): UN
349
+ * evento por llamada —aunque el driver barra las dos ortografías del uuid
350
+ * de partición por dentro: el manager no canoniza particiones, y diverge a
351
+ * propósito de `scopes.detached`, que emite uno por ortografía porque ahí
352
+ * canoniza el MANAGER—, con el objetivo y la partición TAL COMO la pasó el
353
+ * llamante, sin `relation` y SIN conteo (el puerto devuelve `void`; un
354
+ * conteo lo rompería para terceros y un rollback lo desmentiría). Se
355
+ * notifica también cuando no borra nada: el hecho auditable es «alguien
356
+ * pidió borrar las llaves de X». Sujeta a `requireActor` (D-3, breaking) y
357
+ * al actor validado; NO pasa por `assertWrite` (su `RelationRef.operation`
358
+ * es `'relate' | 'unrelate'`, tipo publicado de R-13). Mismo `#write`
359
+ * (invariante 13) y mismo `#notify` que `relate`/`unrelate`.
360
+ *
361
+ * **Y pasan por F-05** (cierre del 🔴 1 del auditor de alpha.3): el mismo
362
+ * orden que `relate` —puerta 1, freeze, F-05 (solo el TIPO: una purga no
363
+ * nombra relación), id, actor, scope—. `purgeSubject` valida su sujeto como
364
+ * `relate` (`#assertSubject`, ⚪ 7: un userset no declarado o un holder mal
365
+ * formado es 422 ANTES del driver y no llega al evento).
366
+ */
367
+ async purgeObject(object, partition, options) {
368
+ this.#assertTransactional(options, 'purgeObject');
369
+ await this.#assertNotFrozen('purgeObject');
370
+ this.#assertTypeDeclared(object);
113
371
  assertScope(partition);
114
372
  this.#assertObjectId(object);
115
- return this.#driver.purgeObject(object, partition);
373
+ this.#assertActor(options, 'purgeObject');
374
+ const event = this.#copyEvent({
375
+ operation: 'purgeObject',
376
+ object,
377
+ partition,
378
+ ...this.#actorOf(options),
379
+ ...this.#transactional(options),
380
+ });
381
+ await this.#write(event, () => this.#driver.purgeObject(object, partition, options));
382
+ await this.#notify(event);
116
383
  }
117
- async purgeSubject(subject, partition) {
384
+ async purgeSubject(subject, partition, options) {
385
+ this.#assertTransactional(options, 'purgeSubject');
386
+ await this.#assertNotFrozen('purgeSubject');
118
387
  assertScope(partition);
119
- return this.#driver.purgeSubject(subject, partition);
388
+ this.#assertSubject(subject, partition);
389
+ this.#assertActor(options, 'purgeSubject');
390
+ const event = this.#copyEvent({
391
+ operation: 'purgeSubject',
392
+ subject,
393
+ partition,
394
+ ...this.#actorOf(options),
395
+ ...this.#transactional(options),
396
+ });
397
+ await this.#write(event, () => this.#driver.purgeSubject(subject, partition, options));
398
+ await this.#notify(event);
120
399
  }
121
400
  /**
122
401
  * Membresía TRANSITIVA de un grupo (a través de usersets anidados) —
@@ -126,7 +405,14 @@ export class RelationsManager {
126
405
  * trunca), jamás un `skip`.
127
406
  */
128
407
  async membersOf(object, relation, partition, page) {
408
+ // Cierre-2 · 🟡 3: `membersOf` toma `(object, relation)` —la forma exacta
409
+ // que F-05 guarda— y era la octava operación fuera de «las siete»; un
410
+ // driver de terceros con `membersOfNative: true` sobre un store compartido
411
+ // reabría la fuga de `listSubjects`. F-05 (par, ESTRICTA) ANTES de la
412
+ // capacidad: 422 con cero llamadas, también donde `membersOf` sería 500.
413
+ this.#assertDeclared(object, relation);
129
414
  assertScope(partition);
415
+ this.#assertObjectId(object);
130
416
  if (!this.#driver.membersOf || !this.#driver.capabilities?.membersOfNative) {
131
417
  throw new UnsupportedOperationError('membersOf', 'la membresía transitiva de un grupo', 'relations', `Solo el driver 'database' la resuelve (CTE recursiva); en 'openfga' la transitiva sería ` +
132
418
  `'ListUsers', que trunca. Usa 'listSubjects' para los hechos directos.`);
@@ -141,6 +427,58 @@ export class RelationsManager {
141
427
  }
142
428
  return this.#driver.enumerateRelations(partition, page);
143
429
  }
430
+ /**
431
+ * **K particiones en UN barrido** (2.4.0-alpha.6) si el driver trae
432
+ * `enumerateRelationsMany` (los dos publicados lo traen desde alpha.8: el
433
+ * de `database` es una consulta con `partition_key IN (…)` y cursor
434
+ * estable); si no, K llamadas a `enumerateRelations` concatenadas
435
+ * (correcto, K barridos — el precio queda escrito en la tabla «Limits»).
436
+ * Sin particiones es 500: un barrido para nadie no es un éxito.
437
+ *
438
+ * **El respaldo es exhaustivo o RUIDOSO** (2.4.0-alpha.8 · C2; panel relay
439
+ * 2, analista §8, juez 7.1 🟠). Hasta alpha.7 acumulaba las K páginas y
440
+ * devolvía el cursor de la ÚLTIMA partición que tenía más; reanudar con él
441
+ * aplicaba `uuid > after` a TODAS y **perdía tuplas en silencio** (medido:
442
+ * 6 en el store, 5 vistas) — en el ORIGEN de una migración eso es «esa
443
+ * tupla no existía». Un cursor de una sola partición no sabe reanudar K,
444
+ * así que el respaldo no lo emite: si alguna partición devuelve cursor es
445
+ * 500 `E_AUTHZ_CONFIG` nombrando el método (misma doctrina que el barrido
446
+ * único: si no puede enumerar exhaustivamente, falla ruidoso), y un
447
+ * `after` que llegue aquí —un cursor que el respaldo nunca dio— es 500 con
448
+ * cero llamadas al driver. La salida: implementar `enumerateRelationsMany`
449
+ * en el driver, o paginar partición a partición con `enumerateRelations`
450
+ * (que es lo que hace `reconcileRelations`).
451
+ */
452
+ async enumerateRelationsMany(partitions, page) {
453
+ if (!Array.isArray(partitions) || partitions.length === 0) {
454
+ throw new AuthorizationConfigError('enumerateRelationsMany: pasa al menos una partición (sin particiones no hay nada que enumerar).');
455
+ }
456
+ for (const partition of partitions)
457
+ assertScope(partition);
458
+ if (!this.#driver.enumerateRelations || !this.#driver.capabilities?.enumerateRelations) {
459
+ throw new UnsupportedOperationError('enumerateRelationsMany', 'ser origen de authz:reconcile de relaciones', 'relations');
460
+ }
461
+ if (typeof this.#driver.enumerateRelationsMany === 'function')
462
+ return this.#driver.enumerateRelationsMany(partitions, page);
463
+ if (page?.after !== undefined) {
464
+ throw new AuthorizationConfigError('enumerateRelationsMany: el driver de relaciones no implementa enumerateRelationsMany y el respaldo del manager (K llamadas ' +
465
+ 'a enumerateRelations) no sabe reanudar con un cursor: `after` no se acepta aquí (reanudar aplicaría el cursor de UNA ' +
466
+ 'partición a todas y perdería tuplas en silencio). Implementa enumerateRelationsMany en el driver, o pagina partición a ' +
467
+ 'partición con enumerateRelations.');
468
+ }
469
+ const tuples = [];
470
+ for (const partition of partitions) {
471
+ const one = await this.#driver.enumerateRelations(partition, page);
472
+ if (one.cursor !== undefined) {
473
+ throw new AuthorizationConfigError(`enumerateRelationsMany: la partición ${scopeKey(partition)} tiene más tuplas de las que caben en una página y el driver ` +
474
+ 'de relaciones no implementa enumerateRelationsMany: el respaldo del manager (K llamadas a enumerateRelations) no ' +
475
+ 'puede emitir un cursor que sepa reanudar K particiones —hasta 2.4.0-alpha.7 lo hacía y perdía tuplas en silencio—. ' +
476
+ 'Implementa enumerateRelationsMany en el driver, o pagina partición a partición con enumerateRelations.');
477
+ }
478
+ tuples.push(...one.tuples);
479
+ }
480
+ return { tuples };
481
+ }
144
482
  #assertSubject(subject, partition) {
145
483
  if (isRelUserset(subject)) {
146
484
  // El userset (`group:g#member`) también se ancla a la partición; su
@@ -1 +1 @@
1
- {"version":3,"file":"manager.js","sourceRoot":"","sources":["../../../src/relations/manager.ts"],"names":[],"mappings":"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"}
1
+ {"version":3,"file":"manager.js","sourceRoot":"","sources":["../../../src/relations/manager.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;;;;;;;;GAsBG;AACH,OAAO,EACL,kBAAkB,EAClB,gCAAgC,EAChC,wBAAwB,EACxB,yBAAyB,EACzB,cAAc,GACf,MAAM,cAAc,CAAA;AACrB,OAAO,EAAE,WAAW,EAAE,aAAa,EAAE,gBAAgB,EAAE,eAAe,EAAE,QAAQ,EAAE,MAAM,gBAAgB,CAAA;AACxG,OAAO,EAAE,OAAO,EAAE,WAAW,EAAE,MAAM,aAAa,CAAA;AAClD,OAAO,EAAE,kBAAkB,EAAE,MAAM,cAAc,CAAA;AAmBjD,OAAO,EAAE,YAAY,EAAE,8BAA8B,EAAE,MAAM,aAAa,CAAA;AAC1E,OAAO,EAAE,sBAAsB,EAAE,wBAAwB,EAAE,MAAM,8BAA8B,CAAA;AAmD/F,MAAM,OAAO,gBAAgB;IAClB,OAAO,CAAiB;IACxB,OAAO,CAAiB;IACxB,QAAQ,CAAyB;IAE1C,YAAY,MAAuB,EAAE,MAAuB,EAAE,UAAmC,EAAE;QACjG,IAAI,OAAO,CAAC,KAAK,KAAK,SAAS,EAAE,CAAC;YAChC,IAAI,CAAC,OAAO,CAAC,OAAO,CAAC,KAAK,CAAC,EAAE,CAAC;gBAC5B,MAAM,IAAI,wBAAwB,CAChC,kEAAkE,OAAO,OAAO,CAAC,KAAK,GAAG,CAC1F,CAAA;YACH,CAAC;YACD,IAAI,OAAO,MAAM,CAAC,SAAS,KAAK,UAAU,EAAE,CAAC;gBAC3C,MAAM,IAAI,wBAAwB,CAChC,oGAAoG;oBAClG,qFAAqF,CACxF,CAAA;YACH,CAAC;YACD,MAAM,GAAG,MAAM,CAAC,SAAS,CAAC,OAAO,CAAC,KAAK,CAAC,CAAA;QAC1C,CAAC;QACD,IAAI,OAAO,CAAC,0BAA0B,KAAK,IAAI,IAAI,MAAM,CAAC,YAAY,EAAE,mBAAmB,KAAK,IAAI,EAAE,CAAC;YACrG,MAAM,IAAI,wBAAwB,CAChC,sEAAsE,OAAO,CAAC,UAAU,IAAI,WAAW,IAAI;gBACzG,gCAAgC,MAAM,CAAC,YAAY,CAAC,CAAC,CAAC,MAAM,CAAC,MAAM,CAAC,YAAY,CAAC,mBAAmB,CAAC,CAAC,CAAC,CAAC,yBAAyB,IAAI;gBACrI,4GAA4G;gBAC5G,+FAA+F;gBAC/F,wDAAwD,CAC3D,CAAA;QACH,CAAC;QACD,IAAI,CAAC,OAAO,GAAG,MAAM,CAAA;QACrB,IAAI,CAAC,OAAO,GAAG,MAAM,CAAA;QACrB,IAAI,CAAC,QAAQ,GAAG,OAAO,CAAA;IACzB,CAAC;IAED;;;;;;OAMG;IACH,oBAAoB,CAAC,OAA+C,EAAE,SAAiB;QACrF,IAAI,OAAO,EAAE,WAAW,KAAK,SAAS,IAAI,OAAO,CAAC,WAAW,KAAK,IAAI;YAAE,OAAM;QAC9E,IAAI,IAAI,CAAC,OAAO,CAAC,YAAY,EAAE,mBAAmB,KAAK,IAAI;YAAE,OAAM;QACnE,MAAM,yBAAyB,CAAC,aAAa,CAC3C,aAAa,SAAS,EAAE,EACxB,IAAI,CAAC,QAAQ,CAAC,UAAU,IAAI,WAAW,EACvC,WAAW,CACZ,CAAA;IACH,CAAC;IAED;;;;;;;;;;OAUG;IACH,cAAc,CAAC,OAA+C;QAC5D,OAAO,OAAO,EAAE,WAAW,KAAK,SAAS,IAAI,OAAO,CAAC,WAAW,KAAK,IAAI,CAAC,CAAC,CAAC,EAAE,CAAC,CAAC,CAAC,EAAE,aAAa,EAAE,IAAI,EAAE,CAAA;IAC1G,CAAC;IAED,wHAAwH;IACxH,QAAQ,CAAC,OAA2C;QAClD,OAAO,OAAO,EAAE,KAAK,CAAC,CAAC,CAAC,EAAE,KAAK,EAAE,OAAO,CAAC,KAAK,EAAE,CAAC,CAAC,CAAC,EAAE,CAAA;IACvD,CAAC;IAED;;;;;;;;;;;;;;;;;;;;;OAqBG;IACH,KAAK,CAAC,MAAM,CAAI,KAAyB,EAAE,EAAoB;QAC7D,IAAI,CAAC;YACH,OAAO,MAAM,EAAE,EAAE,CAAA;QACnB,CAAC;QAAC,OAAO,KAAK,EAAE,CAAC;YACf,IAAI,KAAK,YAAY,gCAAgC,IAAI,cAAc,CAAC,KAAK,CAAC,EAAE,CAAC;gBAC/E,MAAM,IAAI,CAAC,OAAO,CAAC,EAAE,GAAG,KAAK,EAAE,aAAa,EAAE,IAAI,EAAE,CAAC,CAAA;YACvD,CAAC;YACD,MAAM,KAAK,CAAA;QACb,CAAC;IACH,CAAC;IAED;;;;;;;OAOG;IACH,UAAU,CAAC,KAAyB;QAClC,MAAM,IAAI,GAAuB,EAAE,GAAG,KAAK,EAAE,SAAS,EAAE,EAAE,GAAG,KAAK,CAAC,SAAS,EAAE,EAAE,CAAA;QAChF,IAAI,KAAK,CAAC,OAAO,KAAK,SAAS,EAAE,CAAC;YAChC,IAAI,CAAC,OAAO,GAAG,YAAY,CAAC,KAAK,CAAC,OAAO,CAAC;gBACxC,CAAC,CAAC,EAAE,GAAG,KAAK,CAAC,OAAO,EAAE,MAAM,EAAE,EAAE,GAAG,KAAK,CAAC,OAAO,CAAC,MAAM,EAAE,EAAE;gBAC3D,CAAC,CAAC,EAAE,GAAG,KAAK,CAAC,OAAO,EAAE,CAAA;QAC1B,CAAC;QACD,IAAI,KAAK,CAAC,MAAM,KAAK,SAAS;YAAE,IAAI,CAAC,MAAM,GAAG,EAAE,GAAG,KAAK,CAAC,MAAM,EAAE,CAAA;QACjE,IAAI,KAAK,CAAC,KAAK,KAAK,SAAS;YAAE,IAAI,CAAC,KAAK,GAAG,EAAE,GAAG,KAAK,CAAC,KAAK,EAAE,CAAA;QAC9D,IAAI,KAAK,CAAC,SAAS,YAAY,IAAI;YAAE,IAAI,CAAC,SAAS,GAAG,IAAI,IAAI,CAAC,KAAK,CAAC,SAAS,CAAC,OAAO,EAAE,CAAC,CAAA;QACzF,OAAO,IAAI,CAAA;IACb,CAAC;IAED;;;;;;;;OAQG;IACH,KAAK,CAAC,OAAO,CAAC,KAAyB;QACrC,IAAI,CAAC;YACH,MAAM,IAAI,CAAC,QAAQ,CAAC,eAAe,EAAE,CAAC,KAAK,CAAC,CAAA;QAC9C,CAAC;QAAC,OAAO,KAAK,EAAE,CAAC;YACf,MAAM,IAAI,CAAC,eAAe,CAAC,KAAK,EAAE,KAAK,CAAC,CAAA;QAC1C,CAAC;IACH,CAAC;IAED,KAAK,CAAC,eAAe,CAAC,KAAyB,EAAE,KAAc;QAC7D,MAAM,OAAO,GAAG,8CAA8C,KAAK,CAAC,SAAS,+BAA+B,CAAA;QAC5G,IAAI,CAAC;YACH,MAAM,EAAE,OAAO,EAAE,MAAM,EAAE,GAAG,MAAM,MAAM,CAAC,gCAAgC,CAAC,CAAA;YAC1E,MAAM,CAAC,KAAK,CAAC,EAAE,GAAG,EAAE,KAAK,EAAE,KAAK,EAAE,EAAE,OAAO,CAAC,CAAA;QAC9C,CAAC;QAAC,MAAM,CAAC;YACP,oEAAoE;YACpE,OAAO,CAAC,KAAK,CAAC,OAAO,EAAE,KAAK,CAAC,CAAA;QAC/B,CAAC;IACH,CAAC;IAED,iFAAiF;IACjF,MAAM;QACJ,OAAO,IAAI,CAAC,OAAO,CAAA;IACrB,CAAC;IAED;;;;;;;;;;OAUG;IACH,YAAY;QACV,OAAO,8BAA8B,CAAC,IAAI,CAAC,OAAO,CAAC,YAAY,CAAC,CAAA;IAClE,CAAC;IAED;;;;;;;;;;;;;;;;;;;;;OAqBG;IACH,eAAe,CAAC,MAAoC,EAAE,QAAgB;QACpE,sBAAsB,CAAC,IAAI,CAAC,OAAO,EAAE,MAAM,EAAE,QAAQ,CAAC,CAAA;IACxD,CAAC;IAED,mBAAmB,CAAC,MAAoC;QACtD,wBAAwB,CAAC,IAAI,CAAC,OAAO,EAAE,MAAM,CAAC,CAAA;IAChD,CAAC;IAED;;;;;;;OAOG;IACH,eAAe,CAAC,MAAiB;QAC/B,gBAAgB,CAAC,qBAAqB,MAAM,EAAE,IAAI,GAAG,EAAE,MAAM,EAAE,EAAE,CAAC,CAAA;IACpE,CAAC;IAED;;;;;;;;OAQG;IACH,YAAY,CAAC,OAA2C,EAAE,SAAiB;QACzE,IAAI,OAAO,EAAE,KAAK,KAAK,SAAS;YAAE,aAAa,CAAC,OAAO,CAAC,KAAK,CAAC,CAAA;QAC9D,IAAI,IAAI,CAAC,QAAQ,CAAC,YAAY,IAAI,CAAC,OAAO,EAAE,KAAK,EAAE,CAAC;YAClD,MAAM,IAAI,kBAAkB,CAC1B,aAAa,SAAS,2EAA2E,CAClG,CAAA;QACH,CAAC;IACH,CAAC;IAED;;;;;;;;;;;OAWG;IACH,YAAY,CAAC,GAAgB,EAAE,SAAiB;QAC9C,MAAM,MAAM,GAAY,IAAI,CAAC,QAAQ,CAAC,WAAW,EAAE,CAAC,GAAG,CAAC,CAAA;QACxD,IAAI,MAAM,KAAK,SAAS;YAAE,OAAM;QAChC,IAAI,MAAM,KAAK,IAAI,IAAI,OAAQ,MAA6B,CAAC,IAAI,KAAK,UAAU,EAAE,CAAC;YACjF,OAAO,CAAC,OAAO,CAAC,MAAM,CAAC,CAAC,IAAI,CAAC,SAAS,EAAE,GAAG,EAAE,GAAE,CAAC,CAAC,CAAA;QACnD,CAAC;QACD,MAAM,wBAAwB,CAAC,mBAAmB,CAAC,aAAa,SAAS,EAAE,EAAE,MAAM,CAAC,CAAA;IACtF,CAAC;IAED;;;;;;;;;;;OAWG;IACH,gBAAgB,CAAC,SAAiB;QAChC,OAAO,kBAAkB,CAAC,aAAa,SAAS,EAAE,EAAE;YAClD,MAAM,EAAE,WAAW;YACnB,KAAK,EAAE,CAAC,IAAI,CAAC,QAAQ,CAAC,KAAK,IAAI,WAAW,CAAC,EAAE,CAAC,OAAO,EAAE;YACvD,SAAS,EAAE,IAAI,CAAC,QAAQ,CAAC,eAAe;SACzC,CAAC,CAAA;IACJ,CAAC;IAED,KAAK,CAAC,MAAM,CACV,OAAmB,EACnB,QAAgB,EAChB,MAAiB,EACjB,SAAmB,EACnB,OAA8B;QAE9B,IAAI,CAAC,oBAAoB,CAAC,OAAO,EAAE,QAAQ,CAAC,CAAA;QAC5C,MAAM,IAAI,CAAC,gBAAgB,CAAC,QAAQ,CAAC,CAAA;QACrC,IAAI,CAAC,eAAe,CAAC,MAAM,EAAE,QAAQ,CAAC,CAAA;QACtC,IAAI,CAAC,eAAe,CAAC,MAAM,CAAC,CAAA;QAC5B,IAAI,CAAC,YAAY,CAAC,OAAO,EAAE,QAAQ,CAAC,CAAA;QACpC,WAAW,CAAC,SAAS,CAAC,CAAA;QACtB,IAAI,CAAC,cAAc,CAAC,OAAO,EAAE,SAAS,CAAC,CAAA;QACvC,uEAAuE;QACvE,uEAAuE;QACvE,eAAe,CAAC,OAAO,EAAE,SAAS,CAAC,CAAA;QACnC,MAAM,GAAG,GAAgB,EAAE,SAAS,EAAE,QAAQ,EAAE,OAAO,EAAE,QAAQ,EAAE,MAAM,EAAE,SAAS,EAAE,CAAA;QACtF,IAAI,OAAO,IAAI,WAAW,IAAI,OAAO;YAAE,GAAG,CAAC,SAAS,GAAG,OAAO,CAAC,SAAS,CAAA;QACxE,IAAI,CAAC,YAAY,CAAC,GAAG,EAAE,QAAQ,CAAC,CAAA;QAChC,MAAM,KAAK,GAAG,IAAI,CAAC,UAAU,CAAC,EAAE,GAAG,GAAG,EAAE,GAAG,IAAI,CAAC,QAAQ,CAAC,OAAO,CAAC,EAAE,GAAG,IAAI,CAAC,cAAc,CAAC,OAAO,CAAC,EAAE,CAAC,CAAA;QACrG,MAAM,IAAI,CAAC,MAAM,CAAC,KAAK,EAAE,GAAG,EAAE,CAAC,IAAI,CAAC,OAAO,CAAC,MAAM,CAAC,OAAO,EAAE,QAAQ,EAAE,MAAM,EAAE,SAAS,EAAE,OAAO,CAAC,CAAC,CAAA;QAClG,MAAM,IAAI,CAAC,OAAO,CAAC,KAAK,CAAC,CAAA;IAC3B,CAAC;IAED,KAAK,CAAC,QAAQ,CACZ,OAAmB,EACnB,QAAgB,EAChB,MAAiB,EACjB,SAAmB,EACnB,OAA8B;QAE9B,IAAI,CAAC,oBAAoB,CAAC,OAAO,EAAE,UAAU,CAAC,CAAA;QAC9C,MAAM,IAAI,CAAC,gBAAgB,CAAC,UAAU,CAAC,CAAA;QACvC,IAAI,CAAC,eAAe,CAAC,MAAM,EAAE,QAAQ,CAAC,CAAA;QACtC,IAAI,CAAC,eAAe,CAAC,MAAM,CAAC,CAAA;QAC5B,IAAI,CAAC,YAAY,CAAC,OAAO,EAAE,UAAU,CAAC,CAAA;QACtC,WAAW,CAAC,SAAS,CAAC,CAAA;QACtB,IAAI,CAAC,cAAc,CAAC,OAAO,EAAE,SAAS,CAAC,CAAA;QACvC,MAAM,GAAG,GAAgB,EAAE,SAAS,EAAE,UAAU,EAAE,OAAO,EAAE,QAAQ,EAAE,MAAM,EAAE,SAAS,EAAE,CAAA;QACxF,IAAI,CAAC,YAAY,CAAC,GAAG,EAAE,UAAU,CAAC,CAAA;QAClC,MAAM,KAAK,GAAG,IAAI,CAAC,UAAU,CAAC,EAAE,GAAG,GAAG,EAAE,GAAG,IAAI,CAAC,QAAQ,CAAC,OAAO,CAAC,EAAE,GAAG,IAAI,CAAC,cAAc,CAAC,OAAO,CAAC,EAAE,CAAC,CAAA;QACrG,MAAM,IAAI,CAAC,MAAM,CAAC,KAAK,EAAE,GAAG,EAAE,CAAC,IAAI,CAAC,OAAO,CAAC,QAAQ,CAAC,OAAO,EAAE,QAAQ,EAAE,MAAM,EAAE,SAAS,EAAE,OAAO,CAAC,CAAC,CAAA;QACpG,MAAM,IAAI,CAAC,OAAO,CAAC,KAAK,CAAC,CAAA;IAC3B,CAAC;IAED;;;;;;;;;OASG;IACH,KAAK,CAAC,KAAK,CAAC,OAAmB,EAAE,QAAgB,EAAE,MAAiB,EAAE,SAAmB;QACvF,IAAI,CAAC,eAAe,CAAC,MAAM,EAAE,QAAQ,CAAC,CAAA;QACtC,WAAW,CAAC,SAAS,CAAC,CAAA;QACtB,IAAI,CAAC,eAAe,CAAC,MAAM,CAAC,CAAA;QAC5B,IAAI,CAAC,cAAc,CAAC,OAAO,EAAE,SAAS,CAAC,CAAA;QACvC,OAAO,IAAI,CAAC,OAAO,CAAC,KAAK,CAAC,OAAO,EAAE,QAAQ,EAAE,MAAM,EAAE,SAAS,CAAC,CAAA;IACjE,CAAC;IAED,KAAK,CAAC,WAAW,CACf,OAAmB,EACnB,QAAgB,EAChB,UAAkB,EAClB,SAAmB,EACnB,IAAmB;QAEnB,IAAI,CAAC,eAAe,CAAC,EAAE,IAAI,EAAE,UAAU,EAAE,EAAE,QAAQ,CAAC,CAAA;QACpD,WAAW,CAAC,SAAS,CAAC,CAAA;QACtB,IAAI,CAAC,cAAc,CAAC,OAAO,EAAE,SAAS,CAAC,CAAA;QACvC,OAAO,IAAI,CAAC,OAAO,CAAC,WAAW,CAAC,OAAO,EAAE,QAAQ,EAAE,UAAU,EAAE,SAAS,EAAE,IAAI,CAAC,CAAA;IACjF,CAAC;IAED,KAAK,CAAC,YAAY,CAChB,QAAgB,EAChB,MAAiB,EACjB,SAAmB,EACnB,IAAmB;QAEnB,IAAI,CAAC,eAAe,CAAC,MAAM,EAAE,QAAQ,CAAC,CAAA;QACtC,WAAW,CAAC,SAAS,CAAC,CAAA;QACtB,IAAI,CAAC,eAAe,CAAC,MAAM,CAAC,CAAA;QAC5B,OAAO,IAAI,CAAC,OAAO,CAAC,YAAY,CAAC,QAAQ,EAAE,MAAM,EAAE,SAAS,EAAE,IAAI,CAAC,CAAA;IACrE,CAAC;IAED;;;;;;;;;;;;;;;;;;;OAmBG;IACH,KAAK,CAAC,WAAW,CAAC,MAAiB,EAAE,SAAmB,EAAE,OAA8B;QACtF,IAAI,CAAC,oBAAoB,CAAC,OAAO,EAAE,aAAa,CAAC,CAAA;QACjD,MAAM,IAAI,CAAC,gBAAgB,CAAC,aAAa,CAAC,CAAA;QAC1C,IAAI,CAAC,mBAAmB,CAAC,MAAM,CAAC,CAAA;QAChC,WAAW,CAAC,SAAS,CAAC,CAAA;QACtB,IAAI,CAAC,eAAe,CAAC,MAAM,CAAC,CAAA;QAC5B,IAAI,CAAC,YAAY,CAAC,OAAO,EAAE,aAAa,CAAC,CAAA;QACzC,MAAM,KAAK,GAAG,IAAI,CAAC,UAAU,CAAC;YAC5B,SAAS,EAAE,aAAa;YACxB,MAAM;YACN,SAAS;YACT,GAAG,IAAI,CAAC,QAAQ,CAAC,OAAO,CAAC;YACzB,GAAG,IAAI,CAAC,cAAc,CAAC,OAAO,CAAC;SAChC,CAAC,CAAA;QACF,MAAM,IAAI,CAAC,MAAM,CAAC,KAAK,EAAE,GAAG,EAAE,CAAC,IAAI,CAAC,OAAO,CAAC,WAAW,CAAC,MAAM,EAAE,SAAS,EAAE,OAAO,CAAC,CAAC,CAAA;QACpF,MAAM,IAAI,CAAC,OAAO,CAAC,KAAK,CAAC,CAAA;IAC3B,CAAC;IAED,KAAK,CAAC,YAAY,CAAC,OAAmB,EAAE,SAAmB,EAAE,OAA8B;QACzF,IAAI,CAAC,oBAAoB,CAAC,OAAO,EAAE,cAAc,CAAC,CAAA;QAClD,MAAM,IAAI,CAAC,gBAAgB,CAAC,cAAc,CAAC,CAAA;QAC3C,WAAW,CAAC,SAAS,CAAC,CAAA;QACtB,IAAI,CAAC,cAAc,CAAC,OAAO,EAAE,SAAS,CAAC,CAAA;QACvC,IAAI,CAAC,YAAY,CAAC,OAAO,EAAE,cAAc,CAAC,CAAA;QAC1C,MAAM,KAAK,GAAG,IAAI,CAAC,UAAU,CAAC;YAC5B,SAAS,EAAE,cAAc;YACzB,OAAO;YACP,SAAS;YACT,GAAG,IAAI,CAAC,QAAQ,CAAC,OAAO,CAAC;YACzB,GAAG,IAAI,CAAC,cAAc,CAAC,OAAO,CAAC;SAChC,CAAC,CAAA;QACF,MAAM,IAAI,CAAC,MAAM,CAAC,KAAK,EAAE,GAAG,EAAE,CAAC,IAAI,CAAC,OAAO,CAAC,YAAY,CAAC,OAAO,EAAE,SAAS,EAAE,OAAO,CAAC,CAAC,CAAA;QACtF,MAAM,IAAI,CAAC,OAAO,CAAC,KAAK,CAAC,CAAA;IAC3B,CAAC;IAED;;;;;;OAMG;IACH,KAAK,CAAC,SAAS,CACb,MAAiB,EACjB,QAAgB,EAChB,SAAmB,EACnB,IAAmB;QAEnB,0EAA0E;QAC1E,sEAAsE;QACtE,2EAA2E;QAC3E,sEAAsE;QACtE,yEAAyE;QACzE,IAAI,CAAC,eAAe,CAAC,MAAM,EAAE,QAAQ,CAAC,CAAA;QACtC,WAAW,CAAC,SAAS,CAAC,CAAA;QACtB,IAAI,CAAC,eAAe,CAAC,MAAM,CAAC,CAAA;QAC5B,IAAI,CAAC,IAAI,CAAC,OAAO,CAAC,SAAS,IAAI,CAAC,IAAI,CAAC,OAAO,CAAC,YAAY,EAAE,eAAe,EAAE,CAAC;YAC3E,MAAM,IAAI,yBAAyB,CACjC,WAAW,EACX,qCAAqC,EACrC,WAAW,EACX,0FAA0F;gBACxF,uEAAuE,CAC1E,CAAA;QACH,CAAC;QACD,OAAO,IAAI,CAAC,OAAO,CAAC,SAAS,CAAC,MAAM,EAAE,QAAQ,EAAE,SAAS,EAAE,IAAI,CAAC,CAAA;IAClE,CAAC;IAED,oGAAoG;IACpG,KAAK,CAAC,kBAAkB,CAAC,SAAmB,EAAE,IAAmB;QAC/D,WAAW,CAAC,SAAS,CAAC,CAAA;QACtB,IAAI,CAAC,IAAI,CAAC,OAAO,CAAC,kBAAkB,IAAI,CAAC,IAAI,CAAC,OAAO,CAAC,YAAY,EAAE,kBAAkB,EAAE,CAAC;YACvF,MAAM,IAAI,yBAAyB,CACjC,oBAAoB,EACpB,6CAA6C,EAC7C,WAAW,CACZ,CAAA;QACH,CAAC;QACD,OAAO,IAAI,CAAC,OAAO,CAAC,kBAAkB,CAAC,SAAS,EAAE,IAAI,CAAC,CAAA;IACzD,CAAC;IAED;;;;;;;;;;;;;;;;;;;;;OAqBG;IACH,KAAK,CAAC,sBAAsB,CAAC,UAAsB,EAAE,IAAmB;QACtE,IAAI,CAAC,KAAK,CAAC,OAAO,CAAC,UAAU,CAAC,IAAI,UAAU,CAAC,MAAM,KAAK,CAAC,EAAE,CAAC;YAC1D,MAAM,IAAI,wBAAwB,CAAC,iGAAiG,CAAC,CAAA;QACvI,CAAC;QACD,KAAK,MAAM,SAAS,IAAI,UAAU;YAAE,WAAW,CAAC,SAAS,CAAC,CAAA;QAC1D,IAAI,CAAC,IAAI,CAAC,OAAO,CAAC,kBAAkB,IAAI,CAAC,IAAI,CAAC,OAAO,CAAC,YAAY,EAAE,kBAAkB,EAAE,CAAC;YACvF,MAAM,IAAI,yBAAyB,CAAC,wBAAwB,EAAE,6CAA6C,EAAE,WAAW,CAAC,CAAA;QAC3H,CAAC;QACD,IAAI,OAAO,IAAI,CAAC,OAAO,CAAC,sBAAsB,KAAK,UAAU;YAAE,OAAO,IAAI,CAAC,OAAO,CAAC,sBAAsB,CAAC,UAAU,EAAE,IAAI,CAAC,CAAA;QAC3H,IAAI,IAAI,EAAE,KAAK,KAAK,SAAS,EAAE,CAAC;YAC9B,MAAM,IAAI,wBAAwB,CAChC,6HAA6H;gBAC3H,uHAAuH;gBACvH,yHAAyH;gBACzH,mCAAmC,CACtC,CAAA;QACH,CAAC;QACD,MAAM,MAAM,GAAoB,EAAE,CAAA;QAClC,KAAK,MAAM,SAAS,IAAI,UAAU,EAAE,CAAC;YACnC,MAAM,GAAG,GAAG,MAAM,IAAI,CAAC,OAAO,CAAC,kBAAkB,CAAC,SAAS,EAAE,IAAI,CAAC,CAAA;YAClE,IAAI,GAAG,CAAC,MAAM,KAAK,SAAS,EAAE,CAAC;gBAC7B,MAAM,IAAI,wBAAwB,CAChC,wCAAwC,QAAQ,CAAC,SAAS,CAAC,+DAA+D;oBACxH,mHAAmH;oBACnH,qHAAqH;oBACrH,wGAAwG,CAC3G,CAAA;YACH,CAAC;YACD,MAAM,CAAC,IAAI,CAAC,GAAG,GAAG,CAAC,MAAM,CAAC,CAAA;QAC5B,CAAC;QACD,OAAO,EAAE,MAAM,EAAE,CAAA;IACnB,CAAC;IAED,cAAc,CAAC,OAAmB,EAAE,SAAmB;QACrD,IAAI,YAAY,CAAC,OAAO,CAAC,EAAE,CAAC;YAC1B,oEAAoE;YACpE,2EAA2E;YAC3E,IAAI,CAAC,eAAe,CAAC,OAAO,CAAC,MAAM,EAAE,OAAO,CAAC,QAAQ,CAAC,CAAA;YACtD,IAAI,CAAC,eAAe,CAAC,OAAO,CAAC,MAAM,CAAC,CAAA;YACpC,WAAW,CAAC,SAAS,CAAC,CAAA;YACtB,OAAM;QACR,CAAC;QACD,aAAa,CAAC,OAAO,CAAC,CAAA;IACxB,CAAC;CACF"}
@@ -1,3 +1,4 @@
1
+ import type { Clock } from '../clock.js';
1
2
  import type { RelationsDriver, ScopeRef } from '../types.js';
2
3
  import type { RelationsConfig } from './define_relations_config.js';
3
4
  export interface RelationsReconcileOptions {
@@ -5,8 +6,20 @@ export interface RelationsReconcileOptions {
5
6
  from: RelationsDriver;
6
7
  /** El driver al que se ESCRIBEN (destino). Necesita `enumerateRelations` para ver lo que sobra. */
7
8
  to: RelationsDriver;
8
- /** La partición a migrar (mono-tenant: `APP_SCOPE`). El reconcile es POR partición. */
9
- partition: ScopeRef;
9
+ /** La partición a migrar (mono-tenant: `APP_SCOPE`). El reconcile es POR partición. Exactamente uno de `partition` / `partitions`. */
10
+ partition?: ScopeRef;
11
+ /**
12
+ * **Varias particiones en UNA pasada** (2.4.0-alpha.6). Mismo recorrido que
13
+ * `partition` para cada una, pero el ORIGEN y el DESTINO se enumeran UNA
14
+ * vez con `enumerateRelationsMany` si el driver lo trae (en `openfga` eso es
15
+ * un barrido del store en vez de K; medido: 3 particiones 1,4 s → 0,46 s) y,
16
+ * si no, con K llamadas a `enumerateRelations` (correcto, K barridos). El
17
+ * reporte es la SUMA de las K pasadas; el seguro de borrado masivo (R-17)
18
+ * se decide POR partición y ANTES de escribir nada en ninguna: una sola
19
+ * partición que dispare el seguro es 500 sin tocar el destino. Para un
20
+ * desglose por tenant, llama por partición.
21
+ */
22
+ partitions?: ScopeRef[];
10
23
  /** Solo reporta lo que HARÍA; cero escrituras (read-only por contrato, como el de roles). */
11
24
  dryRun?: boolean;
12
25
  /** Borra del destino las tuplas que el origen ya no respalda. Sin él, solo añade. */
@@ -21,11 +34,22 @@ export interface RelationsReconcileOptions {
21
34
  */
22
35
  allowMassDelete?: boolean;
23
36
  /**
24
- * La config del DESTINO, para vigilar la deriva del modelo fusionado en
25
- * `--dry-run`: un tipo de relación presente en el origen que el destino NO
26
- * declara no cabría en su modelo fusionado (se reporta en `modelDrift`).
37
+ * La config del DESTINO. Dos usos: vigilar la deriva del modelo fusionado
38
+ * (un tipo del origen que el destino NO declara se reporta en `modelDrift`)
39
+ * y **embudar F-05 ANTES del driver** (L-0): la tupla cuyo tipo o relación
40
+ * el destino no declara se descarta aquí y se cuenta en
41
+ * `skipped.undeclared`, de modo que `--dry-run` y la pasada real dan los
42
+ * MISMOS números. Sin ella, la embuda el 422 del propio driver del destino
43
+ * (la misma función, `assertRelationDeclared`) y se cuenta igual — pero
44
+ * `--dry-run` no puede anticiparla (la reporta como `written`).
27
45
  */
28
46
  toConfig?: RelationsConfig;
47
+ /**
48
+ * El reloj que decide qué tupla del ORIGEN está CADUCADA (R-15): una caducada
49
+ * no se migra —se cuenta en `skipped.expired`— y no respalda nada en el
50
+ * destino. Default `systemClock`; inyectable para el juez.
51
+ */
52
+ now?: Clock;
29
53
  }
30
54
  export interface RelationsReconcileReport {
31
55
  /** ¿Fue `--dry-run` (sin escrituras)? */
@@ -34,7 +58,13 @@ export interface RelationsReconcileReport {
34
58
  written: number;
35
59
  /** Tuplas que sobraban en el destino y se borraron (solo con `prune`; o que se borrarían). */
36
60
  deleted: number;
37
- /** Tuplas que ya estaban exactamente igual. */
61
+ /**
62
+ * Tuplas que estaban en el destino con OTRA caducidad y se reescribieron con
63
+ * la del origen (R-15; delete+write en ambos drivers, nunca un `Ignore` a
64
+ * ciegas que se quedara la caducidad vieja — la lección S7 de la 3b).
65
+ */
66
+ updated: number;
67
+ /** Tuplas que ya estaban exactamente igual (misma clave y misma caducidad). */
38
68
  unchanged: number;
39
69
  /**
40
70
  * Tuplas del destino que el origen ya no respalda y que NO se borraron por
@@ -52,6 +82,51 @@ export interface RelationsReconcileReport {
52
82
  * (salvo `allowMassDelete`); en `--dry-run` NO lanza y esto lo marca.
53
83
  */
54
84
  massDelete: boolean;
85
+ /**
86
+ * Lo que el origen ENUMERÓ y no se migró, con su motivo:
87
+ * - `expired` (R-15) = tuplas caducadas al instante de la pasada. Es la
88
+ * pérdida DECLARADA de la migración (como `expired` en `authz:reconcile`
89
+ * de roles, 3b-8 · B2): se cuenta, no clava el exit 1. Un origen que las
90
+ * filtrara antes de enumerarlas las haría desaparecer sin rastro; por eso
91
+ * tienen que LLEGAR.
92
+ * - `undeclared` (L-0) = tuplas VIVAS cuyo `object.type` o `relation` el
93
+ * DESTINO no declara (F-05): no se escriben —hasta L-0 `modelDrift` las
94
+ * reportaba y `to.relate` las escribía igual, por el driver— y se cuentan
95
+ * aquí. Es una relación viva que no llegó, así que SÍ es deriva
96
+ * (exit ≠ 0 en el comando): declárala en el destino y repite la pasada.
97
+ */
98
+ skipped: {
99
+ expired: number;
100
+ undeclared: number;
101
+ };
102
+ /**
103
+ * **La ventana durable bajo la que corrió la pasada que ESCRIBE** (L-1 ·
104
+ * J1; paridad con `report.frozen` de `authz:reconcile` de roles). La pone
105
+ * `runRelationsReconcile` (el comando), no esta función —que no ve al
106
+ * manager de roles—; ausente en `--dry-run` (el verificador no congela) y
107
+ * cuando se llama a `reconcileRelations` a pelo. `lapsed: true` = el lease
108
+ * se perdió a mitad ⇒ la pasada NO se certifica (exit ≠ 0).
109
+ */
110
+ /** `untilMs` solo dentro de la ventana del OPERADOR (2.4.0-alpha.10): cuándo caduca, o `null` si no caduca. */
111
+ frozen?: {
112
+ durable: true;
113
+ lapsed: boolean;
114
+ leaseMs: number | null;
115
+ fence: number;
116
+ untilMs?: number | null;
117
+ window?: 'operator' | 'own' | 'enclosing';
118
+ };
119
+ /**
120
+ * **La dirección RANCIA** (2.4.0-alpha.10, S1 de la auditoría de sistema):
121
+ * el destino era el driver de relaciones ACTIVO y el origen otro. La pone
122
+ * `runRelationsReconcile` (esta función no sabe cuál es el activo); sin
123
+ * `allowStaleSource` solo llega en `--dry-run` y es deriva.
124
+ */
125
+ staleSource?: {
126
+ to: string;
127
+ from: string;
128
+ allowed: boolean;
129
+ };
55
130
  }
56
131
  /**
57
132
  * Migra las tuplas de relación de `from` a `to` en `partition`. Idempotente
@@ -1 +1 @@
1
- {"version":3,"file":"reconcile.d.ts","sourceRoot":"","sources":["../../../src/relations/reconcile.ts"],"names":[],"mappings":"AAwBA,OAAO,KAAK,EAA6B,eAAe,EAAE,QAAQ,EAAE,MAAM,aAAa,CAAA;AACvF,OAAO,KAAK,EAAE,eAAe,EAAE,MAAM,8BAA8B,CAAA;AAkBnE,MAAM,WAAW,yBAAyB;IACxC,oFAAoF;IACpF,IAAI,EAAE,eAAe,CAAA;IACrB,mGAAmG;IACnG,EAAE,EAAE,eAAe,CAAA;IACnB,uFAAuF;IACvF,SAAS,EAAE,QAAQ,CAAA;IACnB,6FAA6F;IAC7F,MAAM,CAAC,EAAE,OAAO,CAAA;IAChB,qFAAqF;IACrF,KAAK,CAAC,EAAE,OAAO,CAAA;IACf;;;;;;;OAOG;IACH,eAAe,CAAC,EAAE,OAAO,CAAA;IACzB;;;;OAIG;IACH,QAAQ,CAAC,EAAE,eAAe,CAAA;CAC3B;AAED,MAAM,WAAW,wBAAwB;IACvC,yCAAyC;IACzC,MAAM,EAAE,OAAO,CAAA;IACf,mFAAmF;IACnF,OAAO,EAAE,MAAM,CAAA;IACf,8FAA8F;IAC9F,OAAO,EAAE,MAAM,CAAA;IACf,+CAA+C;IAC/C,SAAS,EAAE,MAAM,CAAA;IACjB;;;OAGG;IACH,KAAK,EAAE,MAAM,CAAA;IACb;;;OAGG;IACH,UAAU,EAAE,MAAM,EAAE,CAAA;IACpB;;;;OAIG;IACH,UAAU,EAAE,OAAO,CAAA;CACpB;AA8BD;;;;GAIG;AACH,wBAAsB,kBAAkB,CAAC,OAAO,EAAE,yBAAyB,GAAG,OAAO,CAAC,wBAAwB,CAAC,CAyE9G"}
1
+ {"version":3,"file":"reconcile.d.ts","sourceRoot":"","sources":["../../../src/relations/reconcile.ts"],"names":[],"mappings":"AAqCA,OAAO,KAAK,EAAE,KAAK,EAAE,MAAM,aAAa,CAAA;AAGxC,OAAO,KAAK,EAA6B,eAAe,EAAE,QAAQ,EAAE,MAAM,aAAa,CAAA;AACvF,OAAO,KAAK,EAAE,eAAe,EAAE,MAAM,8BAA8B,CAAA;AAkBnE,MAAM,WAAW,yBAAyB;IACxC,oFAAoF;IACpF,IAAI,EAAE,eAAe,CAAA;IACrB,mGAAmG;IACnG,EAAE,EAAE,eAAe,CAAA;IACnB,sIAAsI;IACtI,SAAS,CAAC,EAAE,QAAQ,CAAA;IACpB;;;;;;;;;;OAUG;IACH,UAAU,CAAC,EAAE,QAAQ,EAAE,CAAA;IACvB,6FAA6F;IAC7F,MAAM,CAAC,EAAE,OAAO,CAAA;IAChB,qFAAqF;IACrF,KAAK,CAAC,EAAE,OAAO,CAAA;IACf;;;;;;;OAOG;IACH,eAAe,CAAC,EAAE,OAAO,CAAA;IACzB;;;;;;;;;OASG;IACH,QAAQ,CAAC,EAAE,eAAe,CAAA;IAC1B;;;;OAIG;IACH,GAAG,CAAC,EAAE,KAAK,CAAA;CACZ;AAED,MAAM,WAAW,wBAAwB;IACvC,yCAAyC;IACzC,MAAM,EAAE,OAAO,CAAA;IACf,mFAAmF;IACnF,OAAO,EAAE,MAAM,CAAA;IACf,8FAA8F;IAC9F,OAAO,EAAE,MAAM,CAAA;IACf;;;;OAIG;IACH,OAAO,EAAE,MAAM,CAAA;IACf,+EAA+E;IAC/E,SAAS,EAAE,MAAM,CAAA;IACjB;;;OAGG;IACH,KAAK,EAAE,MAAM,CAAA;IACb;;;OAGG;IACH,UAAU,EAAE,MAAM,EAAE,CAAA;IACpB;;;;OAIG;IACH,UAAU,EAAE,OAAO,CAAA;IACnB;;;;;;;;;;;;OAYG;IACH,OAAO,EAAE;QAAE,OAAO,EAAE,MAAM,CAAC;QAAC,UAAU,EAAE,MAAM,CAAA;KAAE,CAAA;IAChD;;;;;;;OAOG;IACH,+GAA+G;IAC/G,MAAM,CAAC,EAAE;QAAE,OAAO,EAAE,IAAI,CAAC;QAAC,MAAM,EAAE,OAAO,CAAC;QAAC,OAAO,EAAE,MAAM,GAAG,IAAI,CAAC;QAAC,KAAK,EAAE,MAAM,CAAC;QAAC,OAAO,CAAC,EAAE,MAAM,GAAG,IAAI,CAAC;QAAC,MAAM,CAAC,EAAE,UAAU,GAAG,KAAK,GAAG,WAAW,CAAA;KAAE,CAAA;IACtJ;;;;;OAKG;IACH,WAAW,CAAC,EAAE;QAAE,EAAE,EAAE,MAAM,CAAC;QAAC,IAAI,EAAE,MAAM,CAAC;QAAC,OAAO,EAAE,OAAO,CAAA;KAAE,CAAA;CAC7D;AA0DD;;;;GAIG;AACH,wBAAsB,kBAAkB,CAAC,OAAO,EAAE,yBAAyB,GAAG,OAAO,CAAC,wBAAwB,CAAC,CA0F9G"}