dragdropdo-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.
@@ -0,0 +1,29 @@
1
+ "use strict";
2
+ /**
3
+ * DragDropDo SDK - Node.js Client Library
4
+ *
5
+ * Official Node.js client for the dragdropdo.com Business API
6
+ */
7
+ var __createBinding = (this && this.__createBinding) || (Object.create ? (function(o, m, k, k2) {
8
+ if (k2 === undefined) k2 = k;
9
+ var desc = Object.getOwnPropertyDescriptor(m, k);
10
+ if (!desc || ("get" in desc ? !m.__esModule : desc.writable || desc.configurable)) {
11
+ desc = { enumerable: true, get: function() { return m[k]; } };
12
+ }
13
+ Object.defineProperty(o, k2, desc);
14
+ }) : (function(o, m, k, k2) {
15
+ if (k2 === undefined) k2 = k;
16
+ o[k2] = m[k];
17
+ }));
18
+ var __exportStar = (this && this.__exportStar) || function(m, exports) {
19
+ for (var p in m) if (p !== "default" && !Object.prototype.hasOwnProperty.call(exports, p)) __createBinding(exports, m, p);
20
+ };
21
+ Object.defineProperty(exports, "__esModule", { value: true });
22
+ exports.default = exports.Dragdropdo = void 0;
23
+ var client_1 = require("./client");
24
+ Object.defineProperty(exports, "Dragdropdo", { enumerable: true, get: function () { return client_1.Dragdropdo; } });
25
+ __exportStar(require("./types"), exports);
26
+ __exportStar(require("./errors"), exports);
27
+ // Default export
28
+ var client_2 = require("./client");
29
+ Object.defineProperty(exports, "default", { enumerable: true, get: function () { return client_2.Dragdropdo; } });
@@ -0,0 +1,143 @@
1
+ /**
2
+ * Type definitions for dragdropdo.com Business API Client
3
+ */
4
+ export interface DragdropdoConfig {
5
+ /** API key for authentication */
6
+ apiKey: string;
7
+ /** Base URL of the D3 API (e.g., 'https://api-dev.dragdropdo.com') */
8
+ baseURL?: string;
9
+ /** Request timeout in milliseconds (default: 30000) */
10
+ timeout?: number;
11
+ /** Custom headers to include in all requests */
12
+ headers?: Record<string, string>;
13
+ }
14
+ export interface UploadFileOptions {
15
+ /** File path (absolute or relative) */
16
+ file: string;
17
+ /** Original file name */
18
+ fileName: string;
19
+ /** MIME type of the file */
20
+ mimeType?: string;
21
+ /** Number of parts for multipart upload (default: calculated automatically) */
22
+ parts?: number;
23
+ /** Optional progress callback */
24
+ onProgress?: (progress: UploadProgress) => void;
25
+ }
26
+ export interface UploadProgress {
27
+ /** Current part being uploaded (1-indexed) */
28
+ currentPart: number;
29
+ /** Total number of parts */
30
+ totalParts: number;
31
+ /** Bytes uploaded so far */
32
+ bytesUploaded: number;
33
+ /** Total file size in bytes */
34
+ totalBytes: number;
35
+ /** Upload percentage (0-100) */
36
+ percentage: number;
37
+ }
38
+ export interface UploadResponse {
39
+ /** File key for use in operations (snake_case from API) */
40
+ file_key: string;
41
+ /** Upload ID for completing the upload (snake_case from API) */
42
+ upload_id: string;
43
+ /** Presigned URLs for multipart upload (snake_case from API) */
44
+ presigned_urls: string[];
45
+ /** Object name returned by the API (snake_case from API) */
46
+ object_name?: string;
47
+ /** File key for use in operations (camelCase alias) */
48
+ fileKey: string;
49
+ /** Upload ID for completing the upload (camelCase alias) */
50
+ uploadId: string;
51
+ /** Presigned URLs for multipart upload (camelCase alias) */
52
+ presignedUrls: string[];
53
+ /** Object name returned by the API (camelCase alias) */
54
+ objectName?: string;
55
+ }
56
+ export interface SupportedOperationOptions {
57
+ /** File extension (e.g., 'pdf', 'jpg') */
58
+ ext: string;
59
+ /** Optional action to check (e.g., 'convert', 'compress') */
60
+ action?: string;
61
+ /** Optional parameters for validation (e.g., { convert_to: 'png' }) */
62
+ parameters?: Record<string, any>;
63
+ }
64
+ export interface SupportedOperationResponse {
65
+ /** Whether the operation is supported */
66
+ supported: boolean;
67
+ /** Normalized extension */
68
+ ext: string;
69
+ /** Action name (if provided) */
70
+ action?: string;
71
+ /** Available actions for this extension */
72
+ availableActions?: string[];
73
+ /** Action-specific parameters (e.g., available convert_to targets) */
74
+ parameters?: Record<string, any>;
75
+ }
76
+ export interface OperationOptions {
77
+ /** Action to perform: 'convert', 'compress', 'merge', 'zip', 'share', 'lock', 'unlock', 'reset_password' */
78
+ action: "convert" | "compress" | "merge" | "zip" | "create_zip" | "share" | "lock" | "unlock" | "reset_password";
79
+ /** Array of file keys from upload */
80
+ fileKeys: string[];
81
+ /** Action-specific parameters */
82
+ parameters?: OperationParameters;
83
+ /** Optional user metadata */
84
+ notes?: Record<string, string>;
85
+ }
86
+ export interface OperationParameters {
87
+ /** For convert: target format (e.g., 'pdf', 'png') */
88
+ convert_to?: string;
89
+ /** For compress: compression level (e.g., 'recommended', 'high', 'low') */
90
+ compression_value?: string;
91
+ /** For lock/unlock/reset_password: password */
92
+ password?: string;
93
+ /** For reset_password: old password */
94
+ old_password?: string;
95
+ /** For reset_password: new password */
96
+ new_password?: string;
97
+ }
98
+ export interface OperationResponse {
99
+ /** Main task ID for tracking the operation */
100
+ mainTaskId: string;
101
+ }
102
+ export interface StatusOptions {
103
+ /** Main task ID */
104
+ mainTaskId: string;
105
+ /** Optional file task ID for specific file status */
106
+ fileTaskId?: string;
107
+ }
108
+ export interface FileTaskStatus {
109
+ /** File key */
110
+ fileKey: string;
111
+ /** Status: 'queued' | 'running' | 'completed' | 'failed' */
112
+ status: "queued" | "running" | "completed" | "failed";
113
+ /** Download link (when completed) */
114
+ downloadLink?: string;
115
+ /** Error code (when failed) */
116
+ errorCode?: string;
117
+ /** Error message (when failed) */
118
+ errorMessage?: string;
119
+ }
120
+ export interface StatusResponse {
121
+ /** Overall operation status */
122
+ operationStatus: "queued" | "running" | "completed" | "failed";
123
+ /** Array of file task statuses */
124
+ filesData: FileTaskStatus[];
125
+ }
126
+ export interface PollStatusOptions extends StatusOptions {
127
+ /** Polling interval in milliseconds (default: 2000) */
128
+ interval?: number;
129
+ /** Maximum polling duration in milliseconds (default: 300000 = 5 minutes) */
130
+ timeout?: number;
131
+ /** Callback for each status update */
132
+ onUpdate?: (status: StatusResponse) => void;
133
+ }
134
+ export interface D3Error extends Error {
135
+ /** HTTP status code */
136
+ statusCode?: number;
137
+ /** Error code from API */
138
+ code?: number;
139
+ /** Error message */
140
+ message: string;
141
+ /** Additional error details */
142
+ details?: any;
143
+ }
@@ -0,0 +1,5 @@
1
+ "use strict";
2
+ /**
3
+ * Type definitions for dragdropdo.com Business API Client
4
+ */
5
+ Object.defineProperty(exports, "__esModule", { value: true });
@@ -0,0 +1 @@
1
+ export {};
@@ -0,0 +1,167 @@
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 __setModuleDefault = (this && this.__setModuleDefault) || (Object.create ? (function(o, v) {
14
+ Object.defineProperty(o, "default", { enumerable: true, value: v });
15
+ }) : function(o, v) {
16
+ o["default"] = v;
17
+ });
18
+ var __importStar = (this && this.__importStar) || (function () {
19
+ var ownKeys = function(o) {
20
+ ownKeys = Object.getOwnPropertyNames || function (o) {
21
+ var ar = [];
22
+ for (var k in o) if (Object.prototype.hasOwnProperty.call(o, k)) ar[ar.length] = k;
23
+ return ar;
24
+ };
25
+ return ownKeys(o);
26
+ };
27
+ return function (mod) {
28
+ if (mod && mod.__esModule) return mod;
29
+ var result = {};
30
+ if (mod != null) for (var k = ownKeys(mod), i = 0; i < k.length; i++) if (k[i] !== "default") __createBinding(result, mod, k[i]);
31
+ __setModuleDefault(result, mod);
32
+ return result;
33
+ };
34
+ })();
35
+ var __importDefault = (this && this.__importDefault) || function (mod) {
36
+ return (mod && mod.__esModule) ? mod : { "default": mod };
37
+ };
38
+ Object.defineProperty(exports, "__esModule", { value: true });
39
+ const nock_1 = __importDefault(require("nock"));
40
+ const src_1 = require("../src");
41
+ const fs = __importStar(require("fs"));
42
+ const path = __importStar(require("path"));
43
+ const os = __importStar(require("os"));
44
+ const API_BASE = "https://api-dev.dragdropdo.com";
45
+ describe("Dragdropdo end-to-end (mocked HTTP)", () => {
46
+ beforeAll(() => {
47
+ nock_1.default.disableNetConnect();
48
+ });
49
+ afterAll(() => {
50
+ nock_1.default.enableNetConnect();
51
+ });
52
+ afterEach(() => {
53
+ if (!nock_1.default.isDone()) {
54
+ const pending = nock_1.default.pendingMocks();
55
+ nock_1.default.cleanAll();
56
+ throw new Error(`Not all HTTP mocks were satisfied: ${pending.join(", ")}`);
57
+ }
58
+ nock_1.default.cleanAll();
59
+ });
60
+ test("uploads a file (path) with multipart flow", async () => {
61
+ const client = new src_1.Dragdropdo({ apiKey: "test-key", baseURL: API_BASE });
62
+ const tmpFile = path.join(os.tmpdir(), `d3-test-${Date.now()}.pdf`);
63
+ const sixMbContent = "a".repeat(6 * 1024 * 1024);
64
+ fs.writeFileSync(tmpFile, sixMbContent);
65
+ const cleanup = () => {
66
+ if (fs.existsSync(tmpFile)) {
67
+ fs.unlinkSync(tmpFile);
68
+ }
69
+ };
70
+ (0, nock_1.default)(API_BASE)
71
+ .post("/v1/external/upload", (body) => {
72
+ return (body.file_name === "test.pdf" &&
73
+ body.size === 6 * 1024 * 1024 &&
74
+ body.mime_type === "application/pdf" &&
75
+ body.parts === 2);
76
+ })
77
+ .reply(200, {
78
+ data: {
79
+ file_key: "file-key-123",
80
+ upload_id: "upload-id-456",
81
+ presigned_urls: [
82
+ "https://upload.d3.com/part1",
83
+ "https://upload.d3.com/part2",
84
+ ],
85
+ },
86
+ });
87
+ (0, nock_1.default)("https://upload.d3.com")
88
+ .put("/part1")
89
+ .reply(200, {}, { ETag: '"etag-part-1"' });
90
+ (0, nock_1.default)("https://upload.d3.com")
91
+ .put("/part2")
92
+ .reply(200, {}, { ETag: '"etag-part-2"' });
93
+ (0, nock_1.default)(API_BASE)
94
+ .post("/v1/external/complete-upload", (body) => {
95
+ return (body.file_key === "file-key-123" &&
96
+ body.upload_id === "upload-id-456" &&
97
+ Array.isArray(body.parts) &&
98
+ body.parts.length === 2 &&
99
+ body.parts[0].etag === "etag-part-1" &&
100
+ body.parts[0].part_number === 1 &&
101
+ body.parts[1].etag === "etag-part-2" &&
102
+ body.parts[1].part_number === 2);
103
+ })
104
+ .reply(200, {
105
+ data: {
106
+ message: "Upload completed successfully",
107
+ file_key: "file-key-123",
108
+ },
109
+ });
110
+ let result;
111
+ try {
112
+ result = await client.uploadFile({
113
+ file: tmpFile,
114
+ fileName: "test.pdf",
115
+ mimeType: "application/pdf",
116
+ parts: 2,
117
+ });
118
+ }
119
+ finally {
120
+ cleanup();
121
+ }
122
+ expect(result.fileKey).toBe("file-key-123");
123
+ expect(result.uploadId).toBe("upload-id-456");
124
+ expect(result.presignedUrls).toHaveLength(2);
125
+ });
126
+ test("creates an operation and polls status to completion", async () => {
127
+ const client = new src_1.Dragdropdo({ apiKey: "test-key", baseURL: API_BASE });
128
+ (0, nock_1.default)(API_BASE)
129
+ .post("/v1/external/do", {
130
+ action: "convert",
131
+ file_keys: ["file-key-123"],
132
+ parameters: { convert_to: "png" },
133
+ notes: undefined,
134
+ })
135
+ .reply(200, { data: { mainTaskId: "task-123" } });
136
+ (0, nock_1.default)(API_BASE)
137
+ .get("/v1/external/status/task-123")
138
+ .reply(200, {
139
+ data: {
140
+ operationStatus: "queued",
141
+ filesData: [{ fileKey: "file-key-123", status: "queued" }],
142
+ },
143
+ })
144
+ .get("/v1/external/status/task-123")
145
+ .reply(200, {
146
+ data: {
147
+ operationStatus: "completed",
148
+ filesData: [
149
+ {
150
+ fileKey: "file-key-123",
151
+ status: "completed",
152
+ downloadLink: "https://files.d3.com/output.png",
153
+ },
154
+ ],
155
+ },
156
+ });
157
+ const operation = await client.convert(["file-key-123"], "png");
158
+ expect(operation.mainTaskId).toBe("task-123");
159
+ const status = await client.pollStatus({
160
+ mainTaskId: operation.mainTaskId,
161
+ interval: 5,
162
+ timeout: 1000,
163
+ });
164
+ expect(status.operationStatus).toBe("completed");
165
+ expect(status.filesData[0].downloadLink).toContain("files.d3.com");
166
+ });
167
+ });
@@ -0,0 +1 @@
1
+ export {};
@@ -0,0 +1,104 @@
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 __setModuleDefault = (this && this.__setModuleDefault) || (Object.create ? (function(o, v) {
14
+ Object.defineProperty(o, "default", { enumerable: true, value: v });
15
+ }) : function(o, v) {
16
+ o["default"] = v;
17
+ });
18
+ var __importStar = (this && this.__importStar) || (function () {
19
+ var ownKeys = function(o) {
20
+ ownKeys = Object.getOwnPropertyNames || function (o) {
21
+ var ar = [];
22
+ for (var k in o) if (Object.prototype.hasOwnProperty.call(o, k)) ar[ar.length] = k;
23
+ return ar;
24
+ };
25
+ return ownKeys(o);
26
+ };
27
+ return function (mod) {
28
+ if (mod && mod.__esModule) return mod;
29
+ var result = {};
30
+ if (mod != null) for (var k = ownKeys(mod), i = 0; i < k.length; i++) if (k[i] !== "default") __createBinding(result, mod, k[i]);
31
+ __setModuleDefault(result, mod);
32
+ return result;
33
+ };
34
+ })();
35
+ var __importDefault = (this && this.__importDefault) || function (mod) {
36
+ return (mod && mod.__esModule) ? mod : { "default": mod };
37
+ };
38
+ Object.defineProperty(exports, "__esModule", { value: true });
39
+ const axios_1 = __importDefault(require("axios"));
40
+ const src_1 = require("../src");
41
+ const fs = __importStar(require("fs"));
42
+ const os = __importStar(require("os"));
43
+ const path = __importStar(require("path"));
44
+ const API_BASE = process.env.D3_BASE_URL ?? "https://api-dev.dragdropdo.com";
45
+ const API_KEY = process.env.D3_API_KEY ?? "";
46
+ const RUN_LIVE = process.env.RUN_LIVE_TESTS === "1";
47
+ // Skip unless explicitly enabled with RUN_LIVE_TESTS=1 and a real API key.
48
+ const maybeDescribe = RUN_LIVE && API_KEY ? describe : describe.skip;
49
+ if (!RUN_LIVE || !API_KEY) {
50
+ // Provide a hint when the suite is skipped.
51
+ // eslint-disable-next-line no-console
52
+ console.warn("Skipping live API tests. Set RUN_LIVE_TESTS=1 and D3_API_KEY to run.");
53
+ }
54
+ maybeDescribe("Dragdropdo live API", () => {
55
+ const log = (...args) => console.log("[live-test]", ...args);
56
+ test("upload, convert, poll, download", async () => {
57
+ if (!API_KEY) {
58
+ throw new Error("API_KEY is required for live tests");
59
+ }
60
+ const client = new src_1.Dragdropdo({ apiKey: API_KEY, baseURL: API_BASE });
61
+ const tmpFile = path.join(os.tmpdir(), `d3-live-${Date.now()}.txt`);
62
+ fs.writeFileSync(tmpFile, "hello world");
63
+ log("Uploading file...");
64
+ const upload = await client.uploadFile({
65
+ file: tmpFile,
66
+ fileName: "hello.txt",
67
+ mimeType: "text/plain",
68
+ parts: 1,
69
+ });
70
+ log("Upload result:", upload);
71
+ log("Starting convert...");
72
+ const operation = await client.convert([upload.fileKey || upload.file_key], "png");
73
+ log("Operation:", operation);
74
+ log("Polling status...");
75
+ const mainTaskId = operation.mainTaskId || operation.main_task_id;
76
+ if (!mainTaskId) {
77
+ throw new Error("mainTaskId not found in operation response");
78
+ }
79
+ const status = await client.pollStatus({
80
+ mainTaskId: mainTaskId,
81
+ interval: 3000,
82
+ timeout: 60000,
83
+ });
84
+ log("Final status:", status);
85
+ const opStatus = status.operationStatus || status.operation_status;
86
+ expect(opStatus).toBe("completed");
87
+ const filesData = status.filesData || status.files_data || [];
88
+ const link = filesData[0]?.downloadLink || filesData[0]?.download_link;
89
+ expect(link).toBeTruthy();
90
+ if (link) {
91
+ log("Downloading output...");
92
+ const res = await axios_1.default.get(link, {
93
+ responseType: "arraybuffer",
94
+ });
95
+ const buf = Buffer.from(res.data);
96
+ log("Downloaded bytes:", buf.length);
97
+ expect(res.status).toBe(200);
98
+ expect(buf.length).toBeGreaterThan(0);
99
+ }
100
+ if (fs.existsSync(tmpFile)) {
101
+ fs.unlinkSync(tmpFile);
102
+ }
103
+ }, 120000);
104
+ });
package/package.json ADDED
@@ -0,0 +1,42 @@
1
+ {
2
+ "name": "dragdropdo-sdk",
3
+ "version": "1.0.0",
4
+ "description": "Official Node.js client library for the dragdropdo.com Business API",
5
+ "main": "dist/index.js",
6
+ "types": "dist/index.d.ts",
7
+ "scripts": {
8
+ "build": "tsc",
9
+ "prepublishOnly": "npm run build",
10
+ "test": "jest"
11
+ },
12
+ "keywords": [
13
+ "dragdropdo-sdk",
14
+ "dragdropdo-node-client",
15
+ "file-conversion",
16
+ "api-client",
17
+ "file-processing",
18
+ "pdf",
19
+ "convert",
20
+ "compress"
21
+ ],
22
+ "author": "TrippyTech Labs LLP",
23
+ "license": "ISC",
24
+ "dependencies": {
25
+ "axios": "^1.6.0"
26
+ },
27
+ "devDependencies": {
28
+ "@types/node": "^20.0.0",
29
+ "@types/jest": "^29.5.0",
30
+ "jest": "^29.0.0",
31
+ "nock": "^13.5.0",
32
+ "ts-jest": "^29.0.0",
33
+ "typescript": "^5.0.0"
34
+ },
35
+ "files": [
36
+ "dist",
37
+ "README.md"
38
+ ],
39
+ "engines": {
40
+ "node": ">=14.0.0"
41
+ }
42
+ }