vidspotai-shared 1.0.113 → 1.0.115

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 (95) hide show
  1. package/lib/globals/types.d.ts +17 -1
  2. package/lib/globals/types.d.ts.map +1 -1
  3. package/lib/globals/types.js +18 -0
  4. package/lib/libs/index.d.ts +1 -0
  5. package/lib/libs/index.d.ts.map +1 -1
  6. package/lib/libs/index.js +1 -0
  7. package/lib/libs/mediaStore.d.ts +3 -31
  8. package/lib/libs/mediaStore.d.ts.map +1 -1
  9. package/lib/libs/mediaStore.js +16 -140
  10. package/lib/libs/storage/GcsBackend.d.ts +9 -0
  11. package/lib/libs/storage/GcsBackend.d.ts.map +1 -0
  12. package/lib/libs/storage/GcsBackend.js +42 -0
  13. package/lib/libs/storage/MediaStorage.d.ts +117 -0
  14. package/lib/libs/storage/MediaStorage.d.ts.map +1 -0
  15. package/lib/libs/storage/MediaStorage.js +117 -0
  16. package/lib/libs/storage/R2Backend.d.ts +42 -0
  17. package/lib/libs/storage/R2Backend.d.ts.map +1 -0
  18. package/lib/libs/storage/R2Backend.js +175 -0
  19. package/lib/libs/storage/StorageBackend.d.ts +41 -0
  20. package/lib/libs/storage/StorageBackend.d.ts.map +1 -0
  21. package/lib/libs/storage/StorageBackend.js +2 -0
  22. package/lib/libs/storage/cdnUrl.d.ts +27 -0
  23. package/lib/libs/storage/cdnUrl.d.ts.map +1 -0
  24. package/lib/libs/storage/cdnUrl.js +48 -0
  25. package/lib/libs/storage/index.d.ts +6 -0
  26. package/lib/libs/storage/index.d.ts.map +1 -0
  27. package/lib/libs/storage/index.js +21 -0
  28. package/lib/models/agent.model.d.ts +27 -0
  29. package/lib/models/agent.model.d.ts.map +1 -1
  30. package/lib/models/index.d.ts +1 -0
  31. package/lib/models/index.d.ts.map +1 -1
  32. package/lib/models/index.js +1 -0
  33. package/lib/models/outreach.model.d.ts +7 -1
  34. package/lib/models/outreach.model.d.ts.map +1 -1
  35. package/lib/models/outreachIntegration.model.d.ts +42 -0
  36. package/lib/models/outreachIntegration.model.d.ts.map +1 -0
  37. package/lib/models/outreachIntegration.model.js +8 -0
  38. package/lib/models/video.model.d.ts +7 -1
  39. package/lib/models/video.model.d.ts.map +1 -1
  40. package/lib/schemas/videoPlan.schema.d.ts +1 -0
  41. package/lib/schemas/videoPlan.schema.d.ts.map +1 -1
  42. package/lib/schemas/videoPlan.schema.js +10 -0
  43. package/lib/services/agent/tools/generateAvatarVideo.tool.d.ts.map +1 -1
  44. package/lib/services/agent/tools/generateAvatarVideo.tool.js +3 -5
  45. package/lib/services/agent/tools/planVideo.tool.d.ts +1 -0
  46. package/lib/services/agent/tools/planVideo.tool.d.ts.map +1 -1
  47. package/lib/services/aiGen/providers/alibaba/alibaba.d.ts.map +1 -1
  48. package/lib/services/aiGen/providers/alibaba/alibaba.js +5 -11
  49. package/lib/services/aiGen/providers/bytedance/bytedance.service.d.ts.map +1 -1
  50. package/lib/services/aiGen/providers/bytedance/bytedance.service.js +5 -0
  51. package/lib/services/aiGen/providers/elevenlabs/elevenlabs.service.d.ts.map +1 -1
  52. package/lib/services/aiGen/providers/elevenlabs/elevenlabs.service.js +3 -7
  53. package/lib/services/aiGen/providers/google/google.service.d.ts.map +1 -1
  54. package/lib/services/aiGen/providers/google/google.service.js +7 -4
  55. package/lib/services/aiGen/providers/google/googleMusic.d.ts.map +1 -1
  56. package/lib/services/aiGen/providers/google/googleMusic.js +3 -7
  57. package/lib/services/aiGen/providers/kling/kling.service.d.ts +16 -7
  58. package/lib/services/aiGen/providers/kling/kling.service.d.ts.map +1 -1
  59. package/lib/services/aiGen/providers/kling/kling.service.js +2 -2
  60. package/lib/services/aiGen/providers/kling/klingImage.service.d.ts.map +1 -1
  61. package/lib/services/aiGen/providers/kling/klingImage.service.js +3 -5
  62. package/lib/services/aiGen/providers/kling/klingStatus.d.ts +1 -1
  63. package/lib/services/aiGen/providers/kling/klingStatus.d.ts.map +1 -1
  64. package/lib/services/aiGen/providers/kling/klingStatus.js +8 -19
  65. package/lib/services/aiGen/providers/minimax/minimax.service.d.ts.map +1 -1
  66. package/lib/services/aiGen/providers/minimax/minimax.service.js +7 -17
  67. package/lib/services/aiGen/providers/openai/openai.service.d.ts.map +1 -1
  68. package/lib/services/aiGen/providers/openai/openai.service.js +5 -13
  69. package/lib/services/aiGen/providers/pixverse/pixverse.service.d.ts.map +1 -1
  70. package/lib/services/aiGen/providers/pixverse/pixverse.service.js +5 -0
  71. package/lib/services/aiGen/providers/runway/runway.service.d.ts.map +1 -1
  72. package/lib/services/aiGen/providers/runway/runway.service.js +5 -10
  73. package/lib/services/avatarGen/IAvatarVideoProvider.d.ts +25 -3
  74. package/lib/services/avatarGen/IAvatarVideoProvider.d.ts.map +1 -1
  75. package/lib/services/avatarGen/IAvatarVideoProvider.js +2 -1
  76. package/lib/services/avatarGen/providers/heygenAvatarProvider.d.ts +23 -2
  77. package/lib/services/avatarGen/providers/heygenAvatarProvider.d.ts.map +1 -1
  78. package/lib/services/avatarGen/providers/heygenAvatarProvider.js +71 -0
  79. package/lib/services/avatarGen/providers/tavusAvatarProvider.d.ts +3 -4
  80. package/lib/services/avatarGen/providers/tavusAvatarProvider.d.ts.map +1 -1
  81. package/lib/services/avatarGen/providers/tavusAvatarProvider.js +17 -0
  82. package/lib/services/editor/planToProject.d.ts.map +1 -1
  83. package/lib/services/editor/planToProject.js +29 -1
  84. package/lib/services/firestore.service.d.ts +3 -0
  85. package/lib/services/firestore.service.d.ts.map +1 -1
  86. package/lib/services/firestore.service.js +7 -0
  87. package/lib/services/gcp/uploadAudioBuffer.d.ts.map +1 -1
  88. package/lib/services/gcp/uploadAudioBuffer.js +4 -0
  89. package/lib/services/index.d.ts +1 -0
  90. package/lib/services/index.d.ts.map +1 -1
  91. package/lib/services/index.js +1 -0
  92. package/lib/services/outreachWebhooks.service.d.ts +24 -0
  93. package/lib/services/outreachWebhooks.service.d.ts.map +1 -0
  94. package/lib/services/outreachWebhooks.service.js +41 -0
  95. package/package.json +1 -1
@@ -38,7 +38,7 @@ exports.OpenaiService = void 0;
38
38
  const openai_1 = __importStar(require("openai"));
39
39
  const aiModels_1 = require("../../../../globals/aiModels");
40
40
  const types_1 = require("../../../../globals/types");
41
- const firebase_1 = require("../../../../libs/firebase");
41
+ const storage_1 = require("../../../../libs/storage");
42
42
  const utils_1 = require("../../../../utils");
43
43
  const logger_1 = require("../../../../utils/logger");
44
44
  const errors_1 = require("../../../../utils/errors");
@@ -148,15 +148,9 @@ class OpenaiService extends baseAiGenProvider_service_1.BaseAiGenProviderService
148
148
  const response = await this.client.videos.downloadContent(task);
149
149
  const blob = await response.blob();
150
150
  const buffer = Buffer.from(await blob.arrayBuffer());
151
- // Upload to Firebase Storage
151
+ // Upload to storage — GCS write + best-effort R2 mirror (zero-egress).
152
152
  const filePath = `${outputFilePath}/${outputFilename}.mp4`;
153
- const file = (0, firebase_1.getBucket)().file(filePath);
154
- await file.save(buffer, { contentType: "video/mp4" });
155
- // Generate a signed URL
156
- const [signedUrl] = await file.getSignedUrl({
157
- action: "read",
158
- expires: "03-09-2491",
159
- });
153
+ const signedUrl = await storage_1.mediaStorage.put(filePath, buffer, "video/mp4");
160
154
  return {
161
155
  status: types_1.EVideoSceneStatus.COMPLETED,
162
156
  videoUrl: signedUrl,
@@ -307,7 +301,6 @@ class OpenaiService extends baseAiGenProvider_service_1.BaseAiGenProviderService
307
301
  }
308
302
  }
309
303
  const data = resp.data ?? [];
310
- const bucket = (0, firebase_1.getBucket)();
311
304
  const ts = Date.now();
312
305
  const ext = params.outputFormat ?? "png";
313
306
  const urls = [];
@@ -323,9 +316,8 @@ class OpenaiService extends baseAiGenProvider_service_1.BaseAiGenProviderService
323
316
  else
324
317
  continue;
325
318
  const path = `images/openai/${ts}-${Math.random().toString(36).slice(2, 8)}-${i}.${ext}`;
326
- const file = bucket.file(path);
327
- await file.save(bytes, { contentType: `image/${ext}` });
328
- const [signed] = await file.getSignedUrl({ action: "read", expires: "03-09-2491" });
319
+ // mediaStorage: GCS write + best-effort R2 mirror (zero-egress delivery).
320
+ const signed = await storage_1.mediaStorage.put(path, bytes, `image/${ext}`);
329
321
  urls.push(signed);
330
322
  }
331
323
  if (!urls.length)
@@ -1 +1 @@
1
- {"version":3,"file":"pixverse.service.d.ts","sourceRoot":"","sources":["../../../../../src/services/aiGen/providers/pixverse/pixverse.service.ts"],"names":[],"mappings":"AAEA,OAAO,EAAE,wBAAwB,EAAE,MAAM,8BAA8B,CAAC;AACxE,OAAO,EACL,iBAAiB,EACjB,qBAAqB,EACrB,qBAAqB,EACrB,iBAAiB,EACjB,iBAAiB,EAClB,MAAM,UAAU,CAAC;AA+FlB,qBAAa,eAAgB,SAAQ,wBAAwB;IAC3D,OAAO,CAAC,QAAQ,CAAC,OAAO,CAAkD;IAK1E;;;;;;OAMG;YACW,WAAW;IA6CnB,aAAa,CACjB,MAAM,EAAE,qBAAqB,GAC5B,OAAO,CAAC,qBAAqB,CAAC;IAyL3B,gBAAgB,CAAC,EACrB,IAAI,EACJ,cAAc,EACd,cAAyB,GAC1B,EAAE,iBAAiB,GAAG,OAAO,CAAC,iBAAiB,CAAC;IA+GjD,aAAa,CAAC,MAAM,EAAE,iBAAiB,GAAG,MAAM;CAkDjD"}
1
+ {"version":3,"file":"pixverse.service.d.ts","sourceRoot":"","sources":["../../../../../src/services/aiGen/providers/pixverse/pixverse.service.ts"],"names":[],"mappings":"AAEA,OAAO,EAAE,wBAAwB,EAAE,MAAM,8BAA8B,CAAC;AACxE,OAAO,EACL,iBAAiB,EACjB,qBAAqB,EACrB,qBAAqB,EACrB,iBAAiB,EACjB,iBAAiB,EAClB,MAAM,UAAU,CAAC;AAgGlB,qBAAa,eAAgB,SAAQ,wBAAwB;IAC3D,OAAO,CAAC,QAAQ,CAAC,OAAO,CAAkD;IAK1E;;;;;;OAMG;YACW,WAAW;IA6CnB,aAAa,CACjB,MAAM,EAAE,qBAAqB,GAC5B,OAAO,CAAC,qBAAqB,CAAC;IAyL3B,gBAAgB,CAAC,EACrB,IAAI,EACJ,cAAc,EACd,cAAyB,GAC1B,EAAE,iBAAiB,GAAG,OAAO,CAAC,iBAAiB,CAAC;IAoHjD,aAAa,CAAC,MAAM,EAAE,iBAAiB,GAAG,MAAM;CAkDjD"}
@@ -10,6 +10,7 @@ const helpers_1 = require("../../helpers");
10
10
  const aiModels_1 = require("../../../../globals/aiModels");
11
11
  const types_1 = require("../../../../globals/types");
12
12
  const firebase_1 = require("../../../../libs/firebase");
13
+ const storage_1 = require("../../../../libs/storage");
13
14
  const helpers_2 = require("../../../../utils/helpers");
14
15
  const mp4Duration_1 = require("../../../../utils/mp4Duration");
15
16
  const logger_1 = require("../../../../utils/logger");
@@ -372,6 +373,10 @@ class PixVerseService extends baseAiGenProvider_service_1.BaseAiGenProviderServi
372
373
  },
373
374
  },
374
375
  });
376
+ // mediaStorage: best-effort R2 mirror (zero-egress delivery). GCS keeps the
377
+ // firebaseStorage download-token URL as the stored system-of-record URL; the
378
+ // CDN Worker resolves either URL family to the same R2 object.
379
+ await storage_1.mediaStorage.mirrorBytes(filePath, buffer, "video/mp4");
375
380
  const publicVideoUrl = `https://firebasestorage.googleapis.com/v0/b/${bucket.name}` +
376
381
  `/o/${encodeURIComponent(filePath)}?alt=media&token=${downloadToken}`;
377
382
  return {
@@ -1 +1 @@
1
- {"version":3,"file":"runway.service.d.ts","sourceRoot":"","sources":["../../../../../src/services/aiGen/providers/runway/runway.service.ts"],"names":[],"mappings":"AAOA,OAAO,EAAE,wBAAwB,EAAE,MAAM,8BAA8B,CAAC;AACxE,OAAO,EACL,iBAAiB,EACjB,qBAAqB,EACrB,qBAAqB,EACrB,qBAAqB,EACrB,qBAAqB,EACrB,iBAAiB,EACjB,iBAAiB,EAClB,MAAM,UAAU,CAAC;AAIlB,qBAAa,aAAc,SAAQ,wBAAwB;IACzD,OAAO,CAAC,QAAQ,CAAC,OAAO,CAAqC;IAC7D,OAAO,CAAC,QAAQ,CAAC,MAAM,CAAS;;YAUlB,OAAO;IAgCf,aAAa,CACjB,MAAM,EAAE,qBAAqB,GAC5B,OAAO,CAAC,qBAAqB,CAAC;IA6G3B,gBAAgB,CAAC,EACrB,IAAI,EACJ,cAAc,EACd,cAAyB,GAC1B,EAAE,iBAAiB,GAAG,OAAO,CAAC,iBAAiB,CAAC;IA4DjD,aAAa,CAAC,EAAE,QAAQ,EAAE,QAAY,EAAE,SAAiB,EAAE,SAAa,EAAE,WAAW,EAAE,WAAW,EAAE,EAAE,iBAAiB,GAAG,MAAM;IA0BhI;;;;;;;;OAQG;IACG,aAAa,CACjB,MAAM,EAAE,qBAAqB,GAC5B,OAAO,CAAC,qBAAqB,CAAC;CA0ElC"}
1
+ {"version":3,"file":"runway.service.d.ts","sourceRoot":"","sources":["../../../../../src/services/aiGen/providers/runway/runway.service.ts"],"names":[],"mappings":"AAOA,OAAO,EAAE,wBAAwB,EAAE,MAAM,8BAA8B,CAAC;AACxE,OAAO,EACL,iBAAiB,EACjB,qBAAqB,EACrB,qBAAqB,EACrB,qBAAqB,EACrB,qBAAqB,EACrB,iBAAiB,EACjB,iBAAiB,EAClB,MAAM,UAAU,CAAC;AAIlB,qBAAa,aAAc,SAAQ,wBAAwB;IACzD,OAAO,CAAC,QAAQ,CAAC,OAAO,CAAqC;IAC7D,OAAO,CAAC,QAAQ,CAAC,MAAM,CAAS;;YAUlB,OAAO;IAgCf,aAAa,CACjB,MAAM,EAAE,qBAAqB,GAC5B,OAAO,CAAC,qBAAqB,CAAC;IA6G3B,gBAAgB,CAAC,EACrB,IAAI,EACJ,cAAc,EACd,cAAyB,GAC1B,EAAE,iBAAiB,GAAG,OAAO,CAAC,iBAAiB,CAAC;IAuDjD,aAAa,CAAC,EAAE,QAAQ,EAAE,QAAY,EAAE,SAAiB,EAAE,SAAa,EAAE,WAAW,EAAE,WAAW,EAAE,EAAE,iBAAiB,GAAG,MAAM;IA0BhI;;;;;;;;OAQG;IACG,aAAa,CACjB,MAAM,EAAE,qBAAqB,GAC5B,OAAO,CAAC,qBAAqB,CAAC;CAyElC"}
@@ -7,7 +7,7 @@ exports.RunwayService = void 0;
7
7
  const axios_1 = __importDefault(require("axios"));
8
8
  const aiModels_1 = require("../../../../globals/aiModels");
9
9
  const types_1 = require("../../../../globals/types");
10
- const firebase_1 = require("../../../../libs/firebase");
10
+ const storage_1 = require("../../../../libs/storage");
11
11
  const helpers_1 = require("../../../../utils/helpers");
12
12
  const logger_1 = require("../../../../utils/logger");
13
13
  const helpers_2 = require("../../helpers");
@@ -161,12 +161,8 @@ class RunwayService extends baseAiGenProvider_service_1.BaseAiGenProviderService
161
161
  }
162
162
  const buffer = Buffer.from(videoResp.data);
163
163
  const filePath = `${outputFilePath}/${outputFilename}.mp4`;
164
- const file = (0, firebase_1.getBucket)().file(filePath);
165
- await file.save(buffer, { contentType: "video/mp4" });
166
- const [signedUrl] = await file.getSignedUrl({
167
- action: "read",
168
- expires: "03-09-2491",
169
- });
164
+ // mediaStorage: GCS write + best-effort R2 mirror (zero-egress delivery).
165
+ const signedUrl = await storage_1.mediaStorage.put(filePath, buffer, "video/mp4");
170
166
  return {
171
167
  videoUrl: signedUrl,
172
168
  status: types_1.EVideoSceneStatus.COMPLETED,
@@ -264,9 +260,8 @@ class RunwayService extends baseAiGenProvider_service_1.BaseAiGenProviderService
264
260
  const ext = (contentType.split("/")[1] ?? "png").toLowerCase();
265
261
  const ts = Date.now();
266
262
  const path = `images/runway/${ts}-${Math.random().toString(36).slice(2, 8)}.${ext}`;
267
- const file = (0, firebase_1.getBucket)().file(path);
268
- await file.save(Buffer.from(imgResp.data), { contentType });
269
- const [signed] = await file.getSignedUrl({ action: "read", expires: "03-09-2491" });
263
+ // mediaStorage: GCS write + best-effort R2 mirror (zero-egress delivery).
264
+ const signed = await storage_1.mediaStorage.put(path, Buffer.from(imgResp.data), contentType);
270
265
  return {
271
266
  imageUrl: signed,
272
267
  providerRequestId: run.id,
@@ -120,11 +120,33 @@ export interface ISupportsHostedCatalog {
120
120
  listAvatars(): Promise<AvatarOption[]>;
121
121
  listVoices(): Promise<VoiceOption[]>;
122
122
  }
123
+ export interface CreateReplicaResult {
124
+ /** Provider-scoped id for the trained replica/look. Persist it, and once
125
+ * status is "ready" pass it straight through as `hostedAvatarId`. */
126
+ replicaId: string;
127
+ /**
128
+ * Present only when the engine requires an out-of-band consent step before
129
+ * the replica can render (HeyGen: a hosted webcam page the subject must
130
+ * open within 24h). Absent when the engine captures consent as part of
131
+ * training itself (Tavus: a consent clip is submitted in the same call).
132
+ */
133
+ consentUrl?: string;
134
+ /**
135
+ * Opaque per-engine bookkeeping the caller must persist and pass back to
136
+ * `checkReplicaStatus` unchanged (HeyGen: the `avatar_group_id` — consent
137
+ * status lives on the group, not the individual look/replica).
138
+ */
139
+ providerRef?: string;
140
+ }
141
+ export interface ReplicaTrainingStatus {
142
+ status: "training" | "pending_consent" | "ready" | "failed";
143
+ errorMessage?: string;
144
+ }
123
145
  /** Engine can train a likeness replica from user media (HeyGen instant avatar, Tavus replica). */
124
146
  export interface ISupportsReplica {
125
- createReplica(trainingMediaUrl: string, consent: ConsentRecord): Promise<{
126
- replicaId: string;
127
- }>;
147
+ createReplica(trainingMediaUrl: string, consent: ConsentRecord): Promise<CreateReplicaResult>;
148
+ /** `providerRef` is whatever `createReplica` returned as `providerRef` — pass it back unchanged. */
149
+ checkReplicaStatus(replicaId: string, providerRef?: string): Promise<ReplicaTrainingStatus>;
128
150
  }
129
151
  /** Engine can dub an existing video into another language (Tavus — our multilingual wedge). */
130
152
  export interface ISupportsDubbing {
@@ -1 +1 @@
1
- {"version":3,"file":"IAvatarVideoProvider.d.ts","sourceRoot":"","sources":["../../../src/services/avatarGen/IAvatarVideoProvider.ts"],"names":[],"mappings":"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"}
1
+ {"version":3,"file":"IAvatarVideoProvider.d.ts","sourceRoot":"","sources":["../../../src/services/avatarGen/IAvatarVideoProvider.ts"],"names":[],"mappings":"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"}
@@ -35,7 +35,8 @@ function supportsHostedCatalog(p) {
35
35
  typeof p.listVoices === "function");
36
36
  }
37
37
  function supportsReplica(p) {
38
- return typeof p.createReplica === "function";
38
+ return (typeof p.createReplica === "function" &&
39
+ typeof p.checkReplicaStatus === "function");
39
40
  }
40
41
  function supportsDubbing(p) {
41
42
  return typeof p.dub === "function";
@@ -1,5 +1,5 @@
1
1
  import { EVideoGenModels } from "../../../globals/aiModels";
2
- import { AvatarCapabilities, AvatarGenerateRequest, AvatarOption, AvatarStatusQuery, AvatarStatusResult, AvatarSubmitResult, EAvatarEngine, IAvatarVideoProvider, ISupportsHostedCatalog, VoiceOption } from "../IAvatarVideoProvider";
2
+ import { AvatarCapabilities, AvatarGenerateRequest, AvatarOption, AvatarStatusQuery, AvatarStatusResult, AvatarSubmitResult, ConsentRecord, CreateReplicaResult, EAvatarEngine, IAvatarVideoProvider, ISupportsHostedCatalog, ISupportsReplica, ReplicaTrainingStatus, VoiceOption } from "../IAvatarVideoProvider";
3
3
  /**
4
4
  * HeyGen avatar engine — a HOSTED engine (the caller picks a HeyGen-hosted
5
5
  * avatar + voice and supplies a script; HeyGen does its own TTS + lipsync).
@@ -20,8 +20,27 @@ import { AvatarCapabilities, AvatarGenerateRequest, AvatarOption, AvatarStatusQu
20
20
  * Capabilities: inputMode "hosted", nativeTts true (HeyGen synthesizes), no
21
21
  * multi-scene split (one render per script). It also exposes the hosted catalog
22
22
  * (ISupportsHostedCatalog) so the UI / agent can list pickable avatars + voices.
23
+ *
24
+ * Also implements ISupportsReplica — training a "digital twin" from user
25
+ * footage (HeyGen API, verified 2026-09-17 against developers.heygen.com's
26
+ * current v3 avatar docs; v2 above stays on v2 per its own sunset window,
27
+ * training only exists on v3):
28
+ * • train : POST /v3/avatars { type: "digital_twin", name, file: { type:
29
+ * "url", url } } → { data: { avatar_item: { id, status }, //
30
+ * avatar_group: { id, status, consent_status } } }. `avatar_item.id`
31
+ * (a "look") is the id rendered with; `avatar_group.id` owns consent.
32
+ * • consent : POST /v3/avatars/{group_id}/consent {} → { data: { url } } —
33
+ * a hosted webcam consent page, valid 24h, the subject must open.
34
+ * Uploading a pre-recorded consent clip instead (skipping the
35
+ * hosted page) is an enterprise-only tier we don't assume here.
36
+ * • status : GET /v3/avatars/looks/{look_id} → { data: { status: processing|
37
+ * completed|failed, error } } for training, then GET
38
+ * /v3/avatars/{group_id} → { data: { status: pending_consent|
39
+ * completed|failed } } for consent — training gates first, then
40
+ * consent (this is why checkReplicaStatus needs `providerRef`,
41
+ * the group id, in addition to the look id).
23
42
  */
24
- export declare class HeyGenAvatarProvider implements IAvatarVideoProvider, ISupportsHostedCatalog {
43
+ export declare class HeyGenAvatarProvider implements IAvatarVideoProvider, ISupportsHostedCatalog, ISupportsReplica {
25
44
  private readonly modelKey;
26
45
  /** Static so callers can branch on capability without constructing (which
27
46
  * would require HEYGEN_API_KEY just to read the input mode). */
@@ -35,6 +54,8 @@ export declare class HeyGenAvatarProvider implements IAvatarVideoProvider, ISupp
35
54
  constructor(modelKey?: EVideoGenModels);
36
55
  generate(req: AvatarGenerateRequest): Promise<AvatarSubmitResult>;
37
56
  checkStatus(query: AvatarStatusQuery): Promise<AvatarStatusResult>;
57
+ createReplica(trainingMediaUrl: string, consent: ConsentRecord): Promise<CreateReplicaResult>;
58
+ checkReplicaStatus(replicaId: string, providerRef?: string): Promise<ReplicaTrainingStatus>;
38
59
  listAvatars(): Promise<AvatarOption[]>;
39
60
  listVoices(): Promise<VoiceOption[]>;
40
61
  private normalizeGender;
@@ -1 +1 @@
1
- {"version":3,"file":"heygenAvatarProvider.d.ts","sourceRoot":"","sources":["../../../../src/services/avatarGen/providers/heygenAvatarProvider.ts"],"names":[],"mappings":"AACA,OAAO,EAAE,eAAe,EAAE,MAAM,2BAA2B,CAAC;AAI5D,OAAO,EACL,kBAAkB,EAClB,qBAAqB,EACrB,YAAY,EACZ,iBAAiB,EACjB,kBAAkB,EAClB,kBAAkB,EAClB,aAAa,EACb,oBAAoB,EACpB,sBAAsB,EACtB,WAAW,EACZ,MAAM,yBAAyB,CAAC;AAEjC;;;;;;;;;;;;;;;;;;;;GAoBG;AACH,qBAAa,oBACX,YAAW,oBAAoB,EAAE,sBAAsB;IAmBrD,OAAO,CAAC,QAAQ,CAAC,QAAQ;IAjB3B;qEACiE;IACjE,MAAM,CAAC,QAAQ,CAAC,YAAY,EAAE,kBAAkB,CAI9C;IAEF,QAAQ,CAAC,MAAM,wBAAwB;IACvC,QAAQ,CAAC,YAAY,qBAAqC;IAE1D,OAAO,CAAC,QAAQ,CAAC,OAAO,CAA4B;IACpD,OAAO,CAAC,QAAQ,CAAC,MAAM,CAAS;IAChC,OAAO,CAAC,QAAQ,CAAC,aAAa,CAAW;IACzC,OAAO,CAAC,QAAQ,CAAC,aAAa,CAAU;gBAGrB,QAAQ,GAAE,eAA+C;IAQtE,QAAQ,CAAC,GAAG,EAAE,qBAAqB,GAAG,OAAO,CAAC,kBAAkB,CAAC;IA6CjE,WAAW,CAAC,KAAK,EAAE,iBAAiB,GAAG,OAAO,CAAC,kBAAkB,CAAC;IAgClE,WAAW,IAAI,OAAO,CAAC,YAAY,EAAE,CAAC;IAYtC,UAAU,IAAI,OAAO,CAAC,WAAW,EAAE,CAAC;IAwB1C,OAAO,CAAC,eAAe;YAOT,OAAO;IA0BrB,2EAA2E;YAC7D,gBAAgB;CAmD/B"}
1
+ {"version":3,"file":"heygenAvatarProvider.d.ts","sourceRoot":"","sources":["../../../../src/services/avatarGen/providers/heygenAvatarProvider.ts"],"names":[],"mappings":"AACA,OAAO,EAAE,eAAe,EAAE,MAAM,2BAA2B,CAAC;AAI5D,OAAO,EACL,kBAAkB,EAClB,qBAAqB,EACrB,YAAY,EACZ,iBAAiB,EACjB,kBAAkB,EAClB,kBAAkB,EAClB,aAAa,EACb,mBAAmB,EACnB,aAAa,EACb,oBAAoB,EACpB,sBAAsB,EACtB,gBAAgB,EAChB,qBAAqB,EACrB,WAAW,EACZ,MAAM,yBAAyB,CAAC;AAEjC;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;GAuCG;AACH,qBAAa,oBACX,YAAW,oBAAoB,EAAE,sBAAsB,EAAE,gBAAgB;IAmBvE,OAAO,CAAC,QAAQ,CAAC,QAAQ;IAjB3B;qEACiE;IACjE,MAAM,CAAC,QAAQ,CAAC,YAAY,EAAE,kBAAkB,CAI9C;IAEF,QAAQ,CAAC,MAAM,wBAAwB;IACvC,QAAQ,CAAC,YAAY,qBAAqC;IAE1D,OAAO,CAAC,QAAQ,CAAC,OAAO,CAA4B;IACpD,OAAO,CAAC,QAAQ,CAAC,MAAM,CAAS;IAChC,OAAO,CAAC,QAAQ,CAAC,aAAa,CAAW;IACzC,OAAO,CAAC,QAAQ,CAAC,aAAa,CAAU;gBAGrB,QAAQ,GAAE,eAA+C;IAQtE,QAAQ,CAAC,GAAG,EAAE,qBAAqB,GAAG,OAAO,CAAC,kBAAkB,CAAC;IA6CjE,WAAW,CAAC,KAAK,EAAE,iBAAiB,GAAG,OAAO,CAAC,kBAAkB,CAAC;IAgClE,aAAa,CACjB,gBAAgB,EAAE,MAAM,EACxB,OAAO,EAAE,aAAa,GACrB,OAAO,CAAC,mBAAmB,CAAC;IA+CzB,kBAAkB,CACtB,SAAS,EAAE,MAAM,EACjB,WAAW,CAAC,EAAE,MAAM,GACnB,OAAO,CAAC,qBAAqB,CAAC;IA2C3B,WAAW,IAAI,OAAO,CAAC,YAAY,EAAE,CAAC;IAYtC,UAAU,IAAI,OAAO,CAAC,WAAW,EAAE,CAAC;IAwB1C,OAAO,CAAC,eAAe;YAOT,OAAO;IA0BrB,2EAA2E;YAC7D,gBAAgB;CAmD/B"}
@@ -30,6 +30,25 @@ const IAvatarVideoProvider_1 = require("../IAvatarVideoProvider");
30
30
  * Capabilities: inputMode "hosted", nativeTts true (HeyGen synthesizes), no
31
31
  * multi-scene split (one render per script). It also exposes the hosted catalog
32
32
  * (ISupportsHostedCatalog) so the UI / agent can list pickable avatars + voices.
33
+ *
34
+ * Also implements ISupportsReplica — training a "digital twin" from user
35
+ * footage (HeyGen API, verified 2026-09-17 against developers.heygen.com's
36
+ * current v3 avatar docs; v2 above stays on v2 per its own sunset window,
37
+ * training only exists on v3):
38
+ * • train : POST /v3/avatars { type: "digital_twin", name, file: { type:
39
+ * "url", url } } → { data: { avatar_item: { id, status }, //
40
+ * avatar_group: { id, status, consent_status } } }. `avatar_item.id`
41
+ * (a "look") is the id rendered with; `avatar_group.id` owns consent.
42
+ * • consent : POST /v3/avatars/{group_id}/consent {} → { data: { url } } —
43
+ * a hosted webcam consent page, valid 24h, the subject must open.
44
+ * Uploading a pre-recorded consent clip instead (skipping the
45
+ * hosted page) is an enterprise-only tier we don't assume here.
46
+ * • status : GET /v3/avatars/looks/{look_id} → { data: { status: processing|
47
+ * completed|failed, error } } for training, then GET
48
+ * /v3/avatars/{group_id} → { data: { status: pending_consent|
49
+ * completed|failed } } for consent — training gates first, then
50
+ * consent (this is why checkReplicaStatus needs `providerRef`,
51
+ * the group id, in addition to the look id).
33
52
  */
34
53
  class HeyGenAvatarProvider {
35
54
  constructor(modelKey = aiModels_1.EVideoGenModels.HEYGEN_AVATAR) {
@@ -94,6 +113,58 @@ class HeyGenAvatarProvider {
94
113
  }
95
114
  return { status: types_1.EVideoSceneStatus.PENDING };
96
115
  }
116
+ // ─── ISupportsReplica ─────────────────────────────────────────────────────
117
+ async createReplica(trainingMediaUrl, consent) {
118
+ const createData = await this.request("/v3/avatars", "POST", {
119
+ type: "digital_twin",
120
+ name: `vidspot-${consent.userId}-${consent.capturedAt}`,
121
+ file: { type: "url", url: trainingMediaUrl },
122
+ }, this.submitTimeout);
123
+ const lookId = createData?.data?.avatar_item?.id;
124
+ const groupId = createData?.data?.avatar_group?.id;
125
+ if (!lookId || !groupId) {
126
+ throw new Error(`HeyGen createReplica returned no avatar_item/avatar_group id: ${JSON.stringify(createData?.error ?? createData)}`);
127
+ }
128
+ // Kick off the hosted webcam consent flow immediately — the link is only
129
+ // valid 24h, so surface it to the caller right away rather than waiting
130
+ // for training (which runs independently) to finish first.
131
+ const consentData = await this.request(`/v3/avatars/${encodeURIComponent(groupId)}/consent`, "POST", {}, this.submitTimeout);
132
+ const consentUrl = consentData?.data?.url;
133
+ if (!consentUrl) {
134
+ logger_1.logger.warn("HeyGenAvatarProvider.createReplica: no consent url returned — training will proceed but the subject cannot approve consent yet", { groupId, response: consentData });
135
+ }
136
+ return { replicaId: lookId, providerRef: groupId, consentUrl };
137
+ }
138
+ async checkReplicaStatus(replicaId, providerRef) {
139
+ if (!providerRef) {
140
+ throw new Error("HeyGenAvatarProvider.checkReplicaStatus requires providerRef (the avatar_group_id returned by createReplica)");
141
+ }
142
+ const lookData = await this.requestWithRetry(`/v3/avatars/looks/${encodeURIComponent(replicaId)}`, "GET", undefined, this.statusTimeout);
143
+ const lookStatus = lookData?.data?.status;
144
+ if (lookStatus === "failed") {
145
+ return {
146
+ status: "failed",
147
+ errorMessage: lookData?.data?.error?.message ?? "HeyGen digital twin training failed",
148
+ };
149
+ }
150
+ if (lookStatus !== "completed") {
151
+ return { status: "training" };
152
+ }
153
+ // Training is done — now the gate is consent, which lives on the group.
154
+ const groupData = await this.requestWithRetry(`/v3/avatars/${encodeURIComponent(providerRef)}`, "GET", undefined, this.statusTimeout);
155
+ const groupStatus = groupData?.data?.status;
156
+ if (groupStatus === "completed") {
157
+ return { status: "ready" };
158
+ }
159
+ if (groupStatus === "failed") {
160
+ return {
161
+ status: "failed",
162
+ errorMessage: groupData?.data?.error?.message ?? "Avatar consent was rejected",
163
+ };
164
+ }
165
+ // "pending_consent" (or HeyGen hasn't materialized a status yet).
166
+ return { status: "pending_consent" };
167
+ }
97
168
  // ─── ISupportsHostedCatalog ───────────────────────────────────────────────
98
169
  async listAvatars() {
99
170
  const data = await this.requestWithRetry("/v2/avatars", "GET", undefined, this.statusTimeout);
@@ -1,5 +1,5 @@
1
1
  import { EVideoGenModels } from "../../../globals/aiModels";
2
- import { AvatarCapabilities, AvatarGenerateRequest, AvatarOption, AvatarStatusQuery, AvatarStatusResult, AvatarSubmitResult, ConsentRecord, EAvatarEngine, IAvatarVideoProvider, ISupportsHostedCatalog, ISupportsReplica, VoiceOption } from "../IAvatarVideoProvider";
2
+ import { AvatarCapabilities, AvatarGenerateRequest, AvatarOption, AvatarStatusQuery, AvatarStatusResult, AvatarSubmitResult, ConsentRecord, CreateReplicaResult, EAvatarEngine, IAvatarVideoProvider, ISupportsHostedCatalog, ISupportsReplica, ReplicaTrainingStatus, VoiceOption } from "../IAvatarVideoProvider";
3
3
  /**
4
4
  * Tavus avatar engine — a HOSTED engine driven by a trained "replica"
5
5
  * (Tavus's term for a likeness model). The caller supplies a replica_id + a
@@ -39,9 +39,8 @@ export declare class TavusAvatarProvider implements IAvatarVideoProvider, ISuppo
39
39
  constructor(modelKey?: EVideoGenModels);
40
40
  generate(req: AvatarGenerateRequest): Promise<AvatarSubmitResult>;
41
41
  checkStatus(query: AvatarStatusQuery): Promise<AvatarStatusResult>;
42
- createReplica(trainingMediaUrl: string, consent: ConsentRecord): Promise<{
43
- replicaId: string;
44
- }>;
42
+ createReplica(trainingMediaUrl: string, consent: ConsentRecord): Promise<CreateReplicaResult>;
43
+ checkReplicaStatus(replicaId: string): Promise<ReplicaTrainingStatus>;
45
44
  /** For Tavus the catalog of "avatars" is the account's trained replicas. */
46
45
  listAvatars(): Promise<AvatarOption[]>;
47
46
  /**
@@ -1 +1 @@
1
- {"version":3,"file":"tavusAvatarProvider.d.ts","sourceRoot":"","sources":["../../../../src/services/avatarGen/providers/tavusAvatarProvider.ts"],"names":[],"mappings":"AACA,OAAO,EAAE,eAAe,EAAE,MAAM,2BAA2B,CAAC;AAG5D,OAAO,EACL,kBAAkB,EAClB,qBAAqB,EACrB,YAAY,EACZ,iBAAiB,EACjB,kBAAkB,EAClB,kBAAkB,EAClB,aAAa,EACb,aAAa,EACb,oBAAoB,EACpB,sBAAsB,EACtB,gBAAgB,EAChB,WAAW,EACZ,MAAM,yBAAyB,CAAC;AAEjC;;;;;;;;;;;;;;;;;;;;;;;;GAwBG;AACH,qBAAa,mBACX,YAAW,oBAAoB,EAAE,sBAAsB,EAAE,gBAAgB;IAmBvE,OAAO,CAAC,QAAQ,CAAC,QAAQ;IAjB3B;oEACgE;IAChE,MAAM,CAAC,QAAQ,CAAC,YAAY,EAAE,kBAAkB,CAI9C;IAEF,QAAQ,CAAC,MAAM,uBAAuB;IACtC,QAAQ,CAAC,YAAY,qBAAoC;IAEzD,OAAO,CAAC,QAAQ,CAAC,OAAO,CAA0B;IAClD,OAAO,CAAC,QAAQ,CAAC,MAAM,CAAS;IAChC,OAAO,CAAC,QAAQ,CAAC,aAAa,CAAW;IACzC,OAAO,CAAC,QAAQ,CAAC,aAAa,CAAU;gBAGrB,QAAQ,GAAE,eAA8C;IAQrE,QAAQ,CAAC,GAAG,EAAE,qBAAqB,GAAG,OAAO,CAAC,kBAAkB,CAAC;IA4BjE,WAAW,CAAC,KAAK,EAAE,iBAAiB,GAAG,OAAO,CAAC,kBAAkB,CAAC;IAiClE,aAAa,CACjB,gBAAgB,EAAE,MAAM,EACxB,OAAO,EAAE,aAAa,GACrB,OAAO,CAAC;QAAE,SAAS,EAAE,MAAM,CAAA;KAAE,CAAC;IA2BjC,4EAA4E;IACtE,WAAW,IAAI,OAAO,CAAC,YAAY,EAAE,CAAC;IAgB5C;;;;OAIG;IACG,UAAU,IAAI,OAAO,CAAC,WAAW,EAAE,CAAC;YAM5B,OAAO;YA0BP,gBAAgB;CAiE/B"}
1
+ {"version":3,"file":"tavusAvatarProvider.d.ts","sourceRoot":"","sources":["../../../../src/services/avatarGen/providers/tavusAvatarProvider.ts"],"names":[],"mappings":"AACA,OAAO,EAAE,eAAe,EAAE,MAAM,2BAA2B,CAAC;AAG5D,OAAO,EACL,kBAAkB,EAClB,qBAAqB,EACrB,YAAY,EACZ,iBAAiB,EACjB,kBAAkB,EAClB,kBAAkB,EAClB,aAAa,EACb,mBAAmB,EACnB,aAAa,EACb,oBAAoB,EACpB,sBAAsB,EACtB,gBAAgB,EAChB,qBAAqB,EACrB,WAAW,EACZ,MAAM,yBAAyB,CAAC;AAEjC;;;;;;;;;;;;;;;;;;;;;;;;GAwBG;AACH,qBAAa,mBACX,YAAW,oBAAoB,EAAE,sBAAsB,EAAE,gBAAgB;IAmBvE,OAAO,CAAC,QAAQ,CAAC,QAAQ;IAjB3B;oEACgE;IAChE,MAAM,CAAC,QAAQ,CAAC,YAAY,EAAE,kBAAkB,CAI9C;IAEF,QAAQ,CAAC,MAAM,uBAAuB;IACtC,QAAQ,CAAC,YAAY,qBAAoC;IAEzD,OAAO,CAAC,QAAQ,CAAC,OAAO,CAA0B;IAClD,OAAO,CAAC,QAAQ,CAAC,MAAM,CAAS;IAChC,OAAO,CAAC,QAAQ,CAAC,aAAa,CAAW;IACzC,OAAO,CAAC,QAAQ,CAAC,aAAa,CAAU;gBAGrB,QAAQ,GAAE,eAA8C;IAQrE,QAAQ,CAAC,GAAG,EAAE,qBAAqB,GAAG,OAAO,CAAC,kBAAkB,CAAC;IA4BjE,WAAW,CAAC,KAAK,EAAE,iBAAiB,GAAG,OAAO,CAAC,kBAAkB,CAAC;IAiClE,aAAa,CACjB,gBAAgB,EAAE,MAAM,EACxB,OAAO,EAAE,aAAa,GACrB,OAAO,CAAC,mBAAmB,CAAC;IA2BzB,kBAAkB,CAAC,SAAS,EAAE,MAAM,GAAG,OAAO,CAAC,qBAAqB,CAAC;IAsB3E,4EAA4E;IACtE,WAAW,IAAI,OAAO,CAAC,YAAY,EAAE,CAAC;IAgB5C;;;;OAIG;IACG,UAAU,IAAI,OAAO,CAAC,WAAW,EAAE,CAAC;YAM5B,OAAO;YA0BP,gBAAgB;CAiE/B"}
@@ -95,8 +95,25 @@ class TavusAvatarProvider {
95
95
  if (!data?.replica_id) {
96
96
  throw new Error(`Tavus createReplica returned no replica_id: ${JSON.stringify(data)}`);
97
97
  }
98
+ // Tavus bakes consent into the training call itself (consent_video_url
99
+ // above) — no separate out-of-band consent step, unlike HeyGen.
98
100
  return { replicaId: data.replica_id };
99
101
  }
102
+ async checkReplicaStatus(replicaId) {
103
+ // Single-replica GET is not list-wrapped (mirrors /v2/videos/{id} below).
104
+ const data = await this.requestWithRetry(`/v2/replicas/${encodeURIComponent(replicaId)}`, "GET", undefined, this.statusTimeout);
105
+ // Tavus replica status enum: started | completed | error.
106
+ if (data?.status === "completed") {
107
+ return { status: "ready" };
108
+ }
109
+ if (data?.status === "error") {
110
+ return {
111
+ status: "failed",
112
+ errorMessage: data.error_message ?? "Tavus replica training failed",
113
+ };
114
+ }
115
+ return { status: "training" };
116
+ }
100
117
  // ─── ISupportsHostedCatalog ───────────────────────────────────────────────
101
118
  /** For Tavus the catalog of "avatars" is the account's trained replicas. */
102
119
  async listAvatars() {
@@ -1 +1 @@
1
- {"version":3,"file":"planToProject.d.ts","sourceRoot":"","sources":["../../../src/services/editor/planToProject.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAKV,OAAO,EAIR,MAAM,8BAA8B,CAAC;AAEtC,OAAO,KAAK,EAAE,kBAAkB,EAAE,MAAM,uBAAuB,CAAC;AAehE,OAAO,EAAE,QAAQ,EAAE,yBAAyB,EAAE,eAAe,EAAE,MAAM,yBAAyB,CAAC;AAC/F,YAAY,EAAE,kBAAkB,EAAE,kBAAkB,EAAE,MAAM,uBAAuB,CAAC;AAEpF;;;;;;;;;;;;;;;;;;GAkBG;AACH,wBAAgB,aAAa,CAAC,KAAK,EAAE,kBAAkB,GAAG,OAAO,CA6bhE"}
1
+ {"version":3,"file":"planToProject.d.ts","sourceRoot":"","sources":["../../../src/services/editor/planToProject.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAKV,OAAO,EAIR,MAAM,8BAA8B,CAAC;AAEtC,OAAO,KAAK,EAAE,kBAAkB,EAAE,MAAM,uBAAuB,CAAC;AAehE,OAAO,EAAE,QAAQ,EAAE,yBAAyB,EAAE,eAAe,EAAE,MAAM,yBAAyB,CAAC;AAC/F,YAAY,EAAE,kBAAkB,EAAE,kBAAkB,EAAE,MAAM,uBAAuB,CAAC;AAOpF;;;;;;;;;;;;;;;;;;GAkBG;AACH,wBAAgB,aAAa,CAAC,KAAK,EAAE,kBAAkB,GAAG,OAAO,CAsdhE"}
@@ -11,6 +11,10 @@ var planToProject_helpers_2 = require("./planToProject.helpers");
11
11
  Object.defineProperty(exports, "TRACK_ID", { enumerable: true, get: function () { return planToProject_helpers_2.TRACK_ID; } });
12
12
  Object.defineProperty(exports, "buildOverlayClipsForScene", { enumerable: true, get: function () { return planToProject_helpers_2.buildOverlayClipsForScene; } });
13
13
  Object.defineProperty(exports, "PLACEHOLDER_URL", { enumerable: true, get: function () { return planToProject_helpers_2.PLACEHOLDER_URL; } });
14
+ // Reach per-recipient website-screenshot opening scene (see plan.websiteScreenshotUrl
15
+ // below) — a fixed-length title-card scene, long enough to register as a distinct
16
+ // beat but short enough not to delay the pitch.
17
+ const WEBSITE_OPENING_SCENE_DURATION_MS = 3000;
14
18
  /**
15
19
  * planToProject — pure translator from an approved VideoPlan + per-scene
16
20
  * executor outcomes into the canonical Project IR. The Project is what gets
@@ -40,12 +44,36 @@ function planToProject(input) {
40
44
  // Walk scenes in order; build clips per kind and accumulate offset.
41
45
  const clips = [];
42
46
  const transitions = [];
43
- let offsetMs = 0;
44
47
  let prevVisualClipId = null;
45
48
  let hasVoiceover = false;
46
49
  let hasOverlays = false;
47
50
  let hasCaptions = false;
48
51
  let hasBroll = false;
52
+ // Reach per-recipient website screenshot — a genuine LEADING scene (its own
53
+ // time slice on the main visual track), not a spanning overlay like the logo
54
+ // below. Only emitted when the outreach fan-out injected
55
+ // plan.websiteScreenshotUrl (the planner never sets it); every other scene's
56
+ // display.from/to shifts automatically since offsetMs starts past it.
57
+ let offsetMs = 0;
58
+ if (plan.websiteScreenshotUrl) {
59
+ const openingClip = {
60
+ id: "website-opening",
61
+ trackId: planToProject_helpers_1.TRACK_ID.visual,
62
+ type: "image",
63
+ display: { from: 0, to: WEBSITE_OPENING_SCENE_DURATION_MS },
64
+ name: "Website",
65
+ src: plan.websiteScreenshotUrl,
66
+ fit: "cover",
67
+ provenance: { tier: "T0", source: "website-screenshot", creditsSpent: 0 },
68
+ effects: [],
69
+ transform: { x: 0, y: 0, scaleX: 1, scaleY: 1, rotation: 0, opacity: 1 },
70
+ locked: false,
71
+ metadata: { websiteOpening: true },
72
+ };
73
+ clips.push(openingClip);
74
+ prevVisualClipId = openingClip.id;
75
+ offsetMs = WEBSITE_OPENING_SCENE_DURATION_MS;
76
+ }
49
77
  const sortedScenes = [...plan.scenes].sort((a, b) => a.sceneIndex - b.sceneIndex);
50
78
  for (const scene of sortedScenes) {
51
79
  const outcome = outcomes[scene.sceneIndex];
@@ -18,6 +18,7 @@ import { IVideoQaJobModel } from "../models/videoQaJob.model";
18
18
  import { IGithubConnectionModel } from "../models/githubConnection.model";
19
19
  import { IProductConnectionModel } from "../models/productConnection.model";
20
20
  import { IOutreachCampaignModel, IOutreachRecipientModel, IOutreachTemplateModel, IPersonalizedVideoModel, IVideoViewModel } from "../models/outreach.model";
21
+ import { IApiKeyModel, IWebhookSubscriptionModel } from "../models/outreachIntegration.model";
21
22
  import { IOrganizationCreditLedgerEntry, IOrganizationInviteModel, IOrganizationMemberModel, IOrganizationModel } from "../models/organization.model";
22
23
  /**
23
24
  * FirestoreService
@@ -83,6 +84,8 @@ export declare class FirestoreService {
83
84
  static outreachCampaignsCol: CollectionReference<IOutreachCampaignModel, DocumentData>;
84
85
  static outreachRecipientsCol: CollectionReference<IOutreachRecipientModel, DocumentData>;
85
86
  static videoViewsCol: CollectionReference<IVideoViewModel, DocumentData>;
87
+ static apiKeysCol: CollectionReference<IApiKeyModel, DocumentData>;
88
+ static webhookSubscriptionsCol: CollectionReference<IWebhookSubscriptionModel, DocumentData>;
86
89
  static organizationsCol: CollectionReference<IOrganizationModel, DocumentData>;
87
90
  static organizationMembersCol: CollectionReference<IOrganizationMemberModel, DocumentData>;
88
91
  static organizationInvitesCol: CollectionReference<IOrganizationInviteModel, DocumentData>;
@@ -1 +1 @@
1
- {"version":3,"file":"firestore.service.d.ts","sourceRoot":"","sources":["../../src/services/firestore.service.ts"],"names":[],"mappings":"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"}
1
+ {"version":3,"file":"firestore.service.d.ts","sourceRoot":"","sources":["../../src/services/firestore.service.ts"],"names":[],"mappings":"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"}
@@ -220,6 +220,13 @@ FirestoreService.outreachRecipientsCol = firebase_1.firestore
220
220
  FirestoreService.videoViewsCol = firebase_1.firestore
221
221
  .collection("videoViews")
222
222
  .withConverter(collectionConverter());
223
+ // Reach Phase 7 — self-serve API integration
224
+ FirestoreService.apiKeysCol = firebase_1.firestore
225
+ .collection("apiKeys")
226
+ .withConverter(collectionConverter());
227
+ FirestoreService.webhookSubscriptionsCol = firebase_1.firestore
228
+ .collection("webhookSubscriptions")
229
+ .withConverter(collectionConverter());
223
230
  // Enterprise: Organizations & Team Members
224
231
  FirestoreService.organizationsCol = firebase_1.firestore
225
232
  .collection("organizations")
@@ -1 +1 @@
1
- {"version":3,"file":"uploadAudioBuffer.d.ts","sourceRoot":"","sources":["../../../src/services/gcp/uploadAudioBuffer.ts"],"names":[],"mappings":"AAGA;;;;;;;;;;GAUG;AACH,wBAAsB,sBAAsB,CAC1C,MAAM,EAAE,MAAM,EACd,WAAW,EAAE,MAAM,EACnB,WAAW,GAAE,MAAqB,GACjC,OAAO,CAAC,MAAM,CAAC,CAWjB"}
1
+ {"version":3,"file":"uploadAudioBuffer.d.ts","sourceRoot":"","sources":["../../../src/services/gcp/uploadAudioBuffer.ts"],"names":[],"mappings":"AAIA;;;;;;;;;;GAUG;AACH,wBAAsB,sBAAsB,CAC1C,MAAM,EAAE,MAAM,EACd,WAAW,EAAE,MAAM,EACnB,WAAW,GAAE,MAAqB,GACjC,OAAO,CAAC,MAAM,CAAC,CAcjB"}
@@ -3,6 +3,7 @@ Object.defineProperty(exports, "__esModule", { value: true });
3
3
  exports.uploadAudioBufferToGcs = uploadAudioBufferToGcs;
4
4
  const node_crypto_1 = require("node:crypto");
5
5
  const firebase_1 = require("../../libs/firebase");
6
+ const storage_1 = require("../../libs/storage");
6
7
  /**
7
8
  * Uploads an audio buffer to the project's Firebase Storage bucket and
8
9
  * returns a public download URL. Used by the agent VO pipeline: ElevenLabs
@@ -24,5 +25,8 @@ async function uploadAudioBufferToGcs(buffer, destination, contentType = "audio/
24
25
  metadata: { firebaseStorageDownloadTokens: downloadToken },
25
26
  },
26
27
  });
28
+ // mediaStorage: best-effort R2 mirror (zero-egress delivery). GCS keeps the
29
+ // firebaseStorage download-token URL as the stored system-of-record URL.
30
+ await storage_1.mediaStorage.mirrorBytes(destination, buffer, contentType);
27
31
  return `https://firebasestorage.googleapis.com/v0/b/${bucket.name}/o/${encodeURIComponent(destination)}?alt=media&token=${downloadToken}`;
28
32
  }
@@ -5,6 +5,7 @@ export * from "./firestore.service";
5
5
  export * from "./aiGen";
6
6
  export * from "./avatarGen";
7
7
  export * from "./bullmq.service";
8
+ export * from "./outreachWebhooks.service";
8
9
  export * from "./gcp";
9
10
  export * from "./credit.service";
10
11
  export * from "./notification.service";
@@ -1 +1 @@
1
- {"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../src/services/index.ts"],"names":[],"mappings":"AAAA,cAAc,iBAAiB,CAAC;AAChC,cAAc,gBAAgB,CAAC;AAC/B,cAAc,eAAe,CAAC;AAC9B,cAAc,qBAAqB,CAAC;AACpC,cAAc,SAAS,CAAC;AACxB,cAAc,aAAa,CAAC;AAC5B,cAAc,kBAAkB,CAAC;AACjC,cAAc,OAAO,CAAC;AACtB,cAAc,kBAAkB,CAAC;AACjC,cAAc,wBAAwB,CAAC;AACvC,cAAc,mBAAmB,CAAC;AAClC,cAAc,qCAAqC,CAAC;AACpD,cAAc,qBAAqB,CAAC;AACpC,cAAc,OAAO,CAAC;AACtB,cAAc,eAAe,CAAC;AAC9B,cAAc,YAAY,CAAC;AAC3B,cAAc,iBAAiB,CAAC;AAChC,cAAc,OAAO,CAAC;AACtB,cAAc,SAAS,CAAC;AACxB,cAAc,QAAQ,CAAC;AACvB,cAAc,kBAAkB,CAAC;AACjC,cAAc,sBAAsB,CAAC;AACrC,cAAc,2BAA2B,CAAC;AAC1C,cAAc,0BAA0B,CAAC;AACzC,cAAc,0BAA0B,CAAC;AACzC,cAAc,wBAAwB,CAAC;AACvC,cAAc,2BAA2B,CAAC;AAC1C,cAAc,SAAS,CAAC;AACxB,cAAc,UAAU,CAAC;AACzB,cAAc,eAAe,CAAC;AAC9B,cAAc,iBAAiB,CAAC;AAChC,cAAc,iBAAiB,CAAC;AAChC,cAAc,gBAAgB,CAAC;AAC/B,cAAc,gBAAgB,CAAC;AAC/B,cAAc,YAAY,CAAC;AAC3B,cAAc,kBAAkB,CAAC;AACjC,cAAc,kBAAkB,CAAC;AACjC,cAAc,YAAY,CAAC;AAC3B,cAAc,8BAA8B,CAAC;AAC7C,cAAc,SAAS,CAAC"}
1
+ {"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../src/services/index.ts"],"names":[],"mappings":"AAAA,cAAc,iBAAiB,CAAC;AAChC,cAAc,gBAAgB,CAAC;AAC/B,cAAc,eAAe,CAAC;AAC9B,cAAc,qBAAqB,CAAC;AACpC,cAAc,SAAS,CAAC;AACxB,cAAc,aAAa,CAAC;AAC5B,cAAc,kBAAkB,CAAC;AACjC,cAAc,4BAA4B,CAAC;AAC3C,cAAc,OAAO,CAAC;AACtB,cAAc,kBAAkB,CAAC;AACjC,cAAc,wBAAwB,CAAC;AACvC,cAAc,mBAAmB,CAAC;AAClC,cAAc,qCAAqC,CAAC;AACpD,cAAc,qBAAqB,CAAC;AACpC,cAAc,OAAO,CAAC;AACtB,cAAc,eAAe,CAAC;AAC9B,cAAc,YAAY,CAAC;AAC3B,cAAc,iBAAiB,CAAC;AAChC,cAAc,OAAO,CAAC;AACtB,cAAc,SAAS,CAAC;AACxB,cAAc,QAAQ,CAAC;AACvB,cAAc,kBAAkB,CAAC;AACjC,cAAc,sBAAsB,CAAC;AACrC,cAAc,2BAA2B,CAAC;AAC1C,cAAc,0BAA0B,CAAC;AACzC,cAAc,0BAA0B,CAAC;AACzC,cAAc,wBAAwB,CAAC;AACvC,cAAc,2BAA2B,CAAC;AAC1C,cAAc,SAAS,CAAC;AACxB,cAAc,UAAU,CAAC;AACzB,cAAc,eAAe,CAAC;AAC9B,cAAc,iBAAiB,CAAC;AAChC,cAAc,iBAAiB,CAAC;AAChC,cAAc,gBAAgB,CAAC;AAC/B,cAAc,gBAAgB,CAAC;AAC/B,cAAc,YAAY,CAAC;AAC3B,cAAc,kBAAkB,CAAC;AACjC,cAAc,kBAAkB,CAAC;AACjC,cAAc,YAAY,CAAC;AAC3B,cAAc,8BAA8B,CAAC;AAC7C,cAAc,SAAS,CAAC"}
@@ -21,6 +21,7 @@ __exportStar(require("./firestore.service"), exports);
21
21
  __exportStar(require("./aiGen"), exports);
22
22
  __exportStar(require("./avatarGen"), exports);
23
23
  __exportStar(require("./bullmq.service"), exports);
24
+ __exportStar(require("./outreachWebhooks.service"), exports);
24
25
  __exportStar(require("./gcp"), exports);
25
26
  __exportStar(require("./credit.service"), exports);
26
27
  __exportStar(require("./notification.service"), exports);
@@ -0,0 +1,24 @@
1
+ import { OutreachWebhookEvent } from "../models/outreachIntegration.model";
2
+ /**
3
+ * VidSpot Reach — Phase 7 self-serve API integration. Payload for one
4
+ * webhook-delivery job (one job per active subscriber per event); the worker
5
+ * (apps/node-express-server) owns the signed HTTP POST + BullMQ's own
6
+ * attempts/backoff drive retry.
7
+ */
8
+ export interface WebhookDeliveryJobPayload {
9
+ subscriptionId: string;
10
+ event: OutreachWebhookEvent;
11
+ data: Record<string, unknown>;
12
+ deliveryId: string;
13
+ }
14
+ /**
15
+ * Fan out one webhook-delivery job per ACTIVE subscriber of `event` for
16
+ * `userId`. Best-effort: a lookup/enqueue failure is logged and swallowed so
17
+ * it never blocks the caller's own state transition — campaign completion,
18
+ * video finalization, and view recording all proceed regardless of webhook
19
+ * health. Called from the three Reach event sources: outreachCampaignProcessor
20
+ * / outreachReconcile (campaign.completed, video.ready) and
21
+ * publicOutreach.controller's recordViewEvent (recipient.viewed).
22
+ */
23
+ export declare function dispatchOutreachWebhookEvent(userId: string, event: OutreachWebhookEvent, data: Record<string, unknown>): Promise<void>;
24
+ //# sourceMappingURL=outreachWebhooks.service.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"outreachWebhooks.service.d.ts","sourceRoot":"","sources":["../../src/services/outreachWebhooks.service.ts"],"names":[],"mappings":"AAEA,OAAO,EAAE,oBAAoB,EAAE,MAAM,qCAAqC,CAAC;AAK3E;;;;;GAKG;AACH,MAAM,WAAW,yBAAyB;IACxC,cAAc,EAAE,MAAM,CAAC;IACvB,KAAK,EAAE,oBAAoB,CAAC;IAC5B,IAAI,EAAE,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,CAAC;IAC9B,UAAU,EAAE,MAAM,CAAC;CACpB;AAED;;;;;;;;GAQG;AACH,wBAAsB,4BAA4B,CAChD,MAAM,EAAE,MAAM,EACd,KAAK,EAAE,oBAAoB,EAC3B,IAAI,EAAE,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,GAC5B,OAAO,CAAC,IAAI,CAAC,CA+Bf"}
@@ -0,0 +1,41 @@
1
+ "use strict";
2
+ Object.defineProperty(exports, "__esModule", { value: true });
3
+ exports.dispatchOutreachWebhookEvent = dispatchOutreachWebhookEvent;
4
+ const crypto_1 = require("crypto");
5
+ const types_1 = require("../globals/types");
6
+ const logger_1 = require("../utils/logger");
7
+ const bullmq_service_1 = require("./bullmq.service");
8
+ const firestore_service_1 = require("./firestore.service");
9
+ /**
10
+ * Fan out one webhook-delivery job per ACTIVE subscriber of `event` for
11
+ * `userId`. Best-effort: a lookup/enqueue failure is logged and swallowed so
12
+ * it never blocks the caller's own state transition — campaign completion,
13
+ * video finalization, and view recording all proceed regardless of webhook
14
+ * health. Called from the three Reach event sources: outreachCampaignProcessor
15
+ * / outreachReconcile (campaign.completed, video.ready) and
16
+ * publicOutreach.controller's recordViewEvent (recipient.viewed).
17
+ */
18
+ async function dispatchOutreachWebhookEvent(userId, event, data) {
19
+ try {
20
+ const snap = await firestore_service_1.FirestoreService.webhookSubscriptionsCol
21
+ .where("userId", "==", userId)
22
+ .where("active", "==", true)
23
+ .where("events", "array-contains", event)
24
+ .get();
25
+ if (snap.empty)
26
+ return;
27
+ await Promise.all(snap.docs.map((doc) => bullmq_service_1.bullmq.addJob(types_1.ERedisQueues.WEBHOOK_DELIVERY_JOBS, {
28
+ subscriptionId: doc.id,
29
+ event,
30
+ data,
31
+ deliveryId: (0, crypto_1.randomUUID)(),
32
+ }, { attempts: 5, backoff: { type: "exponential", delay: 5000 } })));
33
+ }
34
+ catch (err) {
35
+ logger_1.logger.warn("dispatchOutreachWebhookEvent: fan-out failed", {
36
+ userId,
37
+ event,
38
+ err: err instanceof Error ? err.message : String(err),
39
+ });
40
+ }
41
+ }