@outfitter/state 0.2.3 → 0.2.5
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 +38 -34
- package/dist/index.d.ts +4 -666
- package/dist/index.js +3 -409
- package/dist/internal/cursor.d.ts +3 -0
- package/dist/internal/cursor.js +15 -0
- package/dist/internal/pagination.d.ts +3 -0
- package/dist/internal/pagination.js +59 -0
- package/dist/internal/stores.d.ts +3 -0
- package/dist/internal/stores.js +208 -0
- package/dist/internal/types.d.ts +2 -0
- package/dist/internal/types.js +1 -0
- package/dist/shared/@outfitter/state-3n2wh1yq.js +154 -0
- package/dist/shared/@outfitter/state-6h22x3e6.d.ts +264 -0
- package/dist/shared/@outfitter/state-9q2yv8dy.d.ts +133 -0
- package/dist/shared/@outfitter/state-cgc92xms.d.ts +139 -0
- package/dist/shared/@outfitter/state-y5wh3wpn.d.ts +139 -0
- package/package.json +26 -26
package/README.md
CHANGED
|
@@ -42,14 +42,14 @@ if (cursorResult.isOk()) {
|
|
|
42
42
|
|
|
43
43
|
Cursors are intentionally **opaque** to consumers. They are immutable, frozen objects that encapsulate pagination state.
|
|
44
44
|
|
|
45
|
-
| Property
|
|
46
|
-
|
|
47
|
-
| `id`
|
|
48
|
-
| `position`
|
|
49
|
-
| `metadata`
|
|
50
|
-
| `ttl`
|
|
51
|
-
| `expiresAt` | `number`
|
|
52
|
-
| `createdAt` | `number`
|
|
45
|
+
| Property | Type | Description |
|
|
46
|
+
| ----------- | ------------------------- | ----------------------------------------------- |
|
|
47
|
+
| `id` | `string` | Unique identifier for storage lookup |
|
|
48
|
+
| `position` | `number` | Current offset in the result set |
|
|
49
|
+
| `metadata` | `Record<string, unknown>` | Optional user-defined context |
|
|
50
|
+
| `ttl` | `number` | Time-to-live in milliseconds (optional) |
|
|
51
|
+
| `expiresAt` | `number` | Computed Unix timestamp for expiry (if TTL set) |
|
|
52
|
+
| `createdAt` | `number` | Unix timestamp when cursor was created |
|
|
53
53
|
|
|
54
54
|
### Why Opaque?
|
|
55
55
|
|
|
@@ -95,7 +95,11 @@ if (result.isOk()) {
|
|
|
95
95
|
### Example: Paginated Handler
|
|
96
96
|
|
|
97
97
|
```typescript
|
|
98
|
-
import {
|
|
98
|
+
import {
|
|
99
|
+
createCursor,
|
|
100
|
+
createCursorStore,
|
|
101
|
+
advanceCursor,
|
|
102
|
+
} from "@outfitter/state";
|
|
99
103
|
import { Result } from "@outfitter/contracts";
|
|
100
104
|
|
|
101
105
|
const store = createCursorStore();
|
|
@@ -150,11 +154,11 @@ const issuesStore = createScopedStore(store, "linear:issues");
|
|
|
150
154
|
const prsStore = createScopedStore(store, "github:prs");
|
|
151
155
|
|
|
152
156
|
// Cursors are isolated - same ID won't conflict
|
|
153
|
-
issuesStore.set(issueCursor);
|
|
154
|
-
prsStore.set(prCursor);
|
|
157
|
+
issuesStore.set(issueCursor); // Stored as "linear:issues:cursor-id"
|
|
158
|
+
prsStore.set(prCursor); // Stored as "github:prs:cursor-id"
|
|
155
159
|
|
|
156
160
|
// Each scope manages its own cursors
|
|
157
|
-
issuesStore.clear();
|
|
161
|
+
issuesStore.clear(); // Only clears issue cursors
|
|
158
162
|
```
|
|
159
163
|
|
|
160
164
|
### Nested Scopes
|
|
@@ -167,8 +171,8 @@ const githubStore = createScopedStore(store, "github");
|
|
|
167
171
|
const issuesStore = createScopedStore(githubStore, "issues");
|
|
168
172
|
const prsStore = createScopedStore(githubStore, "prs");
|
|
169
173
|
|
|
170
|
-
issuesStore.getScope();
|
|
171
|
-
prsStore.getScope();
|
|
174
|
+
issuesStore.getScope(); // "github:issues"
|
|
175
|
+
prsStore.getScope(); // "github:prs"
|
|
172
176
|
```
|
|
173
177
|
|
|
174
178
|
### Scoped Store Behavior
|
|
@@ -183,15 +187,15 @@ if (cursor.isOk()) {
|
|
|
183
187
|
scoped.set(cursor.value);
|
|
184
188
|
|
|
185
189
|
// Underlying store has prefixed ID
|
|
186
|
-
store.list();
|
|
190
|
+
store.list(); // ["my-scope:abc123"]
|
|
187
191
|
|
|
188
192
|
// Scoped store returns clean ID
|
|
189
|
-
scoped.list();
|
|
193
|
+
scoped.list(); // ["abc123"]
|
|
190
194
|
|
|
191
195
|
// Get returns cursor with clean ID
|
|
192
196
|
const result = scoped.get("abc123");
|
|
193
197
|
if (result.isOk()) {
|
|
194
|
-
result.value.id;
|
|
198
|
+
result.value.id; // "abc123" (not "my-scope:abc123")
|
|
195
199
|
}
|
|
196
200
|
}
|
|
197
201
|
```
|
|
@@ -257,7 +261,7 @@ const result = createCursor({
|
|
|
257
261
|
|
|
258
262
|
if (result.isOk()) {
|
|
259
263
|
const cursor = result.value;
|
|
260
|
-
cursor.ttl;
|
|
264
|
+
cursor.ttl; // 3600000
|
|
261
265
|
cursor.expiresAt; // Unix timestamp (e.g., 1706000000000)
|
|
262
266
|
}
|
|
263
267
|
```
|
|
@@ -289,7 +293,7 @@ Cursors created without a TTL never expire:
|
|
|
289
293
|
```typescript
|
|
290
294
|
const result = createCursor({ position: 0 });
|
|
291
295
|
if (result.isOk()) {
|
|
292
|
-
result.value.ttl;
|
|
296
|
+
result.value.ttl; // undefined
|
|
293
297
|
result.value.expiresAt; // undefined
|
|
294
298
|
isExpired(result.value); // always false
|
|
295
299
|
}
|
|
@@ -299,24 +303,24 @@ if (result.isOk()) {
|
|
|
299
303
|
|
|
300
304
|
### Functions
|
|
301
305
|
|
|
302
|
-
| Function
|
|
303
|
-
|
|
304
|
-
| `createCursor(options)`
|
|
306
|
+
| Function | Description |
|
|
307
|
+
| --------------------------------- | ----------------------------------------- |
|
|
308
|
+
| `createCursor(options)` | Create a new immutable pagination cursor |
|
|
305
309
|
| `advanceCursor(cursor, position)` | Create a new cursor with updated position |
|
|
306
|
-
| `isExpired(cursor)`
|
|
307
|
-
| `createCursorStore()`
|
|
308
|
-
| `createPersistentStore(options)`
|
|
309
|
-
| `createScopedStore(store, scope)` | Create a namespace-isolated cursor store
|
|
310
|
+
| `isExpired(cursor)` | Check if a cursor has expired |
|
|
311
|
+
| `createCursorStore()` | Create an in-memory cursor store |
|
|
312
|
+
| `createPersistentStore(options)` | Create a disk-backed cursor store |
|
|
313
|
+
| `createScopedStore(store, scope)` | Create a namespace-isolated cursor store |
|
|
310
314
|
|
|
311
315
|
### Interfaces
|
|
312
316
|
|
|
313
|
-
| Interface
|
|
314
|
-
|
|
315
|
-
| `Cursor`
|
|
316
|
-
| `CreateCursorOptions`
|
|
317
|
-
| `CursorStore`
|
|
318
|
-
| `ScopedStore`
|
|
319
|
-
| `PersistentStore`
|
|
317
|
+
| Interface | Description |
|
|
318
|
+
| ------------------------ | ------------------------------------- |
|
|
319
|
+
| `Cursor` | Immutable pagination cursor |
|
|
320
|
+
| `CreateCursorOptions` | Options for `createCursor()` |
|
|
321
|
+
| `CursorStore` | Base interface for cursor stores |
|
|
322
|
+
| `ScopedStore` | Cursor store with namespace isolation |
|
|
323
|
+
| `PersistentStore` | Cursor store with disk persistence |
|
|
320
324
|
| `PersistentStoreOptions` | Options for `createPersistentStore()` |
|
|
321
325
|
|
|
322
326
|
## Error Handling
|
|
@@ -339,7 +343,7 @@ if (getResult.isErr()) {
|
|
|
339
343
|
// NotFoundError: Cursor not found: nonexistent
|
|
340
344
|
console.error(getResult.error.message);
|
|
341
345
|
console.log(getResult.error.resourceType); // "cursor"
|
|
342
|
-
console.log(getResult.error.resourceId);
|
|
346
|
+
console.log(getResult.error.resourceId); // "nonexistent"
|
|
343
347
|
}
|
|
344
348
|
```
|
|
345
349
|
|