vidspotai-shared 1.0.105 → 1.0.107-dev.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (50) hide show
  1. package/lib/globals/aiModels/enums.d.ts +0 -2
  2. package/lib/globals/aiModels/enums.d.ts.map +1 -1
  3. package/lib/globals/aiModels/enums.js +0 -2
  4. package/lib/globals/aiModels/providers/bytedance.d.ts.map +1 -1
  5. package/lib/globals/aiModels/providers/bytedance.js +4 -89
  6. package/lib/globals/types.d.ts +3 -1
  7. package/lib/globals/types.d.ts.map +1 -1
  8. package/lib/globals/types.js +8 -0
  9. package/lib/models/index.d.ts +1 -0
  10. package/lib/models/index.d.ts.map +1 -1
  11. package/lib/models/index.js +1 -0
  12. package/lib/models/organization.model.d.ts +72 -0
  13. package/lib/models/organization.model.d.ts.map +1 -0
  14. package/lib/models/organization.model.js +6 -0
  15. package/lib/models/user.model.d.ts +12 -0
  16. package/lib/models/user.model.d.ts.map +1 -1
  17. package/lib/models/video.model.d.ts +7 -0
  18. package/lib/models/video.model.d.ts.map +1 -1
  19. package/lib/services/agent/providerFallback/chains.d.ts.map +1 -1
  20. package/lib/services/agent/providerFallback/chains.js +0 -8
  21. package/lib/services/agent/tools/generateVideo.tool.d.ts.map +1 -1
  22. package/lib/services/agent/tools/generateVideo.tool.js +0 -1
  23. package/lib/services/aiGen/aiGenFactory.service.d.ts.map +1 -1
  24. package/lib/services/aiGen/aiGenFactory.service.js +0 -2
  25. package/lib/services/aiGen/providers/bytedance/bytedance.service.d.ts.map +1 -1
  26. package/lib/services/aiGen/providers/bytedance/bytedance.service.js +3 -6
  27. package/lib/services/credit.service.d.ts +4 -2
  28. package/lib/services/credit.service.d.ts.map +1 -1
  29. package/lib/services/credit.service.js +113 -2
  30. package/lib/services/email/index.d.ts +3 -0
  31. package/lib/services/email/index.d.ts.map +1 -0
  32. package/lib/services/email/index.js +18 -0
  33. package/lib/services/email/orgInvite.d.ts +25 -0
  34. package/lib/services/email/orgInvite.d.ts.map +1 -0
  35. package/lib/services/email/orgInvite.js +113 -0
  36. package/lib/services/email/resendClient.d.ts +12 -0
  37. package/lib/services/email/resendClient.d.ts.map +1 -0
  38. package/lib/services/email/resendClient.js +39 -0
  39. package/lib/services/firestore.service.d.ts +5 -0
  40. package/lib/services/firestore.service.d.ts.map +1 -1
  41. package/lib/services/firestore.service.js +13 -0
  42. package/lib/services/index.d.ts +2 -0
  43. package/lib/services/index.d.ts.map +1 -1
  44. package/lib/services/index.js +2 -0
  45. package/lib/services/organizationCredit.service.d.ts +36 -0
  46. package/lib/services/organizationCredit.service.d.ts.map +1 -0
  47. package/lib/services/organizationCredit.service.js +105 -0
  48. package/lib/services/translation/translation.service.d.ts.map +1 -1
  49. package/lib/services/translation/translation.service.js +9 -23
  50. package/package.json +2 -1
@@ -5,6 +5,7 @@ const firestore_1 = require("firebase-admin/firestore");
5
5
  const types_1 = require("../globals/types");
6
6
  const firebase_1 = require("../libs/firebase");
7
7
  const logger_1 = require("../utils/logger");
8
+ const organization_model_1 = require("../models/organization.model");
8
9
  const firestore_service_1 = require("./firestore.service");
9
10
  const notification_service_1 = require("./notification.service");
10
11
  // Once balance drops below this fraction of total, fire CREDITS_LOW. The
@@ -25,6 +26,63 @@ class CreditService {
25
26
  throw new Error("USER_NOT_FOUND");
26
27
  }
27
28
  const data = snap.data();
29
+ // Enterprise Organizations: a member spends from their org's pooled
30
+ // balance instead of their own — transparent to every call site (~30+
31
+ // across controllers/queue-workers/mcp-server all just call
32
+ // consumeCredits(userId, n)). Must live in THIS transaction — Firestore
33
+ // doesn't support nested transactions, so this can't call out to
34
+ // OrganizationCreditService, which owns the separate (non-nested)
35
+ // owner-tops-up-pool transaction.
36
+ const orgId = data.organizationId;
37
+ if (orgId) {
38
+ const orgRef = firestore_service_1.FirestoreService.organizationsCol.doc(orgId);
39
+ const memberRef = firestore_service_1.FirestoreService.organizationMembersCol.doc((0, organization_model_1.organizationMemberDocId)(orgId, userId));
40
+ const [orgSnap, memberSnap] = await Promise.all([
41
+ tx.get(orgRef),
42
+ tx.get(memberRef),
43
+ ]);
44
+ if (!orgSnap.exists)
45
+ throw new Error("ORG_NOT_FOUND");
46
+ if (!memberSnap.exists)
47
+ throw new Error("ORG_MEMBER_NOT_FOUND");
48
+ const orgData = orgSnap.data();
49
+ const orgConsumed = orgData?.credits?.consumed ?? 0;
50
+ const orgTotal = orgData?.credits?.total ?? 0;
51
+ if (orgConsumed + creditsToConsume > orgTotal) {
52
+ throw new Error("ORG_INSUFFICIENT_CREDITS");
53
+ }
54
+ const allocation = memberSnap.data()?.monthlyAllocation;
55
+ if (orgData?.creditMode === "allocated" && allocation) {
56
+ const memberConsumed = allocation.consumed ?? 0;
57
+ if (memberConsumed + creditsToConsume > allocation.total) {
58
+ throw new Error("ORG_MEMBER_ALLOCATION_EXCEEDED");
59
+ }
60
+ tx.update(memberRef, {
61
+ "monthlyAllocation.consumed": memberConsumed + creditsToConsume,
62
+ });
63
+ }
64
+ const newOrgConsumed = orgConsumed + creditsToConsume;
65
+ tx.update(orgRef, { "credits.consumed": newOrgConsumed });
66
+ const ledgerRef = firestore_service_1.FirestoreService.organizationCreditLedgerCol.doc();
67
+ tx.set(ledgerRef, {
68
+ id: ledgerRef.id,
69
+ orgId,
70
+ actorUid: userId,
71
+ delta: -creditsToConsume,
72
+ reason: "consume",
73
+ balanceAfter: orgTotal - newOrgConsumed,
74
+ createdAt: firestore_1.FieldValue.serverTimestamp(),
75
+ });
76
+ // Signal the org path to the caller so the personal CREDITS_LOW flow
77
+ // below is skipped — org-pool-low notifications are a fast-follow.
78
+ return {
79
+ orgSpend: true,
80
+ chargedOrgId: orgId,
81
+ total: 0,
82
+ newRemaining: 0,
83
+ lastNotifiedMs: 0,
84
+ };
85
+ }
28
86
  const consumed = data.credits?.consumed ?? 0;
29
87
  const total = data.credits?.total ?? 0;
30
88
  if (consumed + creditsToConsume > total) {
@@ -35,8 +93,16 @@ class CreditService {
35
93
  });
36
94
  const newRemaining = total - (consumed + creditsToConsume);
37
95
  const lastNotifiedMs = data.lastCreditsLowNotifiedAt?.toMillis?.() ?? 0;
38
- return { total, newRemaining, lastNotifiedMs };
96
+ return {
97
+ orgSpend: false,
98
+ chargedOrgId: null,
99
+ total,
100
+ newRemaining,
101
+ lastNotifiedMs,
102
+ };
39
103
  });
104
+ if (postState.orgSpend)
105
+ return { chargedOrgId: postState.chargedOrgId };
40
106
  const { total, newRemaining, lastNotifiedMs } = postState;
41
107
  if (total > 0 && newRemaining < total * CREDITS_LOW_THRESHOLD) {
42
108
  const sinceLast = Date.now() - lastNotifiedMs;
@@ -62,8 +128,9 @@ class CreditService {
62
128
  });
63
129
  }
64
130
  }
131
+ return { chargedOrgId: postState.chargedOrgId };
65
132
  }
66
- static async refundCredits(userId, creditsToRefund) {
133
+ static async refundCredits(userId, creditsToRefund, spentFromOrgId) {
67
134
  if (creditsToRefund <= 0)
68
135
  return;
69
136
  await firebase_1.firestore.runTransaction(async (tx) => {
@@ -72,6 +139,50 @@ class CreditService {
72
139
  if (!snap.exists) {
73
140
  throw new Error("USER_NOT_FOUND");
74
141
  }
142
+ // `spentFromOrgId` (from the job's `spentFrom` snapshot) takes priority
143
+ // over the user's *current* organizationId — the active org may have
144
+ // changed between the charge and this refund. Callers with no job-doc
145
+ // concept (older refund sites) omit it and fall back to today's
146
+ // re-derive-from-current-org behavior.
147
+ const orgId = spentFromOrgId ?? snap.data()?.organizationId;
148
+ if (orgId) {
149
+ const orgRef = firestore_service_1.FirestoreService.organizationsCol.doc(orgId);
150
+ const memberRef = firestore_service_1.FirestoreService.organizationMembersCol.doc((0, organization_model_1.organizationMemberDocId)(orgId, userId));
151
+ const [orgSnap, memberSnap] = await Promise.all([
152
+ tx.get(orgRef),
153
+ tx.get(memberRef),
154
+ ]);
155
+ // Org/membership may have been deleted since the charge — swallow
156
+ // like the personal path's own "can't go below 0" clamp; there's
157
+ // nowhere left to refund to.
158
+ if (!orgSnap.exists)
159
+ return;
160
+ const orgData = orgSnap.data();
161
+ const orgConsumed = orgData?.credits?.consumed ?? 0;
162
+ const orgTotal = orgData?.credits?.total ?? 0;
163
+ const newOrgConsumed = Math.max(0, orgConsumed - creditsToRefund);
164
+ tx.update(orgRef, { "credits.consumed": newOrgConsumed });
165
+ const allocation = memberSnap.exists
166
+ ? memberSnap.data()?.monthlyAllocation
167
+ : undefined;
168
+ if (orgData?.creditMode === "allocated" && allocation && memberSnap.exists) {
169
+ const newMemberConsumed = Math.max(0, (allocation.consumed ?? 0) - creditsToRefund);
170
+ tx.update(memberRef, {
171
+ "monthlyAllocation.consumed": newMemberConsumed,
172
+ });
173
+ }
174
+ const ledgerRef = firestore_service_1.FirestoreService.organizationCreditLedgerCol.doc();
175
+ tx.set(ledgerRef, {
176
+ id: ledgerRef.id,
177
+ orgId,
178
+ actorUid: userId,
179
+ delta: creditsToRefund,
180
+ reason: "refund",
181
+ balanceAfter: orgTotal - newOrgConsumed,
182
+ createdAt: firestore_1.FieldValue.serverTimestamp(),
183
+ });
184
+ return;
185
+ }
75
186
  const consumed = snap.data()?.credits?.consumed ?? 0;
76
187
  // Never let consumed go below 0
77
188
  const newConsumed = Math.max(0, consumed - creditsToRefund);
@@ -0,0 +1,3 @@
1
+ export * from "./resendClient";
2
+ export * from "./orgInvite";
3
+ //# sourceMappingURL=index.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../../src/services/email/index.ts"],"names":[],"mappings":"AAAA,cAAc,gBAAgB,CAAC;AAC/B,cAAc,aAAa,CAAC"}
@@ -0,0 +1,18 @@
1
+ "use strict";
2
+ var __createBinding = (this && this.__createBinding) || (Object.create ? (function(o, m, k, k2) {
3
+ if (k2 === undefined) k2 = k;
4
+ var desc = Object.getOwnPropertyDescriptor(m, k);
5
+ if (!desc || ("get" in desc ? !m.__esModule : desc.writable || desc.configurable)) {
6
+ desc = { enumerable: true, get: function() { return m[k]; } };
7
+ }
8
+ Object.defineProperty(o, k2, desc);
9
+ }) : (function(o, m, k, k2) {
10
+ if (k2 === undefined) k2 = k;
11
+ o[k2] = m[k];
12
+ }));
13
+ var __exportStar = (this && this.__exportStar) || function(m, exports) {
14
+ for (var p in m) if (p !== "default" && !Object.prototype.hasOwnProperty.call(exports, p)) __createBinding(exports, m, p);
15
+ };
16
+ Object.defineProperty(exports, "__esModule", { value: true });
17
+ __exportStar(require("./resendClient"), exports);
18
+ __exportStar(require("./orgInvite"), exports);
@@ -0,0 +1,25 @@
1
+ import { TOrgRole } from "../../models/organization.model";
2
+ export interface SendOrgInviteEmailInput {
3
+ /** Invitee's email address. */
4
+ to: string;
5
+ orgName: string;
6
+ /** Display name (or email, if no name set) of the org member sending the invite. */
7
+ inviterName: string;
8
+ role: TOrgRole;
9
+ /** Full accept-invite URL, e.g. `${FRONTEND_URL}/invite/${token}`. */
10
+ acceptUrl: string;
11
+ }
12
+ export interface SendOrgInviteEmailResult {
13
+ /** Resend message id. */
14
+ id: string;
15
+ }
16
+ /**
17
+ * Sends the org-invite email via Resend. Throws on misconfiguration or a
18
+ * Resend-reported failure — this is intentional: callers that want
19
+ * best-effort semantics (the invite doc + copyable link are already the
20
+ * source of truth) should call this WITHOUT awaiting and chain `.catch()` to
21
+ * log rather than fail the parent request. See
22
+ * `organization.controller.ts#createInvite`.
23
+ */
24
+ export declare function sendOrgInviteEmail(input: SendOrgInviteEmailInput): Promise<SendOrgInviteEmailResult>;
25
+ //# sourceMappingURL=orgInvite.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"orgInvite.d.ts","sourceRoot":"","sources":["../../../src/services/email/orgInvite.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,QAAQ,EAAE,MAAM,iCAAiC,CAAC;AAM3D,MAAM,WAAW,uBAAuB;IACtC,+BAA+B;IAC/B,EAAE,EAAE,MAAM,CAAC;IACX,OAAO,EAAE,MAAM,CAAC;IAChB,oFAAoF;IACpF,WAAW,EAAE,MAAM,CAAC;IACpB,IAAI,EAAE,QAAQ,CAAC;IACf,sEAAsE;IACtE,SAAS,EAAE,MAAM,CAAC;CACnB;AAED,MAAM,WAAW,wBAAwB;IACvC,yBAAyB;IACzB,EAAE,EAAE,MAAM,CAAC;CACZ;AAiFD;;;;;;;GAOG;AACH,wBAAsB,kBAAkB,CACtC,KAAK,EAAE,uBAAuB,GAC7B,OAAO,CAAC,wBAAwB,CAAC,CA2BnC"}
@@ -0,0 +1,113 @@
1
+ "use strict";
2
+ Object.defineProperty(exports, "__esModule", { value: true });
3
+ exports.sendOrgInviteEmail = sendOrgInviteEmail;
4
+ const logger_1 = require("../../utils/logger");
5
+ const resendClient_1 = require("./resendClient");
6
+ const log = (0, logger_1.createLogger)("email:orgInvite");
7
+ const ROLE_LABEL = {
8
+ owner: "Owner",
9
+ admin: "Admin",
10
+ member: "Member",
11
+ };
12
+ /** Minimal HTML-escaping for the handful of user-controlled strings we interpolate. */
13
+ function esc(s) {
14
+ return s
15
+ .replace(/&/g, "&amp;")
16
+ .replace(/</g, "&lt;")
17
+ .replace(/>/g, "&gt;")
18
+ .replace(/"/g, "&quot;")
19
+ .replace(/'/g, "&#39;");
20
+ }
21
+ function renderHtml(input) {
22
+ const orgName = esc(input.orgName);
23
+ const inviterName = esc(input.inviterName);
24
+ const roleLabel = ROLE_LABEL[input.role] ?? input.role;
25
+ const acceptUrl = esc(input.acceptUrl);
26
+ // Inline styles only — email clients don't reliably support external/embedded CSS.
27
+ return `<!doctype html>
28
+ <html>
29
+ <body style="margin:0;padding:0;background-color:#f4f4f7;font-family:-apple-system,BlinkMacSystemFont,'Segoe UI',Roboto,Helvetica,Arial,sans-serif;">
30
+ <table role="presentation" width="100%" cellpadding="0" cellspacing="0" style="background-color:#f4f4f7;padding:32px 16px;">
31
+ <tr>
32
+ <td align="center">
33
+ <table role="presentation" width="480" cellpadding="0" cellspacing="0" style="max-width:480px;width:100%;background-color:#ffffff;border-radius:12px;overflow:hidden;border:1px solid #e5e5ea;">
34
+ <tr>
35
+ <td style="padding:32px 32px 24px 32px;text-align:center;">
36
+ <div style="font-size:20px;font-weight:700;color:#111114;">VidSpotAI</div>
37
+ </td>
38
+ </tr>
39
+ <tr>
40
+ <td style="padding:0 32px 8px 32px;">
41
+ <h1 style="margin:0 0 16px 0;font-size:18px;line-height:1.4;color:#111114;">
42
+ ${inviterName} invited you to join <strong>${orgName}</strong>
43
+ </h1>
44
+ <p style="margin:0 0 24px 0;font-size:14px;line-height:1.6;color:#52525b;">
45
+ You've been invited to join the <strong>${orgName}</strong> team on VidSpotAI as
46
+ a <strong>${esc(roleLabel)}</strong>. Accept the invite to start collaborating
47
+ on AI-generated video projects together.
48
+ </p>
49
+ </td>
50
+ </tr>
51
+ <tr>
52
+ <td style="padding:0 32px 32px 32px;text-align:center;">
53
+ <a href="${acceptUrl}"
54
+ style="display:inline-block;background:linear-gradient(90deg,#6366f1,#a855f7,#ec4899);color:#ffffff;text-decoration:none;font-size:14px;font-weight:600;padding:12px 28px;border-radius:8px;">
55
+ Accept invite
56
+ </a>
57
+ </td>
58
+ </tr>
59
+ <tr>
60
+ <td style="padding:0 32px 32px 32px;">
61
+ <p style="margin:0;font-size:12px;line-height:1.6;color:#a1a1aa;">
62
+ If the button doesn't work, copy and paste this link into your browser:<br />
63
+ <a href="${acceptUrl}" style="color:#6366f1;word-break:break-all;">${acceptUrl}</a>
64
+ </p>
65
+ </td>
66
+ </tr>
67
+ <tr>
68
+ <td style="padding:20px 32px;background-color:#fafafa;border-top:1px solid #e5e5ea;">
69
+ <p style="margin:0;font-size:11px;line-height:1.5;color:#a1a1aa;">
70
+ This invite expires in 14 days. If you weren't expecting this, you can safely
71
+ ignore this email.
72
+ </p>
73
+ </td>
74
+ </tr>
75
+ </table>
76
+ </td>
77
+ </tr>
78
+ </table>
79
+ </body>
80
+ </html>`;
81
+ }
82
+ /**
83
+ * Sends the org-invite email via Resend. Throws on misconfiguration or a
84
+ * Resend-reported failure — this is intentional: callers that want
85
+ * best-effort semantics (the invite doc + copyable link are already the
86
+ * source of truth) should call this WITHOUT awaiting and chain `.catch()` to
87
+ * log rather than fail the parent request. See
88
+ * `organization.controller.ts#createInvite`.
89
+ */
90
+ async function sendOrgInviteEmail(input) {
91
+ if (!(0, resendClient_1.isResendConfigured)()) {
92
+ throw new Error("sendOrgInviteEmail: RESEND_API_KEY not set");
93
+ }
94
+ const resend = (0, resendClient_1.getResendClient)();
95
+ const subject = `${input.inviterName} invited you to join ${input.orgName} on VidSpotAI`;
96
+ const { data, error } = await resend.emails.send({
97
+ from: resendClient_1.EMAIL_FROM,
98
+ to: input.to,
99
+ subject,
100
+ html: renderHtml(input),
101
+ });
102
+ if (error || !data?.id) {
103
+ const detail = error?.message ?? "no message id returned";
104
+ throw new Error(`sendOrgInviteEmail: Resend send failed — ${detail}`);
105
+ }
106
+ log.info("sendOrgInviteEmail sent", {
107
+ to: input.to,
108
+ orgName: input.orgName,
109
+ role: input.role,
110
+ id: data.id,
111
+ });
112
+ return { id: data.id };
113
+ }
@@ -0,0 +1,12 @@
1
+ import { Resend } from "resend";
2
+ /** True once RESEND_API_KEY is configured. Gate email-sending on this. */
3
+ export declare function isResendConfigured(): boolean;
4
+ /** Lazily-constructed singleton Resend client. Throws if not configured. */
5
+ export declare function getResendClient(): Resend;
6
+ /**
7
+ * Verified sending domain (DKIM/SPF confirmed in Resend for vidspotai.com).
8
+ * Keep the display name generic — individual senders can override the
9
+ * subject/body per email type.
10
+ */
11
+ export declare const EMAIL_FROM = "VidSpotAI <noreply@vidspotai.com>";
12
+ //# sourceMappingURL=resendClient.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"resendClient.d.ts","sourceRoot":"","sources":["../../../src/services/email/resendClient.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,MAAM,EAAE,MAAM,QAAQ,CAAC;AAgBhC,0EAA0E;AAC1E,wBAAgB,kBAAkB,IAAI,OAAO,CAE5C;AAED,4EAA4E;AAC5E,wBAAgB,eAAe,IAAI,MAAM,CASxC;AAED;;;;GAIG;AACH,eAAO,MAAM,UAAU,sCAAsC,CAAC"}
@@ -0,0 +1,39 @@
1
+ "use strict";
2
+ Object.defineProperty(exports, "__esModule", { value: true });
3
+ exports.EMAIL_FROM = void 0;
4
+ exports.isResendConfigured = isResendConfigured;
5
+ exports.getResendClient = getResendClient;
6
+ const resend_1 = require("resend");
7
+ /**
8
+ * Thin Resend client wrapper. Mirrors the other single-provider wrappers in
9
+ * this codebase (e.g. `services/demo/githubOAuth.ts`): a lazy singleton keyed
10
+ * off an env var, a `isXConfigured()` gate the caller can check before doing
11
+ * real work, and a getter that throws a descriptive error instead of letting
12
+ * the SDK fail on `undefined`.
13
+ *
14
+ * Env:
15
+ * RESEND_API_KEY — Resend API key (Doppler `vidspotai-backend` / `dev`
16
+ * config only for now; NOT set in `prd`).
17
+ */
18
+ let client = null;
19
+ /** True once RESEND_API_KEY is configured. Gate email-sending on this. */
20
+ function isResendConfigured() {
21
+ return Boolean(process.env.RESEND_API_KEY);
22
+ }
23
+ /** Lazily-constructed singleton Resend client. Throws if not configured. */
24
+ function getResendClient() {
25
+ const apiKey = process.env.RESEND_API_KEY;
26
+ if (!apiKey) {
27
+ throw new Error("resend: RESEND_API_KEY not set");
28
+ }
29
+ if (!client) {
30
+ client = new resend_1.Resend(apiKey);
31
+ }
32
+ return client;
33
+ }
34
+ /**
35
+ * Verified sending domain (DKIM/SPF confirmed in Resend for vidspotai.com).
36
+ * Keep the display name generic — individual senders can override the
37
+ * subject/body per email type.
38
+ */
39
+ exports.EMAIL_FROM = "VidSpotAI <noreply@vidspotai.com>";
@@ -17,6 +17,7 @@ import { IVideoQaJobModel } from "../models/videoQaJob.model";
17
17
  import { IGithubConnectionModel } from "../models/githubConnection.model";
18
18
  import { IProductConnectionModel } from "../models/productConnection.model";
19
19
  import { IOutreachCampaignModel, IOutreachRecipientModel, IOutreachTemplateModel, IPersonalizedVideoModel, IVideoViewModel } from "../models/outreach.model";
20
+ import { IOrganizationCreditLedgerEntry, IOrganizationInviteModel, IOrganizationMemberModel, IOrganizationModel } from "../models/organization.model";
20
21
  /**
21
22
  * FirestoreService
22
23
  * ----------------
@@ -80,6 +81,10 @@ export declare class FirestoreService {
80
81
  static outreachCampaignsCol: CollectionReference<IOutreachCampaignModel, DocumentData>;
81
82
  static outreachRecipientsCol: CollectionReference<IOutreachRecipientModel, DocumentData>;
82
83
  static videoViewsCol: CollectionReference<IVideoViewModel, DocumentData>;
84
+ static organizationsCol: CollectionReference<IOrganizationModel, DocumentData>;
85
+ static organizationMembersCol: CollectionReference<IOrganizationMemberModel, DocumentData>;
86
+ static organizationInvitesCol: CollectionReference<IOrganizationInviteModel, DocumentData>;
87
+ static organizationCreditLedgerCol: CollectionReference<IOrganizationCreditLedgerEntry, DocumentData>;
83
88
  /**
84
89
  * Sentinel for `.update()` that removes a field from a doc (wraps
85
90
  * `FieldValue.delete()`). Use to clear a transient field — e.g. plan-B's
@@ -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":"AAAA,OAAO,EACL,YAAY,EAEZ,gBAAgB,EAEhB,aAAa,EACd,MAAM,yBAAyB,CAAC;AACjC,OAAO,EACL,mBAAmB,EACnB,iBAAiB,EACjB,UAAU,EAEX,MAAM,0BAA0B,CAAC;AAClC,OAAO,EAAE,WAAW,EAAE,MAAM,kBAAkB,CAAC;AAE/C,OAAO,EACL,kBAAkB,EAClB,cAAc,EACd,cAAc,EACd,iBAAiB,EAClB,MAAM,uBAAuB,CAAC;AAC/B,OAAO,EAAE,iBAAiB,EAAE,MAAM,6BAA6B,CAAC;AAChE,OAAO,EAAE,oBAAoB,EAAE,MAAM,gCAAgC,CAAC;AACtE,OAAO,EAAE,cAAc,EAAE,MAAM,uBAAuB,CAAC;AACvD,OAAO,EAAE,kBAAkB,EAAE,MAAM,8BAA8B,CAAC;AAClE,OAAO,EAAE,SAAS,EAAE,MAAM,qBAAqB,CAAC;AAEhD,OAAO,EAAE,iBAAiB,EAAE,MAAM,6BAA6B,CAAC;AAChE,OAAO,EACL,mBAAmB,EACnB,qBAAqB,EACrB,qBAAqB,EACrB,gBAAgB,EACjB,MAAM,wBAAwB,CAAC;AAChC,OAAO,EAAE,WAAW,EAAE,MAAM,uBAAuB,CAAC;AACpD,OAAO,EAAE,UAAU,EAAE,MAAM,sBAAsB,CAAC;AAClD,OAAO,EAAE,cAAc,EAAE,MAAM,uBAAuB,CAAC;AACvD,OAAO,EAAE,sBAAsB,EAAE,MAAM,kCAAkC,CAAC;AAC1E,OAAO,EAAE,gBAAgB,EAAE,MAAM,4BAA4B,CAAC;AAC9D,OAAO,EAAE,sBAAsB,EAAE,MAAM,kCAAkC,CAAC;AAC1E,OAAO,EAAE,uBAAuB,EAAE,MAAM,mCAAmC,CAAC;AAC5E,OAAO,EACL,sBAAsB,EACtB,uBAAuB,EACvB,sBAAsB,EACtB,uBAAuB,EACvB,eAAe,EAChB,MAAM,0BAA0B,CAAC;AAClC,OAAO,EACL,8BAA8B,EAC9B,wBAAwB,EACxB,wBAAwB,EACxB,kBAAkB,EACnB,MAAM,8BAA8B,CAAC;AAetC;;;;GAIG;AACH,qBAAa,gBAAgB;IAE3B,MAAM,CAAC,YAAY,oDAEqC;IAExD,MAAM,CAAC,YAAY,oDAEqC;IAExD,MAAM,CAAC,gBAAgB,wDAEqC;IAE5D,MAAM,CAAC,OAAO,+CAEqC;IAEnD,MAAM,CAAC,QAAQ,gDAEqC;IAEpD,MAAM,CAAC,UAAU;;;;;;;;;;;;;;;;;;;qBAEqC;IAEtD,MAAM,CAAC,aAAa,uDAEuC;IAE3D,MAAM,CAAC,gBAAgB,0DAEuC;IAE9D,MAAM,CAAC,YAAY,oDAEqC;IAExD,MAAM,CAAC,cAAc,uDAEsC;IAE3D,MAAM,CAAC,gBAAgB,wDAEqC;IAE5D,MAAM,CAAC,YAAY,oDAEqC;IAExD,MAAM,CAAC,SAAS,iDAEqC;IAErD,MAAM,CAAC,eAAe,uDAEqC;IAG3D,MAAM,CAAC,oBAAoB,4DAEqC;IAEhE;;;;OAIG;IACH,MAAM,CAAC,cAAc,sDAEqC;IAE1D,8EAA8E;IAC9E,MAAM,CAAC,oBAAoB,4DAEqC;IAEhE;;;;OAIG;IACH,MAAM,CAAC,qBAAqB,6DAEqC;IAGjE,MAAM,CAAC,iBAAiB,yDAEqC;IAE7D,MAAM,CAAC,cAAc,sDAEqC;IAE1D,MAAM,CAAC,kBAAkB,2DAEsC;IAE/D,MAAM,CAAC,cAAc,2DAE0C;IAG/D,MAAM,CAAC,oBAAoB,4DAEqC;IAEhE,MAAM,CAAC,qBAAqB,6DAEqC;IAEjE,MAAM,CAAC,oBAAoB,4DAEqC;IAEhE,MAAM,CAAC,qBAAqB,6DAEqC;IAEjE,MAAM,CAAC,aAAa,qDAEqC;IAGzD,MAAM,CAAC,gBAAgB,wDAEqC;IAE5D,MAAM,CAAC,sBAAsB,8DAEqC;IAElE,MAAM,CAAC,sBAAsB,8DAEqC;IAElE,MAAM,CAAC,2BAA2B,oEAEsC;IAIxE;;;;OAIG;IACH,MAAM,CAAC,WAAW,IAAI,UAAU;IAIhC,yCAAyC;WAC5B,eAAe,CAAC,CAAC,EAC5B,aAAa,EAAE,mBAAmB,CAAC,CAAC,CAAC,EACrC,IAAI,EAAE,CAAC,GACN,OAAO,CAAC,iBAAiB,CAAC,CAAC,CAAC,CAAC;IAMhC,qDAAqD;WACxC,OAAO,CAAC,CAAC,EACpB,aAAa,EAAE,mBAAmB,CAAC,CAAC,CAAC,EACrC,EAAE,EAAE,MAAM,EACV,IAAI,EAAE,CAAC,GACN,OAAO,CAAC,iBAAiB,CAAC,CAAC,CAAC,CAAC;IAMhC,0CAA0C;WAC7B,UAAU,CAAC,CAAC,EACvB,aAAa,EAAE,mBAAmB,CAAC,CAAC,CAAC,GACpC,OAAO,CAAC,CAAC,CAAC,GAAG;QAAE,EAAE,EAAE,MAAM,CAAA;KAAE,CAAC,EAAE,CAAC;IAKlC,kCAAkC;WACrB,WAAW,CAAC,CAAC,EACxB,aAAa,EAAE,mBAAmB,CAAC,CAAC,CAAC,EACrC,EAAE,EAAE,MAAM,GACT,OAAO,CAAC,CAAC,CAAC,GAAG;QAAE,EAAE,EAAE,MAAM,CAAA;KAAE,CAAC,GAAG,SAAS,CAAC;IAO5C,+BAA+B;WAClB,WAAW,CAAC,EAAE,EAAE,MAAM,GAAG,OAAO,CAAC,UAAU,GAAG,SAAS,CAAC;IAIrE,+CAA+C;WAClC,cAAc,CAAC,KAAK,EAAE,MAAM,GAAG,OAAO,CAAC,UAAU,GAAG,SAAS,CAAC;IAS3E,gCAAgC;WACnB,iBAAiB,CAAC,CAAC,SAAS,YAAY,EACnD,aAAa,EAAE,mBAAmB,CAAC,CAAC,CAAC,EACrC,SAAS,EAAE,MAAM,EACjB,QAAQ,EAAE,aAAa,EACvB,KAAK,EAAE,GAAG,EACV,OAAO,CAAC,EAAE;QACR,YAAY,CAAC,EAAE,MAAM,CAAC,GAAG,MAAM,CAAC;QAChC,cAAc,CAAC,EAAE,gBAAgB,CAAC;QAClC,KAAK,CAAC,EAAE,MAAM,CAAC;KAChB,GACA,OAAO,CAAC,CAAC,CAAC,GAAG;QAAE,EAAE,EAAE,MAAM,CAAA;KAAE,CAAC,EAAE,CAAC;IAsBlC,8CAA8C;WACjC,UAAU,CAAC,CAAC,EACvB,aAAa,EAAE,mBAAmB,CAAC,CAAC,CAAC,EACrC,EAAE,EAAE,MAAM,EACV,cAAc,EAAE,WAAW,CAAC,CAAC,CAAC,EAC9B,OAAO,GAAE;QAAE,SAAS,CAAC,EAAE,OAAO,CAAA;KAAwB,GACrD,OAAO,CAAC,IAAI,CAAC;IAWhB,OAAO,CAAC,MAAM,CAAC,aAAa;IA2B5B,0CAA0C;WAC7B,cAAc,CACzB,EAAE,EAAE,MAAM,EACV,cAAc,EAAE,OAAO,CAAC,UAAU,CAAC,GAClC,OAAO,CAAC,IAAI,CAAC;IAIhB,sBAAsB;WACT,UAAU,CAAC,CAAC,EACvB,aAAa,EAAE,mBAAmB,CAAC,CAAC,CAAC,EACrC,EAAE,EAAE,MAAM,GACT,OAAO,CAAC,IAAI,CAAC;IAKhB,kCAAkC;WACrB,cAAc,CAAC,CAAC,EAC3B,OAAO,EAAE,CAAC,EAAE,EAAE,iBAAiB,CAAC,WAAW,KAAK,OAAO,CAAC,CAAC,CAAC,GACzD,OAAO,CAAC,CAAC,CAAC;CAGd"}
@@ -217,3 +217,16 @@ FirestoreService.outreachRecipientsCol = firebase_1.firestore
217
217
  FirestoreService.videoViewsCol = firebase_1.firestore
218
218
  .collection("videoViews")
219
219
  .withConverter(collectionConverter());
220
+ // Enterprise: Organizations & Team Members
221
+ FirestoreService.organizationsCol = firebase_1.firestore
222
+ .collection("organizations")
223
+ .withConverter(collectionConverter());
224
+ FirestoreService.organizationMembersCol = firebase_1.firestore
225
+ .collection("organizationMembers")
226
+ .withConverter(collectionConverter());
227
+ FirestoreService.organizationInvitesCol = firebase_1.firestore
228
+ .collection("organizationInvites")
229
+ .withConverter(collectionConverter());
230
+ FirestoreService.organizationCreditLedgerCol = firebase_1.firestore
231
+ .collection("organizationCreditLedger")
232
+ .withConverter(collectionConverter());
@@ -35,4 +35,6 @@ export * from "./socialAI";
35
35
  export * from "./socialInsights";
36
36
  export * from "./socialAccounts";
37
37
  export * from "./freePlan";
38
+ export * from "./organizationCredit.service";
39
+ export * from "./email";
38
40
  //# sourceMappingURL=index.d.ts.map
@@ -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,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"}
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,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"}
@@ -51,3 +51,5 @@ __exportStar(require("./socialAI"), exports);
51
51
  __exportStar(require("./socialInsights"), exports);
52
52
  __exportStar(require("./socialAccounts"), exports);
53
53
  __exportStar(require("./freePlan"), exports);
54
+ __exportStar(require("./organizationCredit.service"), exports);
55
+ __exportStar(require("./email"), exports);
@@ -0,0 +1,36 @@
1
+ /**
2
+ * Enterprise: Organizations & Team Members — credit-pool funding.
3
+ *
4
+ * Day-to-day spend/refund against the pool happens transparently inside
5
+ * `CreditService.consumeCredits`/`refundCredits` (redirected there when the
6
+ * acting user has `organizationId` set, within the SAME transaction as the
7
+ * personal-credit path would have used — Firestore transactions can't nest,
8
+ * so that logic lives inline in credit.service.ts rather than calling out to
9
+ * this file). This service covers the one op that's genuinely distinct: the
10
+ * owner moving credits FROM their own personal balance INTO the org pool.
11
+ * No new Stripe/seat billing — the pool is funded entirely this way for MVP.
12
+ */
13
+ export declare class OrganizationCreditService {
14
+ /**
15
+ * Owner-only. Reads owner's user doc + the org doc, then in the same
16
+ * transaction: increments the owner's personal `credits.consumed` (spends
17
+ * `amount` of their own remaining balance) and increments the org's
18
+ * `credits.total` (tops up the pool) by the same amount. Throws
19
+ * "INSUFFICIENT_CREDITS" if the owner doesn't have `amount` remaining —
20
+ * reusing the existing personal error code since this is, from the owner's
21
+ * point of view, spending their own balance.
22
+ */
23
+ static transferToOrgPool(orgId: string, ownerUid: string, amount: number): Promise<{
24
+ orgTotal: number;
25
+ orgRemaining: number;
26
+ }>;
27
+ /**
28
+ * Owner/admin-set monthly draw cap for a member (only meaningful once the
29
+ * org's creditMode is "allocated"). Setting `monthlyTotal` to undefined
30
+ * clears the member's allocation (falls back to full-pool access if the org
31
+ * later flips back to "shared", or is simply uncapped within "allocated"
32
+ * mode until set again).
33
+ */
34
+ static setMemberAllocation(orgId: string, memberUid: string, monthlyTotal: number | undefined): Promise<void>;
35
+ }
36
+ //# sourceMappingURL=organizationCredit.service.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"organizationCredit.service.d.ts","sourceRoot":"","sources":["../../src/services/organizationCredit.service.ts"],"names":[],"mappings":"AAKA;;;;;;;;;;;GAWG;AACH,qBAAa,yBAAyB;IACpC;;;;;;;;OAQG;WACU,iBAAiB,CAC5B,KAAK,EAAE,MAAM,EACb,QAAQ,EAAE,MAAM,EAChB,MAAM,EAAE,MAAM,GACb,OAAO,CAAC;QAAE,QAAQ,EAAE,MAAM,CAAC;QAAC,YAAY,EAAE,MAAM,CAAA;KAAE,CAAC;IAqDtD;;;;;;OAMG;WACU,mBAAmB,CAC9B,KAAK,EAAE,MAAM,EACb,SAAS,EAAE,MAAM,EACjB,YAAY,EAAE,MAAM,GAAG,SAAS,GAC/B,OAAO,CAAC,IAAI,CAAC;CA0BjB"}
@@ -0,0 +1,105 @@
1
+ "use strict";
2
+ Object.defineProperty(exports, "__esModule", { value: true });
3
+ exports.OrganizationCreditService = void 0;
4
+ const firestore_1 = require("firebase-admin/firestore");
5
+ const firebase_1 = require("../libs/firebase");
6
+ const organization_model_1 = require("../models/organization.model");
7
+ const firestore_service_1 = require("./firestore.service");
8
+ /**
9
+ * Enterprise: Organizations & Team Members — credit-pool funding.
10
+ *
11
+ * Day-to-day spend/refund against the pool happens transparently inside
12
+ * `CreditService.consumeCredits`/`refundCredits` (redirected there when the
13
+ * acting user has `organizationId` set, within the SAME transaction as the
14
+ * personal-credit path would have used — Firestore transactions can't nest,
15
+ * so that logic lives inline in credit.service.ts rather than calling out to
16
+ * this file). This service covers the one op that's genuinely distinct: the
17
+ * owner moving credits FROM their own personal balance INTO the org pool.
18
+ * No new Stripe/seat billing — the pool is funded entirely this way for MVP.
19
+ */
20
+ class OrganizationCreditService {
21
+ /**
22
+ * Owner-only. Reads owner's user doc + the org doc, then in the same
23
+ * transaction: increments the owner's personal `credits.consumed` (spends
24
+ * `amount` of their own remaining balance) and increments the org's
25
+ * `credits.total` (tops up the pool) by the same amount. Throws
26
+ * "INSUFFICIENT_CREDITS" if the owner doesn't have `amount` remaining —
27
+ * reusing the existing personal error code since this is, from the owner's
28
+ * point of view, spending their own balance.
29
+ */
30
+ static async transferToOrgPool(orgId, ownerUid, amount) {
31
+ if (!Number.isFinite(amount) || amount <= 0) {
32
+ throw new Error("INVALID_AMOUNT");
33
+ }
34
+ return firebase_1.firestore.runTransaction(async (tx) => {
35
+ const userRef = firestore_service_1.FirestoreService.usersCol.doc(ownerUid);
36
+ const orgRef = firestore_service_1.FirestoreService.organizationsCol.doc(orgId);
37
+ // All reads before any writes (Firestore transaction requirement).
38
+ const [userSnap, orgSnap] = await Promise.all([
39
+ tx.get(userRef),
40
+ tx.get(orgRef),
41
+ ]);
42
+ if (!userSnap.exists)
43
+ throw new Error("USER_NOT_FOUND");
44
+ if (!orgSnap.exists)
45
+ throw new Error("ORG_NOT_FOUND");
46
+ const userData = userSnap.data();
47
+ const orgData = orgSnap.data();
48
+ if (orgData?.ownerId !== ownerUid) {
49
+ throw new Error("ORG_NOT_OWNER");
50
+ }
51
+ const userConsumed = userData?.credits?.consumed ?? 0;
52
+ const userTotal = userData?.credits?.total ?? 0;
53
+ if (userConsumed + amount > userTotal) {
54
+ throw new Error("INSUFFICIENT_CREDITS");
55
+ }
56
+ const orgConsumed = orgData?.credits?.consumed ?? 0;
57
+ const orgTotal = orgData?.credits?.total ?? 0;
58
+ const newOrgTotal = orgTotal + amount;
59
+ tx.update(userRef, { "credits.consumed": userConsumed + amount });
60
+ tx.update(orgRef, { "credits.total": newOrgTotal });
61
+ const ledgerRef = firestore_service_1.FirestoreService.organizationCreditLedgerCol.doc();
62
+ tx.set(ledgerRef, {
63
+ id: ledgerRef.id,
64
+ orgId,
65
+ actorUid: ownerUid,
66
+ delta: amount,
67
+ reason: "transfer_in",
68
+ balanceAfter: newOrgTotal - orgConsumed,
69
+ createdAt: firestore_1.FieldValue.serverTimestamp(),
70
+ });
71
+ return { orgTotal: newOrgTotal, orgRemaining: newOrgTotal - orgConsumed };
72
+ });
73
+ }
74
+ /**
75
+ * Owner/admin-set monthly draw cap for a member (only meaningful once the
76
+ * org's creditMode is "allocated"). Setting `monthlyTotal` to undefined
77
+ * clears the member's allocation (falls back to full-pool access if the org
78
+ * later flips back to "shared", or is simply uncapped within "allocated"
79
+ * mode until set again).
80
+ */
81
+ static async setMemberAllocation(orgId, memberUid, monthlyTotal) {
82
+ const memberRef = firestore_service_1.FirestoreService.organizationMembersCol.doc((0, organization_model_1.organizationMemberDocId)(orgId, memberUid));
83
+ const snap = await memberRef.get();
84
+ if (!snap.exists)
85
+ throw new Error("ORG_MEMBER_NOT_FOUND");
86
+ if (monthlyTotal === undefined) {
87
+ await memberRef.update({
88
+ monthlyAllocation: firestore_service_1.FirestoreService.deleteField(),
89
+ });
90
+ return;
91
+ }
92
+ if (!Number.isFinite(monthlyTotal) || monthlyTotal < 0) {
93
+ throw new Error("INVALID_AMOUNT");
94
+ }
95
+ const existing = snap.data()?.monthlyAllocation;
96
+ await memberRef.update({
97
+ monthlyAllocation: {
98
+ total: monthlyTotal,
99
+ consumed: existing?.consumed ?? 0,
100
+ resetAt: existing?.resetAt ?? Date.now() + 30 * 24 * 60 * 60 * 1000,
101
+ },
102
+ });
103
+ }
104
+ }
105
+ exports.OrganizationCreditService = OrganizationCreditService;
@@ -1 +1 @@
1
- {"version":3,"file":"translation.service.d.ts","sourceRoot":"","sources":["../../../src/services/translation/translation.service.ts"],"names":[],"mappings":"AAEA,OAAO,EAAE,cAAc,EAAE,WAAW,EAAE,MAAM,qBAAqB,CAAC;AAGlE;;;;;;;;;;;;;;;;;;;;;;;;;;GA0BG;AAEH,eAAO,MAAM,kBAAkB,uBAAuB,CAAC;AAqGvD;;;;GAIG;AACH,iBAAe,SAAS,CACtB,IAAI,EAAE,MAAM,EACZ,IAAI,EAAE,cAAc,EACpB,EAAE,GAAE,cAAkC,EACtC,OAAO,GAAE,IAAI,GAAG,IAAW,GAC1B,OAAO,CAAC,MAAM,CAAC,CAsCjB;AAiDD;;;;;;;;;;;;;;GAcG;AACH,iBAAe,cAAc,CAAC,IAAI,EAAE,MAAM,GAAG,OAAO,CAAC,WAAW,CAAC,CA8ChE;AAOD,eAAO,MAAM,kBAAkB;;;CAG9B,CAAC;AAGF,qDAAqD;AACrD,eAAO,MAAM,qBAAqB,kBAAY,CAAC;AAC/C,0DAA0D;AAC1D,eAAO,MAAM,UAAU,uBAAiB,CAAC"}
1
+ {"version":3,"file":"translation.service.d.ts","sourceRoot":"","sources":["../../../src/services/translation/translation.service.ts"],"names":[],"mappings":"AAEA,OAAO,EAAE,cAAc,EAAE,WAAW,EAAE,MAAM,qBAAqB,CAAC;AAGlE;;;;;;;;;;;;;;;;;;;;;;;;;;GA0BG;AAEH,eAAO,MAAM,kBAAkB,uBAAuB,CAAC;AAqGvD;;;;GAIG;AACH,iBAAe,SAAS,CACtB,IAAI,EAAE,MAAM,EACZ,IAAI,EAAE,cAAc,EACpB,EAAE,GAAE,cAAkC,EACtC,OAAO,GAAE,IAAI,GAAG,IAAW,GAC1B,OAAO,CAAC,MAAM,CAAC,CAsCjB;AAiCD;;;;;;;;;;;;;;GAcG;AACH,iBAAe,cAAc,CAAC,IAAI,EAAE,MAAM,GAAG,OAAO,CAAC,WAAW,CAAC,CA8ChE;AAOD,eAAO,MAAM,kBAAkB;;;CAG9B,CAAC;AAGF,qDAAqD;AACrD,eAAO,MAAM,qBAAqB,kBAAY,CAAC;AAC/C,0DAA0D;AAC1D,eAAO,MAAM,UAAU,uBAAiB,CAAC"}