peakurl 1.1.0 → 1.1.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.
- package/README.md +17 -3
- package/bin/peakurl.js +533 -5
- package/man/peakurl.1 +48 -0
- package/package.json +6 -6
package/README.md
CHANGED
|
@@ -6,7 +6,7 @@ The official command-line interface for PeakURL.
|
|
|
6
6
|
|
|
7
7
|
Use `peakurl` to create short links, inspect existing links, and manage your PeakURL account from the terminal.
|
|
8
8
|
|
|
9
|
-
Learn more in the full CLI docs: <https://peakurl.org/
|
|
9
|
+
Learn more in the full CLI docs: <https://go.peakurl.org/7a0e0b>
|
|
10
10
|
|
|
11
11
|
## Install
|
|
12
12
|
|
|
@@ -73,6 +73,7 @@ export PEAKURL_API_KEY=0123456789abcdef0123456789abcdef0123456789abcdef
|
|
|
73
73
|
| `peakurl delete [id-or-alias...]` | Delete links by ID or alias, in bulk, or clear all links. |
|
|
74
74
|
| `peakurl activity <subcommand>` | View audit logs, delete activity records, or clear history. |
|
|
75
75
|
| `peakurl webhook <subcommand>` | List, create, delete, and inspect supported webhook events. |
|
|
76
|
+
| `peakurl job <cmd>` | Manage server-side scheduled jobs. |
|
|
76
77
|
| `peakurl update` | Show the latest available CLI version and install command. |
|
|
77
78
|
|
|
78
79
|
## Examples
|
|
@@ -228,6 +229,19 @@ Check the latest available CLI version:
|
|
|
228
229
|
peakurl update --check
|
|
229
230
|
```
|
|
230
231
|
|
|
232
|
+
Manage scheduled jobs:
|
|
233
|
+
|
|
234
|
+
```bash
|
|
235
|
+
# List all registered scheduled jobs
|
|
236
|
+
peakurl job list
|
|
237
|
+
|
|
238
|
+
# Force a job to run immediately
|
|
239
|
+
peakurl job run peakurl_version_check
|
|
240
|
+
|
|
241
|
+
# Trigger all currently due jobs
|
|
242
|
+
peakurl job run-due
|
|
243
|
+
```
|
|
244
|
+
|
|
231
245
|
Show the recommended install command:
|
|
232
246
|
|
|
233
247
|
```bash
|
|
@@ -255,7 +269,7 @@ export PEAKURL_DISABLE_UPDATE_CHECK=1
|
|
|
255
269
|
## Links
|
|
256
270
|
|
|
257
271
|
- Website: <https://peakurl.org/>
|
|
258
|
-
- CLI docs: <https://peakurl.org/
|
|
259
|
-
- API docs: <https://peakurl.org/
|
|
272
|
+
- CLI docs: <https://go.peakurl.org/7a0e0b>
|
|
273
|
+
- API docs: <https://go.peakurl.org/d373f6>
|
|
260
274
|
- npm package: <https://www.npmjs.com/package/peakurl>
|
|
261
275
|
- Issues: <https://github.com/PeakURL/CLI/issues>
|
package/bin/peakurl.js
CHANGED
|
@@ -120,7 +120,6 @@ var ApiClient = class {
|
|
|
120
120
|
constructor(config) {
|
|
121
121
|
this.config = config;
|
|
122
122
|
}
|
|
123
|
-
config;
|
|
124
123
|
/**
|
|
125
124
|
* Loads the currently authenticated user.
|
|
126
125
|
*
|
|
@@ -314,6 +313,86 @@ var ApiClient = class {
|
|
|
314
313
|
`webhooks/${encodeURIComponent(id)}`
|
|
315
314
|
);
|
|
316
315
|
}
|
|
316
|
+
/**
|
|
317
|
+
* Loads the current status of the cron scheduler.
|
|
318
|
+
*
|
|
319
|
+
* @returns API response envelope containing the scheduler status.
|
|
320
|
+
*/
|
|
321
|
+
getJobStatus() {
|
|
322
|
+
return this.request("GET", "system/cron");
|
|
323
|
+
}
|
|
324
|
+
/**
|
|
325
|
+
* Triggers all due cron jobs to run.
|
|
326
|
+
*
|
|
327
|
+
* @returns API response envelope containing the execution results.
|
|
328
|
+
*/
|
|
329
|
+
runDueJobs() {
|
|
330
|
+
return this.request("POST", "system/cron/run");
|
|
331
|
+
}
|
|
332
|
+
/**
|
|
333
|
+
* Forces a specific cron job to run immediately.
|
|
334
|
+
*
|
|
335
|
+
* @param id Job identifier.
|
|
336
|
+
* @returns API response envelope containing the execution result.
|
|
337
|
+
*/
|
|
338
|
+
runJob(id) {
|
|
339
|
+
return this.request(
|
|
340
|
+
"POST",
|
|
341
|
+
`system/cron/run/${encodeURIComponent(id)}`
|
|
342
|
+
);
|
|
343
|
+
}
|
|
344
|
+
/**
|
|
345
|
+
* Clears cron execution history.
|
|
346
|
+
*
|
|
347
|
+
* @param jobId Optional job identifier to clear history only for one job.
|
|
348
|
+
* @returns API response envelope containing the deleted count.
|
|
349
|
+
*/
|
|
350
|
+
clearJobHistory(jobId) {
|
|
351
|
+
return this.request(
|
|
352
|
+
"POST",
|
|
353
|
+
"system/cron/history/clear",
|
|
354
|
+
jobId ? { job_id: jobId } : void 0
|
|
355
|
+
);
|
|
356
|
+
}
|
|
357
|
+
/**
|
|
358
|
+
* Updates the schedule configuration for a cron job.
|
|
359
|
+
*
|
|
360
|
+
* @param id Job identifier.
|
|
361
|
+
* @param payload New configuration options.
|
|
362
|
+
* @returns API response envelope containing the updated job.
|
|
363
|
+
*/
|
|
364
|
+
updateJobSchedule(id, payload) {
|
|
365
|
+
return this.request(
|
|
366
|
+
"PATCH",
|
|
367
|
+
`system/cron/jobs/${encodeURIComponent(id)}`,
|
|
368
|
+
payload
|
|
369
|
+
);
|
|
370
|
+
}
|
|
371
|
+
/**
|
|
372
|
+
* Resets a cron job schedule to its default configuration.
|
|
373
|
+
*
|
|
374
|
+
* @param id Job identifier.
|
|
375
|
+
* @returns API response envelope containing the restored job.
|
|
376
|
+
*/
|
|
377
|
+
resetJobSchedule(id) {
|
|
378
|
+
return this.request(
|
|
379
|
+
"POST",
|
|
380
|
+
`system/cron/jobs/${encodeURIComponent(id)}/reset`
|
|
381
|
+
);
|
|
382
|
+
}
|
|
383
|
+
/**
|
|
384
|
+
* Updates the global cron settings, such as history retention.
|
|
385
|
+
*
|
|
386
|
+
* @param payload New global settings.
|
|
387
|
+
* @returns API response envelope containing the updated retention settings.
|
|
388
|
+
*/
|
|
389
|
+
updateJobSettings(payload) {
|
|
390
|
+
return this.request(
|
|
391
|
+
"POST",
|
|
392
|
+
"system/cron/settings",
|
|
393
|
+
payload
|
|
394
|
+
);
|
|
395
|
+
}
|
|
317
396
|
/**
|
|
318
397
|
* Performs one authenticated API request and normalizes the response.
|
|
319
398
|
*
|
|
@@ -1985,6 +2064,121 @@ ${checks}` : void 0,
|
|
|
1985
2064
|
return sections.length > 0 ? sections.join("\n\n") : "No system status fields returned.";
|
|
1986
2065
|
}
|
|
1987
2066
|
|
|
2067
|
+
// src/lib/job.ts
|
|
2068
|
+
function formatInterval(seconds) {
|
|
2069
|
+
if (seconds < 60) return `${seconds}s`;
|
|
2070
|
+
const minutes = Math.floor(seconds / 60);
|
|
2071
|
+
if (minutes < 60) return `${minutes}m`;
|
|
2072
|
+
const hours = Math.floor(minutes / 60);
|
|
2073
|
+
if (hours < 24) return `${hours}h`;
|
|
2074
|
+
const days = Math.floor(hours / 24);
|
|
2075
|
+
return `${days}d`;
|
|
2076
|
+
}
|
|
2077
|
+
function formatDate(date) {
|
|
2078
|
+
if (!date) return "never";
|
|
2079
|
+
return new Date(date).toISOString().replace("T", " ").substring(0, 19);
|
|
2080
|
+
}
|
|
2081
|
+
function formatJobsList(status2) {
|
|
2082
|
+
const rows2 = status2.jobs.map((job) => [
|
|
2083
|
+
job.id,
|
|
2084
|
+
job.title,
|
|
2085
|
+
job.status,
|
|
2086
|
+
job.is_enabled ? "yes" : "no",
|
|
2087
|
+
formatDate(job.next_run_at)
|
|
2088
|
+
]);
|
|
2089
|
+
const table = formatTable(
|
|
2090
|
+
["ID", "Job", "Status", "Enabled", "Next Run"],
|
|
2091
|
+
rows2
|
|
2092
|
+
);
|
|
2093
|
+
const summary = `
|
|
2094
|
+
${status2.jobs_count} jobs registered.
|
|
2095
|
+
Timezone: ${status2.timezone}
|
|
2096
|
+
History retention: ${status2.retention_days} days`;
|
|
2097
|
+
return `${table}${summary}`;
|
|
2098
|
+
}
|
|
2099
|
+
function formatJobDetails(job) {
|
|
2100
|
+
const rows2 = [
|
|
2101
|
+
["ID", job.id],
|
|
2102
|
+
["Title", job.title],
|
|
2103
|
+
["Status", job.status],
|
|
2104
|
+
["Enabled", job.is_enabled ? "yes" : "no"],
|
|
2105
|
+
["Current interval", formatInterval(job.interval_seconds)],
|
|
2106
|
+
[
|
|
2107
|
+
"Recommended interval",
|
|
2108
|
+
formatInterval(job.recommended_interval_seconds)
|
|
2109
|
+
],
|
|
2110
|
+
["Preferred run time", job.preferred_run_time || "none"],
|
|
2111
|
+
["Customized", job.is_customized ? "yes" : "no"],
|
|
2112
|
+
["Next run", formatDate(job.next_run_at)],
|
|
2113
|
+
["Last run", formatDate(job.last_run_at)],
|
|
2114
|
+
["Last finished", formatDate(job.last_finished_at)],
|
|
2115
|
+
["Attempts", String(job.attempts)],
|
|
2116
|
+
["Maximum attempts", String(job.max_attempts)],
|
|
2117
|
+
["Last error", job.last_error || "none"]
|
|
2118
|
+
];
|
|
2119
|
+
let out = formatDetailsTable(rows2);
|
|
2120
|
+
if (job.recent_runs && job.recent_runs.length > 0) {
|
|
2121
|
+
out += `
|
|
2122
|
+
|
|
2123
|
+
Recent Runs:
|
|
2124
|
+
${formatJobHistory(job.recent_runs)}`;
|
|
2125
|
+
}
|
|
2126
|
+
return out;
|
|
2127
|
+
}
|
|
2128
|
+
function formatJobHistory(runs) {
|
|
2129
|
+
if (!runs || runs.length === 0) {
|
|
2130
|
+
return "No recent runs.";
|
|
2131
|
+
}
|
|
2132
|
+
const rows2 = runs.map((run) => [
|
|
2133
|
+
run.id,
|
|
2134
|
+
run.status,
|
|
2135
|
+
String(run.attempt),
|
|
2136
|
+
formatDate(run.started_at),
|
|
2137
|
+
formatDate(run.finished_at),
|
|
2138
|
+
run.duration_ms ? `${run.duration_ms}ms` : "-",
|
|
2139
|
+
run.output_summary || "-",
|
|
2140
|
+
run.error_message || "-"
|
|
2141
|
+
]);
|
|
2142
|
+
return formatTable(
|
|
2143
|
+
[
|
|
2144
|
+
"Run ID",
|
|
2145
|
+
"Status",
|
|
2146
|
+
"Attempt",
|
|
2147
|
+
"Started",
|
|
2148
|
+
"Finished",
|
|
2149
|
+
"Duration",
|
|
2150
|
+
"Summary",
|
|
2151
|
+
"Error"
|
|
2152
|
+
],
|
|
2153
|
+
rows2
|
|
2154
|
+
);
|
|
2155
|
+
}
|
|
2156
|
+
function formatRunJobResult(result) {
|
|
2157
|
+
let out = `Job: ${result.job_id}
|
|
2158
|
+
Status: ${result.status}`;
|
|
2159
|
+
if (result.summary) {
|
|
2160
|
+
out += `
|
|
2161
|
+
Summary: ${result.summary}`;
|
|
2162
|
+
}
|
|
2163
|
+
if (result.error) {
|
|
2164
|
+
out += `
|
|
2165
|
+
Error: ${result.error}`;
|
|
2166
|
+
}
|
|
2167
|
+
return out;
|
|
2168
|
+
}
|
|
2169
|
+
function formatRunDueResult(result) {
|
|
2170
|
+
if (!result.results || result.results.length === 0) {
|
|
2171
|
+
return "No jobs were due.";
|
|
2172
|
+
}
|
|
2173
|
+
const rows2 = result.results.map((r) => [
|
|
2174
|
+
r.job_id,
|
|
2175
|
+
r.status,
|
|
2176
|
+
r.summary || "-",
|
|
2177
|
+
r.error || "-"
|
|
2178
|
+
]);
|
|
2179
|
+
return formatTable(["Job ID", "Status", "Summary", "Error"], rows2);
|
|
2180
|
+
}
|
|
2181
|
+
|
|
1988
2182
|
// src/lib/update.ts
|
|
1989
2183
|
var PACKAGE_NAME = "peakurl";
|
|
1990
2184
|
var DEFAULT_REGISTRY_URL = "https://registry.npmjs.org";
|
|
@@ -2927,6 +3121,230 @@ async function whoami(options) {
|
|
|
2927
3121
|
writeStdout(userTable(response.data, config.apiBaseUrl));
|
|
2928
3122
|
}
|
|
2929
3123
|
|
|
3124
|
+
// src/commands/job.ts
|
|
3125
|
+
async function getClient() {
|
|
3126
|
+
const config = await getAuthConfig(process.env);
|
|
3127
|
+
return new ApiClient(config);
|
|
3128
|
+
}
|
|
3129
|
+
async function listJobs(options) {
|
|
3130
|
+
const client = await getClient();
|
|
3131
|
+
const response = await client.getJobStatus();
|
|
3132
|
+
if (options.json) {
|
|
3133
|
+
writeJson(response);
|
|
3134
|
+
return;
|
|
3135
|
+
}
|
|
3136
|
+
if (options.quiet) {
|
|
3137
|
+
const ids = response.data.jobs.map((job) => job.id).join("\n");
|
|
3138
|
+
if (ids) {
|
|
3139
|
+
writeStdout(ids);
|
|
3140
|
+
}
|
|
3141
|
+
return;
|
|
3142
|
+
}
|
|
3143
|
+
writeStdout(successLine(response.message));
|
|
3144
|
+
writeStdout();
|
|
3145
|
+
writeStdout(formatJobsList(response.data));
|
|
3146
|
+
}
|
|
3147
|
+
async function getJob(id, options) {
|
|
3148
|
+
const client = await getClient();
|
|
3149
|
+
const response = await client.getJobStatus();
|
|
3150
|
+
const job = response.data.jobs.find((j) => j.id === id);
|
|
3151
|
+
if (!job) {
|
|
3152
|
+
throw new CliError(`Job '${id}' not found.`, 1);
|
|
3153
|
+
}
|
|
3154
|
+
if (options.json) {
|
|
3155
|
+
writeJson({
|
|
3156
|
+
success: true,
|
|
3157
|
+
message: "Job loaded.",
|
|
3158
|
+
data: job,
|
|
3159
|
+
timestamp: response.timestamp
|
|
3160
|
+
});
|
|
3161
|
+
return;
|
|
3162
|
+
}
|
|
3163
|
+
if (options.quiet) {
|
|
3164
|
+
writeStdout(job.id);
|
|
3165
|
+
return;
|
|
3166
|
+
}
|
|
3167
|
+
writeStdout(successLine(`Job ${job.id} loaded.`));
|
|
3168
|
+
writeStdout();
|
|
3169
|
+
writeStdout(formatJobDetails(job));
|
|
3170
|
+
}
|
|
3171
|
+
async function runJob(id, options) {
|
|
3172
|
+
const client = await getClient();
|
|
3173
|
+
const response = await client.runJob(id);
|
|
3174
|
+
if (options.json) {
|
|
3175
|
+
writeJson(response);
|
|
3176
|
+
return;
|
|
3177
|
+
}
|
|
3178
|
+
if (options.quiet) {
|
|
3179
|
+
writeStdout(response.data.status);
|
|
3180
|
+
return;
|
|
3181
|
+
}
|
|
3182
|
+
writeStdout(successLine(response.message));
|
|
3183
|
+
writeStdout();
|
|
3184
|
+
writeStdout(formatRunJobResult(response.data));
|
|
3185
|
+
}
|
|
3186
|
+
async function runDueJobs(options) {
|
|
3187
|
+
const client = await getClient();
|
|
3188
|
+
const response = await client.runDueJobs();
|
|
3189
|
+
if (options.json) {
|
|
3190
|
+
writeJson(response);
|
|
3191
|
+
return;
|
|
3192
|
+
}
|
|
3193
|
+
if (options.quiet) {
|
|
3194
|
+
const statuses = response.data.results.map((r) => r.status).join("\n");
|
|
3195
|
+
if (statuses) {
|
|
3196
|
+
writeStdout(statuses);
|
|
3197
|
+
}
|
|
3198
|
+
return;
|
|
3199
|
+
}
|
|
3200
|
+
writeStdout(successLine(response.message));
|
|
3201
|
+
writeStdout();
|
|
3202
|
+
writeStdout(formatRunDueResult(response.data));
|
|
3203
|
+
}
|
|
3204
|
+
async function listJobHistory(id, options) {
|
|
3205
|
+
const client = await getClient();
|
|
3206
|
+
const response = await client.getJobStatus();
|
|
3207
|
+
const job = response.data.jobs.find((j) => j.id === id);
|
|
3208
|
+
if (!job) {
|
|
3209
|
+
throw new CliError(`Job '${id}' not found.`, 1);
|
|
3210
|
+
}
|
|
3211
|
+
if (options.json) {
|
|
3212
|
+
writeJson({
|
|
3213
|
+
success: true,
|
|
3214
|
+
message: "History loaded.",
|
|
3215
|
+
data: job.recent_runs || [],
|
|
3216
|
+
timestamp: response.timestamp
|
|
3217
|
+
});
|
|
3218
|
+
return;
|
|
3219
|
+
}
|
|
3220
|
+
if (options.quiet) {
|
|
3221
|
+
const ids = (job.recent_runs || []).map((r) => r.id).join("\n");
|
|
3222
|
+
if (ids) {
|
|
3223
|
+
writeStdout(ids);
|
|
3224
|
+
}
|
|
3225
|
+
return;
|
|
3226
|
+
}
|
|
3227
|
+
writeStdout(successLine(`History for job ${job.id} loaded.`));
|
|
3228
|
+
writeStdout();
|
|
3229
|
+
writeStdout(formatJobHistory(job.recent_runs || []));
|
|
3230
|
+
}
|
|
3231
|
+
async function clearJobHistory(options) {
|
|
3232
|
+
const client = await getClient();
|
|
3233
|
+
const response = await client.clearJobHistory(options.job);
|
|
3234
|
+
if (options.json) {
|
|
3235
|
+
writeJson(response);
|
|
3236
|
+
return;
|
|
3237
|
+
}
|
|
3238
|
+
if (options.quiet) {
|
|
3239
|
+
return;
|
|
3240
|
+
}
|
|
3241
|
+
writeStdout(successLine(response.message));
|
|
3242
|
+
}
|
|
3243
|
+
async function updateJobSchedule(id, options) {
|
|
3244
|
+
const client = await getClient();
|
|
3245
|
+
if (options.enabled && options.disabled) {
|
|
3246
|
+
throw new CliError("Cannot specify both --enabled and --disabled.", 1);
|
|
3247
|
+
}
|
|
3248
|
+
const payload = {};
|
|
3249
|
+
if (options.interval !== void 0) {
|
|
3250
|
+
const interval = parseInt(options.interval, 10);
|
|
3251
|
+
if (isNaN(interval) || interval <= 0) {
|
|
3252
|
+
throw new CliError("Interval must be a positive integer.", 1);
|
|
3253
|
+
}
|
|
3254
|
+
payload.interval_seconds = interval;
|
|
3255
|
+
}
|
|
3256
|
+
if (options.preferredTime !== void 0) {
|
|
3257
|
+
if (options.preferredTime.toLowerCase() === "none" || options.preferredTime === "") {
|
|
3258
|
+
payload.preferred_run_time = null;
|
|
3259
|
+
} else if (/^([0-1]?[0-9]|2[0-3]):[0-5][0-9]$/.test(options.preferredTime)) {
|
|
3260
|
+
payload.preferred_run_time = options.preferredTime;
|
|
3261
|
+
} else {
|
|
3262
|
+
throw new CliError(
|
|
3263
|
+
"Preferred time must be in HH:MM format or 'none'.",
|
|
3264
|
+
1
|
|
3265
|
+
);
|
|
3266
|
+
}
|
|
3267
|
+
}
|
|
3268
|
+
if (options.enabled !== void 0) {
|
|
3269
|
+
payload.is_enabled = true;
|
|
3270
|
+
} else if (options.disabled !== void 0) {
|
|
3271
|
+
payload.is_enabled = false;
|
|
3272
|
+
}
|
|
3273
|
+
if (Object.keys(payload).length === 0) {
|
|
3274
|
+
throw new CliError("No schedule changes requested.", 1);
|
|
3275
|
+
}
|
|
3276
|
+
const response = await client.updateJobSchedule(id, payload);
|
|
3277
|
+
if (options.json) {
|
|
3278
|
+
writeJson(response);
|
|
3279
|
+
return;
|
|
3280
|
+
}
|
|
3281
|
+
if (options.quiet) {
|
|
3282
|
+
return;
|
|
3283
|
+
}
|
|
3284
|
+
writeStdout(successLine(response.message));
|
|
3285
|
+
writeStdout();
|
|
3286
|
+
writeStdout(formatJobDetails(response.data));
|
|
3287
|
+
}
|
|
3288
|
+
async function resetJobSchedule(id, options) {
|
|
3289
|
+
const client = await getClient();
|
|
3290
|
+
const response = await client.resetJobSchedule(id);
|
|
3291
|
+
if (options.json) {
|
|
3292
|
+
writeJson(response);
|
|
3293
|
+
return;
|
|
3294
|
+
}
|
|
3295
|
+
if (options.quiet) {
|
|
3296
|
+
return;
|
|
3297
|
+
}
|
|
3298
|
+
writeStdout(successLine(response.message));
|
|
3299
|
+
writeStdout();
|
|
3300
|
+
writeStdout(formatJobDetails(response.data));
|
|
3301
|
+
}
|
|
3302
|
+
async function updateJobSettings(options) {
|
|
3303
|
+
const client = await getClient();
|
|
3304
|
+
if (options.retentionDays !== void 0) {
|
|
3305
|
+
const days = parseInt(options.retentionDays, 10);
|
|
3306
|
+
if (isNaN(days) || days < 0) {
|
|
3307
|
+
throw new CliError(
|
|
3308
|
+
"Retention days must be a non-negative integer.",
|
|
3309
|
+
1
|
|
3310
|
+
);
|
|
3311
|
+
}
|
|
3312
|
+
const response2 = await client.updateJobSettings({
|
|
3313
|
+
retention_days: days
|
|
3314
|
+
});
|
|
3315
|
+
if (options.json) {
|
|
3316
|
+
writeJson(response2);
|
|
3317
|
+
return;
|
|
3318
|
+
}
|
|
3319
|
+
if (options.quiet) {
|
|
3320
|
+
writeStdout(String(response2.data.retention_days));
|
|
3321
|
+
return;
|
|
3322
|
+
}
|
|
3323
|
+
writeStdout(successLine(response2.message));
|
|
3324
|
+
return;
|
|
3325
|
+
}
|
|
3326
|
+
const response = await client.getJobStatus();
|
|
3327
|
+
if (options.json) {
|
|
3328
|
+
writeJson({
|
|
3329
|
+
success: true,
|
|
3330
|
+
message: "Settings loaded.",
|
|
3331
|
+
data: {
|
|
3332
|
+
retention_days: response.data.retention_days,
|
|
3333
|
+
timezone: response.data.timezone
|
|
3334
|
+
},
|
|
3335
|
+
timestamp: response.timestamp
|
|
3336
|
+
});
|
|
3337
|
+
return;
|
|
3338
|
+
}
|
|
3339
|
+
if (options.quiet) {
|
|
3340
|
+
writeStdout(String(response.data.retention_days));
|
|
3341
|
+
return;
|
|
3342
|
+
}
|
|
3343
|
+
writeStdout(successLine("Settings loaded."));
|
|
3344
|
+
writeStdout(`History retention: ${response.data.retention_days} days`);
|
|
3345
|
+
writeStdout(`Timezone: ${response.data.timezone}`);
|
|
3346
|
+
}
|
|
3347
|
+
|
|
2930
3348
|
// src/index.ts
|
|
2931
3349
|
function parseNumber(label) {
|
|
2932
3350
|
return (value) => {
|
|
@@ -2961,7 +3379,7 @@ function getRetryCommandName(argv) {
|
|
|
2961
3379
|
if (!first || first.startsWith("-")) {
|
|
2962
3380
|
return void 0;
|
|
2963
3381
|
}
|
|
2964
|
-
if (first === "webhook" || first === "
|
|
3382
|
+
if (first === "webhook" || first === "activity" || first === "job") {
|
|
2965
3383
|
const second = argv[3]?.trim();
|
|
2966
3384
|
if (second && !second.startsWith("-")) {
|
|
2967
3385
|
return `${first} ${second}`;
|
|
@@ -2969,10 +3387,33 @@ function getRetryCommandName(argv) {
|
|
|
2969
3387
|
}
|
|
2970
3388
|
return first;
|
|
2971
3389
|
}
|
|
3390
|
+
var COMMAND_SUGGESTIONS = {
|
|
3391
|
+
activities: "activity",
|
|
3392
|
+
webhooks: "webhook",
|
|
3393
|
+
jobs: "job",
|
|
3394
|
+
cron: "job",
|
|
3395
|
+
"scheduled-jobs": "job",
|
|
3396
|
+
links: "list",
|
|
3397
|
+
urls: "list"
|
|
3398
|
+
};
|
|
2972
3399
|
async function main() {
|
|
2973
3400
|
const program = new Command();
|
|
2974
3401
|
const version = await getCliVersion();
|
|
2975
|
-
program.name("peakurl").description("Manage your PeakURL site from the terminal.").helpOption("-h, --help", "Show help").helpCommand("help [command]", "Show help for a command").version(version, "-v, --version", "Show CLI version").
|
|
3402
|
+
program.name("peakurl").description("Manage your PeakURL site from the terminal.").helpOption("-h, --help", "Show help").helpCommand("help [command]", "Show help for a command").version(version, "-v, --version", "Show CLI version").configureOutput({
|
|
3403
|
+
outputError: (str, write) => {
|
|
3404
|
+
const match = /error: unknown command '([^']+)'/.exec(str);
|
|
3405
|
+
if (match && COMMAND_SUGGESTIONS[match[1]]) {
|
|
3406
|
+
const suggestion = COMMAND_SUGGESTIONS[match[1]];
|
|
3407
|
+
write(
|
|
3408
|
+
`error: unknown command '${match[1]}'. Did you mean 'peakurl ${suggestion}'?
|
|
3409
|
+
|
|
3410
|
+
`
|
|
3411
|
+
);
|
|
3412
|
+
return;
|
|
3413
|
+
}
|
|
3414
|
+
write(str);
|
|
3415
|
+
}
|
|
3416
|
+
}).showHelpAfterError().showSuggestionAfterError().addHelpText(
|
|
2976
3417
|
"after",
|
|
2977
3418
|
`
|
|
2978
3419
|
Get Started:
|
|
@@ -2986,6 +3427,8 @@ Common Commands:
|
|
|
2986
3427
|
peakurl list --limit 10
|
|
2987
3428
|
peakurl import ./links.csv
|
|
2988
3429
|
peakurl export --format csv
|
|
3430
|
+
peakurl activity list
|
|
3431
|
+
peakurl job list
|
|
2989
3432
|
peakurl webhook list
|
|
2990
3433
|
peakurl update --check
|
|
2991
3434
|
|
|
@@ -3104,7 +3547,7 @@ Run 'peakurl <command> --help' for command-specific flags and examples.`
|
|
|
3104
3547
|
"peakurl delete --all"
|
|
3105
3548
|
]
|
|
3106
3549
|
);
|
|
3107
|
-
const activity = program.command("activity").
|
|
3550
|
+
const activity = program.command("activity").summary("View and manage activity logs").helpOption("-h, --help", "Show help").description(
|
|
3108
3551
|
"View audit log activity entries, delete specific records, or clear all history."
|
|
3109
3552
|
);
|
|
3110
3553
|
addExamples(activity, [
|
|
@@ -3150,7 +3593,92 @@ Run 'peakurl <command> --help' for command-specific flags and examples.`
|
|
|
3150
3593
|
),
|
|
3151
3594
|
["peakurl update", "peakurl update --check", "peakurl update --json"]
|
|
3152
3595
|
);
|
|
3153
|
-
const
|
|
3596
|
+
const jobCmd = program.command("job").summary("Manage scheduled jobs").description(
|
|
3597
|
+
"Manage server-side scheduled jobs, view their execution history, and run them manually."
|
|
3598
|
+
).helpOption("-h, --help", "Show help");
|
|
3599
|
+
addExamples(jobCmd, [
|
|
3600
|
+
"peakurl job",
|
|
3601
|
+
"peakurl job list",
|
|
3602
|
+
"peakurl job get peakurl_version_check",
|
|
3603
|
+
"peakurl job run peakurl_version_check",
|
|
3604
|
+
"peakurl job run-due"
|
|
3605
|
+
]);
|
|
3606
|
+
addExamples(
|
|
3607
|
+
jobCmd.command("list", { isDefault: true }).summary("List scheduled jobs").description("List all registered scheduled jobs.").helpOption("-h, --help", "Show help").option("--json", "Print machine-readable output").option("--quiet", "Print only job IDs").action(listJobs),
|
|
3608
|
+
[
|
|
3609
|
+
"peakurl job",
|
|
3610
|
+
"peakurl job list",
|
|
3611
|
+
"peakurl job list --json",
|
|
3612
|
+
"peakurl job list --quiet"
|
|
3613
|
+
]
|
|
3614
|
+
);
|
|
3615
|
+
addExamples(
|
|
3616
|
+
jobCmd.command("get").summary("Show job details").description(
|
|
3617
|
+
"Show detailed configuration and status for one scheduled job."
|
|
3618
|
+
).helpOption("-h, --help", "Show help").argument("<id>", "Job identifier").option("--json", "Print machine-readable output").option("--quiet", "Print only the job ID").action(getJob),
|
|
3619
|
+
[
|
|
3620
|
+
"peakurl job get peakurl_version_check",
|
|
3621
|
+
"peakurl job get peakurl_version_check --json"
|
|
3622
|
+
]
|
|
3623
|
+
);
|
|
3624
|
+
addExamples(
|
|
3625
|
+
jobCmd.command("run").summary("Run a scheduled job").description("Force a specific scheduled job to run immediately.").helpOption("-h, --help", "Show help").argument("<id>", "Job identifier").option("--json", "Print machine-readable output").option("--quiet", "Print only the execution status").action(runJob),
|
|
3626
|
+
[
|
|
3627
|
+
"peakurl job run peakurl_version_check",
|
|
3628
|
+
"peakurl job run peakurl_version_check --json"
|
|
3629
|
+
]
|
|
3630
|
+
);
|
|
3631
|
+
addExamples(
|
|
3632
|
+
jobCmd.command("run-due").summary("Run due jobs").description("Trigger all scheduled jobs that are currently due.").helpOption("-h, --help", "Show help").option("--json", "Print machine-readable output").option("--quiet", "Print only the execution statuses").action(runDueJobs),
|
|
3633
|
+
["peakurl job run-due", "peakurl job run-due --json"]
|
|
3634
|
+
);
|
|
3635
|
+
addExamples(
|
|
3636
|
+
jobCmd.command("history").summary("View job history").description("View recent execution history for a scheduled job.").helpOption("-h, --help", "Show help").argument("<id>", "Job identifier").option("--json", "Print machine-readable output").option("--quiet", "Print only history record IDs").action(listJobHistory),
|
|
3637
|
+
[
|
|
3638
|
+
"peakurl job history peakurl_version_check",
|
|
3639
|
+
"peakurl job history peakurl_version_check --json"
|
|
3640
|
+
]
|
|
3641
|
+
);
|
|
3642
|
+
addExamples(
|
|
3643
|
+
jobCmd.command("clear-history").summary("Clear job history").description(
|
|
3644
|
+
"Clear execution history for all jobs or a specific job."
|
|
3645
|
+
).helpOption("-h, --help", "Show help").option("--job <id>", "Specific job identifier to clear").option("--json", "Print machine-readable output").option("--quiet", "Suppress success output").action(clearJobHistory),
|
|
3646
|
+
[
|
|
3647
|
+
"peakurl job clear-history",
|
|
3648
|
+
"peakurl job clear-history --job peakurl_version_check",
|
|
3649
|
+
"peakurl job clear-history --json"
|
|
3650
|
+
]
|
|
3651
|
+
);
|
|
3652
|
+
addExamples(
|
|
3653
|
+
jobCmd.command("schedule").summary("Update job schedule").description("Update the schedule configuration for a job.").helpOption("-h, --help", "Show help").argument("<id>", "Job identifier").option("--interval <seconds>", "Execution interval in seconds").option(
|
|
3654
|
+
"--preferred-time <time>",
|
|
3655
|
+
"Preferred run time (HH:MM or 'none')"
|
|
3656
|
+
).option("--enabled", "Enable the job").option("--disabled", "Disable the job").option("--json", "Print machine-readable output").option("--quiet", "Suppress success output").action(updateJobSchedule),
|
|
3657
|
+
[
|
|
3658
|
+
"peakurl job schedule peakurl_version_check --interval 43200",
|
|
3659
|
+
"peakurl job schedule peakurl_version_check --preferred-time 03:00",
|
|
3660
|
+
"peakurl job schedule peakurl_version_check --disabled"
|
|
3661
|
+
]
|
|
3662
|
+
);
|
|
3663
|
+
addExamples(
|
|
3664
|
+
jobCmd.command("reset").summary("Reset job schedule").description("Reset a job's schedule to its default configuration.").helpOption("-h, --help", "Show help").argument("<id>", "Job identifier").option("--json", "Print machine-readable output").option("--quiet", "Suppress success output").action(resetJobSchedule),
|
|
3665
|
+
[
|
|
3666
|
+
"peakurl job reset peakurl_version_check",
|
|
3667
|
+
"peakurl job reset peakurl_version_check --json"
|
|
3668
|
+
]
|
|
3669
|
+
);
|
|
3670
|
+
addExamples(
|
|
3671
|
+
jobCmd.command("settings").summary("Manage scheduler settings").description("View or update global scheduler settings.").helpOption("-h, --help", "Show help").option(
|
|
3672
|
+
"--retention-days <days>",
|
|
3673
|
+
"Number of days to keep execution history"
|
|
3674
|
+
).option("--json", "Print machine-readable output").option("--quiet", "Print minimal output").action(updateJobSettings),
|
|
3675
|
+
[
|
|
3676
|
+
"peakurl job settings",
|
|
3677
|
+
"peakurl job settings --retention-days 14",
|
|
3678
|
+
"peakurl job settings --json"
|
|
3679
|
+
]
|
|
3680
|
+
);
|
|
3681
|
+
const webhook = program.command("webhook").summary("Manage webhooks").helpOption("-h, --help", "Show help").description("Manage outbound webhook integrations.");
|
|
3154
3682
|
addExamples(webhook, [
|
|
3155
3683
|
"peakurl webhook",
|
|
3156
3684
|
"peakurl webhook list",
|
package/man/peakurl.1
CHANGED
|
@@ -195,6 +195,54 @@ List supported webhook event identifiers.
|
|
|
195
195
|
.Bd -literal -offset indent
|
|
196
196
|
peakurl webhook events
|
|
197
197
|
.Ed
|
|
198
|
+
.It Cm job list
|
|
199
|
+
List all registered scheduled jobs.
|
|
200
|
+
.Bd -literal -offset indent
|
|
201
|
+
peakurl job list
|
|
202
|
+
peakurl job list --json
|
|
203
|
+
.Ed
|
|
204
|
+
.It Cm job get Ar id
|
|
205
|
+
Fetch one scheduled job by ID.
|
|
206
|
+
.Bd -literal -offset indent
|
|
207
|
+
peakurl job get peakurl_version_check
|
|
208
|
+
.Ed
|
|
209
|
+
.It Cm job run Ar id
|
|
210
|
+
Force a specific scheduled job to run immediately.
|
|
211
|
+
.Bd -literal -offset indent
|
|
212
|
+
peakurl job run peakurl_version_check
|
|
213
|
+
.Ed
|
|
214
|
+
.It Cm job run-due
|
|
215
|
+
Trigger all scheduled jobs that are currently due.
|
|
216
|
+
.Bd -literal -offset indent
|
|
217
|
+
peakurl job run-due
|
|
218
|
+
.Ed
|
|
219
|
+
.It Cm job history Ar id
|
|
220
|
+
View recent execution history for a scheduled job.
|
|
221
|
+
.Bd -literal -offset indent
|
|
222
|
+
peakurl job history peakurl_version_check
|
|
223
|
+
.Ed
|
|
224
|
+
.It Cm job clear-history
|
|
225
|
+
Clear execution history for all jobs or a specific job.
|
|
226
|
+
.Bd -literal -offset indent
|
|
227
|
+
peakurl job clear-history
|
|
228
|
+
peakurl job clear-history --job peakurl_version_check
|
|
229
|
+
.Ed
|
|
230
|
+
.It Cm job schedule Ar id
|
|
231
|
+
Update the schedule configuration for a job.
|
|
232
|
+
.Bd -literal -offset indent
|
|
233
|
+
peakurl job schedule peakurl_version_check --interval 43200 --preferred-time 03:00 --enabled
|
|
234
|
+
.Ed
|
|
235
|
+
.It Cm job reset Ar id
|
|
236
|
+
Reset a job's schedule to its default configuration.
|
|
237
|
+
.Bd -literal -offset indent
|
|
238
|
+
peakurl job reset peakurl_version_check
|
|
239
|
+
.Ed
|
|
240
|
+
.It Cm job settings
|
|
241
|
+
View or update global scheduler settings.
|
|
242
|
+
.Bd -literal -offset indent
|
|
243
|
+
peakurl job settings
|
|
244
|
+
peakurl job settings --retention-days 14
|
|
245
|
+
.Ed
|
|
198
246
|
.It Cm update
|
|
199
247
|
Check for a newer CLI version and print the npm install command when an
|
|
200
248
|
update is available.
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "peakurl",
|
|
3
|
-
"version": "1.1.
|
|
3
|
+
"version": "1.1.1",
|
|
4
4
|
"description": "Official CLI for creating, listing, and managing PeakURL short links from the terminal",
|
|
5
5
|
"homepage": "https://peakurl.org",
|
|
6
6
|
"bugs": {
|
|
@@ -55,16 +55,16 @@
|
|
|
55
55
|
},
|
|
56
56
|
"devDependencies": {
|
|
57
57
|
"@eslint/js": "^10.0.1",
|
|
58
|
-
"@types/node": "^26.
|
|
59
|
-
"eslint": "^10.
|
|
58
|
+
"@types/node": "^26.6.2",
|
|
59
|
+
"eslint": "^10.11.0",
|
|
60
60
|
"eslint-config-prettier": "^10.1.8",
|
|
61
61
|
"eslint-plugin-prettier": "^5.5.6",
|
|
62
62
|
"globals": "^17.12.0",
|
|
63
|
-
"prettier": "^3.9.
|
|
63
|
+
"prettier": "^3.9.8",
|
|
64
64
|
"tsup": "^8.5.1",
|
|
65
|
-
"tsx": "^4.23.
|
|
65
|
+
"tsx": "^4.23.15",
|
|
66
66
|
"typescript": "^5.9.3",
|
|
67
|
-
"typescript-eslint": "^8.
|
|
67
|
+
"typescript-eslint": "^8.70.1"
|
|
68
68
|
},
|
|
69
69
|
"license": "MIT"
|
|
70
70
|
}
|