@omnistreamai/data-adapter-webdav 0.4.0 → 0.4.2
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/package.json +8 -2
- package/skills/configure-webdav-adapter/SKILL.md +186 -0
- package/CHANGELOG.md +0 -52
- package/dist/index.d.mts +0 -79
- package/dist/index.d.mts.map +0 -1
- package/dist/index.d.ts +0 -79
- package/dist/index.d.ts.map +0 -1
- package/dist/index.js.map +0 -1
- package/dist/index.mjs +0 -258
- package/dist/index.mjs.map +0 -1
- package/src/index.ts +0 -3
- package/src/webdav-adapter.test.ts +0 -423
- package/src/webdav-adapter.ts +0 -458
- package/tsconfig.json +0 -16
- package/tsconfig.tsbuildinfo +0 -1
- package/tsdown.config.ts +0 -12
- package/vitest.config.ts +0 -10
|
@@ -1,423 +0,0 @@
|
|
|
1
|
-
import { describe, it, expect, beforeEach, vi } from 'vitest';
|
|
2
|
-
import { WebDAVAdapter } from './webdav-adapter.js';
|
|
3
|
-
import { AdapterType, AuthType, type ServiceConfig } from '@omnistreamai/data-core';
|
|
4
|
-
|
|
5
|
-
// Mock fetch
|
|
6
|
-
global.fetch = vi.fn();
|
|
7
|
-
|
|
8
|
-
describe('WebDAVAdapter', () => {
|
|
9
|
-
let adapter: WebDAVAdapter;
|
|
10
|
-
const storeName = 'test-store';
|
|
11
|
-
|
|
12
|
-
beforeEach(() => {
|
|
13
|
-
adapter = new WebDAVAdapter();
|
|
14
|
-
vi.clearAllMocks();
|
|
15
|
-
});
|
|
16
|
-
|
|
17
|
-
describe('基本属性', () => {
|
|
18
|
-
it('应该是远程适配器', () => {
|
|
19
|
-
expect(adapter.type).toBe(AdapterType.Remote);
|
|
20
|
-
expect(adapter.name).toBe('WebDAVAdapter');
|
|
21
|
-
});
|
|
22
|
-
});
|
|
23
|
-
|
|
24
|
-
describe('setService', () => {
|
|
25
|
-
it('应该能够设置服务配置', () => {
|
|
26
|
-
const service: ServiceConfig = {
|
|
27
|
-
endpoint: 'https://webdav.example.com/data',
|
|
28
|
-
authentication: {
|
|
29
|
-
authType: AuthType.Token,
|
|
30
|
-
token: {
|
|
31
|
-
access_token: 'test-token',
|
|
32
|
-
token_type: 'Bearer',
|
|
33
|
-
},
|
|
34
|
-
},
|
|
35
|
-
};
|
|
36
|
-
|
|
37
|
-
adapter.setService(service);
|
|
38
|
-
expect(adapter).toBeDefined();
|
|
39
|
-
});
|
|
40
|
-
});
|
|
41
|
-
|
|
42
|
-
describe('initStore', () => {
|
|
43
|
-
it('应该能够初始化存储(不做任何处理)', async () => {
|
|
44
|
-
const service: ServiceConfig = {
|
|
45
|
-
endpoint: 'https://webdav.example.com/data',
|
|
46
|
-
};
|
|
47
|
-
adapter.setService(service);
|
|
48
|
-
|
|
49
|
-
await adapter.initStore(storeName, ['username'], 'id');
|
|
50
|
-
expect(global.fetch).not.toHaveBeenCalled();
|
|
51
|
-
});
|
|
52
|
-
});
|
|
53
|
-
|
|
54
|
-
describe('add', () => {
|
|
55
|
-
it('应该能够添加数据(文件不存在)', async () => {
|
|
56
|
-
const service: ServiceConfig = {
|
|
57
|
-
endpoint: 'https://webdav.example.com/data',
|
|
58
|
-
authentication: {
|
|
59
|
-
authType: AuthType.Token,
|
|
60
|
-
token: {
|
|
61
|
-
access_token: 'test-token',
|
|
62
|
-
token_type: 'Bearer',
|
|
63
|
-
},
|
|
64
|
-
},
|
|
65
|
-
};
|
|
66
|
-
adapter.setService(service);
|
|
67
|
-
|
|
68
|
-
const data = {
|
|
69
|
-
id: '1',
|
|
70
|
-
username: 'test-user',
|
|
71
|
-
email: 'test@example.com',
|
|
72
|
-
};
|
|
73
|
-
|
|
74
|
-
(global.fetch as ReturnType<typeof vi.fn>)
|
|
75
|
-
.mockResolvedValueOnce({
|
|
76
|
-
ok: false,
|
|
77
|
-
status: 404,
|
|
78
|
-
text: async () => '',
|
|
79
|
-
} as unknown as Response)
|
|
80
|
-
.mockResolvedValueOnce({
|
|
81
|
-
ok: true,
|
|
82
|
-
status: 201,
|
|
83
|
-
text: async () => '',
|
|
84
|
-
} as Response)
|
|
85
|
-
.mockResolvedValueOnce({
|
|
86
|
-
ok: true,
|
|
87
|
-
status: 200,
|
|
88
|
-
text: async () => '',
|
|
89
|
-
} as unknown as Response);
|
|
90
|
-
|
|
91
|
-
const result = await adapter.add(storeName, data, 'id');
|
|
92
|
-
expect(result).toEqual(data);
|
|
93
|
-
expect(global.fetch).toHaveBeenCalledTimes(3);
|
|
94
|
-
});
|
|
95
|
-
|
|
96
|
-
it('应该能够添加数据(文件已存在)', async () => {
|
|
97
|
-
const service: ServiceConfig = {
|
|
98
|
-
endpoint: 'https://webdav.example.com/data',
|
|
99
|
-
};
|
|
100
|
-
adapter.setService(service);
|
|
101
|
-
|
|
102
|
-
const data = {
|
|
103
|
-
id: '1',
|
|
104
|
-
username: 'test-user',
|
|
105
|
-
email: 'test@example.com',
|
|
106
|
-
};
|
|
107
|
-
|
|
108
|
-
(global.fetch as ReturnType<typeof vi.fn>)
|
|
109
|
-
.mockResolvedValueOnce({
|
|
110
|
-
ok: true,
|
|
111
|
-
status: 200,
|
|
112
|
-
text: async () => '[]',
|
|
113
|
-
} as unknown as Response)
|
|
114
|
-
.mockResolvedValueOnce({
|
|
115
|
-
ok: true,
|
|
116
|
-
status: 200,
|
|
117
|
-
text: async () => '',
|
|
118
|
-
} as unknown as Response);
|
|
119
|
-
|
|
120
|
-
const result = await adapter.add(storeName, data, 'id');
|
|
121
|
-
expect(result).toEqual(data);
|
|
122
|
-
expect(global.fetch).toHaveBeenCalledTimes(2);
|
|
123
|
-
});
|
|
124
|
-
});
|
|
125
|
-
|
|
126
|
-
describe('getData', () => {
|
|
127
|
-
it('应该能够根据 ID 获取数据', async () => {
|
|
128
|
-
const service: ServiceConfig = {
|
|
129
|
-
endpoint: 'https://webdav.example.com/data',
|
|
130
|
-
};
|
|
131
|
-
adapter.setService(service);
|
|
132
|
-
|
|
133
|
-
const data = [
|
|
134
|
-
{
|
|
135
|
-
id: '1',
|
|
136
|
-
username: 'test-user',
|
|
137
|
-
email: 'test@example.com',
|
|
138
|
-
},
|
|
139
|
-
];
|
|
140
|
-
|
|
141
|
-
(global.fetch as ReturnType<typeof vi.fn>).mockResolvedValueOnce({
|
|
142
|
-
ok: true,
|
|
143
|
-
status: 200,
|
|
144
|
-
text: async () => JSON.stringify(data),
|
|
145
|
-
} as unknown as Response);
|
|
146
|
-
|
|
147
|
-
const result = await adapter.getData(storeName, '1', 'id');
|
|
148
|
-
expect(result).toEqual(data[0]);
|
|
149
|
-
});
|
|
150
|
-
|
|
151
|
-
it('当数据不存在时应该返回 null', async () => {
|
|
152
|
-
const service: ServiceConfig = {
|
|
153
|
-
endpoint: 'https://webdav.example.com/data',
|
|
154
|
-
};
|
|
155
|
-
adapter.setService(service);
|
|
156
|
-
|
|
157
|
-
(global.fetch as ReturnType<typeof vi.fn>).mockResolvedValueOnce({
|
|
158
|
-
ok: false,
|
|
159
|
-
status: 404,
|
|
160
|
-
text: async () => '',
|
|
161
|
-
} as unknown as Response);
|
|
162
|
-
|
|
163
|
-
const result = await adapter.getData(storeName, 'non-existent', 'id');
|
|
164
|
-
expect(result).toBeNull();
|
|
165
|
-
});
|
|
166
|
-
});
|
|
167
|
-
|
|
168
|
-
describe('getList', () => {
|
|
169
|
-
it('应该能够获取列表数据并返回分页结果', async () => {
|
|
170
|
-
const service: ServiceConfig = {
|
|
171
|
-
endpoint: 'https://webdav.example.com/data',
|
|
172
|
-
};
|
|
173
|
-
adapter.setService(service);
|
|
174
|
-
|
|
175
|
-
const data = [
|
|
176
|
-
{ id: '1', username: 'user1' },
|
|
177
|
-
{ id: '2', username: 'user2' },
|
|
178
|
-
];
|
|
179
|
-
|
|
180
|
-
(global.fetch as ReturnType<typeof vi.fn>).mockResolvedValueOnce({
|
|
181
|
-
ok: true,
|
|
182
|
-
status: 200,
|
|
183
|
-
text: async () => JSON.stringify(data),
|
|
184
|
-
} as unknown as Response);
|
|
185
|
-
|
|
186
|
-
const result = await adapter.getList(storeName, undefined, 'id');
|
|
187
|
-
expect(result.data).toEqual(data);
|
|
188
|
-
expect(result.totalCount).toBe(2);
|
|
189
|
-
expect(result.page).toBe(1);
|
|
190
|
-
});
|
|
191
|
-
|
|
192
|
-
it('应该能够获取空列表数据(文件不存在)', async () => {
|
|
193
|
-
const service: ServiceConfig = {
|
|
194
|
-
endpoint: 'https://webdav.example.com/data',
|
|
195
|
-
};
|
|
196
|
-
adapter.setService(service);
|
|
197
|
-
|
|
198
|
-
(global.fetch as ReturnType<typeof vi.fn>)
|
|
199
|
-
.mockResolvedValueOnce({
|
|
200
|
-
ok: false,
|
|
201
|
-
status: 404,
|
|
202
|
-
text: async () => '',
|
|
203
|
-
} as unknown as Response)
|
|
204
|
-
.mockResolvedValueOnce({
|
|
205
|
-
ok: true,
|
|
206
|
-
status: 201,
|
|
207
|
-
text: async () => '',
|
|
208
|
-
} as Response);
|
|
209
|
-
|
|
210
|
-
const result = await adapter.getList(storeName, undefined, 'id');
|
|
211
|
-
expect(result.data).toEqual([]);
|
|
212
|
-
expect(result.totalCount).toBe(0);
|
|
213
|
-
expect(result.page).toBe(1);
|
|
214
|
-
});
|
|
215
|
-
|
|
216
|
-
it('应该支持分页查询', async () => {
|
|
217
|
-
const service: ServiceConfig = {
|
|
218
|
-
endpoint: 'https://webdav.example.com/data',
|
|
219
|
-
};
|
|
220
|
-
adapter.setService(service);
|
|
221
|
-
|
|
222
|
-
const data = Array.from({ length: 100 }, (_, i) => ({
|
|
223
|
-
id: String(i),
|
|
224
|
-
username: `user${i}`,
|
|
225
|
-
}));
|
|
226
|
-
|
|
227
|
-
(global.fetch as ReturnType<typeof vi.fn>).mockResolvedValue({
|
|
228
|
-
ok: true,
|
|
229
|
-
status: 200,
|
|
230
|
-
text: async () => JSON.stringify(data),
|
|
231
|
-
} as unknown as Response);
|
|
232
|
-
|
|
233
|
-
const result = await adapter.getList(storeName, { page: 2, limit: 10 }, 'id');
|
|
234
|
-
expect(result.page).toBe(2);
|
|
235
|
-
expect(result.limit).toBe(10);
|
|
236
|
-
expect(result.totalCount).toBe(100);
|
|
237
|
-
expect(result.data).toHaveLength(10);
|
|
238
|
-
});
|
|
239
|
-
|
|
240
|
-
it('应该支持条件查询', async () => {
|
|
241
|
-
const service: ServiceConfig = {
|
|
242
|
-
endpoint: 'https://webdav.example.com/data',
|
|
243
|
-
};
|
|
244
|
-
adapter.setService(service);
|
|
245
|
-
|
|
246
|
-
const data = [
|
|
247
|
-
{ id: '1', username: 'user1' },
|
|
248
|
-
{ id: '2', username: 'user2' },
|
|
249
|
-
];
|
|
250
|
-
|
|
251
|
-
(global.fetch as ReturnType<typeof vi.fn>).mockResolvedValue({
|
|
252
|
-
ok: true,
|
|
253
|
-
status: 200,
|
|
254
|
-
text: async () => JSON.stringify(data),
|
|
255
|
-
} as unknown as Response);
|
|
256
|
-
|
|
257
|
-
const result = await adapter.getList(storeName, { where: { username: 'user1' } }, 'id');
|
|
258
|
-
expect(result.data).toHaveLength(1);
|
|
259
|
-
expect(result.data[0]?.username).toBe('user1');
|
|
260
|
-
});
|
|
261
|
-
|
|
262
|
-
it('应该支持按字段升序排序', async () => {
|
|
263
|
-
const service: ServiceConfig = {
|
|
264
|
-
endpoint: 'https://webdav.example.com/data',
|
|
265
|
-
};
|
|
266
|
-
adapter.setService(service);
|
|
267
|
-
|
|
268
|
-
const data = [
|
|
269
|
-
{ id: '1', username: 'charlie', age: 30 },
|
|
270
|
-
{ id: '2', username: 'alice', age: 25 },
|
|
271
|
-
{ id: '3', username: 'bob', age: 28 },
|
|
272
|
-
];
|
|
273
|
-
|
|
274
|
-
(global.fetch as ReturnType<typeof vi.fn>).mockResolvedValue({
|
|
275
|
-
ok: true,
|
|
276
|
-
status: 200,
|
|
277
|
-
text: async () => JSON.stringify(data),
|
|
278
|
-
} as unknown as Response);
|
|
279
|
-
|
|
280
|
-
const result = await adapter.getList(storeName, { sortBy: 'username' as any }, 'id');
|
|
281
|
-
expect(result.data).toHaveLength(3);
|
|
282
|
-
expect(result.data[0]?.username).toBe('alice');
|
|
283
|
-
expect(result.data[1]?.username).toBe('bob');
|
|
284
|
-
expect(result.data[2]?.username).toBe('charlie');
|
|
285
|
-
});
|
|
286
|
-
|
|
287
|
-
it('应该支持按字段降序排序', async () => {
|
|
288
|
-
const service: ServiceConfig = {
|
|
289
|
-
endpoint: 'https://webdav.example.com/data',
|
|
290
|
-
};
|
|
291
|
-
adapter.setService(service);
|
|
292
|
-
|
|
293
|
-
const data = [
|
|
294
|
-
{ id: '1', username: 'alice', age: 25 },
|
|
295
|
-
{ id: '2', username: 'charlie', age: 30 },
|
|
296
|
-
{ id: '3', username: 'bob', age: 28 },
|
|
297
|
-
];
|
|
298
|
-
|
|
299
|
-
(global.fetch as ReturnType<typeof vi.fn>).mockResolvedValue({
|
|
300
|
-
ok: true,
|
|
301
|
-
status: 200,
|
|
302
|
-
text: async () => JSON.stringify(data),
|
|
303
|
-
} as unknown as Response);
|
|
304
|
-
|
|
305
|
-
const result = await adapter.getList(storeName, { sortBy: 'username' as any, sortOrder: 'desc' }, 'id');
|
|
306
|
-
expect(result.data).toHaveLength(3);
|
|
307
|
-
expect(result.data[0]?.username).toBe('charlie');
|
|
308
|
-
expect(result.data[1]?.username).toBe('bob');
|
|
309
|
-
expect(result.data[2]?.username).toBe('alice');
|
|
310
|
-
});
|
|
311
|
-
|
|
312
|
-
it('应该支持排序和分页的组合', async () => {
|
|
313
|
-
const service: ServiceConfig = {
|
|
314
|
-
endpoint: 'https://webdav.example.com/data',
|
|
315
|
-
};
|
|
316
|
-
adapter.setService(service);
|
|
317
|
-
|
|
318
|
-
const data = [
|
|
319
|
-
{ id: '1', username: 'charlie', age: 30 },
|
|
320
|
-
{ id: '2', username: 'alice', age: 25 },
|
|
321
|
-
{ id: '3', username: 'bob', age: 28 },
|
|
322
|
-
];
|
|
323
|
-
|
|
324
|
-
(global.fetch as ReturnType<typeof vi.fn>).mockResolvedValue({
|
|
325
|
-
ok: true,
|
|
326
|
-
status: 200,
|
|
327
|
-
text: async () => JSON.stringify(data),
|
|
328
|
-
} as unknown as Response);
|
|
329
|
-
|
|
330
|
-
const result = await adapter.getList(storeName, { sortBy: 'username' as any, page: 2, limit: 1 }, 'id');
|
|
331
|
-
expect(result.data).toHaveLength(1);
|
|
332
|
-
expect(result.data[0]?.username).toBe('bob');
|
|
333
|
-
});
|
|
334
|
-
});
|
|
335
|
-
|
|
336
|
-
describe('update', () => {
|
|
337
|
-
it('应该能够更新数据', async () => {
|
|
338
|
-
const service: ServiceConfig = {
|
|
339
|
-
endpoint: 'https://webdav.example.com/data',
|
|
340
|
-
};
|
|
341
|
-
adapter.setService(service);
|
|
342
|
-
|
|
343
|
-
const existingData = [
|
|
344
|
-
{
|
|
345
|
-
id: '1',
|
|
346
|
-
username: 'test-user',
|
|
347
|
-
email: 'test@example.com',
|
|
348
|
-
},
|
|
349
|
-
];
|
|
350
|
-
|
|
351
|
-
(global.fetch as ReturnType<typeof vi.fn>)
|
|
352
|
-
.mockResolvedValueOnce({
|
|
353
|
-
ok: true,
|
|
354
|
-
status: 200,
|
|
355
|
-
text: async () => JSON.stringify(existingData),
|
|
356
|
-
} as unknown as Response)
|
|
357
|
-
.mockResolvedValueOnce({
|
|
358
|
-
ok: true,
|
|
359
|
-
status: 200,
|
|
360
|
-
text: async () => '',
|
|
361
|
-
} as unknown as Response);
|
|
362
|
-
|
|
363
|
-
const result = await adapter.update(storeName, '1', { email: 'updated@example.com' }, 'id');
|
|
364
|
-
expect(result.email).toBe('updated@example.com');
|
|
365
|
-
});
|
|
366
|
-
});
|
|
367
|
-
|
|
368
|
-
describe('delete', () => {
|
|
369
|
-
it('应该能够删除数据', async () => {
|
|
370
|
-
const service: ServiceConfig = {
|
|
371
|
-
endpoint: 'https://webdav.example.com/data',
|
|
372
|
-
};
|
|
373
|
-
adapter.setService(service);
|
|
374
|
-
|
|
375
|
-
const existingData = [
|
|
376
|
-
{
|
|
377
|
-
id: '1',
|
|
378
|
-
username: 'test-user',
|
|
379
|
-
email: 'test@example.com',
|
|
380
|
-
},
|
|
381
|
-
];
|
|
382
|
-
|
|
383
|
-
(global.fetch as ReturnType<typeof vi.fn>)
|
|
384
|
-
.mockResolvedValueOnce({
|
|
385
|
-
ok: true,
|
|
386
|
-
status: 200,
|
|
387
|
-
text: async () => JSON.stringify(existingData),
|
|
388
|
-
} as unknown as Response)
|
|
389
|
-
.mockResolvedValueOnce({
|
|
390
|
-
ok: true,
|
|
391
|
-
status: 200,
|
|
392
|
-
text: async () => '',
|
|
393
|
-
} as unknown as Response);
|
|
394
|
-
|
|
395
|
-
await adapter.delete(storeName, '1', 'id');
|
|
396
|
-
expect(global.fetch).toHaveBeenCalledTimes(2);
|
|
397
|
-
});
|
|
398
|
-
});
|
|
399
|
-
|
|
400
|
-
describe('clear', () => {
|
|
401
|
-
it('应该能够清空存储', async () => {
|
|
402
|
-
const service: ServiceConfig = {
|
|
403
|
-
endpoint: 'https://webdav.example.com/data',
|
|
404
|
-
};
|
|
405
|
-
adapter.setService(service);
|
|
406
|
-
|
|
407
|
-
const data = [
|
|
408
|
-
{ id: '1', username: 'user1' },
|
|
409
|
-
{ id: '2', username: 'user2' },
|
|
410
|
-
];
|
|
411
|
-
|
|
412
|
-
(global.fetch as ReturnType<typeof vi.fn>).mockResolvedValue({
|
|
413
|
-
ok: true,
|
|
414
|
-
status: 200,
|
|
415
|
-
text: async () => JSON.stringify(data),
|
|
416
|
-
} as unknown as Response);
|
|
417
|
-
|
|
418
|
-
await adapter.clear(storeName);
|
|
419
|
-
expect(global.fetch).toHaveBeenCalled();
|
|
420
|
-
});
|
|
421
|
-
});
|
|
422
|
-
});
|
|
423
|
-
|