@spike-forms/sdk 0.2.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.
package/dist/index.mjs ADDED
@@ -0,0 +1,1552 @@
1
+ // src/errors.ts
2
+ var SpikeError = class extends Error {
3
+ /** HTTP status code from the API response */
4
+ statusCode;
5
+ /** Error code from the API (e.g., 'INVALID_API_KEY', 'FORM_NOT_FOUND') */
6
+ code;
7
+ /** Request ID for debugging and support purposes */
8
+ requestId;
9
+ constructor(message, options) {
10
+ super(message);
11
+ this.name = "SpikeError";
12
+ this.statusCode = options?.statusCode;
13
+ this.code = options?.code;
14
+ this.requestId = options?.requestId;
15
+ if (Error.captureStackTrace) {
16
+ Error.captureStackTrace(this, this.constructor);
17
+ }
18
+ }
19
+ };
20
+ var AuthenticationError = class extends SpikeError {
21
+ constructor(message, options) {
22
+ super(message, { statusCode: 401, ...options });
23
+ this.name = "AuthenticationError";
24
+ }
25
+ };
26
+ var NotFoundError = class extends SpikeError {
27
+ constructor(message, options) {
28
+ super(message, { statusCode: 404, ...options });
29
+ this.name = "NotFoundError";
30
+ }
31
+ };
32
+ var RateLimitError = class extends SpikeError {
33
+ /** Number of seconds to wait before retrying the request */
34
+ retryAfter;
35
+ constructor(message, options) {
36
+ super(message, { statusCode: 429, code: options?.code, requestId: options?.requestId });
37
+ this.name = "RateLimitError";
38
+ this.retryAfter = options?.retryAfter;
39
+ }
40
+ };
41
+ var ValidationError = class extends SpikeError {
42
+ /** Field-specific validation error details */
43
+ details;
44
+ constructor(message, options) {
45
+ super(message, { statusCode: 400, code: options?.code, requestId: options?.requestId });
46
+ this.name = "ValidationError";
47
+ this.details = options?.details;
48
+ }
49
+ };
50
+ var NetworkError = class extends SpikeError {
51
+ constructor(message, options) {
52
+ super(message, { code: options?.code, requestId: options?.requestId });
53
+ this.name = "NetworkError";
54
+ }
55
+ };
56
+
57
+ // src/http.ts
58
+ var HttpClient = class {
59
+ apiKey;
60
+ baseUrl;
61
+ timeout;
62
+ constructor(config) {
63
+ this.apiKey = config.apiKey;
64
+ this.baseUrl = config.baseUrl;
65
+ this.timeout = config.timeout;
66
+ }
67
+ /**
68
+ * Make a GET request
69
+ */
70
+ async get(path, options) {
71
+ return this.request("GET", path, void 0, options);
72
+ }
73
+ /**
74
+ * Make a POST request with authentication
75
+ */
76
+ async post(path, body, options) {
77
+ return this.request("POST", path, body, options);
78
+ }
79
+ /**
80
+ * Make a PATCH request
81
+ */
82
+ async patch(path, body, options) {
83
+ return this.request("PATCH", path, body, options);
84
+ }
85
+ /**
86
+ * Make a PUT request
87
+ */
88
+ async put(path, body, options) {
89
+ return this.request("PUT", path, body, options);
90
+ }
91
+ /**
92
+ * Make a DELETE request
93
+ */
94
+ async delete(path, options) {
95
+ return this.request("DELETE", path, void 0, options);
96
+ }
97
+ /**
98
+ * Make a POST request without authentication (for public form submissions)
99
+ */
100
+ async postPublic(path, body, options) {
101
+ return this.request("POST", path, body, options, false);
102
+ }
103
+ /**
104
+ * Build a URL with query parameters
105
+ */
106
+ buildUrl(path, params) {
107
+ const url = new URL(path, this.baseUrl);
108
+ if (params) {
109
+ for (const [key, value] of Object.entries(params)) {
110
+ if (value !== void 0) {
111
+ url.searchParams.append(key, String(value));
112
+ }
113
+ }
114
+ }
115
+ return url.toString();
116
+ }
117
+ /**
118
+ * Make an HTTP request with timeout and error handling
119
+ */
120
+ async request(method, path, body, options, authenticated = true) {
121
+ const url = this.buildUrl(path, options?.params);
122
+ const controller = new AbortController();
123
+ const timeoutId = setTimeout(() => controller.abort(), this.timeout);
124
+ try {
125
+ const headers = {
126
+ ...options?.headers
127
+ };
128
+ if (authenticated) {
129
+ headers["Authorization"] = `Bearer ${this.apiKey}`;
130
+ }
131
+ if (body !== void 0) {
132
+ headers["Content-Type"] = "application/json";
133
+ }
134
+ const response = await fetch(url, {
135
+ method,
136
+ headers,
137
+ body: body !== void 0 ? JSON.stringify(body) : void 0,
138
+ signal: controller.signal
139
+ });
140
+ clearTimeout(timeoutId);
141
+ if (!response.ok) {
142
+ await this.handleErrorResponse(response);
143
+ }
144
+ const text = await response.text();
145
+ if (!text) {
146
+ return {};
147
+ }
148
+ return JSON.parse(text);
149
+ } catch (error) {
150
+ clearTimeout(timeoutId);
151
+ if (error instanceof Error && error.name === "AbortError") {
152
+ throw new NetworkError(`Request timeout after ${this.timeout}ms`);
153
+ }
154
+ if (error instanceof SpikeError) {
155
+ throw error;
156
+ }
157
+ if (error instanceof Error) {
158
+ throw new NetworkError(error.message);
159
+ }
160
+ throw new NetworkError("An unknown network error occurred");
161
+ }
162
+ }
163
+ /**
164
+ * Handle error responses and throw appropriate SDK errors
165
+ */
166
+ async handleErrorResponse(response) {
167
+ let errorData = {};
168
+ const requestId = response.headers.get("x-request-id") ?? void 0;
169
+ try {
170
+ const text = await response.text();
171
+ if (text) {
172
+ errorData = JSON.parse(text);
173
+ }
174
+ } catch {
175
+ }
176
+ const message = errorData.error || errorData.message || response.statusText || "Request failed";
177
+ const code = errorData.code;
178
+ switch (response.status) {
179
+ case 400:
180
+ throw new ValidationError(message, {
181
+ code,
182
+ requestId,
183
+ details: errorData.details
184
+ });
185
+ case 401:
186
+ throw new AuthenticationError(message, {
187
+ code,
188
+ requestId
189
+ });
190
+ case 404:
191
+ throw new NotFoundError(message, {
192
+ code,
193
+ requestId
194
+ });
195
+ case 429: {
196
+ const retryAfterHeader = response.headers.get("Retry-After");
197
+ const retryAfter = retryAfterHeader ? parseInt(retryAfterHeader, 10) : void 0;
198
+ throw new RateLimitError(message, {
199
+ code,
200
+ requestId,
201
+ retryAfter: Number.isNaN(retryAfter) ? void 0 : retryAfter
202
+ });
203
+ }
204
+ default:
205
+ throw new SpikeError(message, {
206
+ statusCode: response.status,
207
+ code,
208
+ requestId
209
+ });
210
+ }
211
+ }
212
+ };
213
+
214
+ // src/resources/forms.ts
215
+ var FormsResource = class {
216
+ http;
217
+ /**
218
+ * Create a new FormsResource instance
219
+ * @param http - The HTTP client to use for API requests
220
+ */
221
+ constructor(http) {
222
+ this.http = http;
223
+ }
224
+ /**
225
+ * List all forms with optional pagination and filtering.
226
+ *
227
+ * @param params - Optional parameters for filtering and pagination
228
+ * @param params.limit - Maximum number of forms to return
229
+ * @param params.offset - Number of forms to skip for pagination
230
+ * @param params.project_id - Filter forms by project ID
231
+ * @param params.include_inactive - Include inactive forms in the results
232
+ * @returns Promise resolving to an array of forms
233
+ *
234
+ * @example
235
+ * ```typescript
236
+ * // Get all forms
237
+ * const forms = await client.forms.list();
238
+ *
239
+ * // Get forms with pagination
240
+ * const forms = await client.forms.list({ limit: 10, offset: 20 });
241
+ *
242
+ * // Get forms for a specific project
243
+ * const forms = await client.forms.list({ project_id: 'proj_123' });
244
+ *
245
+ * // Include inactive forms
246
+ * const forms = await client.forms.list({ include_inactive: true });
247
+ * ```
248
+ *
249
+ * @see Requirements 4.1
250
+ */
251
+ async list(params) {
252
+ return this.http.get("/forms", {
253
+ params
254
+ });
255
+ }
256
+ /**
257
+ * Create a new form.
258
+ *
259
+ * @param data - The form data to create
260
+ * @param data.name - Display name for the form (required)
261
+ * @param data.project_id - ID of the project to add the form to (optional)
262
+ * @returns Promise resolving to the created form
263
+ *
264
+ * @example
265
+ * ```typescript
266
+ * // Create a simple form
267
+ * const form = await client.forms.create({ name: 'Contact Form' });
268
+ *
269
+ * // Create a form in a project
270
+ * const form = await client.forms.create({
271
+ * name: 'Feedback Form',
272
+ * project_id: 'proj_123'
273
+ * });
274
+ * ```
275
+ *
276
+ * @see Requirements 4.2
277
+ */
278
+ async create(data) {
279
+ return this.http.post("/forms", data);
280
+ }
281
+ /**
282
+ * Get a single form by ID.
283
+ *
284
+ * @param id - The unique identifier of the form
285
+ * @returns Promise resolving to the form
286
+ * @throws NotFoundError if the form does not exist
287
+ *
288
+ * @example
289
+ * ```typescript
290
+ * const form = await client.forms.get('form_123');
291
+ * console.log(form.name, form.submission_count);
292
+ * ```
293
+ *
294
+ * @see Requirements 4.3
295
+ */
296
+ async get(id) {
297
+ return this.http.get(`/forms/${id}`);
298
+ }
299
+ /**
300
+ * Update a form's properties.
301
+ *
302
+ * @param id - The unique identifier of the form to update
303
+ * @param data - The properties to update
304
+ * @param data.name - New display name for the form
305
+ * @param data.project_id - ID of the project to move the form to (or null to remove from project)
306
+ * @param data.is_active - Whether the form should be active
307
+ * @returns Promise resolving to the updated form
308
+ * @throws NotFoundError if the form does not exist
309
+ *
310
+ * @example
311
+ * ```typescript
312
+ * // Update form name
313
+ * const form = await client.forms.update('form_123', { name: 'New Name' });
314
+ *
315
+ * // Deactivate a form
316
+ * const form = await client.forms.update('form_123', { is_active: false });
317
+ *
318
+ * // Move form to a different project
319
+ * const form = await client.forms.update('form_123', { project_id: 'proj_456' });
320
+ * ```
321
+ *
322
+ * @see Requirements 4.4
323
+ */
324
+ async update(id, data) {
325
+ return this.http.patch(`/forms/${id}`, data);
326
+ }
327
+ /**
328
+ * Delete a form by ID.
329
+ *
330
+ * @param id - The unique identifier of the form to delete
331
+ * @returns Promise resolving to a success response
332
+ * @throws NotFoundError if the form does not exist
333
+ *
334
+ * @example
335
+ * ```typescript
336
+ * await client.forms.delete('form_123');
337
+ * ```
338
+ *
339
+ * @see Requirements 4.5
340
+ */
341
+ async delete(id) {
342
+ return this.http.delete(`/forms/${id}`);
343
+ }
344
+ /**
345
+ * Submit data to a form. This is a public endpoint that does not require authentication.
346
+ *
347
+ * @param slug - The URL-friendly slug of the form
348
+ * @param data - The form data to submit as key-value pairs
349
+ * @returns Promise resolving to the submission response
350
+ * @throws NotFoundError if the form does not exist
351
+ * @throws ValidationError if the form is inactive or data is invalid
352
+ *
353
+ * @example
354
+ * ```typescript
355
+ * // Submit to a contact form
356
+ * const result = await client.forms.submit('contact-form', {
357
+ * name: 'John Doe',
358
+ * email: 'john@example.com',
359
+ * message: 'Hello!'
360
+ * });
361
+ *
362
+ * if (result.success) {
363
+ * console.log('Submission ID:', result.submission_id);
364
+ * }
365
+ * ```
366
+ *
367
+ * @see Requirements 4.6
368
+ */
369
+ async submit(slug, data) {
370
+ return this.http.postPublic(`/f/${slug}`, data);
371
+ }
372
+ /**
373
+ * Get the HTML template for a form.
374
+ *
375
+ * Returns the stored HTML from S3 or a default template if none exists.
376
+ *
377
+ * @param id - The unique identifier of the form
378
+ * @returns Promise resolving to the HTML content
379
+ * @throws NotFoundError if the form does not exist
380
+ *
381
+ * @example
382
+ * ```typescript
383
+ * const { html } = await client.forms.getHtml('form_123');
384
+ * console.log(html);
385
+ * ```
386
+ */
387
+ async getHtml(id) {
388
+ return this.http.get(`/forms/${id}/html`);
389
+ }
390
+ /**
391
+ * Save HTML template for a form to S3 storage.
392
+ *
393
+ * @param id - The unique identifier of the form
394
+ * @param html - The HTML content to save
395
+ * @returns Promise resolving to the save response with the S3 URL
396
+ * @throws NotFoundError if the form does not exist
397
+ *
398
+ * @example
399
+ * ```typescript
400
+ * const result = await client.forms.saveHtml('form_123', '<html>...</html>');
401
+ * if (result.success) {
402
+ * console.log('Saved to:', result.html_url);
403
+ * }
404
+ * ```
405
+ */
406
+ async saveHtml(id, html) {
407
+ return this.http.put(`/forms/${id}/html`, { html });
408
+ }
409
+ };
410
+
411
+ // src/resources/submissions.ts
412
+ var SubmissionsResource = class {
413
+ http;
414
+ /**
415
+ * Create a new SubmissionsResource instance
416
+ * @param http - The HTTP client to use for API requests
417
+ */
418
+ constructor(http) {
419
+ this.http = http;
420
+ }
421
+ /**
422
+ * List submissions for a form with optional filtering and pagination.
423
+ *
424
+ * @param formId - The unique identifier of the form
425
+ * @param params - Optional parameters for filtering and pagination
426
+ * @param params.limit - Maximum number of submissions to return
427
+ * @param params.offset - Number of submissions to skip for pagination
428
+ * @param params.since - Only return submissions created after this ISO 8601 timestamp
429
+ * @param params.order - Sort order for submissions ('asc' or 'desc')
430
+ * @param params.filter - Filter string for searching submissions
431
+ * @param params.is_spam - Filter by spam status
432
+ * @param params.is_read - Filter by read status
433
+ * @returns Promise resolving to an array of submissions
434
+ * @throws NotFoundError if the form does not exist
435
+ *
436
+ * @example
437
+ * ```typescript
438
+ * // Get all submissions for a form
439
+ * const submissions = await client.submissions.list('form_123');
440
+ *
441
+ * // Get submissions with pagination
442
+ * const submissions = await client.submissions.list('form_123', {
443
+ * limit: 10,
444
+ * offset: 20
445
+ * });
446
+ *
447
+ * // Get unread submissions
448
+ * const unread = await client.submissions.list('form_123', {
449
+ * is_read: false
450
+ * });
451
+ *
452
+ * // Get non-spam submissions since a date
453
+ * const recent = await client.submissions.list('form_123', {
454
+ * since: '2024-01-01T00:00:00Z',
455
+ * is_spam: false,
456
+ * order: 'desc'
457
+ * });
458
+ *
459
+ * // Search submissions
460
+ * const filtered = await client.submissions.list('form_123', {
461
+ * filter: 'john@example.com'
462
+ * });
463
+ * ```
464
+ *
465
+ * @see Requirements 5.1
466
+ */
467
+ async list(formId, params) {
468
+ return this.http.get(`/forms/${formId}/submissions`, {
469
+ params
470
+ });
471
+ }
472
+ /**
473
+ * Get submission statistics for a form.
474
+ *
475
+ * @param formId - The unique identifier of the form
476
+ * @returns Promise resolving to submission statistics
477
+ * @throws NotFoundError if the form does not exist
478
+ *
479
+ * @example
480
+ * ```typescript
481
+ * const stats = await client.submissions.getStats('form_123');
482
+ * console.log(`Total: ${stats.total}, Unread: ${stats.unread}, Spam: ${stats.spam}`);
483
+ * console.log(`Today: ${stats.today}, This week: ${stats.this_week}`);
484
+ * ```
485
+ *
486
+ * @see Requirements 5.2
487
+ */
488
+ async getStats(formId) {
489
+ return this.http.get(`/forms/${formId}/submissions/stats`);
490
+ }
491
+ /**
492
+ * Export all submissions for a form as JSON.
493
+ *
494
+ * @param formId - The unique identifier of the form
495
+ * @returns Promise resolving to an array of all submissions
496
+ * @throws NotFoundError if the form does not exist
497
+ *
498
+ * @example
499
+ * ```typescript
500
+ * // Export all submissions
501
+ * const allSubmissions = await client.submissions.export('form_123');
502
+ *
503
+ * // Process exported data
504
+ * for (const submission of allSubmissions) {
505
+ * console.log(submission.data);
506
+ * }
507
+ * ```
508
+ *
509
+ * @see Requirements 5.3
510
+ */
511
+ async export(formId) {
512
+ return this.http.get(`/forms/${formId}/submissions/export`);
513
+ }
514
+ /**
515
+ * Perform a bulk update operation on multiple submissions.
516
+ *
517
+ * @param formId - The unique identifier of the form
518
+ * @param data - The bulk update request
519
+ * @param data.action - The action to perform ('markRead', 'markUnread', 'star', 'unstar', 'markSpam', 'notSpam')
520
+ * @param data.submission_ids - Array of submission IDs to update
521
+ * @returns Promise resolving to a success response
522
+ * @throws NotFoundError if the form does not exist
523
+ * @throws ValidationError if the action is invalid or submission IDs are empty
524
+ *
525
+ * @example
526
+ * ```typescript
527
+ * // Mark submissions as read
528
+ * await client.submissions.bulkUpdate('form_123', {
529
+ * action: 'markRead',
530
+ * submission_ids: ['sub_1', 'sub_2', 'sub_3']
531
+ * });
532
+ *
533
+ * // Star submissions
534
+ * await client.submissions.bulkUpdate('form_123', {
535
+ * action: 'star',
536
+ * submission_ids: ['sub_1']
537
+ * });
538
+ *
539
+ * // Mark submissions as spam
540
+ * await client.submissions.bulkUpdate('form_123', {
541
+ * action: 'markSpam',
542
+ * submission_ids: ['sub_4', 'sub_5']
543
+ * });
544
+ *
545
+ * // Mark submissions as not spam
546
+ * await client.submissions.bulkUpdate('form_123', {
547
+ * action: 'notSpam',
548
+ * submission_ids: ['sub_6']
549
+ * });
550
+ * ```
551
+ *
552
+ * @see Requirements 5.4
553
+ */
554
+ async bulkUpdate(formId, data) {
555
+ return this.http.post(`/forms/${formId}/submissions/bulk`, data);
556
+ }
557
+ /**
558
+ * Delete multiple submissions from a form.
559
+ *
560
+ * @param formId - The unique identifier of the form
561
+ * @param submissionIds - Array of submission IDs to delete
562
+ * @returns Promise resolving to a success response
563
+ * @throws NotFoundError if the form does not exist
564
+ * @throws ValidationError if submission IDs are empty
565
+ *
566
+ * @example
567
+ * ```typescript
568
+ * // Delete multiple submissions
569
+ * await client.submissions.bulkDelete('form_123', ['sub_1', 'sub_2', 'sub_3']);
570
+ * ```
571
+ *
572
+ * @see Requirements 5.5
573
+ */
574
+ async bulkDelete(formId, submissionIds) {
575
+ return this.http.delete(`/forms/${formId}/submissions/bulk`, {
576
+ params: {
577
+ ids: submissionIds.join(",")
578
+ }
579
+ });
580
+ }
581
+ };
582
+
583
+ // src/resources/rules.ts
584
+ var RulesResource = class {
585
+ http;
586
+ /**
587
+ * Create a new RulesResource instance
588
+ * @param http - The HTTP client to use for API requests
589
+ */
590
+ constructor(http) {
591
+ this.http = http;
592
+ }
593
+ /**
594
+ * List all rules for a form.
595
+ *
596
+ * @param formId - The unique identifier of the form
597
+ * @returns Promise resolving to an array of rules
598
+ * @throws NotFoundError if the form does not exist
599
+ *
600
+ * @example
601
+ * ```typescript
602
+ * // Get all rules for a form
603
+ * const rules = await client.rules.list('form_123');
604
+ *
605
+ * // Filter active rules
606
+ * const activeRules = rules.filter(rule => rule.is_active);
607
+ *
608
+ * // Check rule conditions
609
+ * for (const rule of rules) {
610
+ * console.log(`Rule: ${rule.name}, Conditions: ${rule.conditions.length}`);
611
+ * }
612
+ * ```
613
+ *
614
+ * @see Requirements 6.1
615
+ */
616
+ async list(formId) {
617
+ return this.http.get(`/forms/${formId}/rules`);
618
+ }
619
+ /**
620
+ * Create a new rule for a form.
621
+ *
622
+ * @param formId - The unique identifier of the form
623
+ * @param data - The rule data to create
624
+ * @param data.name - Display name for the rule (required)
625
+ * @param data.conditions - Array of conditions that must be met (required)
626
+ * @param data.actions - Array of actions to take when conditions are met (required)
627
+ * @param data.is_active - Whether the rule should be active (defaults to true)
628
+ * @returns Promise resolving to the created rule
629
+ * @throws NotFoundError if the form does not exist
630
+ * @throws ValidationError if the rule data is invalid
631
+ *
632
+ * @example
633
+ * ```typescript
634
+ * // Create a simple email notification rule
635
+ * const rule = await client.rules.create('form_123', {
636
+ * name: 'Notify on VIP submission',
637
+ * conditions: [
638
+ * { field: 'email', operator: 'ends_with', value: '@vip.com' }
639
+ * ],
640
+ * actions: [
641
+ * { type: 'email', config: { to: 'sales@company.com', subject: 'VIP Lead!' } }
642
+ * ]
643
+ * });
644
+ *
645
+ * // Create a webhook rule with multiple conditions
646
+ * const webhookRule = await client.rules.create('form_123', {
647
+ * name: 'Send to CRM',
648
+ * conditions: [
649
+ * { field: 'type', operator: 'equals', value: 'enterprise' },
650
+ * { field: 'budget', operator: 'contains', value: '10000' }
651
+ * ],
652
+ * actions: [
653
+ * { type: 'webhook', config: { url: 'https://crm.example.com/leads' } }
654
+ * ],
655
+ * is_active: true
656
+ * });
657
+ *
658
+ * // Create an inactive rule (for testing)
659
+ * const testRule = await client.rules.create('form_123', {
660
+ * name: 'Test Rule',
661
+ * conditions: [{ field: 'test', operator: 'equals', value: 'true' }],
662
+ * actions: [{ type: 'slack', config: { channel: '#test' } }],
663
+ * is_active: false
664
+ * });
665
+ * ```
666
+ *
667
+ * @see Requirements 6.2
668
+ */
669
+ async create(formId, data) {
670
+ return this.http.post(`/forms/${formId}/rules`, data);
671
+ }
672
+ /**
673
+ * Update a rule's properties.
674
+ *
675
+ * @param formId - The unique identifier of the form
676
+ * @param ruleId - The unique identifier of the rule to update
677
+ * @param data - The properties to update
678
+ * @param data.name - New display name for the rule
679
+ * @param data.conditions - New conditions for the rule
680
+ * @param data.actions - New actions for the rule
681
+ * @param data.is_active - Whether the rule should be active
682
+ * @returns Promise resolving to the updated rule
683
+ * @throws NotFoundError if the form or rule does not exist
684
+ * @throws ValidationError if the update data is invalid
685
+ *
686
+ * @example
687
+ * ```typescript
688
+ * // Update rule name
689
+ * const rule = await client.rules.update('form_123', 'rule_456', {
690
+ * name: 'Updated Rule Name'
691
+ * });
692
+ *
693
+ * // Deactivate a rule
694
+ * const rule = await client.rules.update('form_123', 'rule_456', {
695
+ * is_active: false
696
+ * });
697
+ *
698
+ * // Update conditions
699
+ * const rule = await client.rules.update('form_123', 'rule_456', {
700
+ * conditions: [
701
+ * { field: 'email', operator: 'contains', value: '@newdomain.com' }
702
+ * ]
703
+ * });
704
+ *
705
+ * // Update actions
706
+ * const rule = await client.rules.update('form_123', 'rule_456', {
707
+ * actions: [
708
+ * { type: 'discord', config: { webhook_url: 'https://discord.com/api/webhooks/...' } }
709
+ * ]
710
+ * });
711
+ *
712
+ * // Update multiple properties at once
713
+ * const rule = await client.rules.update('form_123', 'rule_456', {
714
+ * name: 'New Name',
715
+ * is_active: true,
716
+ * conditions: [{ field: 'status', operator: 'equals', value: 'urgent' }],
717
+ * actions: [{ type: 'email', config: { to: 'urgent@company.com' } }]
718
+ * });
719
+ * ```
720
+ *
721
+ * @see Requirements 6.3
722
+ */
723
+ async update(formId, ruleId, data) {
724
+ return this.http.patch(`/forms/${formId}/rules/${ruleId}`, data);
725
+ }
726
+ /**
727
+ * Delete a rule by ID.
728
+ *
729
+ * @param formId - The unique identifier of the form
730
+ * @param ruleId - The unique identifier of the rule to delete
731
+ * @returns Promise resolving to a success response
732
+ * @throws NotFoundError if the form or rule does not exist
733
+ *
734
+ * @example
735
+ * ```typescript
736
+ * // Delete a rule
737
+ * await client.rules.delete('form_123', 'rule_456');
738
+ *
739
+ * // Delete multiple rules
740
+ * const ruleIds = ['rule_1', 'rule_2', 'rule_3'];
741
+ * for (const ruleId of ruleIds) {
742
+ * await client.rules.delete('form_123', ruleId);
743
+ * }
744
+ * ```
745
+ *
746
+ * @see Requirements 6.4
747
+ */
748
+ async delete(formId, ruleId) {
749
+ return this.http.delete(`/forms/${formId}/rules/${ruleId}`);
750
+ }
751
+ };
752
+
753
+ // src/resources/projects.ts
754
+ var ProjectsResource = class {
755
+ http;
756
+ /**
757
+ * Create a new ProjectsResource instance
758
+ * @param http - The HTTP client to use for API requests
759
+ */
760
+ constructor(http) {
761
+ this.http = http;
762
+ }
763
+ /**
764
+ * List all projects.
765
+ *
766
+ * @returns Promise resolving to an array of projects
767
+ *
768
+ * @example
769
+ * ```typescript
770
+ * const projects = await client.projects.list();
771
+ * console.log(`Found ${projects.length} projects`);
772
+ * ```
773
+ *
774
+ * @see Requirements 7.1
775
+ */
776
+ async list() {
777
+ const response = await this.http.get("/projects");
778
+ return response.projects;
779
+ }
780
+ /**
781
+ * Create a new project.
782
+ *
783
+ * @param data - The project data to create
784
+ * @param data.name - Display name for the project (required)
785
+ * @returns Promise resolving to the created project
786
+ *
787
+ * @example
788
+ * ```typescript
789
+ * const project = await client.projects.create({ name: 'Marketing Forms' });
790
+ * console.log('Created project:', project.id);
791
+ * ```
792
+ *
793
+ * @see Requirements 7.2
794
+ */
795
+ async create(data) {
796
+ return this.http.post("/projects", data);
797
+ }
798
+ /**
799
+ * Get a single project by ID.
800
+ *
801
+ * @param id - The unique identifier of the project
802
+ * @returns Promise resolving to the project
803
+ * @throws NotFoundError if the project does not exist
804
+ *
805
+ * @example
806
+ * ```typescript
807
+ * const project = await client.projects.get('proj_123');
808
+ * console.log(project.name, project.form_count);
809
+ * ```
810
+ *
811
+ * @see Requirements 7.3
812
+ */
813
+ async get(id) {
814
+ return this.http.get(`/projects/${id}`);
815
+ }
816
+ /**
817
+ * Update a project's properties.
818
+ *
819
+ * @param id - The unique identifier of the project to update
820
+ * @param data - The properties to update
821
+ * @param data.name - New display name for the project
822
+ * @returns Promise resolving to the updated project
823
+ * @throws NotFoundError if the project does not exist
824
+ *
825
+ * @example
826
+ * ```typescript
827
+ * const project = await client.projects.update('proj_123', { name: 'New Name' });
828
+ * console.log('Updated project:', project.name);
829
+ * ```
830
+ *
831
+ * @see Requirements 7.4
832
+ */
833
+ async update(id, data) {
834
+ return this.http.patch(`/projects/${id}`, data);
835
+ }
836
+ /**
837
+ * Delete a project by ID.
838
+ *
839
+ * @param id - The unique identifier of the project to delete
840
+ * @returns Promise resolving to a success response
841
+ * @throws NotFoundError if the project does not exist
842
+ *
843
+ * @example
844
+ * ```typescript
845
+ * await client.projects.delete('proj_123');
846
+ * ```
847
+ *
848
+ * @see Requirements 7.5
849
+ */
850
+ async delete(id) {
851
+ return this.http.delete(`/projects/${id}`);
852
+ }
853
+ };
854
+
855
+ // src/resources/teams.ts
856
+ var TeamsResource = class {
857
+ http;
858
+ /**
859
+ * Create a new TeamsResource instance
860
+ * @param http - The HTTP client to use for API requests
861
+ */
862
+ constructor(http) {
863
+ this.http = http;
864
+ }
865
+ /**
866
+ * List all teams.
867
+ *
868
+ * @returns Promise resolving to an array of teams
869
+ *
870
+ * @example
871
+ * ```typescript
872
+ * const teams = await client.teams.list();
873
+ * console.log(`Found ${teams.length} teams`);
874
+ * ```
875
+ *
876
+ * @see Requirements 8.1
877
+ */
878
+ async list() {
879
+ return this.http.get("/teams");
880
+ }
881
+ /**
882
+ * Create a new team.
883
+ *
884
+ * @param data - The team data to create
885
+ * @param data.name - Display name for the team (required)
886
+ * @returns Promise resolving to the created team
887
+ *
888
+ * @example
889
+ * ```typescript
890
+ * const team = await client.teams.create({ name: 'Marketing Team' });
891
+ * console.log('Created team:', team.id);
892
+ * ```
893
+ *
894
+ * @see Requirements 8.2
895
+ */
896
+ async create(data) {
897
+ return this.http.post("/teams", data);
898
+ }
899
+ /**
900
+ * Get a single team by ID.
901
+ *
902
+ * @param id - The unique identifier of the team
903
+ * @returns Promise resolving to the team
904
+ * @throws NotFoundError if the team does not exist
905
+ *
906
+ * @example
907
+ * ```typescript
908
+ * const team = await client.teams.get('team_123');
909
+ * console.log(team.name, team.member_count);
910
+ * ```
911
+ *
912
+ * @see Requirements 8.3
913
+ */
914
+ async get(id) {
915
+ return this.http.get(`/teams/${id}`);
916
+ }
917
+ /**
918
+ * Update a team's properties.
919
+ *
920
+ * @param id - The unique identifier of the team to update
921
+ * @param data - The properties to update
922
+ * @param data.name - New display name for the team
923
+ * @returns Promise resolving to the updated team
924
+ * @throws NotFoundError if the team does not exist
925
+ *
926
+ * @example
927
+ * ```typescript
928
+ * const team = await client.teams.update('team_123', { name: 'New Name' });
929
+ * console.log('Updated team:', team.name);
930
+ * ```
931
+ *
932
+ * @see Requirements 8.4
933
+ */
934
+ async update(id, data) {
935
+ return this.http.patch(`/teams/${id}`, data);
936
+ }
937
+ /**
938
+ * Delete a team by ID.
939
+ *
940
+ * @param id - The unique identifier of the team to delete
941
+ * @returns Promise resolving to a success response
942
+ * @throws NotFoundError if the team does not exist
943
+ *
944
+ * @example
945
+ * ```typescript
946
+ * await client.teams.delete('team_123');
947
+ * ```
948
+ *
949
+ * @see Requirements 8.5
950
+ */
951
+ async delete(id) {
952
+ return this.http.delete(`/teams/${id}`);
953
+ }
954
+ /**
955
+ * List all members of a team.
956
+ *
957
+ * @param teamId - The unique identifier of the team
958
+ * @returns Promise resolving to an array of team members
959
+ * @throws NotFoundError if the team does not exist
960
+ *
961
+ * @example
962
+ * ```typescript
963
+ * const members = await client.teams.listMembers('team_123');
964
+ * members.forEach(member => {
965
+ * console.log(`${member.user.name} (${member.role})`);
966
+ * });
967
+ * ```
968
+ *
969
+ * @see Requirements 8.6
970
+ */
971
+ async listMembers(teamId) {
972
+ return this.http.get(`/teams/${teamId}/members`);
973
+ }
974
+ /**
975
+ * Add a user to a team.
976
+ *
977
+ * @param teamId - The unique identifier of the team
978
+ * @param data - The member data
979
+ * @param data.email - Email address of the user to add
980
+ * @param data.role - Role to assign ('admin' or 'member')
981
+ * @returns Promise resolving to the created team member
982
+ * @throws NotFoundError if the team does not exist
983
+ * @throws ValidationError if the user is already a member
984
+ *
985
+ * @example
986
+ * ```typescript
987
+ * const member = await client.teams.addMember('team_123', {
988
+ * email: 'user@example.com',
989
+ * role: 'member'
990
+ * });
991
+ * console.log('Added member:', member.user.name);
992
+ * ```
993
+ *
994
+ * @see Requirements 8.7
995
+ */
996
+ async addMember(teamId, data) {
997
+ return this.http.post(`/teams/${teamId}/members`, data);
998
+ }
999
+ /**
1000
+ * Update a team member's role.
1001
+ *
1002
+ * @param teamId - The unique identifier of the team
1003
+ * @param memberId - The unique identifier of the team member
1004
+ * @param data - The properties to update
1005
+ * @param data.role - New role for the member ('admin' or 'member')
1006
+ * @returns Promise resolving to the updated team member
1007
+ * @throws NotFoundError if the team or member does not exist
1008
+ *
1009
+ * @example
1010
+ * ```typescript
1011
+ * const member = await client.teams.updateMember('team_123', 'member_456', {
1012
+ * role: 'admin'
1013
+ * });
1014
+ * console.log('Updated role to:', member.role);
1015
+ * ```
1016
+ *
1017
+ * @see Requirements 8.8
1018
+ */
1019
+ async updateMember(teamId, memberId, data) {
1020
+ return this.http.patch(`/teams/${teamId}/members/${memberId}`, data);
1021
+ }
1022
+ /**
1023
+ * Remove a member from a team.
1024
+ *
1025
+ * @param teamId - The unique identifier of the team
1026
+ * @param memberId - The unique identifier of the team member to remove
1027
+ * @returns Promise resolving to a success response
1028
+ * @throws NotFoundError if the team or member does not exist
1029
+ *
1030
+ * @example
1031
+ * ```typescript
1032
+ * await client.teams.removeMember('team_123', 'member_456');
1033
+ * ```
1034
+ *
1035
+ * @see Requirements 8.9
1036
+ */
1037
+ async removeMember(teamId, memberId) {
1038
+ return this.http.delete(`/teams/${teamId}/members/${memberId}`);
1039
+ }
1040
+ /**
1041
+ * List all pending invitations for a team.
1042
+ *
1043
+ * @param teamId - The unique identifier of the team
1044
+ * @returns Promise resolving to an array of pending invitations
1045
+ * @throws NotFoundError if the team does not exist
1046
+ *
1047
+ * @example
1048
+ * ```typescript
1049
+ * const invitations = await client.teams.listInvitations('team_123');
1050
+ * invitations.forEach(inv => {
1051
+ * console.log(`${inv.email} invited as ${inv.role}`);
1052
+ * });
1053
+ * ```
1054
+ *
1055
+ * @see Requirements 8.10
1056
+ */
1057
+ async listInvitations(teamId) {
1058
+ return this.http.get(`/teams/${teamId}/invitations`);
1059
+ }
1060
+ /**
1061
+ * Create a new invitation to join a team.
1062
+ *
1063
+ * @param teamId - The unique identifier of the team
1064
+ * @param data - The invitation data
1065
+ * @param data.email - Email address of the person to invite
1066
+ * @param data.role - Role to assign upon acceptance ('admin' or 'member')
1067
+ * @returns Promise resolving to the created invitation
1068
+ * @throws NotFoundError if the team does not exist
1069
+ * @throws ValidationError if an invitation already exists for this email
1070
+ *
1071
+ * @example
1072
+ * ```typescript
1073
+ * const invitation = await client.teams.invite('team_123', {
1074
+ * email: 'newuser@example.com',
1075
+ * role: 'member'
1076
+ * });
1077
+ * console.log('Invitation token:', invitation.token);
1078
+ * ```
1079
+ *
1080
+ * @see Requirements 8.11
1081
+ */
1082
+ async invite(teamId, data) {
1083
+ return this.http.post(`/teams/${teamId}/invitations`, data);
1084
+ }
1085
+ /**
1086
+ * Cancel a pending invitation.
1087
+ *
1088
+ * @param teamId - The unique identifier of the team
1089
+ * @param invitationId - The unique identifier of the invitation to cancel
1090
+ * @returns Promise resolving to a success response
1091
+ * @throws NotFoundError if the team or invitation does not exist
1092
+ *
1093
+ * @example
1094
+ * ```typescript
1095
+ * await client.teams.cancelInvitation('team_123', 'inv_456');
1096
+ * ```
1097
+ *
1098
+ * @see Requirements 8.12
1099
+ */
1100
+ async cancelInvitation(teamId, invitationId) {
1101
+ return this.http.delete(`/teams/${teamId}/invitations/${invitationId}`);
1102
+ }
1103
+ /**
1104
+ * Accept a team invitation using the invitation token.
1105
+ *
1106
+ * @param token - The unique invitation token
1107
+ * @returns Promise resolving to a success response
1108
+ * @throws NotFoundError if the invitation does not exist or has expired
1109
+ *
1110
+ * @example
1111
+ * ```typescript
1112
+ * await client.teams.acceptInvitation('inv_token_abc123');
1113
+ * ```
1114
+ *
1115
+ * @see Requirements 8.13
1116
+ */
1117
+ async acceptInvitation(token) {
1118
+ return this.http.post(`/invitations/${token}/accept`);
1119
+ }
1120
+ };
1121
+
1122
+ // src/resources/user.ts
1123
+ var UserResource = class {
1124
+ http;
1125
+ /**
1126
+ * Create a new UserResource instance
1127
+ * @param http - The HTTP client to use for API requests
1128
+ */
1129
+ constructor(http) {
1130
+ this.http = http;
1131
+ }
1132
+ /**
1133
+ * Get the current user profile.
1134
+ *
1135
+ * @returns Promise resolving to the current user
1136
+ *
1137
+ * @example
1138
+ * ```typescript
1139
+ * const user = await client.user.get();
1140
+ * console.log(`Hello, ${user.name}!`);
1141
+ * console.log(`2FA enabled: ${user.two_factor_enabled}`);
1142
+ * ```
1143
+ *
1144
+ * @see Requirements 9.1
1145
+ */
1146
+ async get() {
1147
+ return this.http.get("/user");
1148
+ }
1149
+ /**
1150
+ * Update the current user's profile properties.
1151
+ *
1152
+ * @param data - The properties to update
1153
+ * @param data.name - New display name for the user
1154
+ * @param data.email - New email address for the user
1155
+ * @returns Promise resolving to the updated user
1156
+ *
1157
+ * @example
1158
+ * ```typescript
1159
+ * const user = await client.user.update({ name: 'New Name' });
1160
+ * console.log('Updated name:', user.name);
1161
+ * ```
1162
+ *
1163
+ * @see Requirements 9.2
1164
+ */
1165
+ async update(data) {
1166
+ return this.http.patch("/user", data);
1167
+ }
1168
+ /**
1169
+ * Delete the current user's account.
1170
+ *
1171
+ * This action is irreversible and will delete all associated data.
1172
+ *
1173
+ * @returns Promise resolving to a success response
1174
+ *
1175
+ * @example
1176
+ * ```typescript
1177
+ * await client.user.delete();
1178
+ * console.log('Account deleted');
1179
+ * ```
1180
+ *
1181
+ * @see Requirements 9.3
1182
+ */
1183
+ async delete() {
1184
+ return this.http.delete("/user");
1185
+ }
1186
+ /**
1187
+ * Initiate two-factor authentication setup.
1188
+ *
1189
+ * Returns a secret and QR code for configuring an authenticator app.
1190
+ *
1191
+ * @returns Promise resolving to the 2FA setup response with secret and QR code
1192
+ *
1193
+ * @example
1194
+ * ```typescript
1195
+ * const setup = await client.user.setup2FA();
1196
+ * console.log('Secret:', setup.secret);
1197
+ * console.log('QR Code:', setup.qr_code);
1198
+ * // Display QR code to user for scanning with authenticator app
1199
+ * ```
1200
+ *
1201
+ * @see Requirements 9.4
1202
+ */
1203
+ async setup2FA() {
1204
+ return this.http.post("/user/2fa/setup");
1205
+ }
1206
+ /**
1207
+ * Enable two-factor authentication with a verification code.
1208
+ *
1209
+ * Call this after setup2FA to confirm the user has configured their
1210
+ * authenticator app correctly.
1211
+ *
1212
+ * @param code - The 6-digit verification code from the authenticator app
1213
+ * @returns Promise resolving to a success response
1214
+ * @throws ValidationError if the code is invalid
1215
+ *
1216
+ * @example
1217
+ * ```typescript
1218
+ * await client.user.enable2FA('123456');
1219
+ * console.log('2FA enabled successfully');
1220
+ * ```
1221
+ *
1222
+ * @see Requirements 9.5
1223
+ */
1224
+ async enable2FA(code) {
1225
+ return this.http.post("/user/2fa/enable", { code });
1226
+ }
1227
+ /**
1228
+ * Disable two-factor authentication.
1229
+ *
1230
+ * Requires a valid verification code to confirm the user's identity.
1231
+ *
1232
+ * @param code - The 6-digit verification code from the authenticator app
1233
+ * @returns Promise resolving to a success response
1234
+ * @throws ValidationError if the code is invalid
1235
+ *
1236
+ * @example
1237
+ * ```typescript
1238
+ * await client.user.disable2FA('123456');
1239
+ * console.log('2FA disabled');
1240
+ * ```
1241
+ *
1242
+ * @see Requirements 9.6
1243
+ */
1244
+ async disable2FA(code) {
1245
+ return this.http.post("/user/2fa/disable", { code });
1246
+ }
1247
+ /**
1248
+ * Verify a two-factor authentication code.
1249
+ *
1250
+ * Use this to verify a 2FA code during login or sensitive operations.
1251
+ *
1252
+ * @param code - The 6-digit verification code from the authenticator app
1253
+ * @returns Promise resolving to a success response
1254
+ * @throws ValidationError if the code is invalid
1255
+ *
1256
+ * @example
1257
+ * ```typescript
1258
+ * await client.user.verify2FA('123456');
1259
+ * console.log('2FA code verified');
1260
+ * ```
1261
+ *
1262
+ * @see Requirements 9.7
1263
+ */
1264
+ async verify2FA(code) {
1265
+ return this.http.post("/user/2fa/verify", { code });
1266
+ }
1267
+ /**
1268
+ * List all API keys for the current user.
1269
+ *
1270
+ * Note: The `key` field will only contain the full key value when
1271
+ * the key is first created. For existing keys, it may be masked.
1272
+ *
1273
+ * @returns Promise resolving to an array of API keys
1274
+ *
1275
+ * @example
1276
+ * ```typescript
1277
+ * const keys = await client.user.listApiKeys();
1278
+ * keys.forEach(key => {
1279
+ * console.log(`${key.name}: last used ${key.last_used_at || 'never'}`);
1280
+ * });
1281
+ * ```
1282
+ *
1283
+ * @see Requirements 9.8
1284
+ */
1285
+ async listApiKeys() {
1286
+ const response = await this.http.get("/user/api-keys");
1287
+ return response.apiKeys;
1288
+ }
1289
+ /**
1290
+ * Create a new API key.
1291
+ *
1292
+ * The returned API key will include the full key value in the `key` field.
1293
+ * This is the only time the full key is available - store it securely.
1294
+ *
1295
+ * @param data - The API key data
1296
+ * @param data.name - Display name for the API key (required)
1297
+ * @returns Promise resolving to the created API key with full key value
1298
+ *
1299
+ * @example
1300
+ * ```typescript
1301
+ * const apiKey = await client.user.createApiKey({ name: 'My Application' });
1302
+ * console.log('API Key created:', apiKey.key);
1303
+ * // Store this key securely - it won't be shown again!
1304
+ * ```
1305
+ *
1306
+ * @see Requirements 9.9
1307
+ */
1308
+ async createApiKey(data) {
1309
+ const response = await this.http.post("/user/api-keys", data);
1310
+ return response.apiKey;
1311
+ }
1312
+ /**
1313
+ * Delete an API key by ID.
1314
+ *
1315
+ * @param id - The unique identifier of the API key to delete
1316
+ * @returns Promise resolving to a success response
1317
+ * @throws NotFoundError if the API key does not exist
1318
+ *
1319
+ * @example
1320
+ * ```typescript
1321
+ * await client.user.deleteApiKey('key_123');
1322
+ * console.log('API key deleted');
1323
+ * ```
1324
+ *
1325
+ * @see Requirements 9.10
1326
+ */
1327
+ async deleteApiKey(id) {
1328
+ return this.http.delete(`/user/api-keys/${id}`);
1329
+ }
1330
+ };
1331
+
1332
+ // src/resources/billing.ts
1333
+ var BillingResource = class {
1334
+ http;
1335
+ /**
1336
+ * Create a new BillingResource instance
1337
+ * @param http - The HTTP client to use for API requests
1338
+ */
1339
+ constructor(http) {
1340
+ this.http = http;
1341
+ }
1342
+ /**
1343
+ * Create a Stripe checkout session for starting a new subscription.
1344
+ *
1345
+ * Returns a URL that the user should be redirected to in order to
1346
+ * complete the checkout process on Stripe's hosted checkout page.
1347
+ *
1348
+ * @param data - The checkout session configuration
1349
+ * @param data.price_id - The Stripe price ID for the subscription plan
1350
+ * @param data.success_url - URL to redirect to after successful checkout
1351
+ * @param data.cancel_url - URL to redirect to if checkout is cancelled
1352
+ * @returns Promise resolving to the checkout response with redirect URL
1353
+ *
1354
+ * @example
1355
+ * ```typescript
1356
+ * const checkout = await client.billing.createCheckout({
1357
+ * price_id: 'price_1234567890',
1358
+ * success_url: 'https://myapp.com/checkout/success',
1359
+ * cancel_url: 'https://myapp.com/checkout/cancel'
1360
+ * });
1361
+ *
1362
+ * // Redirect the user to complete checkout
1363
+ * window.location.href = checkout.url;
1364
+ * ```
1365
+ *
1366
+ * @see Requirements 10.1
1367
+ */
1368
+ async createCheckout(data) {
1369
+ return this.http.post("/billing/checkout", data);
1370
+ }
1371
+ /**
1372
+ * Create a Stripe billing portal session for managing an existing subscription.
1373
+ *
1374
+ * Returns a URL that the user should be redirected to in order to
1375
+ * access the Stripe billing portal where they can:
1376
+ * - View and update payment methods
1377
+ * - View billing history and invoices
1378
+ * - Upgrade, downgrade, or cancel their subscription
1379
+ *
1380
+ * @returns Promise resolving to the portal response with redirect URL
1381
+ *
1382
+ * @example
1383
+ * ```typescript
1384
+ * const portal = await client.billing.createPortal();
1385
+ *
1386
+ * // Redirect the user to the billing portal
1387
+ * window.location.href = portal.url;
1388
+ * ```
1389
+ *
1390
+ * @see Requirements 10.2
1391
+ */
1392
+ async createPortal() {
1393
+ return this.http.post("/billing/portal");
1394
+ }
1395
+ };
1396
+
1397
+ // src/resources/files.ts
1398
+ var FilesResource = class {
1399
+ http;
1400
+ /**
1401
+ * Create a new FilesResource instance
1402
+ * @param http - The HTTP client to use for API requests
1403
+ */
1404
+ constructor(http) {
1405
+ this.http = http;
1406
+ }
1407
+ /**
1408
+ * Get a signed download URL for a file.
1409
+ *
1410
+ * Returns a temporary signed URL that can be used to download the file.
1411
+ * The URL will expire at the time indicated in the response.
1412
+ *
1413
+ * @param id - The unique identifier of the file
1414
+ * @returns Promise resolving to the download response with signed URL and expiration
1415
+ *
1416
+ * @example
1417
+ * ```typescript
1418
+ * const download = await client.files.getDownloadUrl('file_abc123');
1419
+ *
1420
+ * // Use the signed URL to download the file
1421
+ * const response = await fetch(download.url);
1422
+ * const blob = await response.blob();
1423
+ *
1424
+ * // Check when the URL expires
1425
+ * console.log(`URL expires at: ${download.expires_at}`);
1426
+ * ```
1427
+ *
1428
+ * @see Requirements 11.1
1429
+ */
1430
+ async getDownloadUrl(id) {
1431
+ return this.http.get(`/files/${id}/download`);
1432
+ }
1433
+ /**
1434
+ * Delete a file by ID.
1435
+ *
1436
+ * Permanently removes the file from storage. This action cannot be undone.
1437
+ *
1438
+ * @param id - The unique identifier of the file to delete
1439
+ * @returns Promise resolving to a success response
1440
+ *
1441
+ * @example
1442
+ * ```typescript
1443
+ * const result = await client.files.delete('file_abc123');
1444
+ *
1445
+ * if (result.success) {
1446
+ * console.log('File deleted successfully');
1447
+ * }
1448
+ * ```
1449
+ *
1450
+ * @see Requirements 11.2
1451
+ */
1452
+ async delete(id) {
1453
+ return this.http.delete(`/files/${id}`);
1454
+ }
1455
+ };
1456
+
1457
+ // src/client.ts
1458
+ var DEFAULT_BASE_URL = "https://api.spike.ac";
1459
+ var DEFAULT_TIMEOUT = 3e4;
1460
+ var SpikeClient = class {
1461
+ /**
1462
+ * Resource for managing forms.
1463
+ * @see FormsResource
1464
+ */
1465
+ forms;
1466
+ /**
1467
+ * Resource for managing form submissions.
1468
+ * @see SubmissionsResource
1469
+ */
1470
+ submissions;
1471
+ /**
1472
+ * Resource for managing form rules.
1473
+ * @see RulesResource
1474
+ */
1475
+ rules;
1476
+ /**
1477
+ * Resource for managing projects.
1478
+ * @see ProjectsResource
1479
+ */
1480
+ projects;
1481
+ /**
1482
+ * Resource for managing teams.
1483
+ * @see TeamsResource
1484
+ */
1485
+ teams;
1486
+ /**
1487
+ * Resource for managing user profile and settings.
1488
+ * @see UserResource
1489
+ */
1490
+ user;
1491
+ /**
1492
+ * Resource for managing billing and subscriptions.
1493
+ * @see BillingResource
1494
+ */
1495
+ billing;
1496
+ /**
1497
+ * Resource for managing uploaded files.
1498
+ * @see FilesResource
1499
+ */
1500
+ files;
1501
+ /**
1502
+ * The HTTP client used for API requests.
1503
+ * @internal
1504
+ */
1505
+ http;
1506
+ /**
1507
+ * Create a new Spike client instance.
1508
+ *
1509
+ * @param config - Configuration options for the client
1510
+ * @throws ValidationError if the API key is missing or empty
1511
+ *
1512
+ * @example
1513
+ * ```typescript
1514
+ * // Basic usage with API key
1515
+ * const client = new SpikeClient({ apiKey: 'sk_live_abc123' });
1516
+ *
1517
+ * // With all configuration options
1518
+ * const client = new SpikeClient({
1519
+ * apiKey: 'sk_live_abc123',
1520
+ * baseUrl: 'https://spike.ac',
1521
+ * timeout: 30000
1522
+ * });
1523
+ * ```
1524
+ *
1525
+ * @see Requirements 1.1, 1.2, 1.3, 1.4, 1.5
1526
+ */
1527
+ constructor(config) {
1528
+ if (!config.apiKey) {
1529
+ throw new ValidationError("API key is required. Please provide a valid API key.");
1530
+ }
1531
+ this.http = new HttpClient({
1532
+ apiKey: config.apiKey,
1533
+ baseUrl: config.baseUrl ?? DEFAULT_BASE_URL,
1534
+ timeout: config.timeout ?? DEFAULT_TIMEOUT
1535
+ });
1536
+ this.forms = new FormsResource(this.http);
1537
+ this.submissions = new SubmissionsResource(this.http);
1538
+ this.rules = new RulesResource(this.http);
1539
+ this.projects = new ProjectsResource(this.http);
1540
+ this.teams = new TeamsResource(this.http);
1541
+ this.user = new UserResource(this.http);
1542
+ this.billing = new BillingResource(this.http);
1543
+ this.files = new FilesResource(this.http);
1544
+ }
1545
+ };
1546
+
1547
+ // src/index.ts
1548
+ var VERSION = "0.1.0";
1549
+
1550
+ export { AuthenticationError, BillingResource, FilesResource, FormsResource, NetworkError, NotFoundError, ProjectsResource, RateLimitError, RulesResource, SpikeClient, SpikeError, SubmissionsResource, TeamsResource, UserResource, VERSION, ValidationError };
1551
+ //# sourceMappingURL=index.mjs.map
1552
+ //# sourceMappingURL=index.mjs.map