@namzu/sdk 0.4.2 → 0.4.3

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (207) hide show
  1. package/CHANGELOG.md +10 -0
  2. package/dist/advisory/context.test.d.ts +16 -0
  3. package/dist/advisory/context.test.d.ts.map +1 -0
  4. package/dist/advisory/context.test.js +92 -0
  5. package/dist/advisory/context.test.js.map +1 -0
  6. package/dist/advisory/evaluator.test.d.ts +34 -0
  7. package/dist/advisory/evaluator.test.d.ts.map +1 -0
  8. package/dist/advisory/evaluator.test.js +172 -0
  9. package/dist/advisory/evaluator.test.js.map +1 -0
  10. package/dist/advisory/executor.test.d.ts +35 -0
  11. package/dist/advisory/executor.test.d.ts.map +1 -0
  12. package/dist/advisory/executor.test.js +233 -0
  13. package/dist/advisory/executor.test.js.map +1 -0
  14. package/dist/advisory/registry.test.d.ts +16 -0
  15. package/dist/advisory/registry.test.d.ts.map +1 -0
  16. package/dist/advisory/registry.test.js +62 -0
  17. package/dist/advisory/registry.test.js.map +1 -0
  18. package/dist/bridge/a2a/agent-card.test.d.ts +24 -0
  19. package/dist/bridge/a2a/agent-card.test.d.ts.map +1 -0
  20. package/dist/bridge/a2a/agent-card.test.js +118 -0
  21. package/dist/bridge/a2a/agent-card.test.js.map +1 -0
  22. package/dist/bridge/a2a/mapper.test.d.ts +29 -0
  23. package/dist/bridge/a2a/mapper.test.d.ts.map +1 -0
  24. package/dist/bridge/a2a/mapper.test.js +265 -0
  25. package/dist/bridge/a2a/mapper.test.js.map +1 -0
  26. package/dist/bridge/a2a/message.test.d.ts +20 -0
  27. package/dist/bridge/a2a/message.test.d.ts.map +1 -0
  28. package/dist/bridge/a2a/message.test.js +116 -0
  29. package/dist/bridge/a2a/message.test.js.map +1 -0
  30. package/dist/bridge/a2a/task.test.d.ts +29 -0
  31. package/dist/bridge/a2a/task.test.d.ts.map +1 -0
  32. package/dist/bridge/a2a/task.test.js +198 -0
  33. package/dist/bridge/a2a/task.test.js.map +1 -0
  34. package/dist/bridge/mcp/connector/adapter.test.d.ts +27 -0
  35. package/dist/bridge/mcp/connector/adapter.test.d.ts.map +1 -0
  36. package/dist/bridge/mcp/connector/adapter.test.js +203 -0
  37. package/dist/bridge/mcp/connector/adapter.test.js.map +1 -0
  38. package/dist/bridge/sse/mapper.test.d.ts +27 -0
  39. package/dist/bridge/sse/mapper.test.d.ts.map +1 -0
  40. package/dist/bridge/sse/mapper.test.js +271 -0
  41. package/dist/bridge/sse/mapper.test.js.map +1 -0
  42. package/dist/bridge/tools/connector/adapter.test.d.ts +28 -0
  43. package/dist/bridge/tools/connector/adapter.test.d.ts.map +1 -0
  44. package/dist/bridge/tools/connector/adapter.test.js +182 -0
  45. package/dist/bridge/tools/connector/adapter.test.js.map +1 -0
  46. package/dist/bridge/tools/connector/definitions.test.d.ts +23 -0
  47. package/dist/bridge/tools/connector/definitions.test.d.ts.map +1 -0
  48. package/dist/bridge/tools/connector/definitions.test.js +158 -0
  49. package/dist/bridge/tools/connector/definitions.test.js.map +1 -0
  50. package/dist/bridge/tools/connector/router.test.d.ts +21 -0
  51. package/dist/bridge/tools/connector/router.test.d.ts.map +1 -0
  52. package/dist/bridge/tools/connector/router.test.js +139 -0
  53. package/dist/bridge/tools/connector/router.test.js.map +1 -0
  54. package/dist/bus/breaker.test.d.ts +41 -0
  55. package/dist/bus/breaker.test.d.ts.map +1 -0
  56. package/dist/bus/breaker.test.js +242 -0
  57. package/dist/bus/breaker.test.js.map +1 -0
  58. package/dist/bus/index.test.d.ts +25 -0
  59. package/dist/bus/index.test.d.ts.map +1 -0
  60. package/dist/bus/index.test.js +151 -0
  61. package/dist/bus/index.test.js.map +1 -0
  62. package/dist/bus/lock.test.d.ts +44 -0
  63. package/dist/bus/lock.test.d.ts.map +1 -0
  64. package/dist/bus/lock.test.js +226 -0
  65. package/dist/bus/lock.test.js.map +1 -0
  66. package/dist/bus/ownership.test.d.ts +26 -0
  67. package/dist/bus/ownership.test.d.ts.map +1 -0
  68. package/dist/bus/ownership.test.js +205 -0
  69. package/dist/bus/ownership.test.js.map +1 -0
  70. package/dist/connector/BaseConnector.test.d.ts +21 -0
  71. package/dist/connector/BaseConnector.test.d.ts.map +1 -0
  72. package/dist/connector/BaseConnector.test.js +108 -0
  73. package/dist/connector/BaseConnector.test.js.map +1 -0
  74. package/dist/connector/builtins/http.test.d.ts +30 -0
  75. package/dist/connector/builtins/http.test.d.ts.map +1 -0
  76. package/dist/connector/builtins/http.test.js +232 -0
  77. package/dist/connector/builtins/http.test.js.map +1 -0
  78. package/dist/connector/builtins/webhook.test.d.ts +20 -0
  79. package/dist/connector/builtins/webhook.test.d.ts.map +1 -0
  80. package/dist/connector/builtins/webhook.test.js +113 -0
  81. package/dist/connector/builtins/webhook.test.js.map +1 -0
  82. package/dist/connector/execution/factory.test.d.ts +16 -0
  83. package/dist/connector/execution/factory.test.d.ts.map +1 -0
  84. package/dist/connector/execution/factory.test.js +64 -0
  85. package/dist/connector/execution/factory.test.js.map +1 -0
  86. package/dist/connector/execution/remote.test.d.ts +16 -0
  87. package/dist/connector/execution/remote.test.d.ts.map +1 -0
  88. package/dist/connector/execution/remote.test.js +53 -0
  89. package/dist/connector/execution/remote.test.js.map +1 -0
  90. package/dist/connector/mcp/adapter.test.d.ts +34 -0
  91. package/dist/connector/mcp/adapter.test.d.ts.map +1 -0
  92. package/dist/connector/mcp/adapter.test.js +199 -0
  93. package/dist/connector/mcp/adapter.test.js.map +1 -0
  94. package/dist/rag/chunking.test.d.ts +20 -0
  95. package/dist/rag/chunking.test.d.ts.map +1 -0
  96. package/dist/rag/chunking.test.js +92 -0
  97. package/dist/rag/chunking.test.js.map +1 -0
  98. package/dist/rag/context-assembler.test.d.ts +19 -0
  99. package/dist/rag/context-assembler.test.d.ts.map +1 -0
  100. package/dist/rag/context-assembler.test.js +98 -0
  101. package/dist/rag/context-assembler.test.js.map +1 -0
  102. package/dist/rag/embedding.test.d.ts +19 -0
  103. package/dist/rag/embedding.test.d.ts.map +1 -0
  104. package/dist/rag/embedding.test.js +115 -0
  105. package/dist/rag/embedding.test.js.map +1 -0
  106. package/dist/rag/ingestion.test.d.ts +22 -0
  107. package/dist/rag/ingestion.test.d.ts.map +1 -0
  108. package/dist/rag/ingestion.test.js +99 -0
  109. package/dist/rag/ingestion.test.js.map +1 -0
  110. package/dist/rag/knowledge-base.test.d.ts +17 -0
  111. package/dist/rag/knowledge-base.test.d.ts.map +1 -0
  112. package/dist/rag/knowledge-base.test.js +77 -0
  113. package/dist/rag/knowledge-base.test.js.map +1 -0
  114. package/dist/rag/rag-tool.test.d.ts +21 -0
  115. package/dist/rag/rag-tool.test.d.ts.map +1 -0
  116. package/dist/rag/rag-tool.test.js +149 -0
  117. package/dist/rag/rag-tool.test.js.map +1 -0
  118. package/dist/rag/retriever.test.d.ts +26 -0
  119. package/dist/rag/retriever.test.d.ts.map +1 -0
  120. package/dist/rag/retriever.test.js +180 -0
  121. package/dist/rag/retriever.test.js.map +1 -0
  122. package/dist/rag/vector-store.test.d.ts +38 -0
  123. package/dist/rag/vector-store.test.d.ts.map +1 -0
  124. package/dist/rag/vector-store.test.js +175 -0
  125. package/dist/rag/vector-store.test.js.map +1 -0
  126. package/dist/registry/ManagedRegistry.test.d.ts +21 -0
  127. package/dist/registry/ManagedRegistry.test.d.ts.map +1 -0
  128. package/dist/registry/ManagedRegistry.test.js +98 -0
  129. package/dist/registry/ManagedRegistry.test.js.map +1 -0
  130. package/dist/registry/Registry.test.d.ts +18 -0
  131. package/dist/registry/Registry.test.d.ts.map +1 -0
  132. package/dist/registry/Registry.test.js +79 -0
  133. package/dist/registry/Registry.test.js.map +1 -0
  134. package/dist/registry/agent/definitions.test.d.ts +15 -0
  135. package/dist/registry/agent/definitions.test.d.ts.map +1 -0
  136. package/dist/registry/agent/definitions.test.js +84 -0
  137. package/dist/registry/agent/definitions.test.js.map +1 -0
  138. package/dist/registry/connector/definitions.test.d.ts +13 -0
  139. package/dist/registry/connector/definitions.test.d.ts.map +1 -0
  140. package/dist/registry/connector/definitions.test.js +41 -0
  141. package/dist/registry/connector/definitions.test.js.map +1 -0
  142. package/dist/registry/connector/scoped.test.d.ts +21 -0
  143. package/dist/registry/connector/scoped.test.d.ts.map +1 -0
  144. package/dist/registry/connector/scoped.test.js +115 -0
  145. package/dist/registry/connector/scoped.test.js.map +1 -0
  146. package/dist/registry/plugin/index.test.d.ts +12 -0
  147. package/dist/registry/plugin/index.test.d.ts.map +1 -0
  148. package/dist/registry/plugin/index.test.js +69 -0
  149. package/dist/registry/plugin/index.test.js.map +1 -0
  150. package/dist/registry/tool/execute.test.d.ts +42 -0
  151. package/dist/registry/tool/execute.test.d.ts.map +1 -0
  152. package/dist/registry/tool/execute.test.js +281 -0
  153. package/dist/registry/tool/execute.test.js.map +1 -0
  154. package/dist/runtime/query/iteration/phases/advisory.test.d.ts +42 -0
  155. package/dist/runtime/query/iteration/phases/advisory.test.d.ts.map +1 -0
  156. package/dist/runtime/query/iteration/phases/advisory.test.js +334 -0
  157. package/dist/runtime/query/iteration/phases/advisory.test.js.map +1 -0
  158. package/dist/test-setup.d.ts +22 -0
  159. package/dist/test-setup.d.ts.map +1 -0
  160. package/dist/test-setup.js +23 -0
  161. package/dist/test-setup.js.map +1 -0
  162. package/dist/utils/logger.d.ts +1 -1
  163. package/dist/utils/logger.d.ts.map +1 -1
  164. package/dist/utils/logger.js +5 -0
  165. package/dist/utils/logger.js.map +1 -1
  166. package/package.json +4 -1
  167. package/src/advisory/context.test.ts +109 -0
  168. package/src/advisory/evaluator.test.ts +192 -0
  169. package/src/advisory/executor.test.ts +272 -0
  170. package/src/advisory/registry.test.ts +75 -0
  171. package/src/bridge/a2a/agent-card.test.ts +140 -0
  172. package/src/bridge/a2a/mapper.test.ts +293 -0
  173. package/src/bridge/a2a/message.test.ts +138 -0
  174. package/src/bridge/a2a/task.test.ts +235 -0
  175. package/src/bridge/mcp/connector/adapter.test.ts +230 -0
  176. package/src/bridge/sse/mapper.test.ts +422 -0
  177. package/src/bridge/tools/connector/adapter.test.ts +224 -0
  178. package/src/bridge/tools/connector/definitions.test.ts +183 -0
  179. package/src/bridge/tools/connector/router.test.ts +159 -0
  180. package/src/bus/breaker.test.ts +274 -0
  181. package/src/bus/index.test.ts +183 -0
  182. package/src/bus/lock.test.ts +265 -0
  183. package/src/bus/ownership.test.ts +243 -0
  184. package/src/connector/BaseConnector.test.ts +130 -0
  185. package/src/connector/builtins/http.test.ts +290 -0
  186. package/src/connector/builtins/webhook.test.ts +138 -0
  187. package/src/connector/execution/factory.test.ts +75 -0
  188. package/src/connector/execution/remote.test.ts +63 -0
  189. package/src/connector/mcp/adapter.test.ts +249 -0
  190. package/src/rag/chunking.test.ts +107 -0
  191. package/src/rag/context-assembler.test.ts +114 -0
  192. package/src/rag/embedding.test.ts +130 -0
  193. package/src/rag/ingestion.test.ts +114 -0
  194. package/src/rag/knowledge-base.test.ts +106 -0
  195. package/src/rag/rag-tool.test.ts +167 -0
  196. package/src/rag/retriever.test.ts +210 -0
  197. package/src/rag/vector-store.test.ts +196 -0
  198. package/src/registry/ManagedRegistry.test.ts +118 -0
  199. package/src/registry/Registry.test.ts +91 -0
  200. package/src/registry/agent/definitions.test.ts +100 -0
  201. package/src/registry/connector/definitions.test.ts +51 -0
  202. package/src/registry/connector/scoped.test.ts +129 -0
  203. package/src/registry/plugin/index.test.ts +85 -0
  204. package/src/registry/tool/execute.test.ts +330 -0
  205. package/src/runtime/query/iteration/phases/advisory.test.ts +412 -0
  206. package/src/test-setup.ts +24 -0
  207. package/src/utils/logger.ts +6 -1
@@ -0,0 +1,205 @@
1
+ /**
2
+ * Current-code invariants asserted (2026-04-21, ses_006 Phase 1):
3
+ *
4
+ * - `claim(path, owner)` on an unowned file creates ownership, emits
5
+ * `ownership_claimed`, returns `{claimed: true, ownership}`.
6
+ * - `claim(path, owner)` by the same owner is idempotent — returns
7
+ * `{claimed: true, ownership}` WITHOUT re-emitting.
8
+ * - `claim(path, owner)` by a different owner is denied — emits
9
+ * `ownership_denied`, returns `{claimed: false, currentOwner, filePath}`.
10
+ * - `release(path, owner)` on the current owner deletes + emits; returns
11
+ * true. On mismatch or missing entry: returns false; no emit.
12
+ * - `transfer(path, from, to)` requires the current owner to equal
13
+ * `from`. Success replaces the entry with a new `claimedAt`, emits
14
+ * `ownership_transferred`; no intervening `ownership_released` or
15
+ * `ownership_claimed` events. Failure returns false; no emit.
16
+ * - `releaseAll(owner)` sweeps every ownership for `owner`, emits
17
+ * `ownership_released` per entry, returns the count. Other owners'
18
+ * entries are untouched.
19
+ * - File paths are normalised via `path.resolve` before keying —
20
+ * `./foo/bar` and the absolute resolution of the same path collide
21
+ * into one ownership slot.
22
+ * - Ownership is not per-tenant; only per-`RunId`. There is no tenant
23
+ * isolation at this layer (design.md §2.1 aspirational; see §2.7).
24
+ */
25
+ import path from 'node:path';
26
+ import { beforeEach, describe, expect, it, vi } from 'vitest';
27
+ import { EditOwnershipTracker } from './ownership.js';
28
+ function makeLogger() {
29
+ const stub = { info: vi.fn(), warn: vi.fn(), error: vi.fn(), debug: vi.fn() };
30
+ return { ...stub, child: vi.fn(() => ({ ...stub, child: vi.fn() })) };
31
+ }
32
+ function runId(n) {
33
+ return `run_${n}`;
34
+ }
35
+ describe('EditOwnershipTracker', () => {
36
+ let events;
37
+ let tracker;
38
+ beforeEach(() => {
39
+ events = [];
40
+ tracker = new EditOwnershipTracker(makeLogger(), (e) => events.push(e));
41
+ });
42
+ describe('claim', () => {
43
+ it('claims an unowned file, emits ownership_claimed, returns ownership', () => {
44
+ const before = Date.now();
45
+ const result = tracker.claim('/tmp/file.txt', runId(1));
46
+ const after = Date.now();
47
+ expect(result.claimed).toBe(true);
48
+ if (result.claimed) {
49
+ expect(result.ownership.owner).toBe(runId(1));
50
+ expect(result.ownership.filePath).toBe(path.resolve('/tmp/file.txt'));
51
+ expect(result.ownership.claimedAt).toBeGreaterThanOrEqual(before);
52
+ expect(result.ownership.claimedAt).toBeLessThanOrEqual(after);
53
+ }
54
+ expect(events).toEqual([
55
+ { type: 'ownership_claimed', filePath: path.resolve('/tmp/file.txt'), owner: runId(1) },
56
+ ]);
57
+ });
58
+ it('is idempotent when the same owner re-claims — no re-emit', () => {
59
+ tracker.claim('/tmp/file.txt', runId(1));
60
+ events.length = 0;
61
+ const result = tracker.claim('/tmp/file.txt', runId(1));
62
+ expect(result.claimed).toBe(true);
63
+ expect(events).toEqual([]);
64
+ });
65
+ it('denies a claim by a different owner, emits ownership_denied', () => {
66
+ tracker.claim('/tmp/file.txt', runId(1));
67
+ events.length = 0;
68
+ const result = tracker.claim('/tmp/file.txt', runId(2));
69
+ expect(result.claimed).toBe(false);
70
+ if (!result.claimed) {
71
+ expect(result.currentOwner).toBe(runId(1));
72
+ expect(result.filePath).toBe(path.resolve('/tmp/file.txt'));
73
+ }
74
+ expect(events).toEqual([
75
+ {
76
+ type: 'ownership_denied',
77
+ filePath: path.resolve('/tmp/file.txt'),
78
+ requester: runId(2),
79
+ currentOwner: runId(1),
80
+ },
81
+ ]);
82
+ });
83
+ it('normalises file paths — equivalent paths collide', () => {
84
+ tracker.claim('/tmp/foo/../file.txt', runId(1));
85
+ const result = tracker.claim('/tmp/file.txt', runId(2));
86
+ expect(result.claimed).toBe(false);
87
+ });
88
+ });
89
+ describe('release', () => {
90
+ it('releases an owned file, emits ownership_released, returns true', () => {
91
+ tracker.claim('/tmp/file.txt', runId(1));
92
+ events.length = 0;
93
+ const ok = tracker.release('/tmp/file.txt', runId(1));
94
+ expect(ok).toBe(true);
95
+ expect(tracker.getOwner('/tmp/file.txt')).toBeUndefined();
96
+ expect(events).toEqual([
97
+ {
98
+ type: 'ownership_released',
99
+ filePath: path.resolve('/tmp/file.txt'),
100
+ previousOwner: runId(1),
101
+ },
102
+ ]);
103
+ });
104
+ it('returns false when no ownership exists — no emit', () => {
105
+ const ok = tracker.release('/tmp/never-claimed.txt', runId(1));
106
+ expect(ok).toBe(false);
107
+ expect(events).toEqual([]);
108
+ });
109
+ it('returns false when owner mismatches — no emit', () => {
110
+ tracker.claim('/tmp/file.txt', runId(1));
111
+ events.length = 0;
112
+ const ok = tracker.release('/tmp/file.txt', runId(2));
113
+ expect(ok).toBe(false);
114
+ expect(tracker.getOwner('/tmp/file.txt')).toBe(runId(1));
115
+ expect(events).toEqual([]);
116
+ });
117
+ });
118
+ describe('transfer', () => {
119
+ it('transfers ownership from current owner to another — atomic, single event', () => {
120
+ tracker.claim('/tmp/file.txt', runId(1));
121
+ events.length = 0;
122
+ const ok = tracker.transfer('/tmp/file.txt', runId(1), runId(2));
123
+ expect(ok).toBe(true);
124
+ expect(tracker.getOwner('/tmp/file.txt')).toBe(runId(2));
125
+ expect(events).toEqual([
126
+ {
127
+ type: 'ownership_transferred',
128
+ filePath: path.resolve('/tmp/file.txt'),
129
+ from: runId(1),
130
+ to: runId(2),
131
+ },
132
+ ]);
133
+ });
134
+ it('returns false when the `from` argument is not the current owner — no emit', () => {
135
+ tracker.claim('/tmp/file.txt', runId(1));
136
+ events.length = 0;
137
+ const ok = tracker.transfer('/tmp/file.txt', runId(99), runId(2));
138
+ expect(ok).toBe(false);
139
+ expect(tracker.getOwner('/tmp/file.txt')).toBe(runId(1));
140
+ expect(events).toEqual([]);
141
+ });
142
+ it('returns false when no ownership exists — no emit', () => {
143
+ const ok = tracker.transfer('/tmp/file.txt', runId(1), runId(2));
144
+ expect(ok).toBe(false);
145
+ expect(events).toEqual([]);
146
+ });
147
+ it('refreshes claimedAt on successful transfer', async () => {
148
+ tracker.claim('/tmp/file.txt', runId(1));
149
+ const t0 = tracker.getOwner('/tmp/file.txt');
150
+ expect(t0).toBe(runId(1));
151
+ await new Promise((r) => setTimeout(r, 2));
152
+ tracker.transfer('/tmp/file.txt', runId(1), runId(2));
153
+ const list = tracker.listByOwner(runId(2));
154
+ expect(list).toHaveLength(1);
155
+ const after = list[0];
156
+ expect(after?.claimedAt).toBeGreaterThan(0);
157
+ expect(after?.owner).toBe(runId(2));
158
+ });
159
+ });
160
+ describe('releaseAll', () => {
161
+ it('releases every ownership for the owner, returns count, emits per-entry', () => {
162
+ tracker.claim('/tmp/a.txt', runId(1));
163
+ tracker.claim('/tmp/b.txt', runId(1));
164
+ tracker.claim('/tmp/c.txt', runId(2));
165
+ events.length = 0;
166
+ const count = tracker.releaseAll(runId(1));
167
+ expect(count).toBe(2);
168
+ expect(tracker.getOwner('/tmp/a.txt')).toBeUndefined();
169
+ expect(tracker.getOwner('/tmp/b.txt')).toBeUndefined();
170
+ expect(tracker.getOwner('/tmp/c.txt')).toBe(runId(2));
171
+ const released = events.filter((e) => e.type === 'ownership_released');
172
+ expect(released.length).toBe(2);
173
+ for (const e of released) {
174
+ if (e.type === 'ownership_released') {
175
+ expect(e.previousOwner).toBe(runId(1));
176
+ }
177
+ }
178
+ });
179
+ it('returns 0 when the owner has no entries', () => {
180
+ const count = tracker.releaseAll(runId(99));
181
+ expect(count).toBe(0);
182
+ expect(events).toEqual([]);
183
+ });
184
+ });
185
+ describe('read helpers', () => {
186
+ it('getOwner returns undefined for unclaimed paths', () => {
187
+ expect(tracker.getOwner('/tmp/anything.txt')).toBeUndefined();
188
+ });
189
+ it('listByOwner returns all ownerships for a given owner', () => {
190
+ tracker.claim('/tmp/a.txt', runId(1));
191
+ tracker.claim('/tmp/b.txt', runId(1));
192
+ tracker.claim('/tmp/c.txt', runId(2));
193
+ const list = tracker.listByOwner(runId(1));
194
+ expect(list.length).toBe(2);
195
+ expect(new Set(list.map((o) => o.filePath))).toEqual(new Set([path.resolve('/tmp/a.txt'), path.resolve('/tmp/b.txt')]));
196
+ });
197
+ it('checkConflict returns the current owner iff a different owner holds the file', () => {
198
+ tracker.claim('/tmp/file.txt', runId(1));
199
+ expect(tracker.checkConflict('/tmp/file.txt', runId(1))).toBeUndefined();
200
+ expect(tracker.checkConflict('/tmp/file.txt', runId(2))).toBe(runId(1));
201
+ expect(tracker.checkConflict('/tmp/other.txt', runId(2))).toBeUndefined();
202
+ });
203
+ });
204
+ });
205
+ //# sourceMappingURL=ownership.test.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"ownership.test.js","sourceRoot":"","sources":["../../src/bus/ownership.test.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,21 @@
1
+ /**
2
+ * Current-code invariants asserted (2026-04-21, ses_006 Phase 5):
3
+ *
4
+ * - `BaseConnector` is abstract. Each concrete subclass sets id /
5
+ * name / description / connectionType / configSchema / methods
6
+ * and implements connect / disconnect / healthCheck / execute.
7
+ * - `toDefinition()` projects the abstract readonly fields into a
8
+ * `ConnectorDefinition<TConfig>` — used to register the connector
9
+ * with the `ConnectorRegistry`.
10
+ * - `findMethod(name)` returns the method by name or undefined.
11
+ * - `requireMethod(name)` throws with the method name + available
12
+ * names when not found.
13
+ * - `validateInput(method, input)`: zod.safeParse; on failure
14
+ * throws `Invalid input for method "<name>": <joined issues>`.
15
+ * - `measureExecution(fn)` returns `{result, durationMs}` with
16
+ * durationMs rounded.
17
+ * - Auth resolution lives in subclasses (see HttpConnector tests),
18
+ * not in the base class.
19
+ */
20
+ export {};
21
+ //# sourceMappingURL=BaseConnector.test.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"BaseConnector.test.d.ts","sourceRoot":"","sources":["../../src/connector/BaseConnector.test.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;;;;GAkBG"}
@@ -0,0 +1,108 @@
1
+ /**
2
+ * Current-code invariants asserted (2026-04-21, ses_006 Phase 5):
3
+ *
4
+ * - `BaseConnector` is abstract. Each concrete subclass sets id /
5
+ * name / description / connectionType / configSchema / methods
6
+ * and implements connect / disconnect / healthCheck / execute.
7
+ * - `toDefinition()` projects the abstract readonly fields into a
8
+ * `ConnectorDefinition<TConfig>` — used to register the connector
9
+ * with the `ConnectorRegistry`.
10
+ * - `findMethod(name)` returns the method by name or undefined.
11
+ * - `requireMethod(name)` throws with the method name + available
12
+ * names when not found.
13
+ * - `validateInput(method, input)`: zod.safeParse; on failure
14
+ * throws `Invalid input for method "<name>": <joined issues>`.
15
+ * - `measureExecution(fn)` returns `{result, durationMs}` with
16
+ * durationMs rounded.
17
+ * - Auth resolution lives in subclasses (see HttpConnector tests),
18
+ * not in the base class.
19
+ */
20
+ import { describe, expect, it } from 'vitest';
21
+ import { z } from 'zod';
22
+ import { BaseConnector } from './BaseConnector.js';
23
+ class TestConnector extends BaseConnector {
24
+ id = 'conn_test';
25
+ name = 'Test';
26
+ description = 'Test connector';
27
+ connectionType = 'custom';
28
+ configSchema = z.object({ base: z.string() });
29
+ methods = [
30
+ {
31
+ name: 'echo',
32
+ description: 'echo',
33
+ inputSchema: z.object({ value: z.string() }),
34
+ },
35
+ ];
36
+ async connect() { }
37
+ async disconnect() { }
38
+ async healthCheck() {
39
+ return true;
40
+ }
41
+ async execute() {
42
+ return { success: true, output: 'ok', durationMs: 0 };
43
+ }
44
+ // Expose protected methods for direct tests:
45
+ publicRequireMethod(name) {
46
+ return this.requireMethod(name);
47
+ }
48
+ publicValidateInput(method, input) {
49
+ return this.validateInput(method, input);
50
+ }
51
+ publicMeasureExecution(fn) {
52
+ return this.measureExecution(fn);
53
+ }
54
+ // Exposed internal auth resolver on a subclass is a sibling concern —
55
+ // `BaseConnector` does not define any auth handling; the field is
56
+ // just stored.
57
+ getStoredAuth() {
58
+ return this.auth;
59
+ }
60
+ }
61
+ describe('BaseConnector', () => {
62
+ it('toDefinition projects abstract readonly fields', () => {
63
+ const c = new TestConnector();
64
+ const def = c.toDefinition();
65
+ expect(def.id).toBe('conn_test');
66
+ expect(def.name).toBe('Test');
67
+ expect(def.description).toBe('Test connector');
68
+ expect(def.connectionType).toBe('custom');
69
+ expect(def.methods).toHaveLength(1);
70
+ });
71
+ it('findMethod returns undefined for an unknown name', () => {
72
+ const c = new TestConnector();
73
+ expect(c.publicRequireMethod).toBeDefined();
74
+ // findMethod is invoked indirectly via requireMethod — we cover the
75
+ // positive + negative paths below.
76
+ });
77
+ it('requireMethod returns the method when present', () => {
78
+ const c = new TestConnector();
79
+ const method = c.publicRequireMethod('echo');
80
+ expect(method.name).toBe('echo');
81
+ });
82
+ it('requireMethod throws naming the missing method + available names', () => {
83
+ const c = new TestConnector();
84
+ expect(() => c.publicRequireMethod('nope')).toThrow(/Method "nope" not found/);
85
+ expect(() => c.publicRequireMethod('nope')).toThrow(/Available: echo/);
86
+ });
87
+ it('validateInput passes through parsed data on success', () => {
88
+ const c = new TestConnector();
89
+ const method = c.publicRequireMethod('echo');
90
+ expect(c.publicValidateInput(method, { value: 'hi' })).toEqual({ value: 'hi' });
91
+ });
92
+ it('validateInput throws with joined issue messages on failure', () => {
93
+ const c = new TestConnector();
94
+ const method = c.publicRequireMethod('echo');
95
+ expect(() => c.publicValidateInput(method, { value: 123 })).toThrow(/Invalid input for method "echo"/);
96
+ });
97
+ it('measureExecution returns the result + rounded durationMs', async () => {
98
+ const c = new TestConnector();
99
+ const { result, durationMs } = await c.publicMeasureExecution(async () => {
100
+ await new Promise((r) => setTimeout(r, 5));
101
+ return 42;
102
+ });
103
+ expect(result).toBe(42);
104
+ expect(durationMs).toBeGreaterThanOrEqual(0);
105
+ expect(Number.isInteger(durationMs)).toBe(true);
106
+ });
107
+ });
108
+ //# sourceMappingURL=BaseConnector.test.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"BaseConnector.test.js","sourceRoot":"","sources":["../../src/connector/BaseConnector.test.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,30 @@
1
+ /**
2
+ * Current-code invariants asserted (2026-04-21, ses_006 Phase 5):
3
+ *
4
+ * - `HttpConnector.connect` stores config + auth, strips trailing
5
+ * slashes from baseUrl, merges default headers with auth-derived
6
+ * headers.
7
+ * - Auth resolution (http only — webhook has its own):
8
+ * - `api_key` with `apiKey` + optional `headerName` (default
9
+ * `X-API-Key`).
10
+ * - `bearer` with `token` → `Authorization: Bearer <token>`.
11
+ * - `basic` with `username` + `password` → base64 encoded.
12
+ * - `none` / `oauth2` / `custom` → no headers.
13
+ * - Missing required credential fields throw a typed error string.
14
+ * - `disconnect` clears internal state.
15
+ * - `healthCheck` HEAD-fetches baseUrl with a 5s timeout; returns
16
+ * true iff `response.ok || response.status < 500`; false on any
17
+ * thrown fetch (e.g. timeout abort).
18
+ * - `execute("request", input)`:
19
+ * - `requireMethod` + `validateInput` run.
20
+ * - Builds URL from `baseUrl + path` + appends query params.
21
+ * - Sends default+input headers; auto-sets `Content-Type:
22
+ * application/json` when a body is present and no content-type
23
+ * was passed.
24
+ * - Parses response JSON when `content-type: application/json`,
25
+ * else text.
26
+ * - `success: true` iff status in [200, 400). Metadata includes
27
+ * status + statusText.
28
+ */
29
+ export {};
30
+ //# sourceMappingURL=http.test.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"http.test.d.ts","sourceRoot":"","sources":["../../../src/connector/builtins/http.test.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;;;;;;;;;;;;;GA2BG"}
@@ -0,0 +1,232 @@
1
+ /**
2
+ * Current-code invariants asserted (2026-04-21, ses_006 Phase 5):
3
+ *
4
+ * - `HttpConnector.connect` stores config + auth, strips trailing
5
+ * slashes from baseUrl, merges default headers with auth-derived
6
+ * headers.
7
+ * - Auth resolution (http only — webhook has its own):
8
+ * - `api_key` with `apiKey` + optional `headerName` (default
9
+ * `X-API-Key`).
10
+ * - `bearer` with `token` → `Authorization: Bearer <token>`.
11
+ * - `basic` with `username` + `password` → base64 encoded.
12
+ * - `none` / `oauth2` / `custom` → no headers.
13
+ * - Missing required credential fields throw a typed error string.
14
+ * - `disconnect` clears internal state.
15
+ * - `healthCheck` HEAD-fetches baseUrl with a 5s timeout; returns
16
+ * true iff `response.ok || response.status < 500`; false on any
17
+ * thrown fetch (e.g. timeout abort).
18
+ * - `execute("request", input)`:
19
+ * - `requireMethod` + `validateInput` run.
20
+ * - Builds URL from `baseUrl + path` + appends query params.
21
+ * - Sends default+input headers; auto-sets `Content-Type:
22
+ * application/json` when a body is present and no content-type
23
+ * was passed.
24
+ * - Parses response JSON when `content-type: application/json`,
25
+ * else text.
26
+ * - `success: true` iff status in [200, 400). Metadata includes
27
+ * status + statusText.
28
+ */
29
+ import { afterEach, beforeEach, describe, expect, it, vi } from 'vitest';
30
+ import { HttpConnector } from './http.js';
31
+ function makeResponse(init) {
32
+ const headers = new Headers(init.headers ?? { 'content-type': 'application/json' });
33
+ return {
34
+ ok: (init.status ?? 200) < 400,
35
+ status: init.status ?? 200,
36
+ statusText: init.statusText ?? 'OK',
37
+ headers,
38
+ json: async () => init.body,
39
+ text: async () => String(init.body ?? ''),
40
+ };
41
+ }
42
+ describe('HttpConnector', () => {
43
+ let fetchMock;
44
+ beforeEach(() => {
45
+ fetchMock = vi.fn();
46
+ global.fetch = fetchMock;
47
+ });
48
+ afterEach(() => {
49
+ vi.restoreAllMocks();
50
+ });
51
+ describe('connect + disconnect', () => {
52
+ it('strips trailing slashes from baseUrl', async () => {
53
+ const c = new HttpConnector();
54
+ await c.connect({ baseUrl: 'https://api.example.com//', timeoutMs: 30_000 });
55
+ // Follow-up request lands on the cleaned URL:
56
+ fetchMock.mockResolvedValueOnce(makeResponse({ status: 200, body: { ok: true } }));
57
+ await c.execute('request', { method: 'GET', path: 'x' });
58
+ expect(fetchMock).toHaveBeenCalledWith('https://api.example.com/x', expect.any(Object));
59
+ });
60
+ it('disconnect clears internal state; execute after disconnect treats baseUrl as empty', async () => {
61
+ const c = new HttpConnector();
62
+ await c.connect({ baseUrl: 'https://api.example.com', timeoutMs: 30_000 });
63
+ await c.disconnect();
64
+ expect(await c.healthCheck()).toBe(false);
65
+ });
66
+ });
67
+ describe('auth resolution', () => {
68
+ it('api_key default header name = X-API-Key', async () => {
69
+ const c = new HttpConnector();
70
+ await c.connect({ baseUrl: 'https://api.example.com' }, { type: 'api_key', credentials: { apiKey: 'secret' } });
71
+ fetchMock.mockResolvedValueOnce(makeResponse({ status: 200, body: {} }));
72
+ await c.execute('request', { method: 'GET', path: 'x' });
73
+ const headers = fetchMock.mock.calls[0]?.[1].headers;
74
+ expect(headers['X-API-Key']).toBe('secret');
75
+ });
76
+ it('api_key custom header name is honored', async () => {
77
+ const c = new HttpConnector();
78
+ await c.connect({ baseUrl: 'https://api.example.com' }, { type: 'api_key', credentials: { apiKey: 'secret', headerName: 'X-Custom' } });
79
+ fetchMock.mockResolvedValueOnce(makeResponse({ status: 200, body: {} }));
80
+ await c.execute('request', { method: 'GET', path: 'x' });
81
+ const headers = fetchMock.mock.calls[0]?.[1].headers;
82
+ expect(headers['X-Custom']).toBe('secret');
83
+ });
84
+ it('bearer sets Authorization: Bearer <token>', async () => {
85
+ const c = new HttpConnector();
86
+ await c.connect({ baseUrl: 'https://api.example.com' }, { type: 'bearer', credentials: { token: 'tkn' } });
87
+ fetchMock.mockResolvedValueOnce(makeResponse({ status: 200, body: {} }));
88
+ await c.execute('request', { method: 'GET', path: 'x' });
89
+ const headers = fetchMock.mock.calls[0]?.[1].headers;
90
+ expect(headers.Authorization).toBe('Bearer tkn');
91
+ });
92
+ it('basic encodes username:password as base64', async () => {
93
+ const c = new HttpConnector();
94
+ await c.connect({ baseUrl: 'https://api.example.com' }, { type: 'basic', credentials: { username: 'alice', password: 'pw' } });
95
+ fetchMock.mockResolvedValueOnce(makeResponse({ status: 200, body: {} }));
96
+ await c.execute('request', { method: 'GET', path: 'x' });
97
+ const headers = fetchMock.mock.calls[0]?.[1].headers;
98
+ expect(headers.Authorization).toBe(`Basic ${btoa('alice:pw')}`);
99
+ });
100
+ it('none / oauth2 / custom add no auth headers', async () => {
101
+ for (const type of ['none', 'oauth2', 'custom']) {
102
+ const c = new HttpConnector();
103
+ await c.connect({ baseUrl: 'https://api.example.com' }, { type, credentials: {} });
104
+ fetchMock.mockResolvedValueOnce(makeResponse({ status: 200, body: {} }));
105
+ await c.execute('request', { method: 'GET', path: 'x' });
106
+ const headers = fetchMock.mock.calls.at(-1)?.[1].headers;
107
+ expect(headers.Authorization).toBeUndefined();
108
+ expect(headers['X-API-Key']).toBeUndefined();
109
+ }
110
+ });
111
+ it('api_key throws when apiKey is missing', async () => {
112
+ const c = new HttpConnector();
113
+ await expect(c.connect({ baseUrl: 'https://api.example.com' }, { type: 'api_key', credentials: {} })).rejects.toThrow(/missing required credential "apiKey"/);
114
+ });
115
+ it('bearer throws when token is missing', async () => {
116
+ const c = new HttpConnector();
117
+ await expect(c.connect({ baseUrl: 'https://api.example.com' }, { type: 'bearer', credentials: {} })).rejects.toThrow(/missing required credential "token"/);
118
+ });
119
+ it('basic throws when either username or password is missing', async () => {
120
+ const c = new HttpConnector();
121
+ await expect(c.connect({ baseUrl: 'https://api.example.com' }, { type: 'basic', credentials: { username: 'a' } })).rejects.toThrow(/missing required credentials/);
122
+ });
123
+ });
124
+ describe('healthCheck', () => {
125
+ it('returns true for ok responses', async () => {
126
+ const c = new HttpConnector();
127
+ await c.connect({ baseUrl: 'https://api.example.com' });
128
+ fetchMock.mockResolvedValueOnce(makeResponse({ status: 200 }));
129
+ expect(await c.healthCheck()).toBe(true);
130
+ });
131
+ it('returns true for 4xx (not-ok but < 500)', async () => {
132
+ const c = new HttpConnector();
133
+ await c.connect({ baseUrl: 'https://api.example.com' });
134
+ fetchMock.mockResolvedValueOnce(makeResponse({ status: 404 }));
135
+ expect(await c.healthCheck()).toBe(true);
136
+ });
137
+ it('returns false for 5xx', async () => {
138
+ const c = new HttpConnector();
139
+ await c.connect({ baseUrl: 'https://api.example.com' });
140
+ fetchMock.mockResolvedValueOnce(makeResponse({ status: 503 }));
141
+ expect(await c.healthCheck()).toBe(false);
142
+ });
143
+ it('returns false on thrown fetch', async () => {
144
+ const c = new HttpConnector();
145
+ await c.connect({ baseUrl: 'https://api.example.com' });
146
+ fetchMock.mockRejectedValueOnce(new Error('timeout'));
147
+ expect(await c.healthCheck()).toBe(false);
148
+ });
149
+ it('returns false when never connected', async () => {
150
+ const c = new HttpConnector();
151
+ expect(await c.healthCheck()).toBe(false);
152
+ });
153
+ });
154
+ describe('execute', () => {
155
+ it('returns success:true for 2xx + 3xx responses', async () => {
156
+ const c = new HttpConnector();
157
+ await c.connect({ baseUrl: 'https://api.example.com' });
158
+ fetchMock.mockResolvedValueOnce(makeResponse({ status: 200, body: { ok: 1 } }));
159
+ const result = await c.execute('request', { method: 'GET', path: 'thing' });
160
+ expect(result.success).toBe(true);
161
+ expect(result.output).toMatchObject({ status: 200 });
162
+ });
163
+ it('returns success:false for 4xx / 5xx responses', async () => {
164
+ const c = new HttpConnector();
165
+ await c.connect({ baseUrl: 'https://api.example.com' });
166
+ fetchMock.mockResolvedValueOnce(makeResponse({ status: 500, body: { err: 1 } }));
167
+ const result = await c.execute('request', { method: 'GET', path: 'thing' });
168
+ expect(result.success).toBe(false);
169
+ expect(result.metadata).toMatchObject({ status: 500 });
170
+ });
171
+ it('sets Content-Type: application/json when body is set and none provided', async () => {
172
+ const c = new HttpConnector();
173
+ await c.connect({ baseUrl: 'https://api.example.com' });
174
+ fetchMock.mockResolvedValueOnce(makeResponse({ status: 200, body: {} }));
175
+ await c.execute('request', {
176
+ method: 'POST',
177
+ path: 'thing',
178
+ body: { k: 'v' },
179
+ });
180
+ const headers = fetchMock.mock.calls[0]?.[1].headers;
181
+ expect(headers['Content-Type']).toBe('application/json');
182
+ });
183
+ it('preserves caller-supplied Content-Type', async () => {
184
+ const c = new HttpConnector();
185
+ await c.connect({ baseUrl: 'https://api.example.com' });
186
+ fetchMock.mockResolvedValueOnce(makeResponse({ status: 200, body: '' }));
187
+ await c.execute('request', {
188
+ method: 'POST',
189
+ path: 'thing',
190
+ body: 'raw',
191
+ headers: { 'Content-Type': 'text/plain' },
192
+ });
193
+ const headers = fetchMock.mock.calls[0]?.[1].headers;
194
+ expect(headers['Content-Type']).toBe('text/plain');
195
+ });
196
+ it('appends query params to the URL', async () => {
197
+ const c = new HttpConnector();
198
+ await c.connect({ baseUrl: 'https://api.example.com' });
199
+ fetchMock.mockResolvedValueOnce(makeResponse({ status: 200, body: {} }));
200
+ await c.execute('request', {
201
+ method: 'GET',
202
+ path: 'thing',
203
+ query: { a: '1', b: '2' },
204
+ });
205
+ expect(fetchMock.mock.calls[0]?.[0]).toBe('https://api.example.com/thing?a=1&b=2');
206
+ });
207
+ it('parses JSON response when content-type is json', async () => {
208
+ const c = new HttpConnector();
209
+ await c.connect({ baseUrl: 'https://api.example.com' });
210
+ fetchMock.mockResolvedValueOnce(makeResponse({
211
+ status: 200,
212
+ headers: { 'content-type': 'application/json' },
213
+ body: { ok: 1 },
214
+ }));
215
+ const result = await c.execute('request', { method: 'GET', path: 'x' });
216
+ expect(result.output.body).toEqual({ ok: 1 });
217
+ });
218
+ it('returns text body for non-JSON content-type', async () => {
219
+ const c = new HttpConnector();
220
+ await c.connect({ baseUrl: 'https://api.example.com' });
221
+ fetchMock.mockResolvedValueOnce(makeResponse({ status: 200, headers: { 'content-type': 'text/plain' }, body: 'hello' }));
222
+ const result = await c.execute('request', { method: 'GET', path: 'x' });
223
+ expect(result.output.body).toBe('hello');
224
+ });
225
+ it('throws on invalid input (unknown method)', async () => {
226
+ const c = new HttpConnector();
227
+ await c.connect({ baseUrl: 'https://api.example.com' });
228
+ await expect(c.execute('not-a-method', {})).rejects.toThrow(/not found/);
229
+ });
230
+ });
231
+ });
232
+ //# sourceMappingURL=http.test.js.map