@cludz/sdk 0.2.3
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/.github/workflows/publish.yml +26 -0
- package/README.md +66 -0
- package/bun.lock +26 -0
- package/index.ts +110 -0
- package/jsr.json +6 -0
- package/modules/account.ts +26 -0
- package/modules/ai.ts +33 -0
- package/modules/downloader.ts +81 -0
- package/modules/image.ts +157 -0
- package/modules/storage.ts +249 -0
- package/modules/tasks.ts +54 -0
- package/modules/tools.ts +97 -0
- package/package.json +14 -0
- package/tsconfig.json +29 -0
- package/types.ts +290 -0
|
@@ -0,0 +1,26 @@
|
|
|
1
|
+
name: Bump and Publish
|
|
2
|
+
|
|
3
|
+
on:
|
|
4
|
+
push:
|
|
5
|
+
branches:
|
|
6
|
+
- main
|
|
7
|
+
|
|
8
|
+
jobs:
|
|
9
|
+
release:
|
|
10
|
+
runs-on: ubuntu-latest
|
|
11
|
+
permissions:
|
|
12
|
+
contents: write
|
|
13
|
+
id-token: write
|
|
14
|
+
|
|
15
|
+
steps:
|
|
16
|
+
- uses: actions/checkout@v4
|
|
17
|
+
with:
|
|
18
|
+
fetch-depth: 0
|
|
19
|
+
|
|
20
|
+
- uses: oven-sh/setup-bun@v2
|
|
21
|
+
|
|
22
|
+
- name: Install dependencies
|
|
23
|
+
run: bun install
|
|
24
|
+
|
|
25
|
+
- name: Publish to JSR
|
|
26
|
+
run: bunx jsr publish
|
package/README.md
ADDED
|
@@ -0,0 +1,66 @@
|
|
|
1
|
+
# Cludz API JavaScript SDK
|
|
2
|
+
|
|
3
|
+
A clean, modular, and high-performance JavaScript SDK for [Cludz API](https://docs.cludz.net/), built for **Bun**.
|
|
4
|
+
|
|
5
|
+
## Installation
|
|
6
|
+
|
|
7
|
+
This SDK is designed to be used directly in your Bun projects.
|
|
8
|
+
|
|
9
|
+
```bash
|
|
10
|
+
bunx jsr add @cludz/sdk
|
|
11
|
+
```
|
|
12
|
+
|
|
13
|
+
## Quick Start
|
|
14
|
+
|
|
15
|
+
```javascript
|
|
16
|
+
import { Cludz } from '@cludz/sdk';
|
|
17
|
+
|
|
18
|
+
const cludz = new Cludz({
|
|
19
|
+
api: 'https://api.cludz.net/',
|
|
20
|
+
key: 'your_api_key_here'
|
|
21
|
+
});
|
|
22
|
+
|
|
23
|
+
// Download a video
|
|
24
|
+
const video = await cludz.downloader.youtube.download('https://youtube.com/watch?v=...');
|
|
25
|
+
console.log(video.data.url);
|
|
26
|
+
```
|
|
27
|
+
|
|
28
|
+
## Modules
|
|
29
|
+
|
|
30
|
+
### Downloader
|
|
31
|
+
- `cludz.downloader.youtube.search(query, limit)`
|
|
32
|
+
- `cludz.downloader.youtube.searchDownload(query, format)`
|
|
33
|
+
- `cludz.downloader.youtube.download(url, format)`
|
|
34
|
+
- `cludz.downloader.tiktok.download(url, format)`
|
|
35
|
+
- `cludz.downloader.download(platform, url, format)` (Supports: instagram, facebook, pinterest, twitter, soundcloud, twitch)
|
|
36
|
+
|
|
37
|
+
### Tools
|
|
38
|
+
- `cludz.tools.webCheck(url)`
|
|
39
|
+
- `cludz.tools.dns(domain)`
|
|
40
|
+
- `cludz.tools.ssl(domain)`
|
|
41
|
+
- `cludz.tools.meta(url)`
|
|
42
|
+
- `cludz.tools.qr(text)`: Returns a Bun Response (Image).
|
|
43
|
+
- `cludz.tools.barcode(text, options)`: Returns a Bun Response (Image).
|
|
44
|
+
|
|
45
|
+
### Image
|
|
46
|
+
- `cludz.image.meme(source, topText, bottomText)`: Generate a meme. `source` can be a URL, local path, Buffer, or Blob.
|
|
47
|
+
- `cludz.image.compress(source, quality)`: Compress an image (quality 1-100).
|
|
48
|
+
- `cludz.image.convert(source, format)`: Convert image format (jpeg, png, webp, avif).
|
|
49
|
+
- `cludz.image.crop(source, { left, top, width, height })`: Crop an image.
|
|
50
|
+
- *Note: All image methods return a standard `Response` object containing the binary image data.*
|
|
51
|
+
|
|
52
|
+
### Account
|
|
53
|
+
- `cludz.account.me()`: Get current account info.
|
|
54
|
+
- `cludz.account.status()`: Get API health/monitoring.
|
|
55
|
+
|
|
56
|
+
## Error Handling
|
|
57
|
+
|
|
58
|
+
The SDK throws descriptive errors when a request fails:
|
|
59
|
+
|
|
60
|
+
```javascript
|
|
61
|
+
try {
|
|
62
|
+
await cludz.tools.qr('Hello this is QR code');
|
|
63
|
+
} catch (error) {
|
|
64
|
+
console.error('Error:', error.message);
|
|
65
|
+
}
|
|
66
|
+
```
|
package/bun.lock
ADDED
|
@@ -0,0 +1,26 @@
|
|
|
1
|
+
{
|
|
2
|
+
"lockfileVersion": 1,
|
|
3
|
+
"configVersion": 1,
|
|
4
|
+
"workspaces": {
|
|
5
|
+
"": {
|
|
6
|
+
"name": "sdk",
|
|
7
|
+
"devDependencies": {
|
|
8
|
+
"@types/bun": "latest",
|
|
9
|
+
},
|
|
10
|
+
"peerDependencies": {
|
|
11
|
+
"typescript": "^5",
|
|
12
|
+
},
|
|
13
|
+
},
|
|
14
|
+
},
|
|
15
|
+
"packages": {
|
|
16
|
+
"@types/bun": ["@types/bun@1.3.9", "", { "dependencies": { "bun-types": "1.3.9" } }, "sha512-KQ571yULOdWJiMH+RIWIOZ7B2RXQGpL1YQrBtLIV3FqDcCu6FsbFUBwhdKUlCKUpS3PJDsHlJ1QKlpxoVR+xtw=="],
|
|
17
|
+
|
|
18
|
+
"@types/node": ["@types/node@25.2.3", "", { "dependencies": { "undici-types": "~7.16.0" } }, "sha512-m0jEgYlYz+mDJZ2+F4v8D1AyQb+QzsNqRuI7xg1VQX/KlKS0qT9r1Mo16yo5F/MtifXFgaofIFsdFMox2SxIbQ=="],
|
|
19
|
+
|
|
20
|
+
"bun-types": ["bun-types@1.3.9", "", { "dependencies": { "@types/node": "*" } }, "sha512-+UBWWOakIP4Tswh0Bt0QD0alpTY8cb5hvgiYeWCMet9YukHbzuruIEeXC2D7nMJPB12kbh8C7XJykSexEqGKJg=="],
|
|
21
|
+
|
|
22
|
+
"typescript": ["typescript@5.9.3", "", { "bin": { "tsc": "bin/tsc", "tsserver": "bin/tsserver" } }, "sha512-jl1vZzPDinLr9eUt3J/t7V6FgNEw9QjvBPdysz9KfQDD41fQrC2Y4vKQdiaUpFT4bXlb1RHhLpp8wtm6M5TgSw=="],
|
|
23
|
+
|
|
24
|
+
"undici-types": ["undici-types@7.16.0", "", {}, "sha512-Zz+aZWSj8LE6zoxD+xrjh4VfkIG8Ya6LvYkZqtUQGJPZjYl53ypCaUwWqo7eI0x66KBGeRo+mlBEkMSeSZ38Nw=="],
|
|
25
|
+
}
|
|
26
|
+
}
|
package/index.ts
ADDED
|
@@ -0,0 +1,110 @@
|
|
|
1
|
+
// import { AI } from "./modules/ai";
|
|
2
|
+
import { Downloader } from "./modules/downloader";
|
|
3
|
+
import { Tools } from "./modules/tools";
|
|
4
|
+
import { Account } from "./modules/account";
|
|
5
|
+
import { Image } from "./modules/image";
|
|
6
|
+
import { Tasks } from "./modules/tasks";
|
|
7
|
+
export { Storage } from "./modules/storage";
|
|
8
|
+
export type { StorageSource } from "./modules/storage";
|
|
9
|
+
|
|
10
|
+
import type { CludzOptions, RequestOptions } from "./types";
|
|
11
|
+
|
|
12
|
+
/**
|
|
13
|
+
* The main Cludz SDK client.
|
|
14
|
+
* Provides access to various modules including downloader, tools, account, image, and tasks.
|
|
15
|
+
*/
|
|
16
|
+
export class Cludz {
|
|
17
|
+
/** The base URL of the Cludz API. */
|
|
18
|
+
public readonly baseUrl: string;
|
|
19
|
+
/** The API key used for authentication. */
|
|
20
|
+
public readonly key?: string;
|
|
21
|
+
|
|
22
|
+
// public readonly ai: AI;
|
|
23
|
+
/** Module for downloading media from supported platforms. */
|
|
24
|
+
public readonly downloader: Downloader;
|
|
25
|
+
/** Module for various utility tools (QR, DNS, SSL, etc.). */
|
|
26
|
+
public readonly tools: Tools;
|
|
27
|
+
/** Module for account management and status monitoring. */
|
|
28
|
+
public readonly account: Account;
|
|
29
|
+
/** Module for image processing and manipulation. */
|
|
30
|
+
public readonly image: Image;
|
|
31
|
+
/** Module for managing and waiting for background tasks. */
|
|
32
|
+
public readonly tasks: Tasks;
|
|
33
|
+
|
|
34
|
+
/**
|
|
35
|
+
* Initializes a new instance of the Cludz client.
|
|
36
|
+
* @param options Configuration options for the client.
|
|
37
|
+
* @throws Error if the API URL is not provided.
|
|
38
|
+
*/
|
|
39
|
+
constructor(options: CludzOptions) {
|
|
40
|
+
if (!options.api) throw new Error("API URL is required");
|
|
41
|
+
|
|
42
|
+
this.baseUrl = options.api.replace(/\/$/, "");
|
|
43
|
+
this.key = options.key;
|
|
44
|
+
|
|
45
|
+
// this.ai = new AI(this);
|
|
46
|
+
this.downloader = new Downloader(this);
|
|
47
|
+
this.tools = new Tools(this);
|
|
48
|
+
this.account = new Account(this);
|
|
49
|
+
this.image = new Image(this);
|
|
50
|
+
this.tasks = new Tasks(this);
|
|
51
|
+
}
|
|
52
|
+
|
|
53
|
+
/**
|
|
54
|
+
* Internal request handler using fetch.
|
|
55
|
+
* @param endpoint The API endpoint to request (e.g., "/v1/youtube/download").
|
|
56
|
+
* @param options Request configuration including method, query params, and body.
|
|
57
|
+
* @returns A promise that resolves to the parsed JSON data or a Response object for binary content.
|
|
58
|
+
* @throws Error if the API returns a non-OK response.
|
|
59
|
+
* @internal
|
|
60
|
+
*/
|
|
61
|
+
async _request<T = any>(endpoint: string, options: RequestOptions = {}): Promise<T | Response> {
|
|
62
|
+
const url = new URL(`${this.baseUrl}${endpoint}`);
|
|
63
|
+
|
|
64
|
+
if (options.query) {
|
|
65
|
+
Object.entries(options.query).forEach(([key, value]) => {
|
|
66
|
+
if (value !== undefined && value !== null) {
|
|
67
|
+
url.searchParams.append(key, value.toString());
|
|
68
|
+
}
|
|
69
|
+
});
|
|
70
|
+
}
|
|
71
|
+
|
|
72
|
+
const headers: Record<string, string> = {
|
|
73
|
+
"Accept": "application/json",
|
|
74
|
+
};
|
|
75
|
+
|
|
76
|
+
if (this.key) {
|
|
77
|
+
headers["X-API-Key"] = this.key;
|
|
78
|
+
}
|
|
79
|
+
|
|
80
|
+
const fetchOptions: RequestInit = {
|
|
81
|
+
method: options.method || "GET",
|
|
82
|
+
headers,
|
|
83
|
+
};
|
|
84
|
+
|
|
85
|
+
if (options.body) {
|
|
86
|
+
if (options.body instanceof FormData) {
|
|
87
|
+
fetchOptions.body = options.body;
|
|
88
|
+
// Don't set Content-Type, fetch will set it with boundary
|
|
89
|
+
} else {
|
|
90
|
+
fetchOptions.body = JSON.stringify(options.body);
|
|
91
|
+
headers["Content-Type"] = "application/json";
|
|
92
|
+
}
|
|
93
|
+
}
|
|
94
|
+
|
|
95
|
+
const response = await fetch(url.toString(), fetchOptions);
|
|
96
|
+
|
|
97
|
+
const contentType = response.headers.get("content-type");
|
|
98
|
+
if (contentType && (contentType.includes("image/") || contentType.includes("application/pdf"))) {
|
|
99
|
+
return response;
|
|
100
|
+
}
|
|
101
|
+
|
|
102
|
+
const data = await response.json() as any;
|
|
103
|
+
|
|
104
|
+
if (!response.ok) {
|
|
105
|
+
throw new Error(data.message || data.statusMessage || `API Error: ${response.status}`);
|
|
106
|
+
}
|
|
107
|
+
|
|
108
|
+
return data as T;
|
|
109
|
+
}
|
|
110
|
+
}
|
package/jsr.json
ADDED
|
@@ -0,0 +1,26 @@
|
|
|
1
|
+
import type { Cludz } from "../index";
|
|
2
|
+
import type { ApiResponse, AccountInfo, MonitoringStats } from "../types";
|
|
3
|
+
|
|
4
|
+
/**
|
|
5
|
+
* Module for account management and status monitoring.
|
|
6
|
+
*/
|
|
7
|
+
export class Account {
|
|
8
|
+
/** @internal */
|
|
9
|
+
constructor(private sdk: Cludz) {}
|
|
10
|
+
|
|
11
|
+
/**
|
|
12
|
+
* Retrieves current account information and API key details.
|
|
13
|
+
* @returns A promise that resolves to the account information.
|
|
14
|
+
*/
|
|
15
|
+
async me(): Promise<ApiResponse<AccountInfo>> {
|
|
16
|
+
return this.sdk._request("/v1/me") as Promise<ApiResponse<AccountInfo>>;
|
|
17
|
+
}
|
|
18
|
+
|
|
19
|
+
/**
|
|
20
|
+
* Retrieves API status and overall monitoring statistics.
|
|
21
|
+
* @returns A promise that resolves to the monitoring statistics.
|
|
22
|
+
*/
|
|
23
|
+
async status(): Promise<MonitoringStats> {
|
|
24
|
+
return this.sdk._request("/monitoring/stats") as Promise<MonitoringStats>;
|
|
25
|
+
}
|
|
26
|
+
}
|
package/modules/ai.ts
ADDED
|
@@ -0,0 +1,33 @@
|
|
|
1
|
+
import type { Cludz } from "../index";
|
|
2
|
+
import type { ApiResponse } from "../types";
|
|
3
|
+
|
|
4
|
+
// AI is currently not available.
|
|
5
|
+
// /**
|
|
6
|
+
// * Module for interacting with Cludz AI models.
|
|
7
|
+
// */
|
|
8
|
+
// export class AI {
|
|
9
|
+
// /** @internal */
|
|
10
|
+
// constructor(private sdk: Cludz) {}
|
|
11
|
+
|
|
12
|
+
// /**
|
|
13
|
+
// * Sends a message to the Mimo AI model (Flash V2).
|
|
14
|
+
// * @param text The message or prompt to send.
|
|
15
|
+
// * @returns A promise that resolves to the AI's response text.
|
|
16
|
+
// */
|
|
17
|
+
// async mimo(text: string): Promise<ApiResponse<string>> {
|
|
18
|
+
// return this.sdk._request("/v1/ai/mimo/chat", {
|
|
19
|
+
// query: { text }
|
|
20
|
+
// }) as Promise<ApiResponse<string>>;
|
|
21
|
+
// }
|
|
22
|
+
|
|
23
|
+
// /**
|
|
24
|
+
// * Sends a message to the GPT AI model (OSS 120B).
|
|
25
|
+
// * @param text The message or prompt to send.
|
|
26
|
+
// * @returns A promise that resolves to the AI's response text.
|
|
27
|
+
// */
|
|
28
|
+
// async gpt(text: string): Promise<ApiResponse<string>> {
|
|
29
|
+
// return this.sdk._request("/v1/ai/gpt/chat", {
|
|
30
|
+
// query: { text }
|
|
31
|
+
// }) as Promise<ApiResponse<string>>;
|
|
32
|
+
// }
|
|
33
|
+
// }
|
|
@@ -0,0 +1,81 @@
|
|
|
1
|
+
import type { Cludz } from "../index";
|
|
2
|
+
import type { ApiResponse, TaskResult } from "../types";
|
|
3
|
+
|
|
4
|
+
/**
|
|
5
|
+
* Module for downloading media from various platforms.
|
|
6
|
+
*/
|
|
7
|
+
export class Downloader {
|
|
8
|
+
/** @internal */
|
|
9
|
+
constructor(private sdk: Cludz) {}
|
|
10
|
+
|
|
11
|
+
/**
|
|
12
|
+
* YouTube-specific download and search methods.
|
|
13
|
+
*/
|
|
14
|
+
public readonly youtube = {
|
|
15
|
+
/**
|
|
16
|
+
* Search for YouTube videos.
|
|
17
|
+
* @param query The search query.
|
|
18
|
+
* @param limit Maximum number of results to return (default: 1).
|
|
19
|
+
* @returns A promise that resolves to the search results.
|
|
20
|
+
*/
|
|
21
|
+
search: (query: string, limit: number = 1): Promise<ApiResponse<TaskResult>> => {
|
|
22
|
+
return this.sdk._request("/v1/youtube/search", {
|
|
23
|
+
query: { query, limit }
|
|
24
|
+
}) as Promise<ApiResponse<TaskResult>>;
|
|
25
|
+
},
|
|
26
|
+
|
|
27
|
+
/**
|
|
28
|
+
* Download a YouTube video by search query (directs to the first result).
|
|
29
|
+
* @param query The search query.
|
|
30
|
+
* @param format The desired output format ("mp3" or "mp4"). Defaults to "mp4".
|
|
31
|
+
* @returns A promise that resolves to the task information.
|
|
32
|
+
*/
|
|
33
|
+
searchDownload: (query: string, format: "mp3" | "mp4" = "mp4"): Promise<ApiResponse<TaskResult>> => {
|
|
34
|
+
return this.sdk._request("/v1/youtube/search/download", {
|
|
35
|
+
query: { query, format }
|
|
36
|
+
}) as Promise<ApiResponse<TaskResult>>;
|
|
37
|
+
},
|
|
38
|
+
|
|
39
|
+
/**
|
|
40
|
+
* Download a YouTube video by its URL.
|
|
41
|
+
* @param url The valid YouTube video URL.
|
|
42
|
+
* @param format The desired output format ("mp3" or "mp4"). Defaults to "mp4".
|
|
43
|
+
* @returns A promise that resolves to the task information.
|
|
44
|
+
*/
|
|
45
|
+
download: (url: string, format: "mp3" | "mp4" = "mp4"): Promise<ApiResponse<TaskResult>> => {
|
|
46
|
+
return this.sdk._request("/v1/youtube/download", {
|
|
47
|
+
query: { url, format }
|
|
48
|
+
}) as Promise<ApiResponse<TaskResult>>;
|
|
49
|
+
}
|
|
50
|
+
};
|
|
51
|
+
|
|
52
|
+
/**
|
|
53
|
+
* TikTok-specific download methods.
|
|
54
|
+
*/
|
|
55
|
+
public readonly tiktok = {
|
|
56
|
+
/**
|
|
57
|
+
* Download a TikTok video or audio.
|
|
58
|
+
* @param url The valid TikTok video URL.
|
|
59
|
+
* @param format The desired output format ("mp3" or "mp4"). Defaults to "mp4".
|
|
60
|
+
* @returns A promise that resolves to the task information.
|
|
61
|
+
*/
|
|
62
|
+
download: (url: string, format: "mp3" | "mp4" = "mp4"): Promise<ApiResponse<TaskResult>> => {
|
|
63
|
+
return this.sdk._request("/v1/tiktok/download", {
|
|
64
|
+
query: { url, format }
|
|
65
|
+
}) as Promise<ApiResponse<TaskResult>>;
|
|
66
|
+
}
|
|
67
|
+
};
|
|
68
|
+
|
|
69
|
+
/**
|
|
70
|
+
* Generic downloader for other platforms.
|
|
71
|
+
* @param platform The platform identifier (e.g., "instagram", "facebook").
|
|
72
|
+
* @param url The media URL.
|
|
73
|
+
* @param format The desired output format ("mp3" or "mp4"). Defaults to "mp4".
|
|
74
|
+
* @returns A promise that resolves to the task information.
|
|
75
|
+
*/
|
|
76
|
+
async download(platform: string, url: string, format: "mp3" | "mp4" = "mp4"): Promise<ApiResponse<TaskResult>> {
|
|
77
|
+
return this.sdk._request(`/v1/${platform}/download`, {
|
|
78
|
+
query: { url, format }
|
|
79
|
+
}) as Promise<ApiResponse<TaskResult>>;
|
|
80
|
+
}
|
|
81
|
+
}
|
package/modules/image.ts
ADDED
|
@@ -0,0 +1,157 @@
|
|
|
1
|
+
import type { Cludz } from "../index";
|
|
2
|
+
|
|
3
|
+
/**
|
|
4
|
+
* Supported image source types.
|
|
5
|
+
* Can be a URL string, a local file path string, a Buffer, a Blob, or a File.
|
|
6
|
+
*/
|
|
7
|
+
export type ImageSource = string | Buffer | Blob | File;
|
|
8
|
+
|
|
9
|
+
/**
|
|
10
|
+
* Module for image processing and manipulation.
|
|
11
|
+
* Supports environment-agnostic file resolution (Bun and Node.js).
|
|
12
|
+
*/
|
|
13
|
+
export class Image {
|
|
14
|
+
/** @internal */
|
|
15
|
+
constructor(private sdk: Cludz) {}
|
|
16
|
+
|
|
17
|
+
/**
|
|
18
|
+
* Resolves various image sources into a Blob or URL string.
|
|
19
|
+
* @param source The image source to resolve.
|
|
20
|
+
* @returns A promise that resolves to a Blob or a URL string.
|
|
21
|
+
* @private
|
|
22
|
+
*/
|
|
23
|
+
private async resolveImage(source: ImageSource): Promise<Blob | string> {
|
|
24
|
+
if (typeof source === "string") {
|
|
25
|
+
if (source.startsWith("http://") || source.startsWith("https://")) {
|
|
26
|
+
return source;
|
|
27
|
+
} else {
|
|
28
|
+
// Assume local path - dynamic import to stay environment-agnostic where possible
|
|
29
|
+
try {
|
|
30
|
+
// Try Bun first as it's the primary environment
|
|
31
|
+
// @ts-ignore
|
|
32
|
+
if (typeof Bun !== "undefined") {
|
|
33
|
+
// @ts-ignore
|
|
34
|
+
return Bun.file(source).blob();
|
|
35
|
+
}
|
|
36
|
+
// Fallback to Node.js
|
|
37
|
+
const { readFile } = await import("node:fs/promises");
|
|
38
|
+
const buffer = await readFile(source);
|
|
39
|
+
return new Blob([buffer]);
|
|
40
|
+
} catch (error: any) {
|
|
41
|
+
throw new Error(`Failed to read local image path: ${error.message}`);
|
|
42
|
+
}
|
|
43
|
+
}
|
|
44
|
+
}
|
|
45
|
+
|
|
46
|
+
if (source instanceof Blob || (typeof File !== "undefined" && source instanceof File)) {
|
|
47
|
+
return source;
|
|
48
|
+
}
|
|
49
|
+
|
|
50
|
+
if (Buffer.isBuffer(source)) {
|
|
51
|
+
return new Blob([source]);
|
|
52
|
+
}
|
|
53
|
+
|
|
54
|
+
throw new Error("Invalid image source type. Supported: URL string, local path string, Buffer, or Blob/File.");
|
|
55
|
+
}
|
|
56
|
+
|
|
57
|
+
/**
|
|
58
|
+
* Generates a meme by adding text to an image.
|
|
59
|
+
* @param source The image source (URL, path, Buffer, Blob, or File).
|
|
60
|
+
* @param top The text to display at the top of the meme.
|
|
61
|
+
* @param bottom The text to display at the bottom of the meme.
|
|
62
|
+
* @returns A promise that resolves to a Response object containing the generated image.
|
|
63
|
+
*/
|
|
64
|
+
async meme(source: ImageSource, top?: string, bottom?: string): Promise<Response> {
|
|
65
|
+
const image = await this.resolveImage(source);
|
|
66
|
+
const formData = new FormData();
|
|
67
|
+
|
|
68
|
+
if (typeof image === "string") {
|
|
69
|
+
formData.append("image", image);
|
|
70
|
+
} else {
|
|
71
|
+
formData.append("image", image, "image.png");
|
|
72
|
+
}
|
|
73
|
+
|
|
74
|
+
if (top) formData.append("top", top);
|
|
75
|
+
if (bottom) formData.append("bottom", bottom);
|
|
76
|
+
|
|
77
|
+
return this.sdk._request("/v1/image/meme", {
|
|
78
|
+
method: "POST",
|
|
79
|
+
body: formData
|
|
80
|
+
}) as Promise<Response>;
|
|
81
|
+
}
|
|
82
|
+
|
|
83
|
+
/**
|
|
84
|
+
* Compresses an image to reduce its file size.
|
|
85
|
+
* @param source The image source (URL, path, Buffer, Blob, or File).
|
|
86
|
+
* @param quality Compression quality (1-100). Defaults to 80.
|
|
87
|
+
* @returns A promise that resolves to a Response object containing the compressed image.
|
|
88
|
+
*/
|
|
89
|
+
async compress(source: ImageSource, quality: number = 80): Promise<Response> {
|
|
90
|
+
const image = await this.resolveImage(source);
|
|
91
|
+
const formData = new FormData();
|
|
92
|
+
|
|
93
|
+
if (typeof image === "string") {
|
|
94
|
+
formData.append("image", image);
|
|
95
|
+
} else {
|
|
96
|
+
formData.append("image", image, "image.png");
|
|
97
|
+
}
|
|
98
|
+
|
|
99
|
+
formData.append("quality", quality.toString());
|
|
100
|
+
|
|
101
|
+
return this.sdk._request("/v1/image/compress", {
|
|
102
|
+
method: "POST",
|
|
103
|
+
body: formData
|
|
104
|
+
}) as Promise<Response>;
|
|
105
|
+
}
|
|
106
|
+
|
|
107
|
+
/**
|
|
108
|
+
* Converts an image to a different format.
|
|
109
|
+
* @param source The image source (URL, path, Buffer, Blob, or File).
|
|
110
|
+
* @param format The target image format.
|
|
111
|
+
* @returns A promise that resolves to a Response object containing the converted image.
|
|
112
|
+
*/
|
|
113
|
+
async convert(source: ImageSource, format: "jpeg" | "jpg" | "png" | "webp" | "avif"): Promise<Response> {
|
|
114
|
+
const image = await this.resolveImage(source);
|
|
115
|
+
const formData = new FormData();
|
|
116
|
+
|
|
117
|
+
if (typeof image === "string") {
|
|
118
|
+
formData.append("image", image);
|
|
119
|
+
} else {
|
|
120
|
+
formData.append("image", image, "image.png");
|
|
121
|
+
}
|
|
122
|
+
|
|
123
|
+
formData.append("format", format);
|
|
124
|
+
|
|
125
|
+
return this.sdk._request("/v1/image/convert", {
|
|
126
|
+
method: "POST",
|
|
127
|
+
body: formData
|
|
128
|
+
}) as Promise<Response>;
|
|
129
|
+
}
|
|
130
|
+
|
|
131
|
+
/**
|
|
132
|
+
* Crops an image to specific dimensions.
|
|
133
|
+
* @param source The image source (URL, path, Buffer, Blob, or File).
|
|
134
|
+
* @param options The crop dimensions (left, top, width, height).
|
|
135
|
+
* @returns A promise that resolves to a Response object containing the cropped image.
|
|
136
|
+
*/
|
|
137
|
+
async crop(source: ImageSource, options: { left: number; top: number; width: number; height: number }): Promise<Response> {
|
|
138
|
+
const image = await this.resolveImage(source);
|
|
139
|
+
const formData = new FormData();
|
|
140
|
+
|
|
141
|
+
if (typeof image === "string") {
|
|
142
|
+
formData.append("image", image);
|
|
143
|
+
} else {
|
|
144
|
+
formData.append("image", image, "image.png");
|
|
145
|
+
}
|
|
146
|
+
|
|
147
|
+
formData.append("left", options.left.toString());
|
|
148
|
+
formData.append("top", options.top.toString());
|
|
149
|
+
formData.append("width", options.width.toString());
|
|
150
|
+
formData.append("height", options.height.toString());
|
|
151
|
+
|
|
152
|
+
return this.sdk._request("/v1/image/crop", {
|
|
153
|
+
method: "POST",
|
|
154
|
+
body: formData
|
|
155
|
+
}) as Promise<Response>;
|
|
156
|
+
}
|
|
157
|
+
}
|
|
@@ -0,0 +1,249 @@
|
|
|
1
|
+
import type { StorageOptions, FileInfo } from "../types";
|
|
2
|
+
|
|
3
|
+
/**
|
|
4
|
+
* Supported storage source types.
|
|
5
|
+
* Can be a local file path string, a Buffer, a Blob, or a File.
|
|
6
|
+
*/
|
|
7
|
+
export type StorageSource = string | Buffer | Blob | File;
|
|
8
|
+
|
|
9
|
+
/**
|
|
10
|
+
* Standalone module for interacting with Cludz Storage containers.
|
|
11
|
+
*/
|
|
12
|
+
export class Storage {
|
|
13
|
+
/** The base URL of the storage container. */
|
|
14
|
+
public readonly api: string;
|
|
15
|
+
/** The storage container identifier. */
|
|
16
|
+
public readonly id: string;
|
|
17
|
+
/** The access token for this storage container. */
|
|
18
|
+
public readonly token: string;
|
|
19
|
+
|
|
20
|
+
/**
|
|
21
|
+
* Initializes a new instance of the Storage client.
|
|
22
|
+
* @param options Configuration options for the storage container.
|
|
23
|
+
* @throws Error if any required option (api, id, token) is missing.
|
|
24
|
+
*/
|
|
25
|
+
constructor(options: StorageOptions) {
|
|
26
|
+
if (!options.api) throw new Error("API URL is required");
|
|
27
|
+
if (!options.id) throw new Error("Storage ID is required");
|
|
28
|
+
if (!options.token) throw new Error("Token is required");
|
|
29
|
+
|
|
30
|
+
this.api = `${options.api.replace(/\/$/, "")}/storage/${options.id}`;
|
|
31
|
+
this.id = options.id;
|
|
32
|
+
this.token = options.token;
|
|
33
|
+
}
|
|
34
|
+
|
|
35
|
+
/**
|
|
36
|
+
* Constructs headers for storage requests.
|
|
37
|
+
* @param additional Optional additional headers.
|
|
38
|
+
* @returns A record of headers.
|
|
39
|
+
* @private
|
|
40
|
+
*/
|
|
41
|
+
private getHeaders(additional: Record<string, string> = {}): Record<string, string> {
|
|
42
|
+
return {
|
|
43
|
+
Token: this.token,
|
|
44
|
+
...additional,
|
|
45
|
+
};
|
|
46
|
+
}
|
|
47
|
+
|
|
48
|
+
/**
|
|
49
|
+
* Normalizes a storage path by ensuring it starts with a slash.
|
|
50
|
+
* @param p The path to normalize.
|
|
51
|
+
* @returns The normalized path.
|
|
52
|
+
* @private
|
|
53
|
+
*/
|
|
54
|
+
private normalizePath(p: string): string {
|
|
55
|
+
return p.startsWith("/") ? p : `/${p}`;
|
|
56
|
+
}
|
|
57
|
+
|
|
58
|
+
/**
|
|
59
|
+
* Resolves various file sources into a Blob or File for FormData.
|
|
60
|
+
* @param source The file source (path, Buffer, Blob, or File).
|
|
61
|
+
* @param fileName Optional file name to use when resolving from generic sources.
|
|
62
|
+
* @returns A promise that resolves to a Blob or File.
|
|
63
|
+
* @private
|
|
64
|
+
*/
|
|
65
|
+
private async resolveFile(source: StorageSource, fileName: string = "file"): Promise<Blob | File> {
|
|
66
|
+
if (typeof source === "string") {
|
|
67
|
+
try {
|
|
68
|
+
// Try Bun first
|
|
69
|
+
// @ts-ignore
|
|
70
|
+
if (typeof Bun !== "undefined") {
|
|
71
|
+
// @ts-ignore
|
|
72
|
+
return Bun.file(source);
|
|
73
|
+
}
|
|
74
|
+
// Fallback to Node.js
|
|
75
|
+
const { readFile } = await import("node:fs/promises");
|
|
76
|
+
const buffer = await readFile(source);
|
|
77
|
+
// Extract filename from path if not provided
|
|
78
|
+
const name = fileName === "file" ? source.split(/[\\/]/).pop() || "file" : fileName;
|
|
79
|
+
return new File([buffer], name);
|
|
80
|
+
} catch (error: any) {
|
|
81
|
+
throw new Error(`Failed to read local file path: ${error.message}`);
|
|
82
|
+
}
|
|
83
|
+
}
|
|
84
|
+
|
|
85
|
+
if (source instanceof Blob || (typeof File !== "undefined" && source instanceof File)) {
|
|
86
|
+
return source;
|
|
87
|
+
}
|
|
88
|
+
|
|
89
|
+
if (Buffer.isBuffer(source)) {
|
|
90
|
+
return new Blob([source]);
|
|
91
|
+
}
|
|
92
|
+
|
|
93
|
+
throw new Error("Invalid file source type. Supported: local path string, Buffer, or Blob/File.");
|
|
94
|
+
}
|
|
95
|
+
|
|
96
|
+
/**
|
|
97
|
+
* Uploads a file to a specific directory in the storage.
|
|
98
|
+
* @param targetDirectory The target directory in storage (e.g., "/Documents").
|
|
99
|
+
* @param source The file source (local path, Buffer, Blob, or File).
|
|
100
|
+
* @param fileName Optional filename to use in storage.
|
|
101
|
+
* @returns A promise that resolves when the upload is complete.
|
|
102
|
+
* @throws Error if the upload fails.
|
|
103
|
+
*/
|
|
104
|
+
async upload(targetDirectory: string, source: StorageSource, fileName?: string): Promise<void> {
|
|
105
|
+
const url = `${this.api}${this.normalizePath(targetDirectory)}`;
|
|
106
|
+
const fileObj = await this.resolveFile(source, fileName);
|
|
107
|
+
|
|
108
|
+
const finalFileName = fileName || (fileObj instanceof File ? fileObj.name : "file");
|
|
109
|
+
|
|
110
|
+
const formData = new FormData();
|
|
111
|
+
formData.append("file", fileObj, finalFileName);
|
|
112
|
+
|
|
113
|
+
const response = await fetch(url, {
|
|
114
|
+
method: "POST",
|
|
115
|
+
headers: this.getHeaders(),
|
|
116
|
+
body: formData,
|
|
117
|
+
});
|
|
118
|
+
|
|
119
|
+
if (!response.ok) {
|
|
120
|
+
const errorText = await response.text();
|
|
121
|
+
throw new Error(`Upload failed: ${response.status} ${response.statusText} - ${errorText}`);
|
|
122
|
+
}
|
|
123
|
+
}
|
|
124
|
+
|
|
125
|
+
/**
|
|
126
|
+
* Deletes a file or directory from the storage.
|
|
127
|
+
* @param targetPath The path of the item to delete.
|
|
128
|
+
* @returns A promise that resolves when the deletion is complete.
|
|
129
|
+
* @throws Error if the deletion fails.
|
|
130
|
+
*/
|
|
131
|
+
async delete(targetPath: string): Promise<void> {
|
|
132
|
+
const url = `${this.api}${this.normalizePath(targetPath)}`;
|
|
133
|
+
const response = await fetch(url, {
|
|
134
|
+
method: "DELETE",
|
|
135
|
+
headers: this.getHeaders(),
|
|
136
|
+
});
|
|
137
|
+
|
|
138
|
+
if (!response.ok) {
|
|
139
|
+
const errorText = await response.text();
|
|
140
|
+
throw new Error(`Delete failed: ${response.status} ${response.statusText} - ${errorText}`);
|
|
141
|
+
}
|
|
142
|
+
}
|
|
143
|
+
|
|
144
|
+
/**
|
|
145
|
+
* Creates a new folder in the storage.
|
|
146
|
+
* @param parentPath The path to the parent directory.
|
|
147
|
+
* @param folderName The name of the new folder.
|
|
148
|
+
* @returns A promise that resolves when the folder is created.
|
|
149
|
+
* @throws Error if the folder creation fails.
|
|
150
|
+
*/
|
|
151
|
+
async createFolder(parentPath: string, folderName: string): Promise<void> {
|
|
152
|
+
const url = `${this.api}${this.normalizePath(parentPath)}`;
|
|
153
|
+
const response = await fetch(url, {
|
|
154
|
+
method: "POST",
|
|
155
|
+
headers: this.getHeaders({ "Content-Type": "application/json" }),
|
|
156
|
+
body: JSON.stringify({ type: "folder", name: folderName }),
|
|
157
|
+
});
|
|
158
|
+
|
|
159
|
+
if (!response.ok) {
|
|
160
|
+
const errorText = await response.text();
|
|
161
|
+
throw new Error(`Create folder failed: ${response.status} ${response.statusText} - ${errorText}`);
|
|
162
|
+
}
|
|
163
|
+
}
|
|
164
|
+
|
|
165
|
+
/**
|
|
166
|
+
* Creates an empty file in the storage.
|
|
167
|
+
* @param parentPath The path to the parent directory.
|
|
168
|
+
* @param fileName The name of the new file.
|
|
169
|
+
* @returns A promise that resolves when the file is created.
|
|
170
|
+
* @throws Error if the file creation fails.
|
|
171
|
+
*/
|
|
172
|
+
async createFile(parentPath: string, fileName: string): Promise<void> {
|
|
173
|
+
const url = `${this.api}${this.normalizePath(parentPath)}`;
|
|
174
|
+
const response = await fetch(url, {
|
|
175
|
+
method: "POST",
|
|
176
|
+
headers: this.getHeaders({ "Content-Type": "application/json" }),
|
|
177
|
+
body: JSON.stringify({ type: "file", name: fileName }),
|
|
178
|
+
});
|
|
179
|
+
|
|
180
|
+
if (!response.ok) {
|
|
181
|
+
const errorText = await response.text();
|
|
182
|
+
throw new Error(`Create file failed: ${response.status} ${response.statusText} - ${errorText}`);
|
|
183
|
+
}
|
|
184
|
+
}
|
|
185
|
+
|
|
186
|
+
/**
|
|
187
|
+
* Renames or moves a file or directory in the storage.
|
|
188
|
+
* @param targetPath The current path of the item.
|
|
189
|
+
* @param newName The new name for the item.
|
|
190
|
+
* @returns A promise that resolves when the item is renamed.
|
|
191
|
+
* @throws Error if the rename operation fails.
|
|
192
|
+
*/
|
|
193
|
+
async rename(targetPath: string, newName: string): Promise<void> {
|
|
194
|
+
const url = `${this.api}${this.normalizePath(targetPath)}`;
|
|
195
|
+
const response = await fetch(url, {
|
|
196
|
+
method: "PUT",
|
|
197
|
+
headers: this.getHeaders({ "Content-Type": "application/json" }),
|
|
198
|
+
body: JSON.stringify({ new_name: newName }),
|
|
199
|
+
});
|
|
200
|
+
|
|
201
|
+
if (!response.ok) {
|
|
202
|
+
const errorText = await response.text();
|
|
203
|
+
throw new Error(`Rename failed: ${response.status} ${response.statusText} - ${errorText}`);
|
|
204
|
+
}
|
|
205
|
+
}
|
|
206
|
+
|
|
207
|
+
/**
|
|
208
|
+
* Lists the contents of a directory in the storage.
|
|
209
|
+
* @param targetPath The path of the directory to list.
|
|
210
|
+
* @returns A promise that resolves to an array of file and directory information.
|
|
211
|
+
* @throws Error if the list operation fails.
|
|
212
|
+
*/
|
|
213
|
+
async list(targetPath: string): Promise<FileInfo[]> {
|
|
214
|
+
const url = `${this.api}${this.normalizePath(targetPath)}`;
|
|
215
|
+
const response = await fetch(url, {
|
|
216
|
+
method: "GET",
|
|
217
|
+
headers: this.getHeaders(),
|
|
218
|
+
});
|
|
219
|
+
|
|
220
|
+
if (!response.ok) {
|
|
221
|
+
const errorText = await response.text();
|
|
222
|
+
throw new Error(`List failed: ${response.status} ${response.statusText} - ${errorText}`);
|
|
223
|
+
}
|
|
224
|
+
|
|
225
|
+
const json = await response.json() as { data: FileInfo[] };
|
|
226
|
+
return json.data;
|
|
227
|
+
}
|
|
228
|
+
|
|
229
|
+
/**
|
|
230
|
+
* Downloads a file from the storage as a Blob.
|
|
231
|
+
* @param targetPath The path of the file in storage.
|
|
232
|
+
* @returns A promise that resolves to the file data as a Blob.
|
|
233
|
+
* @throws Error if the download operation fails.
|
|
234
|
+
*/
|
|
235
|
+
async download(targetPath: string): Promise<Blob> {
|
|
236
|
+
const url = `${this.api}${this.normalizePath(targetPath)}`;
|
|
237
|
+
const response = await fetch(url, {
|
|
238
|
+
method: "GET",
|
|
239
|
+
headers: this.getHeaders(),
|
|
240
|
+
});
|
|
241
|
+
|
|
242
|
+
if (!response.ok) {
|
|
243
|
+
const errorText = await response.text();
|
|
244
|
+
throw new Error(`Download failed: ${response.status} ${response.statusText} - ${errorText}`);
|
|
245
|
+
}
|
|
246
|
+
|
|
247
|
+
return response.blob();
|
|
248
|
+
}
|
|
249
|
+
}
|
package/modules/tasks.ts
ADDED
|
@@ -0,0 +1,54 @@
|
|
|
1
|
+
import type { Cludz } from "../index";
|
|
2
|
+
import type { ApiResponse, TaskState, TaskData } from "../types";
|
|
3
|
+
|
|
4
|
+
/**
|
|
5
|
+
* Module for managing and waiting for background tasks.
|
|
6
|
+
*/
|
|
7
|
+
export class Tasks {
|
|
8
|
+
/** @internal */
|
|
9
|
+
constructor(private sdk: Cludz) {}
|
|
10
|
+
|
|
11
|
+
/**
|
|
12
|
+
* Retrieves the current state of a specific background task.
|
|
13
|
+
* @template T The expected type of the task result data. Defaults to TaskData.
|
|
14
|
+
* @param id The unique task identifier.
|
|
15
|
+
* @returns A promise that resolves to the task state.
|
|
16
|
+
*/
|
|
17
|
+
public get<T = TaskData>(id: string): Promise<ApiResponse<TaskState<T>>> {
|
|
18
|
+
return this.sdk._request(`/v1/tasks/${id}`) as Promise<ApiResponse<TaskState<T>>>;
|
|
19
|
+
}
|
|
20
|
+
|
|
21
|
+
/**
|
|
22
|
+
* Polls a task until it reaches a "Completed" or "Failed" state.
|
|
23
|
+
* @template T The expected type of the task result data. Defaults to TaskData.
|
|
24
|
+
* @param id The unique task identifier.
|
|
25
|
+
* @param interval Polling interval in milliseconds. Defaults to 1000.
|
|
26
|
+
* @param timeout Maximum time to wait in milliseconds. Defaults to 60000.
|
|
27
|
+
* @returns A promise that resolves to the final task state.
|
|
28
|
+
* @throws Error if the task fails or times out.
|
|
29
|
+
*/
|
|
30
|
+
public async waitFor<T = TaskData>(
|
|
31
|
+
id: string,
|
|
32
|
+
interval: number = 1000,
|
|
33
|
+
timeout: number = 60000
|
|
34
|
+
): Promise<TaskState<T>> {
|
|
35
|
+
const start = Date.now();
|
|
36
|
+
|
|
37
|
+
while (Date.now() - start < timeout) {
|
|
38
|
+
const resp = await this.get(id);
|
|
39
|
+
const task = resp.data;
|
|
40
|
+
|
|
41
|
+
if (task.status === "Completed") {
|
|
42
|
+
return task as TaskState<T>;
|
|
43
|
+
}
|
|
44
|
+
|
|
45
|
+
if (task.status === "Failed") {
|
|
46
|
+
throw new Error(task.message || task.error || "Task failed");
|
|
47
|
+
}
|
|
48
|
+
|
|
49
|
+
await new Promise((resolve) => setTimeout(resolve, interval));
|
|
50
|
+
}
|
|
51
|
+
|
|
52
|
+
throw new Error(`Task timeout after ${timeout}ms`);
|
|
53
|
+
}
|
|
54
|
+
}
|
package/modules/tools.ts
ADDED
|
@@ -0,0 +1,97 @@
|
|
|
1
|
+
import type { Cludz } from "../index";
|
|
2
|
+
import type { ApiResponse, WebCheckResult, DnsResult, SslResult } from "../types";
|
|
3
|
+
|
|
4
|
+
/**
|
|
5
|
+
* Options for barcode generation.
|
|
6
|
+
*/
|
|
7
|
+
export interface BarcodeOptions {
|
|
8
|
+
/** The barcode symbology type (e.g., "code128", "ean13"). */
|
|
9
|
+
type?: string;
|
|
10
|
+
/** Whether to show the text below the barcode. */
|
|
11
|
+
showText?: boolean;
|
|
12
|
+
/** Scaling factor for the barcode. */
|
|
13
|
+
scale?: number;
|
|
14
|
+
/** Height of the barcode in pixels. */
|
|
15
|
+
height?: number;
|
|
16
|
+
}
|
|
17
|
+
|
|
18
|
+
/**
|
|
19
|
+
* Module for various utility tools including network checks and media generation.
|
|
20
|
+
*/
|
|
21
|
+
export class Tools {
|
|
22
|
+
/** @internal */
|
|
23
|
+
constructor(private sdk: Cludz) {}
|
|
24
|
+
|
|
25
|
+
/**
|
|
26
|
+
* Performs a web connectivity check on a URL.
|
|
27
|
+
* @param url The URL to check.
|
|
28
|
+
* @returns A promise that resolves to the web check results.
|
|
29
|
+
*/
|
|
30
|
+
async webCheck(url: string): Promise<ApiResponse<WebCheckResult>> {
|
|
31
|
+
return this.sdk._request("/v1/tools/web-check", {
|
|
32
|
+
query: { url }
|
|
33
|
+
}) as Promise<ApiResponse<WebCheckResult>>;
|
|
34
|
+
}
|
|
35
|
+
|
|
36
|
+
/**
|
|
37
|
+
* Retrieves DNS records for a specific domain.
|
|
38
|
+
* @param domain The domain name to query.
|
|
39
|
+
* @returns A promise that resolves to the DNS results.
|
|
40
|
+
*/
|
|
41
|
+
async dns(domain: string): Promise<ApiResponse<DnsResult>> {
|
|
42
|
+
return this.sdk._request("/v1/tools/dns", {
|
|
43
|
+
query: { domain }
|
|
44
|
+
}) as Promise<ApiResponse<DnsResult>>;
|
|
45
|
+
}
|
|
46
|
+
|
|
47
|
+
/**
|
|
48
|
+
* Retrieves SSL certificate information for a domain.
|
|
49
|
+
* @param domain The domain name to query.
|
|
50
|
+
* @returns A promise that resolves to the SSL information.
|
|
51
|
+
*/
|
|
52
|
+
async ssl(domain: string): Promise<ApiResponse<SslResult>> {
|
|
53
|
+
return this.sdk._request("/v1/tools/ssl", {
|
|
54
|
+
query: { domain }
|
|
55
|
+
}) as Promise<ApiResponse<SslResult>>;
|
|
56
|
+
}
|
|
57
|
+
|
|
58
|
+
/**
|
|
59
|
+
* Retrieves OpenGraph metadata for a given URL.
|
|
60
|
+
* @param url The URL to analyze.
|
|
61
|
+
* @returns A promise that resolves to the metadata.
|
|
62
|
+
*/
|
|
63
|
+
async meta(url: string): Promise<ApiResponse> {
|
|
64
|
+
return this.sdk._request("/v1/tools/meta", {
|
|
65
|
+
query: { url }
|
|
66
|
+
}) as Promise<ApiResponse>;
|
|
67
|
+
}
|
|
68
|
+
|
|
69
|
+
/**
|
|
70
|
+
* Generates a QR Code image.
|
|
71
|
+
* @param text The text or URL to encode in the QR code.
|
|
72
|
+
* @returns A promise that resolves to a Response object containing the image.
|
|
73
|
+
*/
|
|
74
|
+
async qr(text: string): Promise<Response> {
|
|
75
|
+
return this.sdk._request("/v1/tools/qr", {
|
|
76
|
+
query: { text }
|
|
77
|
+
}) as Promise<Response>;
|
|
78
|
+
}
|
|
79
|
+
|
|
80
|
+
/**
|
|
81
|
+
* Generates a Barcode image.
|
|
82
|
+
* @param text The text to encode in the barcode.
|
|
83
|
+
* @param options Configuration options for barcode generation.
|
|
84
|
+
* @returns A promise that resolves to a Response object containing the image.
|
|
85
|
+
*/
|
|
86
|
+
async barcode(text: string, options: BarcodeOptions = {}): Promise<Response> {
|
|
87
|
+
return this.sdk._request("/v1/tools/barcode", {
|
|
88
|
+
query: {
|
|
89
|
+
text,
|
|
90
|
+
type: options.type,
|
|
91
|
+
show_text: options.showText ?? true,
|
|
92
|
+
scale: options.scale,
|
|
93
|
+
height: options.height
|
|
94
|
+
}
|
|
95
|
+
}) as Promise<Response>;
|
|
96
|
+
}
|
|
97
|
+
}
|
package/package.json
ADDED
|
@@ -0,0 +1,14 @@
|
|
|
1
|
+
{
|
|
2
|
+
"name": "@cludz/sdk",
|
|
3
|
+
"description": "Cludz API JavaScript SDK",
|
|
4
|
+
"version": "0.2.3",
|
|
5
|
+
"module": "index.ts",
|
|
6
|
+
"type": "module",
|
|
7
|
+
"private": false,
|
|
8
|
+
"devDependencies": {
|
|
9
|
+
"@types/bun": "latest"
|
|
10
|
+
},
|
|
11
|
+
"peerDependencies": {
|
|
12
|
+
"typescript": "^5"
|
|
13
|
+
}
|
|
14
|
+
}
|
package/tsconfig.json
ADDED
|
@@ -0,0 +1,29 @@
|
|
|
1
|
+
{
|
|
2
|
+
"compilerOptions": {
|
|
3
|
+
// Environment setup & latest features
|
|
4
|
+
"lib": ["ESNext"],
|
|
5
|
+
"target": "ESNext",
|
|
6
|
+
"module": "Preserve",
|
|
7
|
+
"moduleDetection": "force",
|
|
8
|
+
"jsx": "react-jsx",
|
|
9
|
+
"allowJs": true,
|
|
10
|
+
|
|
11
|
+
// Bundler mode
|
|
12
|
+
"moduleResolution": "bundler",
|
|
13
|
+
"allowImportingTsExtensions": true,
|
|
14
|
+
"verbatimModuleSyntax": true,
|
|
15
|
+
"noEmit": true,
|
|
16
|
+
|
|
17
|
+
// Best practices
|
|
18
|
+
"strict": true,
|
|
19
|
+
"skipLibCheck": true,
|
|
20
|
+
"noFallthroughCasesInSwitch": true,
|
|
21
|
+
"noUncheckedIndexedAccess": true,
|
|
22
|
+
"noImplicitOverride": true,
|
|
23
|
+
|
|
24
|
+
// Some stricter flags (disabled by default)
|
|
25
|
+
"noUnusedLocals": false,
|
|
26
|
+
"noUnusedParameters": false,
|
|
27
|
+
"noPropertyAccessFromIndexSignature": false
|
|
28
|
+
}
|
|
29
|
+
}
|
package/types.ts
ADDED
|
@@ -0,0 +1,290 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Options for initializing the Cludz client.
|
|
3
|
+
*/
|
|
4
|
+
export interface CludzOptions {
|
|
5
|
+
/** The base URL of the Cludz API. */
|
|
6
|
+
api: string;
|
|
7
|
+
/** The API key for authentication. */
|
|
8
|
+
key?: string;
|
|
9
|
+
}
|
|
10
|
+
|
|
11
|
+
/**
|
|
12
|
+
* Standard API response wrapper.
|
|
13
|
+
* @template T The type of the data returned by the API.
|
|
14
|
+
*/
|
|
15
|
+
export interface ApiResponse<T = any> {
|
|
16
|
+
/** HTTP status code. */
|
|
17
|
+
statusCode: number;
|
|
18
|
+
/** Short description of the status. */
|
|
19
|
+
statusMessage: string;
|
|
20
|
+
/** Detailed message from the server. */
|
|
21
|
+
message: string;
|
|
22
|
+
/** The actual response data. */
|
|
23
|
+
data: T;
|
|
24
|
+
}
|
|
25
|
+
|
|
26
|
+
/**
|
|
27
|
+
* Options for making an internal SDK request.
|
|
28
|
+
*/
|
|
29
|
+
export interface RequestOptions {
|
|
30
|
+
/** The HTTP method to use. */
|
|
31
|
+
method?: "GET" | "POST" | "PUT" | "DELETE";
|
|
32
|
+
/** URL query parameters. */
|
|
33
|
+
query?: Record<string, any>;
|
|
34
|
+
/** Request body data. */
|
|
35
|
+
body?: any;
|
|
36
|
+
}
|
|
37
|
+
|
|
38
|
+
/**
|
|
39
|
+
* Information about the current account and API key.
|
|
40
|
+
*/
|
|
41
|
+
export interface AccountInfo {
|
|
42
|
+
/** Account details. */
|
|
43
|
+
account: {
|
|
44
|
+
/** Unique account identifier. */
|
|
45
|
+
id: string;
|
|
46
|
+
};
|
|
47
|
+
/** API key details. */
|
|
48
|
+
token: {
|
|
49
|
+
/** Name of the API key. */
|
|
50
|
+
name: string;
|
|
51
|
+
/** Total number of requests made with this key. */
|
|
52
|
+
total_requests: number;
|
|
53
|
+
/** Last time the key was used. */
|
|
54
|
+
last_used_at: string | null;
|
|
55
|
+
/** When the key was created. */
|
|
56
|
+
created_at: string;
|
|
57
|
+
};
|
|
58
|
+
/** License details. */
|
|
59
|
+
license: {
|
|
60
|
+
/** License name. */
|
|
61
|
+
name: string;
|
|
62
|
+
/** Whether the license is currently active. */
|
|
63
|
+
is_active: boolean;
|
|
64
|
+
/** When the license expires. */
|
|
65
|
+
expires_at: string | null;
|
|
66
|
+
};
|
|
67
|
+
/** Rate limiting details. */
|
|
68
|
+
rate_limit: {
|
|
69
|
+
/** Maximum requests allowed per minute. */
|
|
70
|
+
limit_per_minute: number;
|
|
71
|
+
/** Requests used in the current minute. */
|
|
72
|
+
used_this_minute: number;
|
|
73
|
+
/** Requests remaining for the current minute. */
|
|
74
|
+
remaining: number;
|
|
75
|
+
/** When the rate limit resets. */
|
|
76
|
+
reset_at: string;
|
|
77
|
+
/** Seconds remaining until the rate limit resets. */
|
|
78
|
+
reset_in_seconds: number;
|
|
79
|
+
};
|
|
80
|
+
}
|
|
81
|
+
|
|
82
|
+
/**
|
|
83
|
+
* Statistics for API monitoring.
|
|
84
|
+
*/
|
|
85
|
+
export interface MonitoringStats {
|
|
86
|
+
/** Total requests processed. */
|
|
87
|
+
requests: number;
|
|
88
|
+
/** Server uptime string. */
|
|
89
|
+
uptime: string;
|
|
90
|
+
/** Current error rate percentage. */
|
|
91
|
+
error_rate: number;
|
|
92
|
+
/** Average response time in milliseconds. */
|
|
93
|
+
avg_response_time_ms: number;
|
|
94
|
+
/** Timestamp of the statistics. */
|
|
95
|
+
timestamp: string;
|
|
96
|
+
}
|
|
97
|
+
|
|
98
|
+
/**
|
|
99
|
+
* Represents a single YouTube search result.
|
|
100
|
+
*/
|
|
101
|
+
export interface YouTubeSearchResult {
|
|
102
|
+
/** YouTube video ID. */
|
|
103
|
+
id: string;
|
|
104
|
+
/** Video title. */
|
|
105
|
+
title: string;
|
|
106
|
+
/** YouTube video URL. */
|
|
107
|
+
url: string;
|
|
108
|
+
/** Thumbnail image URL. */
|
|
109
|
+
thumbnail: string;
|
|
110
|
+
/** Video description. */
|
|
111
|
+
description: string;
|
|
112
|
+
/** Duration in seconds. */
|
|
113
|
+
duration: number;
|
|
114
|
+
/** Formatted duration string (e.g., "3:45"). */
|
|
115
|
+
duration_string: string;
|
|
116
|
+
/** Number of views. */
|
|
117
|
+
views: number;
|
|
118
|
+
/** URL of the video webpage. */
|
|
119
|
+
webpage_url: string;
|
|
120
|
+
}
|
|
121
|
+
|
|
122
|
+
/**
|
|
123
|
+
* List of YouTube search results.
|
|
124
|
+
*/
|
|
125
|
+
export interface YouTubeSearchList {
|
|
126
|
+
/** Number of results returned. */
|
|
127
|
+
count: number;
|
|
128
|
+
/** The list of search results. */
|
|
129
|
+
list: YouTubeSearchResult[];
|
|
130
|
+
}
|
|
131
|
+
|
|
132
|
+
/**
|
|
133
|
+
* Result of a media download request.
|
|
134
|
+
*/
|
|
135
|
+
export interface DownloadResult {
|
|
136
|
+
/** The URL where the media can be downloaded. */
|
|
137
|
+
download_url: string;
|
|
138
|
+
}
|
|
139
|
+
|
|
140
|
+
/**
|
|
141
|
+
* Result of a web connectivity check.
|
|
142
|
+
*/
|
|
143
|
+
export interface WebCheckResult {
|
|
144
|
+
/** HTTP status code of the target URL. */
|
|
145
|
+
status: number;
|
|
146
|
+
/** HTTP status text. */
|
|
147
|
+
statusText: string;
|
|
148
|
+
/** Content type of the response. */
|
|
149
|
+
contentType: string;
|
|
150
|
+
/** Latency in a human-readable format. */
|
|
151
|
+
latency: string;
|
|
152
|
+
}
|
|
153
|
+
|
|
154
|
+
/**
|
|
155
|
+
* DNS lookup results.
|
|
156
|
+
*/
|
|
157
|
+
export interface DnsResult {
|
|
158
|
+
/** A (IPv4) records. */
|
|
159
|
+
A?: string[];
|
|
160
|
+
/** AAAA (IPv6) records. */
|
|
161
|
+
AAAA?: string[];
|
|
162
|
+
/** MX (Mail Exchange) records. */
|
|
163
|
+
MX?: { exchange: string; priority: number }[];
|
|
164
|
+
/** TXT (Text) records. */
|
|
165
|
+
TXT?: string[][];
|
|
166
|
+
/** NS (Name Server) records. */
|
|
167
|
+
NS?: string[];
|
|
168
|
+
}
|
|
169
|
+
|
|
170
|
+
/**
|
|
171
|
+
* SSL certificate information.
|
|
172
|
+
*/
|
|
173
|
+
export interface SslResult {
|
|
174
|
+
/** Certificate subject. */
|
|
175
|
+
subject: any;
|
|
176
|
+
/** Certificate issuer. */
|
|
177
|
+
issuer: any;
|
|
178
|
+
/** Start of validity period. */
|
|
179
|
+
valid_from: string;
|
|
180
|
+
/** End of validity period. */
|
|
181
|
+
valid_to: string;
|
|
182
|
+
/** Days remaining until expiration. */
|
|
183
|
+
remaining_days: number;
|
|
184
|
+
}
|
|
185
|
+
|
|
186
|
+
/**
|
|
187
|
+
* Result of starting a background task.
|
|
188
|
+
*/
|
|
189
|
+
export interface TaskResult {
|
|
190
|
+
/** Unique task identifier. */
|
|
191
|
+
taskId: string;
|
|
192
|
+
/** URL to poll for task status. */
|
|
193
|
+
status_url: string;
|
|
194
|
+
}
|
|
195
|
+
|
|
196
|
+
/**
|
|
197
|
+
* Unified interface representing all possible task result data.
|
|
198
|
+
* All fields are optional to support different task types.
|
|
199
|
+
*/
|
|
200
|
+
export interface TaskData {
|
|
201
|
+
/** Number of results (YouTube search). */
|
|
202
|
+
count?: number;
|
|
203
|
+
/** List of search results (YouTube search). */
|
|
204
|
+
list?: YouTubeSearchResult[];
|
|
205
|
+
/** URL for media download (Downloader). */
|
|
206
|
+
download_url?: string;
|
|
207
|
+
/** HTTP status code (Web check). */
|
|
208
|
+
status?: number;
|
|
209
|
+
/** HTTP status text (Web check). */
|
|
210
|
+
statusText?: string;
|
|
211
|
+
/** Response content type (Web check). */
|
|
212
|
+
contentType?: string;
|
|
213
|
+
/** Response latency (Web check). */
|
|
214
|
+
latency?: string;
|
|
215
|
+
/** IPv4 records (DNS). */
|
|
216
|
+
A?: string[];
|
|
217
|
+
/** IPv6 records (DNS). */
|
|
218
|
+
AAAA?: string[];
|
|
219
|
+
/** MX records (DNS). */
|
|
220
|
+
MX?: { exchange: string; priority: number }[];
|
|
221
|
+
/** TXT records (DNS). */
|
|
222
|
+
TXT?: string[][];
|
|
223
|
+
/** Name server records (DNS). */
|
|
224
|
+
NS?: string[];
|
|
225
|
+
/** Certificate subject (SSL). */
|
|
226
|
+
subject?: any;
|
|
227
|
+
/** Certificate issuer (SSL). */
|
|
228
|
+
issuer?: any;
|
|
229
|
+
/** Certificate valid from date (SSL). */
|
|
230
|
+
valid_from?: string;
|
|
231
|
+
/** Certificate valid to date (SSL). */
|
|
232
|
+
valid_to?: string;
|
|
233
|
+
/** Days remaining for SSL certificate (SSL). */
|
|
234
|
+
remaining_days?: number;
|
|
235
|
+
}
|
|
236
|
+
|
|
237
|
+
/**
|
|
238
|
+
* Current state of a background task.
|
|
239
|
+
* @template T The type of the result data when the task is completed. Defaults to TaskData.
|
|
240
|
+
*/
|
|
241
|
+
export interface TaskState<T = TaskData> {
|
|
242
|
+
/** Unique task identifier. */
|
|
243
|
+
id: string;
|
|
244
|
+
/** User ID associated with the task, if any. */
|
|
245
|
+
user_id: string | null;
|
|
246
|
+
/** Current status of the task. */
|
|
247
|
+
status: "Pending" | "Processing" | "Completed" | "Failed";
|
|
248
|
+
/** Progress percentage (0-100). */
|
|
249
|
+
progress: number;
|
|
250
|
+
/** Status message or update. */
|
|
251
|
+
message: string | null;
|
|
252
|
+
/** Final task result data. */
|
|
253
|
+
data: T | null;
|
|
254
|
+
/** Error message if the task failed. */
|
|
255
|
+
error: string | null;
|
|
256
|
+
/** When the task was created. */
|
|
257
|
+
created_at: string;
|
|
258
|
+
/** When the task was last updated. */
|
|
259
|
+
updated_at: string;
|
|
260
|
+
}
|
|
261
|
+
|
|
262
|
+
/**
|
|
263
|
+
* Options for initializing a Storage instance.
|
|
264
|
+
*/
|
|
265
|
+
export interface StorageOptions {
|
|
266
|
+
/** The base URL of the Cludz Storage API. */
|
|
267
|
+
api: string;
|
|
268
|
+
/** The storage container identifier. */
|
|
269
|
+
id: string;
|
|
270
|
+
/** The access token for this storage container. */
|
|
271
|
+
token: string;
|
|
272
|
+
}
|
|
273
|
+
|
|
274
|
+
/**
|
|
275
|
+
* Information about a file or directory in storage.
|
|
276
|
+
*/
|
|
277
|
+
export interface FileInfo {
|
|
278
|
+
/** Name of the item. */
|
|
279
|
+
name: string;
|
|
280
|
+
/** Size in bytes. */
|
|
281
|
+
size: number;
|
|
282
|
+
/** Whether the item is a directory. */
|
|
283
|
+
isDirectory: boolean;
|
|
284
|
+
/** Item checksum for integrity verification. */
|
|
285
|
+
checksum: string;
|
|
286
|
+
/** When the item was created. */
|
|
287
|
+
created_at: string;
|
|
288
|
+
/** When the item was last modified. */
|
|
289
|
+
modified_at: string;
|
|
290
|
+
}
|