@jantstack/adonis-authz 2.5.0-alpha.3 → 2.5.0-alpha.4
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.
- package/README.md +414 -35
- package/build/commands/authz_catalog_diff.d.ts +0 -1
- package/build/commands/authz_catalog_diff.js +0 -1
- package/build/commands/authz_catalog_prune_orphans.d.ts +0 -1
- package/build/commands/authz_catalog_prune_orphans.js +0 -1
- package/build/commands/authz_catalog_sync.d.ts +0 -1
- package/build/commands/authz_catalog_sync.js +0 -1
- package/build/commands/authz_freeze.d.ts +0 -1
- package/build/commands/authz_freeze.js +0 -1
- package/build/commands/authz_reconcile.d.ts +0 -1
- package/build/commands/authz_reconcile.js +0 -1
- package/build/commands/authz_relations_reconcile.d.ts +0 -1
- package/build/commands/authz_relations_reconcile.js +56 -8
- package/build/commands/authz_scopes_relay.d.ts +0 -1
- package/build/commands/authz_scopes_relay.js +49 -5
- package/build/commands/authz_scopes_requeue.d.ts +0 -1
- package/build/commands/authz_scopes_requeue.js +14 -2
- package/build/commands/authz_unfreeze.d.ts +0 -1
- package/build/commands/authz_unfreeze.js +0 -1
- package/build/commands/main.d.ts +0 -1
- package/build/commands/main.js +0 -1
- package/build/commands/openfga_provision.d.ts +10 -1
- package/build/commands/openfga_provision.js +43 -3
- package/build/configure.d.ts +0 -1
- package/build/configure.js +0 -1
- package/build/index.d.ts +7 -5
- package/build/index.js +10 -3
- package/build/providers/authz_provider.d.ts +0 -1
- package/build/providers/authz_provider.js +0 -1
- package/build/services/main.d.ts +0 -1
- package/build/services/main.js +0 -1
- package/build/services/relations.d.ts +0 -1
- package/build/services/relations.js +0 -1
- package/build/src/catalog/catalog.d.ts +0 -1
- package/build/src/catalog/catalog.js +0 -1
- package/build/src/catalog/catalog_cache.d.ts +13 -1
- package/build/src/catalog/catalog_cache.js +25 -1
- package/build/src/clock.d.ts +0 -1
- package/build/src/clock.js +0 -1
- package/build/src/define_config.d.ts +0 -1
- package/build/src/define_config.js +24 -1
- package/build/src/drivers/database_driver.d.ts +6 -1
- package/build/src/drivers/database_driver.js +22 -2
- package/build/src/drivers/database_relations_driver.d.ts +11 -5
- package/build/src/drivers/database_relations_driver.js +90 -18
- package/build/src/drivers/openfga_driver.d.ts +159 -26
- package/build/src/drivers/openfga_driver.js +882 -199
- package/build/src/drivers/openfga_facts.d.ts +91 -1
- package/build/src/drivers/openfga_facts.js +277 -3
- package/build/src/drivers/openfga_relations_driver.d.ts +41 -13
- package/build/src/drivers/openfga_relations_driver.js +422 -228
- package/build/src/errors.d.ts +121 -1
- package/build/src/errors.js +153 -1
- package/build/src/expiry.d.ts +51 -2
- package/build/src/expiry.js +96 -2
- package/build/src/freeze.d.ts +0 -1
- package/build/src/freeze.js +0 -1
- package/build/src/hierarchical_resolver.d.ts +0 -1
- package/build/src/hierarchical_resolver.js +0 -1
- package/build/src/http/app_access_middleware.d.ts +0 -1
- package/build/src/http/app_access_middleware.js +0 -1
- package/build/src/http/resource_access_middleware.d.ts +0 -1
- package/build/src/http/resource_access_middleware.js +0 -1
- package/build/src/identity.d.ts +2 -1
- package/build/src/identity.js +4 -1
- package/build/src/manager.d.ts +0 -1
- package/build/src/manager.js +156 -28
- package/build/src/memoize_ancestors.d.ts +0 -1
- package/build/src/memoize_ancestors.js +0 -1
- package/build/src/models/authz_assignment.d.ts +5 -6
- package/build/src/models/authz_assignment.js +0 -1
- package/build/src/models/authz_deny.d.ts +5 -6
- package/build/src/models/authz_deny.js +0 -1
- package/build/src/models/authz_permission.d.ts +5 -6
- package/build/src/models/authz_permission.js +0 -1
- package/build/src/models/authz_role.d.ts +5 -6
- package/build/src/models/authz_role.js +0 -1
- package/build/src/models/authz_role_permission.d.ts +5 -6
- package/build/src/models/authz_role_permission.js +0 -1
- package/build/src/openfga.d.ts +2 -3
- package/build/src/openfga.js +4 -2
- package/build/src/reconcile.d.ts +0 -1
- package/build/src/reconcile.js +0 -1
- package/build/src/relation_partition_trigger.d.ts +0 -1
- package/build/src/relation_partition_trigger.js +0 -1
- package/build/src/relations/check_many.d.ts +0 -1
- package/build/src/relations/check_many.js +0 -1
- package/build/src/relations/define_relations_config.d.ts +25 -3
- package/build/src/relations/define_relations_config.js +8 -3
- package/build/src/relations/deny_reach.d.ts +102 -0
- package/build/src/relations/deny_reach.js +230 -0
- package/build/src/relations/group_depth.d.ts +215 -0
- package/build/src/relations/group_depth.js +453 -0
- package/build/src/relations/manager.d.ts +14 -7
- package/build/src/relations/manager.js +60 -15
- package/build/src/relations/page.d.ts +19 -0
- package/build/src/relations/page.js +74 -0
- package/build/src/relations/reconcile.d.ts +58 -4
- package/build/src/relations/reconcile.js +266 -12
- package/build/src/relations/tuple_key.d.ts +0 -1
- package/build/src/relations/tuple_key.js +0 -1
- package/build/src/relations/tuple_order.d.ts +5 -4
- package/build/src/relations/tuple_order.js +5 -4
- package/build/src/relations_config_store.d.ts +57 -2
- package/build/src/relations_config_store.js +155 -5
- package/build/src/relations_reconcile.d.ts +0 -1
- package/build/src/relations_reconcile.js +0 -1
- package/build/src/scope_outbox.d.ts +0 -1
- package/build/src/scope_outbox.js +0 -1
- package/build/src/shared/backend_guard.d.ts +52 -1
- package/build/src/shared/backend_guard.js +164 -2
- package/build/src/shared/sql_expiry.d.ts +0 -1
- package/build/src/shared/sql_expiry.js +0 -1
- package/build/src/shared/transaction_guard.d.ts +0 -1
- package/build/src/shared/transaction_guard.js +0 -1
- package/build/src/sql_descendants.d.ts +0 -1
- package/build/src/sql_descendants.js +0 -1
- package/build/src/testing/contract.d.ts +7 -1
- package/build/src/testing/contract.js +77 -1
- package/build/src/testing/main.d.ts +0 -1
- package/build/src/testing/main.js +0 -1
- package/build/src/testing/migration_contract.d.ts +0 -1
- package/build/src/testing/migration_contract.js +0 -1
- package/build/src/testing/relations_contract.d.ts +7 -1
- package/build/src/testing/relations_contract.js +174 -7
- package/build/src/testing/relations_reconcile_contract.d.ts +0 -1
- package/build/src/testing/relations_reconcile_contract.js +0 -1
- package/build/src/testing/scope_outbox_contract.d.ts +0 -1
- package/build/src/testing/scope_outbox_contract.js +0 -1
- package/build/src/testing/scope_tree.d.ts +0 -1
- package/build/src/testing/scope_tree.js +0 -1
- package/build/src/testing/test_clock.d.ts +0 -1
- package/build/src/testing/test_clock.js +0 -1
- package/build/src/traits/authz_scopes.d.ts +0 -1
- package/build/src/traits/authz_scopes.js +0 -1
- package/build/src/traits/has_uuid.d.ts +5 -6
- package/build/src/traits/has_uuid.js +0 -1
- package/build/src/types.d.ts +89 -14
- package/build/src/types.js +4 -1
- package/build/stubs/config/authorization.stub +22 -6
- package/build/stubs/main.d.ts +0 -1
- package/build/stubs/main.js +0 -1
- package/package.json +4 -3
- package/build/commands/authz_catalog_diff.d.ts.map +0 -1
- package/build/commands/authz_catalog_diff.js.map +0 -1
- package/build/commands/authz_catalog_prune_orphans.d.ts.map +0 -1
- package/build/commands/authz_catalog_prune_orphans.js.map +0 -1
- package/build/commands/authz_catalog_sync.d.ts.map +0 -1
- package/build/commands/authz_catalog_sync.js.map +0 -1
- package/build/commands/authz_freeze.d.ts.map +0 -1
- package/build/commands/authz_freeze.js.map +0 -1
- package/build/commands/authz_reconcile.d.ts.map +0 -1
- package/build/commands/authz_reconcile.js.map +0 -1
- package/build/commands/authz_relations_reconcile.d.ts.map +0 -1
- package/build/commands/authz_relations_reconcile.js.map +0 -1
- package/build/commands/authz_scopes_relay.d.ts.map +0 -1
- package/build/commands/authz_scopes_relay.js.map +0 -1
- package/build/commands/authz_scopes_requeue.d.ts.map +0 -1
- package/build/commands/authz_scopes_requeue.js.map +0 -1
- package/build/commands/authz_unfreeze.d.ts.map +0 -1
- package/build/commands/authz_unfreeze.js.map +0 -1
- package/build/commands/main.d.ts.map +0 -1
- package/build/commands/main.js.map +0 -1
- package/build/commands/openfga_provision.d.ts.map +0 -1
- package/build/commands/openfga_provision.js.map +0 -1
- package/build/configure.d.ts.map +0 -1
- package/build/configure.js.map +0 -1
- package/build/index.d.ts.map +0 -1
- package/build/index.js.map +0 -1
- package/build/providers/authz_provider.d.ts.map +0 -1
- package/build/providers/authz_provider.js.map +0 -1
- package/build/services/main.d.ts.map +0 -1
- package/build/services/main.js.map +0 -1
- package/build/services/relations.d.ts.map +0 -1
- package/build/services/relations.js.map +0 -1
- package/build/src/catalog/catalog.d.ts.map +0 -1
- package/build/src/catalog/catalog.js.map +0 -1
- package/build/src/catalog/catalog_cache.d.ts.map +0 -1
- package/build/src/catalog/catalog_cache.js.map +0 -1
- package/build/src/clock.d.ts.map +0 -1
- package/build/src/clock.js.map +0 -1
- package/build/src/define_config.d.ts.map +0 -1
- package/build/src/define_config.js.map +0 -1
- package/build/src/drivers/database_driver.d.ts.map +0 -1
- package/build/src/drivers/database_driver.js.map +0 -1
- package/build/src/drivers/database_relations_driver.d.ts.map +0 -1
- package/build/src/drivers/database_relations_driver.js.map +0 -1
- package/build/src/drivers/openfga_driver.d.ts.map +0 -1
- package/build/src/drivers/openfga_driver.js.map +0 -1
- package/build/src/drivers/openfga_facts.d.ts.map +0 -1
- package/build/src/drivers/openfga_facts.js.map +0 -1
- package/build/src/drivers/openfga_relations_driver.d.ts.map +0 -1
- package/build/src/drivers/openfga_relations_driver.js.map +0 -1
- package/build/src/errors.d.ts.map +0 -1
- package/build/src/errors.js.map +0 -1
- package/build/src/expiry.d.ts.map +0 -1
- package/build/src/expiry.js.map +0 -1
- package/build/src/freeze.d.ts.map +0 -1
- package/build/src/freeze.js.map +0 -1
- package/build/src/hierarchical_resolver.d.ts.map +0 -1
- package/build/src/hierarchical_resolver.js.map +0 -1
- package/build/src/http/app_access_middleware.d.ts.map +0 -1
- package/build/src/http/app_access_middleware.js.map +0 -1
- package/build/src/http/resource_access_middleware.d.ts.map +0 -1
- package/build/src/http/resource_access_middleware.js.map +0 -1
- package/build/src/identity.d.ts.map +0 -1
- package/build/src/identity.js.map +0 -1
- package/build/src/manager.d.ts.map +0 -1
- package/build/src/manager.js.map +0 -1
- package/build/src/memoize_ancestors.d.ts.map +0 -1
- package/build/src/memoize_ancestors.js.map +0 -1
- package/build/src/models/authz_assignment.d.ts.map +0 -1
- package/build/src/models/authz_assignment.js.map +0 -1
- package/build/src/models/authz_deny.d.ts.map +0 -1
- package/build/src/models/authz_deny.js.map +0 -1
- package/build/src/models/authz_permission.d.ts.map +0 -1
- package/build/src/models/authz_permission.js.map +0 -1
- package/build/src/models/authz_role.d.ts.map +0 -1
- package/build/src/models/authz_role.js.map +0 -1
- package/build/src/models/authz_role_permission.d.ts.map +0 -1
- package/build/src/models/authz_role_permission.js.map +0 -1
- package/build/src/openfga.d.ts.map +0 -1
- package/build/src/openfga.js.map +0 -1
- package/build/src/reconcile.d.ts.map +0 -1
- package/build/src/reconcile.js.map +0 -1
- package/build/src/relation_partition_trigger.d.ts.map +0 -1
- package/build/src/relation_partition_trigger.js.map +0 -1
- package/build/src/relations/check_many.d.ts.map +0 -1
- package/build/src/relations/check_many.js.map +0 -1
- package/build/src/relations/define_relations_config.d.ts.map +0 -1
- package/build/src/relations/define_relations_config.js.map +0 -1
- package/build/src/relations/manager.d.ts.map +0 -1
- package/build/src/relations/manager.js.map +0 -1
- package/build/src/relations/reconcile.d.ts.map +0 -1
- package/build/src/relations/reconcile.js.map +0 -1
- package/build/src/relations/tuple_key.d.ts.map +0 -1
- package/build/src/relations/tuple_key.js.map +0 -1
- package/build/src/relations/tuple_order.d.ts.map +0 -1
- package/build/src/relations/tuple_order.js.map +0 -1
- package/build/src/relations_config_store.d.ts.map +0 -1
- package/build/src/relations_config_store.js.map +0 -1
- package/build/src/relations_reconcile.d.ts.map +0 -1
- package/build/src/relations_reconcile.js.map +0 -1
- package/build/src/scope_outbox.d.ts.map +0 -1
- package/build/src/scope_outbox.js.map +0 -1
- package/build/src/shared/backend_guard.d.ts.map +0 -1
- package/build/src/shared/backend_guard.js.map +0 -1
- package/build/src/shared/sql_expiry.d.ts.map +0 -1
- package/build/src/shared/sql_expiry.js.map +0 -1
- package/build/src/shared/transaction_guard.d.ts.map +0 -1
- package/build/src/shared/transaction_guard.js.map +0 -1
- package/build/src/sql_descendants.d.ts.map +0 -1
- package/build/src/sql_descendants.js.map +0 -1
- package/build/src/testing/contract.d.ts.map +0 -1
- package/build/src/testing/contract.js.map +0 -1
- package/build/src/testing/main.d.ts.map +0 -1
- package/build/src/testing/main.js.map +0 -1
- package/build/src/testing/migration_contract.d.ts.map +0 -1
- package/build/src/testing/migration_contract.js.map +0 -1
- package/build/src/testing/relations_contract.d.ts.map +0 -1
- package/build/src/testing/relations_contract.js.map +0 -1
- package/build/src/testing/relations_reconcile_contract.d.ts.map +0 -1
- package/build/src/testing/relations_reconcile_contract.js.map +0 -1
- package/build/src/testing/scope_outbox_contract.d.ts.map +0 -1
- package/build/src/testing/scope_outbox_contract.js.map +0 -1
- package/build/src/testing/scope_tree.d.ts.map +0 -1
- package/build/src/testing/scope_tree.js.map +0 -1
- package/build/src/testing/test_clock.d.ts.map +0 -1
- package/build/src/testing/test_clock.js.map +0 -1
- package/build/src/traits/authz_scopes.d.ts.map +0 -1
- package/build/src/traits/authz_scopes.js.map +0 -1
- package/build/src/traits/has_uuid.d.ts.map +0 -1
- package/build/src/traits/has_uuid.js.map +0 -1
- package/build/src/types.d.ts.map +0 -1
- package/build/src/types.js.map +0 -1
- package/build/stubs/main.d.ts.map +0 -1
- package/build/stubs/main.js.map +0 -1
package/build/src/manager.js
CHANGED
|
@@ -10,7 +10,7 @@ import { assertKnownScope, canonicalScopeTargets, isAuthzError, resolveChain, ro
|
|
|
10
10
|
import { CatalogCache, GLOBAL_OWNER_KEY, invalidateAuthzCatalog, isRoleVisibleWith, readLocalRoles, withAuthzCatalogWrite } from './catalog/catalog_cache.js';
|
|
11
11
|
import { assertAssignableAt } from './catalog/catalog.js';
|
|
12
12
|
import { systemClock } from './clock.js';
|
|
13
|
-
import { ActorRequiredError,
|
|
13
|
+
import { ActorRequiredError, AuthorizationBackendTimeoutError, isPartialWrite, AuthorizationFrozenError, AuthorizationConfigError, AuthorizationInternalError, CatalogConflictError, InvalidIdentityError, MassPurgeRefusedError, PruneInterruptedError, NoDescendantsResolverError, NotWithinError, PermissionNotDelegableError, RankExceededError, RoleImmutableError, RoleLevelAboveOwnerError, ScopeCycleError, ScopeResolverError, ScopeTreeDriftError, TooManyScopesError, UnknownPermissionError, UnknownRoleError, UnknownScopeError, FreezeHeldError, UnsupportedOperationError, ViewExpiredError, WithinRequiredError, WithinRootForbiddenError, ScopeDriftUnguardedError, ScopeDepthLimitError, ScopeRequeueRefusedError, StaleSourceRefusedError, OperatorWindowExpiredError, isDeploymentFailure, isTransientRelayFailure, markDeploymentFailure, } from './errors.js';
|
|
14
14
|
import { APP_SCOPE_TYPE, normalizeAuthorizationCapabilities } from './types.js';
|
|
15
15
|
import { memoizeAncestors } from './memoize_ancestors.js';
|
|
16
16
|
import { AUTHZ_TABLES_ORIGIN } from './reconcile.js';
|
|
@@ -77,6 +77,14 @@ export const DEFAULT_RELAY_BATCH = 100;
|
|
|
77
77
|
export const DEFAULT_RELAY_LIMIT = 10_000;
|
|
78
78
|
/** Páginas que `authz:reconcile` pasea para MEDIR la ventana del relay (3b-3a). */
|
|
79
79
|
const RELAY_WINDOW_MAX_PAGES = 1_000;
|
|
80
|
+
/**
|
|
81
|
+
* **Fallos del relay que solo dicen algo de la posición del HIJO** (asentar · cierre 2, O-2 del re-ataque): el
|
|
82
|
+
* `E_AUTHZ_SCOPE_TREE_DRIFT` del respaldo (el consumidor no pone al hijo bajo el padre ENCOLADO). La pasada contamina
|
|
83
|
+
* solo la clave del hijo, no la del padre encolado: un `attached` de OTRO hijo bajo ese padre escribe otra arista y
|
|
84
|
+
* conmuta (la misma lectura que la variante B del censo de aparcadas, alpha.8). Hasta aquí, mientras la entrada fallaba
|
|
85
|
+
* —hasta `maxAttempts` pasadas, y una más tras cada `requeue`— taponaba la org entera para los hijos nuevos.
|
|
86
|
+
*/
|
|
87
|
+
const CHILD_ONLY_FAILURES = new WeakSet();
|
|
80
88
|
/**
|
|
81
89
|
* **Saltos que la sonda de `only` sigue hacia atrás para heredar el ORIGEN de
|
|
82
90
|
* un bloqueo** (2.4.0-alpha.6). Cada salto es una consulta `earlierPending`
|
|
@@ -1214,6 +1222,7 @@ export class AuthorizationManager {
|
|
|
1214
1222
|
const parked = new Set();
|
|
1215
1223
|
/** El último id visto: la outbox pagina desde ahí (lo saltado se queda). */
|
|
1216
1224
|
let after;
|
|
1225
|
+
const passContext = { outbox, batchSize, appliedThisPass: [] };
|
|
1217
1226
|
const defer = (item, keys, reason, error, origin) => {
|
|
1218
1227
|
for (const key of keys)
|
|
1219
1228
|
block(key, item.id, origin);
|
|
@@ -1295,24 +1304,42 @@ export class AuthorizationManager {
|
|
|
1295
1304
|
}
|
|
1296
1305
|
}
|
|
1297
1306
|
}
|
|
1307
|
+
let appliedHow;
|
|
1298
1308
|
try {
|
|
1299
|
-
await this.#applyScopeChange(driver, item);
|
|
1309
|
+
appliedHow = await this.#applyScopeChange(driver, item, passContext);
|
|
1300
1310
|
}
|
|
1301
1311
|
catch (error) {
|
|
1302
1312
|
const message = error instanceof Error ? error.message : String(error);
|
|
1303
|
-
const transient =
|
|
1313
|
+
const transient = isTransientRelayFailure(error);
|
|
1314
|
+
const code = typeof error?.code === 'string' ? error.code : undefined;
|
|
1304
1315
|
await outbox.markFailed(item.id, message, { transient });
|
|
1305
|
-
|
|
1316
|
+
const failedKeys = typeof error === 'object' && error !== null && CHILD_ONLY_FAILURES.has(error) ? [scopeKey(item.change.child)] : keys;
|
|
1317
|
+
for (const key of failedKeys)
|
|
1306
1318
|
block(key, item.id, 'failed');
|
|
1307
1319
|
parked.add(id);
|
|
1308
|
-
failures.push({
|
|
1320
|
+
failures.push({
|
|
1321
|
+
id: item.id,
|
|
1322
|
+
change: item.change,
|
|
1323
|
+
error: message,
|
|
1324
|
+
transient,
|
|
1325
|
+
...(code !== undefined ? { code } : {}),
|
|
1326
|
+
...(isDeploymentFailure(error) ? { deployment: true } : {}),
|
|
1327
|
+
});
|
|
1309
1328
|
entries.push({ id: item.id, change: item.change, status: 'failed', reason: message, attempts: item.attempts });
|
|
1310
1329
|
continue;
|
|
1311
1330
|
}
|
|
1312
1331
|
await outbox.markApplied(item.id);
|
|
1313
1332
|
done.add(id);
|
|
1314
1333
|
applied.push({ id: item.id, change: item.change, attempts: item.attempts });
|
|
1315
|
-
|
|
1334
|
+
passContext.appliedThisPass.push(item.change);
|
|
1335
|
+
entries.push({
|
|
1336
|
+
id: item.id,
|
|
1337
|
+
change: item.change,
|
|
1338
|
+
status: 'applied',
|
|
1339
|
+
attempts: item.attempts,
|
|
1340
|
+
...(appliedHow?.reason !== undefined ? { reason: appliedHow.reason } : {}),
|
|
1341
|
+
...(appliedHow?.appliedParent !== undefined ? { appliedParent: appliedHow.appliedParent } : {}),
|
|
1342
|
+
});
|
|
1316
1343
|
}
|
|
1317
1344
|
// Una outbox que ignora `after` devuelve el mismo lote atascado: la
|
|
1318
1345
|
// pasada termina aquí en vez de dar vueltas (lo que quede, y lo que
|
|
@@ -1380,18 +1407,6 @@ export class AuthorizationManager {
|
|
|
1380
1407
|
'lo que no se pidió (filtra en el puerto, no en memoria).');
|
|
1381
1408
|
}
|
|
1382
1409
|
}
|
|
1383
|
-
/**
|
|
1384
|
-
* La caída del BACKEND no dice nada de la entrada (alpha.5 · R2a): un
|
|
1385
|
-
* `AuthorizationBackendError` (503; el timeout es uno), y en general
|
|
1386
|
-
* cualquier 503 (el freeze, el resolutor caído). Todo lo demás —422, 500,
|
|
1387
|
-
* `E_AUTHZ_SCOPE_TREE_DRIFT`, el padre inexistente, un error sin status de
|
|
1388
|
-
* un driver de terceros— es de la entrada y cuenta hacia el aparcado.
|
|
1389
|
-
*/
|
|
1390
|
-
static #isTransientRelayFailure(error) {
|
|
1391
|
-
if (error instanceof AuthorizationBackendError)
|
|
1392
|
-
return true;
|
|
1393
|
-
return typeof error === 'object' && error !== null && error.status === 503;
|
|
1394
|
-
}
|
|
1395
1410
|
/**
|
|
1396
1411
|
* Las claves de scope de lo APARCADO ⇒ el id aparcado que las nombra
|
|
1397
1412
|
* (alpha.5 · R2a). El censo lo lee `#relayInputs`: el `dead` ya leído si
|
|
@@ -2112,17 +2127,105 @@ export class AuthorizationManager {
|
|
|
2112
2127
|
* —el driver demuestra cero o lanza—, arista al final** (S6). Al revés,
|
|
2113
2128
|
* una purga muerta a medias dejaría grants vivos en un scope sin ancestro,
|
|
2114
2129
|
* los denies heredados dejarían de aplicar y esos permisos serían
|
|
2115
|
-
* INDENEGABLES (invariante 2).
|
|
2130
|
+
* INDENEGABLES (invariante 2). **Salvo el PADRE** (lote C · TREE): un
|
|
2131
|
+
* `attached`/`moved` se aplica con el padre FRESCO del consumidor, no con
|
|
2132
|
+
* el encolado (ver el cuerpo); devuelve `'superseded'` si el nodo ya no
|
|
2133
|
+
* existe en el consumidor (aplicada sin arista).
|
|
2116
2134
|
*/
|
|
2117
|
-
async #applyScopeChange(driver, item) {
|
|
2135
|
+
async #applyScopeChange(driver, item, context) {
|
|
2118
2136
|
const change = item.change;
|
|
2119
|
-
if (change.op === 'attached') {
|
|
2120
|
-
|
|
2121
|
-
|
|
2122
|
-
|
|
2123
|
-
|
|
2124
|
-
|
|
2125
|
-
|
|
2137
|
+
if (change.op === 'attached' || change.op === 'moved') {
|
|
2138
|
+
// **Asentar · cierre 1 (B4 del auditor del panel de estrategia)**: el padre FRESCO es SOLO para un driver que
|
|
2139
|
+
// mantiene el árbol como HECHOS en su store (`capabilities.hierarchyFacts`: `openfga`). En `database` no hay árbol
|
|
2140
|
+
// que pueda divergir —decide `resolveChain` en cada pregunta—, así que su relay se comporta EXACTAMENTE como en
|
|
2141
|
+
// `f19fd37`: el padre ENCOLADO, sin resolutor ni modos de fallo nuevos (caso de paridad en `scope_outbox.spec`).
|
|
2142
|
+
if (driver.capabilities?.hierarchyFacts !== true) {
|
|
2143
|
+
if (change.op === 'attached')
|
|
2144
|
+
await driver.onScopeAttached?.(change.child, change.parent);
|
|
2145
|
+
else
|
|
2146
|
+
await driver.onScopeMoved?.(change.child, change.parent);
|
|
2147
|
+
return undefined;
|
|
2148
|
+
}
|
|
2149
|
+
// **El relay aplica el padre FRESCO del consumidor** (lote C · TREE, decisión del dueño 2026-10-20 (1), (d)
|
|
2150
|
+
// corregida del juez; 🟠 «TREE con outbox»). El padre ENCOLADO es el que el consumidor quería al notificar, y la
|
|
2151
|
+
// receta publicada notifica ANTES de confirmar la fila: dos `moved` del MISMO nodo pueden confirmar en un orden y
|
|
2152
|
+
// encolarse en el otro, y relevar el padre encolado dejaba el store, para siempre y en silencio, con OTRO padre que
|
|
2153
|
+
// la base del consumidor (medido: 1000/1000 forzado en PG y 200/200 en MySQL). Convergencia (juez TREE §2): la
|
|
2154
|
+
// entrada del ÚLTIMO commit de un nodo se aplica después de ese commit y lee el estado final.
|
|
2155
|
+
//
|
|
2156
|
+
// **Pero el resolutor no es fiable por construcción** (🔴 1 del auditor del paso 4; firma del dueño 2026-10-21): uno
|
|
2157
|
+
// filtrado por tenant responde `null` de todo en un comando (README «the realistic accident») y uno con caché/réplica
|
|
2158
|
+
// responde el padre VIEJO. Aplicar a ciegas convertía un fallo ruidoso en un TREE persistente y MUDO. Regla mínima:
|
|
2159
|
+
// el padre fresco se aplica cuando lo RESPALDA la propia cola —otra entrada del mismo hijo que lo dice (pendiente,
|
|
2160
|
+
// aplicada en esta pasada o aplicada después)—; si no, la entrada FALLA con un error que CONSUME intento (y se aparca
|
|
2161
|
+
// con su motivo tras `maxAttempts`, exit ≠ 0 en cada pasada):
|
|
2162
|
+
// - cadena con padre = encolado ⇒ se aplica (el caso normal);
|
|
2163
|
+
// - padre ≠ encolado RESPALDADO (otra entrada del hijo con ese padre) ⇒ se aplica el fresco, `reason:
|
|
2164
|
+
// 'consumer-parent'` y `appliedParent` en el reporte (la carrera S1: el store converge);
|
|
2165
|
+
// - padre ≠ encolado SIN respaldo ⇒ 500 `E_AUTHZ_SCOPE_TREE_DRIFT` (resolutor rancio, o un cambio no notificado);
|
|
2166
|
+
// con un resolutor que se refresca (TTL), un reintento posterior ve el padre encolado y lo aplica;
|
|
2167
|
+
// - `null` RESPALDADO por un `detached` del hijo en la cola ⇒ aplicada SIN arista, `reason: 'superseded'` (D×D no
|
|
2168
|
+
// resucita un nodo borrado);
|
|
2169
|
+
// - `null` sin respaldo ⇒ 422 `E_AUTHZ_UNKNOWN_SCOPE` (resolutor filtrado por tenant, o hijo huérfano en la base);
|
|
2170
|
+
// - cadena TRUNCADA (`[hijo]` de un nodo que no es la raíz: le falta `app`) ⇒ 503 `E_AUTHZ_RESOLVER_FAILED`
|
|
2171
|
+
// (auditor ⚪ 7: jamás inventar la raíz);
|
|
2172
|
+
// - el resolutor LANZA ⇒ 503 transitorio, no consume intento (regla de alpha.5);
|
|
2173
|
+
// - sin `scopes.resolveChain` ⇒ 500 `E_AUTHZ_CONFIG` (desviación 6 del paso 4).
|
|
2174
|
+
// Residuo declarado: con un resolutor rancio Y otra entrada del mismo hijo que respalde justo el padre rancio (dos
|
|
2175
|
+
// movimientos seguidos del nodo dentro del TTL de la caché) el relay no puede distinguirlo de la carrera S1 y aplica;
|
|
2176
|
+
// el reporte lo dice (`consumer-parent`, exit 1 del relay) y la red (`authz:reconcile --dry-run`, su fase `tree`) lo
|
|
2177
|
+
// ve; el campo `drift.treeMismatch` NO existe todavía (llega en 2.6). Límite declarado `openfga.relay.stale-resolver`.
|
|
2178
|
+
let resolver;
|
|
2179
|
+
try {
|
|
2180
|
+
resolver = this.#resolver('authz:scopes:relay');
|
|
2181
|
+
}
|
|
2182
|
+
catch (error) {
|
|
2183
|
+
// Desviación 6 del paso 4, con su caso (asentar · cierre 1, 🟡-3 del tester): un proceso relay sin
|
|
2184
|
+
// `scopes.resolveChain` es un DESPLIEGUE mal configurado ⇒ transitorio para el relay (inv. 5): no consume intento
|
|
2185
|
+
// ni aparca la cola entera. Hasta el caso, el 500 contaba intento y la aparcaba en `maxAttempts` pasadas.
|
|
2186
|
+
throw markDeploymentFailure(error);
|
|
2187
|
+
}
|
|
2188
|
+
const chain = await resolveChain(resolver, change.child, 'authz:scopes:relay');
|
|
2189
|
+
const childKey = scopeKey(change.child);
|
|
2190
|
+
if (chain === null) {
|
|
2191
|
+
if (await this.#relayBacking(context, item, (other) => other.op === 'detached' && scopeKey(other.child) === childKey)) {
|
|
2192
|
+
return { reason: 'superseded', appliedParent: null };
|
|
2193
|
+
}
|
|
2194
|
+
throw new UnknownScopeError(`authz:scopes:relay: el resolutor del consumidor no conoce ${childKey} (devolvió null) y ninguna entrada ` +
|
|
2195
|
+
`'detached' de ese nodo en la cola lo respalda. No se aplica nada: un resolutor filtrado por tenant (sin ` +
|
|
2196
|
+
`petición en el comando) o con caché, o una fila huérfana en tu árbol. El resolutor del relay tiene que leer ` +
|
|
2197
|
+
`lo CONFIRMADO, sin contexto de tenant. La entrada consume intento y se aparca si persiste.`);
|
|
2198
|
+
}
|
|
2199
|
+
if (chain.length < 2) {
|
|
2200
|
+
throw new ScopeResolverError('authz:scopes:relay', new TypeError(`resolveChain devolvió una cadena de un solo elemento para ${childKey}: le falta la raíz 'app'`));
|
|
2201
|
+
}
|
|
2202
|
+
const parent = chain[1];
|
|
2203
|
+
const parentKey = scopeKey(parent);
|
|
2204
|
+
let reason;
|
|
2205
|
+
if (parentKey !== scopeKey(change.parent)) {
|
|
2206
|
+
const backed = await this.#relayBacking(context, item, (other) => other.op !== 'detached' && scopeKey(other.child) === childKey && scopeKey(other.parent) === parentKey);
|
|
2207
|
+
if (!backed) {
|
|
2208
|
+
const drift = new ScopeTreeDriftError(`authz:scopes:relay: el padre de ${childKey} que da el resolutor del consumidor (${parentKey}) no es el ` +
|
|
2209
|
+
`encolado (${scopeKey(change.parent)}) y ninguna otra entrada de ese nodo en la cola lo respalda. No se ` +
|
|
2210
|
+
`aplica nada: un resolutor con caché o réplica atrasada, o un cambio de árbol no notificado. El resolutor del ` +
|
|
2211
|
+
`relay tiene que leer lo CONFIRMADO, sin TTL. La entrada consume intento y se aparca si persiste. Si tu base ` +
|
|
2212
|
+
`ya tiene a ${childKey} bajo ${parentKey} y esta entrada es una intención VIEJA (otra entrada del nodo se ` +
|
|
2213
|
+
`aplicó antes en otra pasada), la salida es volver a notificar scopes.moved(${childKey}, ${parentKey}) —la ` +
|
|
2214
|
+
`entrada nueva la respalda— y reencolar #${String(item.id)} con authz:scopes:requeue ` +
|
|
2215
|
+
`--id=${String(item.id)} --apply. Si ese requeue se niega (E_AUTHZ_REQUEUE_REFUSED) solo por cambios ` +
|
|
2216
|
+
`aplicados de OTROS hijos bajo ${scopeKey(change.parent)}, el conflicto es falso: authz:scopes:requeue ` +
|
|
2217
|
+
`--id=${String(item.id)} --force y después authz:scopes:relay (el relay vuelve a resolver el padre en ` +
|
|
2218
|
+
`fresco y exige respaldo: no revierte nada).`);
|
|
2219
|
+
CHILD_ONLY_FAILURES.add(drift);
|
|
2220
|
+
throw drift;
|
|
2221
|
+
}
|
|
2222
|
+
reason = 'consumer-parent';
|
|
2223
|
+
}
|
|
2224
|
+
if (change.op === 'attached')
|
|
2225
|
+
await driver.onScopeAttached?.(change.child, parent);
|
|
2226
|
+
else
|
|
2227
|
+
await driver.onScopeMoved?.(change.child, parent);
|
|
2228
|
+
return { ...(reason !== undefined ? { reason } : {}), appliedParent: parent };
|
|
2126
2229
|
}
|
|
2127
2230
|
// La auditoría no pierde al autor por haber pasado por una cola.
|
|
2128
2231
|
const event = {
|
|
@@ -2134,6 +2237,32 @@ export class AuthorizationManager {
|
|
|
2134
2237
|
await driver.onScopeDetached?.(change.child);
|
|
2135
2238
|
await this.#notify(event);
|
|
2136
2239
|
}
|
|
2240
|
+
/**
|
|
2241
|
+
* **¿La cola RESPALDA el padre fresco?** (asentar · cierre 1, 🔴 1 del auditor). Otra entrada del mismo hijo que lo
|
|
2242
|
+
* dice: aplicada en ESTA pasada, PENDIENTE (cualquier id; se pagina la cola entera, solo cuando el fresco no coincide
|
|
2243
|
+
* con el encolado: raro) o APLICADA con un id posterior (`laterApplied`, si la outbox lo trae). Nunca una aplicada
|
|
2244
|
+
* ANTERIOR de otra pasada: una caché rancia diría justo el padre de esa entrada vieja.
|
|
2245
|
+
*/
|
|
2246
|
+
async #relayBacking(context, item, matches) {
|
|
2247
|
+
if (context.appliedThisPass.some(matches))
|
|
2248
|
+
return true;
|
|
2249
|
+
const mine = String(item.id);
|
|
2250
|
+
let after;
|
|
2251
|
+
for (let page = 0; page < RELAY_WINDOW_MAX_PAGES; page++) {
|
|
2252
|
+
const batch = await context.outbox.pending(context.batchSize, after);
|
|
2253
|
+
if (batch.some((other) => String(other.id) !== mine && matches(other.change)))
|
|
2254
|
+
return true;
|
|
2255
|
+
if (batch.length < context.batchSize)
|
|
2256
|
+
break;
|
|
2257
|
+
after = batch[batch.length - 1].id;
|
|
2258
|
+
}
|
|
2259
|
+
if (typeof context.outbox.laterApplied === 'function') {
|
|
2260
|
+
const later = await context.outbox.laterApplied(item.id, [item.change.child], RELAY_WINDOW_MAX_PAGES);
|
|
2261
|
+
if (later.some((other) => matches(other.change)))
|
|
2262
|
+
return true;
|
|
2263
|
+
}
|
|
2264
|
+
return false;
|
|
2265
|
+
}
|
|
2137
2266
|
/** Cota entera positiva de las opciones del relay (500 si llega otra cosa). */
|
|
2138
2267
|
/**
|
|
2139
2268
|
* **Una opción desconocida es 500, nunca silencio** (2.4.0-alpha.8 · X-1;
|
|
@@ -3826,4 +3955,3 @@ export class AuthorizationManager {
|
|
|
3826
3955
|
}
|
|
3827
3956
|
}
|
|
3828
3957
|
_a = AuthorizationManager;
|
|
3829
|
-
//# sourceMappingURL=manager.js.map
|
|
@@ -77,6 +77,11 @@ declare const AuthzAssignment_base: {
|
|
|
77
77
|
<Model extends import("@adonisjs/lucid/types/model").LucidModel>(this: Model, event: "paginate", handler: import("@adonisjs/lucid/types/model").HooksHandler<import("@adonisjs/lucid/types/model").ModelPaginatorContract<InstanceType<Model>>, "paginate">): void;
|
|
78
78
|
<Model extends import("@adonisjs/lucid/types/model").LucidModel, Event extends import("@adonisjs/lucid/types/model").EventsList>(this: Model, event: Event, handler: import("@adonisjs/lucid/types/model").HooksHandler<InstanceType<Model>, Event>): void;
|
|
79
79
|
};
|
|
80
|
+
before: {
|
|
81
|
+
<Model extends import("@adonisjs/lucid/types/model").LucidModel, Event extends "find" | "fetch">(this: Model, event: Event, handler: import("@adonisjs/lucid/types/model").HooksHandler<import("@adonisjs/lucid/types/model").ModelQueryBuilderContract<Model>, Event>): void;
|
|
82
|
+
<Model extends import("@adonisjs/lucid/types/model").LucidModel>(this: Model, event: "paginate", handler: import("@adonisjs/lucid/types/model").HooksHandler<[import("@adonisjs/lucid/types/model").ModelQueryBuilderContract<Model>, import("@adonisjs/lucid/types/model").ModelQueryBuilderContract<Model>], "paginate">): void;
|
|
83
|
+
<Model extends import("@adonisjs/lucid/types/model").LucidModel, Event extends import("@adonisjs/lucid/types/model").EventsList>(this: Model, event: Event, handler: import("@adonisjs/lucid/types/model").HooksHandler<InstanceType<Model>, Event>): void;
|
|
84
|
+
};
|
|
80
85
|
readonly booted: boolean;
|
|
81
86
|
$columnsDefinitions: Map<string, import("@adonisjs/lucid/types/model").ModelColumnOptions>;
|
|
82
87
|
$relationsDefinitions: Map<string, import("@adonisjs/lucid/types/relations").RelationshipsContract>;
|
|
@@ -113,11 +118,6 @@ declare const AuthzAssignment_base: {
|
|
|
113
118
|
};
|
|
114
119
|
$defineProperty: <Model extends import("@adonisjs/lucid/types/model").LucidModel, Prop extends keyof Model>(this: Model, propertyName: Prop, defaultValue: Model[Prop], strategy: "inherit" | "define" | ((value: Model[Prop]) => Model[Prop])) => void;
|
|
115
120
|
boot: () => void;
|
|
116
|
-
before: {
|
|
117
|
-
<Model extends import("@adonisjs/lucid/types/model").LucidModel, Event extends "find" | "fetch">(this: Model, event: Event, handler: import("@adonisjs/lucid/types/model").HooksHandler<import("@adonisjs/lucid/types/model").ModelQueryBuilderContract<Model>, Event>): void;
|
|
118
|
-
<Model extends import("@adonisjs/lucid/types/model").LucidModel>(this: Model, event: "paginate", handler: import("@adonisjs/lucid/types/model").HooksHandler<[import("@adonisjs/lucid/types/model").ModelQueryBuilderContract<Model>, import("@adonisjs/lucid/types/model").ModelQueryBuilderContract<Model>], "paginate">): void;
|
|
119
|
-
<Model extends import("@adonisjs/lucid/types/model").LucidModel, Event extends import("@adonisjs/lucid/types/model").EventsList>(this: Model, event: Event, handler: import("@adonisjs/lucid/types/model").HooksHandler<InstanceType<Model>, Event>): void;
|
|
120
|
-
};
|
|
121
121
|
create: <T extends import("@adonisjs/lucid/types/model").LucidModel>(this: T, values: Partial<import("@adonisjs/lucid/types/model").ModelAttributes<InstanceType<T>>>, options?: import("@adonisjs/lucid/types/model").ModelAssignOptions) => Promise<InstanceType<T>>;
|
|
122
122
|
createQuietly: <T extends import("@adonisjs/lucid/types/model").LucidModel>(this: T, values: Partial<import("@adonisjs/lucid/types/model").ModelAttributes<InstanceType<T>>>, options?: import("@adonisjs/lucid/types/model").ModelAssignOptions) => Promise<InstanceType<T>>;
|
|
123
123
|
createMany: <T extends import("@adonisjs/lucid/types/model").LucidModel>(this: T, values: Partial<import("@adonisjs/lucid/types/model").ModelAttributes<InstanceType<T>>>[], options?: import("@adonisjs/lucid/types/model").ModelAssignOptions) => Promise<InstanceType<T>[]>;
|
|
@@ -163,4 +163,3 @@ export default class AuthzAssignment extends AuthzAssignment_base {
|
|
|
163
163
|
createdAt: DateTime;
|
|
164
164
|
}
|
|
165
165
|
export {};
|
|
166
|
-
//# sourceMappingURL=authz_assignment.d.ts.map
|
|
@@ -75,6 +75,11 @@ declare const AuthzDeny_base: {
|
|
|
75
75
|
<Model extends import("@adonisjs/lucid/types/model").LucidModel>(this: Model, event: "paginate", handler: import("@adonisjs/lucid/types/model").HooksHandler<import("@adonisjs/lucid/types/model").ModelPaginatorContract<InstanceType<Model>>, "paginate">): void;
|
|
76
76
|
<Model extends import("@adonisjs/lucid/types/model").LucidModel, Event extends import("@adonisjs/lucid/types/model").EventsList>(this: Model, event: Event, handler: import("@adonisjs/lucid/types/model").HooksHandler<InstanceType<Model>, Event>): void;
|
|
77
77
|
};
|
|
78
|
+
before: {
|
|
79
|
+
<Model extends import("@adonisjs/lucid/types/model").LucidModel, Event extends "find" | "fetch">(this: Model, event: Event, handler: import("@adonisjs/lucid/types/model").HooksHandler<import("@adonisjs/lucid/types/model").ModelQueryBuilderContract<Model>, Event>): void;
|
|
80
|
+
<Model extends import("@adonisjs/lucid/types/model").LucidModel>(this: Model, event: "paginate", handler: import("@adonisjs/lucid/types/model").HooksHandler<[import("@adonisjs/lucid/types/model").ModelQueryBuilderContract<Model>, import("@adonisjs/lucid/types/model").ModelQueryBuilderContract<Model>], "paginate">): void;
|
|
81
|
+
<Model extends import("@adonisjs/lucid/types/model").LucidModel, Event extends import("@adonisjs/lucid/types/model").EventsList>(this: Model, event: Event, handler: import("@adonisjs/lucid/types/model").HooksHandler<InstanceType<Model>, Event>): void;
|
|
82
|
+
};
|
|
78
83
|
readonly booted: boolean;
|
|
79
84
|
$columnsDefinitions: Map<string, import("@adonisjs/lucid/types/model").ModelColumnOptions>;
|
|
80
85
|
$relationsDefinitions: Map<string, import("@adonisjs/lucid/types/relations").RelationshipsContract>;
|
|
@@ -111,11 +116,6 @@ declare const AuthzDeny_base: {
|
|
|
111
116
|
};
|
|
112
117
|
$defineProperty: <Model extends import("@adonisjs/lucid/types/model").LucidModel, Prop extends keyof Model>(this: Model, propertyName: Prop, defaultValue: Model[Prop], strategy: "inherit" | "define" | ((value: Model[Prop]) => Model[Prop])) => void;
|
|
113
118
|
boot: () => void;
|
|
114
|
-
before: {
|
|
115
|
-
<Model extends import("@adonisjs/lucid/types/model").LucidModel, Event extends "find" | "fetch">(this: Model, event: Event, handler: import("@adonisjs/lucid/types/model").HooksHandler<import("@adonisjs/lucid/types/model").ModelQueryBuilderContract<Model>, Event>): void;
|
|
116
|
-
<Model extends import("@adonisjs/lucid/types/model").LucidModel>(this: Model, event: "paginate", handler: import("@adonisjs/lucid/types/model").HooksHandler<[import("@adonisjs/lucid/types/model").ModelQueryBuilderContract<Model>, import("@adonisjs/lucid/types/model").ModelQueryBuilderContract<Model>], "paginate">): void;
|
|
117
|
-
<Model extends import("@adonisjs/lucid/types/model").LucidModel, Event extends import("@adonisjs/lucid/types/model").EventsList>(this: Model, event: Event, handler: import("@adonisjs/lucid/types/model").HooksHandler<InstanceType<Model>, Event>): void;
|
|
118
|
-
};
|
|
119
119
|
create: <T extends import("@adonisjs/lucid/types/model").LucidModel>(this: T, values: Partial<import("@adonisjs/lucid/types/model").ModelAttributes<InstanceType<T>>>, options?: import("@adonisjs/lucid/types/model").ModelAssignOptions) => Promise<InstanceType<T>>;
|
|
120
120
|
createQuietly: <T extends import("@adonisjs/lucid/types/model").LucidModel>(this: T, values: Partial<import("@adonisjs/lucid/types/model").ModelAttributes<InstanceType<T>>>, options?: import("@adonisjs/lucid/types/model").ModelAssignOptions) => Promise<InstanceType<T>>;
|
|
121
121
|
createMany: <T extends import("@adonisjs/lucid/types/model").LucidModel>(this: T, values: Partial<import("@adonisjs/lucid/types/model").ModelAttributes<InstanceType<T>>>[], options?: import("@adonisjs/lucid/types/model").ModelAssignOptions) => Promise<InstanceType<T>[]>;
|
|
@@ -158,4 +158,3 @@ export default class AuthzDeny extends AuthzDeny_base {
|
|
|
158
158
|
createdAt: DateTime;
|
|
159
159
|
}
|
|
160
160
|
export {};
|
|
161
|
-
//# sourceMappingURL=authz_deny.d.ts.map
|
|
@@ -75,6 +75,11 @@ declare const AuthzPermission_base: {
|
|
|
75
75
|
<Model extends import("@adonisjs/lucid/types/model").LucidModel>(this: Model, event: "paginate", handler: import("@adonisjs/lucid/types/model").HooksHandler<import("@adonisjs/lucid/types/model").ModelPaginatorContract<InstanceType<Model>>, "paginate">): void;
|
|
76
76
|
<Model extends import("@adonisjs/lucid/types/model").LucidModel, Event extends import("@adonisjs/lucid/types/model").EventsList>(this: Model, event: Event, handler: import("@adonisjs/lucid/types/model").HooksHandler<InstanceType<Model>, Event>): void;
|
|
77
77
|
};
|
|
78
|
+
before: {
|
|
79
|
+
<Model extends import("@adonisjs/lucid/types/model").LucidModel, Event extends "find" | "fetch">(this: Model, event: Event, handler: import("@adonisjs/lucid/types/model").HooksHandler<import("@adonisjs/lucid/types/model").ModelQueryBuilderContract<Model>, Event>): void;
|
|
80
|
+
<Model extends import("@adonisjs/lucid/types/model").LucidModel>(this: Model, event: "paginate", handler: import("@adonisjs/lucid/types/model").HooksHandler<[import("@adonisjs/lucid/types/model").ModelQueryBuilderContract<Model>, import("@adonisjs/lucid/types/model").ModelQueryBuilderContract<Model>], "paginate">): void;
|
|
81
|
+
<Model extends import("@adonisjs/lucid/types/model").LucidModel, Event extends import("@adonisjs/lucid/types/model").EventsList>(this: Model, event: Event, handler: import("@adonisjs/lucid/types/model").HooksHandler<InstanceType<Model>, Event>): void;
|
|
82
|
+
};
|
|
78
83
|
readonly booted: boolean;
|
|
79
84
|
$columnsDefinitions: Map<string, import("@adonisjs/lucid/types/model").ModelColumnOptions>;
|
|
80
85
|
$relationsDefinitions: Map<string, import("@adonisjs/lucid/types/relations").RelationshipsContract>;
|
|
@@ -111,11 +116,6 @@ declare const AuthzPermission_base: {
|
|
|
111
116
|
};
|
|
112
117
|
$defineProperty: <Model extends import("@adonisjs/lucid/types/model").LucidModel, Prop extends keyof Model>(this: Model, propertyName: Prop, defaultValue: Model[Prop], strategy: "inherit" | "define" | ((value: Model[Prop]) => Model[Prop])) => void;
|
|
113
118
|
boot: () => void;
|
|
114
|
-
before: {
|
|
115
|
-
<Model extends import("@adonisjs/lucid/types/model").LucidModel, Event extends "find" | "fetch">(this: Model, event: Event, handler: import("@adonisjs/lucid/types/model").HooksHandler<import("@adonisjs/lucid/types/model").ModelQueryBuilderContract<Model>, Event>): void;
|
|
116
|
-
<Model extends import("@adonisjs/lucid/types/model").LucidModel>(this: Model, event: "paginate", handler: import("@adonisjs/lucid/types/model").HooksHandler<[import("@adonisjs/lucid/types/model").ModelQueryBuilderContract<Model>, import("@adonisjs/lucid/types/model").ModelQueryBuilderContract<Model>], "paginate">): void;
|
|
117
|
-
<Model extends import("@adonisjs/lucid/types/model").LucidModel, Event extends import("@adonisjs/lucid/types/model").EventsList>(this: Model, event: Event, handler: import("@adonisjs/lucid/types/model").HooksHandler<InstanceType<Model>, Event>): void;
|
|
118
|
-
};
|
|
119
119
|
create: <T extends import("@adonisjs/lucid/types/model").LucidModel>(this: T, values: Partial<import("@adonisjs/lucid/types/model").ModelAttributes<InstanceType<T>>>, options?: import("@adonisjs/lucid/types/model").ModelAssignOptions) => Promise<InstanceType<T>>;
|
|
120
120
|
createQuietly: <T extends import("@adonisjs/lucid/types/model").LucidModel>(this: T, values: Partial<import("@adonisjs/lucid/types/model").ModelAttributes<InstanceType<T>>>, options?: import("@adonisjs/lucid/types/model").ModelAssignOptions) => Promise<InstanceType<T>>;
|
|
121
121
|
createMany: <T extends import("@adonisjs/lucid/types/model").LucidModel>(this: T, values: Partial<import("@adonisjs/lucid/types/model").ModelAttributes<InstanceType<T>>>[], options?: import("@adonisjs/lucid/types/model").ModelAssignOptions) => Promise<InstanceType<T>[]>;
|
|
@@ -162,4 +162,3 @@ export default class AuthzPermission extends AuthzPermission_base {
|
|
|
162
162
|
updatedAt: DateTime;
|
|
163
163
|
}
|
|
164
164
|
export {};
|
|
165
|
-
//# sourceMappingURL=authz_permission.d.ts.map
|
|
@@ -77,6 +77,11 @@ declare const AuthzRole_base: {
|
|
|
77
77
|
<Model extends import("@adonisjs/lucid/types/model").LucidModel>(this: Model, event: "paginate", handler: import("@adonisjs/lucid/types/model").HooksHandler<import("@adonisjs/lucid/types/model").ModelPaginatorContract<InstanceType<Model>>, "paginate">): void;
|
|
78
78
|
<Model extends import("@adonisjs/lucid/types/model").LucidModel, Event extends import("@adonisjs/lucid/types/model").EventsList>(this: Model, event: Event, handler: import("@adonisjs/lucid/types/model").HooksHandler<InstanceType<Model>, Event>): void;
|
|
79
79
|
};
|
|
80
|
+
before: {
|
|
81
|
+
<Model extends import("@adonisjs/lucid/types/model").LucidModel, Event extends "find" | "fetch">(this: Model, event: Event, handler: import("@adonisjs/lucid/types/model").HooksHandler<import("@adonisjs/lucid/types/model").ModelQueryBuilderContract<Model>, Event>): void;
|
|
82
|
+
<Model extends import("@adonisjs/lucid/types/model").LucidModel>(this: Model, event: "paginate", handler: import("@adonisjs/lucid/types/model").HooksHandler<[import("@adonisjs/lucid/types/model").ModelQueryBuilderContract<Model>, import("@adonisjs/lucid/types/model").ModelQueryBuilderContract<Model>], "paginate">): void;
|
|
83
|
+
<Model extends import("@adonisjs/lucid/types/model").LucidModel, Event extends import("@adonisjs/lucid/types/model").EventsList>(this: Model, event: Event, handler: import("@adonisjs/lucid/types/model").HooksHandler<InstanceType<Model>, Event>): void;
|
|
84
|
+
};
|
|
80
85
|
readonly booted: boolean;
|
|
81
86
|
$columnsDefinitions: Map<string, import("@adonisjs/lucid/types/model").ModelColumnOptions>;
|
|
82
87
|
$relationsDefinitions: Map<string, import("@adonisjs/lucid/types/relations").RelationshipsContract>;
|
|
@@ -113,11 +118,6 @@ declare const AuthzRole_base: {
|
|
|
113
118
|
};
|
|
114
119
|
$defineProperty: <Model extends import("@adonisjs/lucid/types/model").LucidModel, Prop extends keyof Model>(this: Model, propertyName: Prop, defaultValue: Model[Prop], strategy: "inherit" | "define" | ((value: Model[Prop]) => Model[Prop])) => void;
|
|
115
120
|
boot: () => void;
|
|
116
|
-
before: {
|
|
117
|
-
<Model extends import("@adonisjs/lucid/types/model").LucidModel, Event extends "find" | "fetch">(this: Model, event: Event, handler: import("@adonisjs/lucid/types/model").HooksHandler<import("@adonisjs/lucid/types/model").ModelQueryBuilderContract<Model>, Event>): void;
|
|
118
|
-
<Model extends import("@adonisjs/lucid/types/model").LucidModel>(this: Model, event: "paginate", handler: import("@adonisjs/lucid/types/model").HooksHandler<[import("@adonisjs/lucid/types/model").ModelQueryBuilderContract<Model>, import("@adonisjs/lucid/types/model").ModelQueryBuilderContract<Model>], "paginate">): void;
|
|
119
|
-
<Model extends import("@adonisjs/lucid/types/model").LucidModel, Event extends import("@adonisjs/lucid/types/model").EventsList>(this: Model, event: Event, handler: import("@adonisjs/lucid/types/model").HooksHandler<InstanceType<Model>, Event>): void;
|
|
120
|
-
};
|
|
121
121
|
create: <T extends import("@adonisjs/lucid/types/model").LucidModel>(this: T, values: Partial<import("@adonisjs/lucid/types/model").ModelAttributes<InstanceType<T>>>, options?: import("@adonisjs/lucid/types/model").ModelAssignOptions) => Promise<InstanceType<T>>;
|
|
122
122
|
createQuietly: <T extends import("@adonisjs/lucid/types/model").LucidModel>(this: T, values: Partial<import("@adonisjs/lucid/types/model").ModelAttributes<InstanceType<T>>>, options?: import("@adonisjs/lucid/types/model").ModelAssignOptions) => Promise<InstanceType<T>>;
|
|
123
123
|
createMany: <T extends import("@adonisjs/lucid/types/model").LucidModel>(this: T, values: Partial<import("@adonisjs/lucid/types/model").ModelAttributes<InstanceType<T>>>[], options?: import("@adonisjs/lucid/types/model").ModelAssignOptions) => Promise<InstanceType<T>[]>;
|
|
@@ -170,4 +170,3 @@ export default class AuthzRole extends AuthzRole_base {
|
|
|
170
170
|
updatedAt: DateTime;
|
|
171
171
|
}
|
|
172
172
|
export {};
|
|
173
|
-
//# sourceMappingURL=authz_role.d.ts.map
|
|
@@ -75,6 +75,11 @@ declare const AuthzRolePermission_base: {
|
|
|
75
75
|
<Model extends import("@adonisjs/lucid/types/model").LucidModel>(this: Model, event: "paginate", handler: import("@adonisjs/lucid/types/model").HooksHandler<import("@adonisjs/lucid/types/model").ModelPaginatorContract<InstanceType<Model>>, "paginate">): void;
|
|
76
76
|
<Model extends import("@adonisjs/lucid/types/model").LucidModel, Event extends import("@adonisjs/lucid/types/model").EventsList>(this: Model, event: Event, handler: import("@adonisjs/lucid/types/model").HooksHandler<InstanceType<Model>, Event>): void;
|
|
77
77
|
};
|
|
78
|
+
before: {
|
|
79
|
+
<Model extends import("@adonisjs/lucid/types/model").LucidModel, Event extends "find" | "fetch">(this: Model, event: Event, handler: import("@adonisjs/lucid/types/model").HooksHandler<import("@adonisjs/lucid/types/model").ModelQueryBuilderContract<Model>, Event>): void;
|
|
80
|
+
<Model extends import("@adonisjs/lucid/types/model").LucidModel>(this: Model, event: "paginate", handler: import("@adonisjs/lucid/types/model").HooksHandler<[import("@adonisjs/lucid/types/model").ModelQueryBuilderContract<Model>, import("@adonisjs/lucid/types/model").ModelQueryBuilderContract<Model>], "paginate">): void;
|
|
81
|
+
<Model extends import("@adonisjs/lucid/types/model").LucidModel, Event extends import("@adonisjs/lucid/types/model").EventsList>(this: Model, event: Event, handler: import("@adonisjs/lucid/types/model").HooksHandler<InstanceType<Model>, Event>): void;
|
|
82
|
+
};
|
|
78
83
|
readonly booted: boolean;
|
|
79
84
|
$columnsDefinitions: Map<string, import("@adonisjs/lucid/types/model").ModelColumnOptions>;
|
|
80
85
|
$relationsDefinitions: Map<string, import("@adonisjs/lucid/types/relations").RelationshipsContract>;
|
|
@@ -111,11 +116,6 @@ declare const AuthzRolePermission_base: {
|
|
|
111
116
|
};
|
|
112
117
|
$defineProperty: <Model extends import("@adonisjs/lucid/types/model").LucidModel, Prop extends keyof Model>(this: Model, propertyName: Prop, defaultValue: Model[Prop], strategy: "inherit" | "define" | ((value: Model[Prop]) => Model[Prop])) => void;
|
|
113
118
|
boot: () => void;
|
|
114
|
-
before: {
|
|
115
|
-
<Model extends import("@adonisjs/lucid/types/model").LucidModel, Event extends "find" | "fetch">(this: Model, event: Event, handler: import("@adonisjs/lucid/types/model").HooksHandler<import("@adonisjs/lucid/types/model").ModelQueryBuilderContract<Model>, Event>): void;
|
|
116
|
-
<Model extends import("@adonisjs/lucid/types/model").LucidModel>(this: Model, event: "paginate", handler: import("@adonisjs/lucid/types/model").HooksHandler<[import("@adonisjs/lucid/types/model").ModelQueryBuilderContract<Model>, import("@adonisjs/lucid/types/model").ModelQueryBuilderContract<Model>], "paginate">): void;
|
|
117
|
-
<Model extends import("@adonisjs/lucid/types/model").LucidModel, Event extends import("@adonisjs/lucid/types/model").EventsList>(this: Model, event: Event, handler: import("@adonisjs/lucid/types/model").HooksHandler<InstanceType<Model>, Event>): void;
|
|
118
|
-
};
|
|
119
119
|
create: <T extends import("@adonisjs/lucid/types/model").LucidModel>(this: T, values: Partial<import("@adonisjs/lucid/types/model").ModelAttributes<InstanceType<T>>>, options?: import("@adonisjs/lucid/types/model").ModelAssignOptions) => Promise<InstanceType<T>>;
|
|
120
120
|
createQuietly: <T extends import("@adonisjs/lucid/types/model").LucidModel>(this: T, values: Partial<import("@adonisjs/lucid/types/model").ModelAttributes<InstanceType<T>>>, options?: import("@adonisjs/lucid/types/model").ModelAssignOptions) => Promise<InstanceType<T>>;
|
|
121
121
|
createMany: <T extends import("@adonisjs/lucid/types/model").LucidModel>(this: T, values: Partial<import("@adonisjs/lucid/types/model").ModelAttributes<InstanceType<T>>>[], options?: import("@adonisjs/lucid/types/model").ModelAssignOptions) => Promise<InstanceType<T>[]>;
|
|
@@ -152,4 +152,3 @@ export default class AuthzRolePermission extends AuthzRolePermission_base {
|
|
|
152
152
|
createdAt: DateTime;
|
|
153
153
|
}
|
|
154
154
|
export {};
|
|
155
|
-
//# sourceMappingURL=authz_role_permission.d.ts.map
|
package/build/src/openfga.d.ts
CHANGED
|
@@ -24,6 +24,5 @@ export type { OpenFgaRelationsDriverOptions } from './drivers/openfga_relations_
|
|
|
24
24
|
* JSON y cadenas—, pero se publica por esta misma puerta: es material de
|
|
25
25
|
* OpenFGA y solo lo usa quien lo elige.
|
|
26
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';
|
|
29
|
-
//# sourceMappingURL=openfga.d.ts.map
|
|
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, factsModelDifferences, } from './drivers/openfga_facts.js';
|
|
28
|
+
export type { FactsModelComparison, FactsModelDifference, FactsModelSlice, FactsRelations, FactsCatalogTuple, FactsTuple, FactsRelationsConfig, RelationObjectType, RelationObjectRelation, } from './drivers/openfga_facts.js';
|
package/build/src/openfga.js
CHANGED
|
@@ -22,5 +22,7 @@ export { OpenFgaRelationsDriver, DEFAULT_LIST_OBJECTS_DEADLINE_MS, LIST_OBJECTS_
|
|
|
22
22
|
* JSON y cadenas—, pero se publica por esta misma puerta: es material de
|
|
23
23
|
* OpenFGA y solo lo usa quien lo elige.
|
|
24
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,
|
|
26
|
-
|
|
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,
|
|
26
|
+
// L11 (lote «antes de RC»): la comparación modelo servido ↔ config, la que usan las dos puertas y la relectura de
|
|
27
|
+
// `openfga:provision`.
|
|
28
|
+
factsModelDifferences, } from './drivers/openfga_facts.js';
|
package/build/src/reconcile.d.ts
CHANGED
|
@@ -34,4 +34,3 @@ export declare function reconcileMaxTuples(value: number | undefined): number;
|
|
|
34
34
|
export declare function emptyReconcileCounts(): ReconcileCounts;
|
|
35
35
|
export declare function emptyReconcilePhases(): Record<ReconcileFamily, ReconcileCounts>;
|
|
36
36
|
export declare function sumReconcilePhases(phases: Record<ReconcileFamily, ReconcileCounts>): ReconcileCounts;
|
|
37
|
-
//# sourceMappingURL=reconcile.d.ts.map
|
package/build/src/reconcile.js
CHANGED
|
@@ -5,4 +5,3 @@ export declare function relationPartitionTrigger(dialect: string): string[];
|
|
|
5
5
|
/** Las sentencias para soltar el trigger (y, en PG, su función) en el `down()`. */
|
|
6
6
|
export declare function relationPartitionTriggerDrops(dialect: string): string[];
|
|
7
7
|
export {};
|
|
8
|
-
//# sourceMappingURL=relation_partition_trigger.d.ts.map
|
|
@@ -14,4 +14,3 @@ export declare function distinctObjects(objects: RelObject[]): {
|
|
|
14
14
|
};
|
|
15
15
|
/** Reparte las respuestas de los objetos DISTINTOS a las posiciones del lote. */
|
|
16
16
|
export declare function expandByPosition(index: number[], answers: boolean[]): boolean[];
|
|
17
|
-
//# sourceMappingURL=check_many.d.ts.map
|
|
@@ -48,10 +48,10 @@ export type RelationDenyPhase = 'read' | 'write';
|
|
|
48
48
|
* Las claves del lote D entran AQUÍ, en el mismo commit que su efecto.
|
|
49
49
|
*/
|
|
50
50
|
export declare const RELATIONS_SPEC_KEYS: Readonly<{
|
|
51
|
-
root: readonly ["objectTypes", "holderTypes", "database"];
|
|
51
|
+
root: readonly ["objectTypes", "holderTypes", "database", "maxGroupDepth"];
|
|
52
52
|
objectType: readonly ["type", "relations", "deny"];
|
|
53
53
|
relation: readonly ["name", "includes"];
|
|
54
|
-
database: readonly ["membersOf"];
|
|
54
|
+
database: readonly ["membersOf", "enforceGroupDepth"];
|
|
55
55
|
}>;
|
|
56
56
|
/** Una relación de un tipo de objeto (`document#viewer`), con sus `includes` de un nivel. */
|
|
57
57
|
export interface RelationObjectRelationSpec {
|
|
@@ -87,6 +87,15 @@ export interface RelationsDatabaseOptions {
|
|
|
87
87
|
* `database`.
|
|
88
88
|
*/
|
|
89
89
|
membersOf?: boolean;
|
|
90
|
+
/**
|
|
91
|
+
* **El límite de anidación de grupos en `database`, OPT-IN** (lote «antes de RC» · R1, decisión del dueño 2026-10-17
|
|
92
|
+
* (5): «`database` SIN límite por defecto —no tiene techo técnico—, opt-in con mando explícito aparte del número»).
|
|
93
|
+
* `true` ⇒ el driver `database` rechaza con 422 `E_AUTHZ_GROUP_DEPTH_LIMIT` la arista `group#member` que deje una
|
|
94
|
+
* cadena más larga que `maxGroupDepth` (que entonces es OBLIGATORIO y numérico: 500 al arrancar si no). Mando aparte
|
|
95
|
+
* a propósito (V2-4 del auditor): el `maxGroupDepth` que pones para tu CI `openfga` NO activa el gate en tu producción
|
|
96
|
+
* `database`. Default `false`.
|
|
97
|
+
*/
|
|
98
|
+
enforceGroupDepth?: boolean;
|
|
90
99
|
}
|
|
91
100
|
/** La config que declara el consumidor. */
|
|
92
101
|
export interface RelationsConfigSpec {
|
|
@@ -100,12 +109,26 @@ export interface RelationsConfigSpec {
|
|
|
100
109
|
holderTypes?: readonly string[];
|
|
101
110
|
/** Opciones del driver `database` (donde vive `membersOf`). */
|
|
102
111
|
database?: RelationsDatabaseOptions;
|
|
112
|
+
/**
|
|
113
|
+
* **El techo de anidación de grupos que declara la APP** (lote «antes de RC» · R1, decisiones del dueño 2026-10-17 (5)
|
|
114
|
+
* y (5-bis)): saltos `group⊂group` del camino MÁS LARGO. Cada driver declara su techo — `openfga` lo CALIBRA contra
|
|
115
|
+
* el servidor al primer uso (22 en OpenFGA v1.19 por defecto) y lo aplica SIEMPRE; `database` no tiene ninguno salvo
|
|
116
|
+
* `database.enforceGroupDepth` —; este valor solo puede BAJAR el de `openfga` (uno mayor que el calibrado ⇒ 500
|
|
117
|
+
* `E_AUTHZ_CONFIG` al calibrar, con las dos cifras) y es EL número en `database` con el opt-in. Entero 1..97 o `false`
|
|
118
|
+
* (apaga el de `openfga`, de forma explícita); cualquier otro valor ⇒ 500 al ARRANCAR. El paquete no lee variables de
|
|
119
|
+
* entorno: valida la tuya (`Env.schema.number.optional()`) y pásala aquí.
|
|
120
|
+
*/
|
|
121
|
+
maxGroupDepth?: number | false;
|
|
103
122
|
}
|
|
104
123
|
/** La config ya validada y CONGELADA que consulta el manager de relaciones. */
|
|
105
124
|
export interface RelationsConfig {
|
|
106
125
|
readonly objectTypes: readonly RelationObjectTypeSpec[];
|
|
107
126
|
/** ¿`membersOf` está habilitado (opción de `database`)? */
|
|
108
127
|
readonly membersOf: boolean;
|
|
128
|
+
/** R1: el techo de anidación de grupos declarado por la app (`undefined` = el del driver; `false` = apagado explícito). */
|
|
129
|
+
readonly maxGroupDepth?: number | false;
|
|
130
|
+
/** R1: ¿el driver `database` aplica `maxGroupDepth`? (opt-in, `database.enforceGroupDepth`). */
|
|
131
|
+
readonly enforceGroupDepth?: boolean;
|
|
109
132
|
/** ¿Existe el tipo de objeto? (F-05, cara del tipo). */
|
|
110
133
|
hasType(objectType: string): boolean;
|
|
111
134
|
/** ¿La relación está declarada para ese tipo? (F-05, cara de la relación). */
|
|
@@ -292,4 +315,3 @@ export declare function assertDenySubject(subject: unknown): void;
|
|
|
292
315
|
* versión la lea como «permanente» sin que nadie lo decidiera.
|
|
293
316
|
*/
|
|
294
317
|
export declare function assertDenyNoExpiry(options: unknown): void;
|
|
295
|
-
//# sourceMappingURL=define_relations_config.d.ts.map
|