whisperai-sdk 1.0.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/README.md ADDED
@@ -0,0 +1,163 @@
1
+ # whisperai-sdk
2
+
3
+ Unofficial TypeScript SDK for [WhisperAI](https://whisperai.com/). This package provides methods and interfaces for interacting with the WhisperAI service without external runtime dependencies (except axios).
4
+
5
+ **Disclaimer:** This is an unofficial implementation and is not affiliated with WhisperAI.
6
+
7
+ ## Installation
8
+
9
+ ```bash
10
+ npm install whisperai-sdk
11
+ ```
12
+
13
+ ## Usage
14
+
15
+ ### Initialization
16
+
17
+ Initialize the client with your WhisperAI credentials.
18
+
19
+ ```typescript
20
+ import { WhisperClient } from 'whisperai-sdk';
21
+
22
+ const client = new WhisperClient({
23
+ login: {
24
+ email: "your-email@example.com",
25
+ password: "your-password"
26
+ },
27
+ // Optional: Override default settings
28
+ // whisperUrl: "https://whisperai.com",
29
+ // chunkSize: 8 * 1024 * 1024 // 8MB
30
+ });
31
+ ```
32
+
33
+ The client handles authentication automatically. It will log in on the first request and refresh the session if the token expires.
34
+
35
+ ### Methods
36
+
37
+ #### User & Account
38
+
39
+ Get current user information, usage statistics, and subscription details.
40
+
41
+ ```typescript
42
+ // Get user info
43
+ const userInfo = await client.user();
44
+ console.log(`User: ${userInfo.firstName} ${userInfo.lastName}`);
45
+
46
+ // Get usage stats
47
+ const usage = await client.usage();
48
+ console.log(`Monthly Usage: ${usage.monthlyUsageMinutes} minutes`);
49
+
50
+ // Get subscription details
51
+ const subscription = await client.subscriptionDetails();
52
+ ```
53
+
54
+ #### Uploading Audio
55
+
56
+ Upload audio files for transcription. The `upload` method handles file chunking automatically.
57
+
58
+ ```typescript
59
+ import fs from 'fs';
60
+
61
+ // Read file buffer
62
+ const buffer = fs.readFileSync('./interview.mp3');
63
+
64
+ // Upload
65
+ const result = await client.upload(buffer, {
66
+ filename: 'interview.mp3',
67
+ durationSeconds: 120, // Total duration in seconds
68
+ mimeType: 'audio/mpeg', // Optional
69
+ title: 'Interview with John Doe', // Optional
70
+ enableSpeakerDetection: true, // Optional
71
+ speakerCount: 'auto' // Optional: 'auto' or number
72
+ });
73
+
74
+ console.log(`Uploaded recording ID: ${result.id}`);
75
+ ```
76
+
77
+ #### Transcription
78
+
79
+ Manage transcriptions for uploaded recordings.
80
+
81
+ ```typescript
82
+ const recordingId = 12345;
83
+
84
+ // Start/Request transcription
85
+ const transcriptionJob = await client.transcription(recordingId);
86
+
87
+ // Check recording status and get transcription result
88
+ const recording = await client.recording(recordingId);
89
+
90
+ if (recording.status === 'completed' && recording.transcription) {
91
+ console.log(recording.transcription.content);
92
+
93
+ // Access segments with timestamps
94
+ recording.transcription.segments.forEach(segment => {
95
+ console.log(`[${segment.start} - ${segment.end}]: ${segment.text}`);
96
+ });
97
+ }
98
+ ```
99
+
100
+ #### Translation
101
+
102
+ Translate a recording to another language.
103
+
104
+ ```typescript
105
+ const recordingId = 12345;
106
+
107
+ // Translate to Spanish
108
+ const translation = await client.translate(recordingId, 'es');
109
+ ```
110
+
111
+ #### Recordings Management
112
+
113
+ List and retrieve recordings.
114
+
115
+ ```typescript
116
+ // Get a specific recording by ID
117
+ const recording = await client.recording(recordingId);
118
+
119
+ // List recordings (paginated)
120
+ const recordingsList = await client.recordings({
121
+ limit: 10,
122
+ page: 1,
123
+ // search: "interview", // Optional search query
124
+ // status: "completed" // Optional status filter
125
+ });
126
+
127
+ console.log(`Found ${recordingsList.meta.totalItems} recordings`);
128
+ ```
129
+
130
+ #### Analytics
131
+
132
+ Get a summary of your activity.
133
+
134
+ ```typescript
135
+ const summary = await client.summary();
136
+ console.log(`Total recordings: ${summary.recordings.total}`);
137
+ ```
138
+
139
+ ## Error Handling
140
+
141
+ The SDK throws specific errors for different failure scenarios.
142
+
143
+ ```typescript
144
+ import { WhisperAuthError, WhisperNetworkError, WhisperApiError } from 'whisperai-sdk/errors';
145
+
146
+ try {
147
+ await client.user();
148
+ } catch (error) {
149
+ if (error instanceof WhisperAuthError) {
150
+ console.error("Authentication failed. Check credentials.");
151
+ } else if (error instanceof WhisperNetworkError) {
152
+ console.error("Network issue.");
153
+ } else if (error instanceof WhisperApiError) {
154
+ console.error(`API Error ${error.status}: ${JSON.stringify(error.data)}`);
155
+ } else {
156
+ console.error("Unknown error:", error);
157
+ }
158
+ }
159
+ ```
160
+
161
+ ## License
162
+
163
+ MIT
@@ -0,0 +1,35 @@
1
+ import type { ClientOptions, UserInfo, UsageInfo, InitMetaFile, InitChunkResponse, UploadChunkResponse, FinalizeChunkResponse, TranscriptionResponse, TranslateResponse, SummaryResponse, RecordingResponse, RecordingsQuery, RecordingsResponse, SubscriptionDetailsResponse } from "./types.js";
2
+ export declare class WhisperClient {
3
+ private cookies?;
4
+ private readonly clientOptions;
5
+ constructor(clientOptions: ClientOptions);
6
+ login(): Promise<UserInfo>;
7
+ user(): Promise<UserInfo>;
8
+ usage(): Promise<UsageInfo>;
9
+ subscriptionDetails(): Promise<SubscriptionDetailsResponse>;
10
+ upload(fileBuffer: Uint8Array, meta: InitMetaFile): Promise<FinalizeChunkResponse>;
11
+ initChunk(fileBuffer: Uint8Array, meta: InitMetaFile): Promise<InitChunkResponse>;
12
+ uploadChunk(fileBuffer: Uint8Array, recordingId: number, chunkIndex: number): Promise<UploadChunkResponse>;
13
+ finalizeChunk(recordingId: number): Promise<FinalizeChunkResponse>;
14
+ transcription(recordingId: number): Promise<TranscriptionResponse>;
15
+ translate(recordingId: number, language: string): Promise<TranslateResponse>;
16
+ recording(recordingId: number): Promise<RecordingResponse>;
17
+ recordings(query?: RecordingsQuery): Promise<RecordingsResponse>;
18
+ summary(): Promise<SummaryResponse>;
19
+ private get loginLink();
20
+ private get userLink();
21
+ private get usageLink();
22
+ private get subscriptionDetailsLink();
23
+ private get initChunkLink();
24
+ private get uploadChunkLink();
25
+ private get finalizeChunkLink();
26
+ private get transcriptionLink();
27
+ private get summaryLink();
28
+ private translateLink;
29
+ private recordingLink;
30
+ private get recordingsLink();
31
+ private getCountChunks;
32
+ private get requestOptions();
33
+ private recall;
34
+ private handleRequest;
35
+ }
@@ -0,0 +1,9 @@
1
+ export declare enum WhisperStatus {
2
+ PENDING = "pending",
3
+ VALIDATING = "validating",
4
+ UPLOADING = "uploading",
5
+ PROCESSING = "processing",
6
+ COMPLETED = "completed",
7
+ FAILED = "failed",
8
+ CANCELLED = "cancelled"
9
+ }
@@ -0,0 +1,18 @@
1
+ export declare abstract class WhisperError extends Error {
2
+ abstract readonly code: string;
3
+ protected constructor(message: string);
4
+ }
5
+ export declare class WhisperApiError extends WhisperError {
6
+ readonly status: number;
7
+ readonly response: unknown;
8
+ readonly code = "API_ERROR";
9
+ constructor(status: number, response: unknown);
10
+ }
11
+ export declare class WhisperAuthError extends WhisperError {
12
+ readonly code = "AUTH_ERROR";
13
+ constructor();
14
+ }
15
+ export declare class WhisperNetworkError extends WhisperError {
16
+ readonly code = "NETWORK_ERROR";
17
+ constructor(cause?: unknown);
18
+ }
@@ -0,0 +1,3 @@
1
+ export * from "./types.js";
2
+ export * from "./client.js";
3
+ export * from "./constant.js";
package/dist/index.js ADDED
@@ -0,0 +1,203 @@
1
+ // src/client.ts
2
+ import axios from "axios";
3
+
4
+ // src/errors.ts
5
+ class WhisperError extends Error {
6
+ constructor(message) {
7
+ super(message);
8
+ this.name = new.target.name;
9
+ }
10
+ }
11
+
12
+ class WhisperApiError extends WhisperError {
13
+ status;
14
+ response;
15
+ code = "API_ERROR";
16
+ constructor(status, response) {
17
+ super(`Whisper API error (${status})`);
18
+ this.status = status;
19
+ this.response = response;
20
+ }
21
+ }
22
+
23
+ class WhisperAuthError extends WhisperError {
24
+ code = "AUTH_ERROR";
25
+ constructor() {
26
+ super("Authentication failed");
27
+ }
28
+ }
29
+
30
+ class WhisperNetworkError extends WhisperError {
31
+ code = "NETWORK_ERROR";
32
+ constructor(cause) {
33
+ super("Network error");
34
+ this.cause = cause;
35
+ }
36
+ }
37
+
38
+ // src/client.ts
39
+ class WhisperClient {
40
+ cookies;
41
+ clientOptions;
42
+ constructor(clientOptions) {
43
+ this.clientOptions = {
44
+ whisperUrl: "https://whisperai.com",
45
+ chunkSize: 8 * 1024 * 1024,
46
+ ...clientOptions
47
+ };
48
+ }
49
+ login() {
50
+ return this.handleRequest(axios.post(this.loginLink, this.clientOptions.login));
51
+ }
52
+ user() {
53
+ return this.recall(() => axios.get(this.userLink, this.requestOptions));
54
+ }
55
+ usage() {
56
+ return this.recall(() => axios.get(this.usageLink, this.requestOptions));
57
+ }
58
+ subscriptionDetails() {
59
+ return this.recall(() => axios.get(this.subscriptionDetailsLink, this.requestOptions));
60
+ }
61
+ upload(fileBuffer, meta) {
62
+ const totalChunks = this.getCountChunks(fileBuffer.length);
63
+ return this.initChunk(fileBuffer, meta).then((response) => Promise.all(Array.from({ length: totalChunks }, (_, i) => this.uploadChunk(fileBuffer, response.recordingId, i))).then(() => this.finalizeChunk(response.recordingId)));
64
+ }
65
+ initChunk(fileBuffer, meta) {
66
+ return this.recall(() => axios.post(this.initChunkLink, {
67
+ filename: meta.filename,
68
+ durationSeconds: meta.durationSeconds,
69
+ totalSize: fileBuffer.length,
70
+ mimeType: meta.mimeType ?? "",
71
+ title: meta.title ?? meta.filename,
72
+ enableSpeakerDetection: meta.enableSpeakerDetection ?? false,
73
+ speakerCount: meta.speakerCount ?? "auto",
74
+ language: meta.language ?? "",
75
+ totalChunks: this.getCountChunks(fileBuffer.length)
76
+ }, this.requestOptions));
77
+ }
78
+ uploadChunk(fileBuffer, recordingId, chunkIndex) {
79
+ const start = chunkIndex * this.clientOptions.chunkSize;
80
+ const end = Math.min(start + this.clientOptions.chunkSize, fileBuffer.length);
81
+ const chunk = fileBuffer.slice(start, end);
82
+ const blob = new Blob([chunk], { type: "application/octet-stream" });
83
+ const formData = new FormData;
84
+ formData.append("chunk", blob, `chunk_${chunkIndex}`);
85
+ formData.append("recordingId", recordingId.toString());
86
+ formData.append("chunkIndex", chunkIndex.toString());
87
+ return this.recall(() => axios.post(this.uploadChunkLink, formData, this.requestOptions));
88
+ }
89
+ finalizeChunk(recordingId) {
90
+ return this.recall(() => axios.post(this.finalizeChunkLink, { recordingId }, this.requestOptions));
91
+ }
92
+ transcription(recordingId) {
93
+ return this.recall(() => axios.post(this.transcriptionLink, { recordingId }, this.requestOptions));
94
+ }
95
+ translate(recordingId, language) {
96
+ return this.recall(() => axios.post(this.translateLink(recordingId), { targetLanguage: language }, this.requestOptions));
97
+ }
98
+ recording(recordingId) {
99
+ return this.recall(() => axios.get(this.recordingLink(recordingId), this.requestOptions));
100
+ }
101
+ recordings(query) {
102
+ return this.recall(() => axios.get(this.recordingsLink, {
103
+ ...this.requestOptions,
104
+ params: { page: 1, limit: 5, ...query ?? {} }
105
+ }));
106
+ }
107
+ summary() {
108
+ return this.recall(() => axios.get(this.summaryLink, this.requestOptions));
109
+ }
110
+ get loginLink() {
111
+ return `${this.clientOptions.whisperUrl}/api/login`;
112
+ }
113
+ get userLink() {
114
+ return `${this.clientOptions.whisperUrl}/api/user`;
115
+ }
116
+ get usageLink() {
117
+ return `${this.clientOptions.whisperUrl}/api/usage`;
118
+ }
119
+ get subscriptionDetailsLink() {
120
+ return `${this.clientOptions.whisperUrl}/api/subscription-details`;
121
+ }
122
+ get initChunkLink() {
123
+ return `${this.clientOptions.whisperUrl}/api/v2/recordings/chunked/init`;
124
+ }
125
+ get uploadChunkLink() {
126
+ return `${this.clientOptions.whisperUrl}/api/v2/recordings/chunked/upload`;
127
+ }
128
+ get finalizeChunkLink() {
129
+ return `${this.clientOptions.whisperUrl}/api/v2/recordings/chunked/finalize`;
130
+ }
131
+ get transcriptionLink() {
132
+ return `${this.clientOptions.whisperUrl}/api/v2/transcription`;
133
+ }
134
+ get summaryLink() {
135
+ return `${this.clientOptions.whisperUrl}/api/analytics/summary`;
136
+ }
137
+ translateLink(recordingId) {
138
+ return `${this.clientOptions.whisperUrl}/api/v2/translation/${recordingId}/translate`;
139
+ }
140
+ recordingLink(recordingId) {
141
+ return `${this.clientOptions.whisperUrl}/api/recordings/${recordingId}`;
142
+ }
143
+ get recordingsLink() {
144
+ return `${this.clientOptions.whisperUrl}/api/recordings-paginated`;
145
+ }
146
+ getCountChunks(size) {
147
+ return Math.ceil(size / this.clientOptions.chunkSize);
148
+ }
149
+ get requestOptions() {
150
+ return {
151
+ headers: {
152
+ Cookie: this.cookies
153
+ }
154
+ };
155
+ }
156
+ async recall(call) {
157
+ try {
158
+ if (typeof this.cookies !== "string")
159
+ await this.login();
160
+ return await this.handleRequest(call());
161
+ } catch (error) {
162
+ if (error.code !== "AUTH_ERROR") {
163
+ throw error;
164
+ }
165
+ await this.login();
166
+ return this.handleRequest(call());
167
+ }
168
+ }
169
+ async handleRequest(request) {
170
+ try {
171
+ const response = await request;
172
+ this.cookies = (response.headers["set-cookie"] ?? []).join("; ");
173
+ return response.data;
174
+ } catch (err) {
175
+ console.log("err", err);
176
+ if (axios.isAxiosError(err)) {
177
+ if (!err.response) {
178
+ throw new WhisperNetworkError(err);
179
+ }
180
+ if (err.response.status === 401) {
181
+ throw new WhisperAuthError;
182
+ }
183
+ throw new WhisperApiError(err.response.status, err.response.data);
184
+ }
185
+ throw err;
186
+ }
187
+ }
188
+ }
189
+ // src/constant.ts
190
+ var WhisperStatus;
191
+ ((WhisperStatus2) => {
192
+ WhisperStatus2["PENDING"] = "pending";
193
+ WhisperStatus2["VALIDATING"] = "validating";
194
+ WhisperStatus2["UPLOADING"] = "uploading";
195
+ WhisperStatus2["PROCESSING"] = "processing";
196
+ WhisperStatus2["COMPLETED"] = "completed";
197
+ WhisperStatus2["FAILED"] = "failed";
198
+ WhisperStatus2["CANCELLED"] = "cancelled";
199
+ })(WhisperStatus ||= {});
200
+ export {
201
+ WhisperStatus,
202
+ WhisperClient
203
+ };
@@ -0,0 +1,218 @@
1
+ import { WhisperStatus } from "./constant.js";
2
+ export interface ClientOptions {
3
+ login: {
4
+ email: string;
5
+ password: string;
6
+ };
7
+ chunkSize?: number;
8
+ whisperUrl?: string;
9
+ }
10
+ export interface RequestError {
11
+ message: string;
12
+ path: string;
13
+ }
14
+ export interface UserInfo {
15
+ id: number;
16
+ username: string | null;
17
+ email: string;
18
+ firstName: string;
19
+ lastName: string;
20
+ profileImageUrl: string | null;
21
+ subscriptionTier: "free" | "premium";
22
+ stripeSubscriptionId: string | null;
23
+ stripeCustomerId: string | null;
24
+ trialStartDate: string | null;
25
+ trialEndDate: string | null;
26
+ hasUsedTrial: boolean;
27
+ monthlyUsageMinutes: number;
28
+ usageResetDate: string;
29
+ deletedMinutesThisCycle: number;
30
+ subscriptionStatus: "past_due" | "active";
31
+ subscriptionEndDate: string | null;
32
+ cancellationOffered: boolean;
33
+ unsubscribed: boolean;
34
+ hearAboutUs: string | null;
35
+ industry: "Healthcare & Medical" | "Legal & Compliance" | "Education & Research" | "Media & Entertainment" | "Technology & Software" | "Consulting & Professional Services" | "Financial Services (Banking, Insurance, Accounting)" | "Government & Nonprofit" | "Sales & Marketing / Advertising" | "Real Estate & Construction" | "Manufacturing & Engineering" | "Human Resources & Recruiting" | "Customer Support / Call Centers" | "Student" | string;
36
+ totalMinutes: number;
37
+ recordingsCount: number;
38
+ subscriptionPausedUntil: string | null;
39
+ subscriptionPauseStarts: string | null;
40
+ subscriptionOriginalTier: string | null;
41
+ discountCodeApplied: string | null;
42
+ retentionOfferShown: string | null;
43
+ billingFrequency: "monthly" | "weekly";
44
+ hasSeenTutorial: boolean;
45
+ lastLoginAt: string | null;
46
+ createdAt: string;
47
+ updatedAt: string;
48
+ }
49
+ export interface UsageInfo {
50
+ monthlyUsageMinutes: number;
51
+ subscriptionTier: "free" | "premium";
52
+ limits: {
53
+ monthlyMinutes: number;
54
+ dailyMinutes: number;
55
+ maxFileSize: number;
56
+ };
57
+ }
58
+ export interface InitMetaFile {
59
+ filename: string;
60
+ durationSeconds: number;
61
+ title?: string;
62
+ mimeType?: string;
63
+ totalSize?: number;
64
+ language?: number;
65
+ enableSpeakerDetection?: boolean;
66
+ speakerCount?: "auto" | number;
67
+ }
68
+ export interface InitChunkResponse {
69
+ sessionId: string;
70
+ recordingId: number;
71
+ }
72
+ export interface UploadChunkResponse {
73
+ success: boolean;
74
+ chunkIndex: number;
75
+ uploadedChunks: number;
76
+ totalChunks: number;
77
+ }
78
+ export interface FinalizeChunkResponse {
79
+ id: number;
80
+ userId: number;
81
+ title: string;
82
+ originalFilename: string;
83
+ fileExtension: string;
84
+ mimeType: string;
85
+ audioUrl: string;
86
+ duration: number;
87
+ language: string;
88
+ status: WhisperStatus;
89
+ speakerDetectionEnabled: boolean;
90
+ speakerCount: number | null;
91
+ totalChunks: number;
92
+ metadata: Record<string, unknown> | null;
93
+ idempotencyKey: string | null;
94
+ uploadSessionId: string;
95
+ createdAt: string;
96
+ updatedAt: string;
97
+ }
98
+ export interface TranscriptionResponse {
99
+ id: number;
100
+ recordingId: number;
101
+ status: "queued" | "processing" | "completed" | "failed" | "canceled";
102
+ createdAt: string;
103
+ updatedAt: string;
104
+ }
105
+ export interface TranslateResponse {
106
+ success: true;
107
+ message: string;
108
+ translation: {
109
+ id: number;
110
+ transcriptionId: number;
111
+ targetLanguage: string;
112
+ content: string;
113
+ status: string;
114
+ };
115
+ }
116
+ export interface SummaryResponse {
117
+ usage: {
118
+ monthlyMinutes: number;
119
+ monthlyLimit: number;
120
+ percentage: number;
121
+ };
122
+ recordings: {
123
+ total: number;
124
+ thisMonth: number;
125
+ totalMinutes: number;
126
+ averageDuration: number;
127
+ };
128
+ activity: {
129
+ dailyCounts: Record<string, number>;
130
+ mostActiveDay: string;
131
+ currentStreak: number;
132
+ };
133
+ insights: {
134
+ shouldUpgrade: boolean;
135
+ suggestedTier: string;
136
+ upgradeReason: string;
137
+ };
138
+ }
139
+ export interface RecordingResponse {
140
+ id: number;
141
+ userId: number;
142
+ title: string;
143
+ originalFilename: string;
144
+ fileExtension: string;
145
+ mimeType: string;
146
+ audioUrl: string;
147
+ duration: number;
148
+ language: string;
149
+ status: string;
150
+ speakerDetectionEnabled: boolean;
151
+ speakerCount: number | null;
152
+ totalChunks: number;
153
+ metadata: Record<string, unknown> | null;
154
+ idempotencyKey: string | null;
155
+ uploadSessionId: string;
156
+ accessToken: string;
157
+ accessTokenExpiry: string;
158
+ createdAt: string;
159
+ updatedAt: string;
160
+ transcription: {
161
+ id: number;
162
+ userId: number;
163
+ recordingId: number;
164
+ content: string;
165
+ editedContent: string | null;
166
+ confidence: number;
167
+ segments: Array<{
168
+ id: number;
169
+ start: number;
170
+ end: number;
171
+ text: string;
172
+ }>;
173
+ translations: Array<{
174
+ id: number;
175
+ transcriptionId: number;
176
+ targetLanguage: string;
177
+ content: string;
178
+ status: string;
179
+ createdAt: string;
180
+ }>;
181
+ timestamps: {
182
+ words: unknown[];
183
+ duration: number;
184
+ language: string;
185
+ segments: Array<{
186
+ id: number;
187
+ start: number;
188
+ end: number;
189
+ text: string;
190
+ }>;
191
+ };
192
+ speakers: unknown | null;
193
+ speakerNames: Record<string, unknown>;
194
+ createdAt: string;
195
+ updatedAt: string;
196
+ summary: unknown | null;
197
+ };
198
+ }
199
+ export interface RecordingsQuery {
200
+ page?: number;
201
+ limit?: number;
202
+ }
203
+ export interface RecordingsResponse {
204
+ data: RecordingResponse[];
205
+ total: string;
206
+ page: number;
207
+ limit: number;
208
+ pages: number;
209
+ hasNext: boolean;
210
+ hasPrev: boolean;
211
+ }
212
+ export interface SubscriptionDetailsResponse {
213
+ isPaidPlan: boolean;
214
+ isTrialActive: boolean;
215
+ nextBillingDate: string | null;
216
+ billingAmount: number | null;
217
+ subscriptionStatus: string;
218
+ }
package/package.json ADDED
@@ -0,0 +1,71 @@
1
+ {
2
+ "name": "whisperai-sdk",
3
+ "version": "1.0.0",
4
+ "description": "TypeScript SDK for WhisperAI: methods and interfaces for interacting with the service without external runtime dependencies.",
5
+ "keywords": [
6
+ "whisper",
7
+ "speech-to-text",
8
+ "transcription",
9
+ "typescript",
10
+ "sdk"
11
+ ],
12
+ "homepage": "https://whisperai.com/",
13
+ "bugs": {
14
+ "url": "https://github.com/iHaiduk/whisperai/issues"
15
+ },
16
+ "repository": {
17
+ "type": "git",
18
+ "url": "git+https://github.com/iHaiduk/whisperai.git"
19
+ },
20
+ "license": "MIT",
21
+ "author": "Igor Haiduk",
22
+ "type": "module",
23
+ "exports": {
24
+ ".": {
25
+ "types": "./dist/index.d.ts",
26
+ "import": "./dist/index.js"
27
+ }
28
+ },
29
+ "main": "./dist/index.js",
30
+ "types": "./dist/index.d.ts",
31
+ "files": [
32
+ "dist"
33
+ ],
34
+ "scripts": {
35
+ "build": "npm run clean && bun build ./src/index.ts --outdir ./dist --target=node --format=esm --external axios && tsc --emitDeclarationOnly",
36
+ "format": "prettier --write \"src/**/*.ts\"",
37
+ "lint": "eslint \"{src,apps,libs,test}/**/*.ts\" --fix",
38
+ "clean": "rm -rf dist",
39
+ "typecheck": "tsc -p tsconfig.json --noEmit",
40
+ "release": "semantic-release"
41
+ },
42
+ "dependencies": {
43
+ "axios": "^1.13.2"
44
+ },
45
+ "devDependencies": {
46
+ "@commitlint/cli": "20.2.0",
47
+ "@commitlint/config-conventional": "20.2.0",
48
+ "@eslint/js": "9.39.2",
49
+ "@semantic-release/changelog": "6.0.3",
50
+ "@semantic-release/exec": "7.1.0",
51
+ "@semantic-release/git": "10.0.1",
52
+ "@semantic-release/github": "12.0.2",
53
+ "@semantic-release/npm": "13.1.3",
54
+ "@types/bun": "^1.3.5",
55
+ "@types/node": "25.0.3",
56
+ "@typescript-eslint/eslint-plugin": "8.50.1",
57
+ "@typescript-eslint/parser": "8.50.1",
58
+ "conventional-changelog-conventionalcommits": "9.1.0",
59
+ "eslint": "9.39.2",
60
+ "eslint-config-prettier": "10.1.8",
61
+ "eslint-plugin-prettier": "5.5.4",
62
+ "prettier": "3.7.4",
63
+ "semantic-release": "25.0.2",
64
+ "typescript": "5.9.3",
65
+ "typescript-eslint": "8.50.1"
66
+ },
67
+ "engines": {
68
+ "node": ">=22.0.0"
69
+ },
70
+ "module": "./dist/index.js"
71
+ }