@scalemule/sdk 0.0.1

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,108 @@
1
+ // src/services/upload-compression.ts
2
+ var MIN_COMPRESS_SIZE = 100 * 1024;
3
+ var COMPRESSIBLE_TYPES = /* @__PURE__ */ new Set([
4
+ "image/jpeg",
5
+ "image/jpg",
6
+ "image/png",
7
+ "image/bmp",
8
+ "image/tiff"
9
+ ]);
10
+ var SKIP_TYPES = /* @__PURE__ */ new Set([
11
+ "image/gif",
12
+ "image/svg+xml",
13
+ "image/webp",
14
+ "image/avif"
15
+ ]);
16
+ var NETWORK_PROFILES = {
17
+ "slow-2g": { maxWidth: 1280, maxHeight: 1280, quality: 0.6, maxSizeMB: 0.5 },
18
+ "2g": { maxWidth: 1600, maxHeight: 1600, quality: 0.65, maxSizeMB: 1 },
19
+ "3g": { maxWidth: 2048, maxHeight: 2048, quality: 0.75, maxSizeMB: 2 },
20
+ "4g": { maxWidth: 3840, maxHeight: 3840, quality: 0.85, maxSizeMB: 5 }
21
+ };
22
+ async function maybeCompressImage(file, userConfig, sessionId, telemetry) {
23
+ const type = file.type?.toLowerCase() || "";
24
+ if (!type.startsWith("image/")) return null;
25
+ if (SKIP_TYPES.has(type)) {
26
+ telemetry?.emit(sessionId, "upload.compression.skipped", { reason: "format", type });
27
+ return null;
28
+ }
29
+ if (!COMPRESSIBLE_TYPES.has(type)) {
30
+ telemetry?.emit(sessionId, "upload.compression.skipped", { reason: "unsupported_type", type });
31
+ return null;
32
+ }
33
+ if (file.size < MIN_COMPRESS_SIZE) {
34
+ telemetry?.emit(sessionId, "upload.compression.skipped", { reason: "too_small", size: file.size });
35
+ return null;
36
+ }
37
+ const networkType = getNetworkEffectiveType();
38
+ const defaultProfile = { maxWidth: 3840, maxHeight: 3840, quality: 0.85, maxSizeMB: 5 };
39
+ const networkProfile = NETWORK_PROFILES[networkType] ?? defaultProfile;
40
+ const config = {
41
+ maxWidth: userConfig?.maxWidth ?? networkProfile.maxWidth,
42
+ maxHeight: userConfig?.maxHeight ?? networkProfile.maxHeight,
43
+ quality: userConfig?.quality ?? networkProfile.quality,
44
+ maxSizeMB: userConfig?.maxSizeMB ?? networkProfile.maxSizeMB
45
+ };
46
+ telemetry?.emit(sessionId, "upload.compression.started", {
47
+ original_size: file.size,
48
+ network: networkType,
49
+ target_quality: config.quality
50
+ });
51
+ try {
52
+ const imageCompression = await loadImageCompression();
53
+ if (!imageCompression) {
54
+ telemetry?.emit(sessionId, "upload.compression.skipped", { reason: "library_unavailable" });
55
+ return null;
56
+ }
57
+ const compressed = await imageCompression(file, {
58
+ maxSizeMB: config.maxSizeMB,
59
+ maxWidthOrHeight: Math.max(config.maxWidth, config.maxHeight),
60
+ initialQuality: config.quality,
61
+ useWebWorker: true,
62
+ fileType: type === "image/png" ? "image/webp" : void 0
63
+ });
64
+ if (compressed.size >= file.size * 0.95) {
65
+ telemetry?.emit(sessionId, "upload.compression.skipped", {
66
+ reason: "no_size_reduction",
67
+ original_size: file.size,
68
+ compressed_size: compressed.size
69
+ });
70
+ return null;
71
+ }
72
+ telemetry?.emit(sessionId, "upload.compression.completed", {
73
+ original_size: file.size,
74
+ compressed_size: compressed.size,
75
+ ratio: (compressed.size / file.size).toFixed(2)
76
+ });
77
+ return compressed;
78
+ } catch (err) {
79
+ telemetry?.emit(sessionId, "upload.compression.skipped", {
80
+ reason: "error",
81
+ error: err instanceof Error ? err.message : "Unknown compression error"
82
+ });
83
+ return null;
84
+ }
85
+ }
86
+ var cachedImport = null;
87
+ async function loadImageCompression() {
88
+ if (cachedImport === false) return null;
89
+ if (cachedImport) return cachedImport;
90
+ try {
91
+ const mod = await Function('return import("browser-image-compression")')();
92
+ cachedImport = mod.default || mod;
93
+ return cachedImport;
94
+ } catch {
95
+ cachedImport = false;
96
+ return null;
97
+ }
98
+ }
99
+ function getNetworkEffectiveType() {
100
+ if (typeof navigator !== "undefined" && "connection" in navigator) {
101
+ const conn = navigator.connection;
102
+ return conn?.effectiveType || "4g";
103
+ }
104
+ return "4g";
105
+ }
106
+ export {
107
+ maybeCompressImage
108
+ };
@@ -0,0 +1,6 @@
1
+ import {
2
+ UploadResumeStore
3
+ } from "./chunk-3FTGBRLU.mjs";
4
+ export {
5
+ UploadResumeStore
6
+ };
package/package.json ADDED
@@ -0,0 +1,90 @@
1
+ {
2
+ "name": "@scalemule/sdk",
3
+ "version": "0.0.1",
4
+ "description": "Official TypeScript/JavaScript SDK for ScaleMule Backend-as-a-Service",
5
+ "main": "dist/index.js",
6
+ "module": "dist/index.mjs",
7
+ "types": "dist/index.d.ts",
8
+ "exports": {
9
+ ".": {
10
+ "types": "./dist/index.d.ts",
11
+ "import": "./dist/index.mjs",
12
+ "require": "./dist/index.js"
13
+ }
14
+ },
15
+ "files": [
16
+ "dist",
17
+ "README.md",
18
+ "LICENSE"
19
+ ],
20
+ "scripts": {
21
+ "build": "tsup src/index.ts --format cjs,esm --dts --clean --external @scalemule/ui --external browser-image-compression",
22
+ "dev": "tsup src/index.ts --format cjs,esm --dts --watch",
23
+ "test": "vitest run",
24
+ "test:watch": "vitest",
25
+ "test:coverage": "vitest run --coverage",
26
+ "lint": "eslint src --ext .ts",
27
+ "lint:fix": "eslint src --ext .ts --fix",
28
+ "format": "prettier --write \"src/**/*.ts\"",
29
+ "format:check": "prettier --check \"src/**/*.ts\"",
30
+ "typecheck": "tsc --noEmit",
31
+ "prepublishOnly": "npm run build && npm test && npm run lint",
32
+ "release": "npm run prepublishOnly && npm publish --access public"
33
+ },
34
+ "keywords": [
35
+ "scalemule",
36
+ "backend-as-a-service",
37
+ "baas",
38
+ "api",
39
+ "sdk",
40
+ "typescript",
41
+ "javascript",
42
+ "client",
43
+ "rest",
44
+ "http"
45
+ ],
46
+ "author": "ScaleMule Inc. <support@scalemule.com>",
47
+ "license": "MIT",
48
+ "homepage": "https://scalemule.com",
49
+ "repository": {
50
+ "type": "git",
51
+ "url": "git+https://github.com/scalemule/sdk.git"
52
+ },
53
+ "bugs": {
54
+ "url": "https://github.com/scalemule/sdk/issues"
55
+ },
56
+ "engines": {
57
+ "node": ">=18.0.0"
58
+ },
59
+ "dependencies": {},
60
+ "peerDependencies": {
61
+ "@scalemule/ui": "^0.0.1",
62
+ "browser-image-compression": ">=2.0.0"
63
+ },
64
+ "peerDependenciesMeta": {
65
+ "@scalemule/ui": {
66
+ "optional": false
67
+ },
68
+ "browser-image-compression": {
69
+ "optional": true
70
+ }
71
+ },
72
+ "devDependencies": {
73
+ "@scalemule/ui": "^0.0.1",
74
+ "@types/node": "^20.10.0",
75
+ "@typescript-eslint/eslint-plugin": "^6.13.0",
76
+ "@typescript-eslint/parser": "^6.13.0",
77
+ "@vitest/coverage-v8": "^1.0.0",
78
+ "eslint": "^8.54.0",
79
+ "eslint-config-prettier": "^9.0.0",
80
+ "eslint-plugin-prettier": "^5.0.0",
81
+ "prettier": "^3.1.0",
82
+ "tsup": "^8.0.0",
83
+ "typescript": "^5.3.0",
84
+ "vitest": "^1.0.0"
85
+ },
86
+ "publishConfig": {
87
+ "access": "public",
88
+ "registry": "https://registry.npmjs.org/"
89
+ }
90
+ }