kernl 0.6.2 → 0.6.3
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/.turbo/turbo-build.log +1 -1
- package/.turbo/turbo-check-types.log +1 -1
- package/CHANGELOG.md +30 -0
- package/dist/agent/__tests__/concurrency.test.js +1 -1
- package/dist/agent/__tests__/run.test.js +1 -1
- package/dist/{types/agent.d.ts → agent/types.d.ts} +2 -2
- package/dist/agent/types.d.ts.map +1 -0
- package/dist/agent.d.ts +36 -4
- package/dist/agent.d.ts.map +1 -1
- package/dist/agent.js +58 -0
- package/dist/api/models/thread.d.ts +1 -1
- package/dist/api/resources/threads/threads.d.ts +1 -1
- package/dist/api/resources/threads/threads.d.ts.map +1 -1
- package/dist/api/resources/threads/threads.js +1 -1
- package/dist/api/resources/threads/types.d.ts +2 -2
- package/dist/api/resources/threads/types.d.ts.map +1 -1
- package/dist/context.d.ts +4 -4
- package/dist/context.d.ts.map +1 -1
- package/dist/guardrail.d.ts +2 -2
- package/dist/index.d.ts +5 -3
- package/dist/index.d.ts.map +1 -1
- package/dist/index.js +4 -3
- package/dist/internal.d.ts +2 -2
- package/dist/internal.js +1 -1
- package/dist/kernl/index.d.ts +1 -1
- package/dist/kernl/index.d.ts.map +1 -1
- package/dist/kernl/index.js +0 -1
- package/dist/kernl/kernl.d.ts +7 -18
- package/dist/kernl/kernl.d.ts.map +1 -1
- package/dist/kernl/kernl.js +29 -29
- package/dist/kernl/types.d.ts +91 -0
- package/dist/kernl/types.d.ts.map +1 -0
- package/dist/lib/error.d.ts +2 -2
- package/dist/lifecycle.d.ts +2 -2
- package/dist/memory/codec.d.ts +32 -0
- package/dist/memory/codec.d.ts.map +1 -0
- package/dist/memory/codec.js +97 -0
- package/dist/memory/codecs/domain.d.ts +34 -0
- package/dist/memory/codecs/domain.d.ts.map +1 -0
- package/dist/memory/codecs/domain.js +99 -0
- package/dist/memory/codecs/identity.d.ts +12 -0
- package/dist/memory/codecs/identity.d.ts.map +1 -0
- package/dist/memory/codecs/identity.js +17 -0
- package/dist/memory/codecs/index.d.ts +31 -0
- package/dist/memory/codecs/index.d.ts.map +1 -0
- package/dist/memory/codecs/index.js +39 -0
- package/dist/memory/codecs/tpuf.d.ts +38 -0
- package/dist/memory/codecs/tpuf.d.ts.map +1 -0
- package/dist/memory/codecs/tpuf.js +90 -0
- package/dist/memory/encoder.d.ts +29 -0
- package/dist/memory/encoder.d.ts.map +1 -0
- package/dist/memory/encoder.js +45 -0
- package/dist/memory/handle.d.ts +89 -0
- package/dist/memory/handle.d.ts.map +1 -0
- package/dist/memory/handle.js +128 -0
- package/dist/memory/index.d.ts +12 -0
- package/dist/memory/index.d.ts.map +1 -0
- package/dist/memory/index.js +7 -0
- package/dist/memory/indexes.d.ts +91 -0
- package/dist/memory/indexes.d.ts.map +1 -0
- package/dist/memory/indexes.js +7 -0
- package/dist/memory/memory.d.ts +51 -0
- package/dist/memory/memory.d.ts.map +1 -0
- package/dist/memory/memory.js +107 -0
- package/dist/memory/schema.d.ts +41 -0
- package/dist/memory/schema.d.ts.map +1 -0
- package/dist/memory/schema.js +112 -0
- package/dist/memory/store.d.ts +36 -0
- package/dist/memory/store.d.ts.map +1 -0
- package/dist/memory/store.js +4 -0
- package/dist/memory/types.d.ts +250 -0
- package/dist/memory/types.d.ts.map +1 -0
- package/dist/memory/types.js +4 -0
- package/dist/storage/base.d.ts +6 -1
- package/dist/storage/base.d.ts.map +1 -1
- package/dist/storage/in-memory.d.ts +24 -2
- package/dist/storage/in-memory.d.ts.map +1 -1
- package/dist/storage/in-memory.js +131 -0
- package/dist/storage/thread.d.ts +1 -1
- package/dist/thread/__tests__/integration.test.js +1 -1
- package/dist/thread/__tests__/mock.d.ts +1 -1
- package/dist/thread/__tests__/namespace.test.js +1 -1
- package/dist/thread/__tests__/thread.test.js +1 -1
- package/dist/thread/thread.d.ts +2 -2
- package/dist/thread/thread.d.ts.map +1 -1
- package/dist/{types/thread.d.ts → thread/types.d.ts} +2 -2
- package/dist/thread/types.d.ts.map +1 -0
- package/dist/thread/utils.d.ts +2 -2
- package/dist/thread/utils.d.ts.map +1 -1
- package/package.json +4 -2
- package/src/{types/agent.ts → agent/types.ts} +1 -1
- package/src/agent.ts +78 -2
- package/src/api/__tests__/threads.test.ts +2 -2
- package/src/api/models/thread.ts +1 -1
- package/src/api/resources/threads/events.ts +1 -1
- package/src/api/resources/threads/threads.ts +2 -2
- package/src/api/resources/threads/types.ts +2 -2
- package/src/context.ts +6 -136
- package/src/guardrail.ts +2 -2
- package/src/index.ts +35 -6
- package/src/internal.ts +2 -2
- package/src/kernl/index.ts +8 -0
- package/src/{kernl.ts → kernl/kernl.ts} +40 -3
- package/src/kernl/types.ts +106 -0
- package/src/lib/error.ts +2 -2
- package/src/lifecycle.ts +2 -2
- package/src/memory/codecs/domain.ts +115 -0
- package/src/memory/codecs/identity.ts +28 -0
- package/src/memory/codecs/index.ts +61 -0
- package/src/memory/codecs/tpuf.ts +115 -0
- package/src/memory/encoder.ts +56 -0
- package/src/memory/handle.ts +189 -0
- package/src/memory/index.ts +49 -0
- package/src/memory/indexes.ts +108 -0
- package/src/memory/memory.ts +143 -0
- package/src/memory/schema.ts +142 -0
- package/src/memory/store.ts +47 -0
- package/src/memory/types.ts +282 -0
- package/src/storage/__tests__/in-memory.test.ts +1 -1
- package/src/storage/base.ts +7 -1
- package/src/storage/in-memory.ts +170 -2
- package/src/storage/thread.ts +1 -1
- package/src/thread/__tests__/integration.test.ts +1 -1
- package/src/thread/__tests__/mock.ts +1 -1
- package/src/thread/__tests__/thread.test.ts +1 -1
- package/src/thread/thread.ts +2 -2
- package/src/{types/thread.ts → thread/types.ts} +1 -1
- package/src/thread/utils.ts +2 -2
- package/tsconfig.tsbuildinfo +1 -0
- package/dist/api/__tests__/cursor-page.test.d.ts +0 -2
- package/dist/api/__tests__/cursor-page.test.d.ts.map +0 -1
- package/dist/api/__tests__/cursor-page.test.js +0 -414
- package/dist/api/__tests__/offset-page.test.d.ts +0 -2
- package/dist/api/__tests__/offset-page.test.d.ts.map +0 -1
- package/dist/api/__tests__/offset-page.test.js +0 -510
- package/dist/api/pagination/base.d.ts +0 -48
- package/dist/api/pagination/base.d.ts.map +0 -1
- package/dist/api/pagination/base.js +0 -45
- package/dist/api/pagination/cursor.d.ts +0 -44
- package/dist/api/pagination/cursor.d.ts.map +0 -1
- package/dist/api/pagination/cursor.js +0 -52
- package/dist/api/pagination/offset.d.ts +0 -42
- package/dist/api/pagination/offset.d.ts.map +0 -1
- package/dist/api/pagination/offset.js +0 -55
- package/dist/kernl/threads.d.ts +0 -110
- package/dist/kernl/threads.d.ts.map +0 -1
- package/dist/kernl/threads.js +0 -126
- package/dist/kernl.d.ts +0 -51
- package/dist/kernl.d.ts.map +0 -1
- package/dist/kernl.js +0 -91
- package/dist/types/agent.d.ts.map +0 -1
- package/dist/types/kernl.d.ts +0 -42
- package/dist/types/kernl.d.ts.map +0 -1
- package/dist/types/thread.d.ts.map +0 -1
- package/src/api/__tests__/cursor-page.test.ts +0 -512
- package/src/api/__tests__/offset-page.test.ts +0 -624
- package/src/api/pagination/base.ts +0 -79
- package/src/api/pagination/cursor.ts +0 -86
- package/src/api/pagination/offset.ts +0 -89
- package/src/types/kernl.ts +0 -51
- /package/dist/{types/agent.js → agent/types.js} +0 -0
- /package/dist/{types/kernl.js → kernl/types.js} +0 -0
- /package/dist/{types/thread.js → thread/types.js} +0 -0
|
@@ -1,512 +0,0 @@
|
|
|
1
|
-
import { describe, it, expect, vi } from "vitest";
|
|
2
|
-
|
|
3
|
-
import {
|
|
4
|
-
CursorPage,
|
|
5
|
-
type CursorPageResponse,
|
|
6
|
-
type CursorPageParams,
|
|
7
|
-
} from "../pagination/cursor";
|
|
8
|
-
|
|
9
|
-
describe("CursorPage", () => {
|
|
10
|
-
describe("construction", () => {
|
|
11
|
-
it("should initialize with response data", () => {
|
|
12
|
-
const response: CursorPageResponse<string> = {
|
|
13
|
-
data: ["a", "b", "c"],
|
|
14
|
-
next: "cursor_123",
|
|
15
|
-
last: false,
|
|
16
|
-
};
|
|
17
|
-
|
|
18
|
-
const loader = vi.fn();
|
|
19
|
-
const page = new CursorPage({
|
|
20
|
-
params: {},
|
|
21
|
-
response,
|
|
22
|
-
loader,
|
|
23
|
-
});
|
|
24
|
-
|
|
25
|
-
expect(page.data).toEqual(["a", "b", "c"]);
|
|
26
|
-
expect(page.items).toEqual(["a", "b", "c"]);
|
|
27
|
-
expect(page.last).toBe(false);
|
|
28
|
-
});
|
|
29
|
-
|
|
30
|
-
it("should handle empty data array", () => {
|
|
31
|
-
const response: CursorPageResponse<string> = {
|
|
32
|
-
data: [],
|
|
33
|
-
next: null,
|
|
34
|
-
last: true,
|
|
35
|
-
};
|
|
36
|
-
|
|
37
|
-
const loader = vi.fn();
|
|
38
|
-
const page = new CursorPage({
|
|
39
|
-
params: {},
|
|
40
|
-
response,
|
|
41
|
-
loader,
|
|
42
|
-
});
|
|
43
|
-
|
|
44
|
-
expect(page.data).toEqual([]);
|
|
45
|
-
expect(page.items).toEqual([]);
|
|
46
|
-
expect(page.last).toBe(true);
|
|
47
|
-
});
|
|
48
|
-
|
|
49
|
-
it("should handle null data gracefully", () => {
|
|
50
|
-
const response: CursorPageResponse<string> = {
|
|
51
|
-
data: null as any, // simulate backend returning null
|
|
52
|
-
next: null,
|
|
53
|
-
last: true,
|
|
54
|
-
};
|
|
55
|
-
|
|
56
|
-
const loader = vi.fn();
|
|
57
|
-
const page = new CursorPage({
|
|
58
|
-
params: {},
|
|
59
|
-
response,
|
|
60
|
-
loader,
|
|
61
|
-
});
|
|
62
|
-
|
|
63
|
-
expect(page.data).toEqual([]);
|
|
64
|
-
expect(page.items).toEqual([]);
|
|
65
|
-
});
|
|
66
|
-
});
|
|
67
|
-
|
|
68
|
-
describe("items getter", () => {
|
|
69
|
-
it("should return exact reference to data array", () => {
|
|
70
|
-
const data = ["a", "b", "c"];
|
|
71
|
-
const response: CursorPageResponse<string> = {
|
|
72
|
-
data,
|
|
73
|
-
next: null,
|
|
74
|
-
last: false,
|
|
75
|
-
};
|
|
76
|
-
|
|
77
|
-
const page = new CursorPage({
|
|
78
|
-
params: {},
|
|
79
|
-
response,
|
|
80
|
-
loader: vi.fn(),
|
|
81
|
-
});
|
|
82
|
-
|
|
83
|
-
expect(page.items).toBe(page.data);
|
|
84
|
-
});
|
|
85
|
-
});
|
|
86
|
-
|
|
87
|
-
describe("last getter", () => {
|
|
88
|
-
it("should return true when response.last is true", () => {
|
|
89
|
-
const page = new CursorPage({
|
|
90
|
-
params: {},
|
|
91
|
-
response: { data: ["a"], next: "cursor", last: true },
|
|
92
|
-
loader: vi.fn(),
|
|
93
|
-
});
|
|
94
|
-
|
|
95
|
-
expect(page.last).toBe(true);
|
|
96
|
-
});
|
|
97
|
-
|
|
98
|
-
it("should return true when next cursor is null", () => {
|
|
99
|
-
const page = new CursorPage({
|
|
100
|
-
params: {},
|
|
101
|
-
response: { data: ["a"], next: null, last: false },
|
|
102
|
-
loader: vi.fn(),
|
|
103
|
-
});
|
|
104
|
-
|
|
105
|
-
expect(page.last).toBe(true);
|
|
106
|
-
});
|
|
107
|
-
|
|
108
|
-
it("should return true when data is empty", () => {
|
|
109
|
-
const page = new CursorPage({
|
|
110
|
-
params: {},
|
|
111
|
-
response: { data: [], next: "cursor", last: false },
|
|
112
|
-
loader: vi.fn(),
|
|
113
|
-
});
|
|
114
|
-
|
|
115
|
-
expect(page.last).toBe(true);
|
|
116
|
-
});
|
|
117
|
-
|
|
118
|
-
it("should return false when has next cursor and data", () => {
|
|
119
|
-
const page = new CursorPage({
|
|
120
|
-
params: {},
|
|
121
|
-
response: { data: ["a", "b"], next: "cursor_123", last: false },
|
|
122
|
-
loader: vi.fn(),
|
|
123
|
-
});
|
|
124
|
-
|
|
125
|
-
expect(page.last).toBe(false);
|
|
126
|
-
});
|
|
127
|
-
|
|
128
|
-
it("should prioritize response.last over next cursor", () => {
|
|
129
|
-
const page = new CursorPage({
|
|
130
|
-
params: {},
|
|
131
|
-
response: { data: ["a"], next: "cursor", last: true },
|
|
132
|
-
loader: vi.fn(),
|
|
133
|
-
});
|
|
134
|
-
|
|
135
|
-
expect(page.last).toBe(true);
|
|
136
|
-
});
|
|
137
|
-
});
|
|
138
|
-
|
|
139
|
-
describe("next()", () => {
|
|
140
|
-
it("should return null when last is true", async () => {
|
|
141
|
-
const page = new CursorPage({
|
|
142
|
-
params: {},
|
|
143
|
-
response: { data: ["a"], next: null, last: true },
|
|
144
|
-
loader: vi.fn(),
|
|
145
|
-
});
|
|
146
|
-
|
|
147
|
-
const nextPage = await page.next();
|
|
148
|
-
expect(nextPage).toBe(null);
|
|
149
|
-
});
|
|
150
|
-
|
|
151
|
-
it("should return null when no next cursor", async () => {
|
|
152
|
-
const page = new CursorPage({
|
|
153
|
-
params: {},
|
|
154
|
-
response: { data: ["a"], next: null, last: false },
|
|
155
|
-
loader: vi.fn(),
|
|
156
|
-
});
|
|
157
|
-
|
|
158
|
-
const nextPage = await page.next();
|
|
159
|
-
expect(nextPage).toBe(null);
|
|
160
|
-
});
|
|
161
|
-
|
|
162
|
-
it("should fetch next page with cursor in params", async () => {
|
|
163
|
-
const loader = vi.fn().mockResolvedValue({
|
|
164
|
-
data: ["d", "e", "f"],
|
|
165
|
-
next: "cursor_456",
|
|
166
|
-
last: false,
|
|
167
|
-
});
|
|
168
|
-
|
|
169
|
-
const page = new CursorPage({
|
|
170
|
-
params: { limit: 10 },
|
|
171
|
-
response: { data: ["a", "b", "c"], next: "cursor_123", last: false },
|
|
172
|
-
loader,
|
|
173
|
-
});
|
|
174
|
-
|
|
175
|
-
const nextPage = await page.next();
|
|
176
|
-
|
|
177
|
-
expect(loader).toHaveBeenCalledTimes(1);
|
|
178
|
-
expect(loader).toHaveBeenCalledWith({
|
|
179
|
-
limit: 10,
|
|
180
|
-
cursor: "cursor_123",
|
|
181
|
-
});
|
|
182
|
-
|
|
183
|
-
expect(nextPage).not.toBe(null);
|
|
184
|
-
expect(nextPage!.data).toEqual(["d", "e", "f"]);
|
|
185
|
-
expect(nextPage!.items).toEqual(["d", "e", "f"]);
|
|
186
|
-
});
|
|
187
|
-
|
|
188
|
-
it("should preserve params across pagination", async () => {
|
|
189
|
-
const loader = vi.fn().mockResolvedValue({
|
|
190
|
-
data: ["x"],
|
|
191
|
-
next: null,
|
|
192
|
-
last: true,
|
|
193
|
-
});
|
|
194
|
-
|
|
195
|
-
const page = new CursorPage({
|
|
196
|
-
params: { limit: 5, cursor: "initial" },
|
|
197
|
-
response: { data: ["a"], next: "cursor_next", last: false },
|
|
198
|
-
loader,
|
|
199
|
-
});
|
|
200
|
-
|
|
201
|
-
await page.next();
|
|
202
|
-
|
|
203
|
-
expect(loader).toHaveBeenCalledWith({
|
|
204
|
-
limit: 5,
|
|
205
|
-
cursor: "cursor_next", // cursor gets updated
|
|
206
|
-
});
|
|
207
|
-
});
|
|
208
|
-
|
|
209
|
-
it("should return instance of CursorPage", async () => {
|
|
210
|
-
const loader = vi.fn().mockResolvedValue({
|
|
211
|
-
data: ["d"],
|
|
212
|
-
next: null,
|
|
213
|
-
last: true,
|
|
214
|
-
});
|
|
215
|
-
|
|
216
|
-
const page = new CursorPage({
|
|
217
|
-
params: {},
|
|
218
|
-
response: { data: ["a"], next: "cursor", last: false },
|
|
219
|
-
loader,
|
|
220
|
-
});
|
|
221
|
-
|
|
222
|
-
const nextPage = await page.next();
|
|
223
|
-
expect(nextPage).toBeInstanceOf(CursorPage);
|
|
224
|
-
});
|
|
225
|
-
});
|
|
226
|
-
|
|
227
|
-
describe("pages() generator", () => {
|
|
228
|
-
it("should yield only current page when last", async () => {
|
|
229
|
-
const page = new CursorPage({
|
|
230
|
-
params: {},
|
|
231
|
-
response: { data: ["a"], next: null, last: true },
|
|
232
|
-
loader: vi.fn(),
|
|
233
|
-
});
|
|
234
|
-
|
|
235
|
-
const pages: CursorPage<string>[] = [];
|
|
236
|
-
for await (const p of page.pages()) {
|
|
237
|
-
pages.push(p);
|
|
238
|
-
}
|
|
239
|
-
|
|
240
|
-
expect(pages).toHaveLength(1);
|
|
241
|
-
expect(pages[0]).toBe(page);
|
|
242
|
-
});
|
|
243
|
-
|
|
244
|
-
it("should yield multiple pages until last", async () => {
|
|
245
|
-
const loader = vi
|
|
246
|
-
.fn()
|
|
247
|
-
.mockResolvedValueOnce({
|
|
248
|
-
data: ["d", "e"],
|
|
249
|
-
next: "cursor_2",
|
|
250
|
-
last: false,
|
|
251
|
-
})
|
|
252
|
-
.mockResolvedValueOnce({
|
|
253
|
-
data: ["f"],
|
|
254
|
-
next: null,
|
|
255
|
-
last: true,
|
|
256
|
-
});
|
|
257
|
-
|
|
258
|
-
const page = new CursorPage({
|
|
259
|
-
params: {},
|
|
260
|
-
response: { data: ["a", "b", "c"], next: "cursor_1", last: false },
|
|
261
|
-
loader,
|
|
262
|
-
});
|
|
263
|
-
|
|
264
|
-
const pages: CursorPage<string>[] = [];
|
|
265
|
-
for await (const p of page.pages()) {
|
|
266
|
-
pages.push(p);
|
|
267
|
-
}
|
|
268
|
-
|
|
269
|
-
expect(pages).toHaveLength(3);
|
|
270
|
-
expect(pages[0].data).toEqual(["a", "b", "c"]);
|
|
271
|
-
expect(pages[1].data).toEqual(["d", "e"]);
|
|
272
|
-
expect(pages[2].data).toEqual(["f"]);
|
|
273
|
-
expect(loader).toHaveBeenCalledTimes(2);
|
|
274
|
-
});
|
|
275
|
-
|
|
276
|
-
it("should stop when next() returns null", async () => {
|
|
277
|
-
const loader = vi.fn().mockResolvedValue({
|
|
278
|
-
data: [],
|
|
279
|
-
next: null,
|
|
280
|
-
last: true,
|
|
281
|
-
});
|
|
282
|
-
|
|
283
|
-
const page = new CursorPage({
|
|
284
|
-
params: {},
|
|
285
|
-
response: { data: ["a"], next: "cursor", last: false },
|
|
286
|
-
loader,
|
|
287
|
-
});
|
|
288
|
-
|
|
289
|
-
const pages: CursorPage<string>[] = [];
|
|
290
|
-
for await (const p of page.pages()) {
|
|
291
|
-
pages.push(p);
|
|
292
|
-
}
|
|
293
|
-
|
|
294
|
-
expect(pages).toHaveLength(2); // original + one fetched
|
|
295
|
-
});
|
|
296
|
-
});
|
|
297
|
-
|
|
298
|
-
describe("Symbol.asyncIterator", () => {
|
|
299
|
-
it("should iterate over items in single page", async () => {
|
|
300
|
-
const page = new CursorPage({
|
|
301
|
-
params: {},
|
|
302
|
-
response: { data: ["a", "b", "c"], next: null, last: true },
|
|
303
|
-
loader: vi.fn(),
|
|
304
|
-
});
|
|
305
|
-
|
|
306
|
-
const items: string[] = [];
|
|
307
|
-
for await (const item of page) {
|
|
308
|
-
items.push(item);
|
|
309
|
-
}
|
|
310
|
-
|
|
311
|
-
expect(items).toEqual(["a", "b", "c"]);
|
|
312
|
-
});
|
|
313
|
-
|
|
314
|
-
it("should iterate over items across multiple pages", async () => {
|
|
315
|
-
const loader = vi.fn().mockResolvedValueOnce({
|
|
316
|
-
data: ["d", "e"],
|
|
317
|
-
next: null,
|
|
318
|
-
last: true,
|
|
319
|
-
});
|
|
320
|
-
|
|
321
|
-
const page = new CursorPage({
|
|
322
|
-
params: {},
|
|
323
|
-
response: { data: ["a", "b", "c"], next: "cursor_1", last: false },
|
|
324
|
-
loader,
|
|
325
|
-
});
|
|
326
|
-
|
|
327
|
-
const items: string[] = [];
|
|
328
|
-
for await (const item of page) {
|
|
329
|
-
items.push(item);
|
|
330
|
-
}
|
|
331
|
-
|
|
332
|
-
expect(items).toEqual(["a", "b", "c", "d", "e"]);
|
|
333
|
-
});
|
|
334
|
-
|
|
335
|
-
it("should handle empty pages gracefully", async () => {
|
|
336
|
-
const page = new CursorPage({
|
|
337
|
-
params: {},
|
|
338
|
-
response: { data: [], next: null, last: true },
|
|
339
|
-
loader: vi.fn(),
|
|
340
|
-
});
|
|
341
|
-
|
|
342
|
-
const items: string[] = [];
|
|
343
|
-
for await (const item of page) {
|
|
344
|
-
items.push(item);
|
|
345
|
-
}
|
|
346
|
-
|
|
347
|
-
expect(items).toEqual([]);
|
|
348
|
-
});
|
|
349
|
-
|
|
350
|
-
it("should work with complex objects", async () => {
|
|
351
|
-
type User = { id: string; name: string };
|
|
352
|
-
const users: User[] = [
|
|
353
|
-
{ id: "1", name: "Alice" },
|
|
354
|
-
{ id: "2", name: "Bob" },
|
|
355
|
-
];
|
|
356
|
-
|
|
357
|
-
const page = new CursorPage<User>({
|
|
358
|
-
params: {},
|
|
359
|
-
response: { data: users, next: null, last: true },
|
|
360
|
-
loader: vi.fn(),
|
|
361
|
-
});
|
|
362
|
-
|
|
363
|
-
const collected: User[] = [];
|
|
364
|
-
for await (const user of page) {
|
|
365
|
-
collected.push(user);
|
|
366
|
-
}
|
|
367
|
-
|
|
368
|
-
expect(collected).toEqual(users);
|
|
369
|
-
expect(collected[0]).toEqual({ id: "1", name: "Alice" });
|
|
370
|
-
});
|
|
371
|
-
});
|
|
372
|
-
|
|
373
|
-
describe("collect()", () => {
|
|
374
|
-
it("should collect all items from single page", async () => {
|
|
375
|
-
const page = new CursorPage({
|
|
376
|
-
params: {},
|
|
377
|
-
response: { data: ["a", "b", "c"], next: null, last: true },
|
|
378
|
-
loader: vi.fn(),
|
|
379
|
-
});
|
|
380
|
-
|
|
381
|
-
const items = await page.collect();
|
|
382
|
-
expect(items).toEqual(["a", "b", "c"]);
|
|
383
|
-
});
|
|
384
|
-
|
|
385
|
-
it("should collect all items from multiple pages", async () => {
|
|
386
|
-
const loader = vi
|
|
387
|
-
.fn()
|
|
388
|
-
.mockResolvedValueOnce({
|
|
389
|
-
data: ["d", "e", "f"],
|
|
390
|
-
next: "cursor_2",
|
|
391
|
-
last: false,
|
|
392
|
-
})
|
|
393
|
-
.mockResolvedValueOnce({
|
|
394
|
-
data: ["g", "h"],
|
|
395
|
-
next: null,
|
|
396
|
-
last: true,
|
|
397
|
-
});
|
|
398
|
-
|
|
399
|
-
const page = new CursorPage({
|
|
400
|
-
params: {},
|
|
401
|
-
response: { data: ["a", "b", "c"], next: "cursor_1", last: false },
|
|
402
|
-
loader,
|
|
403
|
-
});
|
|
404
|
-
|
|
405
|
-
const items = await page.collect();
|
|
406
|
-
expect(items).toEqual(["a", "b", "c", "d", "e", "f", "g", "h"]);
|
|
407
|
-
expect(loader).toHaveBeenCalledTimes(2);
|
|
408
|
-
});
|
|
409
|
-
|
|
410
|
-
it("should return empty array for empty page", async () => {
|
|
411
|
-
const page = new CursorPage({
|
|
412
|
-
params: {},
|
|
413
|
-
response: { data: [], next: null, last: true },
|
|
414
|
-
loader: vi.fn(),
|
|
415
|
-
});
|
|
416
|
-
|
|
417
|
-
const items = await page.collect();
|
|
418
|
-
expect(items).toEqual([]);
|
|
419
|
-
});
|
|
420
|
-
|
|
421
|
-
it("should preserve item order across pages", async () => {
|
|
422
|
-
const loader = vi
|
|
423
|
-
.fn()
|
|
424
|
-
.mockResolvedValueOnce({ data: [4, 5, 6], next: null, last: true });
|
|
425
|
-
|
|
426
|
-
const page = new CursorPage({
|
|
427
|
-
params: {},
|
|
428
|
-
response: { data: [1, 2, 3], next: "cursor", last: false },
|
|
429
|
-
loader,
|
|
430
|
-
});
|
|
431
|
-
|
|
432
|
-
const items = await page.collect();
|
|
433
|
-
expect(items).toEqual([1, 2, 3, 4, 5, 6]);
|
|
434
|
-
});
|
|
435
|
-
});
|
|
436
|
-
|
|
437
|
-
describe("edge cases", () => {
|
|
438
|
-
it("should handle consecutive next() calls correctly", async () => {
|
|
439
|
-
const loader = vi.fn().mockResolvedValue({
|
|
440
|
-
data: ["next"],
|
|
441
|
-
next: null,
|
|
442
|
-
last: true,
|
|
443
|
-
});
|
|
444
|
-
|
|
445
|
-
const page = new CursorPage({
|
|
446
|
-
params: {},
|
|
447
|
-
response: { data: ["a"], next: "cursor", last: false },
|
|
448
|
-
loader,
|
|
449
|
-
});
|
|
450
|
-
|
|
451
|
-
const next1 = await page.next();
|
|
452
|
-
const next2 = await page.next();
|
|
453
|
-
|
|
454
|
-
expect(next1).not.toBe(null);
|
|
455
|
-
expect(next2).not.toBe(null);
|
|
456
|
-
expect(loader).toHaveBeenCalledTimes(2);
|
|
457
|
-
});
|
|
458
|
-
|
|
459
|
-
it("should handle loader throwing error", async () => {
|
|
460
|
-
const loader = vi.fn().mockRejectedValue(new Error("Network error"));
|
|
461
|
-
|
|
462
|
-
const page = new CursorPage({
|
|
463
|
-
params: {},
|
|
464
|
-
response: { data: ["a"], next: "cursor", last: false },
|
|
465
|
-
loader,
|
|
466
|
-
});
|
|
467
|
-
|
|
468
|
-
await expect(page.next()).rejects.toThrow("Network error");
|
|
469
|
-
});
|
|
470
|
-
|
|
471
|
-
it("should not call loader when last is true", async () => {
|
|
472
|
-
const loader = vi.fn();
|
|
473
|
-
|
|
474
|
-
const page = new CursorPage({
|
|
475
|
-
params: {},
|
|
476
|
-
response: { data: ["a"], next: null, last: true },
|
|
477
|
-
loader,
|
|
478
|
-
});
|
|
479
|
-
|
|
480
|
-
await page.next();
|
|
481
|
-
expect(loader).not.toHaveBeenCalled();
|
|
482
|
-
});
|
|
483
|
-
|
|
484
|
-
it("should handle params with custom properties", async () => {
|
|
485
|
-
interface CustomParams extends CursorPageParams {
|
|
486
|
-
agentId?: string;
|
|
487
|
-
filter?: string;
|
|
488
|
-
}
|
|
489
|
-
|
|
490
|
-
const loader = vi.fn().mockResolvedValue({
|
|
491
|
-
data: ["b"],
|
|
492
|
-
next: null,
|
|
493
|
-
last: true,
|
|
494
|
-
});
|
|
495
|
-
|
|
496
|
-
const page = new CursorPage<string, CustomParams>({
|
|
497
|
-
params: { agentId: "agent-1", filter: "active", limit: 10 },
|
|
498
|
-
response: { data: ["a"], next: "cursor", last: false },
|
|
499
|
-
loader,
|
|
500
|
-
});
|
|
501
|
-
|
|
502
|
-
await page.next();
|
|
503
|
-
|
|
504
|
-
expect(loader).toHaveBeenCalledWith({
|
|
505
|
-
agentId: "agent-1",
|
|
506
|
-
filter: "active",
|
|
507
|
-
limit: 10,
|
|
508
|
-
cursor: "cursor",
|
|
509
|
-
});
|
|
510
|
-
});
|
|
511
|
-
});
|
|
512
|
-
});
|