ts-procedures 5.10.0 → 5.12.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 (252) hide show
  1. package/agent_config/bin/postinstall.mjs +3 -3
  2. package/agent_config/bin/setup.mjs +22 -11
  3. package/agent_config/claude-code/agents/ts-procedures-architect.md +2 -2
  4. package/agent_config/claude-code/skills/{guide → ts-procedures}/SKILL.md +1 -1
  5. package/agent_config/claude-code/skills/{guide → ts-procedures}/api-reference.md +11 -8
  6. package/agent_config/claude-code/skills/{guide → ts-procedures}/patterns.md +8 -2
  7. package/agent_config/claude-code/skills/{review → ts-procedures-review}/SKILL.md +3 -3
  8. package/agent_config/claude-code/skills/{scaffold → ts-procedures-scaffold}/SKILL.md +2 -2
  9. package/agent_config/claude-code/skills/{scaffold → ts-procedures-scaffold}/templates/client.md +4 -4
  10. package/agent_config/copilot/copilot-instructions.md +6 -5
  11. package/agent_config/cursor/cursorrules +6 -5
  12. package/agent_config/lib/install-claude.mjs +35 -87
  13. package/build/codegen/e2e.test.js +21 -14
  14. package/build/codegen/e2e.test.js.map +1 -1
  15. package/build/codegen/emit-index.d.ts +7 -3
  16. package/build/codegen/emit-index.js +33 -20
  17. package/build/codegen/emit-index.js.map +1 -1
  18. package/build/codegen/emit-index.test.js +69 -45
  19. package/build/codegen/emit-index.test.js.map +1 -1
  20. package/build/codegen/pipeline.js +4 -5
  21. package/build/codegen/pipeline.js.map +1 -1
  22. package/build/codegen/pipeline.test.js +4 -4
  23. package/build/codegen/pipeline.test.js.map +1 -1
  24. package/build/src/client/call.d.ts +14 -0
  25. package/build/src/client/call.js +47 -0
  26. package/build/src/client/call.js.map +1 -0
  27. package/build/src/client/call.test.d.ts +1 -0
  28. package/build/src/client/call.test.js +124 -0
  29. package/build/src/client/call.test.js.map +1 -0
  30. package/build/src/client/errors.d.ts +25 -0
  31. package/build/src/client/errors.js +33 -0
  32. package/build/src/client/errors.js.map +1 -0
  33. package/build/src/client/errors.test.d.ts +1 -0
  34. package/build/src/client/errors.test.js +41 -0
  35. package/build/src/client/errors.test.js.map +1 -0
  36. package/build/src/client/fetch-adapter.d.ts +12 -0
  37. package/build/src/client/fetch-adapter.js +156 -0
  38. package/build/src/client/fetch-adapter.js.map +1 -0
  39. package/build/src/client/fetch-adapter.test.d.ts +1 -0
  40. package/build/src/client/fetch-adapter.test.js +271 -0
  41. package/build/src/client/fetch-adapter.test.js.map +1 -0
  42. package/build/src/client/hooks.d.ts +17 -0
  43. package/build/src/client/hooks.js +40 -0
  44. package/build/src/client/hooks.js.map +1 -0
  45. package/build/src/client/hooks.test.d.ts +1 -0
  46. package/build/src/client/hooks.test.js +163 -0
  47. package/build/src/client/hooks.test.js.map +1 -0
  48. package/build/src/client/index.d.ts +22 -0
  49. package/build/src/client/index.js +67 -0
  50. package/build/src/client/index.js.map +1 -0
  51. package/build/src/client/index.test.d.ts +1 -0
  52. package/build/src/client/index.test.js +231 -0
  53. package/build/src/client/index.test.js.map +1 -0
  54. package/build/src/client/request-builder.d.ts +13 -0
  55. package/build/src/client/request-builder.js +53 -0
  56. package/build/src/client/request-builder.js.map +1 -0
  57. package/build/src/client/request-builder.test.d.ts +1 -0
  58. package/build/src/client/request-builder.test.js +160 -0
  59. package/build/src/client/request-builder.test.js.map +1 -0
  60. package/build/src/client/stream.d.ts +27 -0
  61. package/build/src/client/stream.js +118 -0
  62. package/build/src/client/stream.js.map +1 -0
  63. package/build/src/client/stream.test.d.ts +1 -0
  64. package/build/src/client/stream.test.js +228 -0
  65. package/build/src/client/stream.test.js.map +1 -0
  66. package/build/src/client/types.d.ts +78 -0
  67. package/build/src/client/types.js +3 -0
  68. package/build/src/client/types.js.map +1 -0
  69. package/build/src/codegen/bin/cli.d.ts +45 -0
  70. package/build/src/codegen/bin/cli.js +246 -0
  71. package/build/src/codegen/bin/cli.js.map +1 -0
  72. package/build/src/codegen/bin/cli.test.d.ts +1 -0
  73. package/build/src/codegen/bin/cli.test.js +220 -0
  74. package/build/src/codegen/bin/cli.test.js.map +1 -0
  75. package/build/src/codegen/constants.d.ts +1 -0
  76. package/build/src/codegen/constants.js +2 -0
  77. package/build/src/codegen/constants.js.map +1 -0
  78. package/build/src/codegen/e2e.test.d.ts +1 -0
  79. package/build/src/codegen/e2e.test.js +464 -0
  80. package/build/src/codegen/e2e.test.js.map +1 -0
  81. package/build/src/codegen/emit-client-runtime.d.ts +9 -0
  82. package/build/src/codegen/emit-client-runtime.js +99 -0
  83. package/build/src/codegen/emit-client-runtime.js.map +1 -0
  84. package/build/src/codegen/emit-client-runtime.test.d.ts +1 -0
  85. package/build/src/codegen/emit-client-runtime.test.js +78 -0
  86. package/build/src/codegen/emit-client-runtime.test.js.map +1 -0
  87. package/build/src/codegen/emit-client-types.d.ts +8 -0
  88. package/build/src/codegen/emit-client-types.js +25 -0
  89. package/build/src/codegen/emit-client-types.js.map +1 -0
  90. package/build/src/codegen/emit-client-types.test.d.ts +1 -0
  91. package/build/src/codegen/emit-client-types.test.js +33 -0
  92. package/build/src/codegen/emit-client-types.test.js.map +1 -0
  93. package/build/src/codegen/emit-errors.d.ts +19 -0
  94. package/build/src/codegen/emit-errors.js +59 -0
  95. package/build/src/codegen/emit-errors.js.map +1 -0
  96. package/build/src/codegen/emit-errors.test.d.ts +1 -0
  97. package/build/src/codegen/emit-errors.test.js +175 -0
  98. package/build/src/codegen/emit-errors.test.js.map +1 -0
  99. package/build/src/codegen/emit-index.d.ts +12 -0
  100. package/build/src/codegen/emit-index.js +41 -0
  101. package/build/src/codegen/emit-index.js.map +1 -0
  102. package/build/src/codegen/emit-index.test.d.ts +1 -0
  103. package/build/src/codegen/emit-index.test.js +106 -0
  104. package/build/src/codegen/emit-index.test.js.map +1 -0
  105. package/build/src/codegen/emit-scope.d.ts +15 -0
  106. package/build/src/codegen/emit-scope.js +299 -0
  107. package/build/src/codegen/emit-scope.js.map +1 -0
  108. package/build/src/codegen/emit-scope.test.d.ts +1 -0
  109. package/build/src/codegen/emit-scope.test.js +559 -0
  110. package/build/src/codegen/emit-scope.test.js.map +1 -0
  111. package/build/src/codegen/emit-types.d.ts +43 -0
  112. package/build/src/codegen/emit-types.js +111 -0
  113. package/build/src/codegen/emit-types.js.map +1 -0
  114. package/build/src/codegen/emit-types.test.d.ts +1 -0
  115. package/build/src/codegen/emit-types.test.js +184 -0
  116. package/build/src/codegen/emit-types.test.js.map +1 -0
  117. package/build/src/codegen/group-routes.d.ts +23 -0
  118. package/build/src/codegen/group-routes.js +46 -0
  119. package/build/src/codegen/group-routes.js.map +1 -0
  120. package/build/src/codegen/group-routes.test.d.ts +1 -0
  121. package/build/src/codegen/group-routes.test.js +131 -0
  122. package/build/src/codegen/group-routes.test.js.map +1 -0
  123. package/build/src/codegen/index.d.ts +15 -0
  124. package/build/src/codegen/index.js +16 -0
  125. package/build/src/codegen/index.js.map +1 -0
  126. package/build/src/codegen/naming.d.ts +7 -0
  127. package/build/src/codegen/naming.js +21 -0
  128. package/build/src/codegen/naming.js.map +1 -0
  129. package/build/src/codegen/naming.test.d.ts +1 -0
  130. package/build/src/codegen/naming.test.js +40 -0
  131. package/build/src/codegen/naming.test.js.map +1 -0
  132. package/build/src/codegen/pipeline.d.ts +17 -0
  133. package/build/src/codegen/pipeline.js +78 -0
  134. package/build/src/codegen/pipeline.js.map +1 -0
  135. package/build/src/codegen/pipeline.test.d.ts +1 -0
  136. package/build/src/codegen/pipeline.test.js +269 -0
  137. package/build/src/codegen/pipeline.test.js.map +1 -0
  138. package/build/src/codegen/resolve-envelope.d.ts +7 -0
  139. package/build/src/codegen/resolve-envelope.js +46 -0
  140. package/build/src/codegen/resolve-envelope.js.map +1 -0
  141. package/build/src/codegen/resolve-envelope.test.d.ts +1 -0
  142. package/build/src/codegen/resolve-envelope.test.js +69 -0
  143. package/build/src/codegen/resolve-envelope.test.js.map +1 -0
  144. package/build/src/errors.d.ts +33 -0
  145. package/build/src/errors.js +91 -0
  146. package/build/src/errors.js.map +1 -0
  147. package/build/src/errors.test.d.ts +1 -0
  148. package/build/src/errors.test.js +122 -0
  149. package/build/src/errors.test.js.map +1 -0
  150. package/build/src/exports.d.ts +7 -0
  151. package/build/src/exports.js +8 -0
  152. package/build/src/exports.js.map +1 -0
  153. package/build/src/implementations/http/doc-registry.d.ts +12 -0
  154. package/build/src/implementations/http/doc-registry.js +114 -0
  155. package/build/src/implementations/http/doc-registry.js.map +1 -0
  156. package/build/src/implementations/http/doc-registry.test.d.ts +1 -0
  157. package/build/src/implementations/http/doc-registry.test.js +347 -0
  158. package/build/src/implementations/http/doc-registry.test.js.map +1 -0
  159. package/build/src/implementations/http/express-rpc/index.d.ts +94 -0
  160. package/build/src/implementations/http/express-rpc/index.js +185 -0
  161. package/build/src/implementations/http/express-rpc/index.js.map +1 -0
  162. package/build/src/implementations/http/express-rpc/index.test.d.ts +1 -0
  163. package/build/src/implementations/http/express-rpc/index.test.js +684 -0
  164. package/build/src/implementations/http/express-rpc/index.test.js.map +1 -0
  165. package/build/src/implementations/http/express-rpc/types.d.ts +11 -0
  166. package/build/src/implementations/http/express-rpc/types.js +2 -0
  167. package/build/src/implementations/http/express-rpc/types.js.map +1 -0
  168. package/build/src/implementations/http/hono-api/index.d.ts +102 -0
  169. package/build/src/implementations/http/hono-api/index.js +341 -0
  170. package/build/src/implementations/http/hono-api/index.js.map +1 -0
  171. package/build/src/implementations/http/hono-api/index.test.d.ts +1 -0
  172. package/build/src/implementations/http/hono-api/index.test.js +992 -0
  173. package/build/src/implementations/http/hono-api/index.test.js.map +1 -0
  174. package/build/src/implementations/http/hono-api/types.d.ts +13 -0
  175. package/build/src/implementations/http/hono-api/types.js +2 -0
  176. package/build/src/implementations/http/hono-api/types.js.map +1 -0
  177. package/build/src/implementations/http/hono-rpc/index.d.ts +92 -0
  178. package/build/src/implementations/http/hono-rpc/index.js +161 -0
  179. package/build/src/implementations/http/hono-rpc/index.js.map +1 -0
  180. package/build/src/implementations/http/hono-rpc/index.test.d.ts +1 -0
  181. package/build/src/implementations/http/hono-rpc/index.test.js +803 -0
  182. package/build/src/implementations/http/hono-rpc/index.test.js.map +1 -0
  183. package/build/src/implementations/http/hono-rpc/types.d.ts +11 -0
  184. package/build/src/implementations/http/hono-rpc/types.js +2 -0
  185. package/build/src/implementations/http/hono-rpc/types.js.map +1 -0
  186. package/build/src/implementations/http/hono-stream/index.d.ts +120 -0
  187. package/build/src/implementations/http/hono-stream/index.js +309 -0
  188. package/build/src/implementations/http/hono-stream/index.js.map +1 -0
  189. package/build/src/implementations/http/hono-stream/index.test.d.ts +1 -0
  190. package/build/src/implementations/http/hono-stream/index.test.js +1356 -0
  191. package/build/src/implementations/http/hono-stream/index.test.js.map +1 -0
  192. package/build/src/implementations/http/hono-stream/types.d.ts +15 -0
  193. package/build/src/implementations/http/hono-stream/types.js +2 -0
  194. package/build/src/implementations/http/hono-stream/types.js.map +1 -0
  195. package/build/src/implementations/types.d.ts +142 -0
  196. package/build/src/implementations/types.js +2 -0
  197. package/build/src/implementations/types.js.map +1 -0
  198. package/build/src/index.d.ts +165 -0
  199. package/build/src/index.js +253 -0
  200. package/build/src/index.js.map +1 -0
  201. package/build/src/index.test.d.ts +1 -0
  202. package/build/src/index.test.js +890 -0
  203. package/build/src/index.test.js.map +1 -0
  204. package/build/src/schema/compute-schema.d.ts +35 -0
  205. package/build/src/schema/compute-schema.js +41 -0
  206. package/build/src/schema/compute-schema.js.map +1 -0
  207. package/build/src/schema/compute-schema.test.d.ts +1 -0
  208. package/build/src/schema/compute-schema.test.js +107 -0
  209. package/build/src/schema/compute-schema.test.js.map +1 -0
  210. package/build/src/schema/extract-json-schema.d.ts +2 -0
  211. package/build/src/schema/extract-json-schema.js +12 -0
  212. package/build/src/schema/extract-json-schema.js.map +1 -0
  213. package/build/src/schema/extract-json-schema.test.d.ts +1 -0
  214. package/build/src/schema/extract-json-schema.test.js +23 -0
  215. package/build/src/schema/extract-json-schema.test.js.map +1 -0
  216. package/build/src/schema/parser.d.ts +28 -0
  217. package/build/src/schema/parser.js +170 -0
  218. package/build/src/schema/parser.js.map +1 -0
  219. package/build/src/schema/parser.test.d.ts +1 -0
  220. package/build/src/schema/parser.test.js +120 -0
  221. package/build/src/schema/parser.test.js.map +1 -0
  222. package/build/src/schema/resolve-schema-lib.d.ts +12 -0
  223. package/build/src/schema/resolve-schema-lib.js +11 -0
  224. package/build/src/schema/resolve-schema-lib.js.map +1 -0
  225. package/build/src/schema/resolve-schema-lib.test.d.ts +1 -0
  226. package/build/src/schema/resolve-schema-lib.test.js +17 -0
  227. package/build/src/schema/resolve-schema-lib.test.js.map +1 -0
  228. package/build/src/schema/types.d.ts +8 -0
  229. package/build/src/schema/types.js +2 -0
  230. package/build/src/schema/types.js.map +1 -0
  231. package/build/src/stack-utils.d.ts +25 -0
  232. package/build/src/stack-utils.js +95 -0
  233. package/build/src/stack-utils.js.map +1 -0
  234. package/build/src/stack-utils.test.d.ts +1 -0
  235. package/build/src/stack-utils.test.js +80 -0
  236. package/build/src/stack-utils.test.js.map +1 -0
  237. package/docs/ai-agent-setup.md +7 -6
  238. package/docs/client-and-codegen.md +9 -6
  239. package/package.json +1 -1
  240. package/src/codegen/e2e.test.ts +23 -14
  241. package/src/codegen/emit-index.test.ts +72 -45
  242. package/src/codegen/emit-index.ts +43 -20
  243. package/src/codegen/pipeline.test.ts +4 -4
  244. package/src/codegen/pipeline.ts +4 -5
  245. /package/agent_config/claude-code/skills/{guide → ts-procedures}/anti-patterns.md +0 -0
  246. /package/agent_config/claude-code/skills/{review → ts-procedures-review}/checklist.md +0 -0
  247. /package/agent_config/claude-code/skills/{scaffold → ts-procedures-scaffold}/templates/express-rpc.md +0 -0
  248. /package/agent_config/claude-code/skills/{scaffold → ts-procedures-scaffold}/templates/hono-api.md +0 -0
  249. /package/agent_config/claude-code/skills/{scaffold → ts-procedures-scaffold}/templates/hono-rpc.md +0 -0
  250. /package/agent_config/claude-code/skills/{scaffold → ts-procedures-scaffold}/templates/hono-stream.md +0 -0
  251. /package/agent_config/claude-code/skills/{scaffold → ts-procedures-scaffold}/templates/procedure.md +0 -0
  252. /package/agent_config/claude-code/skills/{scaffold → ts-procedures-scaffold}/templates/stream-procedure.md +0 -0
@@ -0,0 +1,271 @@
1
+ import { describe, it, expect, vi, beforeEach, afterEach } from 'vitest';
2
+ import { createFetchAdapter } from './fetch-adapter.js';
3
+ // ── helpers ───────────────────────────────────────────────
4
+ function mockSSEResponse(sseText) {
5
+ const encoder = new TextEncoder();
6
+ const stream = new ReadableStream({
7
+ start(controller) {
8
+ controller.enqueue(encoder.encode(sseText));
9
+ controller.close();
10
+ },
11
+ });
12
+ return new Response(stream, {
13
+ status: 200,
14
+ headers: { 'content-type': 'text/event-stream' },
15
+ });
16
+ }
17
+ function mockSSEResponseChunked(chunks) {
18
+ const encoder = new TextEncoder();
19
+ const stream = new ReadableStream({
20
+ start(controller) {
21
+ for (const chunk of chunks) {
22
+ controller.enqueue(encoder.encode(chunk));
23
+ }
24
+ controller.close();
25
+ },
26
+ });
27
+ return new Response(stream, {
28
+ status: 200,
29
+ headers: { 'content-type': 'text/event-stream' },
30
+ });
31
+ }
32
+ async function collectStream(stream) {
33
+ const items = [];
34
+ for await (const item of stream) {
35
+ items.push(item);
36
+ }
37
+ return items;
38
+ }
39
+ // ── request() tests ───────────────────────────────────────
40
+ describe('createFetchAdapter — request()', () => {
41
+ beforeEach(() => {
42
+ vi.stubGlobal('fetch', vi.fn());
43
+ });
44
+ afterEach(() => {
45
+ vi.unstubAllGlobals();
46
+ });
47
+ it('makes fetch call with correct URL, method, body', async () => {
48
+ const mockFetch = vi.mocked(globalThis.fetch);
49
+ mockFetch.mockResolvedValueOnce(new Response(JSON.stringify({ id: 1 }), { status: 200 }));
50
+ const adapter = createFetchAdapter();
51
+ await adapter.request({
52
+ url: 'https://api.example.com/users',
53
+ method: 'POST',
54
+ body: { name: 'Alice' },
55
+ });
56
+ expect(mockFetch).toHaveBeenCalledOnce();
57
+ const [url, init] = mockFetch.mock.calls[0];
58
+ expect(url).toBe('https://api.example.com/users');
59
+ expect(init.method).toBe('POST');
60
+ expect(init.body).toBe(JSON.stringify({ name: 'Alice' }));
61
+ });
62
+ it('merges config headers with request headers (request wins)', async () => {
63
+ const mockFetch = vi.mocked(globalThis.fetch);
64
+ mockFetch.mockResolvedValueOnce(new Response(JSON.stringify({}), { status: 200 }));
65
+ const adapter = createFetchAdapter({
66
+ headers: {
67
+ 'x-api-key': 'default-key',
68
+ 'x-source': 'config',
69
+ },
70
+ });
71
+ await adapter.request({
72
+ url: 'https://api.example.com/data',
73
+ method: 'GET',
74
+ headers: {
75
+ 'x-api-key': 'override-key', // should win
76
+ 'x-request-id': 'abc123',
77
+ },
78
+ });
79
+ const [, init] = mockFetch.mock.calls[0];
80
+ const headers = init.headers;
81
+ expect(headers['x-api-key']).toBe('override-key');
82
+ expect(headers['x-source']).toBe('config');
83
+ expect(headers['x-request-id']).toBe('abc123');
84
+ });
85
+ it('parses JSON response body', async () => {
86
+ const mockFetch = vi.mocked(globalThis.fetch);
87
+ mockFetch.mockResolvedValueOnce(new Response(JSON.stringify({ result: 'ok' }), { status: 200 }));
88
+ const adapter = createFetchAdapter();
89
+ const response = await adapter.request({
90
+ url: 'https://api.example.com/ping',
91
+ method: 'GET',
92
+ });
93
+ expect(response.status).toBe(200);
94
+ expect(response.body).toEqual({ result: 'ok' });
95
+ });
96
+ it('handles empty/non-JSON response body gracefully (e.g. 204 No Content)', async () => {
97
+ const mockFetch = vi.mocked(globalThis.fetch);
98
+ mockFetch.mockResolvedValueOnce(new Response(null, { status: 204 }));
99
+ const adapter = createFetchAdapter();
100
+ const response = await adapter.request({
101
+ url: 'https://api.example.com/delete',
102
+ method: 'DELETE',
103
+ });
104
+ expect(response.status).toBe(204);
105
+ // body should be null (or empty string) — not throw
106
+ expect(response.body === null || response.body === '').toBe(true);
107
+ });
108
+ it('passes signal to fetch', async () => {
109
+ const mockFetch = vi.mocked(globalThis.fetch);
110
+ mockFetch.mockResolvedValueOnce(new Response(JSON.stringify({}), { status: 200 }));
111
+ const controller = new AbortController();
112
+ const adapter = createFetchAdapter();
113
+ await adapter.request({
114
+ url: 'https://api.example.com/slow',
115
+ method: 'GET',
116
+ signal: controller.signal,
117
+ });
118
+ const [, init] = mockFetch.mock.calls[0];
119
+ expect(init.signal).toBe(controller.signal);
120
+ });
121
+ it('returns response headers as Record<string, string>', async () => {
122
+ const mockFetch = vi.mocked(globalThis.fetch);
123
+ mockFetch.mockResolvedValueOnce(new Response(JSON.stringify({}), {
124
+ status: 200,
125
+ headers: { 'content-type': 'application/json', 'x-request-id': 'xyz' },
126
+ }));
127
+ const adapter = createFetchAdapter();
128
+ const response = await adapter.request({
129
+ url: 'https://api.example.com/data',
130
+ method: 'GET',
131
+ });
132
+ expect(response.headers['content-type']).toBe('application/json');
133
+ expect(response.headers['x-request-id']).toBe('xyz');
134
+ });
135
+ it('sends no body when body is undefined', async () => {
136
+ const mockFetch = vi.mocked(globalThis.fetch);
137
+ mockFetch.mockResolvedValueOnce(new Response(JSON.stringify({}), { status: 200 }));
138
+ const adapter = createFetchAdapter();
139
+ await adapter.request({
140
+ url: 'https://api.example.com/items',
141
+ method: 'GET',
142
+ });
143
+ const [, init] = mockFetch.mock.calls[0];
144
+ expect(init.body).toBeUndefined();
145
+ });
146
+ });
147
+ // ── stream() tests ────────────────────────────────────────
148
+ describe('createFetchAdapter — stream()', () => {
149
+ beforeEach(() => {
150
+ vi.stubGlobal('fetch', vi.fn());
151
+ });
152
+ afterEach(() => {
153
+ vi.unstubAllGlobals();
154
+ });
155
+ it('parses SSE events from stream', async () => {
156
+ const mockFetch = vi.mocked(globalThis.fetch);
157
+ const sseText = 'event: message\ndata: {"count":1}\nid: 0\n\nevent: message\ndata: {"count":2}\nid: 1\n\n';
158
+ mockFetch.mockResolvedValueOnce(mockSSEResponse(sseText));
159
+ const adapter = createFetchAdapter();
160
+ const response = await adapter.stream({
161
+ url: 'https://api.example.com/stream',
162
+ method: 'GET',
163
+ });
164
+ expect(response.status).toBe(200);
165
+ const items = await collectStream(response.body);
166
+ expect(items).toEqual([
167
+ { data: { count: 1 }, event: 'message', id: '0' },
168
+ { data: { count: 2 }, event: 'message', id: '1' },
169
+ ]);
170
+ });
171
+ it('handles multi-line data fields (multiple data: lines joined with newline)', async () => {
172
+ const mockFetch = vi.mocked(globalThis.fetch);
173
+ // Multi-line data: per SSE spec, multiple data: lines are joined with \n
174
+ const sseText = 'event: multi\ndata: {"line":\ndata: "hello"}\n\n';
175
+ mockFetch.mockResolvedValueOnce(mockSSEResponse(sseText));
176
+ const adapter = createFetchAdapter();
177
+ const response = await adapter.stream({
178
+ url: 'https://api.example.com/stream',
179
+ method: 'GET',
180
+ });
181
+ const items = await collectStream(response.body);
182
+ expect(items).toHaveLength(1);
183
+ const item = items[0];
184
+ expect(item.event).toBe('multi');
185
+ // data is parsed from joined lines: '{"line":\n"hello"}'
186
+ expect(item.data).toEqual({ line: 'hello' });
187
+ });
188
+ it('handles chunked SSE data (message split across multiple chunks)', async () => {
189
+ const mockFetch = vi.mocked(globalThis.fetch);
190
+ // Split the SSE message across 3 chunks
191
+ const chunks = [
192
+ 'event: tick\nda',
193
+ 'ta: {"n":42}\n',
194
+ '\n',
195
+ ];
196
+ mockFetch.mockResolvedValueOnce(mockSSEResponseChunked(chunks));
197
+ const adapter = createFetchAdapter();
198
+ const response = await adapter.stream({
199
+ url: 'https://api.example.com/stream',
200
+ method: 'GET',
201
+ });
202
+ const items = await collectStream(response.body);
203
+ expect(items).toEqual([{ data: { n: 42 }, event: 'tick', id: undefined }]);
204
+ });
205
+ it('yields parsed objects with event and id', async () => {
206
+ const mockFetch = vi.mocked(globalThis.fetch);
207
+ const sseText = 'event: update\ndata: {"value":7}\nid: evt-99\n\n';
208
+ mockFetch.mockResolvedValueOnce(mockSSEResponse(sseText));
209
+ const adapter = createFetchAdapter();
210
+ const response = await adapter.stream({
211
+ url: 'https://api.example.com/stream',
212
+ method: 'GET',
213
+ });
214
+ const items = await collectStream(response.body);
215
+ expect(items).toEqual([{ data: { value: 7 }, event: 'update', id: 'evt-99' }]);
216
+ });
217
+ it('handles event: return correctly (just another SSE event)', async () => {
218
+ const mockFetch = vi.mocked(globalThis.fetch);
219
+ const sseText = 'event: message\ndata: {"n":1}\n\nevent: return\ndata: {"total":10}\n\n';
220
+ mockFetch.mockResolvedValueOnce(mockSSEResponse(sseText));
221
+ const adapter = createFetchAdapter();
222
+ const response = await adapter.stream({
223
+ url: 'https://api.example.com/stream',
224
+ method: 'GET',
225
+ });
226
+ // The adapter yields all SSE events as-is — createTypedStream handles 'return' semantics
227
+ const items = await collectStream(response.body);
228
+ expect(items).toEqual([
229
+ { data: { n: 1 }, event: 'message', id: undefined },
230
+ { data: { total: 10 }, event: 'return', id: undefined },
231
+ ]);
232
+ });
233
+ it('returns response headers from stream response', async () => {
234
+ const mockFetch = vi.mocked(globalThis.fetch);
235
+ mockFetch.mockResolvedValueOnce(mockSSEResponse('event: ping\ndata: {}\n\n'));
236
+ const adapter = createFetchAdapter();
237
+ const response = await adapter.stream({
238
+ url: 'https://api.example.com/stream',
239
+ method: 'GET',
240
+ });
241
+ expect(response.headers['content-type']).toContain('text/event-stream');
242
+ });
243
+ it('passes signal to fetch for streams', async () => {
244
+ const mockFetch = vi.mocked(globalThis.fetch);
245
+ mockFetch.mockResolvedValueOnce(mockSSEResponse('event: ping\ndata: {}\n\n'));
246
+ const controller = new AbortController();
247
+ const adapter = createFetchAdapter();
248
+ await adapter.stream({
249
+ url: 'https://api.example.com/stream',
250
+ method: 'GET',
251
+ signal: controller.signal,
252
+ });
253
+ const [, init] = mockFetch.mock.calls[0];
254
+ expect(init.signal).toBe(controller.signal);
255
+ });
256
+ it('handles SSE events without data field gracefully (skips them)', async () => {
257
+ const mockFetch = vi.mocked(globalThis.fetch);
258
+ // Comment-only message (no data field) — should be skipped
259
+ const sseText = ': keep-alive\n\nevent: message\ndata: {"ok":true}\n\n';
260
+ mockFetch.mockResolvedValueOnce(mockSSEResponse(sseText));
261
+ const adapter = createFetchAdapter();
262
+ const response = await adapter.stream({
263
+ url: 'https://api.example.com/stream',
264
+ method: 'GET',
265
+ });
266
+ const items = await collectStream(response.body);
267
+ // Only the message with data is yielded; comment-only block is skipped
268
+ expect(items).toEqual([{ data: { ok: true }, event: 'message', id: undefined }]);
269
+ });
270
+ });
271
+ //# sourceMappingURL=fetch-adapter.test.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"fetch-adapter.test.js","sourceRoot":"","sources":["../../../src/client/fetch-adapter.test.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,17 @@
1
+ import type { BeforeRequestContext, AfterResponseContext, ErrorContext, ClientHooks } from './types.js';
2
+ /**
3
+ * Runs `onBeforeRequest` hooks: global first, then per-procedure.
4
+ * Each hook receives the (possibly mutated) context from the previous hook.
5
+ * Returns the final context.
6
+ */
7
+ export declare function runBeforeRequest(ctx: BeforeRequestContext, globalHooks: ClientHooks, localHooks: ClientHooks | undefined): Promise<BeforeRequestContext>;
8
+ /**
9
+ * Runs `onAfterResponse` hooks: global first, then per-procedure.
10
+ * Returns void.
11
+ */
12
+ export declare function runAfterResponse(ctx: AfterResponseContext, globalHooks: ClientHooks, localHooks: ClientHooks | undefined): Promise<void>;
13
+ /**
14
+ * Runs `onError` hooks: global first, then per-procedure.
15
+ * Returns void.
16
+ */
17
+ export declare function runOnError(ctx: ErrorContext, globalHooks: ClientHooks, localHooks: ClientHooks | undefined): Promise<void>;
@@ -0,0 +1,40 @@
1
+ /**
2
+ * Runs `onBeforeRequest` hooks: global first, then per-procedure.
3
+ * Each hook receives the (possibly mutated) context from the previous hook.
4
+ * Returns the final context.
5
+ */
6
+ export async function runBeforeRequest(ctx, globalHooks, localHooks) {
7
+ let current = ctx;
8
+ if (globalHooks.onBeforeRequest) {
9
+ current = await globalHooks.onBeforeRequest(current);
10
+ }
11
+ if (localHooks?.onBeforeRequest) {
12
+ current = await localHooks.onBeforeRequest(current);
13
+ }
14
+ return current;
15
+ }
16
+ /**
17
+ * Runs `onAfterResponse` hooks: global first, then per-procedure.
18
+ * Returns void.
19
+ */
20
+ export async function runAfterResponse(ctx, globalHooks, localHooks) {
21
+ if (globalHooks.onAfterResponse) {
22
+ await globalHooks.onAfterResponse(ctx);
23
+ }
24
+ if (localHooks?.onAfterResponse) {
25
+ await localHooks.onAfterResponse(ctx);
26
+ }
27
+ }
28
+ /**
29
+ * Runs `onError` hooks: global first, then per-procedure.
30
+ * Returns void.
31
+ */
32
+ export async function runOnError(ctx, globalHooks, localHooks) {
33
+ if (globalHooks.onError) {
34
+ await globalHooks.onError(ctx);
35
+ }
36
+ if (localHooks?.onError) {
37
+ await localHooks.onError(ctx);
38
+ }
39
+ }
40
+ //# sourceMappingURL=hooks.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"hooks.js","sourceRoot":"","sources":["../../../src/client/hooks.ts"],"names":[],"mappings":"AAOA;;;;GAIG;AACH,MAAM,CAAC,KAAK,UAAU,gBAAgB,CACpC,GAAyB,EACzB,WAAwB,EACxB,UAAmC;IAEnC,IAAI,OAAO,GAAG,GAAG,CAAA;IAEjB,IAAI,WAAW,CAAC,eAAe,EAAE,CAAC;QAChC,OAAO,GAAG,MAAM,WAAW,CAAC,eAAe,CAAC,OAAO,CAAC,CAAA;IACtD,CAAC;IAED,IAAI,UAAU,EAAE,eAAe,EAAE,CAAC;QAChC,OAAO,GAAG,MAAM,UAAU,CAAC,eAAe,CAAC,OAAO,CAAC,CAAA;IACrD,CAAC;IAED,OAAO,OAAO,CAAA;AAChB,CAAC;AAED;;;GAGG;AACH,MAAM,CAAC,KAAK,UAAU,gBAAgB,CACpC,GAAyB,EACzB,WAAwB,EACxB,UAAmC;IAEnC,IAAI,WAAW,CAAC,eAAe,EAAE,CAAC;QAChC,MAAM,WAAW,CAAC,eAAe,CAAC,GAAG,CAAC,CAAA;IACxC,CAAC;IAED,IAAI,UAAU,EAAE,eAAe,EAAE,CAAC;QAChC,MAAM,UAAU,CAAC,eAAe,CAAC,GAAG,CAAC,CAAA;IACvC,CAAC;AACH,CAAC;AAED;;;GAGG;AACH,MAAM,CAAC,KAAK,UAAU,UAAU,CAC9B,GAAiB,EACjB,WAAwB,EACxB,UAAmC;IAEnC,IAAI,WAAW,CAAC,OAAO,EAAE,CAAC;QACxB,MAAM,WAAW,CAAC,OAAO,CAAC,GAAG,CAAC,CAAA;IAChC,CAAC;IAED,IAAI,UAAU,EAAE,OAAO,EAAE,CAAC;QACxB,MAAM,UAAU,CAAC,OAAO,CAAC,GAAG,CAAC,CAAA;IAC/B,CAAC;AACH,CAAC"}
@@ -0,0 +1 @@
1
+ export {};
@@ -0,0 +1,163 @@
1
+ import { describe, it, expect } from 'vitest';
2
+ import { runBeforeRequest, runAfterResponse, runOnError } from './hooks.js';
3
+ // ── helpers ───────────────────────────────────────────────
4
+ function makeBeforeCtx(overrides) {
5
+ return {
6
+ procedureName: 'TestProcedure',
7
+ scope: 'test',
8
+ request: { url: 'https://example.com', method: 'GET' },
9
+ ...overrides,
10
+ };
11
+ }
12
+ function makeAfterCtx(overrides) {
13
+ return {
14
+ procedureName: 'TestProcedure',
15
+ scope: 'test',
16
+ request: { url: 'https://example.com', method: 'GET' },
17
+ response: { status: 200, headers: {}, body: null },
18
+ ...overrides,
19
+ };
20
+ }
21
+ function makeErrorCtx(overrides) {
22
+ return {
23
+ procedureName: 'TestProcedure',
24
+ scope: 'test',
25
+ request: { url: 'https://example.com', method: 'GET' },
26
+ error: new Error('something went wrong'),
27
+ ...overrides,
28
+ };
29
+ }
30
+ // ── runBeforeRequest ──────────────────────────────────────
31
+ describe('runBeforeRequest', () => {
32
+ it('runs global hook then local hook in order', async () => {
33
+ const order = [];
34
+ const globalHooks = {
35
+ onBeforeRequest: (ctx) => { order.push('global'); return ctx; },
36
+ };
37
+ const localHooks = {
38
+ onBeforeRequest: (ctx) => { order.push('local'); return ctx; },
39
+ };
40
+ const ctx = makeBeforeCtx();
41
+ await runBeforeRequest(ctx, globalHooks, localHooks);
42
+ expect(order).toEqual(['global', 'local']);
43
+ });
44
+ it('passes the (possibly mutated) context from global to local', async () => {
45
+ const globalHooks = {
46
+ onBeforeRequest: (ctx) => ({
47
+ ...ctx,
48
+ request: { ...ctx.request, url: 'https://mutated.example.com' },
49
+ }),
50
+ };
51
+ let receivedUrl = '';
52
+ const localHooks = {
53
+ onBeforeRequest: (ctx) => { receivedUrl = ctx.request.url; return ctx; },
54
+ };
55
+ const ctx = makeBeforeCtx();
56
+ await runBeforeRequest(ctx, globalHooks, localHooks);
57
+ expect(receivedUrl).toBe('https://mutated.example.com');
58
+ });
59
+ it('returns the final mutated context', async () => {
60
+ const globalHooks = {
61
+ onBeforeRequest: (ctx) => ({ ...ctx, scope: 'mutated-by-global' }),
62
+ };
63
+ const localHooks = {
64
+ onBeforeRequest: (ctx) => ({ ...ctx, scope: ctx.scope + '-then-local' }),
65
+ };
66
+ const ctx = makeBeforeCtx();
67
+ const result = await runBeforeRequest(ctx, globalHooks, localHooks);
68
+ expect(result.scope).toBe('mutated-by-global-then-local');
69
+ });
70
+ it('handles async hooks', async () => {
71
+ const order = [];
72
+ const globalHooks = {
73
+ onBeforeRequest: async (ctx) => { order.push('global'); return ctx; },
74
+ };
75
+ const localHooks = {
76
+ onBeforeRequest: async (ctx) => { order.push('local'); return ctx; },
77
+ };
78
+ await runBeforeRequest(makeBeforeCtx(), globalHooks, localHooks);
79
+ expect(order).toEqual(['global', 'local']);
80
+ });
81
+ it('skips undefined global hook gracefully', async () => {
82
+ const localHooks = {
83
+ onBeforeRequest: (ctx) => ({ ...ctx, scope: 'local-only' }),
84
+ };
85
+ const result = await runBeforeRequest(makeBeforeCtx(), {}, localHooks);
86
+ expect(result.scope).toBe('local-only');
87
+ });
88
+ it('skips undefined local hook gracefully', async () => {
89
+ const globalHooks = {
90
+ onBeforeRequest: (ctx) => ({ ...ctx, scope: 'global-only' }),
91
+ };
92
+ const result = await runBeforeRequest(makeBeforeCtx(), globalHooks, undefined);
93
+ expect(result.scope).toBe('global-only');
94
+ });
95
+ it('skips both hooks gracefully when neither defined', async () => {
96
+ const ctx = makeBeforeCtx();
97
+ const result = await runBeforeRequest(ctx, {}, undefined);
98
+ expect(result).toEqual(ctx);
99
+ });
100
+ });
101
+ // ── runAfterResponse ──────────────────────────────────────
102
+ describe('runAfterResponse', () => {
103
+ it('runs global then local hook', async () => {
104
+ const order = [];
105
+ const globalHooks = { onAfterResponse: () => { order.push('global'); } };
106
+ const localHooks = { onAfterResponse: () => { order.push('local'); } };
107
+ await runAfterResponse(makeAfterCtx(), globalHooks, localHooks);
108
+ expect(order).toEqual(['global', 'local']);
109
+ });
110
+ it('handles async hooks', async () => {
111
+ const order = [];
112
+ const globalHooks = {
113
+ onAfterResponse: async () => { order.push('global'); },
114
+ };
115
+ const localHooks = {
116
+ onAfterResponse: async () => { order.push('local'); },
117
+ };
118
+ await runAfterResponse(makeAfterCtx(), globalHooks, localHooks);
119
+ expect(order).toEqual(['global', 'local']);
120
+ });
121
+ it('skips undefined hooks gracefully', async () => {
122
+ // Should not throw
123
+ await runAfterResponse(makeAfterCtx(), {}, undefined);
124
+ });
125
+ it('returns void', async () => {
126
+ const result = await runAfterResponse(makeAfterCtx(), {}, undefined);
127
+ expect(result).toBeUndefined();
128
+ });
129
+ });
130
+ // ── runOnError ────────────────────────────────────────────
131
+ describe('runOnError', () => {
132
+ it('runs global then local hook', async () => {
133
+ const order = [];
134
+ const globalHooks = { onError: () => { order.push('global'); } };
135
+ const localHooks = { onError: () => { order.push('local'); } };
136
+ await runOnError(makeErrorCtx(), globalHooks, localHooks);
137
+ expect(order).toEqual(['global', 'local']);
138
+ });
139
+ it('handles async hooks', async () => {
140
+ const order = [];
141
+ const globalHooks = { onError: async () => { order.push('global'); } };
142
+ const localHooks = { onError: async () => { order.push('local'); } };
143
+ await runOnError(makeErrorCtx(), globalHooks, localHooks);
144
+ expect(order).toEqual(['global', 'local']);
145
+ });
146
+ it('skips undefined hooks gracefully', async () => {
147
+ await runOnError(makeErrorCtx(), {}, undefined);
148
+ });
149
+ it('returns void', async () => {
150
+ const result = await runOnError(makeErrorCtx(), {}, undefined);
151
+ expect(result).toBeUndefined();
152
+ });
153
+ it('receives the error in context', async () => {
154
+ const receivedErrors = [];
155
+ const globalHooks = {
156
+ onError: (ctx) => { receivedErrors.push(ctx.error); },
157
+ };
158
+ const err = new Error('boom');
159
+ await runOnError(makeErrorCtx({ error: err }), globalHooks, undefined);
160
+ expect(receivedErrors[0]).toBe(err);
161
+ });
162
+ });
163
+ //# sourceMappingURL=hooks.test.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"hooks.test.js","sourceRoot":"","sources":["../../../src/client/hooks.test.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,22 @@
1
+ import type { CreateClientConfig } from './types.js';
2
+ /**
3
+ * Creates a typed client from a config object.
4
+ *
5
+ * The `scopes` callback receives a `ClientInstance` and returns the typed
6
+ * scope bindings (e.g., `{ users: { getUser, createUser }, posts: { ... } }`).
7
+ * The return value of `createClient` is the scopes object.
8
+ *
9
+ * `client.stream()` must return `TypedStream` synchronously even though
10
+ * `executeStream` is async. We achieve this by creating a deferred TypedStream:
11
+ * - A deferred async generator awaits `executeStream` internally, then forwards
12
+ * yields from the inner stream.
13
+ * - The outer `.result` is wired up to the inner stream's `.result`.
14
+ */
15
+ export declare function createClient<TScopes>(config: CreateClientConfig<TScopes>): TScopes;
16
+ export type { ClientAdapter, AdapterRequest, AdapterResponse, AdapterStreamResponse, ClientHooks, BeforeRequestContext, AfterResponseContext, ErrorContext, CallDescriptor, StreamDescriptor, TypedStream, ClientInstance, ProcedureCallOptions, CreateClientConfig, } from './types.js';
17
+ export { ClientRequestError, ClientPathParamError, ClientStreamError } from './errors.js';
18
+ export { createTypedStream } from './stream.js';
19
+ export { executeCall } from './call.js';
20
+ export { executeStream } from './stream.js';
21
+ export { createFetchAdapter } from './fetch-adapter.js';
22
+ export type { FetchAdapterConfig } from './fetch-adapter.js';
@@ -0,0 +1,67 @@
1
+ import { executeCall } from './call.js';
2
+ import { executeStream } from './stream.js';
3
+ // ── createClient ──────────────────────────────────────────
4
+ /**
5
+ * Creates a typed client from a config object.
6
+ *
7
+ * The `scopes` callback receives a `ClientInstance` and returns the typed
8
+ * scope bindings (e.g., `{ users: { getUser, createUser }, posts: { ... } }`).
9
+ * The return value of `createClient` is the scopes object.
10
+ *
11
+ * `client.stream()` must return `TypedStream` synchronously even though
12
+ * `executeStream` is async. We achieve this by creating a deferred TypedStream:
13
+ * - A deferred async generator awaits `executeStream` internally, then forwards
14
+ * yields from the inner stream.
15
+ * - The outer `.result` is wired up to the inner stream's `.result`.
16
+ */
17
+ export function createClient(config) {
18
+ const { adapter, basePath, hooks: globalHooks = {}, scopes } = config;
19
+ const instance = {
20
+ basePath,
21
+ adapter,
22
+ hooks: globalHooks,
23
+ call(descriptor, options) {
24
+ return executeCall(descriptor, basePath, adapter, globalHooks, options);
25
+ },
26
+ stream(descriptor, options) {
27
+ // executeStream is async but stream() must be synchronous.
28
+ // Create a deferred TypedStream that wraps the async executeStream call.
29
+ let resolveResult;
30
+ let rejectResult;
31
+ const resultPromise = new Promise((resolve, reject) => {
32
+ resolveResult = resolve;
33
+ rejectResult = reject;
34
+ });
35
+ // The deferred async generator: awaits executeStream, then forwards
36
+ async function* deferredGenerator() {
37
+ let innerStream;
38
+ try {
39
+ innerStream = await executeStream(descriptor, basePath, adapter, globalHooks, options);
40
+ }
41
+ catch (err) {
42
+ rejectResult(err);
43
+ throw err;
44
+ }
45
+ // Wire up .result from the inner stream
46
+ innerStream.result.then(resolveResult, rejectResult);
47
+ for await (const item of innerStream) {
48
+ yield item;
49
+ }
50
+ }
51
+ const iterator = deferredGenerator();
52
+ return {
53
+ [Symbol.asyncIterator]() {
54
+ return iterator;
55
+ },
56
+ result: resultPromise,
57
+ };
58
+ },
59
+ };
60
+ return scopes(instance);
61
+ }
62
+ export { ClientRequestError, ClientPathParamError, ClientStreamError } from './errors.js';
63
+ export { createTypedStream } from './stream.js';
64
+ export { executeCall } from './call.js';
65
+ export { executeStream } from './stream.js';
66
+ export { createFetchAdapter } from './fetch-adapter.js';
67
+ //# sourceMappingURL=index.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"index.js","sourceRoot":"","sources":["../../../src/client/index.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,WAAW,EAAE,MAAM,WAAW,CAAA;AACvC,OAAO,EAAE,aAAa,EAAqB,MAAM,aAAa,CAAA;AAU9D,6DAA6D;AAE7D;;;;;;;;;;;;GAYG;AACH,MAAM,UAAU,YAAY,CAAU,MAAmC;IACvE,MAAM,EAAE,OAAO,EAAE,QAAQ,EAAE,KAAK,EAAE,WAAW,GAAG,EAAE,EAAE,MAAM,EAAE,GAAG,MAAM,CAAA;IAErE,MAAM,QAAQ,GAAmB;QAC/B,QAAQ;QACR,OAAO;QACP,KAAK,EAAE,WAAW;QAElB,IAAI,CACF,UAA0B,EAC1B,OAA8B;YAE9B,OAAO,WAAW,CAAY,UAAU,EAAE,QAAQ,EAAE,OAAO,EAAE,WAAW,EAAE,OAAO,CAAC,CAAA;QACpF,CAAC;QAED,MAAM,CACJ,UAA4B,EAC5B,OAA8B;YAE9B,2DAA2D;YAC3D,yEAAyE;YAEzE,IAAI,aAAuC,CAAA;YAC3C,IAAI,YAAuC,CAAA;YAE3C,MAAM,aAAa,GAAG,IAAI,OAAO,CAAU,CAAC,OAAO,EAAE,MAAM,EAAE,EAAE;gBAC7D,aAAa,GAAG,OAAO,CAAA;gBACvB,YAAY,GAAG,MAAM,CAAA;YACvB,CAAC,CAAC,CAAA;YAEF,oEAAoE;YACpE,KAAK,SAAS,CAAC,CAAC,iBAAiB;gBAC/B,IAAI,WAAyC,CAAA;gBAC7C,IAAI,CAAC;oBACH,WAAW,GAAG,MAAM,aAAa,CAC/B,UAAU,EACV,QAAQ,EACR,OAAO,EACP,WAAW,EACX,OAAO,CACR,CAAA;gBACH,CAAC;gBAAC,OAAO,GAAG,EAAE,CAAC;oBACb,YAAY,CAAC,GAAG,CAAC,CAAA;oBACjB,MAAM,GAAG,CAAA;gBACX,CAAC;gBAED,wCAAwC;gBACxC,WAAW,CAAC,MAAM,CAAC,IAAI,CAAC,aAAa,EAAE,YAAY,CAAC,CAAA;gBAEpD,IAAI,KAAK,EAAE,MAAM,IAAI,IAAI,WAAW,EAAE,CAAC;oBACrC,MAAM,IAAI,CAAA;gBACZ,CAAC;YACH,CAAC;YAED,MAAM,QAAQ,GAAG,iBAAiB,EAAE,CAAA;YAEpC,OAAO;gBACL,CAAC,MAAM,CAAC,aAAa,CAAC;oBACpB,OAAO,QAAQ,CAAA;gBACjB,CAAC;gBACD,MAAM,EAAE,aAAa;aACtB,CAAA;QACH,CAAC;KACF,CAAA;IAED,OAAO,MAAM,CAAC,QAAQ,CAAC,CAAA;AACzB,CAAC;AAqBD,OAAO,EAAE,kBAAkB,EAAE,oBAAoB,EAAE,iBAAiB,EAAE,MAAM,aAAa,CAAA;AAEzF,OAAO,EAAE,iBAAiB,EAAE,MAAM,aAAa,CAAA;AAC/C,OAAO,EAAE,WAAW,EAAE,MAAM,WAAW,CAAA;AACvC,OAAO,EAAE,aAAa,EAAE,MAAM,aAAa,CAAA;AAE3C,OAAO,EAAE,kBAAkB,EAAE,MAAM,oBAAoB,CAAA"}
@@ -0,0 +1 @@
1
+ export {};