@stack0/sdk 0.3.0 → 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 (40) hide show
  1. package/README.md +33 -10
  2. package/dist/cdn/index.d.mts +56 -26
  3. package/dist/cdn/index.d.ts +56 -26
  4. package/dist/cdn/index.js +84 -23
  5. package/dist/cdn/index.js.map +1 -1
  6. package/dist/cdn/index.mjs +84 -23
  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-DjrRWvXA.d.mts → http-client-Cgie_Rv6.d.mts} +1 -0
  15. package/dist/{http-client-DjrRWvXA.d.ts → http-client-Cgie_Rv6.d.ts} +1 -0
  16. package/dist/index.d.mts +475 -3
  17. package/dist/index.d.ts +475 -3
  18. package/dist/index.js +512 -72
  19. package/dist/index.js.map +1 -1
  20. package/dist/index.mjs +512 -73
  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
package/dist/index.mjs CHANGED
@@ -6,19 +6,24 @@ var HttpClient = class {
6
6
  this.apiKey = config.apiKey;
7
7
  this.baseUrl = config.baseUrl || "https://api.stack0.dev/v1";
8
8
  }
9
- getHeaders() {
10
- return {
11
- "Content-Type": "application/json",
9
+ getHeaders(includeContentType = true) {
10
+ const headers = {
12
11
  Authorization: `Bearer ${this.apiKey}`
13
12
  };
13
+ if (includeContentType) {
14
+ headers["Content-Type"] = "application/json";
15
+ }
16
+ return headers;
14
17
  }
15
18
  async request(method, path, body) {
16
19
  const url = `${this.baseUrl}${path}`;
20
+ const bodyString = body === void 0 ? void 0 : JSON.stringify(body);
21
+ const hasBody = bodyString !== void 0;
17
22
  try {
18
23
  const response = await fetch(url, {
19
24
  method,
20
- headers: this.getHeaders(),
21
- body: body ? JSON.stringify(body) : void 0
25
+ headers: this.getHeaders(hasBody),
26
+ body: hasBody ? bodyString : void 0
22
27
  });
23
28
  if (!response.ok) {
24
29
  await this.handleErrorResponse(response);
@@ -62,6 +67,9 @@ var HttpClient = class {
62
67
  async delete(path) {
63
68
  return this.request("DELETE", path);
64
69
  }
70
+ async deleteWithBody(path, body) {
71
+ return this.request("DELETE", path, body);
72
+ }
65
73
  async patch(path, body) {
66
74
  return this.request("PATCH", path, body);
67
75
  }
@@ -115,10 +123,13 @@ var Mail = class {
115
123
  };
116
124
 
117
125
  // src/cdn/client.ts
126
+ var ALLOWED_WIDTHS = [256, 384, 640, 750, 828, 1080, 1200, 1920, 2048, 3840];
118
127
  var CDN = class {
119
128
  http;
120
- constructor(config) {
129
+ cdnUrl;
130
+ constructor(config, cdnUrl) {
121
131
  this.http = new HttpClient(config);
132
+ this.cdnUrl = cdnUrl;
122
133
  }
123
134
  /**
124
135
  * Generate a presigned URL for uploading a file
@@ -239,7 +250,7 @@ var CDN = class {
239
250
  * ```
240
251
  */
241
252
  async delete(id) {
242
- return this.http.delete(`/cdn/assets/${id}`);
253
+ return this.http.deleteWithBody(`/cdn/assets/${id}`, { id });
243
254
  }
244
255
  /**
245
256
  * Delete multiple assets
@@ -298,24 +309,73 @@ var CDN = class {
298
309
  return this.http.post("/cdn/assets/move", request);
299
310
  }
300
311
  /**
301
- * Get a transformed image URL
312
+ * Get a transformed image URL (client-side, no API call)
302
313
  *
303
314
  * @example
304
315
  * ```typescript
305
- * const { url } = await cdn.getTransformUrl({
306
- * assetId: 'asset-id',
307
- * options: {
308
- * width: 800,
309
- * height: 600,
310
- * fit: 'cover',
311
- * format: 'webp',
312
- * quality: 80,
313
- * },
316
+ * // Using asset's cdnUrl directly
317
+ * const url = cdn.getTransformUrl(asset.cdnUrl, {
318
+ * width: 800,
319
+ * height: 600,
320
+ * fit: 'cover',
321
+ * format: 'webp',
322
+ * quality: 80,
314
323
  * });
324
+ *
325
+ * // Or using cdnUrl from SDK config + s3Key
326
+ * const url = cdn.getTransformUrl(asset.s3Key, { width: 400 });
315
327
  * ```
316
328
  */
317
- async getTransformUrl(request) {
318
- return this.http.post("/cdn/transform", request);
329
+ getTransformUrl(assetUrlOrS3Key, options) {
330
+ let baseUrl;
331
+ if (assetUrlOrS3Key.startsWith("http://") || assetUrlOrS3Key.startsWith("https://")) {
332
+ const url = new URL(assetUrlOrS3Key);
333
+ baseUrl = `${url.protocol}//${url.host}${url.pathname}`;
334
+ } else if (this.cdnUrl) {
335
+ const cdnBase = this.cdnUrl.endsWith("/") ? this.cdnUrl.slice(0, -1) : this.cdnUrl;
336
+ baseUrl = `${cdnBase}/${assetUrlOrS3Key}`;
337
+ } else {
338
+ throw new Error("getTransformUrl requires either a full URL or cdnUrl to be configured in Stack0 options");
339
+ }
340
+ const params = this.buildTransformQuery(options);
341
+ if (!params) {
342
+ return baseUrl;
343
+ }
344
+ return `${baseUrl}?${params}`;
345
+ }
346
+ /**
347
+ * Build transform query parameters
348
+ */
349
+ buildTransformQuery(options) {
350
+ const params = new URLSearchParams();
351
+ if (options.format) params.set("f", options.format);
352
+ if (options.quality !== void 0) params.set("q", options.quality.toString());
353
+ if (options.width !== void 0) {
354
+ const width = this.getNearestWidth(options.width);
355
+ params.set("w", width.toString());
356
+ }
357
+ if (options.height !== void 0) params.set("h", options.height.toString());
358
+ if (options.fit) params.set("fit", options.fit);
359
+ if (options.crop) params.set("crop", options.crop);
360
+ if (options.cropX !== void 0) params.set("crop-x", options.cropX.toString());
361
+ if (options.cropY !== void 0) params.set("crop-y", options.cropY.toString());
362
+ if (options.cropWidth !== void 0) params.set("crop-w", options.cropWidth.toString());
363
+ if (options.cropHeight !== void 0) params.set("crop-h", options.cropHeight.toString());
364
+ if (options.blur !== void 0) params.set("blur", options.blur.toString());
365
+ if (options.sharpen !== void 0) params.set("sharpen", options.sharpen.toString());
366
+ if (options.brightness !== void 0) params.set("brightness", options.brightness.toString());
367
+ if (options.saturation !== void 0) params.set("saturation", options.saturation.toString());
368
+ if (options.grayscale) params.set("grayscale", "true");
369
+ if (options.rotate !== void 0) params.set("rotate", options.rotate.toString());
370
+ if (options.flip) params.set("flip", "y");
371
+ if (options.flop) params.set("flop", "x");
372
+ return params.toString();
373
+ }
374
+ /**
375
+ * Find the nearest allowed width for optimal caching
376
+ */
377
+ getNearestWidth(width) {
378
+ return ALLOWED_WIDTHS.reduce((prev, curr) => Math.abs(curr - width) < Math.abs(prev - width) ? curr : prev);
319
379
  }
320
380
  /**
321
381
  * Get folder tree for navigation
@@ -361,7 +421,10 @@ var CDN = class {
361
421
  async deleteFolder(id, deleteContents = false) {
362
422
  const params = new URLSearchParams();
363
423
  if (deleteContents) params.set("deleteContents", "true");
364
- return this.http.delete(`/cdn/folders/${id}?${params.toString()}`);
424
+ return this.http.deleteWithBody(`/cdn/folders/${id}?${params.toString()}`, {
425
+ id,
426
+ deleteContents
427
+ });
365
428
  }
366
429
  convertAssetDates(asset) {
367
430
  if (typeof asset.createdAt === "string") {
@@ -487,9 +550,7 @@ var CDN = class {
487
550
  params.set("timestamp", request.timestamp.toString());
488
551
  if (request.width) params.set("width", request.width.toString());
489
552
  if (request.format) params.set("format", request.format);
490
- return this.http.get(
491
- `/cdn/video/thumbnail/${request.assetId}?${params.toString()}`
492
- );
553
+ return this.http.get(`/cdn/video/thumbnail/${request.assetId}?${params.toString()}`);
493
554
  }
494
555
  /**
495
556
  * Extract audio from a video file
@@ -590,9 +651,7 @@ var Screenshots = class {
590
651
  if (request.limit) params.set("limit", request.limit.toString());
591
652
  if (request.cursor) params.set("cursor", request.cursor);
592
653
  const query = params.toString();
593
- const response = await this.http.get(
594
- `/webdata/screenshots${query ? `?${query}` : ""}`
595
- );
654
+ const response = await this.http.get(`/webdata/screenshots${query ? `?${query}` : ""}`);
596
655
  return {
597
656
  ...response,
598
657
  items: response.items.map((item) => this.convertDates(item))
@@ -611,8 +670,13 @@ var Screenshots = class {
611
670
  if (request.environment) params.set("environment", request.environment);
612
671
  if (request.projectId) params.set("projectId", request.projectId);
613
672
  const query = params.toString();
614
- return this.http.delete(
615
- `/webdata/screenshots/${request.id}${query ? `?${query}` : ""}`
673
+ return this.http.deleteWithBody(
674
+ `/webdata/screenshots/${request.id}${query ? `?${query}` : ""}`,
675
+ {
676
+ id: request.id,
677
+ environment: request.environment,
678
+ projectId: request.projectId
679
+ }
616
680
  );
617
681
  }
618
682
  /**
@@ -695,9 +759,7 @@ var Screenshots = class {
695
759
  if (request.limit) params.set("limit", request.limit.toString());
696
760
  if (request.cursor) params.set("cursor", request.cursor);
697
761
  const query = params.toString();
698
- const response = await this.http.get(
699
- `/webdata/batch${query ? `?${query}` : ""}`
700
- );
762
+ const response = await this.http.get(`/webdata/batch${query ? `?${query}` : ""}`);
701
763
  return {
702
764
  ...response,
703
765
  items: response.items.map((item) => this.convertBatchJobDates(item))
@@ -711,10 +773,7 @@ var Screenshots = class {
711
773
  if (request.environment) params.set("environment", request.environment);
712
774
  if (request.projectId) params.set("projectId", request.projectId);
713
775
  const query = params.toString();
714
- return this.http.post(
715
- `/webdata/batch/${request.id}/cancel${query ? `?${query}` : ""}`,
716
- {}
717
- );
776
+ return this.http.post(`/webdata/batch/${request.id}/cancel${query ? `?${query}` : ""}`, {});
718
777
  }
719
778
  /**
720
779
  * Create a batch screenshot job and wait for completion
@@ -767,10 +826,7 @@ var Screenshots = class {
767
826
  if (environment) params.set("environment", environment);
768
827
  if (projectId) params.set("projectId", projectId);
769
828
  const query = params.toString();
770
- return this.http.post(
771
- `/webdata/schedules/${id}${query ? `?${query}` : ""}`,
772
- data
773
- );
829
+ return this.http.post(`/webdata/schedules/${id}${query ? `?${query}` : ""}`, data);
774
830
  }
775
831
  /**
776
832
  * Get a schedule by ID
@@ -796,9 +852,7 @@ var Screenshots = class {
796
852
  if (request.limit) params.set("limit", request.limit.toString());
797
853
  if (request.cursor) params.set("cursor", request.cursor);
798
854
  const query = params.toString();
799
- const response = await this.http.get(
800
- `/webdata/schedules${query ? `?${query}` : ""}`
801
- );
855
+ const response = await this.http.get(`/webdata/schedules${query ? `?${query}` : ""}`);
802
856
  return {
803
857
  ...response,
804
858
  items: response.items.map((item) => this.convertScheduleDates(item))
@@ -812,8 +866,13 @@ var Screenshots = class {
812
866
  if (request.environment) params.set("environment", request.environment);
813
867
  if (request.projectId) params.set("projectId", request.projectId);
814
868
  const query = params.toString();
815
- return this.http.delete(
816
- `/webdata/schedules/${request.id}${query ? `?${query}` : ""}`
869
+ return this.http.deleteWithBody(
870
+ `/webdata/schedules/${request.id}${query ? `?${query}` : ""}`,
871
+ {
872
+ id: request.id,
873
+ environment: request.environment,
874
+ projectId: request.projectId
875
+ }
817
876
  );
818
877
  }
819
878
  /**
@@ -939,9 +998,7 @@ var Extraction = class {
939
998
  if (request.limit) params.set("limit", request.limit.toString());
940
999
  if (request.cursor) params.set("cursor", request.cursor);
941
1000
  const query = params.toString();
942
- const response = await this.http.get(
943
- `/webdata/extractions${query ? `?${query}` : ""}`
944
- );
1001
+ const response = await this.http.get(`/webdata/extractions${query ? `?${query}` : ""}`);
945
1002
  return {
946
1003
  ...response,
947
1004
  items: response.items.map((item) => this.convertDates(item))
@@ -960,8 +1017,13 @@ var Extraction = class {
960
1017
  if (request.environment) params.set("environment", request.environment);
961
1018
  if (request.projectId) params.set("projectId", request.projectId);
962
1019
  const query = params.toString();
963
- return this.http.delete(
964
- `/webdata/extractions/${request.id}${query ? `?${query}` : ""}`
1020
+ return this.http.deleteWithBody(
1021
+ `/webdata/extractions/${request.id}${query ? `?${query}` : ""}`,
1022
+ {
1023
+ id: request.id,
1024
+ environment: request.environment,
1025
+ projectId: request.projectId
1026
+ }
965
1027
  );
966
1028
  }
967
1029
  /**
@@ -1040,9 +1102,7 @@ var Extraction = class {
1040
1102
  if (request.limit) params.set("limit", request.limit.toString());
1041
1103
  if (request.cursor) params.set("cursor", request.cursor);
1042
1104
  const query = params.toString();
1043
- const response = await this.http.get(
1044
- `/webdata/batch${query ? `?${query}` : ""}`
1045
- );
1105
+ const response = await this.http.get(`/webdata/batch${query ? `?${query}` : ""}`);
1046
1106
  return {
1047
1107
  ...response,
1048
1108
  items: response.items.map((item) => this.convertBatchJobDates(item))
@@ -1056,10 +1116,7 @@ var Extraction = class {
1056
1116
  if (request.environment) params.set("environment", request.environment);
1057
1117
  if (request.projectId) params.set("projectId", request.projectId);
1058
1118
  const query = params.toString();
1059
- return this.http.post(
1060
- `/webdata/batch/${request.id}/cancel${query ? `?${query}` : ""}`,
1061
- {}
1062
- );
1119
+ return this.http.post(`/webdata/batch/${request.id}/cancel${query ? `?${query}` : ""}`, {});
1063
1120
  }
1064
1121
  /**
1065
1122
  * Create a batch extraction job and wait for completion
@@ -1112,10 +1169,7 @@ var Extraction = class {
1112
1169
  if (environment) params.set("environment", environment);
1113
1170
  if (projectId) params.set("projectId", projectId);
1114
1171
  const query = params.toString();
1115
- return this.http.post(
1116
- `/webdata/schedules/${id}${query ? `?${query}` : ""}`,
1117
- data
1118
- );
1172
+ return this.http.post(`/webdata/schedules/${id}${query ? `?${query}` : ""}`, data);
1119
1173
  }
1120
1174
  /**
1121
1175
  * Get a schedule by ID
@@ -1141,9 +1195,7 @@ var Extraction = class {
1141
1195
  if (request.limit) params.set("limit", request.limit.toString());
1142
1196
  if (request.cursor) params.set("cursor", request.cursor);
1143
1197
  const query = params.toString();
1144
- const response = await this.http.get(
1145
- `/webdata/schedules${query ? `?${query}` : ""}`
1146
- );
1198
+ const response = await this.http.get(`/webdata/schedules${query ? `?${query}` : ""}`);
1147
1199
  return {
1148
1200
  ...response,
1149
1201
  items: response.items.map((item) => this.convertScheduleDates(item))
@@ -1157,8 +1209,13 @@ var Extraction = class {
1157
1209
  if (request.environment) params.set("environment", request.environment);
1158
1210
  if (request.projectId) params.set("projectId", request.projectId);
1159
1211
  const query = params.toString();
1160
- return this.http.delete(
1161
- `/webdata/schedules/${request.id}${query ? `?${query}` : ""}`
1212
+ return this.http.deleteWithBody(
1213
+ `/webdata/schedules/${request.id}${query ? `?${query}` : ""}`,
1214
+ {
1215
+ id: request.id,
1216
+ environment: request.environment,
1217
+ projectId: request.projectId
1218
+ }
1162
1219
  );
1163
1220
  }
1164
1221
  /**
@@ -1196,9 +1253,7 @@ var Extraction = class {
1196
1253
  if (request.periodStart) params.set("periodStart", request.periodStart);
1197
1254
  if (request.periodEnd) params.set("periodEnd", request.periodEnd);
1198
1255
  const query = params.toString();
1199
- const response = await this.http.get(
1200
- `/webdata/usage${query ? `?${query}` : ""}`
1201
- );
1256
+ const response = await this.http.get(`/webdata/usage${query ? `?${query}` : ""}`);
1202
1257
  return this.convertUsageDates(response);
1203
1258
  }
1204
1259
  // ==========================================================================
@@ -1339,7 +1394,14 @@ var Webdata = class {
1339
1394
  if (request.environment) params.set("environment", request.environment);
1340
1395
  if (request.projectId) params.set("projectId", request.projectId);
1341
1396
  const query = params.toString();
1342
- return this.http.delete(`/webdata/screenshots/${request.id}${query ? `?${query}` : ""}`);
1397
+ return this.http.deleteWithBody(
1398
+ `/webdata/screenshots/${request.id}${query ? `?${query}` : ""}`,
1399
+ {
1400
+ id: request.id,
1401
+ environment: request.environment,
1402
+ projectId: request.projectId
1403
+ }
1404
+ );
1343
1405
  }
1344
1406
  /**
1345
1407
  * Capture a screenshot and wait for completion
@@ -1455,7 +1517,14 @@ var Webdata = class {
1455
1517
  if (request.environment) params.set("environment", request.environment);
1456
1518
  if (request.projectId) params.set("projectId", request.projectId);
1457
1519
  const query = params.toString();
1458
- return this.http.delete(`/webdata/extractions/${request.id}${query ? `?${query}` : ""}`);
1520
+ return this.http.deleteWithBody(
1521
+ `/webdata/extractions/${request.id}${query ? `?${query}` : ""}`,
1522
+ {
1523
+ id: request.id,
1524
+ environment: request.environment,
1525
+ projectId: request.projectId
1526
+ }
1527
+ );
1459
1528
  }
1460
1529
  /**
1461
1530
  * Extract content and wait for completion
@@ -1586,7 +1655,14 @@ var Webdata = class {
1586
1655
  if (request.environment) params.set("environment", request.environment);
1587
1656
  if (request.projectId) params.set("projectId", request.projectId);
1588
1657
  const query = params.toString();
1589
- return this.http.delete(`/webdata/schedules/${request.id}${query ? `?${query}` : ""}`);
1658
+ return this.http.deleteWithBody(
1659
+ `/webdata/schedules/${request.id}${query ? `?${query}` : ""}`,
1660
+ {
1661
+ id: request.id,
1662
+ environment: request.environment,
1663
+ projectId: request.projectId
1664
+ }
1665
+ );
1590
1666
  }
1591
1667
  /**
1592
1668
  * Toggle a schedule on or off
@@ -2159,6 +2235,367 @@ var Integrations = class {
2159
2235
  }
2160
2236
  };
2161
2237
 
2238
+ // src/marketing/client.ts
2239
+ var Marketing = class {
2240
+ http;
2241
+ constructor(config) {
2242
+ this.http = new HttpClient(config);
2243
+ }
2244
+ // ============================================================================
2245
+ // Trends
2246
+ // ============================================================================
2247
+ /**
2248
+ * Discover new trends from all sources
2249
+ *
2250
+ * @example
2251
+ * ```typescript
2252
+ * const { trendsDiscovered, trends } = await marketing.discoverTrends({
2253
+ * projectSlug: 'my-project',
2254
+ * environment: 'production',
2255
+ * });
2256
+ * console.log(`Discovered ${trendsDiscovered} new trends`);
2257
+ * ```
2258
+ */
2259
+ async discoverTrends(request) {
2260
+ return this.http.post("/marketing/trends/discover", request);
2261
+ }
2262
+ /**
2263
+ * List trends for a project
2264
+ *
2265
+ * @example
2266
+ * ```typescript
2267
+ * const trends = await marketing.listTrends({
2268
+ * projectSlug: 'my-project',
2269
+ * environment: 'production',
2270
+ * limit: 20,
2271
+ * });
2272
+ * ```
2273
+ */
2274
+ async listTrends(request) {
2275
+ return this.http.get(
2276
+ `/marketing/trends?${new URLSearchParams({
2277
+ projectSlug: request.projectSlug,
2278
+ environment: request.environment,
2279
+ ...request.status && { status: request.status },
2280
+ ...request.limit && { limit: request.limit.toString() }
2281
+ }).toString()}`
2282
+ );
2283
+ }
2284
+ /**
2285
+ * Get a single trend by ID
2286
+ */
2287
+ async getTrend(trendId) {
2288
+ const response = await this.http.get(`/marketing/trends/${trendId}`);
2289
+ return this.convertTrendDates(response);
2290
+ }
2291
+ // ============================================================================
2292
+ // Opportunities
2293
+ // ============================================================================
2294
+ /**
2295
+ * Generate content opportunities from active trends
2296
+ *
2297
+ * @example
2298
+ * ```typescript
2299
+ * const { opportunitiesGenerated, opportunities } = await marketing.generateOpportunities({
2300
+ * projectSlug: 'my-project',
2301
+ * environment: 'production',
2302
+ * });
2303
+ * console.log(`Generated ${opportunitiesGenerated} new content ideas`);
2304
+ * ```
2305
+ */
2306
+ async generateOpportunities(request) {
2307
+ return this.http.post("/marketing/opportunities/generate", request);
2308
+ }
2309
+ /**
2310
+ * List opportunities for a project
2311
+ *
2312
+ * @example
2313
+ * ```typescript
2314
+ * const opportunities = await marketing.listOpportunities({
2315
+ * projectSlug: 'my-project',
2316
+ * environment: 'production',
2317
+ * status: 'pending',
2318
+ * limit: 20,
2319
+ * });
2320
+ * ```
2321
+ */
2322
+ async listOpportunities(request) {
2323
+ const params = new URLSearchParams({
2324
+ projectSlug: request.projectSlug,
2325
+ environment: request.environment,
2326
+ ...request.status && { status: request.status },
2327
+ ...request.limit && { limit: request.limit.toString() }
2328
+ });
2329
+ return this.http.get(`/marketing/opportunities?${params.toString()}`);
2330
+ }
2331
+ /**
2332
+ * Get a single opportunity by ID
2333
+ */
2334
+ async getOpportunity(opportunityId) {
2335
+ const response = await this.http.get(`/marketing/opportunities/${opportunityId}`);
2336
+ return this.convertOpportunityDates(response);
2337
+ }
2338
+ /**
2339
+ * Dismiss an opportunity
2340
+ *
2341
+ * @example
2342
+ * ```typescript
2343
+ * await marketing.dismissOpportunity({ opportunityId: 'opp-id' });
2344
+ * ```
2345
+ */
2346
+ async dismissOpportunity(request) {
2347
+ return this.http.post(`/marketing/opportunities/${request.opportunityId}/dismiss`, {});
2348
+ }
2349
+ // ============================================================================
2350
+ // Content
2351
+ // ============================================================================
2352
+ /**
2353
+ * Create new marketing content
2354
+ *
2355
+ * @example
2356
+ * ```typescript
2357
+ * const content = await marketing.createContent({
2358
+ * projectSlug: 'my-project',
2359
+ * environment: 'production',
2360
+ * contentType: 'tiktok_slideshow',
2361
+ * title: 'How AI is Changing Marketing',
2362
+ * opportunityId: 'opp-id',
2363
+ * });
2364
+ * ```
2365
+ */
2366
+ async createContent(request) {
2367
+ const response = await this.http.post("/marketing/content", request);
2368
+ return this.convertContentDates(response);
2369
+ }
2370
+ /**
2371
+ * List content with filters
2372
+ *
2373
+ * @example
2374
+ * ```typescript
2375
+ * const content = await marketing.listContent({
2376
+ * projectSlug: 'my-project',
2377
+ * environment: 'production',
2378
+ * status: 'published',
2379
+ * limit: 20,
2380
+ * });
2381
+ * ```
2382
+ */
2383
+ async listContent(request) {
2384
+ const params = new URLSearchParams({
2385
+ projectSlug: request.projectSlug,
2386
+ environment: request.environment,
2387
+ ...request.status && { status: request.status },
2388
+ ...request.contentType && { contentType: request.contentType },
2389
+ ...request.approvalStatus && { approvalStatus: request.approvalStatus },
2390
+ ...request.limit && { limit: request.limit.toString() },
2391
+ ...request.offset && { offset: request.offset.toString() }
2392
+ });
2393
+ const response = await this.http.get(`/marketing/content?${params.toString()}`);
2394
+ return response.map((c) => this.convertContentDates(c));
2395
+ }
2396
+ /**
2397
+ * Get a single content by ID
2398
+ */
2399
+ async getContent(contentId) {
2400
+ const response = await this.http.get(`/marketing/content/${contentId}`);
2401
+ return this.convertContentDates(response);
2402
+ }
2403
+ /**
2404
+ * Update content
2405
+ *
2406
+ * @example
2407
+ * ```typescript
2408
+ * const updated = await marketing.updateContent({
2409
+ * contentId: 'content-id',
2410
+ * title: 'Updated Title',
2411
+ * status: 'published',
2412
+ * });
2413
+ * ```
2414
+ */
2415
+ async updateContent(request) {
2416
+ const { contentId, ...data } = request;
2417
+ const response = await this.http.patch(`/marketing/content/${contentId}`, data);
2418
+ return this.convertContentDates(response);
2419
+ }
2420
+ /**
2421
+ * Approve content for publishing
2422
+ *
2423
+ * @example
2424
+ * ```typescript
2425
+ * await marketing.approveContent({
2426
+ * contentId: 'content-id',
2427
+ * reviewNotes: 'Looks great!',
2428
+ * });
2429
+ * ```
2430
+ */
2431
+ async approveContent(request) {
2432
+ const response = await this.http.post(`/marketing/content/${request.contentId}/approve`, request);
2433
+ return this.convertContentDates(response);
2434
+ }
2435
+ /**
2436
+ * Reject content
2437
+ *
2438
+ * @example
2439
+ * ```typescript
2440
+ * await marketing.rejectContent({
2441
+ * contentId: 'content-id',
2442
+ * reviewNotes: 'Needs revisions',
2443
+ * });
2444
+ * ```
2445
+ */
2446
+ async rejectContent(request) {
2447
+ const response = await this.http.post(`/marketing/content/${request.contentId}/reject`, request);
2448
+ return this.convertContentDates(response);
2449
+ }
2450
+ /**
2451
+ * Delete content
2452
+ */
2453
+ async deleteContent(contentId) {
2454
+ return this.http.deleteWithBody(`/marketing/content/${contentId}`, { contentId });
2455
+ }
2456
+ // ============================================================================
2457
+ // Scripts
2458
+ // ============================================================================
2459
+ /**
2460
+ * Create a new script
2461
+ *
2462
+ * @example
2463
+ * ```typescript
2464
+ * const script = await marketing.createScript({
2465
+ * projectSlug: 'my-project',
2466
+ * environment: 'production',
2467
+ * hook: 'Are you ready to see the future?',
2468
+ * slides: [
2469
+ * { order: 0, text: 'AI is changing everything', voiceoverText: 'AI is transforming how we work', duration: 3 },
2470
+ * ],
2471
+ * cta: 'Follow for more insights!',
2472
+ * });
2473
+ * ```
2474
+ */
2475
+ async createScript(request) {
2476
+ const response = await this.http.post("/marketing/scripts", request);
2477
+ return this.convertScriptDates(response);
2478
+ }
2479
+ /**
2480
+ * List scripts
2481
+ */
2482
+ async listScripts(request) {
2483
+ const params = new URLSearchParams({
2484
+ projectSlug: request.projectSlug,
2485
+ environment: request.environment,
2486
+ ...request.contentId && { contentId: request.contentId },
2487
+ ...request.limit && { limit: request.limit.toString() }
2488
+ });
2489
+ const response = await this.http.get(`/marketing/scripts?${params.toString()}`);
2490
+ return response.map((s) => this.convertScriptDates(s));
2491
+ }
2492
+ /**
2493
+ * Get a single script by ID
2494
+ */
2495
+ async getScript(scriptId) {
2496
+ const response = await this.http.get(`/marketing/scripts/${scriptId}`);
2497
+ return this.convertScriptDates(response);
2498
+ }
2499
+ // ============================================================================
2500
+ // Analytics
2501
+ // ============================================================================
2502
+ /**
2503
+ * Get analytics overview
2504
+ *
2505
+ * @example
2506
+ * ```typescript
2507
+ * const analytics = await marketing.getAnalyticsOverview({
2508
+ * projectSlug: 'my-project',
2509
+ * environment: 'production',
2510
+ * });
2511
+ * console.log(`Total content: ${analytics.totalContent}`);
2512
+ * console.log(`Total views: ${analytics.engagement.views}`);
2513
+ * ```
2514
+ */
2515
+ async getAnalyticsOverview(request) {
2516
+ const params = new URLSearchParams({
2517
+ projectSlug: request.projectSlug,
2518
+ environment: request.environment,
2519
+ ...request.startDate && { startDate: request.startDate.toISOString() },
2520
+ ...request.endDate && { endDate: request.endDate.toISOString() }
2521
+ });
2522
+ return this.http.get(`/marketing/analytics/overview?${params.toString()}`);
2523
+ }
2524
+ /**
2525
+ * Get content performance metrics
2526
+ *
2527
+ * @example
2528
+ * ```typescript
2529
+ * const topContent = await marketing.getContentPerformance({
2530
+ * projectSlug: 'my-project',
2531
+ * environment: 'production',
2532
+ * contentType: 'tiktok_slideshow',
2533
+ * limit: 10,
2534
+ * });
2535
+ * ```
2536
+ */
2537
+ async getContentPerformance(request) {
2538
+ const params = new URLSearchParams({
2539
+ projectSlug: request.projectSlug,
2540
+ environment: request.environment,
2541
+ ...request.contentType && { contentType: request.contentType },
2542
+ ...request.limit && { limit: request.limit.toString() }
2543
+ });
2544
+ return this.http.get(`/marketing/analytics/performance?${params.toString()}`);
2545
+ }
2546
+ // ============================================================================
2547
+ // Date Conversion Helpers
2548
+ // ============================================================================
2549
+ convertTrendDates(trend) {
2550
+ if (typeof trend.firstSeenAt === "string") {
2551
+ trend.firstSeenAt = new Date(trend.firstSeenAt);
2552
+ }
2553
+ if (typeof trend.lastUpdatedAt === "string") {
2554
+ trend.lastUpdatedAt = new Date(trend.lastUpdatedAt);
2555
+ }
2556
+ if (trend.expiresAt && typeof trend.expiresAt === "string") {
2557
+ trend.expiresAt = new Date(trend.expiresAt);
2558
+ }
2559
+ if (typeof trend.createdAt === "string") {
2560
+ trend.createdAt = new Date(trend.createdAt);
2561
+ }
2562
+ return trend;
2563
+ }
2564
+ convertOpportunityDates(opp) {
2565
+ if (typeof opp.createdAt === "string") {
2566
+ opp.createdAt = new Date(opp.createdAt);
2567
+ }
2568
+ if (opp.expiresAt && typeof opp.expiresAt === "string") {
2569
+ opp.expiresAt = new Date(opp.expiresAt);
2570
+ }
2571
+ if (opp.usedAt && typeof opp.usedAt === "string") {
2572
+ opp.usedAt = new Date(opp.usedAt);
2573
+ }
2574
+ return opp;
2575
+ }
2576
+ convertContentDates(content) {
2577
+ if (typeof content.createdAt === "string") {
2578
+ content.createdAt = new Date(content.createdAt);
2579
+ }
2580
+ if (content.updatedAt && typeof content.updatedAt === "string") {
2581
+ content.updatedAt = new Date(content.updatedAt);
2582
+ }
2583
+ if (content.reviewedAt && typeof content.reviewedAt === "string") {
2584
+ content.reviewedAt = new Date(content.reviewedAt);
2585
+ }
2586
+ if (content.publishedAt && typeof content.publishedAt === "string") {
2587
+ content.publishedAt = new Date(content.publishedAt);
2588
+ }
2589
+ return content;
2590
+ }
2591
+ convertScriptDates(script) {
2592
+ if (typeof script.createdAt === "string") {
2593
+ script.createdAt = new Date(script.createdAt);
2594
+ }
2595
+ return script;
2596
+ }
2597
+ };
2598
+
2162
2599
  // src/index.ts
2163
2600
  var Stack0 = class {
2164
2601
  mail;
@@ -2166,6 +2603,7 @@ var Stack0 = class {
2166
2603
  screenshots;
2167
2604
  extraction;
2168
2605
  integrations;
2606
+ marketing;
2169
2607
  /**
2170
2608
  * @deprecated Use `screenshots` and `extraction` instead. Will be removed in a future version.
2171
2609
  */
@@ -2176,15 +2614,16 @@ var Stack0 = class {
2176
2614
  baseUrl: config.baseUrl
2177
2615
  };
2178
2616
  this.mail = new Mail(clientConfig);
2179
- this.cdn = new CDN(clientConfig);
2617
+ this.cdn = new CDN(clientConfig, config.cdnUrl);
2180
2618
  this.screenshots = new Screenshots(clientConfig);
2181
2619
  this.extraction = new Extraction(clientConfig);
2182
2620
  this.integrations = new Integrations(clientConfig);
2621
+ this.marketing = new Marketing(clientConfig);
2183
2622
  this.webdata = new Webdata(clientConfig);
2184
2623
  }
2185
2624
  };
2186
2625
  var src_default = Stack0;
2187
2626
 
2188
- export { CDN, Extraction, Integrations, Mail, Screenshots, Stack0, Webdata, src_default as default };
2627
+ export { CDN, Extraction, Integrations, Mail, Marketing, Screenshots, Stack0, Webdata, src_default as default };
2189
2628
  //# sourceMappingURL=index.mjs.map
2190
2629
  //# sourceMappingURL=index.mjs.map