@ahoo-wang/fetcher-wow 1.1.0 → 1.2.1

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 (46) hide show
  1. package/README.md +275 -357
  2. package/README.zh-CN.md +283 -279
  3. package/dist/command/commandClient.d.ts +146 -0
  4. package/dist/command/commandClient.d.ts.map +1 -0
  5. package/dist/command/{commandHeaders.d.ts → commandHttpHeaders.d.ts} +6 -7
  6. package/dist/command/commandHttpHeaders.d.ts.map +1 -0
  7. package/dist/command/commandRequest.d.ts +26 -62
  8. package/dist/command/commandRequest.d.ts.map +1 -1
  9. package/dist/command/index.d.ts +2 -3
  10. package/dist/command/index.d.ts.map +1 -1
  11. package/dist/index.es.js +467 -226
  12. package/dist/index.es.js.map +1 -1
  13. package/dist/index.umd.js +1 -1
  14. package/dist/index.umd.js.map +1 -1
  15. package/dist/query/event/domainEventStream.d.ts +49 -4
  16. package/dist/query/event/domainEventStream.d.ts.map +1 -1
  17. package/dist/query/event/eventStreamQueryApi.d.ts +6 -0
  18. package/dist/query/event/eventStreamQueryApi.d.ts.map +1 -1
  19. package/dist/query/event/eventStreamQueryClient.d.ts +46 -0
  20. package/dist/query/event/eventStreamQueryClient.d.ts.map +1 -0
  21. package/dist/query/event/index.d.ts +1 -0
  22. package/dist/query/event/index.d.ts.map +1 -1
  23. package/dist/query/queryApi.d.ts +62 -0
  24. package/dist/query/queryApi.d.ts.map +1 -1
  25. package/dist/query/snapshot/index.d.ts +1 -0
  26. package/dist/query/snapshot/index.d.ts.map +1 -1
  27. package/dist/query/snapshot/snapshot.d.ts +2 -2
  28. package/dist/query/snapshot/snapshot.d.ts.map +1 -1
  29. package/dist/query/snapshot/snapshotQueryApi.d.ts +28 -0
  30. package/dist/query/snapshot/snapshotQueryApi.d.ts.map +1 -1
  31. package/dist/query/snapshot/snapshotQueryClient.d.ts +74 -0
  32. package/dist/query/snapshot/snapshotQueryClient.d.ts.map +1 -0
  33. package/dist/query/sort.d.ts +4 -0
  34. package/dist/query/sort.d.ts.map +1 -1
  35. package/dist/types/client.d.ts +15 -0
  36. package/dist/types/client.d.ts.map +1 -0
  37. package/dist/types/endpoints.d.ts +28 -0
  38. package/dist/types/endpoints.d.ts.map +1 -0
  39. package/dist/types/index.d.ts +1 -0
  40. package/dist/types/index.d.ts.map +1 -1
  41. package/package.json +4 -4
  42. package/dist/command/commandHeaders.d.ts.map +0 -1
  43. package/dist/command/commandHttpClient.d.ts +0 -133
  44. package/dist/command/commandHttpClient.d.ts.map +0 -1
  45. package/dist/command/commandHttpRequest.d.ts +0 -48
  46. package/dist/command/commandHttpRequest.d.ts.map +0 -1
package/README.zh-CN.md CHANGED
@@ -12,12 +12,13 @@
12
12
 
13
13
  ## 🌟 特性
14
14
 
15
- - **📦 全面的类型定义**:为 Wow 框架实体提供完整的 TypeScript 支持
16
- - **🔧 命令工具**:用于处理 Wow 命令和命令结果的辅助工具
17
- - **🔍 查询 DSL**:丰富的查询条件构建器,支持多种操作符
18
- - **📡 事件流支持**:与服务器发送事件集成,实现实时命令结果
19
- - **🔄 CQRS 模式**:支持命令查询责任分离模式
20
- - **🧱 DDD 构建块**:用于聚合、事件等的领域驱动设计类型
15
+ - **📦 完整的 TypeScript 支持**:为所有 Wow 框架实体提供完整的类型定义,包括命令、事件和查询
16
+ - **🚀 命令客户端**:用于向 Wow 服务发送命令的高级客户端,支持同步和流式响应
17
+ - **🔍 强大的查询 DSL**:丰富的查询条件构建器,支持全面的操作符用于复杂查询
18
+ - **📡 实时事件流**:内置对服务器发送事件的支持,用于接收实时命令结果和数据更新
19
+ - **🔄 CQRS 模式实现**:对命令查询责任分离架构模式的一流支持
20
+ - **🧱 DDD 基础构件**:基本的领域驱动设计构建块,包括聚合、事件和值对象
21
+ - **🔍 查询客户端**:专门用于查询快照和事件流数据的客户端,支持全面的查询操作
21
22
 
22
23
  ## 🚀 快速开始
23
24
 
@@ -38,100 +39,87 @@ yarn add @ahoo-wang/fetcher-wow
38
39
 
39
40
  ### 命令模块
40
41
 
41
- #### CommandHeaders
42
+ #### CommandResult
42
43
 
43
- Wow 命令处理中使用的标准 HTTP 头部常量:
44
+ 表示命令执行结果的接口:
44
45
 
45
46
  ```typescript
46
- import { CommandHeaders } from '@ahoo-wang/fetcher-wow';
47
-
48
- // 使用示例
49
- const request = {
50
- method: 'POST',
51
- headers: {
52
- [CommandHeaders.TENANT_ID]: 'tenant-123',
53
- [CommandHeaders.AGGREGATE_ID]: 'aggregate-456',
54
- [CommandHeaders.REQUEST_ID]: 'request-789',
55
- },
56
- body: JSON.stringify(command),
57
- };
47
+ import { CommandResult, CommandStage } from '@ahoo-wang/fetcher-wow';
58
48
  ```
59
49
 
60
- 关键头部包括:
61
-
62
- - `TENANT_ID` - 租户标识符
63
- - `OWNER_ID` - 所有者标识符
64
- - `AGGREGATE_ID` - 聚合根标识符
65
- - `AGGREGATE_VERSION` - 预期聚合版本
66
- - `REQUEST_ID` - 请求跟踪 ID
67
- - `WAIT_*` - 各种等待条件头部
68
- - `LOCAL_FIRST` - 本地处理偏好
69
- - 以及更多...
70
-
71
- #### CommandRequest
50
+ #### CommandClient
72
51
 
73
- 具有完整配置选项的命令请求接口:
52
+ 用于向 Wow 框架发送命令的 HTTP 客户端。该客户端提供了同步或流式接收命令结果的方法。
74
53
 
75
54
  ```typescript
76
- import { CommandRequest, CommandHeaders } from '@ahoo-wang/fetcher-wow';
55
+ import { Fetcher, URL_RESOLVE_INTERCEPTOR_ORDER } from '@ahoo-wang/fetcher';
56
+ import '@ahoo-wang/fetcher-eventstream';
57
+ import {
58
+ CommandClient,
59
+ CommandRequest,
60
+ HttpMethod,
61
+ CommandHttpHeaders,
62
+ CommandStage,
63
+ } from '@ahoo-wang/fetcher-wow';
64
+ import { idGenerator } from '@ahoo-wang/fetcher-cosec';
65
+
66
+ // 创建 fetcher 实例
67
+ const wowFetcher = new Fetcher({
68
+ baseURL: 'http://localhost:8080/',
69
+ });
70
+
71
+ // 添加拦截器处理 URL 参数
72
+ const ownerId = idGenerator.generateId();
73
+ wowFetcher.interceptors.request.use({
74
+ name: 'AppendOwnerId',
75
+ order: URL_RESOLVE_INTERCEPTOR_ORDER - 1,
76
+ intercept(exchange) {
77
+ exchange.request.urlParams = {
78
+ path: {
79
+ ...exchange.request.urlParams?.path,
80
+ ownerId,
81
+ },
82
+ query: exchange.request.urlParams?.query,
83
+ };
84
+ },
85
+ });
86
+
87
+ // 创建命令客户端
88
+ const commandClient = new CommandClient({
89
+ fetcher: wowFetcher,
90
+ basePath: 'owner/{ownerId}/cart',
91
+ });
77
92
 
78
- const commandRequest: CommandRequest = {
79
- path: '/commands/CreateUser',
80
- method: 'POST',
93
+ // 定义命令请求
94
+ const command: CommandRequest = {
95
+ method: HttpMethod.POST,
81
96
  headers: {
82
- [CommandHeaders.TENANT_ID]: 'tenant-123',
97
+ [CommandHttpHeaders.WAIT_STAGE]: CommandStage.SNAPSHOT,
83
98
  },
84
99
  body: {
85
- name: 'John Doe',
86
- email: 'john@example.com',
100
+ productId: 'productId',
101
+ quantity: 1,
87
102
  },
88
- timeout: 5000,
89
- aggregateId: 'user-456',
90
- requestId: 'req-789',
91
- localFirst: true,
92
- stream: false,
93
103
  };
94
- ```
95
104
 
96
- #### CommandResult
97
-
98
- 表示命令执行结果的接口:
105
+ // 发送命令并等待结果
106
+ const commandResult = await commandClient.send('add_cart_item', command);
99
107
 
100
- ```typescript
101
- import { CommandResult, CommandStage } from '@ahoo-wang/fetcher-wow';
102
-
103
- const commandResult: CommandResult = {
104
- id: 'result-123',
105
- commandId: 'cmd-456',
106
- requestId: 'req-789',
107
- stage: CommandStage.PROCESSED,
108
- contextName: 'user-context',
109
- aggregateName: 'User',
110
- aggregateId: 'user-456',
111
- aggregateVersion: 1,
112
- errorCode: 'Ok',
113
- errorMsg: '',
114
- function: {
115
- functionKind: 'COMMAND',
116
- contextName: 'user-context',
117
- processorName: 'UserProcessor',
118
- name: 'CreateUser',
119
- },
120
- signalTime: Date.now(),
121
- };
108
+ // 发送命令并接收流式结果
109
+ const commandResultStream = await commandClient.sendAndWaitStream(
110
+ 'add_cart_item',
111
+ command,
112
+ );
113
+ for await (const commandResultEvent of commandResultStream) {
114
+ console.log('收到命令结果:', commandResultEvent.data);
115
+ }
122
116
  ```
123
117
 
124
- #### CommandResultEventStream
125
-
126
- 命令结果事件流的类型别名:
118
+ ##### 方法
127
119
 
128
- ```typescript
129
- import { CommandResult } from '@ahoo-wang/fetcher-wow';
130
- import { JsonServerSentEventStream } from '@ahoo-wang/fetcher-eventstream';
131
-
132
- // CommandResultEventStream 是 CommandResult 的 JsonServerSentEventStream
133
- type CommandResultEventStream = JsonServerSentEventStream<CommandResult>;
134
- ```
120
+ - `send(path: string, commandRequest: CommandRequest): Promise<CommandResult>` - 发送命令并等待结果。
121
+ - `sendAndWaitStream(path: string, commandRequest: CommandRequest): Promise<CommandResultEventStream>` -
122
+ 发送命令并以服务器发送事件的形式返回结果流。
135
123
 
136
124
  ### 查询模块
137
125
 
@@ -183,245 +171,261 @@ const dateConditions = [
183
171
  ];
184
172
  ```
185
173
 
186
- #### 操作符
187
-
188
- 用于查询构建的完整操作符枚举:
189
-
190
- ```typescript
191
- import { Operator } from '@ahoo-wang/fetcher-wow';
192
-
193
- // 逻辑操作符
194
- (Operator.AND, Operator.OR, Operator.NOR);
195
-
196
- // 比较操作符
197
- (Operator.EQ,
198
- Operator.NE,
199
- Operator.GT,
200
- Operator.LT,
201
- Operator.GTE,
202
- Operator.LTE);
203
-
204
- // 成员操作符
205
- (Operator.IN, Operator.NOT_IN, Operator.ALL_IN, Operator.BETWEEN);
206
-
207
- // 字符串操作符
208
- (Operator.CONTAINS, Operator.STARTS_WITH, Operator.ENDS_WITH);
209
-
210
- // 存在性操作符
211
- (Operator.NULL, Operator.NOT_NULL, Operator.EXISTS);
212
-
213
- // 布尔操作符
214
- (Operator.TRUE, Operator.FALSE);
215
-
216
- // 日期操作符
217
- (Operator.TODAY,
218
- Operator.BEFORE_TODAY,
219
- Operator.TOMORROW,
220
- Operator.THIS_WEEK,
221
- Operator.NEXT_WEEK,
222
- Operator.LAST_WEEK,
223
- Operator.THIS_MONTH,
224
- Operator.LAST_MONTH,
225
- Operator.RECENT_DAYS,
226
- Operator.EARLIER_DAYS);
227
-
228
- // 特殊操作符
229
- (Operator.ID,
230
- Operator.IDS,
231
- Operator.AGGREGATE_ID,
232
- Operator.AGGREGATE_IDS,
233
- Operator.TENANT_ID,
234
- Operator.OWNER_ID,
235
- Operator.DELETED,
236
- Operator.ALL,
237
- Operator.ELEM_MATCH,
238
- Operator.RAW);
239
- ```
240
-
241
- #### 可查询接口
174
+ #### SnapshotQueryClient
242
175
 
243
- 用于构建带排序、分页和投影的查询的接口:
176
+ 用于查询物化快照的客户端:
244
177
 
245
178
  ```typescript
179
+ import { Fetcher, URL_RESOLVE_INTERCEPTOR_ORDER } from '@ahoo-wang/fetcher';
180
+ import '@ahoo-wang/fetcher-eventstream';
246
181
  import {
247
- Queryable,
248
- SortDirection,
249
- DEFAULT_PAGINATION,
182
+ SnapshotQueryClient,
183
+ all,
184
+ ListQuery,
185
+ PagedQuery,
186
+ SingleQuery,
250
187
  } from '@ahoo-wang/fetcher-wow';
188
+ import { idGenerator } from '@ahoo-wang/fetcher-cosec';
251
189
 
252
- const query: Queryable = {
253
- condition: eq('status', 'active'),
254
- sort: [
255
- { field: 'createdAt', direction: SortDirection.DESC },
256
- { field: 'name', direction: SortDirection.ASC },
257
- ],
258
- projection: {
259
- include: ['id', 'name', 'email', 'status'],
260
- exclude: ['password', 'internalNotes'],
261
- },
262
- };
190
+ interface CartItem {
191
+ productId: string;
192
+ quantity: number;
193
+ }
263
194
 
264
- const pagedQuery = {
265
- ...query,
266
- pagination: {
267
- index: 2,
268
- size: 20,
269
- },
270
- };
271
- ```
195
+ interface CartState {
196
+ id: string;
197
+ items: CartItem[];
198
+ }
272
199
 
273
- ### 类型模块
200
+ // 创建 fetcher 实例
201
+ const wowFetcher = new Fetcher({
202
+ baseURL: 'http://localhost:8080/',
203
+ });
204
+
205
+ // 添加拦截器处理 URL 参数
206
+ const ownerId = idGenerator.generateId();
207
+ wowFetcher.interceptors.request.use({
208
+ name: 'AppendOwnerId',
209
+ order: URL_RESOLVE_INTERCEPTOR_ORDER - 1,
210
+ intercept(exchange) {
211
+ exchange.request.urlParams = {
212
+ path: {
213
+ ...exchange.request.urlParams?.path,
214
+ ownerId,
215
+ },
216
+ query: exchange.request.urlParams?.query,
217
+ };
218
+ },
219
+ });
274
220
 
275
- #### 核心类型
221
+ // 创建快照查询客户端
222
+ const snapshotQueryClient = new SnapshotQueryClient<CartState>({
223
+ fetcher: wowFetcher,
224
+ basePath: 'owner/{ownerId}/cart',
225
+ });
276
226
 
277
- 领域建模的基本类型:
227
+ // 统计快照数量
228
+ const count = await snapshotQueryClient.count(all());
278
229
 
279
- ```typescript
280
- import {
281
- Identifier,
282
- Version,
283
- TenantId,
284
- OwnerId,
285
- NamedAggregate,
286
- AggregateId,
287
- StateCapable,
288
- } from '@ahoo-wang/fetcher-wow';
230
+ // 列出快照
231
+ const listQuery: ListQuery = {
232
+ condition: all(),
233
+ };
234
+ const list = await snapshotQueryClient.list(listQuery);
289
235
 
290
- interface User
291
- extends Identifier,
292
- Version,
293
- TenantId,
294
- OwnerId,
295
- NamedAggregate,
296
- StateCapable<UserState> {
297
- id: string;
298
- version: number;
299
- tenantId: string;
300
- ownerId: string;
301
- contextName: string;
302
- aggregateName: string;
303
- state: UserState;
236
+ // 以流的形式列出快照
237
+ const listStream = await snapshotQueryClient.listStream(listQuery);
238
+ for await (const event of listStream) {
239
+ const snapshot = event.data;
240
+ console.log('收到快照:', snapshot);
304
241
  }
305
242
 
306
- interface UserState {
307
- name: string;
308
- email: string;
309
- status: 'active' | 'inactive';
310
- createdAt: number;
311
- }
312
- ```
243
+ // 列出快照状态
244
+ const stateList = await snapshotQueryClient.listState(listQuery);
313
245
 
314
- #### 错误处理
246
+ // 以流的形式列出快照状态
247
+ const stateStream = await snapshotQueryClient.listStateStream(listQuery);
248
+ for await (const event of stateStream) {
249
+ const state = event.data;
250
+ console.log('收到状态:', state);
251
+ }
315
252
 
316
- 标准错误类型和代码:
253
+ // 分页查询快照
254
+ const pagedQuery: PagedQuery = {
255
+ condition: all(),
256
+ };
257
+ const paged = await snapshotQueryClient.paged(pagedQuery);
317
258
 
318
- ```typescript
319
- import { ErrorInfo, ErrorCodes, RecoverableType } from '@ahoo-wang/fetcher-wow';
259
+ // 分页查询快照状态
260
+ const pagedState = await snapshotQueryClient.pagedState(pagedQuery);
320
261
 
321
- const errorInfo: ErrorInfo = {
322
- errorCode: ErrorCodes.NOT_FOUND,
323
- errorMsg: '用户未找到',
324
- bindingErrors: [],
262
+ // 查询单个快照
263
+ const singleQuery: SingleQuery = {
264
+ condition: all(),
325
265
  };
266
+ const single = await snapshotQueryClient.single(singleQuery);
326
267
 
327
- // 检查错误类型
328
- if (ErrorCodes.isSucceeded(errorInfo.errorCode)) {
329
- console.log('操作成功');
330
- } else {
331
- console.error('操作失败:', errorInfo.errorMsg);
332
- }
268
+ // 查询单个快照状态
269
+ const singleState = await snapshotQueryClient.singleState(singleQuery);
333
270
  ```
334
271
 
335
- #### 函数类型
272
+ #### EventStreamQueryClient
336
273
 
337
- 事件和命令处理程序的函数信息:
274
+ 用于查询领域事件流的客户端:
338
275
 
339
276
  ```typescript
340
- import { FunctionInfo, FunctionKind } from '@ahoo-wang/fetcher-wow';
277
+ import { Fetcher, URL_RESOLVE_INTERCEPTOR_ORDER } from '@ahoo-wang/fetcher';
278
+ import '@ahoo-wang/fetcher-eventstream';
279
+ import {
280
+ EventStreamQueryClient,
281
+ all,
282
+ ListQuery,
283
+ PagedQuery,
284
+ } from '@ahoo-wang/fetcher-wow';
285
+ import { idGenerator } from '@ahoo-wang/fetcher-cosec';
286
+
287
+ // 创建 fetcher 实例
288
+ const wowFetcher = new Fetcher({
289
+ baseURL: 'http://localhost:8080/',
290
+ });
291
+
292
+ // 添加拦截器处理 URL 参数
293
+ const ownerId = idGenerator.generateId();
294
+ wowFetcher.interceptors.request.use({
295
+ name: 'AppendOwnerId',
296
+ order: URL_RESOLVE_INTERCEPTOR_ORDER - 1,
297
+ intercept(exchange) {
298
+ exchange.request.urlParams = {
299
+ path: {
300
+ ...exchange.request.urlParams?.path,
301
+ ownerId,
302
+ },
303
+ query: exchange.request.urlParams?.query,
304
+ };
305
+ },
306
+ });
307
+
308
+ // 创建事件流查询客户端
309
+ const eventStreamQueryClient = new EventStreamQueryClient({
310
+ fetcher: wowFetcher,
311
+ basePath: 'owner/{ownerId}/cart',
312
+ });
313
+
314
+ // 统计事件流数量
315
+ const count = await eventStreamQueryClient.count(all());
341
316
 
342
- const functionInfo: FunctionInfo = {
343
- functionKind: FunctionKind.COMMAND,
344
- contextName: 'user-context',
345
- processorName: 'UserProcessor',
346
- name: 'CreateUser',
317
+ // 列出事件流
318
+ const listQuery: ListQuery = {
319
+ condition: all(),
347
320
  };
321
+ const list = await eventStreamQueryClient.list(listQuery);
322
+
323
+ // 以流的形式列出事件流
324
+ const listStream = await eventStreamQueryClient.listStream(listQuery);
325
+ for await (const event of listStream) {
326
+ const domainEventStream = event.data;
327
+ console.log('收到事件流:', domainEventStream);
328
+ }
329
+
330
+ // 分页查询事件流
331
+ const pagedQuery: PagedQuery = {
332
+ condition: all(),
333
+ };
334
+ const paged = await eventStreamQueryClient.paged(pagedQuery);
348
335
  ```
349
336
 
350
337
  ## 🛠️ 高级用法
351
338
 
352
- ### 复杂查询构建
339
+ ### 完整的命令和查询流程示例
353
340
 
354
341
  ```typescript
342
+ import { Fetcher, URL_RESOLVE_INTERCEPTOR_ORDER } from '@ahoo-wang/fetcher';
343
+ import '@ahoo-wang/fetcher-eventstream';
355
344
  import {
356
- and,
357
- or,
358
- eq,
359
- ne,
360
- gt,
361
- lt,
362
- contains,
363
- isIn,
364
- notIn,
365
- between,
366
- startsWith,
367
- endsWith,
368
- elemMatch,
369
- isNull,
370
- notNull,
371
- exists,
372
- today,
373
- thisWeek,
374
- recentDays,
345
+ CommandClient,
346
+ CommandRequest,
347
+ CommandHttpHeaders,
348
+ CommandStage,
349
+ HttpMethod,
350
+ SnapshotQueryClient,
351
+ all,
352
+ ListQuery,
375
353
  } from '@ahoo-wang/fetcher-wow';
354
+ import { idGenerator } from '@ahoo-wang/fetcher-cosec';
376
355
 
377
- // 构建用户搜索的复杂查询
378
- const userSearchQuery = {
379
- condition: and(
380
- eq('tenantId', 'tenant-123'),
381
- ne('status', 'deleted'),
382
- or(
383
- // 按姓名或邮箱搜索
384
- contains('name', 'john'),
385
- contains('email', 'john'),
386
- ),
387
- // 年龄和分数过滤
388
- gt('age', 18),
389
- between('score', 50, 100),
390
-
391
- // 部门过滤
392
- isIn('departments', 'engineering', 'marketing'),
393
- notIn('blockedDepartments', 'hr', 'finance'),
394
-
395
- // 字符串模式匹配
396
- startsWith('employeeId', 'EMP-'),
397
- endsWith('domain', '.com'),
398
-
399
- // 数组匹配
400
- elemMatch('roles', eq('name', 'admin')),
401
-
402
- // 日期过滤
403
- recentDays('lastLogin', 30),
404
- thisWeek('createdAt'),
405
-
406
- // 存在性检查
407
- exists('phoneNumber'),
408
- notNull('address'),
409
- ),
356
+ interface CartItem {
357
+ productId: string;
358
+ quantity: number;
359
+ }
410
360
 
411
- sort: [
412
- { field: 'score', direction: 'DESC' },
413
- { field: 'lastLogin', direction: 'DESC' },
414
- ],
361
+ interface CartState {
362
+ id: string;
363
+ items: CartItem[];
364
+ }
415
365
 
416
- projection: {
417
- include: ['id', 'name', 'email', 'score', 'lastLogin', 'departments'],
366
+ // 创建 fetcher 实例
367
+ const wowFetcher = new Fetcher({
368
+ baseURL: 'http://localhost:8080/',
369
+ });
370
+
371
+ // 添加拦截器处理 URL 参数
372
+ const ownerId = idGenerator.generateId();
373
+ wowFetcher.interceptors.request.use({
374
+ name: 'AppendOwnerId',
375
+ order: URL_RESOLVE_INTERCEPTOR_ORDER - 1,
376
+ intercept(exchange) {
377
+ exchange.request.urlParams = {
378
+ path: {
379
+ ...exchange.request.urlParams?.path,
380
+ ownerId,
381
+ },
382
+ query: exchange.request.urlParams?.query,
383
+ };
418
384
  },
419
-
420
- pagination: {
421
- index: 1,
422
- size: 50,
385
+ });
386
+
387
+ // 创建客户端
388
+ const commandClient = new CommandClient({
389
+ fetcher: wowFetcher,
390
+ basePath: 'owner/{ownerId}/cart',
391
+ });
392
+
393
+ const snapshotQueryClient = new SnapshotQueryClient<CartState>({
394
+ fetcher: wowFetcher,
395
+ basePath: 'owner/{ownerId}/cart',
396
+ });
397
+
398
+ // 1. 发送命令添加商品到购物车
399
+ const addItemCommand: CommandRequest = {
400
+ method: HttpMethod.POST,
401
+ headers: {
402
+ [CommandHttpHeaders.WAIT_STAGE]: CommandStage.SNAPSHOT,
403
+ },
404
+ body: {
405
+ productId: 'product-123',
406
+ quantity: 2,
423
407
  },
424
408
  };
409
+
410
+ const commandResult = await commandClient.send('add_cart_item', addItemCommand);
411
+ console.log('命令执行完成:', commandResult);
412
+
413
+ // 2. 查询更新后的购物车
414
+ const listQuery: ListQuery = {
415
+ condition: all(),
416
+ };
417
+ const carts = await snapshotQueryClient.list(listQuery);
418
+
419
+ for (const cart of carts) {
420
+ console.log('购物车:', cart.state);
421
+ }
422
+
423
+ // 3. 流式监听购物车更新
424
+ const listStream = await snapshotQueryClient.listStream(listQuery);
425
+ for await (const event of listStream) {
426
+ const cart = event.data;
427
+ console.log('购物车更新:', cart.state);
428
+ }
425
429
  ```
426
430
 
427
431
  ## 🧪 测试