@ionite/redis 0.0.22-beta.20260728.2 → 0.0.22

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 (2) hide show
  1. package/package.json +2 -2
  2. package/README.md +0 -127
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@ionite/redis",
3
- "version": "0.0.22-beta.20260728.2",
3
+ "version": "0.0.22",
4
4
  "description": "redis (node-redis) adapter and Redis stores for ionite. Includes createRedisAdapter (v6) and createRedisAdapterV4 (v4). Install this; redis is included.",
5
5
  "private": false,
6
6
  "author": "ionite",
@@ -24,7 +24,7 @@
24
24
  "./package.json": "./package.json"
25
25
  },
26
26
  "dependencies": {
27
- "@ionite/redis-core": "0.0.22-beta.20260728.2",
27
+ "@ionite/redis-core": "^0.0.22",
28
28
  "redis": "^6.1.0"
29
29
  },
30
30
  "peerDependencies": {
package/README.md DELETED
@@ -1,127 +0,0 @@
1
- # @ionite/redis
2
-
3
- redis (node-redis) adapter and Redis stores for ionite. Includes **createRedisAdapter** (v6, default), **createRedisAdapterV4** (v4), and **`ionRedis(...)`** for secret-backed reactive Redis connections. Install this package; redis is included. You do not need to install `@ionite/redis-core` separately.
4
-
5
- ## Installation
6
-
7
- ```bash
8
- bun add @ionite/redis
9
- ```
10
-
11
- ## Secret-backed reactive Redis
12
-
13
- Use **`ionRedis(source, path, options?)`** when Redis connection details arrive from the default config-backed secret client or a named `ion.secrets` provider and may rotate over time.
14
-
15
- ```ts
16
- import { ionite, envConfig } from '@ionite/server';
17
- import { createValidators } from '@ionite/zod';
18
- import {
19
- ionRedis,
20
- RedisAccessIndex,
21
- RedisAccessAssignmentStore,
22
- RedisAccessCatalogStore,
23
- RedisSessionStore,
24
- RedisUserStore,
25
- } from '@ionite/redis';
26
-
27
- export const ion = ionite(envConfig(), {
28
- validators: createValidators(),
29
- });
30
-
31
- const redis = ionRedis(ion.secret, `${process.env.ION_VAULT_PATH}/redis`);
32
- ion.setStores({
33
- sessionStore: new RedisSessionStore({ redis }),
34
- userStore: new RedisUserStore({ redis }),
35
- accessStore: new RedisAccessAssignmentStore({ redis }),
36
- accessIndex: new RedisAccessIndex({ redis }),
37
- catalogStore: new RedisAccessCatalogStore({ redis }),
38
- });
39
- ```
40
-
41
- Notes:
42
-
43
- - The first argument is a stable `SecretsSource` handle (for example `ion.secret` or `ion.secrets.redis`) and the second is the **secret path**. By default the log label is **`redis`**; override that with `{ sourceName }` when needed.
44
- - The secret payload should be a node-redis client options object. A top-level **`url`** or **`redisUrl`** field is the simplest shape.
45
- - The adapter subscribes with async get-then-watch semantics and defaults to fail-fast: a missing Redis secret rejects `ready()` and store operations instead of waiting silently forever. Pass `{ subscription: { mode: 'wait', timeout: 30_000 } }` only when waiting for the secret to appear is intentional.
46
- - The adapter is source-bound at creation time. Store operations wait for the first configured connection, so you can construct stores synchronously and use `ready()` only when you want an explicit startup or health-check barrier. If the named source is replaced during a config change, the adapter creates the next Redis client first and keeps the old client when refresh fails.
47
-
48
- ## Shared env-based adapter
49
-
50
- Use **`getSharedRedisAdapter()`** when you only want one process-wide adapter from `REDIS_URL` without secret reactivity:
51
-
52
- ```ts
53
- import { closeSharedRedisAdapter, getSharedRedisAdapter } from '@ionite/redis';
54
-
55
- const redis = await getSharedRedisAdapter();
56
- // On shutdown (tests, short-lived workers), close the singleton so the connection does not leak:
57
- await closeSharedRedisAdapter();
58
- ```
59
-
60
- For **createRedisAdapterV4** only, also install redis v4:
61
-
62
- ```bash
63
- bun add @ionite/redis redis@^4
64
- ```
65
-
66
- ## Usage (v5, default)
67
-
68
- ```ts
69
- import { createClient } from 'redis';
70
- import {
71
- createRedisAdapter,
72
- RedisAccessIndex,
73
- RedisAccessAssignmentStore,
74
- RedisAccessCatalogStore,
75
- RedisUserStore,
76
- RedisSessionStore,
77
- RedisMagicLinkStore,
78
- RedisWorkloadTokenStore,
79
- RedisTenantStore,
80
- } from '@ionite/redis';
81
-
82
- const client = createClient({ url: process.env.REDIS_URL ?? 'redis://localhost:3503' });
83
- await client.connect();
84
- const redis = createRedisAdapter(client);
85
-
86
- const userStore = new RedisUserStore({ redis });
87
- const sessionStore = new RedisSessionStore({ redis });
88
- const magicLinkStore = new RedisMagicLinkStore({ redis });
89
- const workloadTokenStore = new RedisWorkloadTokenStore({ redis });
90
- const accessStore = new RedisAccessAssignmentStore({ redis });
91
- const accessIndex = new RedisAccessIndex({ redis });
92
- const catalogStore = new RedisAccessCatalogStore({ redis });
93
- const tenantStore = new RedisTenantStore({ redis });
94
- ```
95
-
96
- ## Usage (v4)
97
-
98
- If you still use redis (node-redis) v4, install `redis@^4` and use **createRedisAdapterV4**:
99
-
100
- ```ts
101
- import { createClient } from 'redis';
102
- import {
103
- createRedisAdapterV4,
104
- RedisUserStore,
105
- RedisSessionStore,
106
- // ...
107
- } from '@ionite/redis';
108
-
109
- const client = createClient({ url: process.env.REDIS_URL ?? 'redis://localhost:3503' });
110
- await client.connect();
111
- const redis = createRedisAdapterV4(client);
112
- // ... same store setup
113
- ```
114
-
115
- Prefer **createRedisAdapter** (v5) when you can upgrade.
116
-
117
- Pass these stores into `ionite` (from `@ionite/server`) the same way you would in-memory stores. `keyPrefix` is **required** in store options (no implicit default; use a distinct per-tenant prefix); `logger` is optional (see `@ionite/redis-core` for the adapter interface and key layout). Use one shared `RedisSessionStore` namespace for opaque browser auth sessions so `SessionStore.get(sid)` can resolve the session without tenant-specific lookup context.
118
-
119
- **Adapter capabilities & key encoding.** `createRedisAdapter` (v4/v6 — one implementation, `createRedisAdapterV4` is a named alias) implements the full `RedisAdapter`: atomic `getdel` (`GETDEL`, **Redis 6.2+**, for single-winner magic-link consume) and server-side `runScript` (`EVAL`, for create-if-absent / unique-index claim / multi-key txn / session compare-and-set). `list()` returns records in a stable, deterministic (lexicographic id) order via `SMEMBERS` + `MGET` — no sorted-set support is needed. `ionRedis(...)` forwards `getdel` and `runScript` from the active client, so those atomic paths apply over secret-backed reactive connections too. Externally-sourced id segments are hash-encoded before they enter a key (§10.2), so a hostile or `:`-bearing id can never split a key or collide with a structural index segment — see `@ionite/redis-core` for the scheme.
120
-
121
- `RedisAccessAssignmentStore` persists granted `AccessChange` **roots** (with deterministic id, optional resource scope, provenance, and status) for SDK-owned SCIM access mutation routing and OAA full sync — one row per **direct** grant (for example `alice → role:editor`), not per permission. Fast authorization checks read **`RedisAccessIndex`** instead — the derived closure materialized from roots + the catalog — exposing `has(...)`, `hasGroup(...)`, `hasRole(...)`, `hasPermission(...)`, `hasAny(...)`, and `hasAll(...)`. Because the index already accounts for group -> role -> permission expansion, nested groups/roles, and `applyToSubResources` inheritance, these checks reflect effective access, not just direct edges. **Example:** grant Alice roles `editor` and `reviewer` that both include permission `read`; AccessAssignmentStore holds two roots, AccessIndex holds both roles and all permissions (with `read` attributed to each root). Revoke `editor`: remove that root and its index rows by `rootId` — Alice keeps `read` via the reviewer root. The index also implements the subject-disabled marker (`setSubjectDisabled`/`isSubjectDisabled`, set by inbound SCIM `active: false`): while set, every `has*` denies with `metadata.reason: 'subject_disabled'`; it is stored independently of edges, so `clear`/reconcile never wipes it.
122
-
123
- `RedisAccessCatalogStore` persists **SCIM/IAM-sourced** Authz Catalog entries (rows the IAM tool authors via SCIM Group create, or definitions with a genuine store lifecycle) under namespaced stores: `groups`, `roles`, and `permissions`. Use it as `FrameworkConfig.authz.catalogStore` or `FrameworkStores.catalogStore` so SCIM Groups aggregation and OAA full sync can translate SDK-native catalog entries without app code writing SCIM extension objects. Code-authored definitions belong in the code-declared catalog instead (`defineCatalog(...)` -> `FrameworkConfig.authz.catalog`), consumed in memory on the read path — never seeded here. `set(entity)` returns a ready-aware catalog entry synchronously (no top-level `await`) and writes to Redis in the background; await `entry.ready()` for a durability guarantee or check `entry.isReady()`.
124
-
125
- `RedisResourceStore` is a Redis-backed writable `ResourceProvider` for apps whose resources are not already in their own database. Wire it as `FrameworkConfig.authz.resources` / `FrameworkStores.resources`; `set(resource)` / `delete(id)` persist and emit the `changed` signal (driving adjacency-cache invalidation, reconcile, and incremental OAA projection), and the optional `deriveEntitlements`/`resolveEntitlement` pair derives requestable per-resource entitlement Groups on demand. Apps with their own resource tables should implement `ResourceProvider` over them directly instead.
126
-
127
- `RedisTenantStore` keeps user-to-tenant membership sets so tenant-directory lookups do not scan every tenant. It then materializes the matching candidate tenants and applies `ListOptions` (stable-order paging + filter) in memory. That is appropriate when each user or discovery lookup maps to a bounded tenant set; use a SQL/search-backed custom `TenantStore` when directories need high-cardinality paging or arbitrary indexed sort/filter behavior.