flowforge-client 0.1.2

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.
package/dist/index.js ADDED
@@ -0,0 +1,811 @@
1
+ "use strict";
2
+ var __defProp = Object.defineProperty;
3
+ var __getOwnPropDesc = Object.getOwnPropertyDescriptor;
4
+ var __getOwnPropNames = Object.getOwnPropertyNames;
5
+ var __hasOwnProp = Object.prototype.hasOwnProperty;
6
+ var __export = (target, all) => {
7
+ for (var name in all)
8
+ __defProp(target, name, { get: all[name], enumerable: true });
9
+ };
10
+ var __copyProps = (to, from, except, desc) => {
11
+ if (from && typeof from === "object" || typeof from === "function") {
12
+ for (let key of __getOwnPropNames(from))
13
+ if (!__hasOwnProp.call(to, key) && key !== except)
14
+ __defProp(to, key, { get: () => from[key], enumerable: !(desc = __getOwnPropDesc(from, key)) || desc.enumerable });
15
+ }
16
+ return to;
17
+ };
18
+ var __toCommonJS = (mod) => __copyProps(__defProp({}, "__esModule", { value: true }), mod);
19
+
20
+ // src/index.ts
21
+ var index_exports = {};
22
+ __export(index_exports, {
23
+ ApiKeysResource: () => ApiKeysResource,
24
+ ApprovalsResource: () => ApprovalsResource,
25
+ EventsResource: () => EventsResource,
26
+ FlowForgeError: () => FlowForgeError,
27
+ FunctionsResource: () => FunctionsResource,
28
+ HealthResource: () => HealthResource,
29
+ QueryBuilder: () => QueryBuilder,
30
+ RunsResource: () => RunsResource,
31
+ ToolsResource: () => ToolsResource,
32
+ UsersResource: () => UsersResource,
33
+ createClient: () => createClient
34
+ });
35
+ module.exports = __toCommonJS(index_exports);
36
+
37
+ // src/builder.ts
38
+ var QueryBuilder = class {
39
+ constructor(request, basePath, responseKey) {
40
+ this.request = request;
41
+ this.basePath = basePath;
42
+ this.responseKey = responseKey;
43
+ this.params = { filters: {} };
44
+ }
45
+ /**
46
+ * Filter by exact match.
47
+ */
48
+ eq(field, value) {
49
+ this.params.filters[field] = value;
50
+ return this;
51
+ }
52
+ /**
53
+ * Order results by a field.
54
+ */
55
+ order(field, direction = "asc") {
56
+ this.params.orderBy = field;
57
+ this.params.orderDir = direction;
58
+ return this;
59
+ }
60
+ /**
61
+ * Limit the number of results.
62
+ */
63
+ limit(n) {
64
+ this.params.limitValue = n;
65
+ return this;
66
+ }
67
+ /**
68
+ * Skip the first n results (for pagination).
69
+ */
70
+ offset(n) {
71
+ this.params.offsetValue = n;
72
+ return this;
73
+ }
74
+ /**
75
+ * Build query string from params.
76
+ */
77
+ buildQueryString() {
78
+ const searchParams = new URLSearchParams();
79
+ for (const [key, value] of Object.entries(this.params.filters)) {
80
+ if (value !== void 0 && value !== null) {
81
+ searchParams.set(key, String(value));
82
+ }
83
+ }
84
+ if (this.params.orderBy) {
85
+ searchParams.set("order_by", this.params.orderBy);
86
+ searchParams.set("order_dir", this.params.orderDir || "asc");
87
+ }
88
+ if (this.params.limitValue !== void 0) {
89
+ searchParams.set("limit", String(this.params.limitValue));
90
+ }
91
+ if (this.params.offsetValue !== void 0) {
92
+ searchParams.set("offset", String(this.params.offsetValue));
93
+ }
94
+ const query = searchParams.toString();
95
+ return query ? `?${query}` : "";
96
+ }
97
+ /**
98
+ * Execute the query and return multiple results.
99
+ */
100
+ async execute() {
101
+ const path = `${this.basePath}${this.buildQueryString()}`;
102
+ const result = await this.request("GET", path);
103
+ if (result.error) {
104
+ return { data: null, error: result.error };
105
+ }
106
+ const items = result.data[this.responseKey] || [];
107
+ return { data: items, error: null };
108
+ }
109
+ /**
110
+ * Execute the query and return a single result.
111
+ * Returns an error if no results found.
112
+ */
113
+ async single() {
114
+ const result = await this.limit(1).execute();
115
+ if (result.error) {
116
+ return { data: null, error: result.error };
117
+ }
118
+ if (result.data.length === 0) {
119
+ const error = {
120
+ message: "No results found",
121
+ status: 404,
122
+ name: "FlowForgeError"
123
+ };
124
+ return { data: null, error };
125
+ }
126
+ return { data: result.data[0], error: null };
127
+ }
128
+ };
129
+
130
+ // src/resources/events.ts
131
+ var EventsResource = class {
132
+ constructor(request) {
133
+ this.request = request;
134
+ }
135
+ /**
136
+ * Send an event to trigger matching workflows.
137
+ *
138
+ * @example
139
+ * ```ts
140
+ * const { data, error } = await ff.events.send('order/created', {
141
+ * order_id: '123',
142
+ * customer: 'Alice'
143
+ * });
144
+ * if (error) console.error(error.message);
145
+ * else console.log('Triggered runs:', data.runs);
146
+ * ```
147
+ */
148
+ async send(name, data, options) {
149
+ return this.request("POST", "/events", {
150
+ name,
151
+ data,
152
+ id: options?.id,
153
+ user_id: options?.user_id,
154
+ timestamp: options?.timestamp
155
+ });
156
+ }
157
+ /**
158
+ * Get a specific event by ID.
159
+ *
160
+ * @example
161
+ * ```ts
162
+ * const { data: event } = await ff.events.get('event-id');
163
+ * ```
164
+ */
165
+ async get(eventId) {
166
+ return this.request("GET", `/events/${eventId}`);
167
+ }
168
+ /**
169
+ * Start building a query to select events.
170
+ *
171
+ * @example
172
+ * ```ts
173
+ * const { data: events } = await ff.events
174
+ * .select()
175
+ * .eq('name', 'order/*')
176
+ * .limit(10)
177
+ * .execute();
178
+ * ```
179
+ */
180
+ select() {
181
+ return new QueryBuilder(
182
+ this.request,
183
+ "/events",
184
+ "events"
185
+ );
186
+ }
187
+ };
188
+
189
+ // src/resources/runs.ts
190
+ var RunsResource = class {
191
+ constructor(request) {
192
+ this.request = request;
193
+ }
194
+ /**
195
+ * Get a run by ID, including its steps.
196
+ *
197
+ * @example
198
+ * ```ts
199
+ * const { data: run } = await ff.runs.get('run-id');
200
+ * console.log(run.status, run.steps);
201
+ * ```
202
+ */
203
+ async get(runId) {
204
+ return this.request("GET", `/runs/${runId}`);
205
+ }
206
+ /**
207
+ * Start building a query to select runs.
208
+ *
209
+ * @example
210
+ * ```ts
211
+ * const { data: runs } = await ff.runs
212
+ * .select()
213
+ * .eq('status', 'completed')
214
+ * .order('created_at', 'desc')
215
+ * .limit(10)
216
+ * .execute();
217
+ * ```
218
+ */
219
+ select() {
220
+ return new QueryBuilder(this.request, "/runs", "runs");
221
+ }
222
+ /**
223
+ * Cancel a running workflow.
224
+ *
225
+ * @example
226
+ * ```ts
227
+ * const { error } = await ff.runs.cancel('run-id');
228
+ * if (error) console.error('Failed to cancel:', error.message);
229
+ * ```
230
+ */
231
+ async cancel(runId) {
232
+ return this.request(
233
+ "POST",
234
+ `/runs/${runId}/cancel`
235
+ );
236
+ }
237
+ /**
238
+ * Replay a completed or failed run.
239
+ *
240
+ * @example
241
+ * ```ts
242
+ * const { data: newRun } = await ff.runs.replay('run-id');
243
+ * console.log('New run ID:', newRun.id);
244
+ * ```
245
+ */
246
+ async replay(runId) {
247
+ return this.request("POST", `/runs/${runId}/replay`);
248
+ }
249
+ /**
250
+ * Wait for a run to complete (polling).
251
+ *
252
+ * @example
253
+ * ```ts
254
+ * const { data: completedRun, error } = await ff.runs.waitFor('run-id', {
255
+ * timeout: 60000
256
+ * });
257
+ * if (error) console.error('Timeout or error:', error.message);
258
+ * else console.log('Run completed with status:', completedRun.status);
259
+ * ```
260
+ */
261
+ async waitFor(runId, options) {
262
+ const timeout = options?.timeout ?? 6e4;
263
+ const interval = options?.interval ?? 1e3;
264
+ const start = Date.now();
265
+ while (Date.now() - start < timeout) {
266
+ const result = await this.get(runId);
267
+ if (result.error) {
268
+ return result;
269
+ }
270
+ if (["completed", "failed", "cancelled"].includes(result.data.status)) {
271
+ return result;
272
+ }
273
+ await new Promise((resolve) => setTimeout(resolve, interval));
274
+ }
275
+ const error = {
276
+ message: "Timeout waiting for run to complete",
277
+ status: 408,
278
+ name: "FlowForgeError"
279
+ };
280
+ return { data: null, error };
281
+ }
282
+ };
283
+
284
+ // src/resources/functions.ts
285
+ var FunctionsResource = class {
286
+ constructor(request) {
287
+ this.request = request;
288
+ }
289
+ /**
290
+ * Get a function by ID.
291
+ *
292
+ * @example
293
+ * ```ts
294
+ * const { data: fn } = await ff.functions.get('my-function');
295
+ * console.log(fn.name, fn.is_active);
296
+ * ```
297
+ */
298
+ async get(functionId) {
299
+ return this.request("GET", `/functions/${functionId}`);
300
+ }
301
+ /**
302
+ * Start building a query to select functions.
303
+ *
304
+ * @example
305
+ * ```ts
306
+ * const { data: fns } = await ff.functions
307
+ * .select()
308
+ * .eq('is_active', true)
309
+ * .eq('trigger_type', 'event')
310
+ * .execute();
311
+ * ```
312
+ */
313
+ select() {
314
+ return new QueryBuilder(
315
+ this.request,
316
+ "/functions",
317
+ "functions"
318
+ );
319
+ }
320
+ /**
321
+ * Create a new function.
322
+ *
323
+ * @example
324
+ * ```ts
325
+ * const { data: fn, error } = await ff.functions.create({
326
+ * id: 'order-processor',
327
+ * name: 'Order Processor',
328
+ * trigger_type: 'event',
329
+ * trigger_value: 'order/created',
330
+ * endpoint_url: 'http://localhost:3000/api/workflows/order',
331
+ * });
332
+ * ```
333
+ */
334
+ async create(input) {
335
+ return this.request("POST", "/functions", input);
336
+ }
337
+ /**
338
+ * Update an existing function.
339
+ *
340
+ * @example
341
+ * ```ts
342
+ * const { error } = await ff.functions.update('my-function', {
343
+ * is_active: false
344
+ * });
345
+ * ```
346
+ */
347
+ async update(functionId, input) {
348
+ return this.request(
349
+ "PATCH",
350
+ `/functions/${functionId}`,
351
+ input
352
+ );
353
+ }
354
+ /**
355
+ * Delete a function.
356
+ *
357
+ * @example
358
+ * ```ts
359
+ * const { error } = await ff.functions.delete('my-function');
360
+ * if (error) console.error('Failed to delete:', error.message);
361
+ * ```
362
+ */
363
+ async delete(functionId) {
364
+ return this.request(
365
+ "DELETE",
366
+ `/functions/${functionId}`
367
+ );
368
+ }
369
+ };
370
+
371
+ // src/resources/tools.ts
372
+ var ToolsResource = class {
373
+ constructor(request) {
374
+ this.request = request;
375
+ }
376
+ /**
377
+ * Get a tool by name.
378
+ *
379
+ * @example
380
+ * ```ts
381
+ * const { data: tool } = await ff.tools.get('send-email');
382
+ * console.log(tool.description, tool.requires_approval);
383
+ * ```
384
+ */
385
+ async get(toolName) {
386
+ return this.request("GET", `/tools/${toolName}`);
387
+ }
388
+ /**
389
+ * Start building a query to select tools.
390
+ *
391
+ * @example
392
+ * ```ts
393
+ * const { data: tools } = await ff.tools
394
+ * .select()
395
+ * .eq('requires_approval', true)
396
+ * .eq('is_active', true)
397
+ * .execute();
398
+ * ```
399
+ */
400
+ select() {
401
+ return new QueryBuilder(this.request, "/tools", "tools");
402
+ }
403
+ /**
404
+ * Create a new tool.
405
+ *
406
+ * @example
407
+ * ```ts
408
+ * const { data: tool, error } = await ff.tools.create({
409
+ * name: 'send-email',
410
+ * description: 'Send an email to a recipient',
411
+ * parameters: {
412
+ * type: 'object',
413
+ * properties: {
414
+ * to: { type: 'string', description: 'Recipient email' },
415
+ * subject: { type: 'string', description: 'Email subject' },
416
+ * body: { type: 'string', description: 'Email body' },
417
+ * },
418
+ * required: ['to', 'subject', 'body'],
419
+ * },
420
+ * requires_approval: true,
421
+ * });
422
+ * ```
423
+ */
424
+ async create(input) {
425
+ return this.request("POST", "/tools", input);
426
+ }
427
+ /**
428
+ * Update an existing tool.
429
+ *
430
+ * @example
431
+ * ```ts
432
+ * const { error } = await ff.tools.update('send-email', {
433
+ * requires_approval: false
434
+ * });
435
+ * ```
436
+ */
437
+ async update(toolName, input) {
438
+ return this.request("PATCH", `/tools/${toolName}`, input);
439
+ }
440
+ /**
441
+ * Delete a tool.
442
+ *
443
+ * @example
444
+ * ```ts
445
+ * const { error } = await ff.tools.delete('my-tool');
446
+ * if (error) console.error('Failed to delete:', error.message);
447
+ * ```
448
+ */
449
+ async delete(toolName) {
450
+ return this.request(
451
+ "DELETE",
452
+ `/tools/${toolName}`
453
+ );
454
+ }
455
+ };
456
+
457
+ // src/resources/approvals.ts
458
+ var ApprovalsResource = class {
459
+ constructor(request) {
460
+ this.request = request;
461
+ }
462
+ /**
463
+ * Get an approval by ID.
464
+ *
465
+ * @example
466
+ * ```ts
467
+ * const { data: approval } = await ff.approvals.get('approval-id');
468
+ * console.log(approval.tool_name, approval.status);
469
+ * ```
470
+ */
471
+ async get(approvalId) {
472
+ return this.request("GET", `/approvals/${approvalId}`);
473
+ }
474
+ /**
475
+ * Start building a query to select approvals.
476
+ *
477
+ * @example
478
+ * ```ts
479
+ * const { data: pending } = await ff.approvals
480
+ * .select()
481
+ * .eq('status', 'pending')
482
+ * .execute();
483
+ * ```
484
+ */
485
+ select() {
486
+ return new QueryBuilder(
487
+ this.request,
488
+ "/approvals",
489
+ "approvals"
490
+ );
491
+ }
492
+ /**
493
+ * Approve a pending tool call.
494
+ *
495
+ * @example
496
+ * ```ts
497
+ * const { error } = await ff.approvals.approve('approval-id');
498
+ * if (error) console.error('Failed to approve:', error.message);
499
+ * ```
500
+ *
501
+ * @example With modified arguments
502
+ * ```ts
503
+ * const { error } = await ff.approvals.approve('approval-id', {
504
+ * modifiedArguments: { amount: 50 } // Override the original amount
505
+ * });
506
+ * ```
507
+ */
508
+ async approve(approvalId, options) {
509
+ return this.request(
510
+ "POST",
511
+ `/approvals/${approvalId}/approve`,
512
+ {
513
+ modified_arguments: options?.modifiedArguments
514
+ }
515
+ );
516
+ }
517
+ /**
518
+ * Reject a pending tool call.
519
+ *
520
+ * @example
521
+ * ```ts
522
+ * const { error } = await ff.approvals.reject('approval-id', 'Too risky');
523
+ * if (error) console.error('Failed to reject:', error.message);
524
+ * ```
525
+ */
526
+ async reject(approvalId, reason) {
527
+ return this.request(
528
+ "POST",
529
+ `/approvals/${approvalId}/reject`,
530
+ { reason }
531
+ );
532
+ }
533
+ };
534
+
535
+ // src/resources/health.ts
536
+ var HealthResource = class {
537
+ constructor(request) {
538
+ this.request = request;
539
+ }
540
+ /**
541
+ * Check if the server is healthy.
542
+ *
543
+ * @example
544
+ * ```ts
545
+ * const { data: healthy, error } = await ff.health.check();
546
+ * if (healthy) console.log('Server is healthy');
547
+ * else console.error('Server is unhealthy:', error?.message);
548
+ * ```
549
+ */
550
+ async check() {
551
+ const result = await this.request("GET", "/health");
552
+ if (result.error) {
553
+ return { data: false, error: null };
554
+ }
555
+ return { data: result.data.status === "healthy", error: null };
556
+ }
557
+ /**
558
+ * Get server statistics.
559
+ *
560
+ * @example
561
+ * ```ts
562
+ * const { data: stats } = await ff.health.stats();
563
+ * console.log('Total runs:', stats.runs.total);
564
+ * console.log('Active functions:', stats.functions.active);
565
+ * ```
566
+ */
567
+ async stats() {
568
+ return this.request("GET", "/stats");
569
+ }
570
+ };
571
+
572
+ // src/resources/users.ts
573
+ var UsersResource = class {
574
+ constructor(request) {
575
+ this.request = request;
576
+ }
577
+ /**
578
+ * List all users (admin only).
579
+ *
580
+ * @param options - Filter options
581
+ * @returns List of users
582
+ *
583
+ * @example
584
+ * ```ts
585
+ * const { data } = await ff.users.list({ includeInactive: true });
586
+ * console.log('Total users:', data?.total);
587
+ * ```
588
+ */
589
+ async list(options) {
590
+ const params = new URLSearchParams();
591
+ if (options?.includeInactive) {
592
+ params.set("include_inactive", "true");
593
+ }
594
+ const query = params.toString();
595
+ return this.request(
596
+ "GET",
597
+ `/users${query ? `?${query}` : ""}`
598
+ );
599
+ }
600
+ /**
601
+ * Get a user by ID (admin only).
602
+ *
603
+ * @param userId - User ID
604
+ * @returns User details
605
+ */
606
+ async get(userId) {
607
+ return this.request("GET", `/users/${userId}`);
608
+ }
609
+ /**
610
+ * Create a new user (admin only).
611
+ *
612
+ * @param input - User details
613
+ * @returns Created user
614
+ *
615
+ * @example
616
+ * ```ts
617
+ * const { data, error } = await ff.users.create({
618
+ * email: 'user@example.com',
619
+ * password: 'securepassword',
620
+ * name: 'John Doe',
621
+ * role: 'member'
622
+ * });
623
+ * ```
624
+ */
625
+ async create(input) {
626
+ return this.request("POST", "/users", input);
627
+ }
628
+ /**
629
+ * Update a user (admin only).
630
+ *
631
+ * @param userId - User ID
632
+ * @param input - Fields to update
633
+ * @returns Updated user
634
+ */
635
+ async update(userId, input) {
636
+ return this.request("PATCH", `/users/${userId}`, input);
637
+ }
638
+ /**
639
+ * Delete a user (admin only).
640
+ *
641
+ * @param userId - User ID
642
+ * @returns Success message
643
+ */
644
+ async delete(userId) {
645
+ return this.request("DELETE", `/users/${userId}`);
646
+ }
647
+ };
648
+
649
+ // src/resources/api-keys.ts
650
+ var ApiKeysResource = class {
651
+ constructor(request) {
652
+ this.request = request;
653
+ }
654
+ /**
655
+ * List all API keys for the tenant.
656
+ *
657
+ * @param options - Filter options
658
+ * @returns List of API keys (without the actual key values)
659
+ *
660
+ * @example
661
+ * ```ts
662
+ * const { data } = await ff.apiKeys.list();
663
+ * data?.keys.forEach(key => {
664
+ * console.log(`${key.name}: ${key.key_prefix}... (${key.key_type})`);
665
+ * });
666
+ * ```
667
+ */
668
+ async list(options) {
669
+ const params = new URLSearchParams();
670
+ if (options?.includeRevoked) {
671
+ params.set("include_revoked", "true");
672
+ }
673
+ const query = params.toString();
674
+ return this.request(
675
+ "GET",
676
+ `/auth/keys${query ? `?${query}` : ""}`
677
+ );
678
+ }
679
+ /**
680
+ * Get an API key by ID.
681
+ *
682
+ * @param keyId - API key ID
683
+ * @returns API key details (without the actual key value)
684
+ */
685
+ async get(keyId) {
686
+ return this.request("GET", `/auth/keys/${keyId}`);
687
+ }
688
+ /**
689
+ * Create a new API key.
690
+ *
691
+ * @param input - API key configuration
692
+ * @returns Created API key WITH the actual key value (only returned once!)
693
+ *
694
+ * @example
695
+ * ```ts
696
+ * const { data, error } = await ff.apiKeys.create({
697
+ * name: 'Production API Key',
698
+ * key_type: 'live',
699
+ * scopes: ['events:send', 'runs:read']
700
+ * });
701
+ *
702
+ * if (data) {
703
+ * // IMPORTANT: Store this key - it won't be shown again!
704
+ * console.log('New API key:', data.key); // ff_live_a1b2c3...
705
+ * }
706
+ * ```
707
+ */
708
+ async create(input) {
709
+ return this.request("POST", "/auth/keys", input);
710
+ }
711
+ /**
712
+ * Revoke an API key.
713
+ *
714
+ * @param keyId - API key ID
715
+ * @param reason - Optional reason for revocation
716
+ * @returns Success message
717
+ *
718
+ * @example
719
+ * ```ts
720
+ * const { error } = await ff.apiKeys.revoke('key-id', 'Compromised');
721
+ * if (!error) {
722
+ * console.log('Key revoked successfully');
723
+ * }
724
+ * ```
725
+ */
726
+ async revoke(keyId, reason) {
727
+ return this.request(
728
+ "DELETE",
729
+ `/auth/keys/${keyId}`,
730
+ reason ? { reason } : void 0
731
+ );
732
+ }
733
+ };
734
+
735
+ // src/client.ts
736
+ function createClient(baseUrl, options = {}) {
737
+ const normalizedBaseUrl = baseUrl.replace(/\/$/, "");
738
+ const fetchFn = options.fetch || globalThis.fetch;
739
+ async function request(method, path, body) {
740
+ const headers = {
741
+ "Content-Type": "application/json"
742
+ };
743
+ if (options.apiKey) {
744
+ headers["X-FlowForge-API-Key"] = options.apiKey;
745
+ }
746
+ try {
747
+ const response = await fetchFn(`${normalizedBaseUrl}/api/v1${path}`, {
748
+ method,
749
+ headers,
750
+ body: body ? JSON.stringify(body) : void 0
751
+ });
752
+ if (!response.ok) {
753
+ const errorBody = await response.json().catch(() => ({}));
754
+ const error = {
755
+ message: errorBody.detail || `HTTP ${response.status}`,
756
+ status: response.status,
757
+ code: errorBody.code,
758
+ detail: errorBody,
759
+ name: "FlowForgeError"
760
+ };
761
+ return { data: null, error };
762
+ }
763
+ const data = await response.json();
764
+ return { data, error: null };
765
+ } catch (err) {
766
+ const error = {
767
+ message: err instanceof Error ? err.message : "Network error",
768
+ status: 0,
769
+ code: "NETWORK_ERROR",
770
+ detail: err,
771
+ name: "FlowForgeError"
772
+ };
773
+ return { data: null, error };
774
+ }
775
+ }
776
+ return {
777
+ events: new EventsResource(request),
778
+ runs: new RunsResource(request),
779
+ functions: new FunctionsResource(request),
780
+ tools: new ToolsResource(request),
781
+ approvals: new ApprovalsResource(request),
782
+ health: new HealthResource(request),
783
+ users: new UsersResource(request),
784
+ apiKeys: new ApiKeysResource(request)
785
+ };
786
+ }
787
+
788
+ // src/types.ts
789
+ var FlowForgeError = class extends Error {
790
+ constructor(message, status, code, detail) {
791
+ super(message);
792
+ this.status = status;
793
+ this.code = code;
794
+ this.detail = detail;
795
+ this.name = "FlowForgeError";
796
+ }
797
+ };
798
+ // Annotate the CommonJS export names for ESM import in node:
799
+ 0 && (module.exports = {
800
+ ApiKeysResource,
801
+ ApprovalsResource,
802
+ EventsResource,
803
+ FlowForgeError,
804
+ FunctionsResource,
805
+ HealthResource,
806
+ QueryBuilder,
807
+ RunsResource,
808
+ ToolsResource,
809
+ UsersResource,
810
+ createClient
811
+ });