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

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (210) hide show
  1. package/README.md +462 -35
  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 +73 -0
  21. package/build/commands/authz_relations_reconcile.d.ts.map +1 -0
  22. package/build/commands/authz_relations_reconcile.js +225 -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 +39 -10
  45. package/build/index.d.ts.map +1 -1
  46. package/build/index.js +35 -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 +48 -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 +101 -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 +86 -4
  68. package/build/src/drivers/database_driver.d.ts.map +1 -1
  69. package/build/src/drivers/database_driver.js +425 -11
  70. package/build/src/drivers/database_driver.js.map +1 -1
  71. package/build/src/drivers/database_relations_driver.d.ts +75 -0
  72. package/build/src/drivers/database_relations_driver.d.ts.map +1 -0
  73. package/build/src/drivers/database_relations_driver.js +450 -0
  74. package/build/src/drivers/database_relations_driver.js.map +1 -0
  75. package/build/src/drivers/openfga_driver.d.ts +713 -119
  76. package/build/src/drivers/openfga_driver.d.ts.map +1 -1
  77. package/build/src/drivers/openfga_driver.js +2048 -476
  78. package/build/src/drivers/openfga_driver.js.map +1 -1
  79. package/build/src/drivers/openfga_facts.d.ts +369 -0
  80. package/build/src/drivers/openfga_facts.d.ts.map +1 -0
  81. package/build/src/drivers/openfga_facts.js +813 -0
  82. package/build/src/drivers/openfga_facts.js.map +1 -0
  83. package/build/src/drivers/openfga_relations_driver.d.ts +120 -0
  84. package/build/src/drivers/openfga_relations_driver.d.ts.map +1 -0
  85. package/build/src/drivers/openfga_relations_driver.js +466 -0
  86. package/build/src/drivers/openfga_relations_driver.js.map +1 -0
  87. package/build/src/errors.d.ts +258 -5
  88. package/build/src/errors.d.ts.map +1 -1
  89. package/build/src/errors.js +238 -7
  90. package/build/src/errors.js.map +1 -1
  91. package/build/src/freeze.d.ts +120 -0
  92. package/build/src/freeze.d.ts.map +1 -0
  93. package/build/src/freeze.js +172 -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 +315 -4
  106. package/build/src/manager.d.ts.map +1 -1
  107. package/build/src/manager.js +1187 -181
  108. package/build/src/manager.js.map +1 -1
  109. package/build/src/models/authz_assignment.d.ts +6 -6
  110. package/build/src/models/authz_assignment.d.ts.map +1 -1
  111. package/build/src/models/authz_deny.d.ts +6 -6
  112. package/build/src/models/authz_deny.d.ts.map +1 -1
  113. package/build/src/models/authz_permission.d.ts +6 -6
  114. package/build/src/models/authz_permission.d.ts.map +1 -1
  115. package/build/src/models/authz_role.d.ts +6 -6
  116. package/build/src/models/authz_role.d.ts.map +1 -1
  117. package/build/src/models/authz_role_permission.d.ts +6 -6
  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 +85 -0
  130. package/build/src/relation_partition_trigger.js.map +1 -0
  131. package/build/src/relations/define_relations_config.d.ts +58 -0
  132. package/build/src/relations/define_relations_config.d.ts.map +1 -0
  133. package/build/src/relations/define_relations_config.js +144 -0
  134. package/build/src/relations/define_relations_config.js.map +1 -0
  135. package/build/src/relations/manager.d.ts +38 -0
  136. package/build/src/relations/manager.d.ts.map +1 -0
  137. package/build/src/relations/manager.js +156 -0
  138. package/build/src/relations/manager.js.map +1 -0
  139. package/build/src/relations/reconcile.d.ts +62 -0
  140. package/build/src/relations/reconcile.d.ts.map +1 -0
  141. package/build/src/relations/reconcile.js +138 -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 +291 -0
  150. package/build/src/scope_outbox.js.map +1 -0
  151. package/build/src/{drivers → shared}/backend_guard.d.ts +14 -0
  152. package/build/src/shared/backend_guard.d.ts.map +1 -0
  153. package/build/src/{drivers → shared}/backend_guard.js +26 -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/sql_descendants.d.ts +47 -1
  158. package/build/src/sql_descendants.d.ts.map +1 -1
  159. package/build/src/sql_descendants.js +75 -1
  160. package/build/src/sql_descendants.js.map +1 -1
  161. package/build/src/testing/contract.d.ts +74 -0
  162. package/build/src/testing/contract.d.ts.map +1 -1
  163. package/build/src/testing/contract.js +672 -169
  164. package/build/src/testing/contract.js.map +1 -1
  165. package/build/src/testing/main.d.ts +6 -0
  166. package/build/src/testing/main.d.ts.map +1 -1
  167. package/build/src/testing/main.js +3 -0
  168. package/build/src/testing/main.js.map +1 -1
  169. package/build/src/testing/migration_contract.d.ts +284 -0
  170. package/build/src/testing/migration_contract.d.ts.map +1 -0
  171. package/build/src/testing/migration_contract.js +586 -0
  172. package/build/src/testing/migration_contract.js.map +1 -0
  173. package/build/src/testing/relations_contract.d.ts +51 -0
  174. package/build/src/testing/relations_contract.d.ts.map +1 -0
  175. package/build/src/testing/relations_contract.js +654 -0
  176. package/build/src/testing/relations_contract.js.map +1 -0
  177. package/build/src/testing/relations_reconcile_contract.d.ts +24 -0
  178. package/build/src/testing/relations_reconcile_contract.d.ts.map +1 -0
  179. package/build/src/testing/relations_reconcile_contract.js +172 -0
  180. package/build/src/testing/relations_reconcile_contract.js.map +1 -0
  181. package/build/src/traits/authz_scopes.js +1 -1
  182. package/build/src/traits/authz_scopes.js.map +1 -1
  183. package/build/src/traits/has_uuid.d.ts +7 -7
  184. package/build/src/traits/has_uuid.d.ts.map +1 -1
  185. package/build/src/types.d.ts +865 -82
  186. package/build/src/types.d.ts.map +1 -1
  187. package/build/src/types.js +10 -0
  188. package/build/src/types.js.map +1 -1
  189. package/build/stubs/config/authorization.stub +104 -4
  190. package/build/stubs/migration.stub +126 -0
  191. package/build/stubs/scopes_outbox_migration.stub +57 -0
  192. package/package.json +4 -2
  193. package/build/commands/openfga_import.d.ts +0 -34
  194. package/build/commands/openfga_import.d.ts.map +0 -1
  195. package/build/commands/openfga_import.js +0 -97
  196. package/build/commands/openfga_import.js.map +0 -1
  197. package/build/src/catalog.d.ts.map +0 -1
  198. package/build/src/catalog.js.map +0 -1
  199. package/build/src/catalog_cache.d.ts.map +0 -1
  200. package/build/src/catalog_cache.js.map +0 -1
  201. package/build/src/drivers/backend_guard.d.ts.map +0 -1
  202. package/build/src/drivers/backend_guard.js.map +0 -1
  203. package/build/src/drivers/sql_expiry.d.ts.map +0 -1
  204. package/build/src/drivers/sql_expiry.js.map +0 -1
  205. package/build/src/middleware/app_access_middleware.d.ts.map +0 -1
  206. package/build/src/middleware/app_access_middleware.js.map +0 -1
  207. /package/build/src/{middleware → http}/app_access_middleware.d.ts +0 -0
  208. /package/build/src/{middleware → http}/app_access_middleware.js +0 -0
  209. /package/build/src/{drivers → shared}/sql_expiry.d.ts +0 -0
  210. /package/build/src/{drivers → shared}/sql_expiry.js +0 -0
@@ -8,6 +8,22 @@
8
8
  * el driver: un consumidor solo-database arranca sin el SDK instalado, y
9
9
  * `scripts/check_purity.mjs` (regla 3) lo vigila en cada build.
10
10
  */
11
- export { OpenFgaAuthorizationDriver, openFgaAuthorizationModel, provisionOpenFgaStore, importAuthzFactsToOpenFga, assertHolderTypes, parseBindingId, correlateBatchResults, isDuplicateWrite, DEFAULT_TIMEOUT_MS, } from './drivers/openfga_driver.js';
12
- export type { HolderTypeMap, OpenFgaDriverOptions, ImportFactsOptions, ImportFactsResult, } from './drivers/openfga_driver.js';
11
+ export { OpenFgaAuthorizationDriver, provisionOpenFgaStore, assertHolderTypes, parseBindingId, correlateBatchResults, isDuplicateWrite, DEFAULT_TIMEOUT_MS, } from './drivers/openfga_driver.js';
12
+ export type { HolderTypeMap, OpenFgaDriverOptions } from './drivers/openfga_driver.js';
13
+ /**
14
+ * El driver `openfga` del puerto `RelationsDriver` (Fase 4, lote 4-4): ReBAC
15
+ * sobre el MISMO store y `modelId` que el driver `facts` de roles. Vive detrás
16
+ * de esta puerta como el resto de lo que toca `@openfga/sdk`.
17
+ */
18
+ export { OpenFgaRelationsDriver } from './drivers/openfga_relations_driver.js';
19
+ export type { OpenFgaRelationsDriverOptions } from './drivers/openfga_relations_driver.js';
20
+ /**
21
+ * El modelo (c2r) y la proyección del catálogo (3b-2a; desde 3b-2k · K2 es
22
+ * el ÚNICO modelo: `openFgaAuthorizationModel` —el del modo `resolver`— y
23
+ * `importAuthzFactsToOpenFga` se borraron con él). Sin `@openfga/sdk` —es
24
+ * JSON y cadenas—, pero se publica por esta misma puerta: es material de
25
+ * OpenFGA y solo lo usa quien lo elige.
26
+ */
27
+ export { openFgaFactsModel, factsRelationsOf, factsRelationMap, factsCatalogTuples, factsTupleId, factsModelBytes, assertFactsModelPublishable, assertFgaObjectId, FACTS_MODEL_MAX_BYTES, FACTS_MODEL_WARN_RATIO, FGA_MAX_RELATION_NAME, FGA_MAX_OBJECT_ID, FACTS_MAX_RESOLVE_DEPTH, FGA_MAX_BATCH_CHECK, factsScopeObject, factsParentTuple, FACTS_SCOPE_TYPE, FACTS_PARENT_RELATION, factsRootTuples, FACTS_ROOTED_RELATION, factsRelationTypeDefinitions, assertRelationsConfigPublishable, RESERVED_FACTS_TYPES, FACTS_GROUP_TYPE, FACTS_GROUP_MEMBER_RELATION, } from './drivers/openfga_facts.js';
28
+ export type { FactsRelations, FactsCatalogTuple, FactsTuple, FactsRelationsConfig, RelationObjectType, RelationObjectRelation, } from './drivers/openfga_facts.js';
13
29
  //# sourceMappingURL=openfga.d.ts.map
@@ -1 +1 @@
1
- {"version":3,"file":"openfga.d.ts","sourceRoot":"","sources":["../../src/openfga.ts"],"names":[],"mappings":"AAAA;;;;;;;;;GASG;AACH,OAAO,EACL,0BAA0B,EAC1B,yBAAyB,EACzB,qBAAqB,EACrB,yBAAyB,EACzB,iBAAiB,EACjB,cAAc,EACd,qBAAqB,EACrB,gBAAgB,EAChB,kBAAkB,GACnB,MAAM,6BAA6B,CAAA;AACpC,YAAY,EACV,aAAa,EACb,oBAAoB,EACpB,kBAAkB,EAClB,iBAAiB,GAClB,MAAM,6BAA6B,CAAA"}
1
+ {"version":3,"file":"openfga.d.ts","sourceRoot":"","sources":["../../src/openfga.ts"],"names":[],"mappings":"AAAA;;;;;;;;;GASG;AACH,OAAO,EACL,0BAA0B,EAC1B,qBAAqB,EACrB,iBAAiB,EACjB,cAAc,EACd,qBAAqB,EACrB,gBAAgB,EAChB,kBAAkB,GACnB,MAAM,6BAA6B,CAAA;AACpC,YAAY,EAAE,aAAa,EAAE,oBAAoB,EAAE,MAAM,6BAA6B,CAAA;AAEtF;;;;GAIG;AACH,OAAO,EAAE,sBAAsB,EAAE,MAAM,uCAAuC,CAAA;AAC9E,YAAY,EAAE,6BAA6B,EAAE,MAAM,uCAAuC,CAAA;AAE1F;;;;;;GAMG;AACH,OAAO,EACL,iBAAiB,EACjB,gBAAgB,EAChB,gBAAgB,EAChB,kBAAkB,EAClB,YAAY,EACZ,eAAe,EACf,2BAA2B,EAC3B,iBAAiB,EACjB,qBAAqB,EACrB,sBAAsB,EACtB,qBAAqB,EACrB,iBAAiB,EACjB,uBAAuB,EACvB,mBAAmB,EACnB,gBAAgB,EAChB,gBAAgB,EAChB,gBAAgB,EAChB,qBAAqB,EACrB,eAAe,EACf,qBAAqB,EACrB,4BAA4B,EAC5B,gCAAgC,EAChC,oBAAoB,EACpB,gBAAgB,EAChB,2BAA2B,GAC5B,MAAM,4BAA4B,CAAA;AACnC,YAAY,EACV,cAAc,EACd,iBAAiB,EACjB,UAAU,EACV,oBAAoB,EACpB,kBAAkB,EAClB,sBAAsB,GACvB,MAAM,4BAA4B,CAAA"}
@@ -8,5 +8,19 @@
8
8
  * el driver: un consumidor solo-database arranca sin el SDK instalado, y
9
9
  * `scripts/check_purity.mjs` (regla 3) lo vigila en cada build.
10
10
  */
11
- export { OpenFgaAuthorizationDriver, openFgaAuthorizationModel, provisionOpenFgaStore, importAuthzFactsToOpenFga, assertHolderTypes, parseBindingId, correlateBatchResults, isDuplicateWrite, DEFAULT_TIMEOUT_MS, } from './drivers/openfga_driver.js';
11
+ export { OpenFgaAuthorizationDriver, provisionOpenFgaStore, assertHolderTypes, parseBindingId, correlateBatchResults, isDuplicateWrite, DEFAULT_TIMEOUT_MS, } from './drivers/openfga_driver.js';
12
+ /**
13
+ * El driver `openfga` del puerto `RelationsDriver` (Fase 4, lote 4-4): ReBAC
14
+ * sobre el MISMO store y `modelId` que el driver `facts` de roles. Vive detrás
15
+ * de esta puerta como el resto de lo que toca `@openfga/sdk`.
16
+ */
17
+ export { OpenFgaRelationsDriver } from './drivers/openfga_relations_driver.js';
18
+ /**
19
+ * El modelo (c2r) y la proyección del catálogo (3b-2a; desde 3b-2k · K2 es
20
+ * el ÚNICO modelo: `openFgaAuthorizationModel` —el del modo `resolver`— y
21
+ * `importAuthzFactsToOpenFga` se borraron con él). Sin `@openfga/sdk` —es
22
+ * JSON y cadenas—, pero se publica por esta misma puerta: es material de
23
+ * OpenFGA y solo lo usa quien lo elige.
24
+ */
25
+ export { openFgaFactsModel, factsRelationsOf, factsRelationMap, factsCatalogTuples, factsTupleId, factsModelBytes, assertFactsModelPublishable, assertFgaObjectId, FACTS_MODEL_MAX_BYTES, FACTS_MODEL_WARN_RATIO, FGA_MAX_RELATION_NAME, FGA_MAX_OBJECT_ID, FACTS_MAX_RESOLVE_DEPTH, FGA_MAX_BATCH_CHECK, factsScopeObject, factsParentTuple, FACTS_SCOPE_TYPE, FACTS_PARENT_RELATION, factsRootTuples, FACTS_ROOTED_RELATION, factsRelationTypeDefinitions, assertRelationsConfigPublishable, RESERVED_FACTS_TYPES, FACTS_GROUP_TYPE, FACTS_GROUP_MEMBER_RELATION, } from './drivers/openfga_facts.js';
12
26
  //# sourceMappingURL=openfga.js.map
@@ -1 +1 @@
1
- {"version":3,"file":"openfga.js","sourceRoot":"","sources":["../../src/openfga.ts"],"names":[],"mappings":"AAAA;;;;;;;;;GASG;AACH,OAAO,EACL,0BAA0B,EAC1B,yBAAyB,EACzB,qBAAqB,EACrB,yBAAyB,EACzB,iBAAiB,EACjB,cAAc,EACd,qBAAqB,EACrB,gBAAgB,EAChB,kBAAkB,GACnB,MAAM,6BAA6B,CAAA"}
1
+ {"version":3,"file":"openfga.js","sourceRoot":"","sources":["../../src/openfga.ts"],"names":[],"mappings":"AAAA;;;;;;;;;GASG;AACH,OAAO,EACL,0BAA0B,EAC1B,qBAAqB,EACrB,iBAAiB,EACjB,cAAc,EACd,qBAAqB,EACrB,gBAAgB,EAChB,kBAAkB,GACnB,MAAM,6BAA6B,CAAA;AAGpC;;;;GAIG;AACH,OAAO,EAAE,sBAAsB,EAAE,MAAM,uCAAuC,CAAA;AAG9E;;;;;;GAMG;AACH,OAAO,EACL,iBAAiB,EACjB,gBAAgB,EAChB,gBAAgB,EAChB,kBAAkB,EAClB,YAAY,EACZ,eAAe,EACf,2BAA2B,EAC3B,iBAAiB,EACjB,qBAAqB,EACrB,sBAAsB,EACtB,qBAAqB,EACrB,iBAAiB,EACjB,uBAAuB,EACvB,mBAAmB,EACnB,gBAAgB,EAChB,gBAAgB,EAChB,gBAAgB,EAChB,qBAAqB,EACrB,eAAe,EACf,qBAAqB,EACrB,4BAA4B,EAC5B,gCAAgC,EAChC,oBAAoB,EACpB,gBAAgB,EAChB,2BAA2B,GAC5B,MAAM,4BAA4B,CAAA"}
@@ -0,0 +1,37 @@
1
+ /**
2
+ * Piezas COMPARTIDAS de `authz:reconcile` (3b-3b): lo que las dos
3
+ * direcciones —`--to=openfga` (3b-3a) y `--to=database`— tienen que decidir
4
+ * igual o el reporte deja de significar lo mismo según hacia dónde se migre.
5
+ *
6
+ * Vive aquí y no en un driver porque el driver `database` no puede importar
7
+ * del `openfga` (arrastraría el SDK, que es una peer dependency opcional) y
8
+ * porque duplicar la normalización de `batchSize`, la cota del volcado o la
9
+ * suma de fases es la forma más barata de que las dos direcciones cuenten
10
+ * distinto. Módulo puro: sin base de datos, sin red y sin `#aliases` del
11
+ * consumidor (`check:purity`).
12
+ */
13
+ import type { ReconcileCounts } from './types.js';
14
+ /** Filas por lote en el ORIGEN y operaciones por escritura en el destino. */
15
+ export declare const RECONCILE_BATCH = 100;
16
+ /**
17
+ * Cómo se NOMBRA el origen cuando los hechos son las tablas del paquete
18
+ * (3b-5). No es un driver: es el esquema PUBLICADO, y por eso tiene nombre
19
+ * propio en el reporte —«de dónde salieron los hechos» es la diferencia
20
+ * entre una migración y una pasada contra el driver activo—.
21
+ */
22
+ export declare const AUTHZ_TABLES_ORIGIN = "authz_assignments/authz_denies";
23
+ /** Tope de filas del reporte que se nombran una a una (el resto solo se cuenta). */
24
+ export declare const RECONCILE_MAX_DETAILS = 200;
25
+ /** Las cuatro fases de una pasada; en `--to=database` las tres primeras son cero. */
26
+ export type ReconcileFamily = 'root' | 'catalog' | 'tree' | 'facts';
27
+ export declare function reconcileBatchSize(value: number | undefined): number;
28
+ /**
29
+ * La cota DECLARADA del volcado (3b-3b · B5). No es una promesa de memoria:
30
+ * es el número por encima del cual la pasada se niega con
31
+ * `E_AUTHZ_RECONCILE_TOO_LARGE` en vez de intentarlo y morir a medias.
32
+ */
33
+ export declare function reconcileMaxTuples(value: number | undefined): number;
34
+ export declare function emptyReconcileCounts(): ReconcileCounts;
35
+ export declare function emptyReconcilePhases(): Record<ReconcileFamily, ReconcileCounts>;
36
+ export declare function sumReconcilePhases(phases: Record<ReconcileFamily, ReconcileCounts>): ReconcileCounts;
37
+ //# sourceMappingURL=reconcile.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"reconcile.d.ts","sourceRoot":"","sources":["../../src/reconcile.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;GAWG;AAIH,OAAO,KAAK,EAAE,eAAe,EAAE,MAAM,YAAY,CAAA;AAEjD,6EAA6E;AAC7E,eAAO,MAAM,eAAe,MAAM,CAAA;AAElC;;;;;GAKG;AACH,eAAO,MAAM,mBAAmB,mCAAmC,CAAA;AAEnE,oFAAoF;AACpF,eAAO,MAAM,qBAAqB,MAAM,CAAA;AAExC,qFAAqF;AACrF,MAAM,MAAM,eAAe,GAAG,MAAM,GAAG,SAAS,GAAG,MAAM,GAAG,OAAO,CAAA;AAEnE,wBAAgB,kBAAkB,CAAC,KAAK,EAAE,MAAM,GAAG,SAAS,GAAG,MAAM,CAMpE;AAED;;;;GAIG;AACH,wBAAgB,kBAAkB,CAAC,KAAK,EAAE,MAAM,GAAG,SAAS,GAAG,MAAM,CAMpE;AAED,wBAAgB,oBAAoB,IAAI,eAAe,CAEtD;AAED,wBAAgB,oBAAoB,IAAI,MAAM,CAAC,eAAe,EAAE,eAAe,CAAC,CAO/E;AAED,wBAAgB,kBAAkB,CAAC,MAAM,EAAE,MAAM,CAAC,eAAe,EAAE,eAAe,CAAC,GAAG,eAAe,CAUpG"}
@@ -0,0 +1,69 @@
1
+ /**
2
+ * Piezas COMPARTIDAS de `authz:reconcile` (3b-3b): lo que las dos
3
+ * direcciones —`--to=openfga` (3b-3a) y `--to=database`— tienen que decidir
4
+ * igual o el reporte deja de significar lo mismo según hacia dónde se migre.
5
+ *
6
+ * Vive aquí y no en un driver porque el driver `database` no puede importar
7
+ * del `openfga` (arrastraría el SDK, que es una peer dependency opcional) y
8
+ * porque duplicar la normalización de `batchSize`, la cota del volcado o la
9
+ * suma de fases es la forma más barata de que las dos direcciones cuenten
10
+ * distinto. Módulo puro: sin base de datos, sin red y sin `#aliases` del
11
+ * consumidor (`check:purity`).
12
+ */
13
+ import { AuthorizationConfigError } from './errors.js';
14
+ import { DEFAULT_RECONCILE_MAX_TUPLES } from './types.js';
15
+ /** Filas por lote en el ORIGEN y operaciones por escritura en el destino. */
16
+ export const RECONCILE_BATCH = 100;
17
+ /**
18
+ * Cómo se NOMBRA el origen cuando los hechos son las tablas del paquete
19
+ * (3b-5). No es un driver: es el esquema PUBLICADO, y por eso tiene nombre
20
+ * propio en el reporte —«de dónde salieron los hechos» es la diferencia
21
+ * entre una migración y una pasada contra el driver activo—.
22
+ */
23
+ export const AUTHZ_TABLES_ORIGIN = 'authz_assignments/authz_denies';
24
+ /** Tope de filas del reporte que se nombran una a una (el resto solo se cuenta). */
25
+ export const RECONCILE_MAX_DETAILS = 200;
26
+ export function reconcileBatchSize(value) {
27
+ if (value === undefined)
28
+ return RECONCILE_BATCH;
29
+ if (!Number.isInteger(value) || value < 1) {
30
+ throw new AuthorizationConfigError(`authz:reconcile: batchSize debe ser un entero >= 1 (llegó ${String(value)})`);
31
+ }
32
+ return value;
33
+ }
34
+ /**
35
+ * La cota DECLARADA del volcado (3b-3b · B5). No es una promesa de memoria:
36
+ * es el número por encima del cual la pasada se niega con
37
+ * `E_AUTHZ_RECONCILE_TOO_LARGE` en vez de intentarlo y morir a medias.
38
+ */
39
+ export function reconcileMaxTuples(value) {
40
+ if (value === undefined)
41
+ return DEFAULT_RECONCILE_MAX_TUPLES;
42
+ if (!Number.isInteger(value) || value < 1) {
43
+ throw new AuthorizationConfigError(`authz:reconcile: maxTuples debe ser un entero >= 1 (llegó ${String(value)})`);
44
+ }
45
+ return value;
46
+ }
47
+ export function emptyReconcileCounts() {
48
+ return { written: 0, updated: 0, unchanged: 0, extra: 0, deleted: 0 };
49
+ }
50
+ export function emptyReconcilePhases() {
51
+ return {
52
+ root: emptyReconcileCounts(),
53
+ catalog: emptyReconcileCounts(),
54
+ tree: emptyReconcileCounts(),
55
+ facts: emptyReconcileCounts(),
56
+ };
57
+ }
58
+ export function sumReconcilePhases(phases) {
59
+ const total = emptyReconcileCounts();
60
+ for (const counts of Object.values(phases)) {
61
+ total.written += counts.written;
62
+ total.updated += counts.updated;
63
+ total.unchanged += counts.unchanged;
64
+ total.extra += counts.extra;
65
+ total.deleted += counts.deleted;
66
+ }
67
+ return total;
68
+ }
69
+ //# sourceMappingURL=reconcile.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"reconcile.js","sourceRoot":"","sources":["../../src/reconcile.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;GAWG;AAEH,OAAO,EAAE,wBAAwB,EAAE,MAAM,aAAa,CAAA;AACtD,OAAO,EAAE,4BAA4B,EAAE,MAAM,YAAY,CAAA;AAGzD,6EAA6E;AAC7E,MAAM,CAAC,MAAM,eAAe,GAAG,GAAG,CAAA;AAElC;;;;;GAKG;AACH,MAAM,CAAC,MAAM,mBAAmB,GAAG,gCAAgC,CAAA;AAEnE,oFAAoF;AACpF,MAAM,CAAC,MAAM,qBAAqB,GAAG,GAAG,CAAA;AAKxC,MAAM,UAAU,kBAAkB,CAAC,KAAyB;IAC1D,IAAI,KAAK,KAAK,SAAS;QAAE,OAAO,eAAe,CAAA;IAC/C,IAAI,CAAC,MAAM,CAAC,SAAS,CAAC,KAAK,CAAC,IAAI,KAAK,GAAG,CAAC,EAAE,CAAC;QAC1C,MAAM,IAAI,wBAAwB,CAAC,6DAA6D,MAAM,CAAC,KAAK,CAAC,GAAG,CAAC,CAAA;IACnH,CAAC;IACD,OAAO,KAAK,CAAA;AACd,CAAC;AAED;;;;GAIG;AACH,MAAM,UAAU,kBAAkB,CAAC,KAAyB;IAC1D,IAAI,KAAK,KAAK,SAAS;QAAE,OAAO,4BAA4B,CAAA;IAC5D,IAAI,CAAC,MAAM,CAAC,SAAS,CAAC,KAAK,CAAC,IAAI,KAAK,GAAG,CAAC,EAAE,CAAC;QAC1C,MAAM,IAAI,wBAAwB,CAAC,6DAA6D,MAAM,CAAC,KAAK,CAAC,GAAG,CAAC,CAAA;IACnH,CAAC;IACD,OAAO,KAAK,CAAA;AACd,CAAC;AAED,MAAM,UAAU,oBAAoB;IAClC,OAAO,EAAE,OAAO,EAAE,CAAC,EAAE,OAAO,EAAE,CAAC,EAAE,SAAS,EAAE,CAAC,EAAE,KAAK,EAAE,CAAC,EAAE,OAAO,EAAE,CAAC,EAAE,CAAA;AACvE,CAAC;AAED,MAAM,UAAU,oBAAoB;IAClC,OAAO;QACL,IAAI,EAAE,oBAAoB,EAAE;QAC5B,OAAO,EAAE,oBAAoB,EAAE;QAC/B,IAAI,EAAE,oBAAoB,EAAE;QAC5B,KAAK,EAAE,oBAAoB,EAAE;KAC9B,CAAA;AACH,CAAC;AAED,MAAM,UAAU,kBAAkB,CAAC,MAAgD;IACjF,MAAM,KAAK,GAAG,oBAAoB,EAAE,CAAA;IACpC,KAAK,MAAM,MAAM,IAAI,MAAM,CAAC,MAAM,CAAC,MAAM,CAAC,EAAE,CAAC;QAC3C,KAAK,CAAC,OAAO,IAAI,MAAM,CAAC,OAAO,CAAA;QAC/B,KAAK,CAAC,OAAO,IAAI,MAAM,CAAC,OAAO,CAAA;QAC/B,KAAK,CAAC,SAAS,IAAI,MAAM,CAAC,SAAS,CAAA;QACnC,KAAK,CAAC,KAAK,IAAI,MAAM,CAAC,KAAK,CAAA;QAC3B,KAAK,CAAC,OAAO,IAAI,MAAM,CAAC,OAAO,CAAA;IACjC,CAAC;IACD,OAAO,KAAK,CAAA;AACd,CAAC"}
@@ -0,0 +1,8 @@
1
+ type TriggerDialect = 'sqlite' | 'postgres' | 'mysql';
2
+ export declare function triggerDialectOf(dialect: string): TriggerDialect;
3
+ /** Las sentencias a EJECUTAR (enteras) para crear el trigger de partición. */
4
+ export declare function relationPartitionTrigger(dialect: string): string[];
5
+ /** Las sentencias para soltar el trigger (y, en PG, su función) en el `down()`. */
6
+ export declare function relationPartitionTriggerDrops(dialect: string): string[];
7
+ export {};
8
+ //# sourceMappingURL=relation_partition_trigger.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"relation_partition_trigger.d.ts","sourceRoot":"","sources":["../../src/relation_partition_trigger.ts"],"names":[],"mappings":"AA+BA,KAAK,cAAc,GAAG,QAAQ,GAAG,UAAU,GAAG,OAAO,CAAA;AAErD,wBAAgB,gBAAgB,CAAC,OAAO,EAAE,MAAM,GAAG,cAAc,CAShE;AAED,8EAA8E;AAC9E,wBAAgB,wBAAwB,CAAC,OAAO,EAAE,MAAM,GAAG,MAAM,EAAE,CA8BlE;AAED,mFAAmF;AACnF,wBAAgB,6BAA6B,CAAC,OAAO,EAAE,MAAM,GAAG,MAAM,EAAE,CAYvE"}
@@ -0,0 +1,85 @@
1
+ /**
2
+ * **La DDL del trigger de partición de `authz_relations` por dialecto** (Fase 4,
3
+ * lote 4-3) — módulo PURO, sin dependencia del servicio `db` de Lucid, para que
4
+ * lo pueda importar tanto el driver `database` de relaciones como el espejo del
5
+ * esquema de la suite (que se carga ANTES de bootear la app).
6
+ *
7
+ * El trigger es la defensa en profundidad contra un escritor «a mano» que meta
8
+ * en `authz_relations` una fila cuyo USERSET (sujeto con `subject_relation`)
9
+ * pertenece a OTRA partición que la de la fila. Cada sentencia se ejecuta
10
+ * ENTERA (su cuerpo `BEGIN…END` lleva `;` dentro): nunca por un runner que
11
+ * trocea por `;`.
12
+ *
13
+ * La forma es RADICALMENTE distinta en cada motor (medido por el analista, y
14
+ * probado en INSERT **y** UPDATE):
15
+ * - **SQLite**: `CREATE TRIGGER … BEFORE INSERT/UPDATE … WHEN … BEGIN SELECT
16
+ * RAISE(ABORT, …); END` — un trigger por evento; `IS NOT` es el distinto
17
+ * null-safe.
18
+ * - **PostgreSQL**: exige una FUNCIÓN plpgsql SEPARADA (`RAISE EXCEPTION`) y
19
+ * un `CREATE TRIGGER … EXECUTE FUNCTION` que la invoca; un solo trigger
20
+ * `BEFORE INSERT OR UPDATE`. `IS DISTINCT FROM` es el distinto null-safe.
21
+ * - **MySQL**: `SIGNAL SQLSTATE '45000'` dentro de `IF … THEN … END IF`; un
22
+ * trigger por evento; `<=>` es el igual null-safe (`NOT (a <=> b)` = distinto).
23
+ *
24
+ * Cualquier otro dialecto ⇒ 500 `E_AUTHZ_UNSUPPORTED_DIALECT` (nunca una tabla
25
+ * sin defensa), exactamente como `sqlDescendantsOf`.
26
+ */
27
+ import { UnsupportedDialectError } from './errors.js';
28
+ const RELATIONS_TABLE = 'authz_relations';
29
+ const TRIGGER_MESSAGE = 'authz_relations: un userset no puede pertenecer a otra partición que su tupla';
30
+ export function triggerDialectOf(dialect) {
31
+ if (dialect === 'sqlite3' || dialect === 'better-sqlite3')
32
+ return 'sqlite';
33
+ if (dialect === 'postgres')
34
+ return 'postgres';
35
+ if (dialect === 'mysql' || dialect === 'mysql2')
36
+ return 'mysql';
37
+ throw new UnsupportedDialectError(`relationPartitionTrigger: dialecto '${dialect}' sin observación en la suite ` +
38
+ `(hoy: PostgreSQL, MySQL 8 y SQLite). El trigger de partición defiende al escritor a mano, ` +
39
+ `y su DDL no se declara igual en dos motores: mídelo antes de dar por buena una tabla sin defensa.`);
40
+ }
41
+ /** Las sentencias a EJECUTAR (enteras) para crear el trigger de partición. */
42
+ export function relationPartitionTrigger(dialect) {
43
+ const kind = triggerDialectOf(dialect);
44
+ if (kind === 'sqlite') {
45
+ const body = (event) => `CREATE TRIGGER authz_relations_partition_b${event === 'INSERT' ? 'i' : 'u'} ` +
46
+ `BEFORE ${event} ON ${RELATIONS_TABLE} FOR EACH ROW ` +
47
+ `WHEN NEW.subject_relation IS NOT NULL AND NEW.subject_partition IS NOT NEW.partition_key ` +
48
+ `BEGIN SELECT RAISE(ABORT, '${TRIGGER_MESSAGE}'); END`;
49
+ return [body('INSERT'), body('UPDATE')];
50
+ }
51
+ if (kind === 'postgres') {
52
+ return [
53
+ `CREATE OR REPLACE FUNCTION authz_relations_partition_guard() RETURNS trigger LANGUAGE plpgsql AS $authz$ ` +
54
+ `BEGIN ` +
55
+ `IF NEW.subject_relation IS NOT NULL AND NEW.subject_partition IS DISTINCT FROM NEW.partition_key THEN ` +
56
+ `RAISE EXCEPTION '${TRIGGER_MESSAGE} (subject_partition=%, partition_key=%)', NEW.subject_partition, NEW.partition_key; ` +
57
+ `END IF; RETURN NEW; END; $authz$`,
58
+ `CREATE TRIGGER authz_relations_partition_biu BEFORE INSERT OR UPDATE ON ${RELATIONS_TABLE} ` +
59
+ `FOR EACH ROW EXECUTE FUNCTION authz_relations_partition_guard()`,
60
+ ];
61
+ }
62
+ // mysql
63
+ const body = (event) => `CREATE TRIGGER authz_relations_partition_b${event === 'INSERT' ? 'i' : 'u'} ` +
64
+ `BEFORE ${event} ON ${RELATIONS_TABLE} FOR EACH ROW ` +
65
+ `BEGIN ` +
66
+ `IF NEW.subject_relation IS NOT NULL AND NOT (NEW.subject_partition <=> NEW.partition_key) THEN ` +
67
+ `SIGNAL SQLSTATE '45000' SET MESSAGE_TEXT = '${TRIGGER_MESSAGE}'; ` +
68
+ `END IF; END`;
69
+ return [body('INSERT'), body('UPDATE')];
70
+ }
71
+ /** Las sentencias para soltar el trigger (y, en PG, su función) en el `down()`. */
72
+ export function relationPartitionTriggerDrops(dialect) {
73
+ const kind = triggerDialectOf(dialect);
74
+ if (kind === 'postgres') {
75
+ return [
76
+ `DROP TRIGGER IF EXISTS authz_relations_partition_biu ON ${RELATIONS_TABLE}`,
77
+ 'DROP FUNCTION IF EXISTS authz_relations_partition_guard()',
78
+ ];
79
+ }
80
+ return [
81
+ 'DROP TRIGGER IF EXISTS authz_relations_partition_bi',
82
+ 'DROP TRIGGER IF EXISTS authz_relations_partition_bu',
83
+ ];
84
+ }
85
+ //# sourceMappingURL=relation_partition_trigger.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"relation_partition_trigger.js","sourceRoot":"","sources":["../../src/relation_partition_trigger.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;;;;;;;;;;;GAyBG;AACH,OAAO,EAAE,uBAAuB,EAAE,MAAM,aAAa,CAAA;AAErD,MAAM,eAAe,GAAG,iBAAiB,CAAA;AACzC,MAAM,eAAe,GAAG,+EAA+E,CAAA;AAIvG,MAAM,UAAU,gBAAgB,CAAC,OAAe;IAC9C,IAAI,OAAO,KAAK,SAAS,IAAI,OAAO,KAAK,gBAAgB;QAAE,OAAO,QAAQ,CAAA;IAC1E,IAAI,OAAO,KAAK,UAAU;QAAE,OAAO,UAAU,CAAA;IAC7C,IAAI,OAAO,KAAK,OAAO,IAAI,OAAO,KAAK,QAAQ;QAAE,OAAO,OAAO,CAAA;IAC/D,MAAM,IAAI,uBAAuB,CAC/B,uCAAuC,OAAO,gCAAgC;QAC5E,4FAA4F;QAC5F,mGAAmG,CACtG,CAAA;AACH,CAAC;AAED,8EAA8E;AAC9E,MAAM,UAAU,wBAAwB,CAAC,OAAe;IACtD,MAAM,IAAI,GAAG,gBAAgB,CAAC,OAAO,CAAC,CAAA;IACtC,IAAI,IAAI,KAAK,QAAQ,EAAE,CAAC;QACtB,MAAM,IAAI,GAAG,CAAC,KAA0B,EAAE,EAAE,CAC1C,6CAA6C,KAAK,KAAK,QAAQ,CAAC,CAAC,CAAC,GAAG,CAAC,CAAC,CAAC,GAAG,GAAG;YAC9E,UAAU,KAAK,OAAO,eAAe,gBAAgB;YACrD,2FAA2F;YAC3F,8BAA8B,eAAe,SAAS,CAAA;QACxD,OAAO,CAAC,IAAI,CAAC,QAAQ,CAAC,EAAE,IAAI,CAAC,QAAQ,CAAC,CAAC,CAAA;IACzC,CAAC;IACD,IAAI,IAAI,KAAK,UAAU,EAAE,CAAC;QACxB,OAAO;YACL,2GAA2G;gBACzG,QAAQ;gBACR,wGAAwG;gBACxG,oBAAoB,eAAe,sFAAsF;gBACzH,kCAAkC;YACpC,2EAA2E,eAAe,GAAG;gBAC3F,iEAAiE;SACpE,CAAA;IACH,CAAC;IACD,QAAQ;IACR,MAAM,IAAI,GAAG,CAAC,KAA0B,EAAE,EAAE,CAC1C,6CAA6C,KAAK,KAAK,QAAQ,CAAC,CAAC,CAAC,GAAG,CAAC,CAAC,CAAC,GAAG,GAAG;QAC9E,UAAU,KAAK,OAAO,eAAe,gBAAgB;QACrD,QAAQ;QACR,iGAAiG;QACjG,+CAA+C,eAAe,KAAK;QACnE,aAAa,CAAA;IACf,OAAO,CAAC,IAAI,CAAC,QAAQ,CAAC,EAAE,IAAI,CAAC,QAAQ,CAAC,CAAC,CAAA;AACzC,CAAC;AAED,mFAAmF;AACnF,MAAM,UAAU,6BAA6B,CAAC,OAAe;IAC3D,MAAM,IAAI,GAAG,gBAAgB,CAAC,OAAO,CAAC,CAAA;IACtC,IAAI,IAAI,KAAK,UAAU,EAAE,CAAC;QACxB,OAAO;YACL,2DAA2D,eAAe,EAAE;YAC5E,2DAA2D;SAC5D,CAAA;IACH,CAAC;IACD,OAAO;QACL,qDAAqD;QACrD,qDAAqD;KACtD,CAAA;AACH,CAAC"}
@@ -0,0 +1,58 @@
1
+ /** Una relación de un tipo de objeto (`document#viewer`), con sus `includes` de un nivel. */
2
+ export interface RelationObjectRelationSpec {
3
+ /** El nombre de la relación (`owner`, `editor`, `viewer`). */
4
+ name: string;
5
+ /**
6
+ * Otras relaciones del MISMO tipo que ésta incluye (`viewer or editor`):
7
+ * un `relate(u, editor, doc)` concede también `viewer`. Un nivel, SIN
8
+ * `from` en v1 (la herencia cross-objeto metería un TTU entre tipos y
9
+ * habría que re-medir profundidad — diferido a 2.6+).
10
+ */
11
+ includes?: readonly string[];
12
+ }
13
+ /** Un tipo de objeto de relaciones (`document`, `folder`, `space`…). */
14
+ export interface RelationObjectTypeSpec {
15
+ /** El tipo FGA del objeto. */
16
+ type: string;
17
+ /** Sus relaciones, en orden de declaración. */
18
+ relations: readonly RelationObjectRelationSpec[];
19
+ }
20
+ /** Opciones específicas del driver `database`. */
21
+ export interface RelationsDatabaseOptions {
22
+ /**
23
+ * Habilita `membersOf` (membresía TRANSITIVA a través de usersets), que solo
24
+ * el driver `database` resuelve (CTE recursiva). En `openfga` la transitiva
25
+ * sería `ListUsers`, que trunca, así que la opción NO es válida fuera de
26
+ * `database`.
27
+ */
28
+ membersOf?: boolean;
29
+ }
30
+ /** La config que declara el consumidor. */
31
+ export interface RelationsConfigSpec {
32
+ /** Los tipos de objeto y sus relaciones. */
33
+ objectTypes: readonly RelationObjectTypeSpec[];
34
+ /**
35
+ * Los holder types del config del consumidor (`user`, `admin`…). Se suman a
36
+ * los tipos reservados: un tipo de objeto de relaciones no puede llamarse
37
+ * como un holder (⚪4).
38
+ */
39
+ holderTypes?: readonly string[];
40
+ /** Opciones del driver `database` (donde vive `membersOf`). */
41
+ database?: RelationsDatabaseOptions;
42
+ }
43
+ /** La config ya validada y CONGELADA que consulta el manager de relaciones. */
44
+ export interface RelationsConfig {
45
+ readonly objectTypes: readonly RelationObjectTypeSpec[];
46
+ /** ¿`membersOf` está habilitado (opción de `database`)? */
47
+ readonly membersOf: boolean;
48
+ /** ¿Existe el tipo de objeto? (F-05, cara del tipo). */
49
+ hasType(objectType: string): boolean;
50
+ /** ¿La relación está declarada para ese tipo? (F-05, cara de la relación). */
51
+ isDeclared(objectType: string, relation: string): boolean;
52
+ }
53
+ /**
54
+ * Valida y congela la config de relaciones. Config inválida ⇒ 422
55
+ * `E_AUTHZ_RELATION_CONFIG` (misma clase que el gate del modelo del lote 4-1).
56
+ */
57
+ export declare function defineRelationsConfig(spec: RelationsConfigSpec): RelationsConfig;
58
+ //# sourceMappingURL=define_relations_config.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"define_relations_config.d.ts","sourceRoot":"","sources":["../../../src/relations/define_relations_config.ts"],"names":[],"mappings":"AA2BA,6FAA6F;AAC7F,MAAM,WAAW,0BAA0B;IACzC,8DAA8D;IAC9D,IAAI,EAAE,MAAM,CAAA;IACZ;;;;;OAKG;IACH,QAAQ,CAAC,EAAE,SAAS,MAAM,EAAE,CAAA;CAC7B;AAED,wEAAwE;AACxE,MAAM,WAAW,sBAAsB;IACrC,8BAA8B;IAC9B,IAAI,EAAE,MAAM,CAAA;IACZ,+CAA+C;IAC/C,SAAS,EAAE,SAAS,0BAA0B,EAAE,CAAA;CACjD;AAED,kDAAkD;AAClD,MAAM,WAAW,wBAAwB;IACvC;;;;;OAKG;IACH,SAAS,CAAC,EAAE,OAAO,CAAA;CACpB;AAED,2CAA2C;AAC3C,MAAM,WAAW,mBAAmB;IAClC,4CAA4C;IAC5C,WAAW,EAAE,SAAS,sBAAsB,EAAE,CAAA;IAC9C;;;;OAIG;IACH,WAAW,CAAC,EAAE,SAAS,MAAM,EAAE,CAAA;IAC/B,+DAA+D;IAC/D,QAAQ,CAAC,EAAE,wBAAwB,CAAA;CACpC;AAED,+EAA+E;AAC/E,MAAM,WAAW,eAAe;IAC9B,QAAQ,CAAC,WAAW,EAAE,SAAS,sBAAsB,EAAE,CAAA;IACvD,2DAA2D;IAC3D,QAAQ,CAAC,SAAS,EAAE,OAAO,CAAA;IAC3B,wDAAwD;IACxD,OAAO,CAAC,UAAU,EAAE,MAAM,GAAG,OAAO,CAAA;IACpC,8EAA8E;IAC9E,UAAU,CAAC,UAAU,EAAE,MAAM,EAAE,QAAQ,EAAE,MAAM,GAAG,OAAO,CAAA;CAC1D;AAMD;;;GAGG;AACH,wBAAgB,qBAAqB,CAAC,IAAI,EAAE,mBAAmB,GAAG,eAAe,CA0IhF"}
@@ -0,0 +1,144 @@
1
+ /**
2
+ * `defineRelationsConfig` — la API declarativa de ReBAC (Fase 4, lote 4-2).
3
+ *
4
+ * Valida la config de relaciones del consumidor y devuelve un objeto
5
+ * CONGELADO que el manager de relaciones consulta para F-05 (`isDeclared`).
6
+ * Es la puerta de entrada, AGNÓSTICA de driver: rige igual en `database` y en
7
+ * `openfga` (paridad ⚪4). El generador del modelo fusionado
8
+ * (`src/drivers/openfga_facts.ts`, lote 4-1) hace la MISMA comprobación de
9
+ * reservados por defensa en profundidad al emitir el modelo —y además la de
10
+ * F-04 (colisión con un permiso del catálogo), que necesita las tuplas del
11
+ * catálogo y por eso vive en la capa del modelo—; las dos comparten la fuente
12
+ * única de tipos reservados (`RESERVED_FACTS_TYPES` en `src/identity.ts`).
13
+ *
14
+ * Pureza (regla 2 de `check_purity.mjs`): este módulo solo depende del puerto
15
+ * (`../types.js`), de los errores y de la gramática compartida
16
+ * (`../identity.js`); JAMÁS de `../manager` ni de `../drivers/*`. Es lo que
17
+ * mantiene `relations/` desacoplado de `roles/`.
18
+ */
19
+ import { RelationConfigError } from '../errors.js';
20
+ import { RESERVED_FACTS_TYPES, RESERVED_SLUGS, RESERVED_SLUG_PREFIXES } from '../identity.js';
21
+ /** La cota de FGA para el nombre de una relación (50). Un tipo de objeto llega a 254. */
22
+ const RELATION_NAME_MAX = 50;
23
+ const OBJECT_TYPE_MAX = 254;
24
+ /** Nombres FGA: minúsculas, dígitos y `._-`; sin `:`/`#`/`@`/espacios ni `|`. */
25
+ const FGA_NAME_FORMAT = /^[a-z0-9][a-z0-9._-]*$/;
26
+ function reject(message) {
27
+ throw new RelationConfigError(message);
28
+ }
29
+ /**
30
+ * Valida y congela la config de relaciones. Config inválida ⇒ 422
31
+ * `E_AUTHZ_RELATION_CONFIG` (misma clase que el gate del modelo del lote 4-1).
32
+ */
33
+ export function defineRelationsConfig(spec) {
34
+ if (!spec || typeof spec !== 'object') {
35
+ reject(`Config de relaciones inválida: se esperaba un objeto y llegó ${JSON.stringify(spec)}.`);
36
+ }
37
+ // `membersOf` SOLO puede vivir en las opciones de `database` (⚪ del tester):
38
+ // ponerlo en la raíz o en un futuro bloque `openfga` es un error de
39
+ // configuración —`openfga` no puede resolver la transitiva sin truncar—.
40
+ if ('membersOf' in spec) {
41
+ reject(`Config de relaciones inválida: 'membersOf' es una opción del driver 'database' ` +
42
+ `(membresía transitiva por CTE recursiva) y va en 'database.membersOf', no en la raíz. ` +
43
+ `En 'openfga' la transitiva sería 'ListUsers', que trunca al tope del servidor.`);
44
+ }
45
+ if (!Array.isArray(spec.objectTypes) || spec.objectTypes.length === 0) {
46
+ reject(`Config de relaciones inválida: 'objectTypes' tiene que ser un array no vacío.`);
47
+ }
48
+ const holderTypes = spec.holderTypes ?? [];
49
+ for (const holder of holderTypes) {
50
+ if (typeof holder !== 'string') {
51
+ reject(`Config de relaciones inválida: un holder type no es una cadena (${JSON.stringify(holder)}).`);
52
+ }
53
+ }
54
+ const reservedTypes = new Set([...RESERVED_FACTS_TYPES, ...holderTypes]);
55
+ const seenTypes = new Set();
56
+ for (const objectType of spec.objectTypes) {
57
+ const type = objectType?.type;
58
+ if (typeof type !== 'string' || !FGA_NAME_FORMAT.test(type) || type.length > OBJECT_TYPE_MAX) {
59
+ reject(`Config de relaciones inválida: tipo de objeto ${JSON.stringify(type)} no es un tipo FGA válido ` +
60
+ `(minúsculas, dígitos y '._-'; sin ':'/'#'/'@'/'|'/espacios; 1-${OBJECT_TYPE_MAX} caracteres).`);
61
+ }
62
+ if (reservedTypes.has(type)) {
63
+ reject(`Config de relaciones inválida: el tipo de objeto '${type}' colisiona con un tipo reservado del ` +
64
+ `modelo compartido (${[...RESERVED_FACTS_TYPES].join(', ')}` +
65
+ `${holderTypes.length ? ', y los holder types ' + holderTypes.join(', ') : ''}). ` +
66
+ `En el store compartido un tipo de relaciones no puede duplicar uno de 'facts' (⚪4): ` +
67
+ `si pudiera declarar 'role_binding', 'relate' compondría el id de un binding real y escalaría a ` +
68
+ `roles.authorize. Renómbralo.`);
69
+ }
70
+ if (seenTypes.has(type)) {
71
+ reject(`Config de relaciones inválida: el tipo de objeto '${type}' está declarado dos veces.`);
72
+ }
73
+ seenTypes.add(type);
74
+ if (!Array.isArray(objectType.relations) || objectType.relations.length === 0) {
75
+ reject(`Config de relaciones inválida: el tipo '${type}' no declara ninguna relación.`);
76
+ }
77
+ const own = new Set();
78
+ for (const relation of objectType.relations) {
79
+ const name = relation?.name;
80
+ if (typeof name !== 'string' || !FGA_NAME_FORMAT.test(name)) {
81
+ reject(`Config de relaciones inválida: relación ${JSON.stringify(name)} del tipo '${type}' no es un ` +
82
+ `nombre de relación válido (minúsculas, dígitos y '._-').`);
83
+ }
84
+ if (name.length > RELATION_NAME_MAX) {
85
+ reject(`Config de relaciones inválida: la relación '${name}' del tipo '${type}' tiene ${name.length} ` +
86
+ `caracteres y FGA admite ${RELATION_NAME_MAX}.`);
87
+ }
88
+ if (RESERVED_SLUGS.has(name)) {
89
+ reject(`Config de relaciones inválida: la relación '${type}#${name}' usa un nombre reservado del modelo ` +
90
+ `facts (${[...RESERVED_SLUGS].join(', ')}): elegiría una relación propia de 'facts' (⚪4).`);
91
+ }
92
+ const family = RESERVED_SLUG_PREFIXES.find((prefix) => name.startsWith(prefix));
93
+ if (family) {
94
+ reject(`Config de relaciones inválida: la relación '${type}#${name}' empieza por '${family}', prefijo ` +
95
+ `reservado de las relaciones derivadas del modelo facts (${RESERVED_SLUG_PREFIXES.join(', ')}): ` +
96
+ `pisaría el nombre de un permiso proyectado (⚪4).`);
97
+ }
98
+ if (own.has(name)) {
99
+ reject(`Config de relaciones inválida: la relación '${type}#${name}' está declarada dos veces.`);
100
+ }
101
+ own.add(name);
102
+ }
103
+ // Los `includes` refieren relaciones del MISMO tipo (un nivel, SIN `from`).
104
+ for (const relation of objectType.relations) {
105
+ for (const included of relation.includes ?? []) {
106
+ if (typeof included !== 'string') {
107
+ reject(`Config de relaciones inválida: un 'includes' de '${type}#${relation.name}' no es una cadena.`);
108
+ }
109
+ // Un `from` (`viewer from parent`) se escribe con un separador; v1 no lo soporta.
110
+ if (/[:#@|. ]/.test(included) && !own.has(included)) {
111
+ reject(`Config de relaciones inválida: '${type}#${relation.name}' incluye '${included}', que parece una ` +
112
+ `herencia cross-objeto ('from'). v1 solo soporta includes de un nivel y del MISMO tipo.`);
113
+ }
114
+ if (!own.has(included)) {
115
+ reject(`Config de relaciones inválida: '${type}#${relation.name}' incluye '${included}', que no es una ` +
116
+ `relación de '${type}'. Los includes son de un nivel y del mismo tipo (v1 no soporta 'from').`);
117
+ }
118
+ if (included === relation.name) {
119
+ reject(`Config de relaciones inválida: '${type}#${relation.name}' se incluye a sí misma.`);
120
+ }
121
+ }
122
+ }
123
+ }
124
+ const declared = new Map();
125
+ // `group` es el tipo BUILT-IN de las relaciones (el portador de los
126
+ // usersets, `group:g#member`): lo emite SIEMPRE el generador del modelo, no
127
+ // el consumidor —por eso NO se declara en `objectTypes` (arriba se rechaza)
128
+ // pero SÍ es un tipo válido para F-05: `relate(group:g#member, viewer, doc)`
129
+ // y `relate(u, member, group:g)` son legales. `role_binding`/`scope`/`role`
130
+ // siguen fuera: la frontera del 🔴 se mantiene.
131
+ declared.set('group', new Set(['member']));
132
+ const frozenTypes = spec.objectTypes.map((objectType) => {
133
+ const relations = objectType.relations.map((relation) => Object.freeze({ name: relation.name, includes: relation.includes ? Object.freeze([...relation.includes]) : undefined }));
134
+ declared.set(objectType.type, new Set(relations.map((r) => r.name)));
135
+ return Object.freeze({ type: objectType.type, relations: Object.freeze(relations) });
136
+ });
137
+ return Object.freeze({
138
+ objectTypes: Object.freeze(frozenTypes),
139
+ membersOf: spec.database?.membersOf === true,
140
+ hasType: (objectType) => declared.has(objectType),
141
+ isDeclared: (objectType, relation) => declared.get(objectType)?.has(relation) ?? false,
142
+ });
143
+ }
144
+ //# sourceMappingURL=define_relations_config.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"define_relations_config.js","sourceRoot":"","sources":["../../../src/relations/define_relations_config.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,38 @@
1
+ import type { RelObject, RelSubject, RelationRef, RelationWriteEvent, RelationWriteOptions, RelationsDriver, RelationObjectsPage, RelationSubjectsPage, RelationPage, RelationTuplePage, ScopeRef } from '../types.js';
2
+ import type { RelationsConfig } from './define_relations_config.js';
3
+ export interface RelationsManagerOptions {
4
+ /**
5
+ * Comprobación PURA de escritura (R-13): recibe la referencia completa de la
6
+ * tupla (sujeto, relación, objeto, partición, operación) y lanza para
7
+ * rechazarla. Corre DESPUÉS de F-05 y ANTES de tocar el driver.
8
+ */
9
+ assertWrite?(ref: RelationRef): void;
10
+ /** Auditoría: se notifica DESPUÉS de una escritura confirmada, con el `actor`. */
11
+ onRelationWrite?(event: RelationWriteEvent): void;
12
+ /** `true` exige `actor` en toda escritura (paridad con `requireActor` de roles). */
13
+ requireActor?: boolean;
14
+ }
15
+ export declare class RelationsManager {
16
+ #private;
17
+ constructor(driver: RelationsDriver, config: RelationsConfig, options?: RelationsManagerOptions);
18
+ /** El driver crudo — salida documentada de las barreras (plataforma y tests). */
19
+ driver(): RelationsDriver;
20
+ relate(subject: RelSubject, relation: string, object: RelObject, partition: ScopeRef, options?: RelationWriteOptions): Promise<void>;
21
+ unrelate(subject: RelSubject, relation: string, object: RelObject, partition: ScopeRef, options?: RelationWriteOptions): Promise<void>;
22
+ check(subject: RelSubject, relation: string, object: RelObject, partition: ScopeRef): Promise<boolean>;
23
+ listObjects(subject: RelSubject, relation: string, objectType: string, partition: ScopeRef, page?: RelationPage): Promise<RelationObjectsPage>;
24
+ listSubjects(relation: string, object: RelObject, partition: ScopeRef, page?: RelationPage): Promise<RelationSubjectsPage>;
25
+ purgeObject(object: RelObject, partition: ScopeRef): Promise<void>;
26
+ purgeSubject(subject: RelSubject, partition: ScopeRef): Promise<void>;
27
+ /**
28
+ * Membresía TRANSITIVA de un grupo (a través de usersets anidados) —
29
+ * DISTINTA de `listSubjects`, que da los hechos DIRECTOS. Solo la trae el
30
+ * driver `database` (`membersOfNative: true`); en `openfga` es 500
31
+ * `E_AUTHZ_UNSUPPORTED` nombrándola (la transitiva sería `ListUsers`, que
32
+ * trunca), jamás un `skip`.
33
+ */
34
+ membersOf(object: RelObject, relation: string, partition: ScopeRef, page?: RelationPage): Promise<RelationSubjectsPage>;
35
+ /** ORIGEN de `authz:reconcile` de relaciones. 500 `E_AUTHZ_UNSUPPORTED` si el driver no lo trae. */
36
+ enumerateRelations(partition: ScopeRef, page?: RelationPage): Promise<RelationTuplePage>;
37
+ }
38
+ //# sourceMappingURL=manager.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"manager.d.ts","sourceRoot":"","sources":["../../../src/relations/manager.ts"],"names":[],"mappings":"AA8BA,OAAO,KAAK,EACV,SAAS,EACT,UAAU,EACV,WAAW,EACX,kBAAkB,EAClB,oBAAoB,EACpB,eAAe,EACf,mBAAmB,EACnB,oBAAoB,EACpB,YAAY,EACZ,iBAAiB,EACjB,QAAQ,EACT,MAAM,aAAa,CAAA;AAEpB,OAAO,KAAK,EAAE,eAAe,EAAE,MAAM,8BAA8B,CAAA;AAEnE,MAAM,WAAW,uBAAuB;IACtC;;;;OAIG;IACH,WAAW,CAAC,CAAC,GAAG,EAAE,WAAW,GAAG,IAAI,CAAA;IACpC,kFAAkF;IAClF,eAAe,CAAC,CAAC,KAAK,EAAE,kBAAkB,GAAG,IAAI,CAAA;IACjD,oFAAoF;IACpF,YAAY,CAAC,EAAE,OAAO,CAAA;CACvB;AAED,qBAAa,gBAAgB;;gBAKf,MAAM,EAAE,eAAe,EAAE,MAAM,EAAE,eAAe,EAAE,OAAO,GAAE,uBAA4B;IAMnG,iFAAiF;IACjF,MAAM,IAAI,eAAe;IAmDnB,MAAM,CACV,OAAO,EAAE,UAAU,EACnB,QAAQ,EAAE,MAAM,EAChB,MAAM,EAAE,SAAS,EACjB,SAAS,EAAE,QAAQ,EACnB,OAAO,CAAC,EAAE,oBAAoB,GAC7B,OAAO,CAAC,IAAI,CAAC;IAYV,QAAQ,CACZ,OAAO,EAAE,UAAU,EACnB,QAAQ,EAAE,MAAM,EAChB,MAAM,EAAE,SAAS,EACjB,SAAS,EAAE,QAAQ,EACnB,OAAO,CAAC,EAAE,oBAAoB,GAC7B,OAAO,CAAC,IAAI,CAAC;IAYV,KAAK,CAAC,OAAO,EAAE,UAAU,EAAE,QAAQ,EAAE,MAAM,EAAE,MAAM,EAAE,SAAS,EAAE,SAAS,EAAE,QAAQ,GAAG,OAAO,CAAC,OAAO,CAAC;IAMtG,WAAW,CACf,OAAO,EAAE,UAAU,EACnB,QAAQ,EAAE,MAAM,EAChB,UAAU,EAAE,MAAM,EAClB,SAAS,EAAE,QAAQ,EACnB,IAAI,CAAC,EAAE,YAAY,GAClB,OAAO,CAAC,mBAAmB,CAAC;IAKzB,YAAY,CAChB,QAAQ,EAAE,MAAM,EAChB,MAAM,EAAE,SAAS,EACjB,SAAS,EAAE,QAAQ,EACnB,IAAI,CAAC,EAAE,YAAY,GAClB,OAAO,CAAC,oBAAoB,CAAC;IAM1B,WAAW,CAAC,MAAM,EAAE,SAAS,EAAE,SAAS,EAAE,QAAQ,GAAG,OAAO,CAAC,IAAI,CAAC;IAMlE,YAAY,CAAC,OAAO,EAAE,UAAU,EAAE,SAAS,EAAE,QAAQ,GAAG,OAAO,CAAC,IAAI,CAAC;IAK3E;;;;;;OAMG;IACG,SAAS,CACb,MAAM,EAAE,SAAS,EACjB,QAAQ,EAAE,MAAM,EAChB,SAAS,EAAE,QAAQ,EACnB,IAAI,CAAC,EAAE,YAAY,GAClB,OAAO,CAAC,oBAAoB,CAAC;IAchC,oGAAoG;IAC9F,kBAAkB,CAAC,SAAS,EAAE,QAAQ,EAAE,IAAI,CAAC,EAAE,YAAY,GAAG,OAAO,CAAC,iBAAiB,CAAC;CAuB/F"}