-
Notifications
You must be signed in to change notification settings - Fork 468
Expand file tree
/
Copy pathConfig.js
More file actions
158 lines (146 loc) · 4.53 KB
/
Copy pathConfig.js
File metadata and controls
158 lines (146 loc) · 4.53 KB
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
// #popclip
// name: Jmpy
// identifier: com.jmpy.popclipext
// icon: jmpy-logo.png
// description: Create short links and dynamic QR codes using Jmpy.
// entitlements: [network]
// module: true
const axios = require("axios");
/**
* Validates and normalizes the selected text into a proper URL.
* Prepend protocol if missing, and check URL validity.
*/
function validateAndNormalizeUrl(text) {
let urlStr = text.trim();
if (!urlStr) {
throw new Error("No URL selected.");
}
// Prepend protocol if user selected a domain without one (e.g., "example.com")
if (!/^https?:\/\//i.test(urlStr)) {
urlStr = "https://" + urlStr;
}
try {
// Basic structural validation using URL constructor
new URL(urlStr);
} catch (e) {
throw new Error("Selected text is not a valid URL.");
}
return urlStr;
}
/**
* Validates the Jmpy API Key format.
*/
function validateApiKey(apiKey) {
if (!apiKey || typeof apiKey !== "string") {
throw new Error("API Key is required. Set it in PopClip options.");
}
const cleanKey = apiKey.trim();
if (!cleanKey.startsWith("jmpy_")) {
throw new Error("Invalid API Key format. It should start with 'jmpy_'.");
}
return cleanKey;
}
/**
* Formats API errors for display in the PopClip tooltip.
*/
function handleApiError(error) {
if (error.response) {
const apiMessage = error.response.data?.message || error.response.data?.error || "";
const status = error.response.status;
if (status === 401 || status === 403) {
return "Authentication failed: Please check your Jmpy API Key.";
}
return `Jmpy API Error (${status}): ${apiMessage || "Request failed"}`;
} else if (error.request) {
return "Network error: Unable to reach Jmpy.me. Check internet connection.";
}
return error.message || "An unexpected error occurred.";
}
module.exports = {
app: {
name: "Jmpy",
link: "https://jmpy.me"
},
options: [
{
identifier: "apikey",
type: "secret",
label: "API Key",
description: "Create an API key in your Jmpy.me dashboard → API Settings."
},
{
identifier: "domain",
type: "string",
label: "API Domain",
description: "Defaults to https://jmpy.me",
defaultValue: "https://jmpy.me"
}
],
actions: [
{
title: "Jmpy Short URL",
icon: "symbol:link.circle.fill",
requirements: ["url"],
after: "copy-result",
code: async (input, options) => {
try {
const url = validateAndNormalizeUrl(input.text);
const apiKey = validateApiKey(options.apikey);
const apiDomain = (options.domain || "https://jmpy.me").trim().replace(/\/+$/, "");
const response = await axios.post(`${apiDomain}/api/v1/short-urls`, {
url: url,
channel: 'popclip'
}, {
headers: {
'x-api-key': apiKey,
'Content-Type': 'application/json'
},
timeout: 10000 // 10s timeout
});
if (response.data && response.data.data && response.data.data.short_url) {
return response.data.data.short_url;
} else {
throw new Error("Invalid response format received from Jmpy.");
}
} catch (error) {
throw new Error(handleApiError(error));
}
}
},
{
title: "Jmpy QR Code",
icon: "symbol:qrcode",
requirements: ["url"],
code: async (input, options) => {
try {
const url = validateAndNormalizeUrl(input.text);
const apiKey = validateApiKey(options.apikey);
const apiDomain = (options.domain || "https://jmpy.me").trim().replace(/\/+$/, "");
const response = await axios.post(`${apiDomain}/api/v1/qr-codes/generate`, {
content_type: 'url',
content_data: { url: url },
is_dynamic: true,
tracking_enabled: true,
use_short_url: true,
source: 'EXTENSION',
channel: 'popclip',
qr_format: 'json'
}, {
headers: {
'x-api-key': apiKey,
'Content-Type': 'application/json'
},
timeout: 10000 // 10s timeout
});
if (response.data && response.data.data && response.data.data.qr_code_url) {
popclip.openUrl(response.data.data.qr_code_url);
} else {
throw new Error("Invalid response format received from Jmpy.");
}
} catch (error) {
throw new Error(handleApiError(error));
}
}
}
]
};