whale-code 6.4.0 → 6.5.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 (187) hide show
  1. package/bin/swagmanager-mcp.js +7 -0
  2. package/dist/cli/app.js +30 -2
  3. package/dist/cli/chat/ChatApp.d.ts +4 -4
  4. package/dist/cli/chat/ChatApp.js +114 -44
  5. package/dist/cli/chat/ChatInput.d.ts +13 -6
  6. package/dist/cli/chat/ChatInput.js +433 -89
  7. package/dist/cli/chat/MemoryManager.d.ts +15 -0
  8. package/dist/cli/chat/MemoryManager.js +61 -0
  9. package/dist/cli/chat/MessageList.d.ts +8 -0
  10. package/dist/cli/chat/MessageList.js +1 -1
  11. package/dist/cli/chat/NodeManager.d.ts +30 -0
  12. package/dist/cli/chat/NodeManager.js +89 -0
  13. package/dist/cli/chat/NodeSelector.d.ts +19 -0
  14. package/dist/cli/chat/NodeSelector.js +37 -0
  15. package/dist/cli/chat/PlanApproval.d.ts +17 -0
  16. package/dist/cli/chat/PlanApproval.js +82 -0
  17. package/dist/cli/chat/SessionManager.d.ts +16 -0
  18. package/dist/cli/chat/SessionManager.js +43 -0
  19. package/dist/cli/chat/SlashMenu.d.ts +38 -0
  20. package/dist/cli/chat/SlashMenu.js +208 -0
  21. package/dist/cli/chat/StatusBar.d.ts +16 -0
  22. package/dist/cli/chat/StatusBar.js +22 -0
  23. package/dist/cli/chat/ThemeSelector.d.ts +14 -0
  24. package/dist/cli/chat/ThemeSelector.js +29 -0
  25. package/dist/cli/chat/ToolIndicator.d.ts +8 -0
  26. package/dist/cli/chat/ToolIndicator.js +33 -9
  27. package/dist/cli/chat/hooks/useAgentLoop.d.ts +2 -1
  28. package/dist/cli/chat/hooks/useAgentLoop.js +22 -17
  29. package/dist/cli/chat/hooks/useSlashCommands.d.ts +19 -0
  30. package/dist/cli/chat/hooks/useSlashCommands.js +254 -15
  31. package/dist/cli/commands/config-cmd.js +4 -25
  32. package/dist/cli/commands/db.d.ts +13 -0
  33. package/dist/cli/commands/db.js +243 -0
  34. package/dist/cli/commands/doctor.js +6 -9
  35. package/dist/cli/commands/mcp.js +1 -20
  36. package/dist/cli/services/agent-events.d.ts +22 -1
  37. package/dist/cli/services/agent-events.js +9 -0
  38. package/dist/cli/services/agent-loop.js +66 -2
  39. package/dist/cli/services/agent-worker-base.js +21 -6
  40. package/dist/cli/services/api-retry.d.ts +25 -0
  41. package/dist/cli/services/api-retry.js +91 -0
  42. package/dist/cli/services/auth-service.d.ts +1 -1
  43. package/dist/cli/services/auth-service.js +40 -19
  44. package/dist/cli/services/background-processes.js +26 -2
  45. package/dist/cli/services/config-store.d.ts +13 -1
  46. package/dist/cli/services/config-store.js +116 -13
  47. package/dist/cli/services/format-server-response.js +12 -6
  48. package/dist/cli/services/ink-resize-fix.d.ts +18 -0
  49. package/dist/cli/services/ink-resize-fix.js +66 -0
  50. package/dist/cli/services/interactive-tools.d.ts +14 -0
  51. package/dist/cli/services/interactive-tools.js +47 -2
  52. package/dist/cli/services/keybinding-manager.js +1 -1
  53. package/dist/cli/services/local-tools.js +35 -2
  54. package/dist/cli/services/server-tools.js +175 -3
  55. package/dist/cli/services/subagent.js +15 -3
  56. package/dist/cli/services/system-prompt.js +5 -3
  57. package/dist/cli/services/task-decomposer.d.ts +35 -0
  58. package/dist/cli/services/task-decomposer.js +199 -0
  59. package/dist/cli/services/team-lead.d.ts +18 -0
  60. package/dist/cli/services/team-lead.js +80 -0
  61. package/dist/cli/services/teammate.js +5 -5
  62. package/dist/cli/services/telemetry.d.ts +8 -2
  63. package/dist/cli/services/telemetry.js +116 -92
  64. package/dist/cli/services/tools/agent-tools.d.ts +1 -0
  65. package/dist/cli/services/tools/agent-tools.js +50 -4
  66. package/dist/cli/services/tools/file-ops.d.ts +2 -0
  67. package/dist/cli/services/tools/file-ops.js +71 -19
  68. package/dist/cli/services/tools/shell-exec.js +22 -12
  69. package/dist/cli/shared/Theme.d.ts +1 -2
  70. package/dist/cli/shared/Theme.js +1 -1
  71. package/dist/cli/shared/WhaleBanner.d.ts +4 -1
  72. package/dist/cli/shared/WhaleBanner.js +12 -8
  73. package/dist/cli/shared/markdown.d.ts +5 -4
  74. package/dist/cli/shared/markdown.js +376 -334
  75. package/dist/cli/shared/theme-manager.d.ts +27 -0
  76. package/dist/cli/shared/theme-manager.js +178 -0
  77. package/dist/cli/shared/theme-presets.d.ts +16 -0
  78. package/dist/cli/shared/theme-presets.js +265 -0
  79. package/dist/index.js +0 -51
  80. package/dist/node/adapters/imessage.d.ts +10 -0
  81. package/dist/node/adapters/imessage.js +45 -6
  82. package/dist/node/cli.js +459 -8
  83. package/dist/node/config.d.ts +17 -0
  84. package/dist/node/gateway-client.d.ts +55 -0
  85. package/dist/node/gateway-client.js +201 -0
  86. package/dist/node/portal/clipboard.d.ts +28 -0
  87. package/dist/node/portal/clipboard.js +183 -0
  88. package/dist/node/portal/discovery.d.ts +29 -0
  89. package/dist/node/portal/discovery.js +61 -0
  90. package/dist/node/portal/forward.d.ts +30 -0
  91. package/dist/node/portal/forward.js +90 -0
  92. package/dist/node/portal/index.d.ts +47 -0
  93. package/dist/node/portal/index.js +250 -0
  94. package/dist/node/portal/multiplexer.d.ts +48 -0
  95. package/dist/node/portal/multiplexer.js +207 -0
  96. package/dist/node/portal/permissions.d.ts +36 -0
  97. package/dist/node/portal/permissions.js +131 -0
  98. package/dist/node/portal/protocol.d.ts +140 -0
  99. package/dist/node/portal/protocol.js +193 -0
  100. package/dist/node/portal/screen.d.ts +18 -0
  101. package/dist/node/portal/screen.js +93 -0
  102. package/dist/node/portal/session.d.ts +68 -0
  103. package/dist/node/portal/session.js +127 -0
  104. package/dist/node/portal/shell.d.ts +26 -0
  105. package/dist/node/portal/shell.js +142 -0
  106. package/dist/node/portal/stream.d.ts +43 -0
  107. package/dist/node/portal/stream.js +90 -0
  108. package/dist/node/portal/transfer.d.ts +33 -0
  109. package/dist/node/portal/transfer.js +231 -0
  110. package/dist/node/portal/ui.d.ts +16 -0
  111. package/dist/node/portal/ui.js +148 -0
  112. package/dist/node/remote-desktop/compile-helper.d.ts +13 -0
  113. package/dist/node/remote-desktop/compile-helper.js +73 -0
  114. package/dist/node/remote-desktop/index.d.ts +67 -0
  115. package/dist/node/remote-desktop/index.js +220 -0
  116. package/dist/node/remote-desktop/protocol.d.ts +96 -0
  117. package/dist/node/remote-desktop/protocol.js +67 -0
  118. package/dist/node/runtime.d.ts +8 -1
  119. package/dist/node/runtime.js +117 -9
  120. package/dist/server/handlers/__test-utils__/test-db.d.ts +25 -0
  121. package/dist/server/handlers/__test-utils__/test-db.js +128 -0
  122. package/dist/server/handlers/api-keys.js +26 -2
  123. package/dist/server/handlers/browser.d.ts +0 -4
  124. package/dist/server/handlers/browser.js +0 -46
  125. package/dist/server/handlers/catalog.js +37 -14
  126. package/dist/server/handlers/clickhouse.d.ts +10 -0
  127. package/dist/server/handlers/clickhouse.js +215 -0
  128. package/dist/server/handlers/comms.d.ts +308 -4
  129. package/dist/server/handlers/comms.js +444 -11
  130. package/dist/server/handlers/creations.js +1 -1
  131. package/dist/server/handlers/crm.d.ts +54 -8
  132. package/dist/server/handlers/crm.js +353 -68
  133. package/dist/server/handlers/embeddings.js +3 -3
  134. package/dist/server/handlers/enrichment.js +39 -55
  135. package/dist/server/handlers/inventory.js +1 -1
  136. package/dist/server/handlers/kali.d.ts +9 -1
  137. package/dist/server/handlers/kali.js +50 -1
  138. package/dist/server/handlers/media.d.ts +8 -0
  139. package/dist/server/handlers/media.js +902 -0
  140. package/dist/server/handlers/meta-ads.js +6 -3
  141. package/dist/server/handlers/nodes.d.ts +2 -0
  142. package/dist/server/handlers/nodes.js +331 -40
  143. package/dist/server/handlers/operations.d.ts +4 -6
  144. package/dist/server/handlers/operations.js +99 -38
  145. package/dist/server/handlers/platform.js +224 -107
  146. package/dist/server/handlers/remove-bg.d.ts +6 -0
  147. package/dist/server/handlers/remove-bg.js +96 -0
  148. package/dist/server/handlers/storefront.d.ts +6 -0
  149. package/dist/server/handlers/storefront.js +477 -0
  150. package/dist/server/handlers/supply-chain.js +21 -3
  151. package/dist/server/handlers/workflow-steps.js +87 -31
  152. package/dist/server/handlers/workflows.js +4 -1
  153. package/dist/server/index.js +334 -88
  154. package/dist/server/lib/clickhouse-buffer.d.ts +48 -0
  155. package/dist/server/lib/clickhouse-buffer.js +175 -0
  156. package/dist/server/lib/clickhouse-client.d.ts +112 -0
  157. package/dist/server/lib/clickhouse-client.js +141 -0
  158. package/dist/server/lib/coa-renderer.d.ts +91 -0
  159. package/dist/server/lib/coa-renderer.js +411 -0
  160. package/dist/server/lib/compaction-service.js +45 -1
  161. package/dist/server/lib/pdf-renderer.d.ts +143 -0
  162. package/dist/server/lib/pdf-renderer.js +867 -0
  163. package/dist/server/lib/react-pdf-layout.d.ts +40 -0
  164. package/dist/server/lib/react-pdf-layout.js +437 -0
  165. package/dist/server/lib/server-agent-loop.d.ts +2 -0
  166. package/dist/server/lib/server-agent-loop.js +61 -15
  167. package/dist/server/lib/server-subagent.d.ts +3 -0
  168. package/dist/server/lib/server-subagent.js +7 -4
  169. package/dist/server/lib/supabase-client.js +51 -3
  170. package/dist/server/lib/template-resolver.js +14 -4
  171. package/dist/server/lib/utils.js +15 -0
  172. package/dist/server/local-agent-gateway.d.ts +44 -0
  173. package/dist/server/local-agent-gateway.js +389 -49
  174. package/dist/server/providers/anthropic.js +12 -2
  175. package/dist/server/providers/gemini.js +17 -2
  176. package/dist/server/proxy-handlers.js +151 -0
  177. package/dist/server/tool-router.d.ts +2 -2
  178. package/dist/server/tool-router.js +25 -35
  179. package/dist/shared/agent-core.d.ts +5 -2
  180. package/dist/shared/agent-core.js +30 -4
  181. package/dist/shared/api-client.js +54 -3
  182. package/dist/shared/sse-parser.d.ts +1 -1
  183. package/dist/shared/sse-parser.js +5 -2
  184. package/dist/shared/tool-dispatch.js +1 -1
  185. package/package.json +16 -10
  186. package/dist/server/handlers/__test-utils__/mock-supabase.d.ts +0 -11
  187. package/dist/server/handlers/__test-utils__/mock-supabase.js +0 -393
@@ -1,393 +0,0 @@
1
- // __test-utils__/mock-supabase.ts — Reusable mock Supabase client for handler tests
2
- //
3
- // Provides an in-memory Supabase client mock with chainable query builder methods
4
- // that mirror the real SupabaseClient interface used by all handlers.
5
- import { vi } from "vitest";
6
- // ---------------------------------------------------------------------------
7
- // In-memory stores
8
- // ---------------------------------------------------------------------------
9
- /** Per-table row arrays keyed by table name */
10
- let tableData = {};
11
- /** Per-RPC function response stubs keyed by RPC name */
12
- let rpcResponses = {};
13
- /** Per-table forced errors (simulates DB failures) */
14
- let tableErrors = {};
15
- // ---------------------------------------------------------------------------
16
- // Public helpers
17
- // ---------------------------------------------------------------------------
18
- /** Pre-populate a table with rows for the current test */
19
- export function setTableData(table, rows) {
20
- tableData[table] = [...rows];
21
- }
22
- /** Pre-configure the return value for an RPC call */
23
- export function setRpcResponse(name, data, error) {
24
- rpcResponses[name] = { data: data ?? null, error: error ?? null };
25
- }
26
- /** Force a table to return an error on any operation */
27
- export function setTableError(table, message, code) {
28
- tableErrors[table] = { message, code };
29
- }
30
- /** Reset all in-memory state between tests */
31
- export function resetMock() {
32
- tableData = {};
33
- rpcResponses = {};
34
- tableErrors = {};
35
- }
36
- /** Get current in-memory rows for a table (for post-operation assertions) */
37
- export function getTableData(table) {
38
- return tableData[table] || [];
39
- }
40
- function defaultState(table) {
41
- return {
42
- table,
43
- selectColumns: "*",
44
- filters: [],
45
- orderCol: null,
46
- orderAsc: true,
47
- limitCount: 1000,
48
- rangeFrom: null,
49
- rangeTo: null,
50
- isSingle: false,
51
- isMaybeSingle: false,
52
- isInsert: false,
53
- isUpdate: false,
54
- isDelete: false,
55
- insertPayload: null,
56
- updatePayload: null,
57
- countMode: false,
58
- headMode: false,
59
- };
60
- }
61
- function applyFilters(rows, filters) {
62
- let result = rows;
63
- for (const fn of filters) {
64
- result = result.filter((r) => fn(r));
65
- }
66
- return result;
67
- }
68
- /** Convert SQL LIKE/ILIKE pattern to regex */
69
- function likeToRegex(pattern, caseInsensitive) {
70
- // Escape regex special chars except % and _
71
- const escaped = pattern.replace(/[.*+?^${}()|[\]\\]/g, (ch) => {
72
- if (ch === "%" || ch === "_")
73
- return ch;
74
- return `\\${ch}`;
75
- });
76
- const regexStr = "^" + escaped.replace(/%/g, ".*").replace(/_/g, ".") + "$";
77
- return new RegExp(regexStr, caseInsensitive ? "i" : "");
78
- }
79
- function buildQueryBuilder(state) {
80
- const builder = {};
81
- // select -----------------------------------------------------------------
82
- builder.select = vi.fn((columns, opts) => {
83
- state.selectColumns = columns || "*";
84
- if (opts?.count)
85
- state.countMode = true;
86
- if (opts?.head)
87
- state.headMode = true;
88
- return builder;
89
- });
90
- // insert -----------------------------------------------------------------
91
- builder.insert = vi.fn((payload) => {
92
- state.isInsert = true;
93
- state.insertPayload = payload;
94
- return builder;
95
- });
96
- // update -----------------------------------------------------------------
97
- builder.update = vi.fn((payload) => {
98
- state.isUpdate = true;
99
- state.updatePayload = payload;
100
- return builder;
101
- });
102
- // delete -----------------------------------------------------------------
103
- builder.delete = vi.fn(() => {
104
- state.isDelete = true;
105
- return builder;
106
- });
107
- // upsert -----------------------------------------------------------------
108
- builder.upsert = vi.fn((payload, _opts) => {
109
- state.isInsert = true;
110
- state.insertPayload = payload;
111
- return builder;
112
- });
113
- // filters ----------------------------------------------------------------
114
- builder.eq = vi.fn((col, val) => {
115
- state.filters.push((r) => r[col] === val);
116
- return builder;
117
- });
118
- builder.neq = vi.fn((col, val) => {
119
- state.filters.push((r) => r[col] !== val);
120
- return builder;
121
- });
122
- builder.gt = vi.fn((col, val) => {
123
- state.filters.push((r) => r[col] > val);
124
- return builder;
125
- });
126
- builder.gte = vi.fn((col, val) => {
127
- state.filters.push((r) => r[col] >= val);
128
- return builder;
129
- });
130
- builder.lt = vi.fn((col, val) => {
131
- state.filters.push((r) => r[col] < val);
132
- return builder;
133
- });
134
- builder.lte = vi.fn((col, val) => {
135
- state.filters.push((r) => r[col] <= val);
136
- return builder;
137
- });
138
- builder.in = vi.fn((col, vals) => {
139
- state.filters.push((r) => vals.includes(r[col]));
140
- return builder;
141
- });
142
- builder.not = vi.fn((col, op, val) => {
143
- state.filters.push((r) => {
144
- switch (op) {
145
- case "eq": return r[col] !== val;
146
- case "is": return r[col] !== val;
147
- case "in": return !(val || []).includes(r[col]);
148
- case "like": return !likeToRegex(val, false).test(String(r[col] ?? ""));
149
- case "ilike": return !likeToRegex(val, true).test(String(r[col] ?? ""));
150
- default: return true;
151
- }
152
- });
153
- return builder;
154
- });
155
- builder.ilike = vi.fn((col, pattern) => {
156
- const re = likeToRegex(pattern, true);
157
- state.filters.push((r) => re.test(String(r[col] ?? "")));
158
- return builder;
159
- });
160
- builder.like = vi.fn((col, pattern) => {
161
- const re = likeToRegex(pattern, false);
162
- state.filters.push((r) => re.test(String(r[col] ?? "")));
163
- return builder;
164
- });
165
- builder.or = vi.fn((expr) => {
166
- // Parse simple PostgREST or-expressions like "status.eq.active,status.eq.draft"
167
- const clauses = expr.split(",").map((c) => c.trim());
168
- const parsedFilters = [];
169
- for (const clause of clauses) {
170
- const parts = clause.split(".");
171
- if (parts.length >= 3) {
172
- const col = parts[0];
173
- const op = parts[1];
174
- const val = parts.slice(2).join(".");
175
- switch (op) {
176
- case "eq":
177
- parsedFilters.push((r) => String(r[col]) === val);
178
- break;
179
- case "neq":
180
- parsedFilters.push((r) => String(r[col]) !== val);
181
- break;
182
- case "ilike":
183
- parsedFilters.push((r) => likeToRegex(val, true).test(String(r[col] ?? "")));
184
- break;
185
- case "like":
186
- parsedFilters.push((r) => likeToRegex(val, false).test(String(r[col] ?? "")));
187
- break;
188
- case "is":
189
- parsedFilters.push((r) => {
190
- if (val === "null")
191
- return r[col] === null || r[col] === undefined;
192
- return false;
193
- });
194
- break;
195
- default:
196
- // Unknown op — pass through
197
- parsedFilters.push(() => true);
198
- }
199
- }
200
- }
201
- if (parsedFilters.length > 0) {
202
- state.filters.push((r) => parsedFilters.some((fn) => fn(r)));
203
- }
204
- return builder;
205
- });
206
- builder.is = vi.fn((col, val) => {
207
- state.filters.push((r) => {
208
- if (val === null)
209
- return r[col] === null || r[col] === undefined;
210
- return r[col] === val;
211
- });
212
- return builder;
213
- });
214
- builder.contains = vi.fn((col, val) => {
215
- state.filters.push((r) => {
216
- const v = r[col];
217
- if (Array.isArray(v) && Array.isArray(val)) {
218
- return val.every((item) => v.includes(item));
219
- }
220
- return false;
221
- });
222
- return builder;
223
- });
224
- builder.containedBy = vi.fn((col, val) => {
225
- state.filters.push((r) => {
226
- const v = r[col];
227
- if (Array.isArray(v) && Array.isArray(val)) {
228
- return v.every((item) => val.includes(item));
229
- }
230
- return false;
231
- });
232
- return builder;
233
- });
234
- builder.textSearch = vi.fn((_col, _query, _opts) => {
235
- // Simplified: no-op (full-text search not easily mockable)
236
- return builder;
237
- });
238
- // ordering / limits ------------------------------------------------------
239
- builder.order = vi.fn((_col, _opts) => {
240
- state.orderCol = _col;
241
- state.orderAsc = _opts?.ascending ?? true;
242
- return builder;
243
- });
244
- builder.limit = vi.fn((n) => {
245
- state.limitCount = n;
246
- return builder;
247
- });
248
- builder.range = vi.fn((from, to) => {
249
- state.rangeFrom = from;
250
- state.rangeTo = to;
251
- return builder;
252
- });
253
- // terminal modifiers -----------------------------------------------------
254
- builder.single = vi.fn(() => {
255
- state.isSingle = true;
256
- return resolve(state);
257
- });
258
- builder.maybeSingle = vi.fn(() => {
259
- state.isMaybeSingle = true;
260
- return resolve(state);
261
- });
262
- // csv export mock --------------------------------------------------------
263
- builder.csv = vi.fn(() => {
264
- const rows = tableData[state.table] || [];
265
- const filtered = applyFilters(rows, state.filters);
266
- if (filtered.length === 0)
267
- return { data: "", error: null };
268
- const keys = Object.keys(filtered[0]);
269
- const header = keys.join(",");
270
- const lines = filtered.map((r) => keys.map((k) => String(r[k] ?? "")).join(","));
271
- return { data: [header, ...lines].join("\n"), error: null };
272
- });
273
- // Make the builder thenable so `await sb.from(...).select(...)...` works
274
- // When no terminal modifier (.single/.maybeSingle) is called, the query
275
- // resolves on await.
276
- builder.then = (onFulfilled, onRejected) => {
277
- const result = resolve(state);
278
- return Promise.resolve(result).then(onFulfilled, onRejected);
279
- };
280
- return builder;
281
- }
282
- /** Resolve the query against the in-memory store */
283
- function resolve(state) {
284
- // Check for forced table errors
285
- const tableError = tableErrors[state.table];
286
- if (tableError) {
287
- return { data: null, error: tableError };
288
- }
289
- const rows = tableData[state.table] || [];
290
- // INSERT
291
- if (state.isInsert) {
292
- const payload = state.insertPayload;
293
- const newRows = Array.isArray(payload) ? payload : [payload];
294
- // Assign ids if missing
295
- const withIds = newRows.map((r, i) => ({
296
- id: `mock-id-${Date.now()}-${i}`,
297
- created_at: new Date().toISOString(),
298
- ...r,
299
- }));
300
- if (!tableData[state.table])
301
- tableData[state.table] = [];
302
- tableData[state.table].push(...withIds);
303
- if (state.isSingle) {
304
- return { data: withIds[0], error: null };
305
- }
306
- return { data: withIds, error: null };
307
- }
308
- // UPDATE
309
- if (state.isUpdate) {
310
- const matching = applyFilters(rows, state.filters);
311
- const updated = matching.map((r) => ({ ...r, ...state.updatePayload }));
312
- // Replace in store
313
- tableData[state.table] = rows.map((r) => {
314
- const upd = updated.find((u) => u.id === r.id);
315
- return upd || r;
316
- });
317
- if (state.isSingle || state.isMaybeSingle) {
318
- return { data: updated[0] || null, error: null };
319
- }
320
- return { data: updated, error: null, count: updated.length };
321
- }
322
- // DELETE
323
- if (state.isDelete) {
324
- const before = rows.length;
325
- const remaining = rows.filter((r) => !state.filters.every((fn) => fn(r)));
326
- tableData[state.table] = remaining;
327
- const deletedCount = before - remaining.length;
328
- return { data: null, error: null, count: deletedCount };
329
- }
330
- // SELECT
331
- let filtered = applyFilters(rows, state.filters);
332
- if (state.orderCol) {
333
- const col = state.orderCol;
334
- const asc = state.orderAsc;
335
- filtered.sort((a, b) => {
336
- if (a[col] < b[col])
337
- return asc ? -1 : 1;
338
- if (a[col] > b[col])
339
- return asc ? 1 : -1;
340
- return 0;
341
- });
342
- }
343
- // Apply range before limit
344
- if (state.rangeFrom !== null && state.rangeTo !== null) {
345
- filtered = filtered.slice(state.rangeFrom, state.rangeTo + 1);
346
- }
347
- else {
348
- filtered = filtered.slice(0, state.limitCount);
349
- }
350
- if (state.countMode && state.headMode) {
351
- return { data: null, error: null, count: filtered.length };
352
- }
353
- if (state.isSingle) {
354
- return { data: filtered[0] || null, error: filtered.length === 0 ? { message: "Row not found" } : null };
355
- }
356
- if (state.isMaybeSingle) {
357
- return { data: filtered[0] || null, error: null };
358
- }
359
- return { data: filtered, error: null, count: filtered.length };
360
- }
361
- // ---------------------------------------------------------------------------
362
- // Main factory
363
- // ---------------------------------------------------------------------------
364
- export function createMockSupabase() {
365
- const client = {
366
- from: vi.fn((table) => {
367
- const state = defaultState(table);
368
- return buildQueryBuilder(state);
369
- }),
370
- rpc: vi.fn((name, params) => {
371
- const resp = rpcResponses[name];
372
- if (resp)
373
- return Promise.resolve(resp);
374
- // Default: success with null data
375
- return Promise.resolve({ data: null, error: null });
376
- }),
377
- storage: {
378
- from: vi.fn((_bucket) => ({
379
- upload: vi.fn((_path, _file, _opts) => Promise.resolve({ data: { path: _path }, error: null })),
380
- getPublicUrl: vi.fn((path) => ({
381
- data: { publicUrl: `https://mock-storage.test/${path}` },
382
- })),
383
- remove: vi.fn((_paths) => Promise.resolve({ data: _paths.map((p) => ({ name: p })), error: null })),
384
- list: vi.fn((_prefix) => Promise.resolve({ data: [], error: null })),
385
- })),
386
- },
387
- auth: {
388
- getUser: vi.fn(() => Promise.resolve({ data: { user: null }, error: null })),
389
- getSession: vi.fn(() => Promise.resolve({ data: { session: null }, error: null })),
390
- },
391
- };
392
- return client;
393
- }