import { n as IamPrimitives, t as AccessControl } from "../../access-control-CxeWQI64.js"; import { t as IamAdapter } from "../../adapter-DeNTUcdv.js"; import { t as IamRequest } from "../../request-BouexCSW.js"; //#region src/adapters/redis/index.d.ts /** IamRedis adapter integration types. Type-only namespace - zero bundle cost. */ declare namespace IamRedis { /** * Describes the minimal IamRedis client surface used by {@link IamRedisAdapter}. * * Both ioredis and node-redis (v4+) implement these methods, so consumers can * pass either without a hard dependency. */ interface ILike { get(key: string): Promise; set(key: string, value: string): Promise; del(...keys: string[]): Promise; hset(key: string, field: string, value: string): Promise; hget(key: string, field: string): Promise; hdel(key: string, ...fields: string[]): Promise; hkeys(key: string): Promise; hvals(key: string): Promise; hgetall(key: string): Promise>; sadd(key: string, ...members: string[]): Promise; srem(key: string, ...members: string[]): Promise; smembers(key: string): Promise; /** Optional Lua EVAL for cross-process atomic RMW on assignments; targets ioredis positional shape. */ eval?(script: string, numkeys: number, ...keysAndArgs: string[]): Promise; } /** Describes the configuration required to construct a {@link IamRedisAdapter}. */ interface IConfig { /** Provides the IamRedis client instance (ioredis, node-redis v4+, or compatible). */ client: TClient; /** Optional key prefix that namespaces every duck-iam key. */ keyPrefix?: string; /** * Invoked when a stored row fails JSON parse or shape validation. The * malformed row is dropped from the result set; the rest are returned * intact. Wire this to your alerting pipeline so corrupt rows do not * silently vanish from authorization decisions. */ onPolicyError?: (err: Error, ctx: { adapter: 'redis'; rowId: string; }) => void; } } /** * IamRedis-backed adapter using hashes + sets. Layout (with `keyPrefix`): * `${p}policies` (hash), `${p}roles` (hash), `${p}assignments:${id}` (set: `roleId\x00scope`), `${p}attrs:${id}` (JSON). * * @template TAction - Constrains valid action strings. * @template TResource - Constrains valid resource strings. * @template TRole - Constrains valid role strings. * @template TScope - Constrains valid scope strings. */ declare class IamRedisAdapter implements IamAdapter.IAdapter { private _client; private _prefix; private _onPolicyError?; /** * Per-assignment-key serialisation. Read-modify-write on the legacy * migration path can race with concurrent `revokeRole` and resurrect a * just-deleted assignment. Without `EVAL`/`MULTI` in the minimal * `IamRedis.ILike` interface, the soundest in-process fix is to serialise * writes against a single assignments key behind a chained promise. * Cross-process races remain - operators running multiple writer * processes should rely on the Lua `eval` path when available. */ private _assignmentWriteLocks; /** * Creates a new IamRedis-backed adapter. * * @param config - Provides the client and optional key prefix. */ constructor(config: IamRedis.IConfig); /** * Parse + validate a stored JSON blob. Returns `null` on parse error or * shape mismatch and routes the failure through `onPolicyError` (or the * console as a last resort) so the malformed row never reaches the engine. */ private _safeParsePolicy; private _safeParseRole; private _reportPolicyError; private _policiesKey; private _rolesKey; private _assignmentsKey; private _attrsKey; /** * Separator between role and scope in an encoded assignment set member. * * NUL (`0x00`) is rejected at encode time so it cannot appear in any * `TRole` / `TScope` string, preventing decode collisions that would drift * privileges (e.g. a space-separated `'admin user'` round-tripping as * `('admin', 'user ')`). */ private static readonly _SEP; /** * Detects entries written by versions of this adapter that used a literal * space as separator. Format: exactly one `0x20`, no `0x00` byte. On read, * such entries are transparently re-encoded with the NUL separator and the * legacy form is removed from the set. * * False positives are scoped to subjects whose role/scope strings happened * to contain spaces - exactly the cases that were silently broken before - * so the migration corrects rather than corrupts them. */ private _isLegacyEncoded; private _encodeAssignment; private _decodeAssignment; /** * Serialise an async task against a specific assignments key. Chains onto * any in-flight task for the same key so concurrent callers see a strict * happens-before order, defeating the migrate-vs-revoke race in a * single-process deployment. */ private _runSerialised; /** * One-shot migration: convert any legacy space-separated assignment members * for `subjectId` to the NUL-separated form. Idempotent and best-effort - * a migration failure must not block authorization, so any errors are * surfaced through `_reportPolicyError` and the original entries left in * place to be retried on the next read. */ private _migrateLegacyAssignment; /** Cross-process atomic legacy-assignment migration via IamRedis EVAL; ARGV pairs `[migrated, legacy]`. */ private static readonly _MIGRATE_LUA; private _migrateLegacyAssignmentLua; /** * Lists every policy stored in the IamRedis hash. * * @param _opts - Ignored read options accepted for interface compatibility. * @returns All policies decoded from the `policies` hash. */ listPolicies(_opts?: IamAdapter.IReadOptions): Promise[]>; /** * Fetches a single policy by ID. * * @param id - Identifies the policy to look up. * @param _opts - Ignored read options accepted for interface compatibility. * @returns The matching policy or `null` when absent. */ getPolicy(id: string, _opts?: IamAdapter.IReadOptions): Promise | null>; /** * Stores or overwrites a policy under its ID. * * @param p - Provides the policy to persist. * @returns Resolves once the HSET completes. */ savePolicy(p: AccessControl.IPolicy): Promise; /** * Removes a policy by ID. * * @param id - Identifies the policy to delete. * @returns Resolves once the HDEL completes. */ deletePolicy(id: string): Promise; /** * Lists every role stored in the IamRedis hash. * * @param _opts - Ignored read options accepted for interface compatibility. * @returns All roles decoded from the `roles` hash. */ listRoles(_opts?: IamAdapter.IReadOptions): Promise[]>; /** * Fetches a single role by ID. * * @param id - Identifies the role to look up. * @param _opts - Ignored read options accepted for interface compatibility. * @returns The matching role or `null` when absent. */ getRole(id: string, _opts?: IamAdapter.IReadOptions): Promise | null>; /** * Stores or overwrites a role under its ID. * * @param r - Provides the role to persist. * @returns Resolves once the HSET completes. */ saveRole(r: AccessControl.IRole): Promise; /** * Removes a role by ID. * * @param id - Identifies the role to delete. * @returns Resolves once the HDEL completes. */ deleteRole(id: string): Promise; /** * Lists deduplicated role IDs assigned to a subject. * * @param subjectId - Identifies the subject whose roles are read. * @param _opts - Ignored read options accepted for interface compatibility. * @returns Deduplicated array of role IDs. */ getSubjectRoles(subjectId: string, _opts?: IamAdapter.IReadOptions): Promise; /** * Lists scoped role assignments for a subject (excludes unscoped). * * @param subjectId - Identifies the subject whose scoped roles are read. * @param _opts - Ignored read options accepted for interface compatibility. * @returns Array of `(role, scope)` pairs. */ getSubjectScopedRoles(subjectId: string, _opts?: IamAdapter.IReadOptions): Promise[]>; /** * Grants a role to a subject, optionally restricted to a scope. * * Idempotent thanks to IamRedis set semantics. * * @param subjectId - Identifies the subject receiving the role. * @param roleId - Specifies the role being granted. * @param scope - Optional scope binding the assignment. * @returns Resolves once the SADD completes. */ assignRole(subjectId: string, roleId: TRole, scope?: TScope): Promise; /** * Removes role assignments matching the given filters. * * Omitting `scope` removes every assignment for the role regardless of scope. * * @param subjectId - Identifies the subject losing the role. * @param roleId - Specifies the role being revoked. * @param scope - Optional scope filter to narrow the delete. * @returns Resolves once the SREM completes. */ revokeRole(subjectId: string, roleId: TRole, scope?: TScope): Promise; /** * Fetches the attribute bag stored for a subject. * * @param subjectId - Identifies the subject whose attributes are read. * @param _opts - Ignored read options accepted for interface compatibility. * @returns The subject's attributes or `{}` when none are recorded. */ getSubjectAttributes(subjectId: string, _opts?: IamAdapter.IReadOptions): Promise; /** * Shallow-merges new attributes into the subject's existing bag. * * @param subjectId - Identifies the subject whose attributes are written. * @param attrs - Provides the partial attribute patch to merge in. * @returns Resolves once the SET completes. */ setSubjectAttributes(subjectId: string, attrs: IamPrimitives.Attributes): Promise; } //#endregion export { IamRedis, IamRedisAdapter }; //# sourceMappingURL=index.d.ts.map