clhq-credits-client 1.1.0-alpha.116
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/.versionrc +3 -0
- package/README.md +99 -0
- package/dist/credits-lambda-client.d.ts +45 -0
- package/dist/credits-lambda-client.d.ts.map +1 -0
- package/dist/credits-lambda-client.js +121 -0
- package/dist/credits-lambda-client.js.map +1 -0
- package/dist/index.d.ts +3 -0
- package/dist/index.d.ts.map +1 -0
- package/dist/index.js +23 -0
- package/dist/index.js.map +1 -0
- package/dist/types.d.ts +88 -0
- package/dist/types.d.ts.map +1 -0
- package/dist/types.js +30 -0
- package/dist/types.js.map +1 -0
- package/package.json +39 -0
- package/src/credits-lambda-client.ts +165 -0
- package/src/index.ts +5 -0
- package/src/types.ts +116 -0
- package/tsconfig.json +19 -0
package/.versionrc
ADDED
package/README.md
ADDED
|
@@ -0,0 +1,99 @@
|
|
|
1
|
+
# CLHQ Credits Client
|
|
2
|
+
|
|
3
|
+
A TypeScript client for invoking the CLHQ Credits Service Lambda functions.
|
|
4
|
+
|
|
5
|
+
## Installation
|
|
6
|
+
|
|
7
|
+
```bash
|
|
8
|
+
npm install clhq-credits-client
|
|
9
|
+
# or
|
|
10
|
+
yarn add clhq-credits-client
|
|
11
|
+
```
|
|
12
|
+
|
|
13
|
+
## Usage
|
|
14
|
+
|
|
15
|
+
```typescript
|
|
16
|
+
import { CreditsLambdaClient, OperationType } from 'clhq-credits-client';
|
|
17
|
+
|
|
18
|
+
// Initialize client
|
|
19
|
+
const creditsClient = new CreditsLambdaClient({
|
|
20
|
+
region: 'ap-southeast-2',
|
|
21
|
+
stage: 'dev'
|
|
22
|
+
});
|
|
23
|
+
|
|
24
|
+
// Reserve credits before operation
|
|
25
|
+
const reservation = await creditsClient.reserveCredits({
|
|
26
|
+
userId: 'user-123',
|
|
27
|
+
operationType: OperationType.VIDEO_EXPORT_1080P,
|
|
28
|
+
estimatedCredits: 8,
|
|
29
|
+
operationId: 'video-export-456'
|
|
30
|
+
});
|
|
31
|
+
|
|
32
|
+
// Execute operation...
|
|
33
|
+
|
|
34
|
+
// Finalize credits after completion
|
|
35
|
+
const finalization = await creditsClient.finalizeCredits({
|
|
36
|
+
reservationId: reservation.reservationId,
|
|
37
|
+
actualCredits: 8,
|
|
38
|
+
resultUrl: 'https://s3.amazonaws.com/bucket/video.mp4'
|
|
39
|
+
});
|
|
40
|
+
|
|
41
|
+
// Or use the convenience method
|
|
42
|
+
const result = await creditsClient.executeWithCredits(
|
|
43
|
+
() => performVideoExport(), // Your operation
|
|
44
|
+
{
|
|
45
|
+
userId: 'user-123',
|
|
46
|
+
operationType: OperationType.VIDEO_EXPORT_1080P,
|
|
47
|
+
estimatedCredits: 8,
|
|
48
|
+
operationId: 'video-export-456'
|
|
49
|
+
},
|
|
50
|
+
(exportResult) => ({
|
|
51
|
+
reservationId: reservation.reservationId,
|
|
52
|
+
actualCredits: 8,
|
|
53
|
+
resultUrl: exportResult.url
|
|
54
|
+
})
|
|
55
|
+
);
|
|
56
|
+
```
|
|
57
|
+
|
|
58
|
+
## API Methods
|
|
59
|
+
|
|
60
|
+
### `reserveCredits(params)`
|
|
61
|
+
Reserve credits before starting an operation.
|
|
62
|
+
|
|
63
|
+
### `finalizeCredits(params)`
|
|
64
|
+
Finalize credit consumption after operation completes.
|
|
65
|
+
|
|
66
|
+
### `releaseCredits(params)`
|
|
67
|
+
Release reserved credits if operation fails.
|
|
68
|
+
|
|
69
|
+
### `getBalance(params)`
|
|
70
|
+
Get user's current credit balance.
|
|
71
|
+
|
|
72
|
+
### `estimateCost(params)`
|
|
73
|
+
Estimate credit cost for an operation.
|
|
74
|
+
|
|
75
|
+
### `executeWithCredits(operation, reserveParams, finalizeParams)`
|
|
76
|
+
Convenience method that handles the full reserve → execute → finalize flow.
|
|
77
|
+
|
|
78
|
+
## Operation Types
|
|
79
|
+
|
|
80
|
+
- `VIDEO_EXPORT_720P`, `VIDEO_EXPORT_1080P`, `VIDEO_EXPORT_4K`
|
|
81
|
+
- `BACKGROUND_REMOVAL`, `AI_IMAGE_GENERATION`, `SUBTITLE_GENERATION`
|
|
82
|
+
- `HLS_TRANSCODING`, `REMOTION_RENDER_*` variants
|
|
83
|
+
- And more...
|
|
84
|
+
|
|
85
|
+
## Configuration
|
|
86
|
+
|
|
87
|
+
The client automatically detects AWS region and stage from environment variables:
|
|
88
|
+
|
|
89
|
+
- `AWS_REGION` (default: 'ap-southeast-2')
|
|
90
|
+
- `STAGE` (default: 'dev')
|
|
91
|
+
|
|
92
|
+
Or you can pass them explicitly to the constructor.
|
|
93
|
+
|
|
94
|
+
## Error Handling
|
|
95
|
+
|
|
96
|
+
The client throws specific errors:
|
|
97
|
+
- `ResourceNotFoundException`: Credits service not available
|
|
98
|
+
- `TooManyRequestsException`: Rate limited
|
|
99
|
+
- Business logic errors from the credits service
|
|
@@ -0,0 +1,45 @@
|
|
|
1
|
+
import { ReserveCreditsRequest, ReserveCreditsResponse, FinalizeCreditsRequest, FinalizeCreditsResponse, ReleaseCreditsRequest, ReleaseCreditsResponse, GetBalanceRequest, GetBalanceResponse, EstimateCostRequest, EstimateCostResponse } from './types';
|
|
2
|
+
export declare class CreditsLambdaClient {
|
|
3
|
+
private lambda;
|
|
4
|
+
private stage;
|
|
5
|
+
constructor(options?: {
|
|
6
|
+
region?: string;
|
|
7
|
+
stage?: string;
|
|
8
|
+
});
|
|
9
|
+
/**
|
|
10
|
+
* Get the Lambda function name for a specific handler
|
|
11
|
+
*/
|
|
12
|
+
private getFunctionName;
|
|
13
|
+
/**
|
|
14
|
+
* Generic method to invoke Lambda functions with proper error handling
|
|
15
|
+
*/
|
|
16
|
+
private invoke;
|
|
17
|
+
/**
|
|
18
|
+
* Reserve credits before starting an operation
|
|
19
|
+
*/
|
|
20
|
+
reserveCredits(params: ReserveCreditsRequest): Promise<ReserveCreditsResponse>;
|
|
21
|
+
/**
|
|
22
|
+
* Finalize credit consumption after operation completes
|
|
23
|
+
*/
|
|
24
|
+
finalizeCredits(params: FinalizeCreditsRequest): Promise<FinalizeCreditsResponse>;
|
|
25
|
+
/**
|
|
26
|
+
* Release reserved credits if operation fails
|
|
27
|
+
*/
|
|
28
|
+
releaseCredits(params: ReleaseCreditsRequest): Promise<ReleaseCreditsResponse>;
|
|
29
|
+
/**
|
|
30
|
+
* Get user's credit balance
|
|
31
|
+
*/
|
|
32
|
+
getBalance(params: GetBalanceRequest): Promise<GetBalanceResponse>;
|
|
33
|
+
/**
|
|
34
|
+
* Estimate credit cost for an operation
|
|
35
|
+
*/
|
|
36
|
+
estimateCost(params: EstimateCostRequest): Promise<EstimateCostResponse>;
|
|
37
|
+
/**
|
|
38
|
+
* Convenience method: Reserve and execute operation with automatic finalization
|
|
39
|
+
*/
|
|
40
|
+
executeWithCredits<T>(operation: () => Promise<T>, reserveParams: ReserveCreditsRequest, finalizeParams: (result: T) => FinalizeCreditsRequest): Promise<{
|
|
41
|
+
result: T;
|
|
42
|
+
creditsUsed: number;
|
|
43
|
+
}>;
|
|
44
|
+
}
|
|
45
|
+
//# sourceMappingURL=credits-lambda-client.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"credits-lambda-client.d.ts","sourceRoot":"","sources":["../src/credits-lambda-client.ts"],"names":[],"mappings":"AACA,OAAO,EACL,qBAAqB,EACrB,sBAAsB,EACtB,sBAAsB,EACtB,uBAAuB,EACvB,qBAAqB,EACrB,sBAAsB,EACtB,iBAAiB,EACjB,kBAAkB,EAClB,mBAAmB,EACnB,oBAAoB,EACrB,MAAM,SAAS,CAAC;AAEjB,qBAAa,mBAAmB;IAC9B,OAAO,CAAC,MAAM,CAAe;IAC7B,OAAO,CAAC,KAAK,CAAS;gBAEV,OAAO,CAAC,EAAE;QAAE,MAAM,CAAC,EAAE,MAAM,CAAC;QAAC,KAAK,CAAC,EAAE,MAAM,CAAA;KAAE;IAOzD;;OAEG;IACH,OAAO,CAAC,eAAe;IAIvB;;OAEG;YACW,MAAM;IAsCpB;;OAEG;IACG,cAAc,CAClB,MAAM,EAAE,qBAAqB,GAC5B,OAAO,CAAC,sBAAsB,CAAC;IAIlC;;OAEG;IACG,eAAe,CACnB,MAAM,EAAE,sBAAsB,GAC7B,OAAO,CAAC,uBAAuB,CAAC;IAInC;;OAEG;IACG,cAAc,CAClB,MAAM,EAAE,qBAAqB,GAC5B,OAAO,CAAC,sBAAsB,CAAC;IAIlC;;OAEG;IACG,UAAU,CAAC,MAAM,EAAE,iBAAiB,GAAG,OAAO,CAAC,kBAAkB,CAAC;IAIxE;;OAEG;IACG,YAAY,CAChB,MAAM,EAAE,mBAAmB,GAC1B,OAAO,CAAC,oBAAoB,CAAC;IAIhC;;OAEG;IACG,kBAAkB,CAAC,CAAC,EACxB,SAAS,EAAE,MAAM,OAAO,CAAC,CAAC,CAAC,EAC3B,aAAa,EAAE,qBAAqB,EACpC,cAAc,EAAE,CAAC,MAAM,EAAE,CAAC,KAAK,sBAAsB,GACpD,OAAO,CAAC;QAAE,MAAM,EAAE,CAAC,CAAC;QAAC,WAAW,EAAE,MAAM,CAAA;KAAE,CAAC;CAyC/C"}
|
|
@@ -0,0 +1,121 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
+
exports.CreditsLambdaClient = void 0;
|
|
4
|
+
const client_lambda_1 = require("@aws-sdk/client-lambda");
|
|
5
|
+
class CreditsLambdaClient {
|
|
6
|
+
lambda;
|
|
7
|
+
stage;
|
|
8
|
+
constructor(options) {
|
|
9
|
+
this.lambda = new client_lambda_1.LambdaClient({
|
|
10
|
+
region: options?.region || process.env.AWS_REGION || 'ap-southeast-2',
|
|
11
|
+
});
|
|
12
|
+
this.stage = options?.stage || process.env.STAGE || 'dev';
|
|
13
|
+
}
|
|
14
|
+
/**
|
|
15
|
+
* Get the Lambda function name for a specific handler
|
|
16
|
+
*/
|
|
17
|
+
getFunctionName(handler) {
|
|
18
|
+
return `clippy-credits-service-${this.stage}-${handler}`;
|
|
19
|
+
}
|
|
20
|
+
/**
|
|
21
|
+
* Generic method to invoke Lambda functions with proper error handling
|
|
22
|
+
*/
|
|
23
|
+
async invoke(handler, payload) {
|
|
24
|
+
const command = new client_lambda_1.InvokeCommand({
|
|
25
|
+
FunctionName: this.getFunctionName(handler),
|
|
26
|
+
Payload: Buffer.from(JSON.stringify(payload)),
|
|
27
|
+
});
|
|
28
|
+
try {
|
|
29
|
+
const response = await this.lambda.send(command);
|
|
30
|
+
if (response.FunctionError) {
|
|
31
|
+
const errorPayload = JSON.parse(Buffer.from(response.Payload).toString());
|
|
32
|
+
throw new Error(errorPayload.errorMessage || 'Lambda invocation failed');
|
|
33
|
+
}
|
|
34
|
+
const result = JSON.parse(Buffer.from(response.Payload).toString());
|
|
35
|
+
if (!result.success && result.error) {
|
|
36
|
+
throw new Error(result.error);
|
|
37
|
+
}
|
|
38
|
+
return result;
|
|
39
|
+
}
|
|
40
|
+
catch (error) {
|
|
41
|
+
// Re-throw Lambda invocation errors
|
|
42
|
+
if (error.name === 'ResourceNotFoundException') {
|
|
43
|
+
throw new Error(`Credits service not available: ${handler}`);
|
|
44
|
+
}
|
|
45
|
+
if (error.name === 'TooManyRequestsException') {
|
|
46
|
+
throw new Error('Credits service rate limited');
|
|
47
|
+
}
|
|
48
|
+
throw error;
|
|
49
|
+
}
|
|
50
|
+
}
|
|
51
|
+
/**
|
|
52
|
+
* Reserve credits before starting an operation
|
|
53
|
+
*/
|
|
54
|
+
async reserveCredits(params) {
|
|
55
|
+
return this.invoke('reserve', params);
|
|
56
|
+
}
|
|
57
|
+
/**
|
|
58
|
+
* Finalize credit consumption after operation completes
|
|
59
|
+
*/
|
|
60
|
+
async finalizeCredits(params) {
|
|
61
|
+
return this.invoke('finalize', params);
|
|
62
|
+
}
|
|
63
|
+
/**
|
|
64
|
+
* Release reserved credits if operation fails
|
|
65
|
+
*/
|
|
66
|
+
async releaseCredits(params) {
|
|
67
|
+
return this.invoke('release', params);
|
|
68
|
+
}
|
|
69
|
+
/**
|
|
70
|
+
* Get user's credit balance
|
|
71
|
+
*/
|
|
72
|
+
async getBalance(params) {
|
|
73
|
+
return this.invoke('balance', params);
|
|
74
|
+
}
|
|
75
|
+
/**
|
|
76
|
+
* Estimate credit cost for an operation
|
|
77
|
+
*/
|
|
78
|
+
async estimateCost(params) {
|
|
79
|
+
return this.invoke('estimate', params);
|
|
80
|
+
}
|
|
81
|
+
/**
|
|
82
|
+
* Convenience method: Reserve and execute operation with automatic finalization
|
|
83
|
+
*/
|
|
84
|
+
async executeWithCredits(operation, reserveParams, finalizeParams) {
|
|
85
|
+
// Reserve credits
|
|
86
|
+
const reservation = await this.reserveCredits(reserveParams);
|
|
87
|
+
if (!reservation.success || !reservation.reservationId) {
|
|
88
|
+
throw new Error(reservation.error || 'Failed to reserve credits');
|
|
89
|
+
}
|
|
90
|
+
try {
|
|
91
|
+
// Execute the operation
|
|
92
|
+
const result = await operation();
|
|
93
|
+
// Finalize credits
|
|
94
|
+
const finalizeRequest = finalizeParams(result);
|
|
95
|
+
finalizeRequest.reservationId = reservation.reservationId;
|
|
96
|
+
const finalization = await this.finalizeCredits(finalizeRequest);
|
|
97
|
+
if (!finalization.success) {
|
|
98
|
+
throw new Error(finalization.error || 'Failed to finalize credits');
|
|
99
|
+
}
|
|
100
|
+
return {
|
|
101
|
+
result,
|
|
102
|
+
creditsUsed: finalization.creditsUsed || 0,
|
|
103
|
+
};
|
|
104
|
+
}
|
|
105
|
+
catch (error) {
|
|
106
|
+
// Release credits on failure
|
|
107
|
+
try {
|
|
108
|
+
await this.releaseCredits({
|
|
109
|
+
reservationId: reservation.reservationId,
|
|
110
|
+
reason: error instanceof Error ? error.message : 'Operation failed',
|
|
111
|
+
});
|
|
112
|
+
}
|
|
113
|
+
catch (releaseError) {
|
|
114
|
+
console.warn('Failed to release credits:', releaseError);
|
|
115
|
+
}
|
|
116
|
+
throw error;
|
|
117
|
+
}
|
|
118
|
+
}
|
|
119
|
+
}
|
|
120
|
+
exports.CreditsLambdaClient = CreditsLambdaClient;
|
|
121
|
+
//# sourceMappingURL=credits-lambda-client.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"credits-lambda-client.js","sourceRoot":"","sources":["../src/credits-lambda-client.ts"],"names":[],"mappings":"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"}
|
package/dist/index.d.ts
ADDED
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"AACA,OAAO,EAAE,mBAAmB,EAAE,MAAM,yBAAyB,CAAC;AAG9D,cAAc,SAAS,CAAC"}
|
package/dist/index.js
ADDED
|
@@ -0,0 +1,23 @@
|
|
|
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
|
+
exports.CreditsLambdaClient = void 0;
|
|
18
|
+
// Main client class
|
|
19
|
+
var credits_lambda_client_1 = require("./credits-lambda-client");
|
|
20
|
+
Object.defineProperty(exports, "CreditsLambdaClient", { enumerable: true, get: function () { return credits_lambda_client_1.CreditsLambdaClient; } });
|
|
21
|
+
// All types
|
|
22
|
+
__exportStar(require("./types"), exports);
|
|
23
|
+
//# sourceMappingURL=index.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"index.js","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":";;;;;;;;;;;;;;;;;AAAA,oBAAoB;AACpB,iEAA8D;AAArD,4HAAA,mBAAmB,OAAA;AAE5B,YAAY;AACZ,0CAAwB"}
|
package/dist/types.d.ts
ADDED
|
@@ -0,0 +1,88 @@
|
|
|
1
|
+
export declare enum OperationType {
|
|
2
|
+
VIDEO_EXPORT_720P = "VIDEO_EXPORT_720P",
|
|
3
|
+
VIDEO_EXPORT_1080P = "VIDEO_EXPORT_1080P",
|
|
4
|
+
VIDEO_EXPORT_4K = "VIDEO_EXPORT_4K",
|
|
5
|
+
GIF_EXPORT = "GIF_EXPORT",
|
|
6
|
+
AUDIO_EXTRACTION = "AUDIO_EXTRACTION",
|
|
7
|
+
BACKGROUND_REMOVAL = "BACKGROUND_REMOVAL",
|
|
8
|
+
AI_IMAGE_GENERATION = "AI_IMAGE_GENERATION",
|
|
9
|
+
AI_TEXT_COMPLETION = "AI_TEXT_COMPLETION",
|
|
10
|
+
SUBTITLE_GENERATION = "SUBTITLE_GENERATION",
|
|
11
|
+
HLS_TRANSCODING = "HLS_TRANSCODING",
|
|
12
|
+
THUMBNAIL_GENERATION = "THUMBNAIL_GENERATION",
|
|
13
|
+
FILMSTRIP_GENERATION = "FILMSTRIP_GENERATION",
|
|
14
|
+
REMOTION_RENDER_720P = "REMOTION_RENDER_720P",
|
|
15
|
+
REMOTION_RENDER_1080P = "REMOTION_RENDER_1080P",
|
|
16
|
+
REMOTION_RENDER_4K = "REMOTION_RENDER_4K",
|
|
17
|
+
REMOTION_THUMBNAIL = "REMOTION_THUMBNAIL"
|
|
18
|
+
}
|
|
19
|
+
export interface ReserveCreditsRequest {
|
|
20
|
+
userId: string;
|
|
21
|
+
operationType: OperationType;
|
|
22
|
+
estimatedCredits: number;
|
|
23
|
+
operationId: string;
|
|
24
|
+
metadata?: Record<string, any>;
|
|
25
|
+
}
|
|
26
|
+
export interface FinalizeCreditsRequest {
|
|
27
|
+
reservationId: string;
|
|
28
|
+
actualCredits: number;
|
|
29
|
+
resultUrl?: string;
|
|
30
|
+
}
|
|
31
|
+
export interface ReleaseCreditsRequest {
|
|
32
|
+
reservationId: string;
|
|
33
|
+
reason?: string;
|
|
34
|
+
}
|
|
35
|
+
export interface GetBalanceRequest {
|
|
36
|
+
userId: string;
|
|
37
|
+
}
|
|
38
|
+
export interface EstimateCostRequest {
|
|
39
|
+
userId: string;
|
|
40
|
+
operationType: OperationType;
|
|
41
|
+
durationMinutes?: number;
|
|
42
|
+
durationSeconds?: number;
|
|
43
|
+
variants?: number;
|
|
44
|
+
isHighRes?: boolean;
|
|
45
|
+
}
|
|
46
|
+
export interface ReserveCreditsResponse {
|
|
47
|
+
success: boolean;
|
|
48
|
+
reservationId?: string;
|
|
49
|
+
creditsReserved?: number;
|
|
50
|
+
newAvailableBalance?: number;
|
|
51
|
+
error?: string;
|
|
52
|
+
}
|
|
53
|
+
export interface FinalizeCreditsResponse {
|
|
54
|
+
success: boolean;
|
|
55
|
+
transactionId?: string;
|
|
56
|
+
creditsUsed?: number;
|
|
57
|
+
newBalance?: number;
|
|
58
|
+
refundedCredits?: number;
|
|
59
|
+
error?: string;
|
|
60
|
+
}
|
|
61
|
+
export interface ReleaseCreditsResponse {
|
|
62
|
+
success: boolean;
|
|
63
|
+
creditsReleased?: number;
|
|
64
|
+
newAvailableBalance?: number;
|
|
65
|
+
error?: string;
|
|
66
|
+
}
|
|
67
|
+
export interface GetBalanceResponse {
|
|
68
|
+
success: boolean;
|
|
69
|
+
totalEarned?: number;
|
|
70
|
+
totalUsed?: number;
|
|
71
|
+
currentBalance?: number;
|
|
72
|
+
expiringCredits?: number;
|
|
73
|
+
expiringDate?: string;
|
|
74
|
+
error?: string;
|
|
75
|
+
}
|
|
76
|
+
export interface EstimateCostResponse {
|
|
77
|
+
success: boolean;
|
|
78
|
+
estimatedCredits?: number;
|
|
79
|
+
breakdown?: {
|
|
80
|
+
baseCost: number;
|
|
81
|
+
durationCost: number;
|
|
82
|
+
modifierCost: number;
|
|
83
|
+
};
|
|
84
|
+
currentBalance?: number;
|
|
85
|
+
canProceed?: boolean;
|
|
86
|
+
error?: string;
|
|
87
|
+
}
|
|
88
|
+
//# sourceMappingURL=types.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"types.d.ts","sourceRoot":"","sources":["../src/types.ts"],"names":[],"mappings":"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"}
|
package/dist/types.js
ADDED
|
@@ -0,0 +1,30 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
// ============================================
|
|
3
|
+
// Operation Types for Credit Calculation
|
|
4
|
+
// ============================================
|
|
5
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
6
|
+
exports.OperationType = void 0;
|
|
7
|
+
var OperationType;
|
|
8
|
+
(function (OperationType) {
|
|
9
|
+
// Video exports
|
|
10
|
+
OperationType["VIDEO_EXPORT_720P"] = "VIDEO_EXPORT_720P";
|
|
11
|
+
OperationType["VIDEO_EXPORT_1080P"] = "VIDEO_EXPORT_1080P";
|
|
12
|
+
OperationType["VIDEO_EXPORT_4K"] = "VIDEO_EXPORT_4K";
|
|
13
|
+
OperationType["GIF_EXPORT"] = "GIF_EXPORT";
|
|
14
|
+
OperationType["AUDIO_EXTRACTION"] = "AUDIO_EXTRACTION";
|
|
15
|
+
// AI operations
|
|
16
|
+
OperationType["BACKGROUND_REMOVAL"] = "BACKGROUND_REMOVAL";
|
|
17
|
+
OperationType["AI_IMAGE_GENERATION"] = "AI_IMAGE_GENERATION";
|
|
18
|
+
OperationType["AI_TEXT_COMPLETION"] = "AI_TEXT_COMPLETION";
|
|
19
|
+
OperationType["SUBTITLE_GENERATION"] = "SUBTITLE_GENERATION";
|
|
20
|
+
// Media processing
|
|
21
|
+
OperationType["HLS_TRANSCODING"] = "HLS_TRANSCODING";
|
|
22
|
+
OperationType["THUMBNAIL_GENERATION"] = "THUMBNAIL_GENERATION";
|
|
23
|
+
OperationType["FILMSTRIP_GENERATION"] = "FILMSTRIP_GENERATION";
|
|
24
|
+
// Remotion rendering
|
|
25
|
+
OperationType["REMOTION_RENDER_720P"] = "REMOTION_RENDER_720P";
|
|
26
|
+
OperationType["REMOTION_RENDER_1080P"] = "REMOTION_RENDER_1080P";
|
|
27
|
+
OperationType["REMOTION_RENDER_4K"] = "REMOTION_RENDER_4K";
|
|
28
|
+
OperationType["REMOTION_THUMBNAIL"] = "REMOTION_THUMBNAIL";
|
|
29
|
+
})(OperationType || (exports.OperationType = OperationType = {}));
|
|
30
|
+
//# sourceMappingURL=types.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"types.js","sourceRoot":"","sources":["../src/types.ts"],"names":[],"mappings":";AAAA,+CAA+C;AAC/C,yCAAyC;AACzC,+CAA+C;;;AAE/C,IAAY,aAwBX;AAxBD,WAAY,aAAa;IACvB,gBAAgB;IAChB,wDAAuC,CAAA;IACvC,0DAAyC,CAAA;IACzC,oDAAmC,CAAA;IACnC,0CAAyB,CAAA;IACzB,sDAAqC,CAAA;IAErC,gBAAgB;IAChB,0DAAyC,CAAA;IACzC,4DAA2C,CAAA;IAC3C,0DAAyC,CAAA;IACzC,4DAA2C,CAAA;IAE3C,mBAAmB;IACnB,oDAAmC,CAAA;IACnC,8DAA6C,CAAA;IAC7C,8DAA6C,CAAA;IAE7C,qBAAqB;IACrB,8DAA6C,CAAA;IAC7C,gEAA+C,CAAA;IAC/C,0DAAyC,CAAA;IACzC,0DAAyC,CAAA;AAC3C,CAAC,EAxBW,aAAa,6BAAb,aAAa,QAwBxB"}
|
package/package.json
ADDED
|
@@ -0,0 +1,39 @@
|
|
|
1
|
+
{
|
|
2
|
+
"name": "clhq-credits-client",
|
|
3
|
+
"version": "1.1.0-alpha.116",
|
|
4
|
+
"description": "Lambda client for invoking credits service",
|
|
5
|
+
"main": "dist/index.js",
|
|
6
|
+
"types": "dist/index.d.ts",
|
|
7
|
+
"license": "UNLICENSED",
|
|
8
|
+
"scripts": {
|
|
9
|
+
"build": "yarn exec tsc -p tsconfig.json",
|
|
10
|
+
"clean:dist": "rimraf dist",
|
|
11
|
+
"clean:all": "yarn run clean:dist",
|
|
12
|
+
"format": "prettier --write \"src/**/*.ts\"",
|
|
13
|
+
"lint": "eslint \"src/**/*.ts\" --fix",
|
|
14
|
+
"version:upgrade:alpha": "standard-version --prerelease alpha",
|
|
15
|
+
"release": "npm publish --tag alpha",
|
|
16
|
+
"release:alpha": "npm publish --tag alpha",
|
|
17
|
+
"release:prealpha": "",
|
|
18
|
+
"clean:build": "rimraf .build",
|
|
19
|
+
"clean:webpack": "rimraf .webpack",
|
|
20
|
+
"clean:serverless": "rimraf .serverless",
|
|
21
|
+
"sls:deploy": "sls deploy",
|
|
22
|
+
"sls:deploy:dev": "env-cmd -f ../../.env.dev sls deploy --stage dev",
|
|
23
|
+
"sls:remove:dev": "env-cmd -f ../../.env.dev sls remove --stage dev",
|
|
24
|
+
"sls:offline": "sls offline",
|
|
25
|
+
"sls:package": "sls package",
|
|
26
|
+
"sls:package2": "npm run clean:all&& npm run sls:package",
|
|
27
|
+
"sls:remove": "sls remove"
|
|
28
|
+
},
|
|
29
|
+
"dependencies": {
|
|
30
|
+
"@aws-sdk/client-lambda": "^3.490.0"
|
|
31
|
+
},
|
|
32
|
+
"devDependencies": {
|
|
33
|
+
"@types/node": "^24.0.4",
|
|
34
|
+
"typescript": "^5.8.3"
|
|
35
|
+
},
|
|
36
|
+
"peerDependencies": {
|
|
37
|
+
"@aws-sdk/client-lambda": "^3.490.0"
|
|
38
|
+
}
|
|
39
|
+
}
|
|
@@ -0,0 +1,165 @@
|
|
|
1
|
+
import { LambdaClient, InvokeCommand } from '@aws-sdk/client-lambda';
|
|
2
|
+
import {
|
|
3
|
+
ReserveCreditsRequest,
|
|
4
|
+
ReserveCreditsResponse,
|
|
5
|
+
FinalizeCreditsRequest,
|
|
6
|
+
FinalizeCreditsResponse,
|
|
7
|
+
ReleaseCreditsRequest,
|
|
8
|
+
ReleaseCreditsResponse,
|
|
9
|
+
GetBalanceRequest,
|
|
10
|
+
GetBalanceResponse,
|
|
11
|
+
EstimateCostRequest,
|
|
12
|
+
EstimateCostResponse,
|
|
13
|
+
} from './types';
|
|
14
|
+
|
|
15
|
+
export class CreditsLambdaClient {
|
|
16
|
+
private lambda: LambdaClient;
|
|
17
|
+
private stage: string;
|
|
18
|
+
|
|
19
|
+
constructor(options?: { region?: string; stage?: string }) {
|
|
20
|
+
this.lambda = new LambdaClient({
|
|
21
|
+
region: options?.region || process.env.AWS_REGION || 'ap-southeast-2',
|
|
22
|
+
});
|
|
23
|
+
this.stage = options?.stage || process.env.STAGE || 'dev';
|
|
24
|
+
}
|
|
25
|
+
|
|
26
|
+
/**
|
|
27
|
+
* Get the Lambda function name for a specific handler
|
|
28
|
+
*/
|
|
29
|
+
private getFunctionName(handler: string): string {
|
|
30
|
+
return `clippy-credits-service-${this.stage}-${handler}`;
|
|
31
|
+
}
|
|
32
|
+
|
|
33
|
+
/**
|
|
34
|
+
* Generic method to invoke Lambda functions with proper error handling
|
|
35
|
+
*/
|
|
36
|
+
private async invoke<TRequest, TResponse>(
|
|
37
|
+
handler: string,
|
|
38
|
+
payload: TRequest
|
|
39
|
+
): Promise<TResponse> {
|
|
40
|
+
const command = new InvokeCommand({
|
|
41
|
+
FunctionName: this.getFunctionName(handler),
|
|
42
|
+
Payload: Buffer.from(JSON.stringify(payload)),
|
|
43
|
+
});
|
|
44
|
+
|
|
45
|
+
try {
|
|
46
|
+
const response = await this.lambda.send(command);
|
|
47
|
+
|
|
48
|
+
if (response.FunctionError) {
|
|
49
|
+
const errorPayload = JSON.parse(
|
|
50
|
+
Buffer.from(response.Payload!).toString()
|
|
51
|
+
);
|
|
52
|
+
throw new Error(errorPayload.errorMessage || 'Lambda invocation failed');
|
|
53
|
+
}
|
|
54
|
+
|
|
55
|
+
const result = JSON.parse(Buffer.from(response.Payload!).toString());
|
|
56
|
+
|
|
57
|
+
if (!result.success && result.error) {
|
|
58
|
+
throw new Error(result.error);
|
|
59
|
+
}
|
|
60
|
+
|
|
61
|
+
return result;
|
|
62
|
+
} catch (error: any) {
|
|
63
|
+
// Re-throw Lambda invocation errors
|
|
64
|
+
if (error.name === 'ResourceNotFoundException') {
|
|
65
|
+
throw new Error(`Credits service not available: ${handler}`);
|
|
66
|
+
}
|
|
67
|
+
if (error.name === 'TooManyRequestsException') {
|
|
68
|
+
throw new Error('Credits service rate limited');
|
|
69
|
+
}
|
|
70
|
+
throw error;
|
|
71
|
+
}
|
|
72
|
+
}
|
|
73
|
+
|
|
74
|
+
/**
|
|
75
|
+
* Reserve credits before starting an operation
|
|
76
|
+
*/
|
|
77
|
+
async reserveCredits(
|
|
78
|
+
params: ReserveCreditsRequest
|
|
79
|
+
): Promise<ReserveCreditsResponse> {
|
|
80
|
+
return this.invoke('reserve', params);
|
|
81
|
+
}
|
|
82
|
+
|
|
83
|
+
/**
|
|
84
|
+
* Finalize credit consumption after operation completes
|
|
85
|
+
*/
|
|
86
|
+
async finalizeCredits(
|
|
87
|
+
params: FinalizeCreditsRequest
|
|
88
|
+
): Promise<FinalizeCreditsResponse> {
|
|
89
|
+
return this.invoke('finalize', params);
|
|
90
|
+
}
|
|
91
|
+
|
|
92
|
+
/**
|
|
93
|
+
* Release reserved credits if operation fails
|
|
94
|
+
*/
|
|
95
|
+
async releaseCredits(
|
|
96
|
+
params: ReleaseCreditsRequest
|
|
97
|
+
): Promise<ReleaseCreditsResponse> {
|
|
98
|
+
return this.invoke('release', params);
|
|
99
|
+
}
|
|
100
|
+
|
|
101
|
+
/**
|
|
102
|
+
* Get user's credit balance
|
|
103
|
+
*/
|
|
104
|
+
async getBalance(params: GetBalanceRequest): Promise<GetBalanceResponse> {
|
|
105
|
+
return this.invoke('balance', params);
|
|
106
|
+
}
|
|
107
|
+
|
|
108
|
+
/**
|
|
109
|
+
* Estimate credit cost for an operation
|
|
110
|
+
*/
|
|
111
|
+
async estimateCost(
|
|
112
|
+
params: EstimateCostRequest
|
|
113
|
+
): Promise<EstimateCostResponse> {
|
|
114
|
+
return this.invoke('estimate', params);
|
|
115
|
+
}
|
|
116
|
+
|
|
117
|
+
/**
|
|
118
|
+
* Convenience method: Reserve and execute operation with automatic finalization
|
|
119
|
+
*/
|
|
120
|
+
async executeWithCredits<T>(
|
|
121
|
+
operation: () => Promise<T>,
|
|
122
|
+
reserveParams: ReserveCreditsRequest,
|
|
123
|
+
finalizeParams: (result: T) => FinalizeCreditsRequest
|
|
124
|
+
): Promise<{ result: T; creditsUsed: number }> {
|
|
125
|
+
// Reserve credits
|
|
126
|
+
const reservation = await this.reserveCredits(reserveParams);
|
|
127
|
+
|
|
128
|
+
if (!reservation.success || !reservation.reservationId) {
|
|
129
|
+
throw new Error(reservation.error || 'Failed to reserve credits');
|
|
130
|
+
}
|
|
131
|
+
|
|
132
|
+
try {
|
|
133
|
+
// Execute the operation
|
|
134
|
+
const result = await operation();
|
|
135
|
+
|
|
136
|
+
// Finalize credits
|
|
137
|
+
const finalizeRequest = finalizeParams(result);
|
|
138
|
+
finalizeRequest.reservationId = reservation.reservationId;
|
|
139
|
+
|
|
140
|
+
const finalization = await this.finalizeCredits(finalizeRequest);
|
|
141
|
+
|
|
142
|
+
if (!finalization.success) {
|
|
143
|
+
throw new Error(finalization.error || 'Failed to finalize credits');
|
|
144
|
+
}
|
|
145
|
+
|
|
146
|
+
return {
|
|
147
|
+
result,
|
|
148
|
+
creditsUsed: finalization.creditsUsed || 0,
|
|
149
|
+
};
|
|
150
|
+
|
|
151
|
+
} catch (error) {
|
|
152
|
+
// Release credits on failure
|
|
153
|
+
try {
|
|
154
|
+
await this.releaseCredits({
|
|
155
|
+
reservationId: reservation.reservationId,
|
|
156
|
+
reason: error instanceof Error ? error.message : 'Operation failed',
|
|
157
|
+
});
|
|
158
|
+
} catch (releaseError) {
|
|
159
|
+
console.warn('Failed to release credits:', releaseError);
|
|
160
|
+
}
|
|
161
|
+
|
|
162
|
+
throw error;
|
|
163
|
+
}
|
|
164
|
+
}
|
|
165
|
+
}
|
package/src/index.ts
ADDED
package/src/types.ts
ADDED
|
@@ -0,0 +1,116 @@
|
|
|
1
|
+
// ============================================
|
|
2
|
+
// Operation Types for Credit Calculation
|
|
3
|
+
// ============================================
|
|
4
|
+
|
|
5
|
+
export enum OperationType {
|
|
6
|
+
// Video exports
|
|
7
|
+
VIDEO_EXPORT_720P = 'VIDEO_EXPORT_720P',
|
|
8
|
+
VIDEO_EXPORT_1080P = 'VIDEO_EXPORT_1080P',
|
|
9
|
+
VIDEO_EXPORT_4K = 'VIDEO_EXPORT_4K',
|
|
10
|
+
GIF_EXPORT = 'GIF_EXPORT',
|
|
11
|
+
AUDIO_EXTRACTION = 'AUDIO_EXTRACTION',
|
|
12
|
+
|
|
13
|
+
// AI operations
|
|
14
|
+
BACKGROUND_REMOVAL = 'BACKGROUND_REMOVAL',
|
|
15
|
+
AI_IMAGE_GENERATION = 'AI_IMAGE_GENERATION',
|
|
16
|
+
AI_TEXT_COMPLETION = 'AI_TEXT_COMPLETION',
|
|
17
|
+
SUBTITLE_GENERATION = 'SUBTITLE_GENERATION',
|
|
18
|
+
|
|
19
|
+
// Media processing
|
|
20
|
+
HLS_TRANSCODING = 'HLS_TRANSCODING',
|
|
21
|
+
THUMBNAIL_GENERATION = 'THUMBNAIL_GENERATION',
|
|
22
|
+
FILMSTRIP_GENERATION = 'FILMSTRIP_GENERATION',
|
|
23
|
+
|
|
24
|
+
// Remotion rendering
|
|
25
|
+
REMOTION_RENDER_720P = 'REMOTION_RENDER_720P',
|
|
26
|
+
REMOTION_RENDER_1080P = 'REMOTION_RENDER_1080P',
|
|
27
|
+
REMOTION_RENDER_4K = 'REMOTION_RENDER_4K',
|
|
28
|
+
REMOTION_THUMBNAIL = 'REMOTION_THUMBNAIL',
|
|
29
|
+
}
|
|
30
|
+
|
|
31
|
+
// ============================================
|
|
32
|
+
// Request Types
|
|
33
|
+
// ============================================
|
|
34
|
+
|
|
35
|
+
export interface ReserveCreditsRequest {
|
|
36
|
+
userId: string;
|
|
37
|
+
operationType: OperationType;
|
|
38
|
+
estimatedCredits: number;
|
|
39
|
+
operationId: string;
|
|
40
|
+
metadata?: Record<string, any>;
|
|
41
|
+
}
|
|
42
|
+
|
|
43
|
+
export interface FinalizeCreditsRequest {
|
|
44
|
+
reservationId: string;
|
|
45
|
+
actualCredits: number;
|
|
46
|
+
resultUrl?: string;
|
|
47
|
+
}
|
|
48
|
+
|
|
49
|
+
export interface ReleaseCreditsRequest {
|
|
50
|
+
reservationId: string;
|
|
51
|
+
reason?: string;
|
|
52
|
+
}
|
|
53
|
+
|
|
54
|
+
export interface GetBalanceRequest {
|
|
55
|
+
userId: string;
|
|
56
|
+
}
|
|
57
|
+
|
|
58
|
+
export interface EstimateCostRequest {
|
|
59
|
+
userId: string;
|
|
60
|
+
operationType: OperationType;
|
|
61
|
+
durationMinutes?: number;
|
|
62
|
+
durationSeconds?: number;
|
|
63
|
+
variants?: number;
|
|
64
|
+
isHighRes?: boolean;
|
|
65
|
+
}
|
|
66
|
+
|
|
67
|
+
// ============================================
|
|
68
|
+
// Response Types
|
|
69
|
+
// ============================================
|
|
70
|
+
|
|
71
|
+
export interface ReserveCreditsResponse {
|
|
72
|
+
success: boolean;
|
|
73
|
+
reservationId?: string;
|
|
74
|
+
creditsReserved?: number;
|
|
75
|
+
newAvailableBalance?: number;
|
|
76
|
+
error?: string;
|
|
77
|
+
}
|
|
78
|
+
|
|
79
|
+
export interface FinalizeCreditsResponse {
|
|
80
|
+
success: boolean;
|
|
81
|
+
transactionId?: string;
|
|
82
|
+
creditsUsed?: number;
|
|
83
|
+
newBalance?: number;
|
|
84
|
+
refundedCredits?: number;
|
|
85
|
+
error?: string;
|
|
86
|
+
}
|
|
87
|
+
|
|
88
|
+
export interface ReleaseCreditsResponse {
|
|
89
|
+
success: boolean;
|
|
90
|
+
creditsReleased?: number;
|
|
91
|
+
newAvailableBalance?: number;
|
|
92
|
+
error?: string;
|
|
93
|
+
}
|
|
94
|
+
|
|
95
|
+
export interface GetBalanceResponse {
|
|
96
|
+
success: boolean;
|
|
97
|
+
totalEarned?: number;
|
|
98
|
+
totalUsed?: number;
|
|
99
|
+
currentBalance?: number;
|
|
100
|
+
expiringCredits?: number;
|
|
101
|
+
expiringDate?: string;
|
|
102
|
+
error?: string;
|
|
103
|
+
}
|
|
104
|
+
|
|
105
|
+
export interface EstimateCostResponse {
|
|
106
|
+
success: boolean;
|
|
107
|
+
estimatedCredits?: number;
|
|
108
|
+
breakdown?: {
|
|
109
|
+
baseCost: number;
|
|
110
|
+
durationCost: number;
|
|
111
|
+
modifierCost: number;
|
|
112
|
+
};
|
|
113
|
+
currentBalance?: number;
|
|
114
|
+
canProceed?: boolean;
|
|
115
|
+
error?: string;
|
|
116
|
+
}
|
package/tsconfig.json
ADDED
|
@@ -0,0 +1,19 @@
|
|
|
1
|
+
{
|
|
2
|
+
"compilerOptions": {
|
|
3
|
+
"target": "ES2022",
|
|
4
|
+
"module": "commonjs",
|
|
5
|
+
"lib": ["ES2022"],
|
|
6
|
+
"outDir": "./dist",
|
|
7
|
+
"rootDir": "./src",
|
|
8
|
+
"strict": true,
|
|
9
|
+
"esModuleInterop": true,
|
|
10
|
+
"skipLibCheck": true,
|
|
11
|
+
"forceConsistentCasingInFileNames": true,
|
|
12
|
+
"resolveJsonModule": true,
|
|
13
|
+
"declaration": true,
|
|
14
|
+
"declarationMap": true,
|
|
15
|
+
"sourceMap": true
|
|
16
|
+
},
|
|
17
|
+
"include": ["src/**/*"],
|
|
18
|
+
"exclude": ["node_modules", "dist"]
|
|
19
|
+
}
|