eggi-ai-db-schema-2 0.1.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.
- package/CHANGELOG.md +750 -0
- package/README.md +660 -0
- package/dist/config/database.d.ts +28 -0
- package/dist/config/database.d.ts.map +1 -0
- package/dist/config/database.js +72 -0
- package/dist/config/database.js.map +1 -0
- package/dist/index.d.ts +28 -0
- package/dist/index.d.ts.map +1 -0
- package/dist/index.js +199 -0
- package/dist/index.js.map +1 -0
- package/dist/lib/database-service.d.ts +714 -0
- package/dist/lib/database-service.d.ts.map +1 -0
- package/dist/lib/database-service.js +1394 -0
- package/dist/lib/database-service.js.map +1 -0
- package/dist/lib/db-types.d.ts +167 -0
- package/dist/lib/db-types.d.ts.map +1 -0
- package/dist/lib/db-types.js +28 -0
- package/dist/lib/db-types.js.map +1 -0
- package/dist/lib/db.d.ts +58 -0
- package/dist/lib/db.d.ts.map +1 -0
- package/dist/lib/db.js +292 -0
- package/dist/lib/db.js.map +1 -0
- package/dist/lib/index.d.ts +11 -0
- package/dist/lib/index.d.ts.map +1 -0
- package/dist/lib/index.js +26 -0
- package/dist/lib/index.js.map +1 -0
- package/dist/lib/pg-client.d.ts +50 -0
- package/dist/lib/pg-client.d.ts.map +1 -0
- package/dist/lib/pg-client.js +106 -0
- package/dist/lib/pg-client.js.map +1 -0
- package/dist/lib/schema.d.ts +298 -0
- package/dist/lib/schema.d.ts.map +1 -0
- package/dist/lib/schema.js +12 -0
- package/dist/lib/schema.js.map +1 -0
- package/dist/migration-manager.d.ts +49 -0
- package/dist/migration-manager.d.ts.map +1 -0
- package/dist/migration-manager.js +282 -0
- package/dist/migration-manager.js.map +1 -0
- package/dist/queries/minimal-connections.d.ts +31 -0
- package/dist/queries/minimal-connections.d.ts.map +1 -0
- package/dist/queries/minimal-connections.js +143 -0
- package/dist/queries/minimal-connections.js.map +1 -0
- package/dist/schema.ts +340 -0
- package/dist/seed.d.ts +8 -0
- package/dist/seed.d.ts.map +1 -0
- package/dist/seed.js +40 -0
- package/dist/seed.js.map +1 -0
- package/dist/types/index.d.ts +7 -0
- package/dist/types/index.d.ts.map +1 -0
- package/dist/types/index.js +23 -0
- package/dist/types/index.js.map +1 -0
- package/dist/types/types.d.ts +77 -0
- package/dist/types/types.d.ts.map +1 -0
- package/dist/types/types.js +3 -0
- package/dist/types/types.js.map +1 -0
- package/dist/utils/authenticated-user-operations.d.ts +110 -0
- package/dist/utils/authenticated-user-operations.d.ts.map +1 -0
- package/dist/utils/authenticated-user-operations.js +292 -0
- package/dist/utils/authenticated-user-operations.js.map +1 -0
- package/dist/utils/authentication-operations.d.ts +48 -0
- package/dist/utils/authentication-operations.d.ts.map +1 -0
- package/dist/utils/authentication-operations.js +172 -0
- package/dist/utils/authentication-operations.js.map +1 -0
- package/dist/utils/company-mapping-job-operations.d.ts +103 -0
- package/dist/utils/company-mapping-job-operations.d.ts.map +1 -0
- package/dist/utils/company-mapping-job-operations.js +413 -0
- package/dist/utils/company-mapping-job-operations.js.map +1 -0
- package/dist/utils/company-sheet-upload-operations.d.ts +53 -0
- package/dist/utils/company-sheet-upload-operations.d.ts.map +1 -0
- package/dist/utils/company-sheet-upload-operations.js +135 -0
- package/dist/utils/company-sheet-upload-operations.js.map +1 -0
- package/dist/utils/contact-operations.d.ts +70 -0
- package/dist/utils/contact-operations.d.ts.map +1 -0
- package/dist/utils/contact-operations.js +294 -0
- package/dist/utils/contact-operations.js.map +1 -0
- package/dist/utils/forager-linkedin-operations.d.ts +74 -0
- package/dist/utils/forager-linkedin-operations.d.ts.map +1 -0
- package/dist/utils/forager-linkedin-operations.js +778 -0
- package/dist/utils/forager-linkedin-operations.js.map +1 -0
- package/dist/utils/ghost-genius-linkedin-operations.d.ts +23 -0
- package/dist/utils/ghost-genius-linkedin-operations.d.ts.map +1 -0
- package/dist/utils/ghost-genius-linkedin-operations.js +282 -0
- package/dist/utils/ghost-genius-linkedin-operations.js.map +1 -0
- package/dist/utils/index.d.ts +29 -0
- package/dist/utils/index.d.ts.map +1 -0
- package/dist/utils/index.js +77 -0
- package/dist/utils/index.js.map +1 -0
- package/dist/utils/introduction-request-operations.d.ts +160 -0
- package/dist/utils/introduction-request-operations.d.ts.map +1 -0
- package/dist/utils/introduction-request-operations.js +492 -0
- package/dist/utils/introduction-request-operations.js.map +1 -0
- package/dist/utils/invitation-operations.d.ts +141 -0
- package/dist/utils/invitation-operations.d.ts.map +1 -0
- package/dist/utils/invitation-operations.js +749 -0
- package/dist/utils/invitation-operations.js.map +1 -0
- package/dist/utils/linkedin-account-operations.d.ts +45 -0
- package/dist/utils/linkedin-account-operations.d.ts.map +1 -0
- package/dist/utils/linkedin-account-operations.js +279 -0
- package/dist/utils/linkedin-account-operations.js.map +1 -0
- package/dist/utils/linkedin-account-relationship-operations.d.ts +77 -0
- package/dist/utils/linkedin-account-relationship-operations.d.ts.map +1 -0
- package/dist/utils/linkedin-account-relationship-operations.js +274 -0
- package/dist/utils/linkedin-account-relationship-operations.js.map +1 -0
- package/dist/utils/linkedin-data-operations.d.ts +102 -0
- package/dist/utils/linkedin-data-operations.d.ts.map +1 -0
- package/dist/utils/linkedin-data-operations.js +613 -0
- package/dist/utils/linkedin-data-operations.js.map +1 -0
- package/dist/utils/linkedin-identifier-utils.d.ts +31 -0
- package/dist/utils/linkedin-identifier-utils.d.ts.map +1 -0
- package/dist/utils/linkedin-identifier-utils.js +63 -0
- package/dist/utils/linkedin-identifier-utils.js.map +1 -0
- package/dist/utils/linkedin-profile-cache.d.ts +131 -0
- package/dist/utils/linkedin-profile-cache.d.ts.map +1 -0
- package/dist/utils/linkedin-profile-cache.js +418 -0
- package/dist/utils/linkedin-profile-cache.js.map +1 -0
- package/dist/utils/llm-inference-job-operations.d.ts +116 -0
- package/dist/utils/llm-inference-job-operations.d.ts.map +1 -0
- package/dist/utils/llm-inference-job-operations.js +267 -0
- package/dist/utils/llm-inference-job-operations.js.map +1 -0
- package/dist/utils/mapping-job-operations.d.ts +272 -0
- package/dist/utils/mapping-job-operations.d.ts.map +1 -0
- package/dist/utils/mapping-job-operations.js +833 -0
- package/dist/utils/mapping-job-operations.js.map +1 -0
- package/dist/utils/mapping-operations.d.ts +80 -0
- package/dist/utils/mapping-operations.d.ts.map +1 -0
- package/dist/utils/mapping-operations.js +318 -0
- package/dist/utils/mapping-operations.js.map +1 -0
- package/dist/utils/on-demand-mapping-operations.d.ts +199 -0
- package/dist/utils/on-demand-mapping-operations.d.ts.map +1 -0
- package/dist/utils/on-demand-mapping-operations.js +728 -0
- package/dist/utils/on-demand-mapping-operations.js.map +1 -0
- package/dist/utils/onboarding-operations.d.ts +53 -0
- package/dist/utils/onboarding-operations.d.ts.map +1 -0
- package/dist/utils/onboarding-operations.js +223 -0
- package/dist/utils/onboarding-operations.js.map +1 -0
- package/dist/utils/organization-assignment-job-operations.d.ts +258 -0
- package/dist/utils/organization-assignment-job-operations.d.ts.map +1 -0
- package/dist/utils/organization-assignment-job-operations.js +881 -0
- package/dist/utils/organization-assignment-job-operations.js.map +1 -0
- package/dist/utils/organization-assignment-operations.d.ts +59 -0
- package/dist/utils/organization-assignment-operations.d.ts.map +1 -0
- package/dist/utils/organization-assignment-operations.js +130 -0
- package/dist/utils/organization-assignment-operations.js.map +1 -0
- package/dist/utils/organization-operations.d.ts +284 -0
- package/dist/utils/organization-operations.d.ts.map +1 -0
- package/dist/utils/organization-operations.js +1030 -0
- package/dist/utils/organization-operations.js.map +1 -0
- package/dist/utils/organization-relationship-operations.d.ts +79 -0
- package/dist/utils/organization-relationship-operations.d.ts.map +1 -0
- package/dist/utils/organization-relationship-operations.js +294 -0
- package/dist/utils/organization-relationship-operations.js.map +1 -0
- package/dist/utils/quota-operations.d.ts +107 -0
- package/dist/utils/quota-operations.d.ts.map +1 -0
- package/dist/utils/quota-operations.js +692 -0
- package/dist/utils/quota-operations.js.map +1 -0
- package/dist/utils/recursive-mapping-job-operations.d.ts +42 -0
- package/dist/utils/recursive-mapping-job-operations.d.ts.map +1 -0
- package/dist/utils/recursive-mapping-job-operations.js +169 -0
- package/dist/utils/recursive-mapping-job-operations.js.map +1 -0
- package/dist/utils/relationship-operations.d.ts +130 -0
- package/dist/utils/relationship-operations.d.ts.map +1 -0
- package/dist/utils/relationship-operations.js +329 -0
- package/dist/utils/relationship-operations.js.map +1 -0
- package/dist/utils/sales-pipeline-operations.d.ts +163 -0
- package/dist/utils/sales-pipeline-operations.d.ts.map +1 -0
- package/dist/utils/sales-pipeline-operations.js +725 -0
- package/dist/utils/sales-pipeline-operations.js.map +1 -0
- package/dist/utils/skills-operations.d.ts +117 -0
- package/dist/utils/skills-operations.d.ts.map +1 -0
- package/dist/utils/skills-operations.js +487 -0
- package/dist/utils/skills-operations.js.map +1 -0
- package/dist/utils/subscription-operations.d.ts +123 -0
- package/dist/utils/subscription-operations.d.ts.map +1 -0
- package/dist/utils/subscription-operations.js +391 -0
- package/dist/utils/subscription-operations.js.map +1 -0
- package/dist/utils/unipile-account-operations.d.ts +96 -0
- package/dist/utils/unipile-account-operations.d.ts.map +1 -0
- package/dist/utils/unipile-account-operations.js +255 -0
- package/dist/utils/unipile-account-operations.js.map +1 -0
- package/dist/utils/user-industry-operations.d.ts +80 -0
- package/dist/utils/user-industry-operations.d.ts.map +1 -0
- package/dist/utils/user-industry-operations.js +237 -0
- package/dist/utils/user-industry-operations.js.map +1 -0
- package/dist/utils/user-operations.d.ts +87 -0
- package/dist/utils/user-operations.d.ts.map +1 -0
- package/dist/utils/user-operations.js +212 -0
- package/dist/utils/user-operations.js.map +1 -0
- package/package.json +98 -0
|
@@ -0,0 +1,123 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* =============================================================================
|
|
3
|
+
* SUBSCRIPTION OPERATIONS
|
|
4
|
+
* =============================================================================
|
|
5
|
+
* Database operations for managing Stripe subscriptions
|
|
6
|
+
*
|
|
7
|
+
* This module provides reusable functions for subscription management,
|
|
8
|
+
* ensuring all subscription-related database operations are centralized
|
|
9
|
+
* and reusable across Lambda functions.
|
|
10
|
+
*/
|
|
11
|
+
import { Pool, PoolClient } from "pg";
|
|
12
|
+
type Database = Pool | PoolClient | any;
|
|
13
|
+
/**
|
|
14
|
+
* Subscription record interface
|
|
15
|
+
*/
|
|
16
|
+
export interface Subscription {
|
|
17
|
+
id: number;
|
|
18
|
+
organizationId: number;
|
|
19
|
+
stripeCustomerId: string;
|
|
20
|
+
stripeSubscriptionId: string;
|
|
21
|
+
stripePriceId: string;
|
|
22
|
+
status: string;
|
|
23
|
+
currentPeriodStart: Date;
|
|
24
|
+
currentPeriodEnd: Date;
|
|
25
|
+
trialStart: Date | null;
|
|
26
|
+
trialEnd: Date | null;
|
|
27
|
+
canceledAt: Date | null;
|
|
28
|
+
metadata: Record<string, any>;
|
|
29
|
+
createdAt: Date;
|
|
30
|
+
updatedAt: Date;
|
|
31
|
+
}
|
|
32
|
+
/**
|
|
33
|
+
* Create or update a subscription record
|
|
34
|
+
*
|
|
35
|
+
* This function ensures one subscription per organization by using ON CONFLICT (organization_id).
|
|
36
|
+
* When a new subscription is created for an organization, it replaces the existing subscription record.
|
|
37
|
+
*
|
|
38
|
+
* @param db - Database instance
|
|
39
|
+
* @param subscriptionData - Subscription data
|
|
40
|
+
* @returns Created or updated subscription
|
|
41
|
+
*/
|
|
42
|
+
export declare function upsertSubscription(db: Database, subscriptionData: {
|
|
43
|
+
organizationId: number;
|
|
44
|
+
stripeCustomerId: string;
|
|
45
|
+
stripeSubscriptionId: string;
|
|
46
|
+
stripePriceId: string;
|
|
47
|
+
status: string;
|
|
48
|
+
currentPeriodStart: Date;
|
|
49
|
+
currentPeriodEnd: Date;
|
|
50
|
+
trialStart?: Date | null;
|
|
51
|
+
trialEnd?: Date | null;
|
|
52
|
+
canceledAt?: Date | null;
|
|
53
|
+
metadata?: Record<string, any>;
|
|
54
|
+
}): Promise<Subscription>;
|
|
55
|
+
/**
|
|
56
|
+
* Get subscription by Stripe subscription ID
|
|
57
|
+
*
|
|
58
|
+
* @param db - Database instance
|
|
59
|
+
* @param stripeSubscriptionId - Stripe subscription ID
|
|
60
|
+
* @returns Subscription or null if not found
|
|
61
|
+
*/
|
|
62
|
+
export declare function getSubscriptionByStripeId(db: Database, stripeSubscriptionId: string): Promise<Subscription | null>;
|
|
63
|
+
/**
|
|
64
|
+
* Get subscription by organization ID
|
|
65
|
+
*
|
|
66
|
+
* @param db - Database instance
|
|
67
|
+
* @param organizationId - Organization ID
|
|
68
|
+
* @returns Subscription or null if not found
|
|
69
|
+
*/
|
|
70
|
+
export declare function getSubscriptionByOrganizationId(db: Database, organizationId: number): Promise<Subscription | null>;
|
|
71
|
+
/**
|
|
72
|
+
* Check if a Stripe event has already been processed (idempotency check)
|
|
73
|
+
*
|
|
74
|
+
* @param db - Database instance
|
|
75
|
+
* @param stripeEventId - Stripe event ID
|
|
76
|
+
* @returns true if event has been processed, false otherwise
|
|
77
|
+
*/
|
|
78
|
+
export declare function isStripeEventProcessed(db: Database, stripeEventId: string): Promise<boolean>;
|
|
79
|
+
/**
|
|
80
|
+
* Update subscription status and dates
|
|
81
|
+
*
|
|
82
|
+
* @param db - Database instance
|
|
83
|
+
* @param stripeSubscriptionId - Stripe subscription ID
|
|
84
|
+
* @param updateData - Data to update
|
|
85
|
+
* @returns Updated subscription or null if not found
|
|
86
|
+
*/
|
|
87
|
+
export declare function updateSubscription(db: Database, stripeSubscriptionId: string, updateData: {
|
|
88
|
+
status?: string;
|
|
89
|
+
currentPeriodStart?: Date;
|
|
90
|
+
currentPeriodEnd?: Date;
|
|
91
|
+
trialStart?: Date | null;
|
|
92
|
+
trialEnd?: Date | null;
|
|
93
|
+
canceledAt?: Date | null;
|
|
94
|
+
metadata?: Record<string, any>;
|
|
95
|
+
}): Promise<Subscription | null>;
|
|
96
|
+
/**
|
|
97
|
+
* Check if an organization has ever had a subscription (regardless of trial or status)
|
|
98
|
+
* This is used to prevent free trial abuse (users canceling and resubscribing to get another free trial)
|
|
99
|
+
*
|
|
100
|
+
* Business Logic: If an organization has ANY previous subscription (even if canceled, even if no trial),
|
|
101
|
+
* they should not get a free trial on resubscription. The free trial is only for first-time subscribers.
|
|
102
|
+
*
|
|
103
|
+
* IMPORTANT: Since subscriptions use ON CONFLICT (organization_id), new subscriptions overwrite old ones.
|
|
104
|
+
* However, the existence of ANY subscription record (regardless of status) indicates the organization
|
|
105
|
+
* has already used their "first subscription" opportunity.
|
|
106
|
+
*
|
|
107
|
+
* @param db - Database instance
|
|
108
|
+
* @param organizationId - Organization ID
|
|
109
|
+
* @returns true if organization has ever had any subscription, false otherwise
|
|
110
|
+
*/
|
|
111
|
+
export declare function hasOrganizationUsedFreeTrial(db: Database, organizationId: number): Promise<boolean>;
|
|
112
|
+
/**
|
|
113
|
+
* Check if a user has ever had a subscription with a free trial period (across all organizations)
|
|
114
|
+
* This is used to prevent free trial abuse (users canceling during trial and resubscribing)
|
|
115
|
+
* The check is per user, not per organization - once a user has used a free trial, they can't get another one
|
|
116
|
+
*
|
|
117
|
+
* @param db - Database instance
|
|
118
|
+
* @param userId - User ID
|
|
119
|
+
* @returns true if user has ever had a subscription with a trial period, false otherwise
|
|
120
|
+
*/
|
|
121
|
+
export declare function hasUserUsedFreeTrial(db: Database, userId: number): Promise<boolean>;
|
|
122
|
+
export {};
|
|
123
|
+
//# sourceMappingURL=subscription-operations.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"subscription-operations.d.ts","sourceRoot":"","sources":["../../src/utils/subscription-operations.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1,391 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
/**
|
|
3
|
+
* =============================================================================
|
|
4
|
+
* SUBSCRIPTION OPERATIONS
|
|
5
|
+
* =============================================================================
|
|
6
|
+
* Database operations for managing Stripe subscriptions
|
|
7
|
+
*
|
|
8
|
+
* This module provides reusable functions for subscription management,
|
|
9
|
+
* ensuring all subscription-related database operations are centralized
|
|
10
|
+
* and reusable across Lambda functions.
|
|
11
|
+
*/
|
|
12
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
13
|
+
exports.upsertSubscription = upsertSubscription;
|
|
14
|
+
exports.getSubscriptionByStripeId = getSubscriptionByStripeId;
|
|
15
|
+
exports.getSubscriptionByOrganizationId = getSubscriptionByOrganizationId;
|
|
16
|
+
exports.isStripeEventProcessed = isStripeEventProcessed;
|
|
17
|
+
exports.updateSubscription = updateSubscription;
|
|
18
|
+
exports.hasOrganizationUsedFreeTrial = hasOrganizationUsedFreeTrial;
|
|
19
|
+
exports.hasUserUsedFreeTrial = hasUserUsedFreeTrial;
|
|
20
|
+
const pg_client_1 = require("../lib/pg-client");
|
|
21
|
+
const db_1 = require("../lib/db");
|
|
22
|
+
/**
|
|
23
|
+
* Create or update a subscription record
|
|
24
|
+
*
|
|
25
|
+
* This function ensures one subscription per organization by using ON CONFLICT (organization_id).
|
|
26
|
+
* When a new subscription is created for an organization, it replaces the existing subscription record.
|
|
27
|
+
*
|
|
28
|
+
* @param db - Database instance
|
|
29
|
+
* @param subscriptionData - Subscription data
|
|
30
|
+
* @returns Created or updated subscription
|
|
31
|
+
*/
|
|
32
|
+
async function upsertSubscription(db, subscriptionData) {
|
|
33
|
+
(0, db_1.debugLogDbOperation)("upsert", "subscriptions", { subscriptionData });
|
|
34
|
+
// Note: We no longer need to preserve trial history in metadata because
|
|
35
|
+
// hasOrganizationUsedFreeTrial now simply checks if ANY subscription exists for the organization.
|
|
36
|
+
// The existence of a subscription record (regardless of status or trial) indicates
|
|
37
|
+
// the organization has already used their "first subscription" opportunity.
|
|
38
|
+
const sql = `
|
|
39
|
+
INSERT INTO public.subscriptions (
|
|
40
|
+
organization_id,
|
|
41
|
+
stripe_customer_id,
|
|
42
|
+
stripe_subscription_id,
|
|
43
|
+
stripe_price_id,
|
|
44
|
+
status,
|
|
45
|
+
current_period_start,
|
|
46
|
+
current_period_end,
|
|
47
|
+
trial_start,
|
|
48
|
+
trial_end,
|
|
49
|
+
canceled_at,
|
|
50
|
+
metadata,
|
|
51
|
+
created_at,
|
|
52
|
+
updated_at
|
|
53
|
+
) VALUES ($1, $2, $3, $4, $5, $6, $7, $8, $9, $10, $11, NOW(), NOW())
|
|
54
|
+
ON CONFLICT (organization_id) DO UPDATE SET
|
|
55
|
+
stripe_customer_id = EXCLUDED.stripe_customer_id,
|
|
56
|
+
stripe_subscription_id = EXCLUDED.stripe_subscription_id,
|
|
57
|
+
stripe_price_id = EXCLUDED.stripe_price_id,
|
|
58
|
+
status = EXCLUDED.status,
|
|
59
|
+
current_period_start = EXCLUDED.current_period_start,
|
|
60
|
+
current_period_end = EXCLUDED.current_period_end,
|
|
61
|
+
trial_start = EXCLUDED.trial_start,
|
|
62
|
+
trial_end = EXCLUDED.trial_end,
|
|
63
|
+
canceled_at = EXCLUDED.canceled_at,
|
|
64
|
+
metadata = EXCLUDED.metadata,
|
|
65
|
+
updated_at = NOW()
|
|
66
|
+
RETURNING
|
|
67
|
+
id,
|
|
68
|
+
organization_id,
|
|
69
|
+
stripe_customer_id,
|
|
70
|
+
stripe_subscription_id,
|
|
71
|
+
stripe_price_id,
|
|
72
|
+
status,
|
|
73
|
+
current_period_start,
|
|
74
|
+
current_period_end,
|
|
75
|
+
trial_start,
|
|
76
|
+
trial_end,
|
|
77
|
+
canceled_at,
|
|
78
|
+
metadata,
|
|
79
|
+
created_at,
|
|
80
|
+
updated_at
|
|
81
|
+
`;
|
|
82
|
+
const result = await (0, pg_client_1.queryOne)(db, sql, [
|
|
83
|
+
subscriptionData.organizationId,
|
|
84
|
+
subscriptionData.stripeCustomerId,
|
|
85
|
+
subscriptionData.stripeSubscriptionId,
|
|
86
|
+
subscriptionData.stripePriceId,
|
|
87
|
+
subscriptionData.status,
|
|
88
|
+
subscriptionData.currentPeriodStart,
|
|
89
|
+
subscriptionData.currentPeriodEnd,
|
|
90
|
+
subscriptionData.trialStart || null,
|
|
91
|
+
subscriptionData.trialEnd || null,
|
|
92
|
+
subscriptionData.canceledAt || null,
|
|
93
|
+
JSON.stringify(subscriptionData.metadata || {}),
|
|
94
|
+
]);
|
|
95
|
+
if (!result) {
|
|
96
|
+
throw new Error("Failed to upsert subscription");
|
|
97
|
+
}
|
|
98
|
+
return {
|
|
99
|
+
id: result.id,
|
|
100
|
+
organizationId: result.organization_id,
|
|
101
|
+
stripeCustomerId: result.stripe_customer_id,
|
|
102
|
+
stripeSubscriptionId: result.stripe_subscription_id,
|
|
103
|
+
stripePriceId: result.stripe_price_id,
|
|
104
|
+
status: result.status,
|
|
105
|
+
currentPeriodStart: result.current_period_start,
|
|
106
|
+
currentPeriodEnd: result.current_period_end,
|
|
107
|
+
trialStart: result.trial_start,
|
|
108
|
+
trialEnd: result.trial_end,
|
|
109
|
+
canceledAt: result.canceled_at,
|
|
110
|
+
metadata: result.metadata,
|
|
111
|
+
createdAt: result.created_at,
|
|
112
|
+
updatedAt: result.updated_at,
|
|
113
|
+
};
|
|
114
|
+
}
|
|
115
|
+
/**
|
|
116
|
+
* Get subscription by Stripe subscription ID
|
|
117
|
+
*
|
|
118
|
+
* @param db - Database instance
|
|
119
|
+
* @param stripeSubscriptionId - Stripe subscription ID
|
|
120
|
+
* @returns Subscription or null if not found
|
|
121
|
+
*/
|
|
122
|
+
async function getSubscriptionByStripeId(db, stripeSubscriptionId) {
|
|
123
|
+
(0, db_1.debugLogDbOperation)("select", "subscriptions", { stripeSubscriptionId });
|
|
124
|
+
const sql = `
|
|
125
|
+
SELECT
|
|
126
|
+
id,
|
|
127
|
+
organization_id,
|
|
128
|
+
stripe_customer_id,
|
|
129
|
+
stripe_subscription_id,
|
|
130
|
+
stripe_price_id,
|
|
131
|
+
status,
|
|
132
|
+
current_period_start,
|
|
133
|
+
current_period_end,
|
|
134
|
+
trial_start,
|
|
135
|
+
trial_end,
|
|
136
|
+
canceled_at,
|
|
137
|
+
metadata,
|
|
138
|
+
created_at,
|
|
139
|
+
updated_at
|
|
140
|
+
FROM public.subscriptions
|
|
141
|
+
WHERE stripe_subscription_id = $1
|
|
142
|
+
LIMIT 1
|
|
143
|
+
`;
|
|
144
|
+
const result = await (0, pg_client_1.queryOne)(db, sql, [stripeSubscriptionId]);
|
|
145
|
+
if (!result) {
|
|
146
|
+
return null;
|
|
147
|
+
}
|
|
148
|
+
return {
|
|
149
|
+
id: result.id,
|
|
150
|
+
organizationId: result.organization_id,
|
|
151
|
+
stripeCustomerId: result.stripe_customer_id,
|
|
152
|
+
stripeSubscriptionId: result.stripe_subscription_id,
|
|
153
|
+
stripePriceId: result.stripe_price_id,
|
|
154
|
+
status: result.status,
|
|
155
|
+
currentPeriodStart: result.current_period_start,
|
|
156
|
+
currentPeriodEnd: result.current_period_end,
|
|
157
|
+
trialStart: result.trial_start,
|
|
158
|
+
trialEnd: result.trial_end,
|
|
159
|
+
canceledAt: result.canceled_at,
|
|
160
|
+
metadata: result.metadata,
|
|
161
|
+
createdAt: result.created_at,
|
|
162
|
+
updatedAt: result.updated_at,
|
|
163
|
+
};
|
|
164
|
+
}
|
|
165
|
+
/**
|
|
166
|
+
* Get subscription by organization ID
|
|
167
|
+
*
|
|
168
|
+
* @param db - Database instance
|
|
169
|
+
* @param organizationId - Organization ID
|
|
170
|
+
* @returns Subscription or null if not found
|
|
171
|
+
*/
|
|
172
|
+
async function getSubscriptionByOrganizationId(db, organizationId) {
|
|
173
|
+
(0, db_1.debugLogDbOperation)("select", "subscriptions", { organizationId });
|
|
174
|
+
const sql = `
|
|
175
|
+
SELECT
|
|
176
|
+
id,
|
|
177
|
+
organization_id,
|
|
178
|
+
stripe_customer_id,
|
|
179
|
+
stripe_subscription_id,
|
|
180
|
+
stripe_price_id,
|
|
181
|
+
status,
|
|
182
|
+
current_period_start,
|
|
183
|
+
current_period_end,
|
|
184
|
+
trial_start,
|
|
185
|
+
trial_end,
|
|
186
|
+
canceled_at,
|
|
187
|
+
metadata,
|
|
188
|
+
created_at,
|
|
189
|
+
updated_at
|
|
190
|
+
FROM public.subscriptions
|
|
191
|
+
WHERE organization_id = $1
|
|
192
|
+
ORDER BY created_at DESC
|
|
193
|
+
LIMIT 1
|
|
194
|
+
`;
|
|
195
|
+
const result = await (0, pg_client_1.queryOne)(db, sql, [organizationId]);
|
|
196
|
+
if (!result) {
|
|
197
|
+
return null;
|
|
198
|
+
}
|
|
199
|
+
return {
|
|
200
|
+
id: result.id,
|
|
201
|
+
organizationId: result.organization_id,
|
|
202
|
+
stripeCustomerId: result.stripe_customer_id,
|
|
203
|
+
stripeSubscriptionId: result.stripe_subscription_id,
|
|
204
|
+
stripePriceId: result.stripe_price_id,
|
|
205
|
+
status: result.status,
|
|
206
|
+
currentPeriodStart: result.current_period_start,
|
|
207
|
+
currentPeriodEnd: result.current_period_end,
|
|
208
|
+
trialStart: result.trial_start,
|
|
209
|
+
trialEnd: result.trial_end,
|
|
210
|
+
canceledAt: result.canceled_at,
|
|
211
|
+
metadata: result.metadata,
|
|
212
|
+
createdAt: result.created_at,
|
|
213
|
+
updatedAt: result.updated_at,
|
|
214
|
+
};
|
|
215
|
+
}
|
|
216
|
+
/**
|
|
217
|
+
* Check if a Stripe event has already been processed (idempotency check)
|
|
218
|
+
*
|
|
219
|
+
* @param db - Database instance
|
|
220
|
+
* @param stripeEventId - Stripe event ID
|
|
221
|
+
* @returns true if event has been processed, false otherwise
|
|
222
|
+
*/
|
|
223
|
+
async function isStripeEventProcessed(db, stripeEventId) {
|
|
224
|
+
(0, db_1.debugLogDbOperation)("select", "subscriptions", { stripeEventId }, undefined, {
|
|
225
|
+
operation: "isStripeEventProcessed",
|
|
226
|
+
});
|
|
227
|
+
const sql = `
|
|
228
|
+
SELECT id
|
|
229
|
+
FROM public.subscriptions
|
|
230
|
+
WHERE metadata->>'stripe_event_id' = $1
|
|
231
|
+
LIMIT 1
|
|
232
|
+
`;
|
|
233
|
+
const result = await (0, pg_client_1.query)(db, sql, [stripeEventId]);
|
|
234
|
+
return result && result.length > 0;
|
|
235
|
+
}
|
|
236
|
+
/**
|
|
237
|
+
* Update subscription status and dates
|
|
238
|
+
*
|
|
239
|
+
* @param db - Database instance
|
|
240
|
+
* @param stripeSubscriptionId - Stripe subscription ID
|
|
241
|
+
* @param updateData - Data to update
|
|
242
|
+
* @returns Updated subscription or null if not found
|
|
243
|
+
*/
|
|
244
|
+
async function updateSubscription(db, stripeSubscriptionId, updateData) {
|
|
245
|
+
(0, db_1.debugLogDbOperation)("update", "subscriptions", {
|
|
246
|
+
stripeSubscriptionId,
|
|
247
|
+
updateData,
|
|
248
|
+
});
|
|
249
|
+
const updates = [];
|
|
250
|
+
const params = [];
|
|
251
|
+
let paramIndex = 1;
|
|
252
|
+
if (updateData.status !== undefined) {
|
|
253
|
+
updates.push(`status = $${paramIndex}`);
|
|
254
|
+
params.push(updateData.status);
|
|
255
|
+
paramIndex++;
|
|
256
|
+
}
|
|
257
|
+
if (updateData.currentPeriodStart !== undefined) {
|
|
258
|
+
updates.push(`current_period_start = $${paramIndex}`);
|
|
259
|
+
params.push(updateData.currentPeriodStart);
|
|
260
|
+
paramIndex++;
|
|
261
|
+
}
|
|
262
|
+
if (updateData.currentPeriodEnd !== undefined) {
|
|
263
|
+
updates.push(`current_period_end = $${paramIndex}`);
|
|
264
|
+
params.push(updateData.currentPeriodEnd);
|
|
265
|
+
paramIndex++;
|
|
266
|
+
}
|
|
267
|
+
if (updateData.trialStart !== undefined) {
|
|
268
|
+
updates.push(`trial_start = $${paramIndex}`);
|
|
269
|
+
params.push(updateData.trialStart);
|
|
270
|
+
paramIndex++;
|
|
271
|
+
}
|
|
272
|
+
if (updateData.trialEnd !== undefined) {
|
|
273
|
+
updates.push(`trial_end = $${paramIndex}`);
|
|
274
|
+
params.push(updateData.trialEnd);
|
|
275
|
+
paramIndex++;
|
|
276
|
+
}
|
|
277
|
+
if (updateData.canceledAt !== undefined) {
|
|
278
|
+
updates.push(`canceled_at = $${paramIndex}`);
|
|
279
|
+
params.push(updateData.canceledAt);
|
|
280
|
+
paramIndex++;
|
|
281
|
+
}
|
|
282
|
+
if (updateData.metadata !== undefined) {
|
|
283
|
+
updates.push(`metadata = $${paramIndex}`);
|
|
284
|
+
params.push(JSON.stringify(updateData.metadata));
|
|
285
|
+
paramIndex++;
|
|
286
|
+
}
|
|
287
|
+
if (updates.length === 0) {
|
|
288
|
+
// Nothing to update, return existing subscription
|
|
289
|
+
return getSubscriptionByStripeId(db, stripeSubscriptionId);
|
|
290
|
+
}
|
|
291
|
+
updates.push(`updated_at = NOW()`);
|
|
292
|
+
params.push(stripeSubscriptionId);
|
|
293
|
+
const sql = `
|
|
294
|
+
UPDATE public.subscriptions
|
|
295
|
+
SET ${updates.join(", ")}
|
|
296
|
+
WHERE stripe_subscription_id = $${paramIndex}
|
|
297
|
+
RETURNING
|
|
298
|
+
id,
|
|
299
|
+
organization_id,
|
|
300
|
+
stripe_customer_id,
|
|
301
|
+
stripe_subscription_id,
|
|
302
|
+
stripe_price_id,
|
|
303
|
+
status,
|
|
304
|
+
current_period_start,
|
|
305
|
+
current_period_end,
|
|
306
|
+
trial_start,
|
|
307
|
+
trial_end,
|
|
308
|
+
canceled_at,
|
|
309
|
+
metadata,
|
|
310
|
+
created_at,
|
|
311
|
+
updated_at
|
|
312
|
+
`;
|
|
313
|
+
const result = await (0, pg_client_1.queryOne)(db, sql, params);
|
|
314
|
+
if (!result) {
|
|
315
|
+
return null;
|
|
316
|
+
}
|
|
317
|
+
return {
|
|
318
|
+
id: result.id,
|
|
319
|
+
organizationId: result.organization_id,
|
|
320
|
+
stripeCustomerId: result.stripe_customer_id,
|
|
321
|
+
stripeSubscriptionId: result.stripe_subscription_id,
|
|
322
|
+
stripePriceId: result.stripe_price_id,
|
|
323
|
+
status: result.status,
|
|
324
|
+
currentPeriodStart: result.current_period_start,
|
|
325
|
+
currentPeriodEnd: result.current_period_end,
|
|
326
|
+
trialStart: result.trial_start,
|
|
327
|
+
trialEnd: result.trial_end,
|
|
328
|
+
canceledAt: result.canceled_at,
|
|
329
|
+
metadata: result.metadata,
|
|
330
|
+
createdAt: result.created_at,
|
|
331
|
+
updatedAt: result.updated_at,
|
|
332
|
+
};
|
|
333
|
+
}
|
|
334
|
+
/**
|
|
335
|
+
* Check if an organization has ever had a subscription (regardless of trial or status)
|
|
336
|
+
* This is used to prevent free trial abuse (users canceling and resubscribing to get another free trial)
|
|
337
|
+
*
|
|
338
|
+
* Business Logic: If an organization has ANY previous subscription (even if canceled, even if no trial),
|
|
339
|
+
* they should not get a free trial on resubscription. The free trial is only for first-time subscribers.
|
|
340
|
+
*
|
|
341
|
+
* IMPORTANT: Since subscriptions use ON CONFLICT (organization_id), new subscriptions overwrite old ones.
|
|
342
|
+
* However, the existence of ANY subscription record (regardless of status) indicates the organization
|
|
343
|
+
* has already used their "first subscription" opportunity.
|
|
344
|
+
*
|
|
345
|
+
* @param db - Database instance
|
|
346
|
+
* @param organizationId - Organization ID
|
|
347
|
+
* @returns true if organization has ever had any subscription, false otherwise
|
|
348
|
+
*/
|
|
349
|
+
async function hasOrganizationUsedFreeTrial(db, organizationId) {
|
|
350
|
+
(0, db_1.debugLogDbOperation)("select", "subscriptions", { organizationId }, undefined, {
|
|
351
|
+
operation: "hasOrganizationUsedFreeTrial",
|
|
352
|
+
});
|
|
353
|
+
const sql = `
|
|
354
|
+
SELECT id
|
|
355
|
+
FROM public.subscriptions
|
|
356
|
+
WHERE organization_id = $1
|
|
357
|
+
LIMIT 1
|
|
358
|
+
`;
|
|
359
|
+
const result = await (0, pg_client_1.query)(db, sql, [organizationId]);
|
|
360
|
+
return result && result.length > 0;
|
|
361
|
+
}
|
|
362
|
+
/**
|
|
363
|
+
* Check if a user has ever had a subscription with a free trial period (across all organizations)
|
|
364
|
+
* This is used to prevent free trial abuse (users canceling during trial and resubscribing)
|
|
365
|
+
* The check is per user, not per organization - once a user has used a free trial, they can't get another one
|
|
366
|
+
*
|
|
367
|
+
* @param db - Database instance
|
|
368
|
+
* @param userId - User ID
|
|
369
|
+
* @returns true if user has ever had a subscription with a trial period, false otherwise
|
|
370
|
+
*/
|
|
371
|
+
async function hasUserUsedFreeTrial(db, userId) {
|
|
372
|
+
(0, db_1.debugLogDbOperation)("select", "subscriptions", { userId }, undefined, {
|
|
373
|
+
operation: "hasUserUsedFreeTrial",
|
|
374
|
+
});
|
|
375
|
+
// Query for user_id as integer in JSONB metadata
|
|
376
|
+
// user_id should always be stored as an integer, but we handle both for safety
|
|
377
|
+
const sql = `
|
|
378
|
+
SELECT id
|
|
379
|
+
FROM public.subscriptions
|
|
380
|
+
WHERE (
|
|
381
|
+
(metadata->'user_id')::numeric = $1::numeric
|
|
382
|
+
OR metadata->>'user_id' = $1::text
|
|
383
|
+
)
|
|
384
|
+
AND trial_start IS NOT NULL
|
|
385
|
+
AND trial_end IS NOT NULL
|
|
386
|
+
LIMIT 1
|
|
387
|
+
`;
|
|
388
|
+
const result = await (0, pg_client_1.query)(db, sql, [userId]);
|
|
389
|
+
return result && result.length > 0;
|
|
390
|
+
}
|
|
391
|
+
//# sourceMappingURL=subscription-operations.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"subscription-operations.js","sourceRoot":"","sources":["../../src/utils/subscription-operations.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1,96 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* =============================================================================
|
|
3
|
+
* UNIPILE ACCOUNT OPERATIONS UTILITIES
|
|
4
|
+
* =============================================================================
|
|
5
|
+
* Utility functions for creating and managing Unipile social media accounts
|
|
6
|
+
*/
|
|
7
|
+
import { Pool, PoolClient } from 'pg';
|
|
8
|
+
import type { Database } from "../lib/db";
|
|
9
|
+
import { type UnipileAccount, type SocialPlatformType, type User } from "../lib/schema";
|
|
10
|
+
export interface UnipileAccountWithUser extends UnipileAccount {
|
|
11
|
+
user: User;
|
|
12
|
+
}
|
|
13
|
+
export interface CreateUnipileAccountData {
|
|
14
|
+
linkedinAccountId: number;
|
|
15
|
+
unipileAccountId: string;
|
|
16
|
+
isActive?: boolean;
|
|
17
|
+
connectedAt?: Date;
|
|
18
|
+
lastSyncedAt?: Date;
|
|
19
|
+
metadata?: Record<string, any>;
|
|
20
|
+
}
|
|
21
|
+
export interface UpdateUnipileAccountData {
|
|
22
|
+
isActive?: boolean;
|
|
23
|
+
lastSyncedAt?: Date;
|
|
24
|
+
metadata?: Record<string, any>;
|
|
25
|
+
}
|
|
26
|
+
export interface UserWithUnipileAccounts extends User {
|
|
27
|
+
unipileAccounts: UnipileAccount[];
|
|
28
|
+
}
|
|
29
|
+
export interface UnipileAccountSearchCriteria {
|
|
30
|
+
platformTypes?: SocialPlatformType[];
|
|
31
|
+
isActive?: boolean;
|
|
32
|
+
userIds?: number[];
|
|
33
|
+
unipileAccountIds?: string[];
|
|
34
|
+
lastSyncedBefore?: Date;
|
|
35
|
+
lastSyncedAfter?: Date;
|
|
36
|
+
}
|
|
37
|
+
export interface PlatformSummary {
|
|
38
|
+
platform: SocialPlatformType;
|
|
39
|
+
totalAccounts: number;
|
|
40
|
+
activeAccounts: number;
|
|
41
|
+
inactiveAccounts: number;
|
|
42
|
+
recentlyConnected: number;
|
|
43
|
+
needsSync: number;
|
|
44
|
+
}
|
|
45
|
+
/**
|
|
46
|
+
* Creates a new Unipile account record
|
|
47
|
+
*
|
|
48
|
+
* @param data - Unipile account creation data
|
|
49
|
+
* @returns Promise resolving to the created account
|
|
50
|
+
*/
|
|
51
|
+
export declare function createUnipileAccount(db: Database | Pool | PoolClient, data: CreateUnipileAccountData): Promise<UnipileAccount>;
|
|
52
|
+
/**
|
|
53
|
+
* Creates or updates a Unipile account (upsert)
|
|
54
|
+
*
|
|
55
|
+
* @param data - Unipile account data
|
|
56
|
+
* @returns Promise resolving to the created or updated account
|
|
57
|
+
*/
|
|
58
|
+
export declare function upsertUnipileAccount(db: Database | Pool | PoolClient, data: CreateUnipileAccountData): Promise<UnipileAccount>;
|
|
59
|
+
/**
|
|
60
|
+
* Simple social account status map for quick UI updates
|
|
61
|
+
*/
|
|
62
|
+
export interface LinkedAccountStatusMap {
|
|
63
|
+
linkedin: boolean;
|
|
64
|
+
whatsapp: boolean;
|
|
65
|
+
twitter: boolean;
|
|
66
|
+
instagram: boolean;
|
|
67
|
+
facebook: boolean;
|
|
68
|
+
}
|
|
69
|
+
/**
|
|
70
|
+
* Gets a simple boolean map of which social accounts are linked for a user
|
|
71
|
+
* Optimized for frontend UI to show connection status without sensitive data
|
|
72
|
+
*
|
|
73
|
+
* @param cognitoUserId - The Cognito user ID
|
|
74
|
+
* @param activeOnly - Whether to only consider active accounts (default: true)
|
|
75
|
+
* @returns Promise resolving to a simple boolean map of linked platforms
|
|
76
|
+
*/
|
|
77
|
+
export declare function getUserLinkedAccountStatus(db: Database | Pool | PoolClient, cognitoUserId: string, activeOnly?: boolean): Promise<LinkedAccountStatusMap>;
|
|
78
|
+
/**
|
|
79
|
+
* Checks if a LinkedIn account with the given ACoA identifier is already connected
|
|
80
|
+
* to a different user via an active Unipile account
|
|
81
|
+
*
|
|
82
|
+
* @param db - Database connection
|
|
83
|
+
* @param linkedinIdentifierAcoa - The ACoA identifier to check
|
|
84
|
+
* @param currentUserId - The current user ID (to exclude from the check)
|
|
85
|
+
* @returns Promise resolving to the existing account's user ID if found, null otherwise
|
|
86
|
+
*/
|
|
87
|
+
export declare function checkAcoaAlreadyConnectedToDifferentUser(db: Database | Pool | PoolClient, linkedinIdentifierAcoa: string, currentUserId: number): Promise<number | null>;
|
|
88
|
+
/**
|
|
89
|
+
* Batch updates last synced time for multiple accounts
|
|
90
|
+
*
|
|
91
|
+
* @param accountIds - Array of account IDs to update
|
|
92
|
+
* @param syncTime - Optional: specific sync time (defaults to now)
|
|
93
|
+
* @returns Promise resolving to number of updated accounts
|
|
94
|
+
*/
|
|
95
|
+
export declare function batchMarkAccountsAsSynced(db: Database | Pool | PoolClient, accountIds: number[], syncTime?: Date): Promise<number>;
|
|
96
|
+
//# sourceMappingURL=unipile-account-operations.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"unipile-account-operations.d.ts","sourceRoot":"","sources":["../../src/utils/unipile-account-operations.ts"],"names":[],"mappings":"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"}
|