ts-procedures 5.15.0 → 5.16.0

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 (47) hide show
  1. package/agent_config/claude-code/skills/ts-procedures/SKILL.md +1 -1
  2. package/agent_config/claude-code/skills/ts-procedures/api-reference.md +57 -4
  3. package/agent_config/claude-code/skills/ts-procedures/patterns.md +102 -3
  4. package/agent_config/claude-code/skills/ts-procedures-scaffold/templates/client.md +33 -5
  5. package/agent_config/copilot/copilot-instructions.md +55 -7
  6. package/agent_config/cursor/cursorrules +55 -7
  7. package/build/client/call.d.ts +18 -9
  8. package/build/client/call.js +25 -19
  9. package/build/client/call.js.map +1 -1
  10. package/build/client/call.test.js +167 -17
  11. package/build/client/call.test.js.map +1 -1
  12. package/build/client/index.d.ts +1 -1
  13. package/build/client/index.js +18 -3
  14. package/build/client/index.js.map +1 -1
  15. package/build/client/index.test.js +104 -0
  16. package/build/client/index.test.js.map +1 -1
  17. package/build/client/resolve-options.d.ts +45 -0
  18. package/build/client/resolve-options.js +82 -0
  19. package/build/client/resolve-options.js.map +1 -0
  20. package/build/client/resolve-options.test.d.ts +1 -0
  21. package/build/client/resolve-options.test.js +158 -0
  22. package/build/client/resolve-options.test.js.map +1 -0
  23. package/build/client/stream.d.ts +18 -9
  24. package/build/client/stream.js +24 -19
  25. package/build/client/stream.js.map +1 -1
  26. package/build/client/stream.test.js +102 -46
  27. package/build/client/stream.test.js.map +1 -1
  28. package/build/client/types.d.ts +68 -1
  29. package/build/client/types.js +1 -1
  30. package/build/codegen/e2e.test.js +141 -0
  31. package/build/codegen/e2e.test.js.map +1 -1
  32. package/build/codegen/emit-client-runtime.js +3 -0
  33. package/build/codegen/emit-client-runtime.js.map +1 -1
  34. package/docs/client-and-codegen.md +123 -2
  35. package/package.json +1 -1
  36. package/src/client/call.test.ts +202 -29
  37. package/src/client/call.ts +41 -28
  38. package/src/client/index.test.ts +117 -0
  39. package/src/client/index.ts +25 -8
  40. package/src/client/resolve-options.test.ts +205 -0
  41. package/src/client/resolve-options.ts +113 -0
  42. package/src/client/stream.test.ts +132 -107
  43. package/src/client/stream.ts +40 -25
  44. package/src/client/types.ts +74 -2
  45. package/src/codegen/e2e.test.ts +151 -0
  46. package/src/codegen/emit-client-runtime.ts +3 -0
  47. package/src/implementations/http/README.md +9 -1
@@ -0,0 +1 @@
1
+ {"version":3,"file":"resolve-options.js","sourceRoot":"","sources":["../../src/client/resolve-options.ts"],"names":[],"mappings":"AAOA;;;GAGG;AACH,MAAM,UAAU,eAAe,CAC7B,QAA2C,EAC3C,OAAyC,EACzC,QAAgB;IAEhB,OAAO,OAAO,EAAE,QAAQ,IAAI,QAAQ,EAAE,QAAQ,IAAI,QAAQ,CAAA;AAC5D,CAAC;AAED;;;;;;;;GAQG;AACH,MAAM,UAAU,aAAa,CAC3B,QAA2C,EAC3C,OAAyC;IAEzC,MAAM,OAAO,GAAkB,EAAE,CAAA;IAEjC,IAAI,QAAQ,EAAE,MAAM;QAAE,OAAO,CAAC,IAAI,CAAC,QAAQ,CAAC,MAAM,CAAC,CAAA;IACnD,IAAI,OAAO,EAAE,MAAM;QAAE,OAAO,CAAC,IAAI,CAAC,OAAO,CAAC,MAAM,CAAC,CAAA;IAEjD,MAAM,OAAO,GAAG,OAAO,EAAE,OAAO,IAAI,QAAQ,EAAE,OAAO,CAAA;IACrD,IAAI,OAAO,IAAI,IAAI,IAAI,OAAO,GAAG,CAAC,EAAE,CAAC;QACnC,OAAO,CAAC,IAAI,CAAC,WAAW,CAAC,OAAO,CAAC,OAAO,CAAC,CAAC,CAAA;IAC5C,CAAC;IAED,IAAI,OAAO,CAAC,MAAM,KAAK,CAAC;QAAE,OAAO,SAAS,CAAA;IAC1C,IAAI,OAAO,CAAC,MAAM,KAAK,CAAC;QAAE,OAAO,OAAO,CAAC,CAAC,CAAC,CAAA;IAC3C,OAAO,WAAW,CAAC,GAAG,CAAC,OAAO,CAAC,CAAA;AACjC,CAAC;AAED;;;GAGG;AACH,MAAM,UAAU,cAAc,CAC5B,QAA2C,EAC3C,OAAyC;IAEzC,MAAM,cAAc,GAAG,QAAQ,EAAE,OAAO,CAAA;IACxC,MAAM,WAAW,GAAG,OAAO,EAAE,OAAO,CAAA;IAEpC,IAAI,CAAC,cAAc,IAAI,CAAC,WAAW;QAAE,OAAO,SAAS,CAAA;IAErD,OAAO,EAAE,GAAG,cAAc,EAAE,GAAG,WAAW,EAAE,CAAA;AAC9C,CAAC;AAED;;;;;;;;;;GAUG;AACH,MAAM,UAAU,WAAW,CACzB,QAA2C,EAC3C,OAAyC;IAEzC,MAAM,WAAW,GAAG,QAAQ,EAAE,IAAI,CAAA;IAClC,MAAM,QAAQ,GAAG,OAAO,EAAE,IAAI,CAAA;IAE9B,IAAI,CAAC,WAAW,IAAI,CAAC,QAAQ;QAAE,OAAO,SAAS,CAAA;IAE/C,OAAO,EAAE,GAAG,WAAW,EAAE,GAAG,QAAQ,EAAiB,CAAA;AACvD,CAAC;AAED;;;;;;;;;;GAUG;AACH,MAAM,UAAU,mBAAmB,CACjC,OAAuB,EACvB,QAA2C,EAC3C,OAAyC;IAEzC,MAAM,MAAM,GAAG,aAAa,CAAC,QAAQ,EAAE,OAAO,CAAC,CAAA;IAC/C,MAAM,eAAe,GAAG,cAAc,CAAC,QAAQ,EAAE,OAAO,CAAC,CAAA;IACzD,MAAM,IAAI,GAAG,WAAW,CAAC,QAAQ,EAAE,OAAO,CAAC,CAAA;IAE3C,MAAM,OAAO,GACX,eAAe,IAAI,OAAO,CAAC,OAAO;QAChC,CAAC,CAAC,EAAE,GAAG,eAAe,EAAE,GAAG,OAAO,CAAC,OAAO,EAAE;QAC5C,CAAC,CAAC,SAAS,CAAA;IAEf,OAAO,EAAE,GAAG,OAAO,EAAE,OAAO,EAAE,MAAM,EAAE,IAAI,EAAE,CAAA;AAC9C,CAAC"}
@@ -0,0 +1 @@
1
+ export {};
@@ -0,0 +1,158 @@
1
+ import { describe, it, expect, vi } from 'vitest';
2
+ import { applyRequestOptions, resolveBasePath, resolveHeaders, resolveMeta, resolveSignal, } from './resolve-options.js';
3
+ // ── resolveBasePath ───────────────────────────────────────
4
+ describe('resolveBasePath', () => {
5
+ it('uses fallback when nothing is set', () => {
6
+ expect(resolveBasePath(undefined, undefined, 'https://api.example.com')).toBe('https://api.example.com');
7
+ });
8
+ it('uses default when only defaults.basePath is set', () => {
9
+ expect(resolveBasePath({ basePath: 'https://default.example.com' }, undefined, 'https://fallback')).toBe('https://default.example.com');
10
+ });
11
+ it('per-call basePath overrides default', () => {
12
+ expect(resolveBasePath({ basePath: 'https://default.example.com' }, { basePath: 'https://percall.example.com' }, 'https://fallback')).toBe('https://percall.example.com');
13
+ });
14
+ });
15
+ // ── resolveHeaders ────────────────────────────────────────
16
+ describe('resolveHeaders', () => {
17
+ it('returns undefined when neither side sets headers', () => {
18
+ expect(resolveHeaders(undefined, undefined)).toBeUndefined();
19
+ });
20
+ it('returns default headers when only defaults set', () => {
21
+ expect(resolveHeaders({ headers: { 'x-a': '1' } }, undefined)).toEqual({ 'x-a': '1' });
22
+ });
23
+ it('per-call keys override default keys', () => {
24
+ const defaults = { headers: { 'x-a': 'default', 'x-b': 'keep' } };
25
+ const options = { headers: { 'x-a': 'override' } };
26
+ expect(resolveHeaders(defaults, options)).toEqual({
27
+ 'x-a': 'override',
28
+ 'x-b': 'keep',
29
+ });
30
+ });
31
+ });
32
+ // ── resolveMeta ───────────────────────────────────────────
33
+ describe('resolveMeta', () => {
34
+ it('returns undefined when neither side sets meta', () => {
35
+ expect(resolveMeta(undefined, undefined)).toBeUndefined();
36
+ });
37
+ it('merges default + per-call meta (shallow), per-call keys win', () => {
38
+ const defaults = { meta: { a: 1, b: 2 } };
39
+ const options = { meta: { b: 99, c: 3 } };
40
+ expect(resolveMeta(defaults, options)).toEqual({ a: 1, b: 99, c: 3 });
41
+ });
42
+ });
43
+ // ── resolveSignal ─────────────────────────────────────────
44
+ describe('resolveSignal', () => {
45
+ it('returns undefined when nothing is set', () => {
46
+ expect(resolveSignal(undefined, undefined)).toBeUndefined();
47
+ });
48
+ it('returns the default signal when no timeout and no per-call signal', () => {
49
+ const controller = new AbortController();
50
+ expect(resolveSignal({ signal: controller.signal }, undefined)).toBe(controller.signal);
51
+ });
52
+ it('returns the per-call signal when no default and no timeout', () => {
53
+ const controller = new AbortController();
54
+ expect(resolveSignal(undefined, { signal: controller.signal })).toBe(controller.signal);
55
+ });
56
+ it('combines default + per-call signals — default aborts combined signal', () => {
57
+ const defaultCtrl = new AbortController();
58
+ const callCtrl = new AbortController();
59
+ const signal = resolveSignal({ signal: defaultCtrl.signal }, { signal: callCtrl.signal });
60
+ expect(signal.aborted).toBe(false);
61
+ defaultCtrl.abort(new Error('default-abort'));
62
+ expect(signal.aborted).toBe(true);
63
+ });
64
+ it('combines default + per-call signals — per-call aborts combined signal', () => {
65
+ const defaultCtrl = new AbortController();
66
+ const callCtrl = new AbortController();
67
+ const signal = resolveSignal({ signal: defaultCtrl.signal }, { signal: callCtrl.signal });
68
+ callCtrl.abort(new Error('call-abort'));
69
+ expect(signal.aborted).toBe(true);
70
+ });
71
+ it('applies timeout via AbortSignal.timeout', () => {
72
+ const spy = vi.spyOn(AbortSignal, 'timeout');
73
+ try {
74
+ const signal = resolveSignal(undefined, { timeout: 100 });
75
+ expect(spy).toHaveBeenCalledWith(100);
76
+ expect(signal).toBeDefined();
77
+ }
78
+ finally {
79
+ spy.mockRestore();
80
+ }
81
+ });
82
+ it('per-call timeout overrides default timeout', () => {
83
+ const spy = vi.spyOn(AbortSignal, 'timeout');
84
+ try {
85
+ resolveSignal({ timeout: 10_000 }, { timeout: 100 });
86
+ expect(spy).toHaveBeenCalledWith(100);
87
+ expect(spy).not.toHaveBeenCalledWith(10_000);
88
+ }
89
+ finally {
90
+ spy.mockRestore();
91
+ }
92
+ });
93
+ it('combines signal + timeout — signal aborts first', () => {
94
+ const controller = new AbortController();
95
+ const signal = resolveSignal(undefined, { signal: controller.signal, timeout: 10_000 });
96
+ expect(signal.aborted).toBe(false);
97
+ controller.abort();
98
+ expect(signal.aborted).toBe(true);
99
+ });
100
+ it('per-call timeout: 0 disables default timeout', () => {
101
+ const signal = resolveSignal({ timeout: 1000 }, { timeout: 0 });
102
+ expect(signal).toBeUndefined();
103
+ });
104
+ });
105
+ // ── applyRequestOptions ───────────────────────────────────
106
+ describe('applyRequestOptions', () => {
107
+ const baseRequest = {
108
+ url: 'https://api.example.com/foo',
109
+ method: 'POST',
110
+ body: { hello: 'world' },
111
+ };
112
+ it('returns the request unchanged when nothing is provided', () => {
113
+ const result = applyRequestOptions(baseRequest, undefined, undefined);
114
+ expect(result.url).toBe(baseRequest.url);
115
+ expect(result.body).toEqual({ hello: 'world' });
116
+ expect(result.headers).toBeUndefined();
117
+ expect(result.signal).toBeUndefined();
118
+ expect(result.meta).toBeUndefined();
119
+ });
120
+ it('merges default + per-call headers, preserving route-declared headers', () => {
121
+ const reqWithHeaders = {
122
+ ...baseRequest,
123
+ headers: { 'content-type': 'application/json', 'x-route': 'declared' },
124
+ };
125
+ const result = applyRequestOptions(reqWithHeaders, { headers: { 'x-default': 'd', 'x-route': 'from-default' } }, { headers: { 'x-call': 'c', 'x-route': 'from-call' } });
126
+ expect(result.headers).toEqual({
127
+ 'x-default': 'd',
128
+ 'x-call': 'c',
129
+ // Route-declared headers WIN over resolved options (typed contract)
130
+ 'content-type': 'application/json',
131
+ 'x-route': 'declared',
132
+ });
133
+ });
134
+ it('attaches meta to the request when provided', () => {
135
+ const result = applyRequestOptions(baseRequest, undefined, {
136
+ meta: { traceId: 'abc' },
137
+ });
138
+ expect(result.meta).toEqual({ traceId: 'abc' });
139
+ });
140
+ it('passes per-call signal through', () => {
141
+ const controller = new AbortController();
142
+ const result = applyRequestOptions(baseRequest, undefined, { signal: controller.signal });
143
+ expect(result.signal).toBe(controller.signal);
144
+ });
145
+ it('attaches a signal when per-call timeout is set', () => {
146
+ const spy = vi.spyOn(AbortSignal, 'timeout');
147
+ try {
148
+ const result = applyRequestOptions(baseRequest, undefined, { timeout: 100 });
149
+ expect(spy).toHaveBeenCalledWith(100);
150
+ expect(result.signal).toBeDefined();
151
+ expect(result.signal?.aborted).toBe(false);
152
+ }
153
+ finally {
154
+ spy.mockRestore();
155
+ }
156
+ });
157
+ });
158
+ //# sourceMappingURL=resolve-options.test.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"resolve-options.test.js","sourceRoot":"","sources":["../../src/client/resolve-options.test.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,QAAQ,EAAE,EAAE,EAAE,MAAM,EAAE,EAAE,EAAE,MAAM,QAAQ,CAAA;AACjD,OAAO,EACL,mBAAmB,EACnB,eAAe,EACf,cAAc,EACd,WAAW,EACX,aAAa,GACd,MAAM,sBAAsB,CAAA;AAG7B,6DAA6D;AAE7D,QAAQ,CAAC,iBAAiB,EAAE,GAAG,EAAE;IAC/B,EAAE,CAAC,mCAAmC,EAAE,GAAG,EAAE;QAC3C,MAAM,CAAC,eAAe,CAAC,SAAS,EAAE,SAAS,EAAE,yBAAyB,CAAC,CAAC,CAAC,IAAI,CAC3E,yBAAyB,CAC1B,CAAA;IACH,CAAC,CAAC,CAAA;IAEF,EAAE,CAAC,iDAAiD,EAAE,GAAG,EAAE;QACzD,MAAM,CACJ,eAAe,CAAC,EAAE,QAAQ,EAAE,6BAA6B,EAAE,EAAE,SAAS,EAAE,kBAAkB,CAAC,CAC5F,CAAC,IAAI,CAAC,6BAA6B,CAAC,CAAA;IACvC,CAAC,CAAC,CAAA;IAEF,EAAE,CAAC,qCAAqC,EAAE,GAAG,EAAE;QAC7C,MAAM,CACJ,eAAe,CACb,EAAE,QAAQ,EAAE,6BAA6B,EAAE,EAC3C,EAAE,QAAQ,EAAE,6BAA6B,EAAE,EAC3C,kBAAkB,CACnB,CACF,CAAC,IAAI,CAAC,6BAA6B,CAAC,CAAA;IACvC,CAAC,CAAC,CAAA;AACJ,CAAC,CAAC,CAAA;AAEF,6DAA6D;AAE7D,QAAQ,CAAC,gBAAgB,EAAE,GAAG,EAAE;IAC9B,EAAE,CAAC,kDAAkD,EAAE,GAAG,EAAE;QAC1D,MAAM,CAAC,cAAc,CAAC,SAAS,EAAE,SAAS,CAAC,CAAC,CAAC,aAAa,EAAE,CAAA;IAC9D,CAAC,CAAC,CAAA;IAEF,EAAE,CAAC,gDAAgD,EAAE,GAAG,EAAE;QACxD,MAAM,CAAC,cAAc,CAAC,EAAE,OAAO,EAAE,EAAE,KAAK,EAAE,GAAG,EAAE,EAAE,EAAE,SAAS,CAAC,CAAC,CAAC,OAAO,CAAC,EAAE,KAAK,EAAE,GAAG,EAAE,CAAC,CAAA;IACxF,CAAC,CAAC,CAAA;IAEF,EAAE,CAAC,qCAAqC,EAAE,GAAG,EAAE;QAC7C,MAAM,QAAQ,GAA0B,EAAE,OAAO,EAAE,EAAE,KAAK,EAAE,SAAS,EAAE,KAAK,EAAE,MAAM,EAAE,EAAE,CAAA;QACxF,MAAM,OAAO,GAAyB,EAAE,OAAO,EAAE,EAAE,KAAK,EAAE,UAAU,EAAE,EAAE,CAAA;QACxE,MAAM,CAAC,cAAc,CAAC,QAAQ,EAAE,OAAO,CAAC,CAAC,CAAC,OAAO,CAAC;YAChD,KAAK,EAAE,UAAU;YACjB,KAAK,EAAE,MAAM;SACd,CAAC,CAAA;IACJ,CAAC,CAAC,CAAA;AACJ,CAAC,CAAC,CAAA;AAEF,6DAA6D;AAE7D,QAAQ,CAAC,aAAa,EAAE,GAAG,EAAE;IAC3B,EAAE,CAAC,+CAA+C,EAAE,GAAG,EAAE;QACvD,MAAM,CAAC,WAAW,CAAC,SAAS,EAAE,SAAS,CAAC,CAAC,CAAC,aAAa,EAAE,CAAA;IAC3D,CAAC,CAAC,CAAA;IAEF,EAAE,CAAC,6DAA6D,EAAE,GAAG,EAAE;QACrE,MAAM,QAAQ,GAA0B,EAAE,IAAI,EAAE,EAAE,CAAC,EAAE,CAAC,EAAE,CAAC,EAAE,CAAC,EAAW,EAAE,CAAA;QACzE,MAAM,OAAO,GAAyB,EAAE,IAAI,EAAE,EAAE,CAAC,EAAE,EAAE,EAAE,CAAC,EAAE,CAAC,EAAW,EAAE,CAAA;QACxE,MAAM,CAAC,WAAW,CAAC,QAAQ,EAAE,OAAO,CAAC,CAAC,CAAC,OAAO,CAAC,EAAE,CAAC,EAAE,CAAC,EAAE,CAAC,EAAE,EAAE,EAAE,CAAC,EAAE,CAAC,EAAE,CAAC,CAAA;IACvE,CAAC,CAAC,CAAA;AACJ,CAAC,CAAC,CAAA;AAEF,6DAA6D;AAE7D,QAAQ,CAAC,eAAe,EAAE,GAAG,EAAE;IAC7B,EAAE,CAAC,uCAAuC,EAAE,GAAG,EAAE;QAC/C,MAAM,CAAC,aAAa,CAAC,SAAS,EAAE,SAAS,CAAC,CAAC,CAAC,aAAa,EAAE,CAAA;IAC7D,CAAC,CAAC,CAAA;IAEF,EAAE,CAAC,mEAAmE,EAAE,GAAG,EAAE;QAC3E,MAAM,UAAU,GAAG,IAAI,eAAe,EAAE,CAAA;QACxC,MAAM,CAAC,aAAa,CAAC,EAAE,MAAM,EAAE,UAAU,CAAC,MAAM,EAAE,EAAE,SAAS,CAAC,CAAC,CAAC,IAAI,CAAC,UAAU,CAAC,MAAM,CAAC,CAAA;IACzF,CAAC,CAAC,CAAA;IAEF,EAAE,CAAC,4DAA4D,EAAE,GAAG,EAAE;QACpE,MAAM,UAAU,GAAG,IAAI,eAAe,EAAE,CAAA;QACxC,MAAM,CAAC,aAAa,CAAC,SAAS,EAAE,EAAE,MAAM,EAAE,UAAU,CAAC,MAAM,EAAE,CAAC,CAAC,CAAC,IAAI,CAAC,UAAU,CAAC,MAAM,CAAC,CAAA;IACzF,CAAC,CAAC,CAAA;IAEF,EAAE,CAAC,sEAAsE,EAAE,GAAG,EAAE;QAC9E,MAAM,WAAW,GAAG,IAAI,eAAe,EAAE,CAAA;QACzC,MAAM,QAAQ,GAAG,IAAI,eAAe,EAAE,CAAA;QACtC,MAAM,MAAM,GAAG,aAAa,CAAC,EAAE,MAAM,EAAE,WAAW,CAAC,MAAM,EAAE,EAAE,EAAE,MAAM,EAAE,QAAQ,CAAC,MAAM,EAAE,CAAE,CAAA;QAE1F,MAAM,CAAC,MAAM,CAAC,OAAO,CAAC,CAAC,IAAI,CAAC,KAAK,CAAC,CAAA;QAClC,WAAW,CAAC,KAAK,CAAC,IAAI,KAAK,CAAC,eAAe,CAAC,CAAC,CAAA;QAC7C,MAAM,CAAC,MAAM,CAAC,OAAO,CAAC,CAAC,IAAI,CAAC,IAAI,CAAC,CAAA;IACnC,CAAC,CAAC,CAAA;IAEF,EAAE,CAAC,uEAAuE,EAAE,GAAG,EAAE;QAC/E,MAAM,WAAW,GAAG,IAAI,eAAe,EAAE,CAAA;QACzC,MAAM,QAAQ,GAAG,IAAI,eAAe,EAAE,CAAA;QACtC,MAAM,MAAM,GAAG,aAAa,CAAC,EAAE,MAAM,EAAE,WAAW,CAAC,MAAM,EAAE,EAAE,EAAE,MAAM,EAAE,QAAQ,CAAC,MAAM,EAAE,CAAE,CAAA;QAE1F,QAAQ,CAAC,KAAK,CAAC,IAAI,KAAK,CAAC,YAAY,CAAC,CAAC,CAAA;QACvC,MAAM,CAAC,MAAM,CAAC,OAAO,CAAC,CAAC,IAAI,CAAC,IAAI,CAAC,CAAA;IACnC,CAAC,CAAC,CAAA;IAEF,EAAE,CAAC,yCAAyC,EAAE,GAAG,EAAE;QACjD,MAAM,GAAG,GAAG,EAAE,CAAC,KAAK,CAAC,WAAW,EAAE,SAAS,CAAC,CAAA;QAC5C,IAAI,CAAC;YACH,MAAM,MAAM,GAAG,aAAa,CAAC,SAAS,EAAE,EAAE,OAAO,EAAE,GAAG,EAAE,CAAC,CAAA;YACzD,MAAM,CAAC,GAAG,CAAC,CAAC,oBAAoB,CAAC,GAAG,CAAC,CAAA;YACrC,MAAM,CAAC,MAAM,CAAC,CAAC,WAAW,EAAE,CAAA;QAC9B,CAAC;gBAAS,CAAC;YACT,GAAG,CAAC,WAAW,EAAE,CAAA;QACnB,CAAC;IACH,CAAC,CAAC,CAAA;IAEF,EAAE,CAAC,4CAA4C,EAAE,GAAG,EAAE;QACpD,MAAM,GAAG,GAAG,EAAE,CAAC,KAAK,CAAC,WAAW,EAAE,SAAS,CAAC,CAAA;QAC5C,IAAI,CAAC;YACH,aAAa,CAAC,EAAE,OAAO,EAAE,MAAM,EAAE,EAAE,EAAE,OAAO,EAAE,GAAG,EAAE,CAAC,CAAA;YACpD,MAAM,CAAC,GAAG,CAAC,CAAC,oBAAoB,CAAC,GAAG,CAAC,CAAA;YACrC,MAAM,CAAC,GAAG,CAAC,CAAC,GAAG,CAAC,oBAAoB,CAAC,MAAM,CAAC,CAAA;QAC9C,CAAC;gBAAS,CAAC;YACT,GAAG,CAAC,WAAW,EAAE,CAAA;QACnB,CAAC;IACH,CAAC,CAAC,CAAA;IAEF,EAAE,CAAC,iDAAiD,EAAE,GAAG,EAAE;QACzD,MAAM,UAAU,GAAG,IAAI,eAAe,EAAE,CAAA;QACxC,MAAM,MAAM,GAAG,aAAa,CAAC,SAAS,EAAE,EAAE,MAAM,EAAE,UAAU,CAAC,MAAM,EAAE,OAAO,EAAE,MAAM,EAAE,CAAE,CAAA;QACxF,MAAM,CAAC,MAAM,CAAC,OAAO,CAAC,CAAC,IAAI,CAAC,KAAK,CAAC,CAAA;QAClC,UAAU,CAAC,KAAK,EAAE,CAAA;QAClB,MAAM,CAAC,MAAM,CAAC,OAAO,CAAC,CAAC,IAAI,CAAC,IAAI,CAAC,CAAA;IACnC,CAAC,CAAC,CAAA;IAEF,EAAE,CAAC,8CAA8C,EAAE,GAAG,EAAE;QACtD,MAAM,MAAM,GAAG,aAAa,CAAC,EAAE,OAAO,EAAE,IAAI,EAAE,EAAE,EAAE,OAAO,EAAE,CAAC,EAAE,CAAC,CAAA;QAC/D,MAAM,CAAC,MAAM,CAAC,CAAC,aAAa,EAAE,CAAA;IAChC,CAAC,CAAC,CAAA;AACJ,CAAC,CAAC,CAAA;AAEF,6DAA6D;AAE7D,QAAQ,CAAC,qBAAqB,EAAE,GAAG,EAAE;IACnC,MAAM,WAAW,GAAmB;QAClC,GAAG,EAAE,6BAA6B;QAClC,MAAM,EAAE,MAAM;QACd,IAAI,EAAE,EAAE,KAAK,EAAE,OAAO,EAAE;KACzB,CAAA;IAED,EAAE,CAAC,wDAAwD,EAAE,GAAG,EAAE;QAChE,MAAM,MAAM,GAAG,mBAAmB,CAAC,WAAW,EAAE,SAAS,EAAE,SAAS,CAAC,CAAA;QACrE,MAAM,CAAC,MAAM,CAAC,GAAG,CAAC,CAAC,IAAI,CAAC,WAAW,CAAC,GAAG,CAAC,CAAA;QACxC,MAAM,CAAC,MAAM,CAAC,IAAI,CAAC,CAAC,OAAO,CAAC,EAAE,KAAK,EAAE,OAAO,EAAE,CAAC,CAAA;QAC/C,MAAM,CAAC,MAAM,CAAC,OAAO,CAAC,CAAC,aAAa,EAAE,CAAA;QACtC,MAAM,CAAC,MAAM,CAAC,MAAM,CAAC,CAAC,aAAa,EAAE,CAAA;QACrC,MAAM,CAAC,MAAM,CAAC,IAAI,CAAC,CAAC,aAAa,EAAE,CAAA;IACrC,CAAC,CAAC,CAAA;IAEF,EAAE,CAAC,sEAAsE,EAAE,GAAG,EAAE;QAC9E,MAAM,cAAc,GAAmB;YACrC,GAAG,WAAW;YACd,OAAO,EAAE,EAAE,cAAc,EAAE,kBAAkB,EAAE,SAAS,EAAE,UAAU,EAAE;SACvE,CAAA;QACD,MAAM,MAAM,GAAG,mBAAmB,CAChC,cAAc,EACd,EAAE,OAAO,EAAE,EAAE,WAAW,EAAE,GAAG,EAAE,SAAS,EAAE,cAAc,EAAE,EAAE,EAC5D,EAAE,OAAO,EAAE,EAAE,QAAQ,EAAE,GAAG,EAAE,SAAS,EAAE,WAAW,EAAE,EAAE,CACvD,CAAA;QACD,MAAM,CAAC,MAAM,CAAC,OAAO,CAAC,CAAC,OAAO,CAAC;YAC7B,WAAW,EAAE,GAAG;YAChB,QAAQ,EAAE,GAAG;YACb,oEAAoE;YACpE,cAAc,EAAE,kBAAkB;YAClC,SAAS,EAAE,UAAU;SACtB,CAAC,CAAA;IACJ,CAAC,CAAC,CAAA;IAEF,EAAE,CAAC,4CAA4C,EAAE,GAAG,EAAE;QACpD,MAAM,MAAM,GAAG,mBAAmB,CAAC,WAAW,EAAE,SAAS,EAAE;YACzD,IAAI,EAAE,EAAE,OAAO,EAAE,KAAK,EAAW;SAClC,CAAC,CAAA;QACF,MAAM,CAAC,MAAM,CAAC,IAAI,CAAC,CAAC,OAAO,CAAC,EAAE,OAAO,EAAE,KAAK,EAAE,CAAC,CAAA;IACjD,CAAC,CAAC,CAAA;IAEF,EAAE,CAAC,gCAAgC,EAAE,GAAG,EAAE;QACxC,MAAM,UAAU,GAAG,IAAI,eAAe,EAAE,CAAA;QACxC,MAAM,MAAM,GAAG,mBAAmB,CAAC,WAAW,EAAE,SAAS,EAAE,EAAE,MAAM,EAAE,UAAU,CAAC,MAAM,EAAE,CAAC,CAAA;QACzF,MAAM,CAAC,MAAM,CAAC,MAAM,CAAC,CAAC,IAAI,CAAC,UAAU,CAAC,MAAM,CAAC,CAAA;IAC/C,CAAC,CAAC,CAAA;IAEF,EAAE,CAAC,gDAAgD,EAAE,GAAG,EAAE;QACxD,MAAM,GAAG,GAAG,EAAE,CAAC,KAAK,CAAC,WAAW,EAAE,SAAS,CAAC,CAAA;QAC5C,IAAI,CAAC;YACH,MAAM,MAAM,GAAG,mBAAmB,CAAC,WAAW,EAAE,SAAS,EAAE,EAAE,OAAO,EAAE,GAAG,EAAE,CAAC,CAAA;YAC5E,MAAM,CAAC,GAAG,CAAC,CAAC,oBAAoB,CAAC,GAAG,CAAC,CAAA;YACrC,MAAM,CAAC,MAAM,CAAC,MAAM,CAAC,CAAC,WAAW,EAAE,CAAA;YACnC,MAAM,CAAC,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,CAAC,IAAI,CAAC,KAAK,CAAC,CAAA;QAC5C,CAAC;gBAAS,CAAC;YACT,GAAG,CAAC,WAAW,EAAE,CAAA;QACnB,CAAC;IACH,CAAC,CAAC,CAAA;AACJ,CAAC,CAAC,CAAA"}
@@ -1,4 +1,4 @@
1
- import type { ClientAdapter, ClientHooks, StreamDescriptor, TypedStream } from './types.js';
1
+ import type { ClientAdapter, ClientHooks, StreamDescriptor, TypedStream, ProcedureCallDefaults, ProcedureCallOptions } from './types.js';
2
2
  /**
3
3
  * Wraps an AsyncIterable into a TypedStream.
4
4
  *
@@ -12,16 +12,25 @@ import type { ClientAdapter, ClientHooks, StreamDescriptor, TypedStream } from '
12
12
  * On error: `.result` rejects and the error is re-thrown from the async iterator.
13
13
  */
14
14
  export declare function createTypedStream<TYield, TReturn = void>(source: AsyncIterable<unknown>, streamMode: 'sse' | 'text'): TypedStream<TYield, TReturn>;
15
+ export interface ExecuteStreamConfig {
16
+ descriptor: StreamDescriptor;
17
+ basePath: string;
18
+ adapter: ClientAdapter;
19
+ hooks: ClientHooks;
20
+ defaults?: ProcedureCallDefaults;
21
+ options?: ProcedureCallOptions;
22
+ }
15
23
  /**
16
24
  * Executes a streaming procedure call through the adapter.
17
25
  *
18
26
  * Flow:
19
- * 1. Build AdapterRequest from descriptor
20
- * 2. Run onBeforeRequest hooks
21
- * 3. Call adapter.stream()
22
- * 4. On adapter error: run onError hooks, re-throw
23
- * 5. Run onAfterResponse immediately (before iteration), body is null
24
- * 6. If non-2xx: throw ClientRequestError
25
- * 7. Return createTypedStream(streamResponse.body, descriptor.streamMode)
27
+ * 1. Resolve base path and build AdapterRequest
28
+ * 2. Apply request options (headers, signal, timeout, meta) from defaults + per-call
29
+ * 3. Run onBeforeRequest hooks
30
+ * 4. Call adapter.stream()
31
+ * 5. On adapter error: run onError hooks, re-throw
32
+ * 6. Run onAfterResponse immediately (before iteration), body is null
33
+ * 7. If non-2xx: throw ClientRequestError
34
+ * 8. Return createTypedStream(streamResponse.body, descriptor.streamMode)
26
35
  */
27
- export declare function executeStream<TYield, TReturn = void>(descriptor: StreamDescriptor, basePath: string, adapter: ClientAdapter, globalHooks: ClientHooks, localHooks: ClientHooks | undefined): Promise<TypedStream<TYield, TReturn>>;
36
+ export declare function executeStream<TYield, TReturn = void>(config: ExecuteStreamConfig): Promise<TypedStream<TYield, TReturn>>;
@@ -1,5 +1,6 @@
1
1
  import { buildAdapterRequest } from './request-builder.js';
2
2
  import { runBeforeRequest, runAfterResponse, runOnError } from './hooks.js';
3
+ import { applyRequestOptions, resolveBasePath } from './resolve-options.js';
3
4
  import { ClientRequestError } from './errors.js';
4
5
  // ── createTypedStream ─────────────────────────────────────
5
6
  /**
@@ -65,33 +66,37 @@ export function createTypedStream(source, streamMode) {
65
66
  result: resultPromise,
66
67
  };
67
68
  }
68
- // ── executeStream ─────────────────────────────────────────
69
69
  /**
70
70
  * Executes a streaming procedure call through the adapter.
71
71
  *
72
72
  * Flow:
73
- * 1. Build AdapterRequest from descriptor
74
- * 2. Run onBeforeRequest hooks
75
- * 3. Call adapter.stream()
76
- * 4. On adapter error: run onError hooks, re-throw
77
- * 5. Run onAfterResponse immediately (before iteration), body is null
78
- * 6. If non-2xx: throw ClientRequestError
79
- * 7. Return createTypedStream(streamResponse.body, descriptor.streamMode)
73
+ * 1. Resolve base path and build AdapterRequest
74
+ * 2. Apply request options (headers, signal, timeout, meta) from defaults + per-call
75
+ * 3. Run onBeforeRequest hooks
76
+ * 4. Call adapter.stream()
77
+ * 5. On adapter error: run onError hooks, re-throw
78
+ * 6. Run onAfterResponse immediately (before iteration), body is null
79
+ * 7. If non-2xx: throw ClientRequestError
80
+ * 8. Return createTypedStream(streamResponse.body, descriptor.streamMode)
80
81
  */
81
- export async function executeStream(descriptor, basePath, adapter, globalHooks, localHooks) {
82
+ export async function executeStream(config) {
83
+ const { descriptor, basePath, adapter, hooks, defaults, options } = config;
82
84
  // 1. Build the initial request
83
- let request = buildAdapterRequest(descriptor, basePath);
84
- // 2. Run before-request hooks
85
- const beforeCtx = await runBeforeRequest({ procedureName: descriptor.name, scope: descriptor.scope, request }, globalHooks, localHooks);
85
+ const resolvedBasePath = resolveBasePath(defaults, options, basePath);
86
+ let request = buildAdapterRequest(descriptor, resolvedBasePath);
87
+ // 2. Apply request-level options (headers, signal, timeout, meta)
88
+ request = applyRequestOptions(request, defaults, options);
89
+ // 3. Run before-request hooks
90
+ const beforeCtx = await runBeforeRequest({ procedureName: descriptor.name, scope: descriptor.scope, request }, hooks, options);
86
91
  request = beforeCtx.request;
87
- // 3. Call the adapter
92
+ // 4. Call the adapter
88
93
  let streamResponse;
89
94
  try {
90
95
  streamResponse = await adapter.stream(request);
91
96
  }
92
97
  catch (err) {
93
- // 4. On adapter error: run error hooks, re-throw
94
- await runOnError({ procedureName: descriptor.name, scope: descriptor.scope, request, error: err }, globalHooks, localHooks);
98
+ // 5. On adapter error: run error hooks, re-throw
99
+ await runOnError({ procedureName: descriptor.name, scope: descriptor.scope, request, error: err }, hooks, options);
95
100
  throw err;
96
101
  }
97
102
  // Build an AdapterResponse shape for the hooks (body is null for streams at this point)
@@ -100,9 +105,9 @@ export async function executeStream(descriptor, basePath, adapter, globalHooks,
100
105
  headers: streamResponse.headers,
101
106
  body: null,
102
107
  };
103
- // 5. Run after-response hooks immediately (before iteration)
104
- await runAfterResponse({ procedureName: descriptor.name, scope: descriptor.scope, request, response: responseForHooks }, globalHooks, localHooks);
105
- // 6. Check status after hooks (hooks may mutate responseForHooks.status)
108
+ // 6. Run after-response hooks immediately (before iteration)
109
+ await runAfterResponse({ procedureName: descriptor.name, scope: descriptor.scope, request, response: responseForHooks }, hooks, options);
110
+ // 7. Check status after hooks (hooks may mutate responseForHooks.status)
106
111
  if (responseForHooks.status < 200 || responseForHooks.status >= 300) {
107
112
  throw new ClientRequestError({
108
113
  status: responseForHooks.status,
@@ -112,7 +117,7 @@ export async function executeStream(descriptor, basePath, adapter, globalHooks,
112
117
  scope: descriptor.scope,
113
118
  });
114
119
  }
115
- // 7. Return the typed stream
120
+ // 8. Return the typed stream
116
121
  return createTypedStream(streamResponse.body, descriptor.streamMode);
117
122
  }
118
123
  //# sourceMappingURL=stream.js.map
@@ -1 +1 @@
1
- {"version":3,"file":"stream.js","sourceRoot":"","sources":["../../src/client/stream.ts"],"names":[],"mappings":"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"}
1
+ {"version":3,"file":"stream.js","sourceRoot":"","sources":["../../src/client/stream.ts"],"names":[],"mappings":"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"}
@@ -32,6 +32,9 @@ function makeStreamAdapter(response, items) {
32
32
  })),
33
33
  };
34
34
  }
35
+ function run({ adapter, hooks = {}, defaults, options, descriptor = makeDescriptor(), basePath = 'https://api.example.com', }) {
36
+ return executeStream({ descriptor, basePath, adapter, hooks, defaults, options });
37
+ }
35
38
  // ── createTypedStream — SSE mode ──────────────────────────
36
39
  describe('createTypedStream — SSE mode', () => {
37
40
  it('yields data payloads for normal events', async () => {
@@ -41,9 +44,8 @@ describe('createTypedStream — SSE mode', () => {
41
44
  ];
42
45
  const stream = createTypedStream(makeAsyncIterable(sseItems), 'sse');
43
46
  const received = [];
44
- for await (const item of stream) {
47
+ for await (const item of stream)
45
48
  received.push(item);
46
- }
47
49
  expect(received).toEqual([{ count: 1 }, { count: 2 }]);
48
50
  });
49
51
  it('captures return event data in .result instead of yielding', async () => {
@@ -53,23 +55,15 @@ describe('createTypedStream — SSE mode', () => {
53
55
  ];
54
56
  const stream = createTypedStream(makeAsyncIterable(sseItems), 'sse');
55
57
  const yielded = [];
56
- for await (const item of stream) {
58
+ for await (const item of stream)
57
59
  yielded.push(item);
58
- }
59
- // Only the 'update' event is yielded
60
60
  expect(yielded).toEqual([{ count: 1 }]);
61
- // The 'return' event resolves .result
62
- const result = await stream.result;
63
- expect(result).toEqual({ total: 99 });
61
+ await expect(stream.result).resolves.toEqual({ total: 99 });
64
62
  });
65
63
  it('resolves .result with undefined when no return event', async () => {
66
- const sseItems = [
67
- { data: 'hello', event: 'message' },
68
- ];
69
- const stream = createTypedStream(makeAsyncIterable(sseItems), 'sse');
64
+ const stream = createTypedStream(makeAsyncIterable([{ data: 'hello', event: 'message' }]), 'sse');
70
65
  for await (const _ of stream) { /* drain */ }
71
- const result = await stream.result;
72
- expect(result).toBeUndefined();
66
+ await expect(stream.result).resolves.toBeUndefined();
73
67
  });
74
68
  it('rejects .result and re-throws on error', async () => {
75
69
  async function* errorIterable() {
@@ -77,23 +71,16 @@ describe('createTypedStream — SSE mode', () => {
77
71
  throw new Error('stream broke');
78
72
  }
79
73
  const stream = createTypedStream(errorIterable(), 'sse');
80
- // Consuming the stream should throw
81
74
  await expect(async () => {
82
75
  for await (const _ of stream) { /* drain */ }
83
76
  }).rejects.toThrow('stream broke');
84
- // .result should also reject
85
77
  await expect(stream.result).rejects.toThrow('stream broke');
86
78
  });
87
79
  it('handles SSE items without event field (defaults to yielding data)', async () => {
88
- const sseItems = [
89
- { data: 'a' },
90
- { data: 'b' },
91
- ];
92
- const stream = createTypedStream(makeAsyncIterable(sseItems), 'sse');
80
+ const stream = createTypedStream(makeAsyncIterable([{ data: 'a' }, { data: 'b' }]), 'sse');
93
81
  const yielded = [];
94
- for await (const item of stream) {
82
+ for await (const item of stream)
95
83
  yielded.push(item);
96
- }
97
84
  expect(yielded).toEqual(['a', 'b']);
98
85
  });
99
86
  });
@@ -103,16 +90,14 @@ describe('createTypedStream — text mode', () => {
103
90
  const chunks = ['chunk1', 'chunk2', 'chunk3'];
104
91
  const stream = createTypedStream(makeAsyncIterable(chunks), 'text');
105
92
  const received = [];
106
- for await (const chunk of stream) {
93
+ for await (const chunk of stream)
107
94
  received.push(chunk);
108
- }
109
95
  expect(received).toEqual(chunks);
110
96
  });
111
97
  it('.result resolves to void on normal completion', async () => {
112
98
  const stream = createTypedStream(makeAsyncIterable(['a', 'b']), 'text');
113
99
  for await (const _ of stream) { /* drain */ }
114
- const result = await stream.result;
115
- expect(result).toBeUndefined();
100
+ await expect(stream.result).resolves.toBeUndefined();
116
101
  });
117
102
  it('rejects .result and re-throws on error', async () => {
118
103
  async function* errorIterable() {
@@ -131,12 +116,11 @@ describe('executeStream', () => {
131
116
  it('calls adapter.stream and returns a TypedStream', async () => {
132
117
  const items = [{ data: 'hello', event: 'msg' }];
133
118
  const adapter = makeStreamAdapter({}, items);
134
- const stream = await executeStream(makeDescriptor(), 'https://api.example.com', adapter, {}, undefined);
119
+ const stream = await run({ adapter });
135
120
  expect(adapter.stream).toHaveBeenCalledOnce();
136
121
  const received = [];
137
- for await (const item of stream) {
122
+ for await (const item of stream)
138
123
  received.push(item);
139
- }
140
124
  expect(received).toEqual(['hello']);
141
125
  });
142
126
  it('runs onBeforeRequest before calling adapter', async () => {
@@ -148,15 +132,14 @@ describe('executeStream', () => {
148
132
  return { status: 200, headers: {}, body: makeAsyncIterable([]) };
149
133
  }),
150
134
  };
151
- const globalHooks = {
135
+ const hooks = {
152
136
  onBeforeRequest: (ctx) => ({
153
137
  ...ctx,
154
138
  request: { ...ctx.request, headers: { 'x-stream-auth': 'stream-token' } },
155
139
  }),
156
140
  };
157
- const stream = await executeStream(makeDescriptor(), 'https://api.example.com', adapter, globalHooks, undefined);
158
- // Drain
159
- for await (const _ of stream) { /* noop */ }
141
+ const stream = await run({ adapter, hooks });
142
+ for await (const _ of stream) { /* drain */ }
160
143
  expect(capturedHeaders[0]?.['x-stream-auth']).toBe('stream-token');
161
144
  });
162
145
  it('runs onAfterResponse immediately (before iteration)', async () => {
@@ -168,11 +151,10 @@ describe('executeStream', () => {
168
151
  return { status: 200, headers: {}, body: makeAsyncIterable([]) };
169
152
  }),
170
153
  };
171
- const globalHooks = {
154
+ const hooks = {
172
155
  onAfterResponse: () => { order.push('afterResponse'); },
173
156
  };
174
- await executeStream(makeDescriptor(), 'https://api.example.com', adapter, globalHooks, undefined);
175
- // After executeStream returns (before iteration), afterResponse should have fired
157
+ await run({ adapter, hooks });
176
158
  expect(order).toEqual(['adapter', 'afterResponse']);
177
159
  });
178
160
  it('throws ClientRequestError on non-2xx status', async () => {
@@ -184,7 +166,7 @@ describe('executeStream', () => {
184
166
  body: makeAsyncIterable([]),
185
167
  })),
186
168
  };
187
- await expect(executeStream(makeDescriptor(), 'https://api.example.com', adapter, {}, undefined)).rejects.toThrow(ClientRequestError);
169
+ await expect(run({ adapter })).rejects.toThrow(ClientRequestError);
188
170
  });
189
171
  it('runs onError on adapter failure and re-throws', async () => {
190
172
  const adapterError = new Error('stream connection failed');
@@ -193,10 +175,10 @@ describe('executeStream', () => {
193
175
  stream: vi.fn(async () => { throw adapterError; }),
194
176
  };
195
177
  const receivedErrors = [];
196
- const globalHooks = {
178
+ const hooks = {
197
179
  onError: (ctx) => { receivedErrors.push(ctx.error); },
198
180
  };
199
- await expect(executeStream(makeDescriptor(), 'https://api.example.com', adapter, globalHooks, undefined)).rejects.toThrow('stream connection failed');
181
+ await expect(run({ adapter, hooks })).rejects.toThrow('stream connection failed');
200
182
  expect(receivedErrors[0]).toBe(adapterError);
201
183
  });
202
184
  it('returns TypedStream with working .result for SSE return event', async () => {
@@ -205,24 +187,98 @@ describe('executeStream', () => {
205
187
  { data: { final: true }, event: 'return' },
206
188
  ];
207
189
  const adapter = makeStreamAdapter({}, sseItems);
208
- const stream = await executeStream(makeDescriptor({ streamMode: 'sse' }), 'https://api.example.com', adapter, {}, undefined);
190
+ const stream = await run({
191
+ adapter,
192
+ descriptor: makeDescriptor({ streamMode: 'sse' }),
193
+ });
209
194
  const yielded = [];
210
- for await (const item of stream) {
195
+ for await (const item of stream)
211
196
  yielded.push(item);
212
- }
213
197
  expect(yielded).toEqual([{ n: 1 }]);
214
198
  await expect(stream.result).resolves.toEqual({ final: true });
215
199
  });
216
200
  it('returns TypedStream for text mode', async () => {
217
201
  const chunks = ['line1', 'line2'];
218
202
  const adapter = makeStreamAdapter({}, chunks);
219
- const stream = await executeStream(makeDescriptor({ streamMode: 'text' }), 'https://api.example.com', adapter, {}, undefined);
203
+ const stream = await run({
204
+ adapter,
205
+ descriptor: makeDescriptor({ streamMode: 'text' }),
206
+ });
220
207
  const received = [];
221
- for await (const chunk of stream) {
208
+ for await (const chunk of stream)
222
209
  received.push(chunk);
223
- }
224
210
  expect(received).toEqual(chunks);
225
211
  await expect(stream.result).resolves.toBeUndefined();
226
212
  });
213
+ // ── Per-call options ──
214
+ it('per-call timeout attaches a signal via AbortSignal.timeout', async () => {
215
+ const spy = vi.spyOn(AbortSignal, 'timeout');
216
+ try {
217
+ let observedSignal;
218
+ const adapter = {
219
+ request: vi.fn(async () => { throw new Error('not expected'); }),
220
+ stream: vi.fn(async (req) => {
221
+ observedSignal = req.signal;
222
+ return { status: 200, headers: {}, body: makeAsyncIterable([]) };
223
+ }),
224
+ };
225
+ await run({ adapter, options: { timeout: 5000 } });
226
+ expect(spy).toHaveBeenCalledWith(5000);
227
+ expect(observedSignal).toBeDefined();
228
+ }
229
+ finally {
230
+ spy.mockRestore();
231
+ }
232
+ });
233
+ it('adapter receives a signal that reflects abort when the caller cancels', async () => {
234
+ const controller = new AbortController();
235
+ const adapter = {
236
+ request: vi.fn(async () => { throw new Error('not expected'); }),
237
+ stream: vi.fn(async (req) => {
238
+ return new Promise((_resolve, reject) => {
239
+ const abort = () => reject(new Error('aborted'));
240
+ if (req.signal?.aborted)
241
+ abort();
242
+ else
243
+ req.signal?.addEventListener('abort', abort, { once: true });
244
+ });
245
+ }),
246
+ };
247
+ const promise = run({ adapter, options: { signal: controller.signal } });
248
+ // Let executeStream reach the adapter before aborting
249
+ await Promise.resolve();
250
+ controller.abort();
251
+ await expect(promise).rejects.toThrow('aborted');
252
+ });
253
+ it('per-call basePath overrides base path for streams', async () => {
254
+ const capturedUrls = [];
255
+ const adapter = {
256
+ request: vi.fn(async () => { throw new Error('not expected'); }),
257
+ stream: vi.fn(async (req) => {
258
+ capturedUrls.push(req.url);
259
+ return { status: 200, headers: {}, body: makeAsyncIterable([]) };
260
+ }),
261
+ };
262
+ const stream = await run({
263
+ adapter,
264
+ descriptor: makeDescriptor({ path: '/tail' }),
265
+ basePath: 'https://default.example.com',
266
+ options: { basePath: 'https://override.example.com' },
267
+ });
268
+ for await (const _ of stream) { /* drain */ }
269
+ expect(capturedUrls[0]).toBe('https://override.example.com/tail');
270
+ });
271
+ it('per-call meta is forwarded to the adapter', async () => {
272
+ let observedMeta;
273
+ const adapter = {
274
+ request: vi.fn(async () => { throw new Error('not expected'); }),
275
+ stream: vi.fn(async (req) => {
276
+ observedMeta = req.meta;
277
+ return { status: 200, headers: {}, body: makeAsyncIterable([]) };
278
+ }),
279
+ };
280
+ await run({ adapter, options: { meta: { traceId: 'stream-trace' } } });
281
+ expect(observedMeta).toEqual({ traceId: 'stream-trace' });
282
+ });
227
283
  });
228
284
  //# sourceMappingURL=stream.test.js.map