@oneuptime/common 9.2.16 → 9.2.17
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/Models/DatabaseModels/CodeRepository.ts +664 -0
- package/Models/DatabaseModels/Index.ts +8 -0
- package/Models/DatabaseModels/LlmLog.ts +818 -0
- package/Models/DatabaseModels/LlmProvider.ts +21 -0
- package/Models/DatabaseModels/Project.ts +206 -0
- package/Models/DatabaseModels/ServiceCatalogCodeRepository.ts +549 -0
- package/Server/API/AIBillingAPI.ts +126 -0
- package/Server/API/GitHubAPI.ts +360 -0
- package/Server/API/IncidentAPI.ts +126 -0
- package/Server/EnvironmentConfig.ts +44 -0
- package/Server/Infrastructure/Postgres/SchemaMigrations/1765580181582-MigrationName.ts +79 -0
- package/Server/Infrastructure/Postgres/SchemaMigrations/1765633554715-MigrationName.ts +75 -0
- package/Server/Infrastructure/Postgres/SchemaMigrations/1765801357168-MigrationName.ts +32 -0
- package/Server/Infrastructure/Postgres/SchemaMigrations/1765810218488-MigrationName.ts +69 -0
- package/Server/Infrastructure/Postgres/SchemaMigrations/1765830758857-MigrationName.ts +111 -0
- package/Server/Infrastructure/Postgres/SchemaMigrations/1765834537501-MigrationName.ts +39 -0
- package/Server/Infrastructure/Postgres/SchemaMigrations/Index.ts +12 -0
- package/Server/Services/AIBillingService.ts +247 -0
- package/Server/Services/AIService.ts +239 -0
- package/Server/Services/CodeRepositoryService.ts +10 -0
- package/Server/Services/IncidentService.ts +89 -0
- package/Server/Services/Index.ts +2 -0
- package/Server/Services/LlmLogService.ts +14 -0
- package/Server/Services/LlmProviderService.ts +58 -0
- package/Server/Services/ServiceCatalogCodeRepositoryService.ts +55 -0
- package/Server/Utils/AI/IncidentAIContextBuilder.ts +498 -0
- package/Server/Utils/CodeRepository/GitHub/GitHub.ts +226 -0
- package/Server/Utils/LLM/LLMService.ts +276 -0
- package/Server/Utils/Workspace/MicrosoftTeams/MicrosoftTeams.ts +166 -0
- package/Server/Utils/Workspace/Slack/Slack.ts +134 -0
- package/Server/Utils/Workspace/Workspace.ts +126 -0
- package/Types/CodeRepository/CodeRepositoryType.ts +1 -1
- package/Types/LlmLogStatus.ts +7 -0
- package/Types/Permission.ts +87 -0
- package/Types/ServiceCatalog/CodeRepositoryImprovementAction.ts +9 -0
- package/UI/Components/AI/AILoader.tsx +95 -0
- package/UI/Components/AI/GenerateFromAIModal.tsx +295 -0
- package/UI/Components/Modal/Modal.tsx +6 -1
- package/build/dist/Models/DatabaseModels/CodeRepository.js +689 -0
- package/build/dist/Models/DatabaseModels/CodeRepository.js.map +1 -0
- package/build/dist/Models/DatabaseModels/Index.js +7 -0
- package/build/dist/Models/DatabaseModels/Index.js.map +1 -1
- package/build/dist/Models/DatabaseModels/LlmLog.js +856 -0
- package/build/dist/Models/DatabaseModels/LlmLog.js.map +1 -0
- package/build/dist/Models/DatabaseModels/LlmProvider.js +22 -0
- package/build/dist/Models/DatabaseModels/LlmProvider.js.map +1 -1
- package/build/dist/Models/DatabaseModels/Project.js +220 -0
- package/build/dist/Models/DatabaseModels/Project.js.map +1 -1
- package/build/dist/Models/DatabaseModels/ServiceCatalogCodeRepository.js +565 -0
- package/build/dist/Models/DatabaseModels/ServiceCatalogCodeRepository.js.map +1 -0
- package/build/dist/Server/API/AIBillingAPI.js +58 -0
- package/build/dist/Server/API/AIBillingAPI.js.map +1 -0
- package/build/dist/Server/API/GitHubAPI.js +207 -0
- package/build/dist/Server/API/GitHubAPI.js.map +1 -0
- package/build/dist/Server/API/IncidentAPI.js +84 -1
- package/build/dist/Server/API/IncidentAPI.js.map +1 -1
- package/build/dist/Server/EnvironmentConfig.js +31 -0
- package/build/dist/Server/EnvironmentConfig.js.map +1 -1
- package/build/dist/Server/Infrastructure/Postgres/SchemaMigrations/1765580181582-MigrationName.js +34 -0
- package/build/dist/Server/Infrastructure/Postgres/SchemaMigrations/1765580181582-MigrationName.js.map +1 -0
- package/build/dist/Server/Infrastructure/Postgres/SchemaMigrations/1765633554715-MigrationName.js +32 -0
- package/build/dist/Server/Infrastructure/Postgres/SchemaMigrations/1765633554715-MigrationName.js.map +1 -0
- package/build/dist/Server/Infrastructure/Postgres/SchemaMigrations/1765801357168-MigrationName.js +38 -0
- package/build/dist/Server/Infrastructure/Postgres/SchemaMigrations/1765801357168-MigrationName.js.map +1 -0
- package/build/dist/Server/Infrastructure/Postgres/SchemaMigrations/1765810218488-MigrationName.js +30 -0
- package/build/dist/Server/Infrastructure/Postgres/SchemaMigrations/1765810218488-MigrationName.js.map +1 -0
- package/build/dist/Server/Infrastructure/Postgres/SchemaMigrations/1765830758857-MigrationName.js +44 -0
- package/build/dist/Server/Infrastructure/Postgres/SchemaMigrations/1765830758857-MigrationName.js.map +1 -0
- package/build/dist/Server/Infrastructure/Postgres/SchemaMigrations/1765834537501-MigrationName.js +22 -0
- package/build/dist/Server/Infrastructure/Postgres/SchemaMigrations/1765834537501-MigrationName.js.map +1 -0
- package/build/dist/Server/Infrastructure/Postgres/SchemaMigrations/Index.js +12 -0
- package/build/dist/Server/Infrastructure/Postgres/SchemaMigrations/Index.js.map +1 -1
- package/build/dist/Server/Services/AIBillingService.js +187 -0
- package/build/dist/Server/Services/AIBillingService.js.map +1 -0
- package/build/dist/Server/Services/AIService.js +185 -0
- package/build/dist/Server/Services/AIService.js.map +1 -0
- package/build/dist/Server/Services/CodeRepositoryService.js +9 -0
- package/build/dist/Server/Services/CodeRepositoryService.js.map +1 -0
- package/build/dist/Server/Services/IncidentService.js +61 -0
- package/build/dist/Server/Services/IncidentService.js.map +1 -1
- package/build/dist/Server/Services/Index.js +2 -0
- package/build/dist/Server/Services/Index.js.map +1 -1
- package/build/dist/Server/Services/LlmLogService.js +13 -0
- package/build/dist/Server/Services/LlmLogService.js.map +1 -0
- package/build/dist/Server/Services/LlmProviderService.js +65 -0
- package/build/dist/Server/Services/LlmProviderService.js.map +1 -1
- package/build/dist/Server/Services/ServiceCatalogCodeRepositoryService.js +54 -0
- package/build/dist/Server/Services/ServiceCatalogCodeRepositoryService.js.map +1 -0
- package/build/dist/Server/Utils/AI/IncidentAIContextBuilder.js +408 -0
- package/build/dist/Server/Utils/AI/IncidentAIContextBuilder.js.map +1 -0
- package/build/dist/Server/Utils/CodeRepository/GitHub/GitHub.js +163 -0
- package/build/dist/Server/Utils/CodeRepository/GitHub/GitHub.js.map +1 -1
- package/build/dist/Server/Utils/LLM/LLMService.js +225 -0
- package/build/dist/Server/Utils/LLM/LLMService.js.map +1 -0
- package/build/dist/Server/Utils/Workspace/MicrosoftTeams/MicrosoftTeams.js +110 -0
- package/build/dist/Server/Utils/Workspace/MicrosoftTeams/MicrosoftTeams.js.map +1 -1
- package/build/dist/Server/Utils/Workspace/Slack/Slack.js +89 -0
- package/build/dist/Server/Utils/Workspace/Slack/Slack.js.map +1 -1
- package/build/dist/Server/Utils/Workspace/Workspace.js +80 -0
- package/build/dist/Server/Utils/Workspace/Workspace.js.map +1 -1
- package/build/dist/Types/CodeRepository/CodeRepositoryType.js +1 -1
- package/build/dist/Types/CodeRepository/CodeRepositoryType.js.map +1 -1
- package/build/dist/Types/LlmLogStatus.js +8 -0
- package/build/dist/Types/LlmLogStatus.js.map +1 -0
- package/build/dist/Types/Permission.js +74 -0
- package/build/dist/Types/Permission.js.map +1 -1
- package/build/dist/Types/ServiceCatalog/CodeRepositoryImprovementAction.js +10 -0
- package/build/dist/Types/ServiceCatalog/CodeRepositoryImprovementAction.js.map +1 -0
- package/build/dist/UI/Components/AI/AILoader.js +64 -0
- package/build/dist/UI/Components/AI/AILoader.js.map +1 -0
- package/build/dist/UI/Components/AI/GenerateFromAIModal.js +207 -0
- package/build/dist/UI/Components/AI/GenerateFromAIModal.js.map +1 -0
- package/build/dist/UI/Components/Modal/Modal.js +6 -1
- package/build/dist/UI/Components/Modal/Modal.js.map +1 -1
- package/package.json +1 -1
|
@@ -0,0 +1,75 @@
|
|
|
1
|
+
import { MigrationInterface, QueryRunner } from "typeorm";
|
|
2
|
+
|
|
3
|
+
export class MigrationName1765633554715 implements MigrationInterface {
|
|
4
|
+
public name = "MigrationName1765633554715";
|
|
5
|
+
|
|
6
|
+
public async up(queryRunner: QueryRunner): Promise<void> {
|
|
7
|
+
await queryRunner.query(
|
|
8
|
+
`CREATE TABLE "ServiceCatalogCodeRepository" ("_id" uuid NOT NULL DEFAULT uuid_generate_v4(), "createdAt" TIMESTAMP WITH TIME ZONE NOT NULL DEFAULT now(), "updatedAt" TIMESTAMP WITH TIME ZONE NOT NULL DEFAULT now(), "deletedAt" TIMESTAMP WITH TIME ZONE, "version" integer NOT NULL, "projectId" uuid NOT NULL, "serviceCatalogId" uuid NOT NULL, "codeRepositoryId" uuid NOT NULL, "servicePathInRepository" character varying, "createdByUserId" uuid, "deletedByUserId" uuid, CONSTRAINT "PK_1a0f992cb6c55f48d9fae93369a" PRIMARY KEY ("_id"))`,
|
|
9
|
+
);
|
|
10
|
+
await queryRunner.query(
|
|
11
|
+
`CREATE INDEX "IDX_41a90624dfbb954e3b50c93dfc" ON "ServiceCatalogCodeRepository" ("projectId") `,
|
|
12
|
+
);
|
|
13
|
+
await queryRunner.query(
|
|
14
|
+
`CREATE INDEX "IDX_4638e464dc7cab644c7926674b" ON "ServiceCatalogCodeRepository" ("serviceCatalogId") `,
|
|
15
|
+
);
|
|
16
|
+
await queryRunner.query(
|
|
17
|
+
`CREATE INDEX "IDX_05b6c65746b28329def0accba9" ON "ServiceCatalogCodeRepository" ("codeRepositoryId") `,
|
|
18
|
+
);
|
|
19
|
+
await queryRunner.query(
|
|
20
|
+
`ALTER TABLE "OnCallDutyPolicyScheduleLayer" ALTER COLUMN "rotation" SET DEFAULT '{"_type":"Recurring","value":{"intervalType":"Day","intervalCount":{"_type":"PositiveNumber","value":1}}}'`,
|
|
21
|
+
);
|
|
22
|
+
await queryRunner.query(
|
|
23
|
+
`ALTER TABLE "OnCallDutyPolicyScheduleLayer" ALTER COLUMN "restrictionTimes" SET DEFAULT '{"_type":"RestrictionTimes","value":{"restictionType":"None","dayRestrictionTimes":null,"weeklyRestrictionTimes":[]}}'`,
|
|
24
|
+
);
|
|
25
|
+
await queryRunner.query(
|
|
26
|
+
`ALTER TABLE "ServiceCatalogCodeRepository" ADD CONSTRAINT "FK_41a90624dfbb954e3b50c93dfc1" FOREIGN KEY ("projectId") REFERENCES "Project"("_id") ON DELETE CASCADE ON UPDATE NO ACTION`,
|
|
27
|
+
);
|
|
28
|
+
await queryRunner.query(
|
|
29
|
+
`ALTER TABLE "ServiceCatalogCodeRepository" ADD CONSTRAINT "FK_4638e464dc7cab644c7926674b8" FOREIGN KEY ("serviceCatalogId") REFERENCES "ServiceCatalog"("_id") ON DELETE CASCADE ON UPDATE NO ACTION`,
|
|
30
|
+
);
|
|
31
|
+
await queryRunner.query(
|
|
32
|
+
`ALTER TABLE "ServiceCatalogCodeRepository" ADD CONSTRAINT "FK_05b6c65746b28329def0accba94" FOREIGN KEY ("codeRepositoryId") REFERENCES "CodeRepository"("_id") ON DELETE CASCADE ON UPDATE NO ACTION`,
|
|
33
|
+
);
|
|
34
|
+
await queryRunner.query(
|
|
35
|
+
`ALTER TABLE "ServiceCatalogCodeRepository" ADD CONSTRAINT "FK_c838ecb46958f5de7a699f50c53" FOREIGN KEY ("createdByUserId") REFERENCES "User"("_id") ON DELETE SET NULL ON UPDATE NO ACTION`,
|
|
36
|
+
);
|
|
37
|
+
await queryRunner.query(
|
|
38
|
+
`ALTER TABLE "ServiceCatalogCodeRepository" ADD CONSTRAINT "FK_1aae6b3a023a36f7c004749afe4" FOREIGN KEY ("deletedByUserId") REFERENCES "User"("_id") ON DELETE SET NULL ON UPDATE NO ACTION`,
|
|
39
|
+
);
|
|
40
|
+
}
|
|
41
|
+
|
|
42
|
+
public async down(queryRunner: QueryRunner): Promise<void> {
|
|
43
|
+
await queryRunner.query(
|
|
44
|
+
`ALTER TABLE "ServiceCatalogCodeRepository" DROP CONSTRAINT "FK_1aae6b3a023a36f7c004749afe4"`,
|
|
45
|
+
);
|
|
46
|
+
await queryRunner.query(
|
|
47
|
+
`ALTER TABLE "ServiceCatalogCodeRepository" DROP CONSTRAINT "FK_c838ecb46958f5de7a699f50c53"`,
|
|
48
|
+
);
|
|
49
|
+
await queryRunner.query(
|
|
50
|
+
`ALTER TABLE "ServiceCatalogCodeRepository" DROP CONSTRAINT "FK_05b6c65746b28329def0accba94"`,
|
|
51
|
+
);
|
|
52
|
+
await queryRunner.query(
|
|
53
|
+
`ALTER TABLE "ServiceCatalogCodeRepository" DROP CONSTRAINT "FK_4638e464dc7cab644c7926674b8"`,
|
|
54
|
+
);
|
|
55
|
+
await queryRunner.query(
|
|
56
|
+
`ALTER TABLE "ServiceCatalogCodeRepository" DROP CONSTRAINT "FK_41a90624dfbb954e3b50c93dfc1"`,
|
|
57
|
+
);
|
|
58
|
+
await queryRunner.query(
|
|
59
|
+
`ALTER TABLE "OnCallDutyPolicyScheduleLayer" ALTER COLUMN "restrictionTimes" SET DEFAULT '{"_type": "RestrictionTimes", "value": {"restictionType": "None", "dayRestrictionTimes": null, "weeklyRestrictionTimes": []}}'`,
|
|
60
|
+
);
|
|
61
|
+
await queryRunner.query(
|
|
62
|
+
`ALTER TABLE "OnCallDutyPolicyScheduleLayer" ALTER COLUMN "rotation" SET DEFAULT '{"_type": "Recurring", "value": {"intervalType": "Day", "intervalCount": {"_type": "PositiveNumber", "value": 1}}}'`,
|
|
63
|
+
);
|
|
64
|
+
await queryRunner.query(
|
|
65
|
+
`DROP INDEX "public"."IDX_05b6c65746b28329def0accba9"`,
|
|
66
|
+
);
|
|
67
|
+
await queryRunner.query(
|
|
68
|
+
`DROP INDEX "public"."IDX_4638e464dc7cab644c7926674b"`,
|
|
69
|
+
);
|
|
70
|
+
await queryRunner.query(
|
|
71
|
+
`DROP INDEX "public"."IDX_41a90624dfbb954e3b50c93dfc"`,
|
|
72
|
+
);
|
|
73
|
+
await queryRunner.query(`DROP TABLE "ServiceCatalogCodeRepository"`);
|
|
74
|
+
}
|
|
75
|
+
}
|
|
@@ -0,0 +1,32 @@
|
|
|
1
|
+
import { MigrationInterface, QueryRunner } from "typeorm";
|
|
2
|
+
import CaptureSpan from "../../../Utils/Telemetry/CaptureSpan";
|
|
3
|
+
|
|
4
|
+
export class MigrationName1765801357168 implements MigrationInterface {
|
|
5
|
+
public name = "MigrationName1765801357168";
|
|
6
|
+
|
|
7
|
+
@CaptureSpan()
|
|
8
|
+
public async up(queryRunner: QueryRunner): Promise<void> {
|
|
9
|
+
await queryRunner.query(
|
|
10
|
+
`ALTER TABLE "ServiceCatalogCodeRepository" ADD "enableAutomaticImprovements" boolean NOT NULL DEFAULT true`,
|
|
11
|
+
);
|
|
12
|
+
await queryRunner.query(
|
|
13
|
+
`ALTER TABLE "ServiceCatalogCodeRepository" ADD "maxOpenPullRequests" integer NOT NULL DEFAULT 3`,
|
|
14
|
+
);
|
|
15
|
+
await queryRunner.query(
|
|
16
|
+
`ALTER TABLE "ServiceCatalogCodeRepository" ADD "restrictedImprovementActions" jsonb`,
|
|
17
|
+
);
|
|
18
|
+
}
|
|
19
|
+
|
|
20
|
+
@CaptureSpan()
|
|
21
|
+
public async down(queryRunner: QueryRunner): Promise<void> {
|
|
22
|
+
await queryRunner.query(
|
|
23
|
+
`ALTER TABLE "ServiceCatalogCodeRepository" DROP COLUMN "restrictedImprovementActions"`,
|
|
24
|
+
);
|
|
25
|
+
await queryRunner.query(
|
|
26
|
+
`ALTER TABLE "ServiceCatalogCodeRepository" DROP COLUMN "maxOpenPullRequests"`,
|
|
27
|
+
);
|
|
28
|
+
await queryRunner.query(
|
|
29
|
+
`ALTER TABLE "ServiceCatalogCodeRepository" DROP COLUMN "enableAutomaticImprovements"`,
|
|
30
|
+
);
|
|
31
|
+
}
|
|
32
|
+
}
|
|
@@ -0,0 +1,69 @@
|
|
|
1
|
+
import { MigrationInterface, QueryRunner } from "typeorm";
|
|
2
|
+
|
|
3
|
+
export class MigrationName1765810218488 implements MigrationInterface {
|
|
4
|
+
public name = "MigrationName1765810218488";
|
|
5
|
+
|
|
6
|
+
public async up(queryRunner: QueryRunner): Promise<void> {
|
|
7
|
+
await queryRunner.query(
|
|
8
|
+
`ALTER TABLE "Project" ADD "aiCurrentBalanceInUSDCents" integer NOT NULL DEFAULT '0'`,
|
|
9
|
+
);
|
|
10
|
+
await queryRunner.query(
|
|
11
|
+
`ALTER TABLE "Project" ADD "autoAiRechargeByBalanceInUSD" integer NOT NULL DEFAULT '20'`,
|
|
12
|
+
);
|
|
13
|
+
await queryRunner.query(
|
|
14
|
+
`ALTER TABLE "Project" ADD "autoRechargeAiWhenCurrentBalanceFallsInUSD" integer NOT NULL DEFAULT '10'`,
|
|
15
|
+
);
|
|
16
|
+
await queryRunner.query(
|
|
17
|
+
`ALTER TABLE "Project" ADD "enableAi" boolean NOT NULL DEFAULT true`,
|
|
18
|
+
);
|
|
19
|
+
await queryRunner.query(
|
|
20
|
+
`ALTER TABLE "Project" ADD "enableAutoRechargeAiBalance" boolean NOT NULL DEFAULT false`,
|
|
21
|
+
);
|
|
22
|
+
await queryRunner.query(
|
|
23
|
+
`ALTER TABLE "Project" ADD "lowAiBalanceNotificationSentToOwners" boolean NOT NULL DEFAULT false`,
|
|
24
|
+
);
|
|
25
|
+
await queryRunner.query(
|
|
26
|
+
`ALTER TABLE "Project" ADD "failedAiBalanceChargeNotificationSentToOwners" boolean NOT NULL DEFAULT false`,
|
|
27
|
+
);
|
|
28
|
+
await queryRunner.query(
|
|
29
|
+
`ALTER TABLE "Project" ADD "notEnabledAiNotificationSentToOwners" boolean NOT NULL DEFAULT false`,
|
|
30
|
+
);
|
|
31
|
+
await queryRunner.query(
|
|
32
|
+
`ALTER TABLE "OnCallDutyPolicyScheduleLayer" ALTER COLUMN "rotation" SET DEFAULT '{"_type":"Recurring","value":{"intervalType":"Day","intervalCount":{"_type":"PositiveNumber","value":1}}}'`,
|
|
33
|
+
);
|
|
34
|
+
await queryRunner.query(
|
|
35
|
+
`ALTER TABLE "OnCallDutyPolicyScheduleLayer" ALTER COLUMN "restrictionTimes" SET DEFAULT '{"_type":"RestrictionTimes","value":{"restictionType":"None","dayRestrictionTimes":null,"weeklyRestrictionTimes":[]}}'`,
|
|
36
|
+
);
|
|
37
|
+
}
|
|
38
|
+
|
|
39
|
+
public async down(queryRunner: QueryRunner): Promise<void> {
|
|
40
|
+
await queryRunner.query(
|
|
41
|
+
`ALTER TABLE "OnCallDutyPolicyScheduleLayer" ALTER COLUMN "restrictionTimes" SET DEFAULT '{"_type": "RestrictionTimes", "value": {"restictionType": "None", "dayRestrictionTimes": null, "weeklyRestrictionTimes": []}}'`,
|
|
42
|
+
);
|
|
43
|
+
await queryRunner.query(
|
|
44
|
+
`ALTER TABLE "OnCallDutyPolicyScheduleLayer" ALTER COLUMN "rotation" SET DEFAULT '{"_type": "Recurring", "value": {"intervalType": "Day", "intervalCount": {"_type": "PositiveNumber", "value": 1}}}'`,
|
|
45
|
+
);
|
|
46
|
+
await queryRunner.query(
|
|
47
|
+
`ALTER TABLE "Project" DROP COLUMN "notEnabledAiNotificationSentToOwners"`,
|
|
48
|
+
);
|
|
49
|
+
await queryRunner.query(
|
|
50
|
+
`ALTER TABLE "Project" DROP COLUMN "failedAiBalanceChargeNotificationSentToOwners"`,
|
|
51
|
+
);
|
|
52
|
+
await queryRunner.query(
|
|
53
|
+
`ALTER TABLE "Project" DROP COLUMN "lowAiBalanceNotificationSentToOwners"`,
|
|
54
|
+
);
|
|
55
|
+
await queryRunner.query(
|
|
56
|
+
`ALTER TABLE "Project" DROP COLUMN "enableAutoRechargeAiBalance"`,
|
|
57
|
+
);
|
|
58
|
+
await queryRunner.query(`ALTER TABLE "Project" DROP COLUMN "enableAi"`);
|
|
59
|
+
await queryRunner.query(
|
|
60
|
+
`ALTER TABLE "Project" DROP COLUMN "autoRechargeAiWhenCurrentBalanceFallsInUSD"`,
|
|
61
|
+
);
|
|
62
|
+
await queryRunner.query(
|
|
63
|
+
`ALTER TABLE "Project" DROP COLUMN "autoAiRechargeByBalanceInUSD"`,
|
|
64
|
+
);
|
|
65
|
+
await queryRunner.query(
|
|
66
|
+
`ALTER TABLE "Project" DROP COLUMN "aiCurrentBalanceInUSDCents"`,
|
|
67
|
+
);
|
|
68
|
+
}
|
|
69
|
+
}
|
|
@@ -0,0 +1,111 @@
|
|
|
1
|
+
import { MigrationInterface, QueryRunner } from "typeorm";
|
|
2
|
+
|
|
3
|
+
export class MigrationName1765830758857 implements MigrationInterface {
|
|
4
|
+
public name = "MigrationName1765830758857";
|
|
5
|
+
|
|
6
|
+
public async up(queryRunner: QueryRunner): Promise<void> {
|
|
7
|
+
await queryRunner.query(
|
|
8
|
+
`CREATE TABLE "LlmLog" ("_id" uuid NOT NULL DEFAULT uuid_generate_v4(), "createdAt" TIMESTAMP WITH TIME ZONE NOT NULL DEFAULT now(), "updatedAt" TIMESTAMP WITH TIME ZONE NOT NULL DEFAULT now(), "deletedAt" TIMESTAMP WITH TIME ZONE, "version" integer NOT NULL, "projectId" uuid NOT NULL, "llmProviderId" uuid, "llmProviderName" character varying(100), "llmType" character varying(100), "modelName" character varying(100), "isGlobalProvider" boolean NOT NULL DEFAULT false, "inputTokens" integer NOT NULL DEFAULT '0', "outputTokens" integer NOT NULL DEFAULT '0', "totalTokens" integer NOT NULL DEFAULT '0', "costInUSDCents" integer NOT NULL DEFAULT '0', "wasBilled" boolean NOT NULL DEFAULT false, "status" character varying(100) NOT NULL, "statusMessage" character varying(500), "feature" character varying(100), "requestPrompt" text, "responsePreview" text, "incidentId" uuid, "alertId" uuid, "scheduledMaintenanceId" uuid, "userId" uuid, "requestStartedAt" TIMESTAMP WITH TIME ZONE, "requestCompletedAt" TIMESTAMP WITH TIME ZONE, "durationMs" integer, "deletedByUserId" uuid, CONSTRAINT "PK_807b7f4578f9dcbb1f7aeeb94f8" PRIMARY KEY ("_id"))`,
|
|
9
|
+
);
|
|
10
|
+
await queryRunner.query(
|
|
11
|
+
`CREATE INDEX "IDX_c3c061a924f368e2cc68a23308" ON "LlmLog" ("projectId") `,
|
|
12
|
+
);
|
|
13
|
+
await queryRunner.query(
|
|
14
|
+
`CREATE INDEX "IDX_bfd15354697dc30fedf7a96976" ON "LlmLog" ("llmProviderId") `,
|
|
15
|
+
);
|
|
16
|
+
await queryRunner.query(
|
|
17
|
+
`CREATE INDEX "IDX_159d2b07c02788dcac8575bf4a" ON "LlmLog" ("incidentId") `,
|
|
18
|
+
);
|
|
19
|
+
await queryRunner.query(
|
|
20
|
+
`CREATE INDEX "IDX_83696b0732c0a3601a9d5d7afe" ON "LlmLog" ("alertId") `,
|
|
21
|
+
);
|
|
22
|
+
await queryRunner.query(
|
|
23
|
+
`CREATE INDEX "IDX_19d277440e9b9e3ed4fa46c227" ON "LlmLog" ("scheduledMaintenanceId") `,
|
|
24
|
+
);
|
|
25
|
+
await queryRunner.query(
|
|
26
|
+
`CREATE INDEX "IDX_5c6c985581a3f85d84a2987daa" ON "LlmLog" ("userId") `,
|
|
27
|
+
);
|
|
28
|
+
await queryRunner.query(
|
|
29
|
+
`ALTER TABLE "LlmProvider" ADD "costPerMillionTokensInUSDCents" integer NOT NULL DEFAULT '0'`,
|
|
30
|
+
);
|
|
31
|
+
await queryRunner.query(
|
|
32
|
+
`ALTER TABLE "OnCallDutyPolicyScheduleLayer" ALTER COLUMN "rotation" SET DEFAULT '{"_type":"Recurring","value":{"intervalType":"Day","intervalCount":{"_type":"PositiveNumber","value":1}}}'`,
|
|
33
|
+
);
|
|
34
|
+
await queryRunner.query(
|
|
35
|
+
`ALTER TABLE "OnCallDutyPolicyScheduleLayer" ALTER COLUMN "restrictionTimes" SET DEFAULT '{"_type":"RestrictionTimes","value":{"restictionType":"None","dayRestrictionTimes":null,"weeklyRestrictionTimes":[]}}'`,
|
|
36
|
+
);
|
|
37
|
+
await queryRunner.query(
|
|
38
|
+
`ALTER TABLE "LlmLog" ADD CONSTRAINT "FK_c3c061a924f368e2cc68a233083" FOREIGN KEY ("projectId") REFERENCES "Project"("_id") ON DELETE CASCADE ON UPDATE NO ACTION`,
|
|
39
|
+
);
|
|
40
|
+
await queryRunner.query(
|
|
41
|
+
`ALTER TABLE "LlmLog" ADD CONSTRAINT "FK_bfd15354697dc30fedf7a96976e" FOREIGN KEY ("llmProviderId") REFERENCES "LlmProvider"("_id") ON DELETE SET NULL ON UPDATE NO ACTION`,
|
|
42
|
+
);
|
|
43
|
+
await queryRunner.query(
|
|
44
|
+
`ALTER TABLE "LlmLog" ADD CONSTRAINT "FK_159d2b07c02788dcac8575bf4a6" FOREIGN KEY ("incidentId") REFERENCES "Incident"("_id") ON DELETE CASCADE ON UPDATE NO ACTION`,
|
|
45
|
+
);
|
|
46
|
+
await queryRunner.query(
|
|
47
|
+
`ALTER TABLE "LlmLog" ADD CONSTRAINT "FK_83696b0732c0a3601a9d5d7afe1" FOREIGN KEY ("alertId") REFERENCES "Alert"("_id") ON DELETE CASCADE ON UPDATE NO ACTION`,
|
|
48
|
+
);
|
|
49
|
+
await queryRunner.query(
|
|
50
|
+
`ALTER TABLE "LlmLog" ADD CONSTRAINT "FK_19d277440e9b9e3ed4fa46c227a" FOREIGN KEY ("scheduledMaintenanceId") REFERENCES "ScheduledMaintenance"("_id") ON DELETE CASCADE ON UPDATE NO ACTION`,
|
|
51
|
+
);
|
|
52
|
+
await queryRunner.query(
|
|
53
|
+
`ALTER TABLE "LlmLog" ADD CONSTRAINT "FK_5c6c985581a3f85d84a2987daae" FOREIGN KEY ("userId") REFERENCES "User"("_id") ON DELETE CASCADE ON UPDATE NO ACTION`,
|
|
54
|
+
);
|
|
55
|
+
await queryRunner.query(
|
|
56
|
+
`ALTER TABLE "LlmLog" ADD CONSTRAINT "FK_bbe2bdcf251d6ef1ea43b666370" FOREIGN KEY ("deletedByUserId") REFERENCES "User"("_id") ON DELETE SET NULL ON UPDATE NO ACTION`,
|
|
57
|
+
);
|
|
58
|
+
}
|
|
59
|
+
|
|
60
|
+
public async down(queryRunner: QueryRunner): Promise<void> {
|
|
61
|
+
await queryRunner.query(
|
|
62
|
+
`ALTER TABLE "LlmLog" DROP CONSTRAINT "FK_bbe2bdcf251d6ef1ea43b666370"`,
|
|
63
|
+
);
|
|
64
|
+
await queryRunner.query(
|
|
65
|
+
`ALTER TABLE "LlmLog" DROP CONSTRAINT "FK_5c6c985581a3f85d84a2987daae"`,
|
|
66
|
+
);
|
|
67
|
+
await queryRunner.query(
|
|
68
|
+
`ALTER TABLE "LlmLog" DROP CONSTRAINT "FK_19d277440e9b9e3ed4fa46c227a"`,
|
|
69
|
+
);
|
|
70
|
+
await queryRunner.query(
|
|
71
|
+
`ALTER TABLE "LlmLog" DROP CONSTRAINT "FK_83696b0732c0a3601a9d5d7afe1"`,
|
|
72
|
+
);
|
|
73
|
+
await queryRunner.query(
|
|
74
|
+
`ALTER TABLE "LlmLog" DROP CONSTRAINT "FK_159d2b07c02788dcac8575bf4a6"`,
|
|
75
|
+
);
|
|
76
|
+
await queryRunner.query(
|
|
77
|
+
`ALTER TABLE "LlmLog" DROP CONSTRAINT "FK_bfd15354697dc30fedf7a96976e"`,
|
|
78
|
+
);
|
|
79
|
+
await queryRunner.query(
|
|
80
|
+
`ALTER TABLE "LlmLog" DROP CONSTRAINT "FK_c3c061a924f368e2cc68a233083"`,
|
|
81
|
+
);
|
|
82
|
+
await queryRunner.query(
|
|
83
|
+
`ALTER TABLE "OnCallDutyPolicyScheduleLayer" ALTER COLUMN "restrictionTimes" SET DEFAULT '{"_type": "RestrictionTimes", "value": {"restictionType": "None", "dayRestrictionTimes": null, "weeklyRestrictionTimes": []}}'`,
|
|
84
|
+
);
|
|
85
|
+
await queryRunner.query(
|
|
86
|
+
`ALTER TABLE "OnCallDutyPolicyScheduleLayer" ALTER COLUMN "rotation" SET DEFAULT '{"_type": "Recurring", "value": {"intervalType": "Day", "intervalCount": {"_type": "PositiveNumber", "value": 1}}}'`,
|
|
87
|
+
);
|
|
88
|
+
await queryRunner.query(
|
|
89
|
+
`ALTER TABLE "LlmProvider" DROP COLUMN "costPerMillionTokensInUSDCents"`,
|
|
90
|
+
);
|
|
91
|
+
await queryRunner.query(
|
|
92
|
+
`DROP INDEX "public"."IDX_5c6c985581a3f85d84a2987daa"`,
|
|
93
|
+
);
|
|
94
|
+
await queryRunner.query(
|
|
95
|
+
`DROP INDEX "public"."IDX_19d277440e9b9e3ed4fa46c227"`,
|
|
96
|
+
);
|
|
97
|
+
await queryRunner.query(
|
|
98
|
+
`DROP INDEX "public"."IDX_83696b0732c0a3601a9d5d7afe"`,
|
|
99
|
+
);
|
|
100
|
+
await queryRunner.query(
|
|
101
|
+
`DROP INDEX "public"."IDX_159d2b07c02788dcac8575bf4a"`,
|
|
102
|
+
);
|
|
103
|
+
await queryRunner.query(
|
|
104
|
+
`DROP INDEX "public"."IDX_bfd15354697dc30fedf7a96976"`,
|
|
105
|
+
);
|
|
106
|
+
await queryRunner.query(
|
|
107
|
+
`DROP INDEX "public"."IDX_c3c061a924f368e2cc68a23308"`,
|
|
108
|
+
);
|
|
109
|
+
await queryRunner.query(`DROP TABLE "LlmLog"`);
|
|
110
|
+
}
|
|
111
|
+
}
|
|
@@ -0,0 +1,39 @@
|
|
|
1
|
+
import { MigrationInterface, QueryRunner } from "typeorm";
|
|
2
|
+
|
|
3
|
+
export class MigrationName1765834537501 implements MigrationInterface {
|
|
4
|
+
public name = "MigrationName1765834537501";
|
|
5
|
+
|
|
6
|
+
public async up(queryRunner: QueryRunner): Promise<void> {
|
|
7
|
+
await queryRunner.query(`ALTER TABLE "LlmLog" DROP COLUMN "inputTokens"`);
|
|
8
|
+
await queryRunner.query(`ALTER TABLE "LlmLog" DROP COLUMN "outputTokens"`);
|
|
9
|
+
await queryRunner.query(`ALTER TABLE "LlmLog" DROP COLUMN "totalTokens"`);
|
|
10
|
+
await queryRunner.query(
|
|
11
|
+
`ALTER TABLE "LlmLog" ADD "totalTokens" integer NOT NULL DEFAULT '0'`,
|
|
12
|
+
);
|
|
13
|
+
await queryRunner.query(
|
|
14
|
+
`ALTER TABLE "OnCallDutyPolicyScheduleLayer" ALTER COLUMN "rotation" SET DEFAULT '{"_type":"Recurring","value":{"intervalType":"Day","intervalCount":{"_type":"PositiveNumber","value":1}}}'`,
|
|
15
|
+
);
|
|
16
|
+
await queryRunner.query(
|
|
17
|
+
`ALTER TABLE "OnCallDutyPolicyScheduleLayer" ALTER COLUMN "restrictionTimes" SET DEFAULT '{"_type":"RestrictionTimes","value":{"restictionType":"None","dayRestrictionTimes":null,"weeklyRestrictionTimes":[]}}'`,
|
|
18
|
+
);
|
|
19
|
+
}
|
|
20
|
+
|
|
21
|
+
public async down(queryRunner: QueryRunner): Promise<void> {
|
|
22
|
+
await queryRunner.query(
|
|
23
|
+
`ALTER TABLE "OnCallDutyPolicyScheduleLayer" ALTER COLUMN "restrictionTimes" SET DEFAULT '{"_type": "RestrictionTimes", "value": {"restictionType": "None", "dayRestrictionTimes": null, "weeklyRestrictionTimes": []}}'`,
|
|
24
|
+
);
|
|
25
|
+
await queryRunner.query(
|
|
26
|
+
`ALTER TABLE "OnCallDutyPolicyScheduleLayer" ALTER COLUMN "rotation" SET DEFAULT '{"_type": "Recurring", "value": {"intervalType": "Day", "intervalCount": {"_type": "PositiveNumber", "value": 1}}}'`,
|
|
27
|
+
);
|
|
28
|
+
await queryRunner.query(`ALTER TABLE "LlmLog" DROP COLUMN "totalTokens"`);
|
|
29
|
+
await queryRunner.query(
|
|
30
|
+
`ALTER TABLE "LlmLog" ADD "totalTokens" integer NOT NULL DEFAULT '0'`,
|
|
31
|
+
);
|
|
32
|
+
await queryRunner.query(
|
|
33
|
+
`ALTER TABLE "LlmLog" ADD "outputTokens" integer NOT NULL DEFAULT '0'`,
|
|
34
|
+
);
|
|
35
|
+
await queryRunner.query(
|
|
36
|
+
`ALTER TABLE "LlmLog" ADD "inputTokens" integer NOT NULL DEFAULT '0'`,
|
|
37
|
+
);
|
|
38
|
+
}
|
|
39
|
+
}
|
|
@@ -196,6 +196,12 @@ import { MigrationName1765477339178 } from "./1765477339178-MigrationName";
|
|
|
196
196
|
import { MigrationName1765540325149 } from "./1765540325149-MigrationName";
|
|
197
197
|
import { MigrationName1765540549739 } from "./1765540549739-MigrationName";
|
|
198
198
|
import { MigrationName1765544010078 } from "./1765544010078-MigrationName";
|
|
199
|
+
import { MigrationName1765580181582 } from "./1765580181582-MigrationName";
|
|
200
|
+
import { MigrationName1765633554715 } from "./1765633554715-MigrationName";
|
|
201
|
+
import { MigrationName1765801357168 } from "./1765801357168-MigrationName";
|
|
202
|
+
import { MigrationName1765810218488 } from "./1765810218488-MigrationName";
|
|
203
|
+
import { MigrationName1765830758857 } from "./1765830758857-MigrationName";
|
|
204
|
+
import { MigrationName1765834537501 } from "./1765834537501-MigrationName";
|
|
199
205
|
|
|
200
206
|
export default [
|
|
201
207
|
InitialMigration,
|
|
@@ -396,4 +402,10 @@ export default [
|
|
|
396
402
|
MigrationName1765540325149,
|
|
397
403
|
MigrationName1765540549739,
|
|
398
404
|
MigrationName1765544010078,
|
|
405
|
+
MigrationName1765580181582,
|
|
406
|
+
MigrationName1765633554715,
|
|
407
|
+
MigrationName1765801357168,
|
|
408
|
+
MigrationName1765810218488,
|
|
409
|
+
MigrationName1765830758857,
|
|
410
|
+
MigrationName1765834537501,
|
|
399
411
|
];
|
|
@@ -0,0 +1,247 @@
|
|
|
1
|
+
import {
|
|
2
|
+
IsBillingEnabled,
|
|
3
|
+
NotificationSlackWebhookOnSubscriptionUpdate,
|
|
4
|
+
} from "../EnvironmentConfig";
|
|
5
|
+
import logger from "../Utils/Logger";
|
|
6
|
+
import BaseService from "./BaseService";
|
|
7
|
+
import BillingService from "./BillingService";
|
|
8
|
+
import ProjectService from "./ProjectService";
|
|
9
|
+
import BadDataException from "../../Types/Exception/BadDataException";
|
|
10
|
+
import ObjectID from "../../Types/ObjectID";
|
|
11
|
+
import Project from "../../Models/DatabaseModels/Project";
|
|
12
|
+
import CaptureSpan from "../Utils/Telemetry/CaptureSpan";
|
|
13
|
+
import SlackUtil from "../Utils/Workspace/Slack/Slack";
|
|
14
|
+
import URL from "../../Types/API/URL";
|
|
15
|
+
import Exception from "../../Types/Exception/Exception";
|
|
16
|
+
|
|
17
|
+
export class AIBillingService extends BaseService {
|
|
18
|
+
public constructor() {
|
|
19
|
+
super();
|
|
20
|
+
}
|
|
21
|
+
|
|
22
|
+
@CaptureSpan()
|
|
23
|
+
public async rechargeBalance(
|
|
24
|
+
projectId: ObjectID,
|
|
25
|
+
amountInUSD: number,
|
|
26
|
+
): Promise<number> {
|
|
27
|
+
if (!IsBillingEnabled) {
|
|
28
|
+
throw new BadDataException("Billing is not enabled");
|
|
29
|
+
}
|
|
30
|
+
|
|
31
|
+
const project: Project | null = await ProjectService.findOneById({
|
|
32
|
+
id: projectId,
|
|
33
|
+
select: {
|
|
34
|
+
aiCurrentBalanceInUSDCents: true,
|
|
35
|
+
enableAutoRechargeAiBalance: true,
|
|
36
|
+
enableAi: true,
|
|
37
|
+
autoAiRechargeByBalanceInUSD: true,
|
|
38
|
+
autoRechargeAiWhenCurrentBalanceFallsInUSD: true,
|
|
39
|
+
paymentProviderCustomerId: true,
|
|
40
|
+
name: true,
|
|
41
|
+
failedAiBalanceChargeNotificationSentToOwners: true,
|
|
42
|
+
},
|
|
43
|
+
props: {
|
|
44
|
+
isRoot: true,
|
|
45
|
+
},
|
|
46
|
+
});
|
|
47
|
+
|
|
48
|
+
if (!project) {
|
|
49
|
+
return 0;
|
|
50
|
+
}
|
|
51
|
+
|
|
52
|
+
try {
|
|
53
|
+
if (
|
|
54
|
+
!(await BillingService.hasPaymentMethods(
|
|
55
|
+
project.paymentProviderCustomerId!,
|
|
56
|
+
))
|
|
57
|
+
) {
|
|
58
|
+
if (!project.failedAiBalanceChargeNotificationSentToOwners) {
|
|
59
|
+
await ProjectService.updateOneById({
|
|
60
|
+
data: {
|
|
61
|
+
failedAiBalanceChargeNotificationSentToOwners: true,
|
|
62
|
+
},
|
|
63
|
+
id: project.id!,
|
|
64
|
+
props: {
|
|
65
|
+
isRoot: true,
|
|
66
|
+
},
|
|
67
|
+
});
|
|
68
|
+
await ProjectService.sendEmailToProjectOwners(
|
|
69
|
+
project.id!,
|
|
70
|
+
"ACTION REQUIRED: AI Balance Recharge Failed for project - " +
|
|
71
|
+
(project.name || ""),
|
|
72
|
+
`We have tried to recharge your AI balance for project - ${
|
|
73
|
+
project.name || ""
|
|
74
|
+
} and failed. We could not find a payment method for the project. Please add a payment method in Project Settings.`,
|
|
75
|
+
);
|
|
76
|
+
}
|
|
77
|
+
throw new BadDataException(
|
|
78
|
+
"No payment methods found for the project. Please add a payment method in Project Settings to continue.",
|
|
79
|
+
);
|
|
80
|
+
}
|
|
81
|
+
|
|
82
|
+
// recharge balance
|
|
83
|
+
const updatedAmount: number = Math.floor(
|
|
84
|
+
(project.aiCurrentBalanceInUSDCents || 0) + amountInUSD * 100,
|
|
85
|
+
);
|
|
86
|
+
|
|
87
|
+
// If the recharge is successful, then update the project balance.
|
|
88
|
+
await BillingService.generateInvoiceAndChargeCustomer(
|
|
89
|
+
project.paymentProviderCustomerId!,
|
|
90
|
+
"AI Balance Recharge",
|
|
91
|
+
amountInUSD,
|
|
92
|
+
);
|
|
93
|
+
|
|
94
|
+
await ProjectService.updateOneById({
|
|
95
|
+
data: {
|
|
96
|
+
aiCurrentBalanceInUSDCents: updatedAmount,
|
|
97
|
+
failedAiBalanceChargeNotificationSentToOwners: false, // reset this flag
|
|
98
|
+
lowAiBalanceNotificationSentToOwners: false, // reset this flag
|
|
99
|
+
notEnabledAiNotificationSentToOwners: false,
|
|
100
|
+
},
|
|
101
|
+
id: project.id!,
|
|
102
|
+
props: {
|
|
103
|
+
isRoot: true,
|
|
104
|
+
},
|
|
105
|
+
});
|
|
106
|
+
|
|
107
|
+
await ProjectService.sendEmailToProjectOwners(
|
|
108
|
+
project.id!,
|
|
109
|
+
"AI Balance Recharge Successful for project - " + (project.name || ""),
|
|
110
|
+
`We have successfully recharged your AI balance for project - ${
|
|
111
|
+
project.name || ""
|
|
112
|
+
} by ${amountInUSD} USD. Your current balance is ${
|
|
113
|
+
updatedAmount / 100
|
|
114
|
+
} USD.`,
|
|
115
|
+
);
|
|
116
|
+
|
|
117
|
+
// Send Slack notification for balance refill
|
|
118
|
+
this.sendBalanceRefillSlackNotification({
|
|
119
|
+
project: project,
|
|
120
|
+
amountInUSD: amountInUSD,
|
|
121
|
+
currentBalanceInUSD: updatedAmount / 100,
|
|
122
|
+
}).catch((error: Exception) => {
|
|
123
|
+
logger.error(
|
|
124
|
+
"Error sending slack message for AI balance refill: " + error,
|
|
125
|
+
);
|
|
126
|
+
});
|
|
127
|
+
|
|
128
|
+
project.aiCurrentBalanceInUSDCents = updatedAmount;
|
|
129
|
+
|
|
130
|
+
return updatedAmount;
|
|
131
|
+
} catch (err) {
|
|
132
|
+
await ProjectService.updateOneById({
|
|
133
|
+
data: {
|
|
134
|
+
failedAiBalanceChargeNotificationSentToOwners: true,
|
|
135
|
+
},
|
|
136
|
+
id: project.id!,
|
|
137
|
+
props: {
|
|
138
|
+
isRoot: true,
|
|
139
|
+
},
|
|
140
|
+
});
|
|
141
|
+
await ProjectService.sendEmailToProjectOwners(
|
|
142
|
+
project.id!,
|
|
143
|
+
"ACTION REQUIRED: AI Balance Recharge Failed for project - " +
|
|
144
|
+
(project.name || ""),
|
|
145
|
+
`We have tried to recharge your AI balance for project - ${
|
|
146
|
+
project.name || ""
|
|
147
|
+
} and failed. Please make sure your payment method is up to date and has sufficient balance. You can add new payment methods in Project Settings.`,
|
|
148
|
+
);
|
|
149
|
+
logger.error(err);
|
|
150
|
+
throw err;
|
|
151
|
+
}
|
|
152
|
+
}
|
|
153
|
+
|
|
154
|
+
@CaptureSpan()
|
|
155
|
+
public async rechargeIfBalanceIsLow(
|
|
156
|
+
projectId: ObjectID,
|
|
157
|
+
options?: {
|
|
158
|
+
autoAiRechargeByBalanceInUSD: number;
|
|
159
|
+
autoRechargeAiWhenCurrentBalanceFallsInUSD: number;
|
|
160
|
+
enableAutoRechargeAiBalance: boolean;
|
|
161
|
+
},
|
|
162
|
+
): Promise<number> {
|
|
163
|
+
let project: Project | null = null;
|
|
164
|
+
if (projectId && IsBillingEnabled) {
|
|
165
|
+
// check payment methods.
|
|
166
|
+
|
|
167
|
+
project = await ProjectService.findOneById({
|
|
168
|
+
id: projectId,
|
|
169
|
+
select: {
|
|
170
|
+
aiCurrentBalanceInUSDCents: true,
|
|
171
|
+
enableAutoRechargeAiBalance: true,
|
|
172
|
+
autoAiRechargeByBalanceInUSD: true,
|
|
173
|
+
autoRechargeAiWhenCurrentBalanceFallsInUSD: true,
|
|
174
|
+
},
|
|
175
|
+
props: {
|
|
176
|
+
isRoot: true,
|
|
177
|
+
},
|
|
178
|
+
});
|
|
179
|
+
|
|
180
|
+
const autoRechargeAiWhenCurrentBalanceFallsInUSD: number =
|
|
181
|
+
options?.autoRechargeAiWhenCurrentBalanceFallsInUSD ||
|
|
182
|
+
project?.autoRechargeAiWhenCurrentBalanceFallsInUSD ||
|
|
183
|
+
0;
|
|
184
|
+
const autoAiRechargeByBalanceInUSD: number =
|
|
185
|
+
options?.autoAiRechargeByBalanceInUSD ||
|
|
186
|
+
project?.autoAiRechargeByBalanceInUSD ||
|
|
187
|
+
0;
|
|
188
|
+
|
|
189
|
+
const enableAutoRechargeAiBalance: boolean = options
|
|
190
|
+
? options.enableAutoRechargeAiBalance
|
|
191
|
+
: project?.enableAutoRechargeAiBalance || false;
|
|
192
|
+
|
|
193
|
+
if (!project) {
|
|
194
|
+
return 0;
|
|
195
|
+
}
|
|
196
|
+
|
|
197
|
+
if (
|
|
198
|
+
enableAutoRechargeAiBalance &&
|
|
199
|
+
autoAiRechargeByBalanceInUSD &&
|
|
200
|
+
autoRechargeAiWhenCurrentBalanceFallsInUSD
|
|
201
|
+
) {
|
|
202
|
+
if (
|
|
203
|
+
(project.aiCurrentBalanceInUSDCents || 0) / 100 <
|
|
204
|
+
autoRechargeAiWhenCurrentBalanceFallsInUSD
|
|
205
|
+
) {
|
|
206
|
+
const updatedAmount: number = await this.rechargeBalance(
|
|
207
|
+
projectId,
|
|
208
|
+
autoAiRechargeByBalanceInUSD,
|
|
209
|
+
);
|
|
210
|
+
project.aiCurrentBalanceInUSDCents = updatedAmount;
|
|
211
|
+
}
|
|
212
|
+
}
|
|
213
|
+
}
|
|
214
|
+
|
|
215
|
+
return project?.aiCurrentBalanceInUSDCents || 0;
|
|
216
|
+
}
|
|
217
|
+
|
|
218
|
+
@CaptureSpan()
|
|
219
|
+
private async sendBalanceRefillSlackNotification(data: {
|
|
220
|
+
project: Project;
|
|
221
|
+
amountInUSD: number;
|
|
222
|
+
currentBalanceInUSD: number;
|
|
223
|
+
}): Promise<void> {
|
|
224
|
+
const { project, amountInUSD, currentBalanceInUSD } = data;
|
|
225
|
+
|
|
226
|
+
if (NotificationSlackWebhookOnSubscriptionUpdate) {
|
|
227
|
+
const slackMessage: string = `*AI Balance Refilled:*
|
|
228
|
+
*Project Name:* ${project.name?.toString() || "N/A"}
|
|
229
|
+
*Project ID:* ${project.id?.toString() || "N/A"}
|
|
230
|
+
*Refill Amount:* $${amountInUSD} USD
|
|
231
|
+
*Current Balance:* $${currentBalanceInUSD} USD
|
|
232
|
+
|
|
233
|
+
${project.createdOwnerName && project.createdOwnerEmail ? `*Project Created By:* ${project.createdOwnerName.toString()} (${project.createdOwnerEmail.toString()})` : ""}`;
|
|
234
|
+
|
|
235
|
+
SlackUtil.sendMessageToChannelViaIncomingWebhook({
|
|
236
|
+
url: URL.fromString(NotificationSlackWebhookOnSubscriptionUpdate),
|
|
237
|
+
text: slackMessage,
|
|
238
|
+
}).catch((error: Exception) => {
|
|
239
|
+
logger.error(
|
|
240
|
+
"Error sending slack message for AI balance refill: " + error,
|
|
241
|
+
);
|
|
242
|
+
});
|
|
243
|
+
}
|
|
244
|
+
}
|
|
245
|
+
}
|
|
246
|
+
|
|
247
|
+
export default new AIBillingService();
|