@stack0/sdk 0.2.9 → 0.3.1

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 (42) hide show
  1. package/README.md +233 -10
  2. package/dist/cdn/index.d.mts +239 -26
  3. package/dist/cdn/index.d.ts +239 -26
  4. package/dist/cdn/index.js +219 -20
  5. package/dist/cdn/index.js.map +1 -1
  6. package/dist/cdn/index.mjs +219 -20
  7. package/dist/cdn/index.mjs.map +1 -1
  8. package/dist/extraction/index.d.mts +1 -1
  9. package/dist/extraction/index.d.ts +1 -1
  10. package/dist/extraction/index.js +33 -29
  11. package/dist/extraction/index.js.map +1 -1
  12. package/dist/extraction/index.mjs +33 -29
  13. package/dist/extraction/index.mjs.map +1 -1
  14. package/dist/http-client-Cgie_Rv6.d.mts +25 -0
  15. package/dist/http-client-Cgie_Rv6.d.ts +25 -0
  16. package/dist/index.d.mts +1006 -3
  17. package/dist/index.d.ts +1006 -3
  18. package/dist/index.js +958 -69
  19. package/dist/index.js.map +1 -1
  20. package/dist/index.mjs +957 -70
  21. package/dist/index.mjs.map +1 -1
  22. package/dist/mail/index.d.mts +1 -1
  23. package/dist/mail/index.d.ts +1 -1
  24. package/dist/mail/index.js +13 -5
  25. package/dist/mail/index.js.map +1 -1
  26. package/dist/mail/index.mjs +13 -5
  27. package/dist/mail/index.mjs.map +1 -1
  28. package/dist/screenshots/index.d.mts +1 -1
  29. package/dist/screenshots/index.d.ts +1 -1
  30. package/dist/screenshots/index.js +32 -26
  31. package/dist/screenshots/index.js.map +1 -1
  32. package/dist/screenshots/index.mjs +32 -26
  33. package/dist/screenshots/index.mjs.map +1 -1
  34. package/dist/webdata/index.d.mts +1 -1
  35. package/dist/webdata/index.d.ts +1 -1
  36. package/dist/webdata/index.js +37 -8
  37. package/dist/webdata/index.js.map +1 -1
  38. package/dist/webdata/index.mjs +37 -8
  39. package/dist/webdata/index.mjs.map +1 -1
  40. package/package.json +1 -1
  41. package/dist/http-client-Wr9lXo9_.d.mts +0 -10
  42. package/dist/http-client-Wr9lXo9_.d.ts +0 -10
package/dist/index.js CHANGED
@@ -10,19 +10,24 @@ var HttpClient = class {
10
10
  this.apiKey = config.apiKey;
11
11
  this.baseUrl = config.baseUrl || "https://api.stack0.dev/v1";
12
12
  }
13
- getHeaders() {
14
- return {
15
- "Content-Type": "application/json",
13
+ getHeaders(includeContentType = true) {
14
+ const headers = {
16
15
  Authorization: `Bearer ${this.apiKey}`
17
16
  };
17
+ if (includeContentType) {
18
+ headers["Content-Type"] = "application/json";
19
+ }
20
+ return headers;
18
21
  }
19
22
  async request(method, path, body) {
20
23
  const url = `${this.baseUrl}${path}`;
24
+ const bodyString = body === void 0 ? void 0 : JSON.stringify(body);
25
+ const hasBody = bodyString !== void 0;
21
26
  try {
22
27
  const response = await fetch(url, {
23
28
  method,
24
- headers: this.getHeaders(),
25
- body: body ? JSON.stringify(body) : void 0
29
+ headers: this.getHeaders(hasBody),
30
+ body: hasBody ? bodyString : void 0
26
31
  });
27
32
  if (!response.ok) {
28
33
  await this.handleErrorResponse(response);
@@ -66,6 +71,9 @@ var HttpClient = class {
66
71
  async delete(path) {
67
72
  return this.request("DELETE", path);
68
73
  }
74
+ async deleteWithBody(path, body) {
75
+ return this.request("DELETE", path, body);
76
+ }
69
77
  async patch(path, body) {
70
78
  return this.request("PATCH", path, body);
71
79
  }
@@ -119,10 +127,13 @@ var Mail = class {
119
127
  };
120
128
 
121
129
  // src/cdn/client.ts
130
+ var ALLOWED_WIDTHS = [256, 384, 640, 750, 828, 1080, 1200, 1920, 2048, 3840];
122
131
  var CDN = class {
123
132
  http;
124
- constructor(config) {
133
+ cdnUrl;
134
+ constructor(config, cdnUrl) {
125
135
  this.http = new HttpClient(config);
136
+ this.cdnUrl = cdnUrl;
126
137
  }
127
138
  /**
128
139
  * Generate a presigned URL for uploading a file
@@ -243,7 +254,7 @@ var CDN = class {
243
254
  * ```
244
255
  */
245
256
  async delete(id) {
246
- return this.http.delete(`/cdn/assets/${id}`);
257
+ return this.http.deleteWithBody(`/cdn/assets/${id}`, { id });
247
258
  }
248
259
  /**
249
260
  * Delete multiple assets
@@ -302,24 +313,73 @@ var CDN = class {
302
313
  return this.http.post("/cdn/assets/move", request);
303
314
  }
304
315
  /**
305
- * Get a transformed image URL
316
+ * Get a transformed image URL (client-side, no API call)
306
317
  *
307
318
  * @example
308
319
  * ```typescript
309
- * const { url } = await cdn.getTransformUrl({
310
- * assetId: 'asset-id',
311
- * options: {
312
- * width: 800,
313
- * height: 600,
314
- * fit: 'cover',
315
- * format: 'webp',
316
- * quality: 80,
317
- * },
320
+ * // Using asset's cdnUrl directly
321
+ * const url = cdn.getTransformUrl(asset.cdnUrl, {
322
+ * width: 800,
323
+ * height: 600,
324
+ * fit: 'cover',
325
+ * format: 'webp',
326
+ * quality: 80,
318
327
  * });
328
+ *
329
+ * // Or using cdnUrl from SDK config + s3Key
330
+ * const url = cdn.getTransformUrl(asset.s3Key, { width: 400 });
319
331
  * ```
320
332
  */
321
- async getTransformUrl(request) {
322
- return this.http.post("/cdn/transform", request);
333
+ getTransformUrl(assetUrlOrS3Key, options) {
334
+ let baseUrl;
335
+ if (assetUrlOrS3Key.startsWith("http://") || assetUrlOrS3Key.startsWith("https://")) {
336
+ const url = new URL(assetUrlOrS3Key);
337
+ baseUrl = `${url.protocol}//${url.host}${url.pathname}`;
338
+ } else if (this.cdnUrl) {
339
+ const cdnBase = this.cdnUrl.endsWith("/") ? this.cdnUrl.slice(0, -1) : this.cdnUrl;
340
+ baseUrl = `${cdnBase}/${assetUrlOrS3Key}`;
341
+ } else {
342
+ throw new Error("getTransformUrl requires either a full URL or cdnUrl to be configured in Stack0 options");
343
+ }
344
+ const params = this.buildTransformQuery(options);
345
+ if (!params) {
346
+ return baseUrl;
347
+ }
348
+ return `${baseUrl}?${params}`;
349
+ }
350
+ /**
351
+ * Build transform query parameters
352
+ */
353
+ buildTransformQuery(options) {
354
+ const params = new URLSearchParams();
355
+ if (options.format) params.set("f", options.format);
356
+ if (options.quality !== void 0) params.set("q", options.quality.toString());
357
+ if (options.width !== void 0) {
358
+ const width = this.getNearestWidth(options.width);
359
+ params.set("w", width.toString());
360
+ }
361
+ if (options.height !== void 0) params.set("h", options.height.toString());
362
+ if (options.fit) params.set("fit", options.fit);
363
+ if (options.crop) params.set("crop", options.crop);
364
+ if (options.cropX !== void 0) params.set("crop-x", options.cropX.toString());
365
+ if (options.cropY !== void 0) params.set("crop-y", options.cropY.toString());
366
+ if (options.cropWidth !== void 0) params.set("crop-w", options.cropWidth.toString());
367
+ if (options.cropHeight !== void 0) params.set("crop-h", options.cropHeight.toString());
368
+ if (options.blur !== void 0) params.set("blur", options.blur.toString());
369
+ if (options.sharpen !== void 0) params.set("sharpen", options.sharpen.toString());
370
+ if (options.brightness !== void 0) params.set("brightness", options.brightness.toString());
371
+ if (options.saturation !== void 0) params.set("saturation", options.saturation.toString());
372
+ if (options.grayscale) params.set("grayscale", "true");
373
+ if (options.rotate !== void 0) params.set("rotate", options.rotate.toString());
374
+ if (options.flip) params.set("flip", "y");
375
+ if (options.flop) params.set("flop", "x");
376
+ return params.toString();
377
+ }
378
+ /**
379
+ * Find the nearest allowed width for optimal caching
380
+ */
381
+ getNearestWidth(width) {
382
+ return ALLOWED_WIDTHS.reduce((prev, curr) => Math.abs(curr - width) < Math.abs(prev - width) ? curr : prev);
323
383
  }
324
384
  /**
325
385
  * Get folder tree for navigation
@@ -365,7 +425,10 @@ var CDN = class {
365
425
  async deleteFolder(id, deleteContents = false) {
366
426
  const params = new URLSearchParams();
367
427
  if (deleteContents) params.set("deleteContents", "true");
368
- return this.http.delete(`/cdn/folders/${id}?${params.toString()}`);
428
+ return this.http.deleteWithBody(`/cdn/folders/${id}?${params.toString()}`, {
429
+ id,
430
+ deleteContents
431
+ });
369
432
  }
370
433
  convertAssetDates(asset) {
371
434
  if (typeof asset.createdAt === "string") {
@@ -385,6 +448,142 @@ var CDN = class {
385
448
  }
386
449
  return folder;
387
450
  }
451
+ // ============================================================================
452
+ // Video Transcoding Methods
453
+ // ============================================================================
454
+ /**
455
+ * Start a video transcoding job
456
+ *
457
+ * @example
458
+ * ```typescript
459
+ * const job = await cdn.transcode({
460
+ * projectSlug: 'my-project',
461
+ * assetId: 'video-asset-id',
462
+ * outputFormat: 'hls',
463
+ * variants: [
464
+ * { quality: '720p', codec: 'h264' },
465
+ * { quality: '1080p', codec: 'h264' },
466
+ * ],
467
+ * webhookUrl: 'https://your-app.com/webhook',
468
+ * });
469
+ * console.log(`Job started: ${job.id}`);
470
+ * ```
471
+ */
472
+ async transcode(request) {
473
+ const response = await this.http.post("/cdn/video/transcode", request);
474
+ return this.convertJobDates(response);
475
+ }
476
+ /**
477
+ * Get a transcoding job by ID
478
+ *
479
+ * @example
480
+ * ```typescript
481
+ * const job = await cdn.getJob('job-id');
482
+ * console.log(`Status: ${job.status}, Progress: ${job.progress}%`);
483
+ * ```
484
+ */
485
+ async getJob(jobId) {
486
+ const response = await this.http.get(`/cdn/video/jobs/${jobId}`);
487
+ return this.convertJobDates(response);
488
+ }
489
+ /**
490
+ * List transcoding jobs with filters
491
+ *
492
+ * @example
493
+ * ```typescript
494
+ * const { jobs, total } = await cdn.listJobs({
495
+ * projectSlug: 'my-project',
496
+ * status: 'processing',
497
+ * limit: 20,
498
+ * });
499
+ * ```
500
+ */
501
+ async listJobs(request) {
502
+ const params = new URLSearchParams();
503
+ params.set("projectSlug", request.projectSlug);
504
+ if (request.assetId) params.set("assetId", request.assetId);
505
+ if (request.status) params.set("status", request.status);
506
+ if (request.limit) params.set("limit", request.limit.toString());
507
+ if (request.offset) params.set("offset", request.offset.toString());
508
+ const response = await this.http.get(`/cdn/video/jobs?${params.toString()}`);
509
+ return {
510
+ ...response,
511
+ jobs: response.jobs.map((job) => this.convertJobDates(job))
512
+ };
513
+ }
514
+ /**
515
+ * Cancel a pending or processing transcoding job
516
+ *
517
+ * @example
518
+ * ```typescript
519
+ * await cdn.cancelJob('job-id');
520
+ * ```
521
+ */
522
+ async cancelJob(jobId) {
523
+ return this.http.post(`/cdn/video/jobs/${jobId}/cancel`, {});
524
+ }
525
+ /**
526
+ * Get streaming URLs for a transcoded video
527
+ *
528
+ * @example
529
+ * ```typescript
530
+ * const urls = await cdn.getStreamingUrls('asset-id');
531
+ * console.log(`HLS URL: ${urls.hlsUrl}`);
532
+ * console.log(`MP4 720p: ${urls.mp4Urls.find(u => u.quality === '720p')?.url}`);
533
+ * ```
534
+ */
535
+ async getStreamingUrls(assetId) {
536
+ return this.http.get(`/cdn/video/stream/${assetId}`);
537
+ }
538
+ /**
539
+ * Generate a thumbnail from a video at a specific timestamp
540
+ *
541
+ * @example
542
+ * ```typescript
543
+ * const thumbnail = await cdn.getThumbnail({
544
+ * assetId: 'video-asset-id',
545
+ * timestamp: 10.5, // 10.5 seconds into the video
546
+ * width: 320,
547
+ * format: 'webp',
548
+ * });
549
+ * console.log(`Thumbnail URL: ${thumbnail.url}`);
550
+ * ```
551
+ */
552
+ async getThumbnail(request) {
553
+ const params = new URLSearchParams();
554
+ params.set("timestamp", request.timestamp.toString());
555
+ if (request.width) params.set("width", request.width.toString());
556
+ if (request.format) params.set("format", request.format);
557
+ return this.http.get(`/cdn/video/thumbnail/${request.assetId}?${params.toString()}`);
558
+ }
559
+ /**
560
+ * Extract audio from a video file
561
+ *
562
+ * @example
563
+ * ```typescript
564
+ * const { jobId } = await cdn.extractAudio({
565
+ * projectSlug: 'my-project',
566
+ * assetId: 'video-asset-id',
567
+ * format: 'mp3',
568
+ * bitrate: 192,
569
+ * });
570
+ * ```
571
+ */
572
+ async extractAudio(request) {
573
+ return this.http.post("/cdn/video/extract-audio", request);
574
+ }
575
+ convertJobDates(job) {
576
+ if (typeof job.createdAt === "string") {
577
+ job.createdAt = new Date(job.createdAt);
578
+ }
579
+ if (job.startedAt && typeof job.startedAt === "string") {
580
+ job.startedAt = new Date(job.startedAt);
581
+ }
582
+ if (job.completedAt && typeof job.completedAt === "string") {
583
+ job.completedAt = new Date(job.completedAt);
584
+ }
585
+ return job;
586
+ }
388
587
  };
389
588
 
390
589
  // src/screenshots/client.ts
@@ -456,9 +655,7 @@ var Screenshots = class {
456
655
  if (request.limit) params.set("limit", request.limit.toString());
457
656
  if (request.cursor) params.set("cursor", request.cursor);
458
657
  const query = params.toString();
459
- const response = await this.http.get(
460
- `/webdata/screenshots${query ? `?${query}` : ""}`
461
- );
658
+ const response = await this.http.get(`/webdata/screenshots${query ? `?${query}` : ""}`);
462
659
  return {
463
660
  ...response,
464
661
  items: response.items.map((item) => this.convertDates(item))
@@ -477,8 +674,13 @@ var Screenshots = class {
477
674
  if (request.environment) params.set("environment", request.environment);
478
675
  if (request.projectId) params.set("projectId", request.projectId);
479
676
  const query = params.toString();
480
- return this.http.delete(
481
- `/webdata/screenshots/${request.id}${query ? `?${query}` : ""}`
677
+ return this.http.deleteWithBody(
678
+ `/webdata/screenshots/${request.id}${query ? `?${query}` : ""}`,
679
+ {
680
+ id: request.id,
681
+ environment: request.environment,
682
+ projectId: request.projectId
683
+ }
482
684
  );
483
685
  }
484
686
  /**
@@ -561,9 +763,7 @@ var Screenshots = class {
561
763
  if (request.limit) params.set("limit", request.limit.toString());
562
764
  if (request.cursor) params.set("cursor", request.cursor);
563
765
  const query = params.toString();
564
- const response = await this.http.get(
565
- `/webdata/batch${query ? `?${query}` : ""}`
566
- );
766
+ const response = await this.http.get(`/webdata/batch${query ? `?${query}` : ""}`);
567
767
  return {
568
768
  ...response,
569
769
  items: response.items.map((item) => this.convertBatchJobDates(item))
@@ -577,10 +777,7 @@ var Screenshots = class {
577
777
  if (request.environment) params.set("environment", request.environment);
578
778
  if (request.projectId) params.set("projectId", request.projectId);
579
779
  const query = params.toString();
580
- return this.http.post(
581
- `/webdata/batch/${request.id}/cancel${query ? `?${query}` : ""}`,
582
- {}
583
- );
780
+ return this.http.post(`/webdata/batch/${request.id}/cancel${query ? `?${query}` : ""}`, {});
584
781
  }
585
782
  /**
586
783
  * Create a batch screenshot job and wait for completion
@@ -633,10 +830,7 @@ var Screenshots = class {
633
830
  if (environment) params.set("environment", environment);
634
831
  if (projectId) params.set("projectId", projectId);
635
832
  const query = params.toString();
636
- return this.http.post(
637
- `/webdata/schedules/${id}${query ? `?${query}` : ""}`,
638
- data
639
- );
833
+ return this.http.post(`/webdata/schedules/${id}${query ? `?${query}` : ""}`, data);
640
834
  }
641
835
  /**
642
836
  * Get a schedule by ID
@@ -662,9 +856,7 @@ var Screenshots = class {
662
856
  if (request.limit) params.set("limit", request.limit.toString());
663
857
  if (request.cursor) params.set("cursor", request.cursor);
664
858
  const query = params.toString();
665
- const response = await this.http.get(
666
- `/webdata/schedules${query ? `?${query}` : ""}`
667
- );
859
+ const response = await this.http.get(`/webdata/schedules${query ? `?${query}` : ""}`);
668
860
  return {
669
861
  ...response,
670
862
  items: response.items.map((item) => this.convertScheduleDates(item))
@@ -678,8 +870,13 @@ var Screenshots = class {
678
870
  if (request.environment) params.set("environment", request.environment);
679
871
  if (request.projectId) params.set("projectId", request.projectId);
680
872
  const query = params.toString();
681
- return this.http.delete(
682
- `/webdata/schedules/${request.id}${query ? `?${query}` : ""}`
873
+ return this.http.deleteWithBody(
874
+ `/webdata/schedules/${request.id}${query ? `?${query}` : ""}`,
875
+ {
876
+ id: request.id,
877
+ environment: request.environment,
878
+ projectId: request.projectId
879
+ }
683
880
  );
684
881
  }
685
882
  /**
@@ -805,9 +1002,7 @@ var Extraction = class {
805
1002
  if (request.limit) params.set("limit", request.limit.toString());
806
1003
  if (request.cursor) params.set("cursor", request.cursor);
807
1004
  const query = params.toString();
808
- const response = await this.http.get(
809
- `/webdata/extractions${query ? `?${query}` : ""}`
810
- );
1005
+ const response = await this.http.get(`/webdata/extractions${query ? `?${query}` : ""}`);
811
1006
  return {
812
1007
  ...response,
813
1008
  items: response.items.map((item) => this.convertDates(item))
@@ -826,8 +1021,13 @@ var Extraction = class {
826
1021
  if (request.environment) params.set("environment", request.environment);
827
1022
  if (request.projectId) params.set("projectId", request.projectId);
828
1023
  const query = params.toString();
829
- return this.http.delete(
830
- `/webdata/extractions/${request.id}${query ? `?${query}` : ""}`
1024
+ return this.http.deleteWithBody(
1025
+ `/webdata/extractions/${request.id}${query ? `?${query}` : ""}`,
1026
+ {
1027
+ id: request.id,
1028
+ environment: request.environment,
1029
+ projectId: request.projectId
1030
+ }
831
1031
  );
832
1032
  }
833
1033
  /**
@@ -906,9 +1106,7 @@ var Extraction = class {
906
1106
  if (request.limit) params.set("limit", request.limit.toString());
907
1107
  if (request.cursor) params.set("cursor", request.cursor);
908
1108
  const query = params.toString();
909
- const response = await this.http.get(
910
- `/webdata/batch${query ? `?${query}` : ""}`
911
- );
1109
+ const response = await this.http.get(`/webdata/batch${query ? `?${query}` : ""}`);
912
1110
  return {
913
1111
  ...response,
914
1112
  items: response.items.map((item) => this.convertBatchJobDates(item))
@@ -922,10 +1120,7 @@ var Extraction = class {
922
1120
  if (request.environment) params.set("environment", request.environment);
923
1121
  if (request.projectId) params.set("projectId", request.projectId);
924
1122
  const query = params.toString();
925
- return this.http.post(
926
- `/webdata/batch/${request.id}/cancel${query ? `?${query}` : ""}`,
927
- {}
928
- );
1123
+ return this.http.post(`/webdata/batch/${request.id}/cancel${query ? `?${query}` : ""}`, {});
929
1124
  }
930
1125
  /**
931
1126
  * Create a batch extraction job and wait for completion
@@ -978,10 +1173,7 @@ var Extraction = class {
978
1173
  if (environment) params.set("environment", environment);
979
1174
  if (projectId) params.set("projectId", projectId);
980
1175
  const query = params.toString();
981
- return this.http.post(
982
- `/webdata/schedules/${id}${query ? `?${query}` : ""}`,
983
- data
984
- );
1176
+ return this.http.post(`/webdata/schedules/${id}${query ? `?${query}` : ""}`, data);
985
1177
  }
986
1178
  /**
987
1179
  * Get a schedule by ID
@@ -1007,9 +1199,7 @@ var Extraction = class {
1007
1199
  if (request.limit) params.set("limit", request.limit.toString());
1008
1200
  if (request.cursor) params.set("cursor", request.cursor);
1009
1201
  const query = params.toString();
1010
- const response = await this.http.get(
1011
- `/webdata/schedules${query ? `?${query}` : ""}`
1012
- );
1202
+ const response = await this.http.get(`/webdata/schedules${query ? `?${query}` : ""}`);
1013
1203
  return {
1014
1204
  ...response,
1015
1205
  items: response.items.map((item) => this.convertScheduleDates(item))
@@ -1023,8 +1213,13 @@ var Extraction = class {
1023
1213
  if (request.environment) params.set("environment", request.environment);
1024
1214
  if (request.projectId) params.set("projectId", request.projectId);
1025
1215
  const query = params.toString();
1026
- return this.http.delete(
1027
- `/webdata/schedules/${request.id}${query ? `?${query}` : ""}`
1216
+ return this.http.deleteWithBody(
1217
+ `/webdata/schedules/${request.id}${query ? `?${query}` : ""}`,
1218
+ {
1219
+ id: request.id,
1220
+ environment: request.environment,
1221
+ projectId: request.projectId
1222
+ }
1028
1223
  );
1029
1224
  }
1030
1225
  /**
@@ -1062,9 +1257,7 @@ var Extraction = class {
1062
1257
  if (request.periodStart) params.set("periodStart", request.periodStart);
1063
1258
  if (request.periodEnd) params.set("periodEnd", request.periodEnd);
1064
1259
  const query = params.toString();
1065
- const response = await this.http.get(
1066
- `/webdata/usage${query ? `?${query}` : ""}`
1067
- );
1260
+ const response = await this.http.get(`/webdata/usage${query ? `?${query}` : ""}`);
1068
1261
  return this.convertUsageDates(response);
1069
1262
  }
1070
1263
  // ==========================================================================
@@ -1205,7 +1398,14 @@ var Webdata = class {
1205
1398
  if (request.environment) params.set("environment", request.environment);
1206
1399
  if (request.projectId) params.set("projectId", request.projectId);
1207
1400
  const query = params.toString();
1208
- return this.http.delete(`/webdata/screenshots/${request.id}${query ? `?${query}` : ""}`);
1401
+ return this.http.deleteWithBody(
1402
+ `/webdata/screenshots/${request.id}${query ? `?${query}` : ""}`,
1403
+ {
1404
+ id: request.id,
1405
+ environment: request.environment,
1406
+ projectId: request.projectId
1407
+ }
1408
+ );
1209
1409
  }
1210
1410
  /**
1211
1411
  * Capture a screenshot and wait for completion
@@ -1321,7 +1521,14 @@ var Webdata = class {
1321
1521
  if (request.environment) params.set("environment", request.environment);
1322
1522
  if (request.projectId) params.set("projectId", request.projectId);
1323
1523
  const query = params.toString();
1324
- return this.http.delete(`/webdata/extractions/${request.id}${query ? `?${query}` : ""}`);
1524
+ return this.http.deleteWithBody(
1525
+ `/webdata/extractions/${request.id}${query ? `?${query}` : ""}`,
1526
+ {
1527
+ id: request.id,
1528
+ environment: request.environment,
1529
+ projectId: request.projectId
1530
+ }
1531
+ );
1325
1532
  }
1326
1533
  /**
1327
1534
  * Extract content and wait for completion
@@ -1452,7 +1659,14 @@ var Webdata = class {
1452
1659
  if (request.environment) params.set("environment", request.environment);
1453
1660
  if (request.projectId) params.set("projectId", request.projectId);
1454
1661
  const query = params.toString();
1455
- return this.http.delete(`/webdata/schedules/${request.id}${query ? `?${query}` : ""}`);
1662
+ return this.http.deleteWithBody(
1663
+ `/webdata/schedules/${request.id}${query ? `?${query}` : ""}`,
1664
+ {
1665
+ id: request.id,
1666
+ environment: request.environment,
1667
+ projectId: request.projectId
1668
+ }
1669
+ );
1456
1670
  }
1457
1671
  /**
1458
1672
  * Toggle a schedule on or off
@@ -1717,12 +1931,683 @@ var Webdata = class {
1717
1931
  }
1718
1932
  };
1719
1933
 
1934
+ // src/integrations/client.ts
1935
+ var CRM = class {
1936
+ http;
1937
+ constructor(http) {
1938
+ this.http = http;
1939
+ }
1940
+ // Contacts
1941
+ async listContacts(connectionId, options) {
1942
+ const params = new URLSearchParams({ connectionId });
1943
+ if (options?.cursor) params.set("cursor", options.cursor);
1944
+ if (options?.limit) params.set("limit", String(options.limit));
1945
+ if (options?.sortBy) params.set("sortBy", options.sortBy);
1946
+ if (options?.sortOrder) params.set("sortOrder", options.sortOrder);
1947
+ return this.http.get(`/integrations/crm/contacts?${params}`);
1948
+ }
1949
+ async getContact(connectionId, id) {
1950
+ return this.http.get(`/integrations/crm/contacts/${id}?connectionId=${connectionId}`);
1951
+ }
1952
+ async createContact(connectionId, data) {
1953
+ return this.http.post("/integrations/crm/contacts", { connectionId, data });
1954
+ }
1955
+ async updateContact(connectionId, id, data) {
1956
+ return this.http.patch(`/integrations/crm/contacts/${id}`, { connectionId, data });
1957
+ }
1958
+ async deleteContact(connectionId, id) {
1959
+ return this.http.delete(`/integrations/crm/contacts/${id}?connectionId=${connectionId}`);
1960
+ }
1961
+ // Companies
1962
+ async listCompanies(connectionId, options) {
1963
+ const params = new URLSearchParams({ connectionId });
1964
+ if (options?.cursor) params.set("cursor", options.cursor);
1965
+ if (options?.limit) params.set("limit", String(options.limit));
1966
+ if (options?.sortBy) params.set("sortBy", options.sortBy);
1967
+ if (options?.sortOrder) params.set("sortOrder", options.sortOrder);
1968
+ return this.http.get(`/integrations/crm/companies?${params}`);
1969
+ }
1970
+ async getCompany(connectionId, id) {
1971
+ return this.http.get(`/integrations/crm/companies/${id}?connectionId=${connectionId}`);
1972
+ }
1973
+ async createCompany(connectionId, data) {
1974
+ return this.http.post("/integrations/crm/companies", { connectionId, data });
1975
+ }
1976
+ async updateCompany(connectionId, id, data) {
1977
+ return this.http.patch(`/integrations/crm/companies/${id}`, { connectionId, data });
1978
+ }
1979
+ async deleteCompany(connectionId, id) {
1980
+ return this.http.delete(`/integrations/crm/companies/${id}?connectionId=${connectionId}`);
1981
+ }
1982
+ // Deals
1983
+ async listDeals(connectionId, options) {
1984
+ const params = new URLSearchParams({ connectionId });
1985
+ if (options?.cursor) params.set("cursor", options.cursor);
1986
+ if (options?.limit) params.set("limit", String(options.limit));
1987
+ if (options?.sortBy) params.set("sortBy", options.sortBy);
1988
+ if (options?.sortOrder) params.set("sortOrder", options.sortOrder);
1989
+ return this.http.get(`/integrations/crm/deals?${params}`);
1990
+ }
1991
+ async getDeal(connectionId, id) {
1992
+ return this.http.get(`/integrations/crm/deals/${id}?connectionId=${connectionId}`);
1993
+ }
1994
+ async createDeal(connectionId, data) {
1995
+ return this.http.post("/integrations/crm/deals", { connectionId, data });
1996
+ }
1997
+ async updateDeal(connectionId, id, data) {
1998
+ return this.http.patch(`/integrations/crm/deals/${id}`, { connectionId, data });
1999
+ }
2000
+ async deleteDeal(connectionId, id) {
2001
+ return this.http.delete(`/integrations/crm/deals/${id}?connectionId=${connectionId}`);
2002
+ }
2003
+ };
2004
+ var Storage = class {
2005
+ http;
2006
+ constructor(http) {
2007
+ this.http = http;
2008
+ }
2009
+ // Files
2010
+ async listFiles(connectionId, folderId, options) {
2011
+ const params = new URLSearchParams({ connectionId });
2012
+ if (folderId) params.set("folderId", folderId);
2013
+ if (options?.cursor) params.set("cursor", options.cursor);
2014
+ if (options?.limit) params.set("limit", String(options.limit));
2015
+ return this.http.get(`/integrations/storage/files?${params}`);
2016
+ }
2017
+ async getFile(connectionId, id) {
2018
+ return this.http.get(`/integrations/storage/files/${id}?connectionId=${connectionId}`);
2019
+ }
2020
+ async uploadFile(connectionId, input) {
2021
+ const base64Data = input.data instanceof ArrayBuffer ? btoa(String.fromCharCode(...new Uint8Array(input.data))) : btoa(String.fromCharCode(...input.data));
2022
+ return this.http.post("/integrations/storage/files", {
2023
+ connectionId,
2024
+ name: input.name,
2025
+ mimeType: input.mimeType,
2026
+ data: base64Data,
2027
+ folderId: input.folderId
2028
+ });
2029
+ }
2030
+ async deleteFile(connectionId, id) {
2031
+ return this.http.delete(`/integrations/storage/files/${id}?connectionId=${connectionId}`);
2032
+ }
2033
+ async downloadFile(connectionId, id) {
2034
+ const response = await this.http.get(
2035
+ `/integrations/storage/files/${id}/download?connectionId=${connectionId}`
2036
+ );
2037
+ const binaryString = atob(response.data);
2038
+ const bytes = new Uint8Array(binaryString.length);
2039
+ for (let i = 0; i < binaryString.length; i++) {
2040
+ bytes[i] = binaryString.charCodeAt(i);
2041
+ }
2042
+ return {
2043
+ data: bytes.buffer,
2044
+ mimeType: response.mimeType,
2045
+ filename: response.filename
2046
+ };
2047
+ }
2048
+ // Folders
2049
+ async listFolders(connectionId, parentId, options) {
2050
+ const params = new URLSearchParams({ connectionId });
2051
+ if (parentId) params.set("parentId", parentId);
2052
+ if (options?.cursor) params.set("cursor", options.cursor);
2053
+ if (options?.limit) params.set("limit", String(options.limit));
2054
+ return this.http.get(`/integrations/storage/folders?${params}`);
2055
+ }
2056
+ async getFolder(connectionId, id) {
2057
+ return this.http.get(`/integrations/storage/folders/${id}?connectionId=${connectionId}`);
2058
+ }
2059
+ async createFolder(connectionId, data) {
2060
+ return this.http.post("/integrations/storage/folders", { connectionId, ...data });
2061
+ }
2062
+ async deleteFolder(connectionId, id) {
2063
+ return this.http.delete(`/integrations/storage/folders/${id}?connectionId=${connectionId}`);
2064
+ }
2065
+ };
2066
+ var Communication = class {
2067
+ http;
2068
+ constructor(http) {
2069
+ this.http = http;
2070
+ }
2071
+ // Channels
2072
+ async listChannels(connectionId, options) {
2073
+ const params = new URLSearchParams({ connectionId });
2074
+ if (options?.cursor) params.set("cursor", options.cursor);
2075
+ if (options?.limit) params.set("limit", String(options.limit));
2076
+ return this.http.get(`/integrations/communication/channels?${params}`);
2077
+ }
2078
+ async getChannel(connectionId, id) {
2079
+ return this.http.get(`/integrations/communication/channels/${id}?connectionId=${connectionId}`);
2080
+ }
2081
+ // Messages
2082
+ async listMessages(connectionId, channelId, options) {
2083
+ const params = new URLSearchParams({ connectionId, channelId });
2084
+ if (options?.cursor) params.set("cursor", options.cursor);
2085
+ if (options?.limit) params.set("limit", String(options.limit));
2086
+ return this.http.get(`/integrations/communication/messages?${params}`);
2087
+ }
2088
+ async sendMessage(connectionId, input) {
2089
+ return this.http.post("/integrations/communication/messages", { connectionId, ...input });
2090
+ }
2091
+ // Users
2092
+ async listUsers(connectionId, options) {
2093
+ const params = new URLSearchParams({ connectionId });
2094
+ if (options?.cursor) params.set("cursor", options.cursor);
2095
+ if (options?.limit) params.set("limit", String(options.limit));
2096
+ return this.http.get(`/integrations/communication/users?${params}`);
2097
+ }
2098
+ };
2099
+ var Productivity = class {
2100
+ http;
2101
+ constructor(http) {
2102
+ this.http = http;
2103
+ }
2104
+ // Documents
2105
+ async listDocuments(connectionId, parentId, options) {
2106
+ const params = new URLSearchParams({ connectionId });
2107
+ if (parentId) params.set("parentId", parentId);
2108
+ if (options?.cursor) params.set("cursor", options.cursor);
2109
+ if (options?.limit) params.set("limit", String(options.limit));
2110
+ return this.http.get(`/integrations/productivity/documents?${params}`);
2111
+ }
2112
+ async getDocument(connectionId, id) {
2113
+ return this.http.get(`/integrations/productivity/documents/${id}?connectionId=${connectionId}`);
2114
+ }
2115
+ async createDocument(connectionId, data) {
2116
+ return this.http.post("/integrations/productivity/documents", { connectionId, ...data });
2117
+ }
2118
+ async updateDocument(connectionId, id, data) {
2119
+ return this.http.patch(`/integrations/productivity/documents/${id}`, { connectionId, ...data });
2120
+ }
2121
+ // Tables
2122
+ async listTables(connectionId, options) {
2123
+ const params = new URLSearchParams({ connectionId });
2124
+ if (options?.cursor) params.set("cursor", options.cursor);
2125
+ if (options?.limit) params.set("limit", String(options.limit));
2126
+ return this.http.get(`/integrations/productivity/tables?${params}`);
2127
+ }
2128
+ async getTable(connectionId, id) {
2129
+ return this.http.get(`/integrations/productivity/tables/${id}?connectionId=${connectionId}`);
2130
+ }
2131
+ // Table Rows
2132
+ async listTableRows(connectionId, tableId, options) {
2133
+ const params = new URLSearchParams({ connectionId });
2134
+ if (options?.cursor) params.set("cursor", options.cursor);
2135
+ if (options?.limit) params.set("limit", String(options.limit));
2136
+ return this.http.get(`/integrations/productivity/tables/${tableId}/rows?${params}`);
2137
+ }
2138
+ async getTableRow(connectionId, tableId, rowId) {
2139
+ return this.http.get(
2140
+ `/integrations/productivity/tables/${tableId}/rows/${rowId}?connectionId=${connectionId}`
2141
+ );
2142
+ }
2143
+ async createTableRow(connectionId, tableId, data) {
2144
+ return this.http.post(`/integrations/productivity/tables/${tableId}/rows`, {
2145
+ connectionId,
2146
+ ...data
2147
+ });
2148
+ }
2149
+ async updateTableRow(connectionId, tableId, rowId, data) {
2150
+ return this.http.patch(`/integrations/productivity/tables/${tableId}/rows/${rowId}`, {
2151
+ connectionId,
2152
+ ...data
2153
+ });
2154
+ }
2155
+ async deleteTableRow(connectionId, tableId, rowId) {
2156
+ return this.http.delete(
2157
+ `/integrations/productivity/tables/${tableId}/rows/${rowId}?connectionId=${connectionId}`
2158
+ );
2159
+ }
2160
+ };
2161
+ var Integrations = class {
2162
+ http;
2163
+ crm;
2164
+ storage;
2165
+ communication;
2166
+ productivity;
2167
+ constructor(config) {
2168
+ this.http = new HttpClient(config);
2169
+ this.crm = new CRM(this.http);
2170
+ this.storage = new Storage(this.http);
2171
+ this.communication = new Communication(this.http);
2172
+ this.productivity = new Productivity(this.http);
2173
+ }
2174
+ // ============================================================================
2175
+ // CONNECTORS
2176
+ // ============================================================================
2177
+ /**
2178
+ * List all available connectors
2179
+ */
2180
+ async listConnectors(category) {
2181
+ const params = category ? `?category=${category}` : "";
2182
+ return this.http.get(`/integrations/connectors${params}`);
2183
+ }
2184
+ /**
2185
+ * Get a specific connector
2186
+ */
2187
+ async getConnector(slug) {
2188
+ return this.http.get(`/integrations/connectors/${slug}`);
2189
+ }
2190
+ // ============================================================================
2191
+ // CONNECTIONS
2192
+ // ============================================================================
2193
+ /**
2194
+ * List all connections
2195
+ */
2196
+ async listConnections(options) {
2197
+ const params = new URLSearchParams();
2198
+ if (options?.connectorId) params.set("connectorId", options.connectorId);
2199
+ if (options?.status) params.set("status", options.status);
2200
+ const queryString = params.toString();
2201
+ return this.http.get(`/integrations/connections${queryString ? `?${queryString}` : ""}`);
2202
+ }
2203
+ /**
2204
+ * Get a specific connection
2205
+ */
2206
+ async getConnection(id) {
2207
+ return this.http.get(`/integrations/connections/${id}`);
2208
+ }
2209
+ /**
2210
+ * Create a new connection (initiates OAuth flow)
2211
+ * Returns the OAuth authorization URL to redirect the user to
2212
+ */
2213
+ async createConnection(connectorSlug, options) {
2214
+ return this.http.post("/integrations/connections", {
2215
+ connectorSlug,
2216
+ ...options
2217
+ });
2218
+ }
2219
+ /**
2220
+ * Delete a connection
2221
+ */
2222
+ async deleteConnection(id) {
2223
+ return this.http.delete(`/integrations/connections/${id}`);
2224
+ }
2225
+ /**
2226
+ * Test a connection's credentials
2227
+ */
2228
+ async testConnection(id) {
2229
+ return this.http.post(`/integrations/connections/${id}/test`, {});
2230
+ }
2231
+ // ============================================================================
2232
+ // PASSTHROUGH
2233
+ // ============================================================================
2234
+ /**
2235
+ * Make a raw passthrough request to the provider API
2236
+ */
2237
+ async passthrough(request) {
2238
+ return this.http.post("/integrations/passthrough", request);
2239
+ }
2240
+ };
2241
+
2242
+ // src/marketing/client.ts
2243
+ var Marketing = class {
2244
+ http;
2245
+ constructor(config) {
2246
+ this.http = new HttpClient(config);
2247
+ }
2248
+ // ============================================================================
2249
+ // Trends
2250
+ // ============================================================================
2251
+ /**
2252
+ * Discover new trends from all sources
2253
+ *
2254
+ * @example
2255
+ * ```typescript
2256
+ * const { trendsDiscovered, trends } = await marketing.discoverTrends({
2257
+ * projectSlug: 'my-project',
2258
+ * environment: 'production',
2259
+ * });
2260
+ * console.log(`Discovered ${trendsDiscovered} new trends`);
2261
+ * ```
2262
+ */
2263
+ async discoverTrends(request) {
2264
+ return this.http.post("/marketing/trends/discover", request);
2265
+ }
2266
+ /**
2267
+ * List trends for a project
2268
+ *
2269
+ * @example
2270
+ * ```typescript
2271
+ * const trends = await marketing.listTrends({
2272
+ * projectSlug: 'my-project',
2273
+ * environment: 'production',
2274
+ * limit: 20,
2275
+ * });
2276
+ * ```
2277
+ */
2278
+ async listTrends(request) {
2279
+ return this.http.get(
2280
+ `/marketing/trends?${new URLSearchParams({
2281
+ projectSlug: request.projectSlug,
2282
+ environment: request.environment,
2283
+ ...request.status && { status: request.status },
2284
+ ...request.limit && { limit: request.limit.toString() }
2285
+ }).toString()}`
2286
+ );
2287
+ }
2288
+ /**
2289
+ * Get a single trend by ID
2290
+ */
2291
+ async getTrend(trendId) {
2292
+ const response = await this.http.get(`/marketing/trends/${trendId}`);
2293
+ return this.convertTrendDates(response);
2294
+ }
2295
+ // ============================================================================
2296
+ // Opportunities
2297
+ // ============================================================================
2298
+ /**
2299
+ * Generate content opportunities from active trends
2300
+ *
2301
+ * @example
2302
+ * ```typescript
2303
+ * const { opportunitiesGenerated, opportunities } = await marketing.generateOpportunities({
2304
+ * projectSlug: 'my-project',
2305
+ * environment: 'production',
2306
+ * });
2307
+ * console.log(`Generated ${opportunitiesGenerated} new content ideas`);
2308
+ * ```
2309
+ */
2310
+ async generateOpportunities(request) {
2311
+ return this.http.post("/marketing/opportunities/generate", request);
2312
+ }
2313
+ /**
2314
+ * List opportunities for a project
2315
+ *
2316
+ * @example
2317
+ * ```typescript
2318
+ * const opportunities = await marketing.listOpportunities({
2319
+ * projectSlug: 'my-project',
2320
+ * environment: 'production',
2321
+ * status: 'pending',
2322
+ * limit: 20,
2323
+ * });
2324
+ * ```
2325
+ */
2326
+ async listOpportunities(request) {
2327
+ const params = new URLSearchParams({
2328
+ projectSlug: request.projectSlug,
2329
+ environment: request.environment,
2330
+ ...request.status && { status: request.status },
2331
+ ...request.limit && { limit: request.limit.toString() }
2332
+ });
2333
+ return this.http.get(`/marketing/opportunities?${params.toString()}`);
2334
+ }
2335
+ /**
2336
+ * Get a single opportunity by ID
2337
+ */
2338
+ async getOpportunity(opportunityId) {
2339
+ const response = await this.http.get(`/marketing/opportunities/${opportunityId}`);
2340
+ return this.convertOpportunityDates(response);
2341
+ }
2342
+ /**
2343
+ * Dismiss an opportunity
2344
+ *
2345
+ * @example
2346
+ * ```typescript
2347
+ * await marketing.dismissOpportunity({ opportunityId: 'opp-id' });
2348
+ * ```
2349
+ */
2350
+ async dismissOpportunity(request) {
2351
+ return this.http.post(`/marketing/opportunities/${request.opportunityId}/dismiss`, {});
2352
+ }
2353
+ // ============================================================================
2354
+ // Content
2355
+ // ============================================================================
2356
+ /**
2357
+ * Create new marketing content
2358
+ *
2359
+ * @example
2360
+ * ```typescript
2361
+ * const content = await marketing.createContent({
2362
+ * projectSlug: 'my-project',
2363
+ * environment: 'production',
2364
+ * contentType: 'tiktok_slideshow',
2365
+ * title: 'How AI is Changing Marketing',
2366
+ * opportunityId: 'opp-id',
2367
+ * });
2368
+ * ```
2369
+ */
2370
+ async createContent(request) {
2371
+ const response = await this.http.post("/marketing/content", request);
2372
+ return this.convertContentDates(response);
2373
+ }
2374
+ /**
2375
+ * List content with filters
2376
+ *
2377
+ * @example
2378
+ * ```typescript
2379
+ * const content = await marketing.listContent({
2380
+ * projectSlug: 'my-project',
2381
+ * environment: 'production',
2382
+ * status: 'published',
2383
+ * limit: 20,
2384
+ * });
2385
+ * ```
2386
+ */
2387
+ async listContent(request) {
2388
+ const params = new URLSearchParams({
2389
+ projectSlug: request.projectSlug,
2390
+ environment: request.environment,
2391
+ ...request.status && { status: request.status },
2392
+ ...request.contentType && { contentType: request.contentType },
2393
+ ...request.approvalStatus && { approvalStatus: request.approvalStatus },
2394
+ ...request.limit && { limit: request.limit.toString() },
2395
+ ...request.offset && { offset: request.offset.toString() }
2396
+ });
2397
+ const response = await this.http.get(`/marketing/content?${params.toString()}`);
2398
+ return response.map((c) => this.convertContentDates(c));
2399
+ }
2400
+ /**
2401
+ * Get a single content by ID
2402
+ */
2403
+ async getContent(contentId) {
2404
+ const response = await this.http.get(`/marketing/content/${contentId}`);
2405
+ return this.convertContentDates(response);
2406
+ }
2407
+ /**
2408
+ * Update content
2409
+ *
2410
+ * @example
2411
+ * ```typescript
2412
+ * const updated = await marketing.updateContent({
2413
+ * contentId: 'content-id',
2414
+ * title: 'Updated Title',
2415
+ * status: 'published',
2416
+ * });
2417
+ * ```
2418
+ */
2419
+ async updateContent(request) {
2420
+ const { contentId, ...data } = request;
2421
+ const response = await this.http.patch(`/marketing/content/${contentId}`, data);
2422
+ return this.convertContentDates(response);
2423
+ }
2424
+ /**
2425
+ * Approve content for publishing
2426
+ *
2427
+ * @example
2428
+ * ```typescript
2429
+ * await marketing.approveContent({
2430
+ * contentId: 'content-id',
2431
+ * reviewNotes: 'Looks great!',
2432
+ * });
2433
+ * ```
2434
+ */
2435
+ async approveContent(request) {
2436
+ const response = await this.http.post(`/marketing/content/${request.contentId}/approve`, request);
2437
+ return this.convertContentDates(response);
2438
+ }
2439
+ /**
2440
+ * Reject content
2441
+ *
2442
+ * @example
2443
+ * ```typescript
2444
+ * await marketing.rejectContent({
2445
+ * contentId: 'content-id',
2446
+ * reviewNotes: 'Needs revisions',
2447
+ * });
2448
+ * ```
2449
+ */
2450
+ async rejectContent(request) {
2451
+ const response = await this.http.post(`/marketing/content/${request.contentId}/reject`, request);
2452
+ return this.convertContentDates(response);
2453
+ }
2454
+ /**
2455
+ * Delete content
2456
+ */
2457
+ async deleteContent(contentId) {
2458
+ return this.http.deleteWithBody(`/marketing/content/${contentId}`, { contentId });
2459
+ }
2460
+ // ============================================================================
2461
+ // Scripts
2462
+ // ============================================================================
2463
+ /**
2464
+ * Create a new script
2465
+ *
2466
+ * @example
2467
+ * ```typescript
2468
+ * const script = await marketing.createScript({
2469
+ * projectSlug: 'my-project',
2470
+ * environment: 'production',
2471
+ * hook: 'Are you ready to see the future?',
2472
+ * slides: [
2473
+ * { order: 0, text: 'AI is changing everything', voiceoverText: 'AI is transforming how we work', duration: 3 },
2474
+ * ],
2475
+ * cta: 'Follow for more insights!',
2476
+ * });
2477
+ * ```
2478
+ */
2479
+ async createScript(request) {
2480
+ const response = await this.http.post("/marketing/scripts", request);
2481
+ return this.convertScriptDates(response);
2482
+ }
2483
+ /**
2484
+ * List scripts
2485
+ */
2486
+ async listScripts(request) {
2487
+ const params = new URLSearchParams({
2488
+ projectSlug: request.projectSlug,
2489
+ environment: request.environment,
2490
+ ...request.contentId && { contentId: request.contentId },
2491
+ ...request.limit && { limit: request.limit.toString() }
2492
+ });
2493
+ const response = await this.http.get(`/marketing/scripts?${params.toString()}`);
2494
+ return response.map((s) => this.convertScriptDates(s));
2495
+ }
2496
+ /**
2497
+ * Get a single script by ID
2498
+ */
2499
+ async getScript(scriptId) {
2500
+ const response = await this.http.get(`/marketing/scripts/${scriptId}`);
2501
+ return this.convertScriptDates(response);
2502
+ }
2503
+ // ============================================================================
2504
+ // Analytics
2505
+ // ============================================================================
2506
+ /**
2507
+ * Get analytics overview
2508
+ *
2509
+ * @example
2510
+ * ```typescript
2511
+ * const analytics = await marketing.getAnalyticsOverview({
2512
+ * projectSlug: 'my-project',
2513
+ * environment: 'production',
2514
+ * });
2515
+ * console.log(`Total content: ${analytics.totalContent}`);
2516
+ * console.log(`Total views: ${analytics.engagement.views}`);
2517
+ * ```
2518
+ */
2519
+ async getAnalyticsOverview(request) {
2520
+ const params = new URLSearchParams({
2521
+ projectSlug: request.projectSlug,
2522
+ environment: request.environment,
2523
+ ...request.startDate && { startDate: request.startDate.toISOString() },
2524
+ ...request.endDate && { endDate: request.endDate.toISOString() }
2525
+ });
2526
+ return this.http.get(`/marketing/analytics/overview?${params.toString()}`);
2527
+ }
2528
+ /**
2529
+ * Get content performance metrics
2530
+ *
2531
+ * @example
2532
+ * ```typescript
2533
+ * const topContent = await marketing.getContentPerformance({
2534
+ * projectSlug: 'my-project',
2535
+ * environment: 'production',
2536
+ * contentType: 'tiktok_slideshow',
2537
+ * limit: 10,
2538
+ * });
2539
+ * ```
2540
+ */
2541
+ async getContentPerformance(request) {
2542
+ const params = new URLSearchParams({
2543
+ projectSlug: request.projectSlug,
2544
+ environment: request.environment,
2545
+ ...request.contentType && { contentType: request.contentType },
2546
+ ...request.limit && { limit: request.limit.toString() }
2547
+ });
2548
+ return this.http.get(`/marketing/analytics/performance?${params.toString()}`);
2549
+ }
2550
+ // ============================================================================
2551
+ // Date Conversion Helpers
2552
+ // ============================================================================
2553
+ convertTrendDates(trend) {
2554
+ if (typeof trend.firstSeenAt === "string") {
2555
+ trend.firstSeenAt = new Date(trend.firstSeenAt);
2556
+ }
2557
+ if (typeof trend.lastUpdatedAt === "string") {
2558
+ trend.lastUpdatedAt = new Date(trend.lastUpdatedAt);
2559
+ }
2560
+ if (trend.expiresAt && typeof trend.expiresAt === "string") {
2561
+ trend.expiresAt = new Date(trend.expiresAt);
2562
+ }
2563
+ if (typeof trend.createdAt === "string") {
2564
+ trend.createdAt = new Date(trend.createdAt);
2565
+ }
2566
+ return trend;
2567
+ }
2568
+ convertOpportunityDates(opp) {
2569
+ if (typeof opp.createdAt === "string") {
2570
+ opp.createdAt = new Date(opp.createdAt);
2571
+ }
2572
+ if (opp.expiresAt && typeof opp.expiresAt === "string") {
2573
+ opp.expiresAt = new Date(opp.expiresAt);
2574
+ }
2575
+ if (opp.usedAt && typeof opp.usedAt === "string") {
2576
+ opp.usedAt = new Date(opp.usedAt);
2577
+ }
2578
+ return opp;
2579
+ }
2580
+ convertContentDates(content) {
2581
+ if (typeof content.createdAt === "string") {
2582
+ content.createdAt = new Date(content.createdAt);
2583
+ }
2584
+ if (content.updatedAt && typeof content.updatedAt === "string") {
2585
+ content.updatedAt = new Date(content.updatedAt);
2586
+ }
2587
+ if (content.reviewedAt && typeof content.reviewedAt === "string") {
2588
+ content.reviewedAt = new Date(content.reviewedAt);
2589
+ }
2590
+ if (content.publishedAt && typeof content.publishedAt === "string") {
2591
+ content.publishedAt = new Date(content.publishedAt);
2592
+ }
2593
+ return content;
2594
+ }
2595
+ convertScriptDates(script) {
2596
+ if (typeof script.createdAt === "string") {
2597
+ script.createdAt = new Date(script.createdAt);
2598
+ }
2599
+ return script;
2600
+ }
2601
+ };
2602
+
1720
2603
  // src/index.ts
1721
2604
  var Stack0 = class {
1722
2605
  mail;
1723
2606
  cdn;
1724
2607
  screenshots;
1725
2608
  extraction;
2609
+ integrations;
2610
+ marketing;
1726
2611
  /**
1727
2612
  * @deprecated Use `screenshots` and `extraction` instead. Will be removed in a future version.
1728
2613
  */
@@ -1733,9 +2618,11 @@ var Stack0 = class {
1733
2618
  baseUrl: config.baseUrl
1734
2619
  };
1735
2620
  this.mail = new Mail(clientConfig);
1736
- this.cdn = new CDN(clientConfig);
2621
+ this.cdn = new CDN(clientConfig, config.cdnUrl);
1737
2622
  this.screenshots = new Screenshots(clientConfig);
1738
2623
  this.extraction = new Extraction(clientConfig);
2624
+ this.integrations = new Integrations(clientConfig);
2625
+ this.marketing = new Marketing(clientConfig);
1739
2626
  this.webdata = new Webdata(clientConfig);
1740
2627
  }
1741
2628
  };
@@ -1743,7 +2630,9 @@ var src_default = Stack0;
1743
2630
 
1744
2631
  exports.CDN = CDN;
1745
2632
  exports.Extraction = Extraction;
2633
+ exports.Integrations = Integrations;
1746
2634
  exports.Mail = Mail;
2635
+ exports.Marketing = Marketing;
1747
2636
  exports.Screenshots = Screenshots;
1748
2637
  exports.Stack0 = Stack0;
1749
2638
  exports.Webdata = Webdata;