@wport/cli 0.9.1-dev.0 → 0.9.2
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/CHANGELOG.md +24 -0
- package/README.md +11 -11
- package/dist/index.js +241 -1284
- package/dist/index.js.map +1 -1
- package/package.json +2 -10
package/dist/index.js
CHANGED
|
@@ -27,6 +27,7 @@ var __toESM = (mod, isNodeMode, target) => (target = mod != null ? __create(__ge
|
|
|
27
27
|
var import_commander = require("commander");
|
|
28
28
|
|
|
29
29
|
// src/lib/errors.ts
|
|
30
|
+
var import_core = require("@wport/core");
|
|
30
31
|
var ExitCode = {
|
|
31
32
|
Success: 0,
|
|
32
33
|
InvalidArgument: 2,
|
|
@@ -48,27 +49,19 @@ var InvalidArgumentError = class extends CliError {
|
|
|
48
49
|
this.name = "InvalidArgumentError";
|
|
49
50
|
}
|
|
50
51
|
};
|
|
51
|
-
var ServerClientHttpError = class extends CliError {
|
|
52
|
-
status;
|
|
53
|
-
body;
|
|
54
|
-
constructor(message, status, body) {
|
|
55
|
-
super(message, ExitCode.ServerClientError);
|
|
56
|
-
this.name = "ServerClientHttpError";
|
|
57
|
-
this.status = status;
|
|
58
|
-
this.body = body;
|
|
59
|
-
}
|
|
60
|
-
};
|
|
61
|
-
var NetworkError = class extends CliError {
|
|
62
|
-
cause;
|
|
63
|
-
constructor(message, cause) {
|
|
64
|
-
super(message, ExitCode.ServerOrNetworkError);
|
|
65
|
-
this.name = "NetworkError";
|
|
66
|
-
this.cause = cause;
|
|
67
|
-
}
|
|
68
|
-
};
|
|
69
52
|
function isCliError(err) {
|
|
70
53
|
return err instanceof CliError;
|
|
71
54
|
}
|
|
55
|
+
function exitCodeForError(err) {
|
|
56
|
+
if (err instanceof import_core.WportInvalidArgumentError) return ExitCode.InvalidArgument;
|
|
57
|
+
if (err instanceof import_core.WportHttpError) {
|
|
58
|
+
return err.status >= 400 && err.status < 500 ? ExitCode.ServerClientError : ExitCode.ServerOrNetworkError;
|
|
59
|
+
}
|
|
60
|
+
if (err instanceof import_core.WportNetworkError) return ExitCode.ServerOrNetworkError;
|
|
61
|
+
return ExitCode.ServerOrNetworkError;
|
|
62
|
+
}
|
|
63
|
+
var ServerClientHttpError = import_core.WportHttpError;
|
|
64
|
+
var NetworkError = import_core.WportNetworkError;
|
|
72
65
|
|
|
73
66
|
// src/lib/output.ts
|
|
74
67
|
var import_cli_table3 = __toESM(require("cli-table3"));
|
|
@@ -146,96 +139,7 @@ function dim(text, color) {
|
|
|
146
139
|
|
|
147
140
|
// src/commands/jobs/search.ts
|
|
148
141
|
var import_node_fs2 = require("fs");
|
|
149
|
-
|
|
150
|
-
// src/lib/api-client.ts
|
|
151
|
-
var import_openapi_fetch = __toESM(require("openapi-fetch"));
|
|
152
|
-
function createApiClient(opts) {
|
|
153
|
-
return (0, import_openapi_fetch.default)({
|
|
154
|
-
baseUrl: opts.baseUrl,
|
|
155
|
-
headers: {
|
|
156
|
-
"Accept-Language": opts.locale,
|
|
157
|
-
"User-Agent": buildUserAgent(),
|
|
158
|
-
Accept: "application/json"
|
|
159
|
-
},
|
|
160
|
-
fetch: (request) => fetchWithTimeout(request, opts.timeoutMs)
|
|
161
|
-
});
|
|
162
|
-
}
|
|
163
|
-
function fetchWithTimeout(request, timeoutMs) {
|
|
164
|
-
const timedRequest = new Request(request, { signal: AbortSignal.timeout(timeoutMs) });
|
|
165
|
-
return fetch(timedRequest).catch((err) => {
|
|
166
|
-
if (isTimeoutAbort(err)) {
|
|
167
|
-
throw new NetworkError(`Request timed out after ${timeoutMs}ms`, err);
|
|
168
|
-
}
|
|
169
|
-
const code = err?.cause?.code;
|
|
170
|
-
const detail = code ? code : err?.message ?? String(err);
|
|
171
|
-
throw new NetworkError(`Cannot reach upstream: ${detail}`, err);
|
|
172
|
-
});
|
|
173
|
-
}
|
|
174
|
-
function isTimeoutAbort(err) {
|
|
175
|
-
if (err && typeof err === "object" && "name" in err) {
|
|
176
|
-
const name = err.name;
|
|
177
|
-
return name === "TimeoutError" || name === "AbortError";
|
|
178
|
-
}
|
|
179
|
-
return false;
|
|
180
|
-
}
|
|
181
|
-
function buildUserAgent() {
|
|
182
|
-
return `wport-cli/${"0.9.1-dev.0"} (node ${process.version}; ${process.platform})`;
|
|
183
|
-
}
|
|
184
|
-
function unwrapDataResponse(body) {
|
|
185
|
-
if (body && typeof body === "object" && "success" in body && "data" in body) {
|
|
186
|
-
return body.data;
|
|
187
|
-
}
|
|
188
|
-
throw new CliError("Unexpected response shape: missing { success, data } wrapper", ExitCode.ServerOrNetworkError);
|
|
189
|
-
}
|
|
190
|
-
function unwrapDataArray(body) {
|
|
191
|
-
const data = unwrapDataResponse(body);
|
|
192
|
-
if (!Array.isArray(data)) {
|
|
193
|
-
throw new CliError("Unexpected response shape: `data` is not an array", ExitCode.ServerOrNetworkError);
|
|
194
|
-
}
|
|
195
|
-
return data;
|
|
196
|
-
}
|
|
197
|
-
function asPaginatedBody(body) {
|
|
198
|
-
if (!body || typeof body !== "object") {
|
|
199
|
-
throw new CliError("Unexpected response shape: not an object", ExitCode.ServerOrNetworkError);
|
|
200
|
-
}
|
|
201
|
-
const b = body;
|
|
202
|
-
if (!Array.isArray(b.data)) {
|
|
203
|
-
throw new CliError("Unexpected response shape: missing `data` array", ExitCode.ServerOrNetworkError);
|
|
204
|
-
}
|
|
205
|
-
for (const key of ["currentPage", "totalPages", "pageSize", "totalCount"]) {
|
|
206
|
-
if (typeof b[key] !== "number") {
|
|
207
|
-
throw new CliError(`Unexpected response shape: missing or non-numeric "${key}"`, ExitCode.ServerOrNetworkError);
|
|
208
|
-
}
|
|
209
|
-
}
|
|
210
|
-
return body;
|
|
211
|
-
}
|
|
212
|
-
function throwForHttpStatus(status, body) {
|
|
213
|
-
const message = extractErrorMessage(body) ?? `HTTP ${status}`;
|
|
214
|
-
if (status >= 400 && status < 500) {
|
|
215
|
-
throw new ServerClientHttpError(message, status, body);
|
|
216
|
-
}
|
|
217
|
-
throw new CliError(message, ExitCode.ServerOrNetworkError);
|
|
218
|
-
}
|
|
219
|
-
function extractErrorMessage(body) {
|
|
220
|
-
if (typeof body === "string") return body;
|
|
221
|
-
if (body && typeof body === "object") {
|
|
222
|
-
const obj = body;
|
|
223
|
-
if (Array.isArray(obj.message)) {
|
|
224
|
-
const parts = obj.message.filter((m) => typeof m === "string");
|
|
225
|
-
if (parts.length > 0) return parts.join("; ");
|
|
226
|
-
}
|
|
227
|
-
if (typeof obj.message === "string") return obj.message;
|
|
228
|
-
if (obj.message && typeof obj.message === "object") {
|
|
229
|
-
try {
|
|
230
|
-
return JSON.stringify(obj.message);
|
|
231
|
-
} catch {
|
|
232
|
-
}
|
|
233
|
-
}
|
|
234
|
-
if (typeof obj.path === "string") return obj.path;
|
|
235
|
-
if (typeof obj.error === "string") return obj.error;
|
|
236
|
-
}
|
|
237
|
-
return null;
|
|
238
|
-
}
|
|
142
|
+
var import_core2 = require("@wport/core");
|
|
239
143
|
|
|
240
144
|
// src/lib/config-store.ts
|
|
241
145
|
var import_node_fs = require("fs");
|
|
@@ -372,7 +276,7 @@ var CHANNEL_BASE_URL = {
|
|
|
372
276
|
dev: "https://developers.wport.me/v2"
|
|
373
277
|
};
|
|
374
278
|
function currentChannel() {
|
|
375
|
-
return true ? "
|
|
279
|
+
return true ? "prod" : "prod";
|
|
376
280
|
}
|
|
377
281
|
function channelBaseUrl(channel) {
|
|
378
282
|
return CHANNEL_BASE_URL[channel] ?? CHANNEL_BASE_URL.prod;
|
|
@@ -387,6 +291,7 @@ function channelBanner() {
|
|
|
387
291
|
// src/lib/global-opts.ts
|
|
388
292
|
var DEFAULT_BASE_URL = channelBaseUrl(currentChannel());
|
|
389
293
|
var API_BASE_ENV_VAR = "WPORT_API_BASE";
|
|
294
|
+
var CLI_SOURCE = "cli";
|
|
390
295
|
var DEFAULT_LOCALE = "zh-TW";
|
|
391
296
|
var DEFAULT_TIMEOUT_MS = 1e4;
|
|
392
297
|
function resolveContext(command) {
|
|
@@ -478,16 +383,18 @@ function registerJobsSearch(parent) {
|
|
|
478
383
|
const ctx = resolveContext(command);
|
|
479
384
|
const fields = resolveSearchFields(flags);
|
|
480
385
|
const query = buildQuery(flags);
|
|
481
|
-
const client = createApiClient({
|
|
386
|
+
const client = (0, import_core2.createApiClient)({
|
|
482
387
|
baseUrl: ctx.baseUrl,
|
|
483
388
|
locale: ctx.locale,
|
|
484
|
-
timeoutMs: ctx.timeoutMs
|
|
389
|
+
timeoutMs: ctx.timeoutMs,
|
|
390
|
+
userAgent: (0, import_core2.buildUserAgent)("wport-cli", "0.9.2"),
|
|
391
|
+
source: CLI_SOURCE
|
|
485
392
|
});
|
|
486
393
|
const { data, error, response } = await client.GET("/api/jobs/search", {
|
|
487
394
|
params: { query }
|
|
488
395
|
});
|
|
489
|
-
if (!response.ok) throwForHttpStatus(response.status, error);
|
|
490
|
-
const paged = asPaginatedBody(data);
|
|
396
|
+
if (!response.ok) (0, import_core2.throwForHttpStatus)(response.status, error);
|
|
397
|
+
const paged = (0, import_core2.asPaginatedBody)(data);
|
|
491
398
|
if (ctx.format === "json") {
|
|
492
399
|
const body = fields ? { ...paged, data: paged.data.map((item) => pickPaths(item, fields)) } : paged;
|
|
493
400
|
printJson(body);
|
|
@@ -564,21 +471,9 @@ function formatDate(s) {
|
|
|
564
471
|
return m ? m[1] : s;
|
|
565
472
|
}
|
|
566
473
|
|
|
567
|
-
// src/
|
|
568
|
-
|
|
569
|
-
|
|
570
|
-
let cursor = 0;
|
|
571
|
-
async function worker() {
|
|
572
|
-
for (; ; ) {
|
|
573
|
-
const index = cursor++;
|
|
574
|
-
if (index >= items.length) return;
|
|
575
|
-
results[index] = await fn(items[index], index);
|
|
576
|
-
}
|
|
577
|
-
}
|
|
578
|
-
const workerCount = Math.min(Math.max(1, limit), items.length);
|
|
579
|
-
await Promise.all(Array.from({ length: workerCount }, () => worker()));
|
|
580
|
-
return results;
|
|
581
|
-
}
|
|
474
|
+
// src/commands/jobs/view.ts
|
|
475
|
+
var import_core3 = require("@wport/core");
|
|
476
|
+
var import_core4 = require("@wport/core");
|
|
582
477
|
|
|
583
478
|
// src/lib/io-helpers.ts
|
|
584
479
|
var import_node_fs3 = require("fs");
|
|
@@ -733,10 +628,12 @@ function registerJobsView(parent) {
|
|
|
733
628
|
ExitCode.InvalidArgument
|
|
734
629
|
);
|
|
735
630
|
}
|
|
736
|
-
const client = createApiClient({
|
|
631
|
+
const client = (0, import_core3.createApiClient)({
|
|
737
632
|
baseUrl: ctx.baseUrl,
|
|
738
633
|
locale: ctx.locale,
|
|
739
|
-
timeoutMs: ctx.timeoutMs
|
|
634
|
+
timeoutMs: ctx.timeoutMs,
|
|
635
|
+
userAgent: (0, import_core3.buildUserAgent)("wport-cli", "0.9.2"),
|
|
636
|
+
source: CLI_SOURCE
|
|
740
637
|
});
|
|
741
638
|
if (flags.batch) {
|
|
742
639
|
await runBatchView(encIdArg, flags, client, ctx.timeoutMs);
|
|
@@ -749,8 +646,8 @@ function registerJobsView(parent) {
|
|
|
749
646
|
const { data, error, response } = await client.GET("/api/jobs/{encId}/view", {
|
|
750
647
|
params: { path: { encId } }
|
|
751
648
|
});
|
|
752
|
-
if (!response.ok) throwForHttpStatus(response.status, error);
|
|
753
|
-
const job = unwrapDataResponse(data);
|
|
649
|
+
if (!response.ok) (0, import_core3.throwForHttpStatus)(response.status, error);
|
|
650
|
+
const job = (0, import_core3.unwrapDataResponse)(data);
|
|
754
651
|
if (flags.fields) {
|
|
755
652
|
printJson(pickPaths(job, parseFieldsList(flags.fields)));
|
|
756
653
|
return;
|
|
@@ -788,11 +685,11 @@ async function fetchJob(client, encId) {
|
|
|
788
685
|
const { data, error, response } = await client.GET("/api/jobs/{encId}/view", {
|
|
789
686
|
params: { path: { encId } }
|
|
790
687
|
});
|
|
791
|
-
if (!response.ok) throwForHttpStatus(response.status, error);
|
|
792
|
-
return unwrapDataResponse(data);
|
|
688
|
+
if (!response.ok) (0, import_core3.throwForHttpStatus)(response.status, error);
|
|
689
|
+
return (0, import_core3.unwrapDataResponse)(data);
|
|
793
690
|
}
|
|
794
691
|
async function runBatch(encIds, concurrency, fetchOne, project) {
|
|
795
|
-
return mapWithConcurrency(encIds, concurrency, async (encId) => {
|
|
692
|
+
return (0, import_core4.mapWithConcurrency)(encIds, concurrency, async (encId) => {
|
|
796
693
|
try {
|
|
797
694
|
const job = await fetchOne(encId);
|
|
798
695
|
return { enc_id: encId, ok: true, data: project(job) };
|
|
@@ -989,6 +886,7 @@ function registerConfigCommand(program2) {
|
|
|
989
886
|
|
|
990
887
|
// src/commands/doctor.ts
|
|
991
888
|
var import_node_fs6 = require("fs");
|
|
889
|
+
var import_core7 = require("@wport/core");
|
|
992
890
|
|
|
993
891
|
// src/lib/credentials-store.ts
|
|
994
892
|
var import_node_fs5 = require("fs");
|
|
@@ -1165,24 +1063,9 @@ function ensureFormat(key, source) {
|
|
|
1165
1063
|
}
|
|
1166
1064
|
}
|
|
1167
1065
|
|
|
1168
|
-
// src/lib/personal-types.ts
|
|
1169
|
-
var PERSONAL_RESUMES_BASE = "/api/v1/personal/resumes";
|
|
1170
|
-
var PERSONAL_APPLICATIONS_BASE = "/api/v1/personal/applications";
|
|
1171
|
-
var OAUTH_BASE = "/api/oauth";
|
|
1172
|
-
var OAUTH_SESSIONS_BASE = `${OAUTH_BASE}/sessions`;
|
|
1173
|
-
var SECTION_WRITE_PLAN = {
|
|
1174
|
-
education: { kind: "per-item-post", path: "/education" },
|
|
1175
|
-
work_experience: { kind: "work-experience", path: "/work-experience" },
|
|
1176
|
-
certificate: { kind: "per-item-post", path: "/certificate" },
|
|
1177
|
-
language: { kind: "per-item-post", path: "/language" },
|
|
1178
|
-
professional_skills: { kind: "single-post", path: "/professional-skills" },
|
|
1179
|
-
autobiography: { kind: "single-post", path: "/autobiography" },
|
|
1180
|
-
job_condition: { kind: "single-post", path: "/job-condition" },
|
|
1181
|
-
portfolio_links: { kind: "bulk-put", path: "/portfolio-links" },
|
|
1182
|
-
background: { kind: "single-post", path: "/background" }
|
|
1183
|
-
};
|
|
1184
|
-
|
|
1185
1066
|
// src/lib/oauth.ts
|
|
1067
|
+
var import_core5 = require("@wport/core");
|
|
1068
|
+
var import_core6 = require("@wport/core");
|
|
1186
1069
|
var EXPIRED_MESSAGE = "The device code expired before authorization completed. Run `wport login` to try again.";
|
|
1187
1070
|
async function oauthPost(opts, path, body) {
|
|
1188
1071
|
const url = new URL(`${opts.baseUrl}${path}`);
|
|
@@ -1190,13 +1073,14 @@ async function oauthPost(opts, path, body) {
|
|
|
1190
1073
|
method: "POST",
|
|
1191
1074
|
headers: {
|
|
1192
1075
|
"Accept-Language": opts.locale,
|
|
1193
|
-
"User-Agent": buildUserAgent(),
|
|
1076
|
+
"User-Agent": (0, import_core5.buildUserAgent)("wport-cli", "0.9.2"),
|
|
1077
|
+
"X-Source": CLI_SOURCE,
|
|
1194
1078
|
Accept: "application/json",
|
|
1195
1079
|
"Content-Type": "application/json"
|
|
1196
1080
|
},
|
|
1197
1081
|
body: JSON.stringify(body)
|
|
1198
1082
|
});
|
|
1199
|
-
const res = await fetchWithTimeout(request, opts.timeoutMs);
|
|
1083
|
+
const res = await (0, import_core5.fetchWithTimeout)(request, opts.timeoutMs);
|
|
1200
1084
|
const respBody = await res.json().catch(() => null);
|
|
1201
1085
|
return { status: res.status, body: respBody };
|
|
1202
1086
|
}
|
|
@@ -1209,15 +1093,15 @@ function oauthErrorCode(body) {
|
|
|
1209
1093
|
async function requestDeviceCode(opts, deviceName) {
|
|
1210
1094
|
const body = {};
|
|
1211
1095
|
if (deviceName) body.device_name = deviceName;
|
|
1212
|
-
const { status, body: respBody } = await oauthPost(opts, `${OAUTH_BASE}/device/code`, body);
|
|
1213
|
-
if (status < 200 || status >= 300) throwForHttpStatus(status, respBody);
|
|
1096
|
+
const { status, body: respBody } = await oauthPost(opts, `${import_core6.OAUTH_BASE}/device/code`, body);
|
|
1097
|
+
if (status < 200 || status >= 300) (0, import_core5.throwForHttpStatus)(status, respBody);
|
|
1214
1098
|
return respBody;
|
|
1215
1099
|
}
|
|
1216
1100
|
async function pollForToken(opts, device, sleep = (ms) => new Promise((resolve) => setTimeout(resolve, ms))) {
|
|
1217
1101
|
let intervalSec = device.interval;
|
|
1218
1102
|
const deadline = Date.now() + device.expires_in * 1e3;
|
|
1219
1103
|
for (; ; ) {
|
|
1220
|
-
const { status, body } = await oauthPost(opts, `${OAUTH_BASE}/token`, {
|
|
1104
|
+
const { status, body } = await oauthPost(opts, `${import_core6.OAUTH_BASE}/token`, {
|
|
1221
1105
|
grant_type: "urn:ietf:params:oauth:grant-type:device_code",
|
|
1222
1106
|
device_code: device.device_code
|
|
1223
1107
|
});
|
|
@@ -1230,14 +1114,14 @@ async function pollForToken(opts, device, sleep = (ms) => new Promise((resolve)
|
|
|
1230
1114
|
} else if (code === "expired_token") {
|
|
1231
1115
|
throw new CliError(EXPIRED_MESSAGE, ExitCode.ServerClientError);
|
|
1232
1116
|
} else if (code !== "authorization_pending") {
|
|
1233
|
-
throwForHttpStatus(status, body);
|
|
1117
|
+
(0, import_core5.throwForHttpStatus)(status, body);
|
|
1234
1118
|
}
|
|
1235
1119
|
if (Date.now() >= deadline) throw new CliError(EXPIRED_MESSAGE, ExitCode.ServerClientError);
|
|
1236
1120
|
await sleep(intervalSec * 1e3);
|
|
1237
1121
|
}
|
|
1238
1122
|
}
|
|
1239
1123
|
async function refreshAccessToken(opts, refreshToken) {
|
|
1240
|
-
const { status, body } = await oauthPost(opts, `${OAUTH_BASE}/token`, {
|
|
1124
|
+
const { status, body } = await oauthPost(opts, `${import_core6.OAUTH_BASE}/token`, {
|
|
1241
1125
|
grant_type: "refresh_token",
|
|
1242
1126
|
refresh_token: refreshToken
|
|
1243
1127
|
});
|
|
@@ -1245,11 +1129,11 @@ async function refreshAccessToken(opts, refreshToken) {
|
|
|
1245
1129
|
if (oauthErrorCode(body) === "invalid_grant") {
|
|
1246
1130
|
throw new CliError("Your session is no longer valid. Run `wport login` to sign in again.", ExitCode.ServerClientError);
|
|
1247
1131
|
}
|
|
1248
|
-
throwForHttpStatus(status, body);
|
|
1132
|
+
(0, import_core5.throwForHttpStatus)(status, body);
|
|
1249
1133
|
}
|
|
1250
1134
|
async function revokeRefreshToken(opts, refreshToken) {
|
|
1251
|
-
const { status, body } = await oauthPost(opts, `${OAUTH_BASE}/revoke`, { token: refreshToken });
|
|
1252
|
-
if (status < 200 || status >= 300) throwForHttpStatus(status, body);
|
|
1135
|
+
const { status, body } = await oauthPost(opts, `${import_core6.OAUTH_BASE}/revoke`, { token: refreshToken });
|
|
1136
|
+
if (status < 200 || status >= 300) (0, import_core5.throwForHttpStatus)(status, body);
|
|
1253
1137
|
}
|
|
1254
1138
|
|
|
1255
1139
|
// src/commands/doctor.ts
|
|
@@ -1272,7 +1156,7 @@ function registerDoctorCommand(program2) {
|
|
|
1272
1156
|
}
|
|
1273
1157
|
async function runDoctor(ctx) {
|
|
1274
1158
|
const line = (s = "") => process.stdout.write(s + "\n");
|
|
1275
|
-
line(`wport-cli ${"0.9.
|
|
1159
|
+
line(`wport-cli ${"0.9.2"}`);
|
|
1276
1160
|
line(` bundled schema fingerprint: ${"839e8a891dfb"}`);
|
|
1277
1161
|
line("");
|
|
1278
1162
|
line("Resolved configuration:");
|
|
@@ -1328,7 +1212,13 @@ function describePersonalLoginLines() {
|
|
|
1328
1212
|
}
|
|
1329
1213
|
async function probeServer(ctx, line) {
|
|
1330
1214
|
try {
|
|
1331
|
-
const client =
|
|
1215
|
+
const client = (0, import_core7.createApiClient)({
|
|
1216
|
+
baseUrl: ctx.baseUrl,
|
|
1217
|
+
locale: ctx.locale,
|
|
1218
|
+
timeoutMs: ctx.timeoutMs,
|
|
1219
|
+
userAgent: (0, import_core7.buildUserAgent)("wport-cli", "0.9.2"),
|
|
1220
|
+
source: CLI_SOURCE
|
|
1221
|
+
});
|
|
1332
1222
|
const { response } = await client.GET("/api/jobs/search", { params: { query: { pageSize: 1 } } });
|
|
1333
1223
|
if (response.ok) {
|
|
1334
1224
|
line(` \u2713 reachable (HTTP ${response.status})`);
|
|
@@ -1353,81 +1243,39 @@ async function probeAuthServer(ctx, line) {
|
|
|
1353
1243
|
}
|
|
1354
1244
|
|
|
1355
1245
|
// src/lib/enterprise-client.ts
|
|
1356
|
-
var
|
|
1357
|
-
|
|
1358
|
-
|
|
1359
|
-
|
|
1360
|
-
|
|
1361
|
-
|
|
1362
|
-
|
|
1363
|
-
|
|
1364
|
-
|
|
1365
|
-
|
|
1366
|
-
"User-Agent": buildUserAgent(),
|
|
1367
|
-
Accept: "application/json"
|
|
1368
|
-
}
|
|
1369
|
-
});
|
|
1370
|
-
const res = await fetchWithTimeout(request, opts.timeoutMs);
|
|
1371
|
-
const body = await res.json().catch(() => null);
|
|
1372
|
-
if (!res.ok) throwEnterpriseHttpError(res.status, body);
|
|
1373
|
-
warnIfRateLimitLow(res.headers);
|
|
1374
|
-
return { body, headers: res.headers };
|
|
1375
|
-
}
|
|
1376
|
-
async function enterpriseWrite(method, opts, path, body, extra) {
|
|
1377
|
-
const url = new URL(`${opts.baseUrl}${ENTERPRISE_PREFIX}${path}`);
|
|
1378
|
-
const headers = {
|
|
1379
|
-
Authorization: `Bearer ${opts.apiKey}`,
|
|
1380
|
-
"Accept-Language": opts.locale,
|
|
1381
|
-
"User-Agent": buildUserAgent(),
|
|
1382
|
-
Accept: "application/json"
|
|
1383
|
-
};
|
|
1384
|
-
if (body !== void 0) headers["Content-Type"] = "application/json";
|
|
1385
|
-
if (extra?.idempotencyKey) headers["Idempotency-Key"] = extra.idempotencyKey;
|
|
1386
|
-
if (extra?.ifMatch) headers["If-Match"] = extra.ifMatch;
|
|
1387
|
-
const request = new Request(url, {
|
|
1388
|
-
method,
|
|
1389
|
-
headers,
|
|
1390
|
-
body: body !== void 0 ? JSON.stringify(body) : void 0
|
|
1391
|
-
});
|
|
1392
|
-
const res = await fetchWithTimeout(request, opts.timeoutMs);
|
|
1393
|
-
const respBody = await res.json().catch(() => null);
|
|
1394
|
-
if (!res.ok) throwEnterpriseHttpError(res.status, respBody);
|
|
1395
|
-
warnIfRateLimitLow(res.headers);
|
|
1396
|
-
return { body: respBody, headers: res.headers };
|
|
1397
|
-
}
|
|
1398
|
-
function enterprisePost(opts, path, body, extra) {
|
|
1399
|
-
return enterpriseWrite("POST", opts, path, body, extra);
|
|
1400
|
-
}
|
|
1401
|
-
function enterprisePatch(opts, path, body, extra) {
|
|
1402
|
-
return enterpriseWrite("PATCH", opts, path, body, extra);
|
|
1403
|
-
}
|
|
1404
|
-
function enterpriseDelete(opts, path, extra) {
|
|
1405
|
-
return enterpriseWrite("DELETE", opts, path, void 0, extra);
|
|
1406
|
-
}
|
|
1407
|
-
function throwEnterpriseHttpError(status, body) {
|
|
1408
|
-
const base = extractErrorMessage(body) ?? `HTTP ${status}`;
|
|
1409
|
-
if (status === 401) {
|
|
1410
|
-
throw new CliError(
|
|
1246
|
+
var import_core8 = require("@wport/core");
|
|
1247
|
+
var transport = __toESM(require("@wport/core"));
|
|
1248
|
+
function withUserAgent(opts) {
|
|
1249
|
+
return { ...opts, userAgent: (0, import_core8.buildUserAgent)("wport-cli", "0.9.2"), source: CLI_SOURCE };
|
|
1250
|
+
}
|
|
1251
|
+
function decorateEnterpriseError(err) {
|
|
1252
|
+
if (!(err instanceof import_core8.WportHttpError)) return err;
|
|
1253
|
+
const base = err.message;
|
|
1254
|
+
if (err.status === 401) {
|
|
1255
|
+
return new import_core8.WportHttpError(
|
|
1411
1256
|
`${base} \u2014 If your key has expired, rotate it in place: \`wport enterprise keys rotate <enc_id>\` (an expired key is still accepted for rotate). If it was revoked or is incorrect, obtain a valid key and run \`wport enterprise login\`.`,
|
|
1412
|
-
|
|
1257
|
+
err.status,
|
|
1258
|
+
err.body
|
|
1413
1259
|
);
|
|
1414
1260
|
}
|
|
1415
|
-
if (status === 403) {
|
|
1416
|
-
|
|
1261
|
+
if (err.status === 403) {
|
|
1262
|
+
return new import_core8.WportHttpError(
|
|
1417
1263
|
`${base} \u2014 Your key may lack the required scope; rotate or issue a key that includes it. If your company account has been suspended, please contact support.`,
|
|
1418
|
-
|
|
1264
|
+
err.status,
|
|
1265
|
+
err.body
|
|
1419
1266
|
);
|
|
1420
1267
|
}
|
|
1421
|
-
if (status === 400) {
|
|
1422
|
-
const missingFields = extractMissingFields(body);
|
|
1268
|
+
if (err.status === 400) {
|
|
1269
|
+
const missingFields = extractMissingFields(err.body);
|
|
1423
1270
|
if (missingFields.length > 0) {
|
|
1424
|
-
|
|
1271
|
+
return new import_core8.WportHttpError(
|
|
1425
1272
|
`${base} \u2014 Missing required fields: ${missingFields.join(", ")}. Fill them via \`wport enterprise jobs update <enc_id> ...\` (or the web console), then publish.`,
|
|
1426
|
-
|
|
1273
|
+
err.status,
|
|
1274
|
+
err.body
|
|
1427
1275
|
);
|
|
1428
1276
|
}
|
|
1429
1277
|
}
|
|
1430
|
-
|
|
1278
|
+
return err;
|
|
1431
1279
|
}
|
|
1432
1280
|
function extractMissingFields(body) {
|
|
1433
1281
|
if (!body || typeof body !== "object") return [];
|
|
@@ -1444,6 +1292,28 @@ function warnIfRateLimitLow(headers) {
|
|
|
1444
1292
|
printWarn(`Rate limit nearly exhausted: ${remaining}/${limit} requests remaining this window.`, false);
|
|
1445
1293
|
}
|
|
1446
1294
|
}
|
|
1295
|
+
async function wrap(p) {
|
|
1296
|
+
let res;
|
|
1297
|
+
try {
|
|
1298
|
+
res = await p;
|
|
1299
|
+
} catch (err) {
|
|
1300
|
+
throw decorateEnterpriseError(err);
|
|
1301
|
+
}
|
|
1302
|
+
warnIfRateLimitLow(res.headers);
|
|
1303
|
+
return res;
|
|
1304
|
+
}
|
|
1305
|
+
function enterpriseGet2(opts, path, query) {
|
|
1306
|
+
return wrap(transport.enterpriseGet(withUserAgent(opts), path, query));
|
|
1307
|
+
}
|
|
1308
|
+
function enterprisePost2(opts, path, body, extra) {
|
|
1309
|
+
return wrap(transport.enterprisePost(withUserAgent(opts), path, body, extra));
|
|
1310
|
+
}
|
|
1311
|
+
function enterprisePatch2(opts, path, body, extra) {
|
|
1312
|
+
return wrap(transport.enterprisePatch(withUserAgent(opts), path, body, extra));
|
|
1313
|
+
}
|
|
1314
|
+
function enterpriseDelete2(opts, path, extra) {
|
|
1315
|
+
return wrap(transport.enterpriseDelete(withUserAgent(opts), path, extra));
|
|
1316
|
+
}
|
|
1447
1317
|
|
|
1448
1318
|
// src/commands/enterprise/login.ts
|
|
1449
1319
|
async function performLogin(ctx, key) {
|
|
@@ -1455,7 +1325,7 @@ async function performLogin(ctx, key) {
|
|
|
1455
1325
|
ExitCode.InvalidArgument
|
|
1456
1326
|
);
|
|
1457
1327
|
}
|
|
1458
|
-
const { body } = await
|
|
1328
|
+
const { body } = await enterpriseGet2({ ...ctx, apiKey: key }, "/me");
|
|
1459
1329
|
saveCredentials({
|
|
1460
1330
|
api_key: key,
|
|
1461
1331
|
company_name: extractCompanyName(body),
|
|
@@ -1520,15 +1390,16 @@ function registerEnterpriseWhoami(parent) {
|
|
|
1520
1390
|
}
|
|
1521
1391
|
|
|
1522
1392
|
// src/commands/enterprise/usage.ts
|
|
1393
|
+
var import_core9 = require("@wport/core");
|
|
1523
1394
|
function num(value) {
|
|
1524
1395
|
return typeof value === "number" && Number.isFinite(value) ? String(value) : "\u2014";
|
|
1525
1396
|
}
|
|
1526
1397
|
async function runUsage(ctx, apiKey) {
|
|
1527
|
-
const { body } = await
|
|
1398
|
+
const { body } = await enterpriseGet2(
|
|
1528
1399
|
{ baseUrl: ctx.baseUrl, locale: ctx.locale, timeoutMs: ctx.timeoutMs, apiKey },
|
|
1529
1400
|
"/usage"
|
|
1530
1401
|
);
|
|
1531
|
-
const usage = unwrapDataResponse(body);
|
|
1402
|
+
const usage = (0, import_core9.unwrapDataResponse)(body);
|
|
1532
1403
|
if (ctx.format === "json") {
|
|
1533
1404
|
printJson(usage);
|
|
1534
1405
|
return;
|
|
@@ -1555,6 +1426,7 @@ function registerEnterpriseUsage(parent) {
|
|
|
1555
1426
|
}
|
|
1556
1427
|
|
|
1557
1428
|
// src/commands/enterprise/jobs/list.ts
|
|
1429
|
+
var import_core10 = require("@wport/core");
|
|
1558
1430
|
var STATUS_MAP = { published: 1, unpublished: 0 };
|
|
1559
1431
|
var MINIMAL_LIST_FIELDS = ["enc_id", "job_title", "status", "updated_at"];
|
|
1560
1432
|
function mapStatusFlag(raw) {
|
|
@@ -1580,7 +1452,7 @@ async function runEnterpriseJobsList(ctx, apiKey, flags) {
|
|
|
1580
1452
|
if (flags.fields && flags.minimal) {
|
|
1581
1453
|
throw new CliError("Use either --fields or --minimal, not both", ExitCode.InvalidArgument);
|
|
1582
1454
|
}
|
|
1583
|
-
const { body } = await
|
|
1455
|
+
const { body } = await enterpriseGet2(
|
|
1584
1456
|
{ baseUrl: ctx.baseUrl, locale: ctx.locale, timeoutMs: ctx.timeoutMs, apiKey },
|
|
1585
1457
|
"/jobs",
|
|
1586
1458
|
{
|
|
@@ -1590,7 +1462,7 @@ async function runEnterpriseJobsList(ctx, apiKey, flags) {
|
|
|
1590
1462
|
status: mapStatusFlag(flags.status)
|
|
1591
1463
|
}
|
|
1592
1464
|
);
|
|
1593
|
-
const paged = asPaginatedBody(body);
|
|
1465
|
+
const paged = (0, import_core10.asPaginatedBody)(body);
|
|
1594
1466
|
const projection = flags.minimal ? MINIMAL_LIST_FIELDS : flags.fields ? parseFieldsList(flags.fields) : void 0;
|
|
1595
1467
|
if (projection || ctx.format === "json") {
|
|
1596
1468
|
printJson(projection ? { ...paged, data: paged.data.map((row) => pickPaths(row, projection)) } : paged);
|
|
@@ -1622,6 +1494,7 @@ function registerEnterpriseJobsList(parent) {
|
|
|
1622
1494
|
}
|
|
1623
1495
|
|
|
1624
1496
|
// src/commands/enterprise/jobs/view.ts
|
|
1497
|
+
var import_core11 = require("@wport/core");
|
|
1625
1498
|
var DETAIL_FIELDS = ["enc_id", "job_title", "code", "status", "created_at", "updated_at"];
|
|
1626
1499
|
function renderDetailLines(job) {
|
|
1627
1500
|
const pad = Math.max(...DETAIL_FIELDS.map((f) => f.length)) + 1;
|
|
@@ -1642,11 +1515,11 @@ function registerEnterpriseJobsView(parent) {
|
|
|
1642
1515
|
}
|
|
1643
1516
|
const globals = command.optsWithGlobals();
|
|
1644
1517
|
const { key } = resolveApiKey(globals.apiKey);
|
|
1645
|
-
const { body } = await
|
|
1518
|
+
const { body } = await enterpriseGet2(
|
|
1646
1519
|
{ baseUrl: ctx.baseUrl, locale: ctx.locale, timeoutMs: ctx.timeoutMs, apiKey: key },
|
|
1647
1520
|
`/jobs/${encodeURIComponent(encId.trim())}`
|
|
1648
1521
|
);
|
|
1649
|
-
const job = unwrapDataResponse(body);
|
|
1522
|
+
const job = (0, import_core11.unwrapDataResponse)(body);
|
|
1650
1523
|
if (flags.fields) {
|
|
1651
1524
|
printJson(pickPaths(job, parseFieldsList(flags.fields)));
|
|
1652
1525
|
return;
|
|
@@ -1661,15 +1534,16 @@ function registerEnterpriseJobsView(parent) {
|
|
|
1661
1534
|
|
|
1662
1535
|
// src/commands/enterprise/jobs/create.ts
|
|
1663
1536
|
var import_node_crypto = require("crypto");
|
|
1537
|
+
var import_core12 = require("@wport/core");
|
|
1664
1538
|
async function runJobsCreate(ctx, apiKey, source, idempotencyKey) {
|
|
1665
1539
|
const jobBody = readJsonObject(source, { timeoutMs: ctx.timeoutMs });
|
|
1666
|
-
const { body } = await
|
|
1540
|
+
const { body } = await enterprisePost2(
|
|
1667
1541
|
{ baseUrl: ctx.baseUrl, locale: ctx.locale, timeoutMs: ctx.timeoutMs, apiKey },
|
|
1668
1542
|
"/jobs",
|
|
1669
1543
|
jobBody,
|
|
1670
1544
|
{ idempotencyKey }
|
|
1671
1545
|
);
|
|
1672
|
-
const created = unwrapDataResponse(body);
|
|
1546
|
+
const created = (0, import_core12.unwrapDataResponse)(body);
|
|
1673
1547
|
if (ctx.format === "json") {
|
|
1674
1548
|
printJson(created);
|
|
1675
1549
|
return;
|
|
@@ -1688,6 +1562,7 @@ function registerEnterpriseJobsCreate(parent) {
|
|
|
1688
1562
|
|
|
1689
1563
|
// src/commands/enterprise/jobs/update.ts
|
|
1690
1564
|
var import_node_crypto2 = require("crypto");
|
|
1565
|
+
var import_core13 = require("@wport/core");
|
|
1691
1566
|
|
|
1692
1567
|
// src/commands/enterprise/jobs/write-shared.ts
|
|
1693
1568
|
function requireEncId(encId) {
|
|
@@ -1700,13 +1575,13 @@ function requireEncId(encId) {
|
|
|
1700
1575
|
async function runJobsUpdate(ctx, apiKey, encId, source, idempotencyKey, ifMatch) {
|
|
1701
1576
|
const trimmed = requireEncId(encId);
|
|
1702
1577
|
const jobBody = readJsonObject(source, { timeoutMs: ctx.timeoutMs });
|
|
1703
|
-
const { body } = await
|
|
1578
|
+
const { body } = await enterprisePatch2(
|
|
1704
1579
|
{ baseUrl: ctx.baseUrl, locale: ctx.locale, timeoutMs: ctx.timeoutMs, apiKey },
|
|
1705
1580
|
`/jobs/${encodeURIComponent(trimmed)}`,
|
|
1706
1581
|
jobBody,
|
|
1707
1582
|
{ idempotencyKey, ifMatch }
|
|
1708
1583
|
);
|
|
1709
|
-
const updated = unwrapDataResponse(body);
|
|
1584
|
+
const updated = (0, import_core13.unwrapDataResponse)(body);
|
|
1710
1585
|
if (ctx.format === "json") {
|
|
1711
1586
|
printJson(updated);
|
|
1712
1587
|
return;
|
|
@@ -1725,15 +1600,16 @@ function registerEnterpriseJobsUpdate(parent) {
|
|
|
1725
1600
|
|
|
1726
1601
|
// src/commands/enterprise/jobs/lifecycle.ts
|
|
1727
1602
|
var import_node_crypto3 = require("crypto");
|
|
1603
|
+
var import_core14 = require("@wport/core");
|
|
1728
1604
|
async function runJobsTransition(ctx, apiKey, encId, action, idempotencyKey) {
|
|
1729
1605
|
const trimmed = requireEncId(encId);
|
|
1730
|
-
const { body } = await
|
|
1606
|
+
const { body } = await enterprisePatch2(
|
|
1731
1607
|
{ baseUrl: ctx.baseUrl, locale: ctx.locale, timeoutMs: ctx.timeoutMs, apiKey },
|
|
1732
1608
|
`/jobs/${encodeURIComponent(trimmed)}/${action}`,
|
|
1733
1609
|
{},
|
|
1734
1610
|
{ idempotencyKey }
|
|
1735
1611
|
);
|
|
1736
|
-
const result = unwrapDataResponse(body);
|
|
1612
|
+
const result = (0, import_core14.unwrapDataResponse)(body);
|
|
1737
1613
|
if (ctx.format === "json") {
|
|
1738
1614
|
printJson(result);
|
|
1739
1615
|
return;
|
|
@@ -1747,7 +1623,7 @@ async function runJobsDelete(ctx, apiKey, encId, confirm, idempotencyKey) {
|
|
|
1747
1623
|
throw new CliError("Refusing to delete without --confirm (destructive, irreversible)", ExitCode.InvalidArgument);
|
|
1748
1624
|
}
|
|
1749
1625
|
const trimmed = requireEncId(encId);
|
|
1750
|
-
await
|
|
1626
|
+
await enterpriseDelete2(
|
|
1751
1627
|
{ baseUrl: ctx.baseUrl, locale: ctx.locale, timeoutMs: ctx.timeoutMs, apiKey },
|
|
1752
1628
|
`/jobs/${encodeURIComponent(trimmed)}`,
|
|
1753
1629
|
{ idempotencyKey }
|
|
@@ -1761,13 +1637,13 @@ async function runJobsDelete(ctx, apiKey, encId, confirm, idempotencyKey) {
|
|
|
1761
1637
|
}
|
|
1762
1638
|
async function runJobsCopy(ctx, apiKey, encId, idempotencyKey) {
|
|
1763
1639
|
const trimmed = requireEncId(encId);
|
|
1764
|
-
const { body } = await
|
|
1640
|
+
const { body } = await enterprisePost2(
|
|
1765
1641
|
{ baseUrl: ctx.baseUrl, locale: ctx.locale, timeoutMs: ctx.timeoutMs, apiKey },
|
|
1766
1642
|
`/jobs/${encodeURIComponent(trimmed)}/copy`,
|
|
1767
1643
|
{},
|
|
1768
1644
|
{ idempotencyKey }
|
|
1769
1645
|
);
|
|
1770
|
-
const result = unwrapDataResponse(body);
|
|
1646
|
+
const result = (0, import_core14.unwrapDataResponse)(body);
|
|
1771
1647
|
if (ctx.format === "json") {
|
|
1772
1648
|
printJson(result);
|
|
1773
1649
|
return;
|
|
@@ -1821,6 +1697,7 @@ function registerEnterpriseJobsDelete(parent) {
|
|
|
1821
1697
|
|
|
1822
1698
|
// src/commands/enterprise/jobs/batch.ts
|
|
1823
1699
|
var import_node_crypto4 = require("crypto");
|
|
1700
|
+
var import_core15 = require("@wport/core");
|
|
1824
1701
|
var BATCH_MIN = 1;
|
|
1825
1702
|
var BATCH_MAX = 10;
|
|
1826
1703
|
async function runJobsBatch(ctx, apiKey, source, confirm, idempotencyKey) {
|
|
@@ -1835,13 +1712,13 @@ async function runJobsBatch(ctx, apiKey, source, confirm, idempotencyKey) {
|
|
|
1835
1712
|
ExitCode.InvalidArgument
|
|
1836
1713
|
);
|
|
1837
1714
|
}
|
|
1838
|
-
const { body } = await
|
|
1715
|
+
const { body } = await enterprisePost2(
|
|
1839
1716
|
{ baseUrl: ctx.baseUrl, locale: ctx.locale, timeoutMs: ctx.timeoutMs, apiKey },
|
|
1840
1717
|
"/jobs/batch",
|
|
1841
1718
|
payload,
|
|
1842
1719
|
{ idempotencyKey }
|
|
1843
1720
|
);
|
|
1844
|
-
const result = unwrapDataResponse(body);
|
|
1721
|
+
const result = (0, import_core15.unwrapDataResponse)(body);
|
|
1845
1722
|
const succeeded = result.succeeded ?? [];
|
|
1846
1723
|
const failed = result.failed ?? [];
|
|
1847
1724
|
if (ctx.format === "json") {
|
|
@@ -1884,6 +1761,7 @@ function registerEnterpriseJobsCommand(parent) {
|
|
|
1884
1761
|
}
|
|
1885
1762
|
|
|
1886
1763
|
// src/commands/enterprise/keys/list.ts
|
|
1764
|
+
var import_core16 = require("@wport/core");
|
|
1887
1765
|
function formatDate3(value) {
|
|
1888
1766
|
return value ? String(value).slice(0, 10) : "";
|
|
1889
1767
|
}
|
|
@@ -1891,11 +1769,11 @@ function formatScopes(scopes) {
|
|
|
1891
1769
|
return Array.isArray(scopes) ? scopes.join(",") : "";
|
|
1892
1770
|
}
|
|
1893
1771
|
async function runKeysList(ctx, apiKey) {
|
|
1894
|
-
const { body } = await
|
|
1772
|
+
const { body } = await enterpriseGet2(
|
|
1895
1773
|
{ baseUrl: ctx.baseUrl, locale: ctx.locale, timeoutMs: ctx.timeoutMs, apiKey },
|
|
1896
1774
|
"/keys"
|
|
1897
1775
|
);
|
|
1898
|
-
const keys = unwrapDataArray(body);
|
|
1776
|
+
const keys = (0, import_core16.unwrapDataArray)(body);
|
|
1899
1777
|
if (ctx.format === "json") {
|
|
1900
1778
|
printJson(keys);
|
|
1901
1779
|
return;
|
|
@@ -1926,6 +1804,7 @@ function registerEnterpriseKeysList(parent) {
|
|
|
1926
1804
|
}
|
|
1927
1805
|
|
|
1928
1806
|
// src/commands/enterprise/keys/rotate.ts
|
|
1807
|
+
var import_core17 = require("@wport/core");
|
|
1929
1808
|
var ENTERPRISE_KEY_EXPIRY_DAYS = [30, 60, 90];
|
|
1930
1809
|
function validateExpiryDays(raw) {
|
|
1931
1810
|
if (raw === void 0) return void 0;
|
|
@@ -1943,12 +1822,12 @@ async function runKeysRotate(ctx, apiKey, encId, flags) {
|
|
|
1943
1822
|
const expiryDays = validateExpiryDays(flags.expiryDays);
|
|
1944
1823
|
const requestBody = {};
|
|
1945
1824
|
if (expiryDays !== void 0) requestBody.expiry_days = expiryDays;
|
|
1946
|
-
const { body } = await
|
|
1825
|
+
const { body } = await enterprisePost2(
|
|
1947
1826
|
{ baseUrl: ctx.baseUrl, locale: ctx.locale, timeoutMs: ctx.timeoutMs, apiKey },
|
|
1948
1827
|
`/keys/${encodeURIComponent(trimmed)}/rotate`,
|
|
1949
1828
|
requestBody
|
|
1950
1829
|
);
|
|
1951
|
-
const issued = unwrapDataResponse(body);
|
|
1830
|
+
const issued = (0, import_core17.unwrapDataResponse)(body);
|
|
1952
1831
|
if (ctx.format === "json") {
|
|
1953
1832
|
printJson(issued);
|
|
1954
1833
|
} else {
|
|
@@ -1987,6 +1866,7 @@ function registerEnterpriseKeysCommand(parent) {
|
|
|
1987
1866
|
}
|
|
1988
1867
|
|
|
1989
1868
|
// src/commands/enterprise/company/view.ts
|
|
1869
|
+
var import_core18 = require("@wport/core");
|
|
1990
1870
|
var COMPANY_STATUS_LABELS = {
|
|
1991
1871
|
0: "not_submitted",
|
|
1992
1872
|
1: "pending_review",
|
|
@@ -2042,11 +1922,11 @@ function renderDetailLines2(company) {
|
|
|
2042
1922
|
return lines;
|
|
2043
1923
|
}
|
|
2044
1924
|
async function runCompanyView(ctx, apiKey, flags) {
|
|
2045
|
-
const { body } = await
|
|
1925
|
+
const { body } = await enterpriseGet2(
|
|
2046
1926
|
{ baseUrl: ctx.baseUrl, locale: ctx.locale, timeoutMs: ctx.timeoutMs, apiKey },
|
|
2047
1927
|
"/company"
|
|
2048
1928
|
);
|
|
2049
|
-
const company = unwrapDataResponse(body);
|
|
1929
|
+
const company = (0, import_core18.unwrapDataResponse)(body);
|
|
2050
1930
|
if (flags.fields) {
|
|
2051
1931
|
printJson(pickPaths(company, parseFieldsList(flags.fields)));
|
|
2052
1932
|
return;
|
|
@@ -2068,6 +1948,7 @@ function registerEnterpriseCompanyView(parent) {
|
|
|
2068
1948
|
|
|
2069
1949
|
// src/commands/enterprise/company/update.ts
|
|
2070
1950
|
var import_node_crypto5 = require("crypto");
|
|
1951
|
+
var import_core19 = require("@wport/core");
|
|
2071
1952
|
|
|
2072
1953
|
// src/commands/enterprise/company/types.ts
|
|
2073
1954
|
var BASIC_FIELDS = [
|
|
@@ -2133,11 +2014,11 @@ async function buildCompanyUpdatePayloads(input, ctx, apiKey) {
|
|
|
2133
2014
|
if (!inputHasBasicField && !inputHasDescriptionField) {
|
|
2134
2015
|
throw new InvalidArgumentError("No writable company fields provided");
|
|
2135
2016
|
}
|
|
2136
|
-
const { body } = await
|
|
2017
|
+
const { body } = await enterpriseGet2(
|
|
2137
2018
|
{ baseUrl: ctx.baseUrl, locale: ctx.locale, timeoutMs: ctx.timeoutMs, apiKey },
|
|
2138
2019
|
"/company"
|
|
2139
2020
|
);
|
|
2140
|
-
const current = unwrapDataResponse(body);
|
|
2021
|
+
const current = (0, import_core19.unwrapDataResponse)(body);
|
|
2141
2022
|
const missingContractFields = CONTRACT_REQUIRED_GET_FIELDS.filter((f) => !(f in current));
|
|
2142
2023
|
if (missingContractFields.length > 0) {
|
|
2143
2024
|
throw new CliError(
|
|
@@ -2204,23 +2085,23 @@ async function runCompanyUpdate(ctx, apiKey, source, idempotencyFlags, options =
|
|
|
2204
2085
|
const requestOpts = { baseUrl: ctx.baseUrl, locale: ctx.locale, timeoutMs: ctx.timeoutMs, apiKey };
|
|
2205
2086
|
let basicResultCompany;
|
|
2206
2087
|
if (needsBasic) {
|
|
2207
|
-
const { body } = await
|
|
2088
|
+
const { body } = await enterprisePatch2(requestOpts, "/company/basic", payloads.basic, {
|
|
2208
2089
|
idempotencyKey: basicKey
|
|
2209
2090
|
});
|
|
2210
|
-
basicResultCompany = unwrapDataResponse(body);
|
|
2091
|
+
basicResultCompany = (0, import_core19.unwrapDataResponse)(body);
|
|
2211
2092
|
}
|
|
2212
2093
|
if (!needsDescriptions) {
|
|
2213
2094
|
printCompanyResult(basicResultCompany, ctx.format);
|
|
2214
2095
|
return;
|
|
2215
2096
|
}
|
|
2216
2097
|
try {
|
|
2217
|
-
const { body } = await
|
|
2098
|
+
const { body } = await enterprisePatch2(
|
|
2218
2099
|
requestOpts,
|
|
2219
2100
|
"/company/descriptions",
|
|
2220
2101
|
payloads.descriptions,
|
|
2221
2102
|
{ idempotencyKey: descriptionsKey }
|
|
2222
2103
|
);
|
|
2223
|
-
const result = unwrapDataResponse(body);
|
|
2104
|
+
const result = (0, import_core19.unwrapDataResponse)(body);
|
|
2224
2105
|
printCompanyResult(result.company, ctx.format);
|
|
2225
2106
|
} catch (err) {
|
|
2226
2107
|
if (!needsBasic) {
|
|
@@ -2279,6 +2160,7 @@ function registerEnterpriseCompanyUpdate(parent) {
|
|
|
2279
2160
|
var import_node_crypto6 = require("crypto");
|
|
2280
2161
|
var import_node_fs7 = require("fs");
|
|
2281
2162
|
var import_node_path3 = require("path");
|
|
2163
|
+
var import_core20 = require("@wport/core");
|
|
2282
2164
|
var EXTENSION_TO_CONTENT_TYPE = {
|
|
2283
2165
|
".png": "image/png",
|
|
2284
2166
|
".jpg": "image/jpeg",
|
|
@@ -2330,29 +2212,29 @@ async function runCompanyLogoUpload(ctx, apiKey, path, idempotencyFlags) {
|
|
|
2330
2212
|
const { contentType, fileSize, bytes } = inspectLocalFile(path);
|
|
2331
2213
|
const { presignKey, confirmKey } = resolveLogoIdempotencyKeys(idempotencyFlags);
|
|
2332
2214
|
const requestOpts = { baseUrl: ctx.baseUrl, locale: ctx.locale, timeoutMs: ctx.timeoutMs, apiKey };
|
|
2333
|
-
const { body: presignBody } = await
|
|
2215
|
+
const { body: presignBody } = await enterprisePost2(
|
|
2334
2216
|
requestOpts,
|
|
2335
2217
|
"/company/logo/presign",
|
|
2336
2218
|
{ content_type: contentType, file_size: fileSize },
|
|
2337
2219
|
{ idempotencyKey: presignKey }
|
|
2338
2220
|
);
|
|
2339
|
-
const presign = unwrapDataResponse(presignBody);
|
|
2221
|
+
const presign = (0, import_core20.unwrapDataResponse)(presignBody);
|
|
2340
2222
|
const putRequest = new Request(presign.upload_url, {
|
|
2341
2223
|
method: "PUT",
|
|
2342
2224
|
headers: { "Content-Type": contentType },
|
|
2343
2225
|
body: bytes
|
|
2344
2226
|
});
|
|
2345
|
-
const putResponse = await fetchWithTimeout(putRequest, ctx.timeoutMs);
|
|
2227
|
+
const putResponse = await (0, import_core20.fetchWithTimeout)(putRequest, ctx.timeoutMs);
|
|
2346
2228
|
if (!putResponse.ok) {
|
|
2347
2229
|
throw new NetworkError(`Failed to upload file to S3: HTTP ${putResponse.status}`);
|
|
2348
2230
|
}
|
|
2349
|
-
const { body: confirmBody } = await
|
|
2231
|
+
const { body: confirmBody } = await enterprisePost2(
|
|
2350
2232
|
requestOpts,
|
|
2351
2233
|
"/company/logo/confirm",
|
|
2352
2234
|
{ s3_key: presign.s3_key },
|
|
2353
2235
|
{ idempotencyKey: confirmKey }
|
|
2354
2236
|
);
|
|
2355
|
-
const result = unwrapDataResponse(confirmBody);
|
|
2237
|
+
const result = (0, import_core20.unwrapDataResponse)(confirmBody);
|
|
2356
2238
|
printLogoResult(result, ctx.format);
|
|
2357
2239
|
}
|
|
2358
2240
|
function registerEnterpriseCompanyLogo(parent) {
|
|
@@ -2374,6 +2256,7 @@ function registerEnterpriseCompanyCommand(parent) {
|
|
|
2374
2256
|
}
|
|
2375
2257
|
|
|
2376
2258
|
// src/commands/enterprise/talents/list.ts
|
|
2259
|
+
var import_core21 = require("@wport/core");
|
|
2377
2260
|
var DEFAULT_PAGE_SIZE = 20;
|
|
2378
2261
|
var MINIMAL_LIST_FIELDS2 = ["enc_resume_id", "candidate_name", "applied_job_title", "applied_at"];
|
|
2379
2262
|
function formatDate4(value) {
|
|
@@ -2383,7 +2266,7 @@ async function runEnterpriseTalentsList(ctx, apiKey, flags) {
|
|
|
2383
2266
|
if (flags.fields && flags.minimal) {
|
|
2384
2267
|
throw new CliError("Use either --fields or --minimal, not both", ExitCode.InvalidArgument);
|
|
2385
2268
|
}
|
|
2386
|
-
const { body } = await
|
|
2269
|
+
const { body } = await enterpriseGet2(
|
|
2387
2270
|
{ baseUrl: ctx.baseUrl, locale: ctx.locale, timeoutMs: ctx.timeoutMs, apiKey },
|
|
2388
2271
|
"/talents",
|
|
2389
2272
|
{
|
|
@@ -2396,7 +2279,7 @@ async function runEnterpriseTalentsList(ctx, apiKey, flags) {
|
|
|
2396
2279
|
pageSize: flags.pageSize ?? DEFAULT_PAGE_SIZE
|
|
2397
2280
|
}
|
|
2398
2281
|
);
|
|
2399
|
-
const paged = asPaginatedBody(body);
|
|
2282
|
+
const paged = (0, import_core21.asPaginatedBody)(body);
|
|
2400
2283
|
const projection = flags.minimal ? MINIMAL_LIST_FIELDS2 : flags.fields ? parseFieldsList(flags.fields) : void 0;
|
|
2401
2284
|
if (projection || ctx.format === "json") {
|
|
2402
2285
|
printJson(projection ? { ...paged, data: paged.data.map((row) => pickPaths(row, projection)) } : paged);
|
|
@@ -2429,16 +2312,17 @@ function registerEnterpriseTalentsList(parent) {
|
|
|
2429
2312
|
}
|
|
2430
2313
|
|
|
2431
2314
|
// src/commands/enterprise/talents/view.ts
|
|
2315
|
+
var import_core22 = require("@wport/core");
|
|
2432
2316
|
async function runEnterpriseTalentsView(ctx, apiKey, encResumeId, flags) {
|
|
2433
2317
|
const trimmed = encResumeId.trim();
|
|
2434
2318
|
if (!trimmed) {
|
|
2435
2319
|
throw new CliError("enc_resume_id must not be empty", ExitCode.InvalidArgument);
|
|
2436
2320
|
}
|
|
2437
|
-
const { body } = await
|
|
2321
|
+
const { body } = await enterpriseGet2(
|
|
2438
2322
|
{ baseUrl: ctx.baseUrl, locale: ctx.locale, timeoutMs: ctx.timeoutMs, apiKey },
|
|
2439
2323
|
`/talents/${encodeURIComponent(trimmed)}`
|
|
2440
2324
|
);
|
|
2441
|
-
const resume = unwrapDataResponse(body);
|
|
2325
|
+
const resume = (0, import_core22.unwrapDataResponse)(body);
|
|
2442
2326
|
if (flags.fields) {
|
|
2443
2327
|
printJson(pickPaths(resume, parseFieldsList(flags.fields)));
|
|
2444
2328
|
return;
|
|
@@ -2456,6 +2340,7 @@ function registerEnterpriseTalentsView(parent) {
|
|
|
2456
2340
|
|
|
2457
2341
|
// src/commands/enterprise/talents/respond.ts
|
|
2458
2342
|
var import_node_crypto7 = require("crypto");
|
|
2343
|
+
var import_core23 = require("@wport/core");
|
|
2459
2344
|
function resolveRespondBody(flags, options = {}) {
|
|
2460
2345
|
const hasBody = flags.body !== void 0;
|
|
2461
2346
|
const hasBodyFile = flags.bodyFile !== void 0;
|
|
@@ -2481,13 +2366,13 @@ async function runEnterpriseTalentsRespond(ctx, apiKey, encResumeId, flags, idem
|
|
|
2481
2366
|
const encJobId = flags.encJobId?.trim();
|
|
2482
2367
|
const payload = { subject, body };
|
|
2483
2368
|
if (encJobId) payload.enc_job_id = encJobId;
|
|
2484
|
-
const { body: respBody } = await
|
|
2369
|
+
const { body: respBody } = await enterprisePost2(
|
|
2485
2370
|
{ baseUrl: ctx.baseUrl, locale: ctx.locale, timeoutMs: ctx.timeoutMs, apiKey },
|
|
2486
2371
|
`/talents/${encodeURIComponent(trimmedId)}/respond`,
|
|
2487
2372
|
payload,
|
|
2488
2373
|
{ idempotencyKey }
|
|
2489
2374
|
);
|
|
2490
|
-
const result = unwrapDataResponse(respBody);
|
|
2375
|
+
const result = (0, import_core23.unwrapDataResponse)(respBody);
|
|
2491
2376
|
if (ctx.format === "json") {
|
|
2492
2377
|
printJson(result);
|
|
2493
2378
|
return;
|
|
@@ -2516,15 +2401,16 @@ function registerEnterpriseTalentsCommand(parent) {
|
|
|
2516
2401
|
|
|
2517
2402
|
// src/commands/enterprise/campaigns/create.ts
|
|
2518
2403
|
var import_node_crypto8 = require("crypto");
|
|
2404
|
+
var import_core24 = require("@wport/core");
|
|
2519
2405
|
async function runCampaignCreate(ctx, apiKey, source, idempotencyKey) {
|
|
2520
2406
|
const campaignBody = readJsonObject(source, { timeoutMs: ctx.timeoutMs });
|
|
2521
|
-
const { body } = await
|
|
2407
|
+
const { body } = await enterprisePost2(
|
|
2522
2408
|
{ baseUrl: ctx.baseUrl, locale: ctx.locale, timeoutMs: ctx.timeoutMs, apiKey },
|
|
2523
2409
|
"/campaigns",
|
|
2524
2410
|
campaignBody,
|
|
2525
2411
|
{ idempotencyKey }
|
|
2526
2412
|
);
|
|
2527
|
-
const created = unwrapDataResponse(body);
|
|
2413
|
+
const created = (0, import_core24.unwrapDataResponse)(body);
|
|
2528
2414
|
if (ctx.format === "json") {
|
|
2529
2415
|
printJson(created);
|
|
2530
2416
|
return;
|
|
@@ -2542,6 +2428,7 @@ function registerEnterpriseCampaignsCreate(parent) {
|
|
|
2542
2428
|
}
|
|
2543
2429
|
|
|
2544
2430
|
// src/commands/enterprise/campaigns/list.ts
|
|
2431
|
+
var import_core25 = require("@wport/core");
|
|
2545
2432
|
var STATUS_MAP2 = { open: 1, closed: 0 };
|
|
2546
2433
|
var MINIMAL_LIST_FIELDS3 = ["enc_id", "name", "status", "job_count"];
|
|
2547
2434
|
function mapStatusFlag2(raw) {
|
|
@@ -2561,7 +2448,7 @@ async function runEnterpriseCampaignsList(ctx, apiKey, flags) {
|
|
|
2561
2448
|
if (flags.fields && flags.minimal) {
|
|
2562
2449
|
throw new CliError("Use either --fields or --minimal, not both", ExitCode.InvalidArgument);
|
|
2563
2450
|
}
|
|
2564
|
-
const { body } = await
|
|
2451
|
+
const { body } = await enterpriseGet2(
|
|
2565
2452
|
{ baseUrl: ctx.baseUrl, locale: ctx.locale, timeoutMs: ctx.timeoutMs, apiKey },
|
|
2566
2453
|
"/campaigns",
|
|
2567
2454
|
{
|
|
@@ -2571,7 +2458,7 @@ async function runEnterpriseCampaignsList(ctx, apiKey, flags) {
|
|
|
2571
2458
|
status: mapStatusFlag2(flags.status)
|
|
2572
2459
|
}
|
|
2573
2460
|
);
|
|
2574
|
-
const paged = asPaginatedBody(body);
|
|
2461
|
+
const paged = (0, import_core25.asPaginatedBody)(body);
|
|
2575
2462
|
const projection = flags.minimal ? MINIMAL_LIST_FIELDS3 : flags.fields ? parseFieldsList(flags.fields) : void 0;
|
|
2576
2463
|
if (projection || ctx.format === "json") {
|
|
2577
2464
|
printJson(projection ? { ...paged, data: paged.data.map((row) => pickPaths(row, projection)) } : paged);
|
|
@@ -2604,15 +2491,16 @@ function registerEnterpriseCampaignsList(parent) {
|
|
|
2604
2491
|
|
|
2605
2492
|
// src/commands/enterprise/campaigns/lifecycle.ts
|
|
2606
2493
|
var import_node_crypto9 = require("crypto");
|
|
2494
|
+
var import_core26 = require("@wport/core");
|
|
2607
2495
|
async function runCampaignTransition(ctx, apiKey, encId, action, idempotencyKey) {
|
|
2608
2496
|
const trimmed = requireEncId(encId);
|
|
2609
|
-
const { body } = await
|
|
2497
|
+
const { body } = await enterprisePatch2(
|
|
2610
2498
|
{ baseUrl: ctx.baseUrl, locale: ctx.locale, timeoutMs: ctx.timeoutMs, apiKey },
|
|
2611
2499
|
`/campaigns/${encodeURIComponent(trimmed)}/${action}`,
|
|
2612
2500
|
{},
|
|
2613
2501
|
{ idempotencyKey }
|
|
2614
2502
|
);
|
|
2615
|
-
const result = unwrapDataResponse(body);
|
|
2503
|
+
const result = (0, import_core26.unwrapDataResponse)(body);
|
|
2616
2504
|
if (ctx.format === "json") {
|
|
2617
2505
|
printJson(result);
|
|
2618
2506
|
return;
|
|
@@ -2638,16 +2526,17 @@ function registerEnterpriseCampaignsUnpublish(parent) {
|
|
|
2638
2526
|
|
|
2639
2527
|
// src/commands/enterprise/campaigns/update.ts
|
|
2640
2528
|
var import_node_crypto10 = require("crypto");
|
|
2529
|
+
var import_core27 = require("@wport/core");
|
|
2641
2530
|
async function runCampaignUpdate(ctx, apiKey, encId, source, idempotencyKey) {
|
|
2642
2531
|
const trimmed = requireEncId(encId);
|
|
2643
2532
|
const campaignBody = readJsonObject(source, { timeoutMs: ctx.timeoutMs });
|
|
2644
|
-
const { body } = await
|
|
2533
|
+
const { body } = await enterprisePatch2(
|
|
2645
2534
|
{ baseUrl: ctx.baseUrl, locale: ctx.locale, timeoutMs: ctx.timeoutMs, apiKey },
|
|
2646
2535
|
`/campaigns/${encodeURIComponent(trimmed)}`,
|
|
2647
2536
|
campaignBody,
|
|
2648
2537
|
{ idempotencyKey }
|
|
2649
2538
|
);
|
|
2650
|
-
const updated = unwrapDataResponse(body);
|
|
2539
|
+
const updated = (0, import_core27.unwrapDataResponse)(body);
|
|
2651
2540
|
if (ctx.format === "json") {
|
|
2652
2541
|
printJson(updated);
|
|
2653
2542
|
return;
|
|
@@ -2665,16 +2554,17 @@ function registerEnterpriseCampaignsUpdate(parent) {
|
|
|
2665
2554
|
}
|
|
2666
2555
|
|
|
2667
2556
|
// src/commands/enterprise/campaigns/view.ts
|
|
2557
|
+
var import_core28 = require("@wport/core");
|
|
2668
2558
|
async function runEnterpriseCampaignsView(ctx, apiKey, encId, flags) {
|
|
2669
2559
|
const trimmed = encId.trim();
|
|
2670
2560
|
if (!trimmed) {
|
|
2671
2561
|
throw new CliError("enc_id must not be empty", ExitCode.InvalidArgument);
|
|
2672
2562
|
}
|
|
2673
|
-
const { body } = await
|
|
2563
|
+
const { body } = await enterpriseGet2(
|
|
2674
2564
|
{ baseUrl: ctx.baseUrl, locale: ctx.locale, timeoutMs: ctx.timeoutMs, apiKey },
|
|
2675
2565
|
`/campaigns/${encodeURIComponent(trimmed)}`
|
|
2676
2566
|
);
|
|
2677
|
-
const campaign = unwrapDataResponse(body);
|
|
2567
|
+
const campaign = (0, import_core28.unwrapDataResponse)(body);
|
|
2678
2568
|
if (flags.fields) {
|
|
2679
2569
|
printJson(pickPaths(campaign, parseFieldsList(flags.fields)));
|
|
2680
2570
|
return;
|
|
@@ -2818,7 +2708,11 @@ function registerLoginCommand(program2) {
|
|
|
2818
2708
|
});
|
|
2819
2709
|
}
|
|
2820
2710
|
|
|
2711
|
+
// src/commands/auth/whoami.ts
|
|
2712
|
+
var import_core30 = require("@wport/core");
|
|
2713
|
+
|
|
2821
2714
|
// src/lib/personal-client.ts
|
|
2715
|
+
var import_core29 = require("@wport/core");
|
|
2822
2716
|
var EXPIRY_SKEW_MS = 3e4;
|
|
2823
2717
|
var NOT_LOGGED_IN_MESSAGE = "Not logged in. Run `wport login`.";
|
|
2824
2718
|
async function ensureFreshCredentials(opts) {
|
|
@@ -2847,7 +2741,8 @@ async function attemptRequest(opts, method, path, accessToken, body, query, extr
|
|
|
2847
2741
|
const headers = {
|
|
2848
2742
|
Authorization: `Bearer ${accessToken}`,
|
|
2849
2743
|
"Accept-Language": opts.locale,
|
|
2850
|
-
"User-Agent": buildUserAgent(),
|
|
2744
|
+
"User-Agent": (0, import_core29.buildUserAgent)("wport-cli", "0.9.2"),
|
|
2745
|
+
"X-Source": CLI_SOURCE,
|
|
2851
2746
|
Accept: "application/json"
|
|
2852
2747
|
};
|
|
2853
2748
|
if (body !== void 0) headers["Content-Type"] = "application/json";
|
|
@@ -2857,7 +2752,7 @@ async function attemptRequest(opts, method, path, accessToken, body, query, extr
|
|
|
2857
2752
|
headers,
|
|
2858
2753
|
body: body !== void 0 ? JSON.stringify(body) : void 0
|
|
2859
2754
|
});
|
|
2860
|
-
const res = await fetchWithTimeout(request, opts.timeoutMs);
|
|
2755
|
+
const res = await (0, import_core29.fetchWithTimeout)(request, opts.timeoutMs);
|
|
2861
2756
|
const respBody = await res.json().catch(() => null);
|
|
2862
2757
|
return { status: res.status, body: respBody, headers: res.headers };
|
|
2863
2758
|
}
|
|
@@ -2889,13 +2784,13 @@ function personalDelete(opts, path, extra) {
|
|
|
2889
2784
|
}
|
|
2890
2785
|
function throwPersonalHttpError(status, body) {
|
|
2891
2786
|
if (status === 401) {
|
|
2892
|
-
const base = extractErrorMessage(body) ?? `HTTP ${status}`;
|
|
2787
|
+
const base = (0, import_core29.extractErrorMessage)(body) ?? `HTTP ${status}`;
|
|
2893
2788
|
throw new CliError(
|
|
2894
2789
|
`${base} \u2014 Your session may have expired or the request was rejected. Run \`wport login\` to sign in again.`,
|
|
2895
2790
|
ExitCode.ServerClientError
|
|
2896
2791
|
);
|
|
2897
2792
|
}
|
|
2898
|
-
throwForHttpStatus(status, body);
|
|
2793
|
+
(0, import_core29.throwForHttpStatus)(status, body);
|
|
2899
2794
|
}
|
|
2900
2795
|
function warnIfRateLimitLow2(headers) {
|
|
2901
2796
|
const remaining = Number(headers.get("x-ratelimit-remaining"));
|
|
@@ -2906,6 +2801,7 @@ function warnIfRateLimitLow2(headers) {
|
|
|
2906
2801
|
}
|
|
2907
2802
|
|
|
2908
2803
|
// src/commands/auth/whoami.ts
|
|
2804
|
+
var import_core31 = require("@wport/core");
|
|
2909
2805
|
var PLACEHOLDER = "\u2014";
|
|
2910
2806
|
function display(value) {
|
|
2911
2807
|
const clean = sanitizeForTerminal(value ?? "");
|
|
@@ -2913,8 +2809,8 @@ function display(value) {
|
|
|
2913
2809
|
}
|
|
2914
2810
|
async function performWhoami(ctx) {
|
|
2915
2811
|
const opts = { baseUrl: ctx.baseUrl, locale: ctx.locale, timeoutMs: ctx.timeoutMs };
|
|
2916
|
-
const { body } = await personalGet(opts, OAUTH_SESSIONS_BASE);
|
|
2917
|
-
const sessions = unwrapDataArray(body);
|
|
2812
|
+
const { body } = await personalGet(opts, import_core31.OAUTH_SESSIONS_BASE);
|
|
2813
|
+
const sessions = (0, import_core30.unwrapDataArray)(body);
|
|
2918
2814
|
const current = sessions.find((s) => s.is_current);
|
|
2919
2815
|
const localLoginAt = loadPersonalCredentials()?.session_created_at ?? null;
|
|
2920
2816
|
if (ctx.format === "json") {
|
|
@@ -2966,13 +2862,15 @@ function registerLogoutCommand(program2) {
|
|
|
2966
2862
|
}
|
|
2967
2863
|
|
|
2968
2864
|
// src/commands/sessions/list.ts
|
|
2865
|
+
var import_core32 = require("@wport/core");
|
|
2866
|
+
var import_core33 = require("@wport/core");
|
|
2969
2867
|
function formatDate5(value) {
|
|
2970
2868
|
return value ? String(value).slice(0, 10) : "";
|
|
2971
2869
|
}
|
|
2972
2870
|
async function runSessionsList(ctx) {
|
|
2973
2871
|
const opts = { baseUrl: ctx.baseUrl, locale: ctx.locale, timeoutMs: ctx.timeoutMs };
|
|
2974
|
-
const { body } = await personalGet(opts, OAUTH_SESSIONS_BASE);
|
|
2975
|
-
const sessions = unwrapDataArray(body);
|
|
2872
|
+
const { body } = await personalGet(opts, import_core33.OAUTH_SESSIONS_BASE);
|
|
2873
|
+
const sessions = (0, import_core32.unwrapDataArray)(body);
|
|
2976
2874
|
if (ctx.format === "json") {
|
|
2977
2875
|
printJson(sessions);
|
|
2978
2876
|
return;
|
|
@@ -2996,6 +2894,8 @@ function registerSessionsList(parent) {
|
|
|
2996
2894
|
}
|
|
2997
2895
|
|
|
2998
2896
|
// src/commands/sessions/revoke.ts
|
|
2897
|
+
var import_core34 = require("@wport/core");
|
|
2898
|
+
var import_core35 = require("@wport/core");
|
|
2999
2899
|
async function runSessionsRevoke(ctx, encId, allOthers) {
|
|
3000
2900
|
const hasEncId = encId !== void 0;
|
|
3001
2901
|
if (hasEncId === allOthers) {
|
|
@@ -3003,8 +2903,8 @@ async function runSessionsRevoke(ctx, encId, allOthers) {
|
|
|
3003
2903
|
}
|
|
3004
2904
|
const opts = { baseUrl: ctx.baseUrl, locale: ctx.locale, timeoutMs: ctx.timeoutMs };
|
|
3005
2905
|
if (allOthers) {
|
|
3006
|
-
const { body } = await personalDelete(opts, `${OAUTH_SESSIONS_BASE}/others`);
|
|
3007
|
-
const result = unwrapDataResponse(body);
|
|
2906
|
+
const { body } = await personalDelete(opts, `${import_core34.OAUTH_SESSIONS_BASE}/others`);
|
|
2907
|
+
const result = (0, import_core35.unwrapDataResponse)(body);
|
|
3008
2908
|
if (ctx.format === "json") {
|
|
3009
2909
|
printJson(result);
|
|
3010
2910
|
return;
|
|
@@ -3015,7 +2915,7 @@ async function runSessionsRevoke(ctx, encId, allOthers) {
|
|
|
3015
2915
|
}
|
|
3016
2916
|
const trimmed = encId.trim();
|
|
3017
2917
|
if (!trimmed) throw new CliError("enc_id must not be empty", ExitCode.InvalidArgument);
|
|
3018
|
-
await personalDelete(opts, `${OAUTH_SESSIONS_BASE}/${encodeURIComponent(trimmed)}`);
|
|
2918
|
+
await personalDelete(opts, `${import_core34.OAUTH_SESSIONS_BASE}/${encodeURIComponent(trimmed)}`);
|
|
3019
2919
|
if (ctx.format === "json") {
|
|
3020
2920
|
printJson({ enc_id: trimmed, revoked: true });
|
|
3021
2921
|
return;
|
|
@@ -3037,949 +2937,19 @@ function registerSessionsCommand(program2) {
|
|
|
3037
2937
|
registerSessionsRevoke(sessions);
|
|
3038
2938
|
}
|
|
3039
2939
|
|
|
3040
|
-
// src/lib/resume-schema/definition.ts
|
|
3041
|
-
var DEGREE_TYPE_VALUES = ["phd", "master", "bachelor", "associate", "senior_high", "junior_or_below"];
|
|
3042
|
-
var EDUCATION_STATUS_VALUES = ["graduated", "dropped", "studying"];
|
|
3043
|
-
var JOB_FEATURE_CODE_VALUES = ["dispatch", "executive", "full_time", "internship", "part_time"];
|
|
3044
|
-
var WORKING_HOUR_TYPE_VALUES = ["day_shift", "evening_shift", "night_shift", "rotating_shift", "weekend_shift"];
|
|
3045
|
-
var AVAILABLE_START_TYPE_VALUES = ["available_after_hired", "available_custom_date"];
|
|
3046
|
-
var AVAILABLE_START_PERIOD_VALUES = ["week", "two_weeks", "month", "two_months", "three_months", "anytime"];
|
|
3047
|
-
var SALARY_EXPECTATION_TYPE_VALUES = ["negotiable", "company_rules", "custom"];
|
|
3048
|
-
var SALARY_UNIT_VALUES = ["hourly", "daily", "monthly", "yearly"];
|
|
3049
|
-
var PROFICIENCY_LEVEL_VALUES = ["beginner", "daily_convo", "proficient", "native"];
|
|
3050
|
-
var JOB_STATUS_VALUES = ["employed", "military", "student", "unemployed"];
|
|
3051
|
-
var VEHICLE_OR_LICENSE_TYPE_VALUES = [
|
|
3052
|
-
"bus",
|
|
3053
|
-
"heavy_motorcycle",
|
|
3054
|
-
"light_motorcycle",
|
|
3055
|
-
"light_car",
|
|
3056
|
-
"pro_bus",
|
|
3057
|
-
"pro_small_car",
|
|
3058
|
-
"pro_trailer",
|
|
3059
|
-
"pro_truck",
|
|
3060
|
-
"scooter",
|
|
3061
|
-
"trailer",
|
|
3062
|
-
"truck"
|
|
3063
|
-
];
|
|
3064
|
-
var CURRENT_YEAR = (/* @__PURE__ */ new Date()).getFullYear();
|
|
3065
|
-
var TOP_LEVEL_FIELDS = {
|
|
3066
|
-
name: {
|
|
3067
|
-
type: "string",
|
|
3068
|
-
required: true,
|
|
3069
|
-
minLength: 1,
|
|
3070
|
-
maxLength: 100,
|
|
3071
|
-
description: "\u5C65\u6B77\u540D\u7A31",
|
|
3072
|
-
example: "\u6211\u7684\u5C65\u6B77\u540D\u7A31"
|
|
3073
|
-
}
|
|
3074
|
-
};
|
|
3075
|
-
var educationSection = {
|
|
3076
|
-
key: "education",
|
|
3077
|
-
kind: "array",
|
|
3078
|
-
description: "\u5B78\u6B77\uFF0C\u53EF\u591A\u7B46",
|
|
3079
|
-
fields: {
|
|
3080
|
-
school_name: {
|
|
3081
|
-
type: "string",
|
|
3082
|
-
required: true,
|
|
3083
|
-
minLength: 1,
|
|
3084
|
-
maxLength: 80,
|
|
3085
|
-
description: "\u5B78\u6821\u540D\u7A31",
|
|
3086
|
-
example: "National Taiwan University"
|
|
3087
|
-
},
|
|
3088
|
-
degree_code: {
|
|
3089
|
-
type: "enum",
|
|
3090
|
-
required: true,
|
|
3091
|
-
enumValues: DEGREE_TYPE_VALUES,
|
|
3092
|
-
description: "\u5B78\u6B77\u7B49\u7D1A",
|
|
3093
|
-
example: "bachelor"
|
|
3094
|
-
},
|
|
3095
|
-
department: {
|
|
3096
|
-
type: "string",
|
|
3097
|
-
required: true,
|
|
3098
|
-
minLength: 1,
|
|
3099
|
-
maxLength: 80,
|
|
3100
|
-
description: "\u4E3B\u4FEE\u79D1\u7CFB\u540D\u7A31",
|
|
3101
|
-
example: "Computer Science"
|
|
3102
|
-
},
|
|
3103
|
-
minor_department: {
|
|
3104
|
-
type: "string",
|
|
3105
|
-
required: false,
|
|
3106
|
-
minLength: 1,
|
|
3107
|
-
maxLength: 80,
|
|
3108
|
-
description: "\u526F\u4FEE\u79D1\u7CFB\u540D\u7A31",
|
|
3109
|
-
example: "Mathematics"
|
|
3110
|
-
},
|
|
3111
|
-
department_class_code: {
|
|
3112
|
-
type: "string",
|
|
3113
|
-
required: false,
|
|
3114
|
-
description: "\u4E3B\u4FEE\u79D1\u7CFB\u985E\u5225\u4EE3\u78BC",
|
|
3115
|
-
example: "engineering"
|
|
3116
|
-
},
|
|
3117
|
-
minor_department_class_code: {
|
|
3118
|
-
type: "string",
|
|
3119
|
-
required: false,
|
|
3120
|
-
description: "\u526F\u4FEE\u79D1\u7CFB\u985E\u5225\u4EE3\u78BC",
|
|
3121
|
-
example: "industry_machinery"
|
|
3122
|
-
},
|
|
3123
|
-
edu_status_code: {
|
|
3124
|
-
type: "enum",
|
|
3125
|
-
required: true,
|
|
3126
|
-
enumValues: EDUCATION_STATUS_VALUES,
|
|
3127
|
-
description: "\u5C31\u5B78\u72C0\u614B",
|
|
3128
|
-
example: "studying"
|
|
3129
|
-
},
|
|
3130
|
-
start_year: {
|
|
3131
|
-
type: "integer",
|
|
3132
|
-
required: true,
|
|
3133
|
-
min: 1900,
|
|
3134
|
-
max: CURRENT_YEAR,
|
|
3135
|
-
description: "\u5165\u5B78\u5E74\u4EFD",
|
|
3136
|
-
example: 2015
|
|
3137
|
-
},
|
|
3138
|
-
start_month: {
|
|
3139
|
-
type: "integer",
|
|
3140
|
-
required: true,
|
|
3141
|
-
min: 1,
|
|
3142
|
-
max: 12,
|
|
3143
|
-
description: "\u5165\u5B78\u6708\u4EFD",
|
|
3144
|
-
example: 9
|
|
3145
|
-
},
|
|
3146
|
-
end_year: {
|
|
3147
|
-
type: "integer",
|
|
3148
|
-
required: false,
|
|
3149
|
-
min: 1900,
|
|
3150
|
-
max: CURRENT_YEAR,
|
|
3151
|
-
description: "\u7562\u696D\u5E74\u4EFD\uFF08edu_status_code \u70BA graduated/dropped \u6642\u5FC5\u586B\uFF09",
|
|
3152
|
-
example: 2019
|
|
3153
|
-
},
|
|
3154
|
-
end_month: {
|
|
3155
|
-
type: "integer",
|
|
3156
|
-
required: false,
|
|
3157
|
-
min: 1,
|
|
3158
|
-
max: 12,
|
|
3159
|
-
description: "\u7562\u696D\u6708\u4EFD\uFF08edu_status_code \u70BA graduated/dropped \u6642\u5FC5\u586B\uFF09",
|
|
3160
|
-
example: 6
|
|
3161
|
-
},
|
|
3162
|
-
experience: {
|
|
3163
|
-
type: "string",
|
|
3164
|
-
required: false,
|
|
3165
|
-
htmlText: true,
|
|
3166
|
-
maxLength: 2e3,
|
|
3167
|
-
description: "\u5728\u6821\u7D93\u6B77\uFF08\u5BCC\u6587\u672C\uFF09",
|
|
3168
|
-
example: "<p>Served as the president of the student council.</p>"
|
|
3169
|
-
}
|
|
3170
|
-
},
|
|
3171
|
-
crossFieldRules: [
|
|
3172
|
-
{
|
|
3173
|
-
name: "education-graduation-date",
|
|
3174
|
-
message: 'When edu_status_code is "graduated" or "dropped", end_year/end_month are required and the end date must be after start_year/start_month and not later than today.',
|
|
3175
|
-
check(item) {
|
|
3176
|
-
const status = item.edu_status_code;
|
|
3177
|
-
if (status !== "graduated" && status !== "dropped") return true;
|
|
3178
|
-
const { end_year, end_month, start_year, start_month } = item;
|
|
3179
|
-
if (typeof end_year !== "number" || typeof end_month !== "number") return false;
|
|
3180
|
-
if (typeof start_year !== "number" || typeof start_month !== "number") return true;
|
|
3181
|
-
const start = new Date(start_year, start_month - 1);
|
|
3182
|
-
const end = new Date(end_year, end_month - 1);
|
|
3183
|
-
return end > start && end <= /* @__PURE__ */ new Date();
|
|
3184
|
-
}
|
|
3185
|
-
}
|
|
3186
|
-
]
|
|
3187
|
-
};
|
|
3188
|
-
var workExperienceSection = {
|
|
3189
|
-
key: "work_experience",
|
|
3190
|
-
kind: "wrapper",
|
|
3191
|
-
description: "\u5DE5\u4F5C\u7D93\u9A57\uFF08\u5305\u88DD\u5C64\u542B\u300C\u7121\u5DE5\u4F5C\u7D93\u9A57\u300D\u65D7\u6A19\uFF09",
|
|
3192
|
-
wrapperFields: {
|
|
3193
|
-
has_no_work_experience: {
|
|
3194
|
-
type: "boolean",
|
|
3195
|
-
required: false,
|
|
3196
|
-
description: "\u662F\u5426\u7121\u5DE5\u4F5C\u7D93\u9A57\uFF08true \u6642 items \u5FC5\u70BA\u7A7A\u9663\u5217\uFF09",
|
|
3197
|
-
example: false
|
|
3198
|
-
}
|
|
3199
|
-
},
|
|
3200
|
-
fields: {
|
|
3201
|
-
job_title: {
|
|
3202
|
-
type: "string",
|
|
3203
|
-
required: true,
|
|
3204
|
-
maxLength: 100,
|
|
3205
|
-
description: "\u8077\u7A31",
|
|
3206
|
-
example: "Software Engineer"
|
|
3207
|
-
},
|
|
3208
|
-
job_type: {
|
|
3209
|
-
type: "enum",
|
|
3210
|
-
required: true,
|
|
3211
|
-
enumValues: JOB_FEATURE_CODE_VALUES,
|
|
3212
|
-
description: "\u8077\u52D9\u985E\u578B",
|
|
3213
|
-
example: "full_time"
|
|
3214
|
-
},
|
|
3215
|
-
company_name: {
|
|
3216
|
-
type: "string",
|
|
3217
|
-
required: true,
|
|
3218
|
-
maxLength: 200,
|
|
3219
|
-
description: "\u516C\u53F8\u540D\u7A31",
|
|
3220
|
-
example: "Tech Corp"
|
|
3221
|
-
},
|
|
3222
|
-
start_year: {
|
|
3223
|
-
type: "integer",
|
|
3224
|
-
required: true,
|
|
3225
|
-
min: 1900,
|
|
3226
|
-
max: CURRENT_YEAR,
|
|
3227
|
-
description: "\u4EFB\u8077\u958B\u59CB\u5E74\u4EFD",
|
|
3228
|
-
example: 2020
|
|
3229
|
-
},
|
|
3230
|
-
start_month: {
|
|
3231
|
-
type: "integer",
|
|
3232
|
-
required: true,
|
|
3233
|
-
min: 1,
|
|
3234
|
-
max: 12,
|
|
3235
|
-
description: "\u4EFB\u8077\u958B\u59CB\u6708\u4EFD",
|
|
3236
|
-
example: 1
|
|
3237
|
-
},
|
|
3238
|
-
end_year: {
|
|
3239
|
-
type: "integer",
|
|
3240
|
-
required: false,
|
|
3241
|
-
min: 1900,
|
|
3242
|
-
max: CURRENT_YEAR,
|
|
3243
|
-
description: "\u4EFB\u8077\u7D50\u675F\u5E74\u4EFD\uFF08is_current \u70BA false \u6642\u5FC5\u586B\uFF09",
|
|
3244
|
-
example: 2022
|
|
3245
|
-
},
|
|
3246
|
-
end_month: {
|
|
3247
|
-
type: "integer",
|
|
3248
|
-
required: false,
|
|
3249
|
-
min: 1,
|
|
3250
|
-
max: 12,
|
|
3251
|
-
description: "\u4EFB\u8077\u7D50\u675F\u6708\u4EFD\uFF08is_current \u70BA false \u6642\u5FC5\u586B\uFF09",
|
|
3252
|
-
example: 12
|
|
3253
|
-
},
|
|
3254
|
-
is_current: {
|
|
3255
|
-
type: "boolean",
|
|
3256
|
-
required: true,
|
|
3257
|
-
description: "\u662F\u5426\u5728\u8077\u4E2D\uFF08\u8B80\u5BEB\u4E0D\u5C0D\u7A31\uFF1A\u805A\u5408\u683C\u5F0F\u53D6 read shape \u70BA boolean\uFF0Corchestrator \u5BEB\u5165\u6642\u8F49 0/1\uFF09",
|
|
3258
|
-
example: false
|
|
3259
|
-
},
|
|
3260
|
-
job_description: {
|
|
3261
|
-
type: "string",
|
|
3262
|
-
required: false,
|
|
3263
|
-
htmlText: true,
|
|
3264
|
-
maxLength: 1e4,
|
|
3265
|
-
description: "\u5DE5\u4F5C\u5167\u5BB9\u63CF\u8FF0\uFF08\u5BCC\u6587\u672C\uFF09",
|
|
3266
|
-
example: "<p>Built and maintained internal developer tools.</p>"
|
|
3267
|
-
}
|
|
3268
|
-
},
|
|
3269
|
-
crossFieldRules: [
|
|
3270
|
-
{
|
|
3271
|
-
name: "work-experience-end-date",
|
|
3272
|
-
message: "When is_current is true, end_year/end_month must not be present. When is_current is false, end_year/end_month are required and the end date must be on/after the start date and not later than today.",
|
|
3273
|
-
check(item) {
|
|
3274
|
-
if (typeof item.is_current !== "boolean") return true;
|
|
3275
|
-
if (item.is_current) {
|
|
3276
|
-
return item.end_year === void 0 && item.end_month === void 0;
|
|
3277
|
-
}
|
|
3278
|
-
const { end_year, end_month, start_year, start_month } = item;
|
|
3279
|
-
if (typeof end_year !== "number" || typeof end_month !== "number") return false;
|
|
3280
|
-
if (typeof start_year !== "number" || typeof start_month !== "number") return true;
|
|
3281
|
-
const start = new Date(start_year, start_month - 1);
|
|
3282
|
-
const end = new Date(end_year, end_month - 1);
|
|
3283
|
-
return end >= start && end <= /* @__PURE__ */ new Date();
|
|
3284
|
-
}
|
|
3285
|
-
},
|
|
3286
|
-
{
|
|
3287
|
-
name: "work-experience-no-experience-items-empty",
|
|
3288
|
-
message: "When has_no_work_experience is true, items must be an empty array.",
|
|
3289
|
-
check(wrapper) {
|
|
3290
|
-
if (wrapper.has_no_work_experience !== true) return true;
|
|
3291
|
-
return Array.isArray(wrapper.items) && wrapper.items.length === 0;
|
|
3292
|
-
}
|
|
3293
|
-
}
|
|
3294
|
-
]
|
|
3295
|
-
};
|
|
3296
|
-
var certificateSection = {
|
|
3297
|
-
key: "certificate",
|
|
3298
|
-
kind: "array",
|
|
3299
|
-
description: "\u8B49\u7167\uFF0C\u53EF\u591A\u7B46",
|
|
3300
|
-
fields: {
|
|
3301
|
-
certificate_code: {
|
|
3302
|
-
type: "string",
|
|
3303
|
-
required: true,
|
|
3304
|
-
description: "\u8B49\u7167\u4EE3\u78BC",
|
|
3305
|
-
example: "4001001014"
|
|
3306
|
-
},
|
|
3307
|
-
issue_year: {
|
|
3308
|
-
type: "integer",
|
|
3309
|
-
required: true,
|
|
3310
|
-
min: 1900,
|
|
3311
|
-
max: 2100,
|
|
3312
|
-
description: "\u8D77\u59CB\u5E74\u4EFD\uFF08\u683C\u5F0F\uFF1AYYYY\uFF09",
|
|
3313
|
-
example: 2023
|
|
3314
|
-
},
|
|
3315
|
-
issue_month: {
|
|
3316
|
-
type: "integer",
|
|
3317
|
-
required: true,
|
|
3318
|
-
min: 1,
|
|
3319
|
-
max: 12,
|
|
3320
|
-
description: "\u8D77\u59CB\u6708\u4EFD\uFF08\u683C\u5F0F\uFF1AMM\uFF09",
|
|
3321
|
-
example: 1
|
|
3322
|
-
},
|
|
3323
|
-
expiry_year: {
|
|
3324
|
-
type: "integer",
|
|
3325
|
-
required: false,
|
|
3326
|
-
min: 1900,
|
|
3327
|
-
max: 2100,
|
|
3328
|
-
description: "\u5230\u671F\u5E74\u4EFD\uFF08is_permanent \u70BA false \u6642\u5FC5\u586B\uFF09",
|
|
3329
|
-
example: 2025
|
|
3330
|
-
},
|
|
3331
|
-
expiry_month: {
|
|
3332
|
-
type: "integer",
|
|
3333
|
-
required: false,
|
|
3334
|
-
min: 1,
|
|
3335
|
-
max: 12,
|
|
3336
|
-
description: "\u5230\u671F\u6708\u4EFD\uFF08is_permanent \u70BA false \u6642\u5FC5\u586B\uFF09",
|
|
3337
|
-
example: 1
|
|
3338
|
-
},
|
|
3339
|
-
is_permanent: {
|
|
3340
|
-
type: "boolean",
|
|
3341
|
-
required: true,
|
|
3342
|
-
description: "\u662F\u5426\u6C38\u4E45\u6709\u6548",
|
|
3343
|
-
example: false
|
|
3344
|
-
}
|
|
3345
|
-
},
|
|
3346
|
-
crossFieldRules: [
|
|
3347
|
-
{
|
|
3348
|
-
name: "certificate-expiry-required",
|
|
3349
|
-
message: "When is_permanent is false, expiry_year/expiry_month are required and must not be earlier than issue_year/issue_month.",
|
|
3350
|
-
check(item) {
|
|
3351
|
-
if (item.is_permanent !== false) return true;
|
|
3352
|
-
const { expiry_year, expiry_month, issue_year, issue_month } = item;
|
|
3353
|
-
if (typeof expiry_year !== "number" || typeof expiry_month !== "number") return false;
|
|
3354
|
-
if (typeof issue_year !== "number" || typeof issue_month !== "number") return true;
|
|
3355
|
-
return expiry_year * 12 + expiry_month >= issue_year * 12 + issue_month;
|
|
3356
|
-
}
|
|
3357
|
-
}
|
|
3358
|
-
]
|
|
3359
|
-
};
|
|
3360
|
-
var languageSection = {
|
|
3361
|
-
key: "language",
|
|
3362
|
-
kind: "array",
|
|
3363
|
-
description: "\u8A9E\u8A00\u80FD\u529B\uFF0C\u53EF\u591A\u7B46",
|
|
3364
|
-
fields: {
|
|
3365
|
-
code: {
|
|
3366
|
-
type: "string",
|
|
3367
|
-
required: true,
|
|
3368
|
-
description: "\u6280\u80FD\u8A9E\u8A00\u4EE3\u78BC\uFF08\u5C0D\u61C9 skill_languages \u8CC7\u6599\u8868\u4E2D\u7684 code\uFF09",
|
|
3369
|
-
example: "Chinese"
|
|
3370
|
-
},
|
|
3371
|
-
proficiency_level_code: {
|
|
3372
|
-
type: "enum",
|
|
3373
|
-
required: true,
|
|
3374
|
-
enumValues: PROFICIENCY_LEVEL_VALUES,
|
|
3375
|
-
description: "\u719F\u7DF4\u7A0B\u5EA6",
|
|
3376
|
-
example: "proficient"
|
|
3377
|
-
}
|
|
3378
|
-
}
|
|
3379
|
-
};
|
|
3380
|
-
var professionalSkillsSection = {
|
|
3381
|
-
key: "professional_skills",
|
|
3382
|
-
kind: "object",
|
|
3383
|
-
description: "\u5C08\u696D\u6280\u80FD",
|
|
3384
|
-
fields: {
|
|
3385
|
-
tech_tool_codes: {
|
|
3386
|
-
type: "string[]",
|
|
3387
|
-
required: true,
|
|
3388
|
-
minItems: 1,
|
|
3389
|
-
maxItems: 10,
|
|
3390
|
-
description: "\u5DE5\u5177\u4EE3\u78BC\u9663\u5217\uFF08\u6700\u591A 10 \u500B\uFF09",
|
|
3391
|
-
example: ["12001001045", "12001001044"]
|
|
3392
|
-
},
|
|
3393
|
-
other_tool_description: {
|
|
3394
|
-
type: "string",
|
|
3395
|
-
required: false,
|
|
3396
|
-
htmlText: true,
|
|
3397
|
-
maxLength: 2e3,
|
|
3398
|
-
description: "\u5176\u4ED6\u64C5\u9577\u5DE5\u5177\u63CF\u8FF0\uFF08\u5BCC\u6587\u672C\uFF0C\u5BE6\u969B\u6587\u5B57\u4E0A\u9650 2000 \u5B57\uFF09",
|
|
3399
|
-
example: "\u719F\u6089 Photoshop \u548C Illustrator"
|
|
3400
|
-
},
|
|
3401
|
-
job_skill_codes: {
|
|
3402
|
-
type: "string[]",
|
|
3403
|
-
required: true,
|
|
3404
|
-
minItems: 1,
|
|
3405
|
-
maxItems: 10,
|
|
3406
|
-
description: "\u6280\u80FD\u4EE3\u78BC\u9663\u5217\uFF08\u6700\u591A 10 \u500B\uFF09",
|
|
3407
|
-
example: ["5001001006", "5001001007"]
|
|
3408
|
-
},
|
|
3409
|
-
other_job_skill_description: {
|
|
3410
|
-
type: "string",
|
|
3411
|
-
required: false,
|
|
3412
|
-
htmlText: true,
|
|
3413
|
-
maxLength: 2e3,
|
|
3414
|
-
description: "\u5176\u4ED6\u5DE5\u4F5C\u6280\u80FD\u63CF\u8FF0\uFF08\u5BCC\u6587\u672C\uFF0C\u5BE6\u969B\u6587\u5B57\u4E0A\u9650 2000 \u5B57\uFF09",
|
|
3415
|
-
example: "\u719F\u6089 Scrum \u548C\u654F\u6377\u958B\u767C\u6D41\u7A0B"
|
|
3416
|
-
}
|
|
3417
|
-
}
|
|
3418
|
-
};
|
|
3419
|
-
var autobiographySection = {
|
|
3420
|
-
key: "autobiography",
|
|
3421
|
-
kind: "scalar",
|
|
3422
|
-
description: "\u81EA\u50B3\uFF08\u7D14\u5B57\u4E32\u7BC0\uFF09",
|
|
3423
|
-
valueDef: {
|
|
3424
|
-
type: "string",
|
|
3425
|
-
required: true,
|
|
3426
|
-
htmlText: true,
|
|
3427
|
-
maxLength: 3e3,
|
|
3428
|
-
description: "\u81EA\u50B3\u5167\u5BB9\uFF08\u5BCC\u6587\u672C\u683C\u5F0F\uFF09\uFF0C\u5BE6\u969B\u6587\u5B57\u9577\u5EA6\u4E0D\u8D85\u904E 3000 \u5B57",
|
|
3429
|
-
example: "<p>This is my <strong>autobiography</strong>.</p>"
|
|
3430
|
-
}
|
|
3431
|
-
};
|
|
3432
|
-
var jobConditionSection = {
|
|
3433
|
-
key: "job_condition",
|
|
3434
|
-
kind: "object",
|
|
3435
|
-
description: "\u5E0C\u671B\u5DE5\u4F5C\u689D\u4EF6",
|
|
3436
|
-
fields: {
|
|
3437
|
-
feature_codes: {
|
|
3438
|
-
type: "enum[]",
|
|
3439
|
-
required: true,
|
|
3440
|
-
enumValues: JOB_FEATURE_CODE_VALUES,
|
|
3441
|
-
description: "\u5E0C\u671B\u6027\u8CEA\u4EE3\u78BC\uFF08\u591A\u9078\uFF09",
|
|
3442
|
-
example: ["full_time", "part_time"]
|
|
3443
|
-
},
|
|
3444
|
-
working_hour_type_codes: {
|
|
3445
|
-
type: "enum[]",
|
|
3446
|
-
required: true,
|
|
3447
|
-
enumValues: WORKING_HOUR_TYPE_VALUES,
|
|
3448
|
-
description: "\u4E0A\u73ED\u6642\u6BB5\u4EE3\u78BC\uFF08\u591A\u9078\uFF09",
|
|
3449
|
-
example: ["day_shift", "evening_shift"]
|
|
3450
|
-
},
|
|
3451
|
-
available_start_type_code: {
|
|
3452
|
-
type: "enum",
|
|
3453
|
-
required: true,
|
|
3454
|
-
enumValues: AVAILABLE_START_TYPE_VALUES,
|
|
3455
|
-
description: "\u53EF\u4E0A\u73ED\u6642\u9593\u985E\u578B\u4EE3\u78BC",
|
|
3456
|
-
example: "available_after_hired"
|
|
3457
|
-
},
|
|
3458
|
-
available_start_date: {
|
|
3459
|
-
type: "date",
|
|
3460
|
-
required: false,
|
|
3461
|
-
description: "\u81EA\u8A02\u53EF\u4E0A\u73ED\u65E5\u671F\uFF08available_start_type_code \u70BA available_custom_date \u6642\u5FC5\u586B\uFF09",
|
|
3462
|
-
example: "2025-05-01"
|
|
3463
|
-
},
|
|
3464
|
-
available_start_period_code: {
|
|
3465
|
-
type: "enum",
|
|
3466
|
-
required: false,
|
|
3467
|
-
enumValues: AVAILABLE_START_PERIOD_VALUES,
|
|
3468
|
-
description: "\u9304\u53D6\u5F8C\u671F\u9593\u4EE3\u78BC\uFF08available_start_type_code \u70BA available_after_hired \u6642\u5FC5\u586B\uFF09",
|
|
3469
|
-
example: "week"
|
|
3470
|
-
},
|
|
3471
|
-
salary_expectation_type_code: {
|
|
3472
|
-
type: "enum",
|
|
3473
|
-
required: true,
|
|
3474
|
-
enumValues: SALARY_EXPECTATION_TYPE_VALUES,
|
|
3475
|
-
description: "\u5E0C\u671B\u5F85\u9047\u985E\u578B\u4EE3\u78BC",
|
|
3476
|
-
example: "negotiable"
|
|
3477
|
-
},
|
|
3478
|
-
salary_unit_code: {
|
|
3479
|
-
type: "enum",
|
|
3480
|
-
required: false,
|
|
3481
|
-
enumValues: SALARY_UNIT_VALUES,
|
|
3482
|
-
description: "\u85AA\u8CC7\u55AE\u4F4D\u4EE3\u78BC\uFF08salary_expectation_type_code \u70BA custom \u6642\u5FC5\u586B\uFF09",
|
|
3483
|
-
example: "monthly"
|
|
3484
|
-
},
|
|
3485
|
-
salary_amount: {
|
|
3486
|
-
type: "number",
|
|
3487
|
-
required: false,
|
|
3488
|
-
min: 0,
|
|
3489
|
-
description: "\u81EA\u8A02\u85AA\u8CC7\u91D1\u984D\uFF08salary_expectation_type_code \u70BA custom \u6642\u5FC5\u586B\uFF09",
|
|
3490
|
-
example: 5e4
|
|
3491
|
-
},
|
|
3492
|
-
expected_salary_currency_code: {
|
|
3493
|
-
type: "string",
|
|
3494
|
-
required: false,
|
|
3495
|
-
minLength: 3,
|
|
3496
|
-
maxLength: 3,
|
|
3497
|
-
description: "\u671F\u671B\u85AA\u8CC7\u5E63\u5225\u4EE3\u78BC\uFF08ISO 4217\uFF0Csalary_expectation_type_code \u70BA custom \u6642\u5FC5\u586B\uFF09",
|
|
3498
|
-
example: "TWD"
|
|
3499
|
-
},
|
|
3500
|
-
area_codes: {
|
|
3501
|
-
type: "string[]",
|
|
3502
|
-
required: false,
|
|
3503
|
-
description: "\u5E0C\u671B\u5730\u9EDE\u4EE3\u78BC\uFF08\u591A\u9078\uFF09",
|
|
3504
|
-
example: ["6001005009", "6001006008"]
|
|
3505
|
-
},
|
|
3506
|
-
job_classification_codes: {
|
|
3507
|
-
type: "string[]",
|
|
3508
|
-
required: false,
|
|
3509
|
-
description: "\u5E0C\u671B\u8077\u985E\u4EE3\u78BC\uFF08\u591A\u9078\uFF09",
|
|
3510
|
-
example: ["2002002006", "2003002007"]
|
|
3511
|
-
}
|
|
3512
|
-
},
|
|
3513
|
-
crossFieldRules: [
|
|
3514
|
-
{
|
|
3515
|
-
name: "job-condition-available-start",
|
|
3516
|
-
message: 'When available_start_type_code is "available_custom_date", available_start_date is required. When it is "available_after_hired", available_start_period_code is required.',
|
|
3517
|
-
check(item) {
|
|
3518
|
-
const code = item.available_start_type_code;
|
|
3519
|
-
if (code === "available_custom_date") {
|
|
3520
|
-
const v = item.available_start_date;
|
|
3521
|
-
return v !== void 0 && v !== null && v !== "";
|
|
3522
|
-
}
|
|
3523
|
-
if (code === "available_after_hired") {
|
|
3524
|
-
const v = item.available_start_period_code;
|
|
3525
|
-
return v !== void 0 && v !== null && v !== "";
|
|
3526
|
-
}
|
|
3527
|
-
return true;
|
|
3528
|
-
}
|
|
3529
|
-
},
|
|
3530
|
-
{
|
|
3531
|
-
name: "job-condition-salary-expectation",
|
|
3532
|
-
message: 'When salary_expectation_type_code is "custom", salary_unit_code, salary_amount, and expected_salary_currency_code are all required.',
|
|
3533
|
-
check(item) {
|
|
3534
|
-
if (item.salary_expectation_type_code !== "custom") return true;
|
|
3535
|
-
const hasUnit = item.salary_unit_code !== void 0 && item.salary_unit_code !== null && item.salary_unit_code !== "";
|
|
3536
|
-
const hasAmount = typeof item.salary_amount === "number";
|
|
3537
|
-
const hasCurrency = typeof item.expected_salary_currency_code === "string" && item.expected_salary_currency_code.length > 0;
|
|
3538
|
-
return hasUnit && hasAmount && hasCurrency;
|
|
3539
|
-
}
|
|
3540
|
-
}
|
|
3541
|
-
]
|
|
3542
|
-
};
|
|
3543
|
-
var portfolioLinksSection = {
|
|
3544
|
-
key: "portfolio_links",
|
|
3545
|
-
kind: "array",
|
|
3546
|
-
maxItems: 5,
|
|
3547
|
-
description: "\u4F5C\u54C1\u96C6\u9023\u7D50\uFF0C\u6700\u591A 5 \u7B46",
|
|
3548
|
-
fields: {
|
|
3549
|
-
link_title: {
|
|
3550
|
-
type: "string",
|
|
3551
|
-
required: true,
|
|
3552
|
-
minLength: 1,
|
|
3553
|
-
maxLength: 50,
|
|
3554
|
-
description: "\u4F5C\u54C1\u96C6\u6A19\u984C",
|
|
3555
|
-
example: "My Portfolio"
|
|
3556
|
-
},
|
|
3557
|
-
link_url: {
|
|
3558
|
-
type: "string",
|
|
3559
|
-
required: true,
|
|
3560
|
-
minLength: 1,
|
|
3561
|
-
maxLength: 2083,
|
|
3562
|
-
description: "\u4F5C\u54C1\u96C6\u9023\u7D50\uFF08URL\uFF09",
|
|
3563
|
-
example: "https://myportfolio.com"
|
|
3564
|
-
}
|
|
3565
|
-
}
|
|
3566
|
-
};
|
|
3567
|
-
var backgroundSection = {
|
|
3568
|
-
key: "background",
|
|
3569
|
-
kind: "object",
|
|
3570
|
-
description: "\u80CC\u666F\u8CC7\u8A0A\uFF08\u99D5\u7167\uFF0F\u8ECA\u8F1B\uFF0F\u5175\u5F79\u72C0\u614B\uFF09",
|
|
3571
|
-
fields: {
|
|
3572
|
-
// identity_types(身分種類)刻意不列:屬會員個資唯讀例外(pm_27 欄位),寫聚合不收,
|
|
3573
|
-
// validate 對此鍵給 read-only 專屬訊息而非泛用 unknown-field(見 design doc §4.2)。
|
|
3574
|
-
driving_license_types: {
|
|
3575
|
-
type: "enum[]",
|
|
3576
|
-
required: false,
|
|
3577
|
-
enumValues: VEHICLE_OR_LICENSE_TYPE_VALUES,
|
|
3578
|
-
description: "\u99D5\u99DB\u57F7\u7167\u985E\u578B\u5217\u8868",
|
|
3579
|
-
example: ["scooter", "light_motorcycle"]
|
|
3580
|
-
},
|
|
3581
|
-
vehicle_types: {
|
|
3582
|
-
type: "enum[]",
|
|
3583
|
-
required: false,
|
|
3584
|
-
enumValues: VEHICLE_OR_LICENSE_TYPE_VALUES,
|
|
3585
|
-
description: "\u8ECA\u8F1B\u985E\u578B\u5217\u8868",
|
|
3586
|
-
example: ["scooter"]
|
|
3587
|
-
},
|
|
3588
|
-
job_status: {
|
|
3589
|
-
type: "enum",
|
|
3590
|
-
required: false,
|
|
3591
|
-
enumValues: JOB_STATUS_VALUES,
|
|
3592
|
-
description: "\u5DE5\u4F5C\u72C0\u614B",
|
|
3593
|
-
example: "employed"
|
|
3594
|
-
}
|
|
3595
|
-
}
|
|
3596
|
-
};
|
|
3597
|
-
var SECTIONS = [
|
|
3598
|
-
educationSection,
|
|
3599
|
-
workExperienceSection,
|
|
3600
|
-
certificateSection,
|
|
3601
|
-
languageSection,
|
|
3602
|
-
professionalSkillsSection,
|
|
3603
|
-
autobiographySection,
|
|
3604
|
-
jobConditionSection,
|
|
3605
|
-
portfolioLinksSection,
|
|
3606
|
-
backgroundSection
|
|
3607
|
-
];
|
|
3608
|
-
function getSection(key) {
|
|
3609
|
-
return SECTIONS.find((s) => s.key === key);
|
|
3610
|
-
}
|
|
3611
|
-
|
|
3612
|
-
// src/lib/resume-schema/to-json-schema.ts
|
|
3613
|
-
var JSON_SCHEMA_DRAFT = "http://json-schema.org/draft-07/schema#";
|
|
3614
|
-
function fieldDefToJsonSchema(field) {
|
|
3615
|
-
const out = {};
|
|
3616
|
-
switch (field.type) {
|
|
3617
|
-
case "string":
|
|
3618
|
-
out.type = "string";
|
|
3619
|
-
if (field.minLength !== void 0) out.minLength = field.minLength;
|
|
3620
|
-
if (field.maxLength !== void 0) out.maxLength = field.maxLength;
|
|
3621
|
-
break;
|
|
3622
|
-
case "number":
|
|
3623
|
-
out.type = "number";
|
|
3624
|
-
if (field.min !== void 0) out.minimum = field.min;
|
|
3625
|
-
if (field.max !== void 0) out.maximum = field.max;
|
|
3626
|
-
break;
|
|
3627
|
-
case "integer":
|
|
3628
|
-
out.type = "integer";
|
|
3629
|
-
if (field.min !== void 0) out.minimum = field.min;
|
|
3630
|
-
if (field.max !== void 0) out.maximum = field.max;
|
|
3631
|
-
break;
|
|
3632
|
-
case "boolean":
|
|
3633
|
-
out.type = "boolean";
|
|
3634
|
-
break;
|
|
3635
|
-
case "enum":
|
|
3636
|
-
out.type = "string";
|
|
3637
|
-
out.enum = field.enumValues ? [...field.enumValues] : [];
|
|
3638
|
-
break;
|
|
3639
|
-
case "string[]":
|
|
3640
|
-
out.type = "array";
|
|
3641
|
-
out.items = { type: "string" };
|
|
3642
|
-
if (field.minItems !== void 0) out.minItems = field.minItems;
|
|
3643
|
-
if (field.maxItems !== void 0) out.maxItems = field.maxItems;
|
|
3644
|
-
break;
|
|
3645
|
-
case "enum[]":
|
|
3646
|
-
out.type = "array";
|
|
3647
|
-
out.items = { type: "string", enum: field.enumValues ? [...field.enumValues] : [] };
|
|
3648
|
-
if (field.minItems !== void 0) out.minItems = field.minItems;
|
|
3649
|
-
if (field.maxItems !== void 0) out.maxItems = field.maxItems;
|
|
3650
|
-
break;
|
|
3651
|
-
case "date":
|
|
3652
|
-
out.type = "string";
|
|
3653
|
-
out.format = "date";
|
|
3654
|
-
break;
|
|
3655
|
-
}
|
|
3656
|
-
out.description = field.htmlText ? `${field.description}(\u5B57\u6578\u4E0A\u9650\u8A08\u7B97\u65B9\u5F0F:\u5148\u525D\u9664 HTML tag,\u4EE5\u7D14\u6587\u5B57\u9577\u5EA6\u8A08\u7B97)` : field.description;
|
|
3657
|
-
if (field.example !== void 0) out.example = field.example;
|
|
3658
|
-
return out;
|
|
3659
|
-
}
|
|
3660
|
-
function fieldsToPropertiesAndRequired(fields) {
|
|
3661
|
-
const properties = {};
|
|
3662
|
-
const required = [];
|
|
3663
|
-
for (const [key, field] of Object.entries(fields)) {
|
|
3664
|
-
properties[key] = fieldDefToJsonSchema(field);
|
|
3665
|
-
if (field.required) required.push(key);
|
|
3666
|
-
}
|
|
3667
|
-
return { properties, required };
|
|
3668
|
-
}
|
|
3669
|
-
function buildSectionSchema(section) {
|
|
3670
|
-
if (section.kind === "scalar") {
|
|
3671
|
-
return fieldDefToJsonSchema(section.valueDef);
|
|
3672
|
-
}
|
|
3673
|
-
if (section.kind === "object") {
|
|
3674
|
-
const { properties, required } = fieldsToPropertiesAndRequired(section.fields);
|
|
3675
|
-
return {
|
|
3676
|
-
type: "object",
|
|
3677
|
-
description: section.description,
|
|
3678
|
-
additionalProperties: false,
|
|
3679
|
-
required,
|
|
3680
|
-
properties
|
|
3681
|
-
};
|
|
3682
|
-
}
|
|
3683
|
-
if (section.kind === "array") {
|
|
3684
|
-
const { properties, required } = fieldsToPropertiesAndRequired(section.fields);
|
|
3685
|
-
const schema = {
|
|
3686
|
-
type: "array",
|
|
3687
|
-
description: section.description,
|
|
3688
|
-
items: { type: "object", additionalProperties: false, required, properties }
|
|
3689
|
-
};
|
|
3690
|
-
if (section.maxItems !== void 0) schema.maxItems = section.maxItems;
|
|
3691
|
-
return schema;
|
|
3692
|
-
}
|
|
3693
|
-
const wrapperParts = fieldsToPropertiesAndRequired(section.wrapperFields ?? {});
|
|
3694
|
-
const itemParts = fieldsToPropertiesAndRequired(section.fields);
|
|
3695
|
-
return {
|
|
3696
|
-
type: "object",
|
|
3697
|
-
description: section.description,
|
|
3698
|
-
additionalProperties: false,
|
|
3699
|
-
required: [...wrapperParts.required, "items"],
|
|
3700
|
-
properties: {
|
|
3701
|
-
...wrapperParts.properties,
|
|
3702
|
-
items: {
|
|
3703
|
-
type: "array",
|
|
3704
|
-
items: { type: "object", additionalProperties: false, required: itemParts.required, properties: itemParts.properties }
|
|
3705
|
-
}
|
|
3706
|
-
}
|
|
3707
|
-
};
|
|
3708
|
-
}
|
|
3709
|
-
function buildAggregateJsonSchema(sectionKey) {
|
|
3710
|
-
if (sectionKey !== void 0) {
|
|
3711
|
-
const section = getSection(sectionKey);
|
|
3712
|
-
if (!section) {
|
|
3713
|
-
const allowed = SECTIONS.map((s) => s.key).join(", ");
|
|
3714
|
-
throw new CliError(`Unknown section "${sectionKey}". Allowed: ${allowed}`, ExitCode.InvalidArgument);
|
|
3715
|
-
}
|
|
3716
|
-
return buildSectionSchema(section);
|
|
3717
|
-
}
|
|
3718
|
-
const properties = {
|
|
3719
|
-
name: fieldDefToJsonSchema(TOP_LEVEL_FIELDS.name)
|
|
3720
|
-
};
|
|
3721
|
-
for (const section of SECTIONS) {
|
|
3722
|
-
properties[section.key] = buildSectionSchema(section);
|
|
3723
|
-
}
|
|
3724
|
-
return {
|
|
3725
|
-
$schema: JSON_SCHEMA_DRAFT,
|
|
3726
|
-
title: "wport resume aggregate",
|
|
3727
|
-
description: "wport \u5C65\u6B77\u805A\u5408\u683C\u5F0F(\u4F9B personal resumes create/update/validate \u4F7F\u7528)\u3002view \u8F38\u51FA\u53E6\u542B\u552F\u8B80\u7684 photo_url(\u6703\u54E1\u500B\u8CC7),\u4E0D\u5728\u6B64\u5BEB\u5165\u805A\u5408 schema \u5167,\u5982\u9700\u66F4\u65B0\u8ACB\u8D70 profile \u76F8\u95DC\u6D41\u7A0B\u3002",
|
|
3728
|
-
type: "object",
|
|
3729
|
-
additionalProperties: false,
|
|
3730
|
-
required: ["name"],
|
|
3731
|
-
properties
|
|
3732
|
-
};
|
|
3733
|
-
}
|
|
3734
|
-
|
|
3735
2940
|
// src/commands/personal/resumes/schema.ts
|
|
2941
|
+
var import_core36 = require("@wport/core");
|
|
3736
2942
|
function registerPersonalResumesSchema(parent) {
|
|
3737
2943
|
parent.command("schema").description("Print the resume aggregate JSON Schema (offline, no login required)").option("--section <name>", "print only the given section (e.g. education, work_experience)").action((opts) => {
|
|
3738
|
-
printJson(buildAggregateJsonSchema(opts.section));
|
|
3739
|
-
});
|
|
3740
|
-
}
|
|
3741
|
-
|
|
3742
|
-
// src/lib/resume-schema/validate.ts
|
|
3743
|
-
var TOP_LEVEL_READ_ONLY_KEYS = /* @__PURE__ */ new Set(["photo_url"]);
|
|
3744
|
-
var BACKGROUND_READ_ONLY_KEYS = /* @__PURE__ */ new Set(["identity_types"]);
|
|
3745
|
-
var NO_READ_ONLY_KEYS = /* @__PURE__ */ new Set();
|
|
3746
|
-
function itemAllowedKeys(fields) {
|
|
3747
|
-
return /* @__PURE__ */ new Set([...Object.keys(fields), "enc_id"]);
|
|
3748
|
-
}
|
|
3749
|
-
function isPlainObject(value) {
|
|
3750
|
-
return typeof value === "object" && value !== null && !Array.isArray(value);
|
|
3751
|
-
}
|
|
3752
|
-
function describeType(value) {
|
|
3753
|
-
if (value === null) return "null";
|
|
3754
|
-
if (Array.isArray(value)) return "an array";
|
|
3755
|
-
return typeof value;
|
|
3756
|
-
}
|
|
3757
|
-
function unknownFieldMessage(key) {
|
|
3758
|
-
return `Unknown field "${key}" \u2014 not part of the resume schema`;
|
|
3759
|
-
}
|
|
3760
|
-
function readOnlyFieldMessage(key) {
|
|
3761
|
-
return `Field "${key}" is read-only (member profile data) \u2014 not part of the resume write aggregate`;
|
|
3762
|
-
}
|
|
3763
|
-
function stripHtml2(s) {
|
|
3764
|
-
return s.replace(/<[^>]*>/g, "");
|
|
3765
|
-
}
|
|
3766
|
-
function isValidDateString(s) {
|
|
3767
|
-
if (!/^\d{4}-\d{2}-\d{2}$/.test(s)) return false;
|
|
3768
|
-
const [y, m, d] = s.split("-").map(Number);
|
|
3769
|
-
const date = new Date(Date.UTC(y, m - 1, d));
|
|
3770
|
-
return date.getUTCFullYear() === y && date.getUTCMonth() === m - 1 && date.getUTCDate() === d;
|
|
3771
|
-
}
|
|
3772
|
-
function checkUnknownKeys(obj, allowedKeys, readOnlyKeys, pathFor, issues) {
|
|
3773
|
-
for (const key of Object.keys(obj)) {
|
|
3774
|
-
if (allowedKeys.has(key)) continue;
|
|
3775
|
-
if (readOnlyKeys.has(key)) {
|
|
3776
|
-
issues.push({ path: pathFor(key), message: readOnlyFieldMessage(key) });
|
|
3777
|
-
continue;
|
|
3778
|
-
}
|
|
3779
|
-
issues.push({ path: pathFor(key), message: unknownFieldMessage(key) });
|
|
3780
|
-
}
|
|
3781
|
-
}
|
|
3782
|
-
function checkFieldValue(field, value, path, issues) {
|
|
3783
|
-
switch (field.type) {
|
|
3784
|
-
case "string": {
|
|
3785
|
-
if (typeof value !== "string") {
|
|
3786
|
-
issues.push({ path, message: `Expected a string (got ${describeType(value)})` });
|
|
3787
|
-
return;
|
|
3788
|
-
}
|
|
3789
|
-
const text = field.htmlText ? stripHtml2(value) : value;
|
|
3790
|
-
if (field.minLength !== void 0 && text.length < field.minLength) {
|
|
3791
|
-
issues.push({ path, message: `Must be at least ${field.minLength} characters (got ${text.length})` });
|
|
3792
|
-
}
|
|
3793
|
-
if (field.maxLength !== void 0 && text.length > field.maxLength) {
|
|
3794
|
-
issues.push({ path, message: `Must be at most ${field.maxLength} characters (got ${text.length})` });
|
|
3795
|
-
}
|
|
3796
|
-
return;
|
|
3797
|
-
}
|
|
3798
|
-
case "number": {
|
|
3799
|
-
if (typeof value !== "number" || Number.isNaN(value)) {
|
|
3800
|
-
issues.push({ path, message: `Expected a number (got ${describeType(value)})` });
|
|
3801
|
-
return;
|
|
3802
|
-
}
|
|
3803
|
-
checkRange(field, value, path, issues);
|
|
3804
|
-
return;
|
|
3805
|
-
}
|
|
3806
|
-
case "integer": {
|
|
3807
|
-
if (typeof value !== "number" || !Number.isInteger(value)) {
|
|
3808
|
-
issues.push({ path, message: `Expected an integer (got ${describeType(value)})` });
|
|
3809
|
-
return;
|
|
3810
|
-
}
|
|
3811
|
-
checkRange(field, value, path, issues);
|
|
3812
|
-
return;
|
|
3813
|
-
}
|
|
3814
|
-
case "boolean": {
|
|
3815
|
-
if (typeof value !== "boolean") issues.push({ path, message: `Expected a boolean (got ${describeType(value)})` });
|
|
3816
|
-
return;
|
|
3817
|
-
}
|
|
3818
|
-
case "enum": {
|
|
3819
|
-
const allowed = field.enumValues ?? [];
|
|
3820
|
-
if (typeof value !== "string" || !allowed.includes(value)) {
|
|
3821
|
-
issues.push({ path, message: `Invalid value ${JSON.stringify(value)} \u2014 allowed: ${allowed.join(", ")}` });
|
|
3822
|
-
}
|
|
3823
|
-
return;
|
|
3824
|
-
}
|
|
3825
|
-
case "string[]": {
|
|
3826
|
-
if (!Array.isArray(value)) {
|
|
3827
|
-
issues.push({ path, message: `Expected an array (got ${describeType(value)})` });
|
|
3828
|
-
return;
|
|
3829
|
-
}
|
|
3830
|
-
value.forEach((v, i) => {
|
|
3831
|
-
if (typeof v !== "string") issues.push({ path: `${path}[${i}]`, message: `Expected a string (got ${describeType(v)})` });
|
|
3832
|
-
});
|
|
3833
|
-
checkItemsCount(field, value, path, issues);
|
|
3834
|
-
return;
|
|
3835
|
-
}
|
|
3836
|
-
case "enum[]": {
|
|
3837
|
-
const allowed = field.enumValues ?? [];
|
|
3838
|
-
if (!Array.isArray(value)) {
|
|
3839
|
-
issues.push({ path, message: `Expected an array (got ${describeType(value)})` });
|
|
3840
|
-
return;
|
|
3841
|
-
}
|
|
3842
|
-
value.forEach((v, i) => {
|
|
3843
|
-
if (typeof v !== "string" || !allowed.includes(v)) {
|
|
3844
|
-
issues.push({ path: `${path}[${i}]`, message: `Invalid value ${JSON.stringify(v)} \u2014 allowed: ${allowed.join(", ")}` });
|
|
3845
|
-
}
|
|
3846
|
-
});
|
|
3847
|
-
checkItemsCount(field, value, path, issues);
|
|
3848
|
-
return;
|
|
3849
|
-
}
|
|
3850
|
-
case "date": {
|
|
3851
|
-
if (typeof value !== "string" || !isValidDateString(value)) {
|
|
3852
|
-
issues.push({ path, message: `Expected a date string in YYYY-MM-DD format (got ${JSON.stringify(value)})` });
|
|
3853
|
-
}
|
|
3854
|
-
return;
|
|
3855
|
-
}
|
|
3856
|
-
}
|
|
3857
|
-
}
|
|
3858
|
-
function checkRange(field, value, path, issues) {
|
|
3859
|
-
if (field.min !== void 0 && value < field.min) issues.push({ path, message: `Must be >= ${field.min} (got ${value})` });
|
|
3860
|
-
if (field.max !== void 0 && value > field.max) issues.push({ path, message: `Must be <= ${field.max} (got ${value})` });
|
|
3861
|
-
}
|
|
3862
|
-
function checkItemsCount(field, value, path, issues) {
|
|
3863
|
-
if (field.minItems !== void 0 && value.length < field.minItems) {
|
|
3864
|
-
issues.push({ path, message: `Must have at least ${field.minItems} item(s) (got ${value.length})` });
|
|
3865
|
-
}
|
|
3866
|
-
if (field.maxItems !== void 0 && value.length > field.maxItems) {
|
|
3867
|
-
issues.push({ path, message: `Must have at most ${field.maxItems} item(s) (got ${value.length})` });
|
|
3868
|
-
}
|
|
3869
|
-
}
|
|
3870
|
-
function checkFields(obj, fields, pathFor, issues) {
|
|
3871
|
-
for (const [key, field] of Object.entries(fields)) {
|
|
3872
|
-
const value = obj[key];
|
|
3873
|
-
const path = pathFor(key);
|
|
3874
|
-
if (value === void 0) {
|
|
3875
|
-
if (field.required) issues.push({ path, message: `Missing required field "${key}"` });
|
|
3876
|
-
continue;
|
|
3877
|
-
}
|
|
3878
|
-
checkFieldValue(field, value, path, issues);
|
|
3879
|
-
}
|
|
3880
|
-
}
|
|
3881
|
-
function checkCrossFieldRules(rules, item, path, issues) {
|
|
3882
|
-
for (const rule of rules ?? []) {
|
|
3883
|
-
if (!rule.check(item)) issues.push({ path, message: rule.message });
|
|
3884
|
-
}
|
|
3885
|
-
}
|
|
3886
|
-
function validateArraySection(section, value, issues) {
|
|
3887
|
-
const path = section.key;
|
|
3888
|
-
if (!Array.isArray(value)) {
|
|
3889
|
-
issues.push({ path, message: `Expected an array (got ${describeType(value)})` });
|
|
3890
|
-
return;
|
|
3891
|
-
}
|
|
3892
|
-
if (section.maxItems !== void 0 && value.length > section.maxItems) {
|
|
3893
|
-
issues.push({ path, message: `Must have at most ${section.maxItems} item(s) (got ${value.length})` });
|
|
3894
|
-
}
|
|
3895
|
-
value.forEach((item, i) => {
|
|
3896
|
-
const itemPath = `${path}[${i}]`;
|
|
3897
|
-
if (!isPlainObject(item)) {
|
|
3898
|
-
issues.push({ path: itemPath, message: `Expected an object (got ${describeType(item)})` });
|
|
3899
|
-
return;
|
|
3900
|
-
}
|
|
3901
|
-
checkUnknownKeys(item, itemAllowedKeys(section.fields), NO_READ_ONLY_KEYS, (k) => `${itemPath}.${k}`, issues);
|
|
3902
|
-
checkFields(item, section.fields, (k) => `${itemPath}.${k}`, issues);
|
|
3903
|
-
checkCrossFieldRules(section.crossFieldRules, item, itemPath, issues);
|
|
2944
|
+
printJson((0, import_core36.buildAggregateJsonSchema)(opts.section));
|
|
3904
2945
|
});
|
|
3905
2946
|
}
|
|
3906
|
-
function validateObjectSection(section, value, issues) {
|
|
3907
|
-
const path = section.key;
|
|
3908
|
-
if (!isPlainObject(value)) {
|
|
3909
|
-
issues.push({ path, message: `Expected an object (got ${describeType(value)})` });
|
|
3910
|
-
return;
|
|
3911
|
-
}
|
|
3912
|
-
const readOnly = section.key === "background" ? BACKGROUND_READ_ONLY_KEYS : NO_READ_ONLY_KEYS;
|
|
3913
|
-
checkUnknownKeys(value, new Set(Object.keys(section.fields)), readOnly, (k) => `${path}.${k}`, issues);
|
|
3914
|
-
checkFields(value, section.fields, (k) => `${path}.${k}`, issues);
|
|
3915
|
-
checkCrossFieldRules(section.crossFieldRules, value, path, issues);
|
|
3916
|
-
}
|
|
3917
|
-
function validateScalarSection(section, value, issues) {
|
|
3918
|
-
checkFieldValue(section.valueDef, value, section.key, issues);
|
|
3919
|
-
}
|
|
3920
|
-
function validateWrapperSection(section, value, issues) {
|
|
3921
|
-
const path = section.key;
|
|
3922
|
-
if (!isPlainObject(value)) {
|
|
3923
|
-
issues.push({ path, message: `Expected an object (got ${describeType(value)})` });
|
|
3924
|
-
return;
|
|
3925
|
-
}
|
|
3926
|
-
const wrapperFields = section.wrapperFields ?? {};
|
|
3927
|
-
const allowedTopKeys = /* @__PURE__ */ new Set([...Object.keys(wrapperFields), "items"]);
|
|
3928
|
-
checkUnknownKeys(value, allowedTopKeys, NO_READ_ONLY_KEYS, (k) => `${path}.${k}`, issues);
|
|
3929
|
-
checkFields(value, wrapperFields, (k) => `${path}.${k}`, issues);
|
|
3930
|
-
const items = value.items;
|
|
3931
|
-
const itemsPath = `${path}.items`;
|
|
3932
|
-
if (items === void 0) {
|
|
3933
|
-
issues.push({ path: itemsPath, message: 'Missing required field "items"' });
|
|
3934
|
-
} else if (!Array.isArray(items)) {
|
|
3935
|
-
issues.push({ path: itemsPath, message: `Expected an array (got ${describeType(items)})` });
|
|
3936
|
-
} else {
|
|
3937
|
-
items.forEach((item, i) => {
|
|
3938
|
-
const itemPath = `${itemsPath}[${i}]`;
|
|
3939
|
-
if (!isPlainObject(item)) {
|
|
3940
|
-
issues.push({ path: itemPath, message: `Expected an object (got ${describeType(item)})` });
|
|
3941
|
-
return;
|
|
3942
|
-
}
|
|
3943
|
-
checkUnknownKeys(item, itemAllowedKeys(section.fields), NO_READ_ONLY_KEYS, (k) => `${itemPath}.${k}`, issues);
|
|
3944
|
-
checkFields(item, section.fields, (k) => `${itemPath}.${k}`, issues);
|
|
3945
|
-
checkCrossFieldRules(section.crossFieldRules, item, itemPath, issues);
|
|
3946
|
-
});
|
|
3947
|
-
}
|
|
3948
|
-
checkCrossFieldRules(section.crossFieldRules, value, path, issues);
|
|
3949
|
-
}
|
|
3950
|
-
function validateAggregate(input) {
|
|
3951
|
-
if (!isPlainObject(input)) {
|
|
3952
|
-
return [{ path: "(root)", message: `Input must be a JSON object at the top level (got ${describeType(input)})` }];
|
|
3953
|
-
}
|
|
3954
|
-
const issues = [];
|
|
3955
|
-
const allowedTopKeys = /* @__PURE__ */ new Set(["name", ...SECTIONS.map((s) => s.key)]);
|
|
3956
|
-
checkUnknownKeys(input, allowedTopKeys, TOP_LEVEL_READ_ONLY_KEYS, (k) => k, issues);
|
|
3957
|
-
checkFields(input, TOP_LEVEL_FIELDS, (k) => k, issues);
|
|
3958
|
-
for (const section of SECTIONS) {
|
|
3959
|
-
const value = input[section.key];
|
|
3960
|
-
if (value === void 0) continue;
|
|
3961
|
-
switch (section.kind) {
|
|
3962
|
-
case "array":
|
|
3963
|
-
validateArraySection(section, value, issues);
|
|
3964
|
-
break;
|
|
3965
|
-
case "object":
|
|
3966
|
-
validateObjectSection(section, value, issues);
|
|
3967
|
-
break;
|
|
3968
|
-
case "scalar":
|
|
3969
|
-
validateScalarSection(section, value, issues);
|
|
3970
|
-
break;
|
|
3971
|
-
case "wrapper":
|
|
3972
|
-
validateWrapperSection(section, value, issues);
|
|
3973
|
-
break;
|
|
3974
|
-
}
|
|
3975
|
-
}
|
|
3976
|
-
return issues;
|
|
3977
|
-
}
|
|
3978
2947
|
|
|
3979
2948
|
// src/commands/personal/resumes/validate.ts
|
|
2949
|
+
var import_core37 = require("@wport/core");
|
|
3980
2950
|
function runResumesValidate(ctx, filePath) {
|
|
3981
2951
|
const input = readJsonInput(filePath, { timeoutMs: ctx.timeoutMs });
|
|
3982
|
-
const issues = validateAggregate(input);
|
|
2952
|
+
const issues = (0, import_core37.validateAggregate)(input);
|
|
3983
2953
|
if (issues.length === 0) {
|
|
3984
2954
|
if (ctx.format === "json") {
|
|
3985
2955
|
printJson({ valid: true });
|
|
@@ -4007,43 +2977,9 @@ function registerPersonalResumesValidate(parent) {
|
|
|
4007
2977
|
|
|
4008
2978
|
// src/commands/personal/resumes/template.ts
|
|
4009
2979
|
var import_node_fs8 = require("fs");
|
|
4010
|
-
|
|
4011
|
-
// src/lib/resume-schema/template.ts
|
|
4012
|
-
function buildFieldsExample(fields) {
|
|
4013
|
-
const out = {};
|
|
4014
|
-
for (const [key, field] of Object.entries(fields)) {
|
|
4015
|
-
if (field.example !== void 0) out[key] = field.example;
|
|
4016
|
-
}
|
|
4017
|
-
return out;
|
|
4018
|
-
}
|
|
4019
|
-
function buildSectionTemplate(section) {
|
|
4020
|
-
switch (section.kind) {
|
|
4021
|
-
case "scalar":
|
|
4022
|
-
return section.valueDef.example;
|
|
4023
|
-
case "object":
|
|
4024
|
-
return buildFieldsExample(section.fields);
|
|
4025
|
-
case "array":
|
|
4026
|
-
return [buildFieldsExample(section.fields)];
|
|
4027
|
-
case "wrapper":
|
|
4028
|
-
return {
|
|
4029
|
-
...buildFieldsExample(section.wrapperFields ?? {}),
|
|
4030
|
-
items: [buildFieldsExample(section.fields)]
|
|
4031
|
-
};
|
|
4032
|
-
}
|
|
4033
|
-
}
|
|
4034
|
-
function buildTemplate() {
|
|
4035
|
-
const template = {
|
|
4036
|
-
name: TOP_LEVEL_FIELDS.name.example
|
|
4037
|
-
};
|
|
4038
|
-
for (const section of SECTIONS) {
|
|
4039
|
-
template[section.key] = buildSectionTemplate(section);
|
|
4040
|
-
}
|
|
4041
|
-
return template;
|
|
4042
|
-
}
|
|
4043
|
-
|
|
4044
|
-
// src/commands/personal/resumes/template.ts
|
|
2980
|
+
var import_core38 = require("@wport/core");
|
|
4045
2981
|
function runResumesTemplate(outPath) {
|
|
4046
|
-
const template = buildTemplate();
|
|
2982
|
+
const template = (0, import_core38.buildTemplate)();
|
|
4047
2983
|
if (outPath === void 0) {
|
|
4048
2984
|
printJson(template);
|
|
4049
2985
|
return;
|
|
@@ -4067,6 +3003,8 @@ function registerPersonalResumesTemplate(parent) {
|
|
|
4067
3003
|
}
|
|
4068
3004
|
|
|
4069
3005
|
// src/commands/personal/resumes/list.ts
|
|
3006
|
+
var import_core39 = require("@wport/core");
|
|
3007
|
+
var import_core40 = require("@wport/core");
|
|
4070
3008
|
var MINIMAL_LIST_FIELDS4 = ["enc_id", "name", "updated_at", "is_complete", "is_published"];
|
|
4071
3009
|
function formatDate6(value) {
|
|
4072
3010
|
return value ? String(value).slice(0, 10) : "";
|
|
@@ -4076,8 +3014,8 @@ function formatQuotaLine(quota) {
|
|
|
4076
3014
|
return `${quota.used}/${quota.max_resumes} used, ${status}.`;
|
|
4077
3015
|
}
|
|
4078
3016
|
async function fetchResumeList(opts) {
|
|
4079
|
-
const { body } = await personalGet(opts, PERSONAL_RESUMES_BASE);
|
|
4080
|
-
return unwrapDataResponse(body);
|
|
3017
|
+
const { body } = await personalGet(opts, import_core40.PERSONAL_RESUMES_BASE);
|
|
3018
|
+
return (0, import_core39.unwrapDataResponse)(body);
|
|
4081
3019
|
}
|
|
4082
3020
|
async function runResumesList(ctx, flags) {
|
|
4083
3021
|
if (flags.fields && flags.minimal) {
|
|
@@ -4110,17 +3048,20 @@ function registerPersonalResumesList(parent) {
|
|
|
4110
3048
|
}
|
|
4111
3049
|
|
|
4112
3050
|
// src/commands/personal/resumes/view.ts
|
|
3051
|
+
var import_core41 = require("@wport/core");
|
|
3052
|
+
var import_core42 = require("@wport/core");
|
|
3053
|
+
var import_core43 = require("@wport/core");
|
|
4113
3054
|
async function fetchResumeAggregate(opts, encId) {
|
|
4114
3055
|
const trimmed = encId.trim();
|
|
4115
3056
|
if (!trimmed) {
|
|
4116
3057
|
throw new CliError("enc_id must not be empty", ExitCode.InvalidArgument);
|
|
4117
3058
|
}
|
|
4118
|
-
const { body } = await personalGet(opts, `${PERSONAL_RESUMES_BASE}/${encodeURIComponent(trimmed)}`);
|
|
4119
|
-
return unwrapDataResponse(body);
|
|
3059
|
+
const { body } = await personalGet(opts, `${import_core42.PERSONAL_RESUMES_BASE}/${encodeURIComponent(trimmed)}`);
|
|
3060
|
+
return (0, import_core41.unwrapDataResponse)(body);
|
|
4120
3061
|
}
|
|
4121
3062
|
function summarizeSections(resume) {
|
|
4122
3063
|
const rows = [{ section: "name", summary: resume.name }];
|
|
4123
|
-
for (const def of SECTIONS) {
|
|
3064
|
+
for (const def of import_core43.SECTIONS) {
|
|
4124
3065
|
rows.push({ section: def.key, summary: summarizeSection(def, resume) });
|
|
4125
3066
|
}
|
|
4126
3067
|
return rows;
|
|
@@ -4197,8 +3138,14 @@ function registerPersonalResumesExport(parent) {
|
|
|
4197
3138
|
});
|
|
4198
3139
|
}
|
|
4199
3140
|
|
|
3141
|
+
// src/commands/personal/resumes/create.ts
|
|
3142
|
+
var import_core47 = require("@wport/core");
|
|
3143
|
+
|
|
4200
3144
|
// src/lib/resume-orchestrator.ts
|
|
4201
3145
|
var import_node_crypto11 = require("crypto");
|
|
3146
|
+
var import_core44 = require("@wport/core");
|
|
3147
|
+
var import_core45 = require("@wport/core");
|
|
3148
|
+
var import_core46 = require("@wport/core");
|
|
4202
3149
|
function freshIdempotencyKey() {
|
|
4203
3150
|
return { idempotencyKey: (0, import_node_crypto11.randomUUID)() };
|
|
4204
3151
|
}
|
|
@@ -4213,8 +3160,8 @@ function extractErrorCode(body) {
|
|
|
4213
3160
|
}
|
|
4214
3161
|
async function createShell(opts) {
|
|
4215
3162
|
try {
|
|
4216
|
-
const { body } = await personalPost(opts, PERSONAL_RESUMES_BASE, {}, freshIdempotencyKey());
|
|
4217
|
-
return unwrapDataResponse(body).enc_id;
|
|
3163
|
+
const { body } = await personalPost(opts, import_core45.PERSONAL_RESUMES_BASE, {}, freshIdempotencyKey());
|
|
3164
|
+
return (0, import_core44.unwrapDataResponse)(body).enc_id;
|
|
4218
3165
|
} catch (err) {
|
|
4219
3166
|
if (err instanceof ServerClientHttpError) {
|
|
4220
3167
|
const code = extractErrorCode(err.body);
|
|
@@ -4235,7 +3182,7 @@ async function createShell(opts) {
|
|
|
4235
3182
|
}
|
|
4236
3183
|
}
|
|
4237
3184
|
async function renameResume(opts, encId, name) {
|
|
4238
|
-
await personalPut(opts, `${PERSONAL_RESUMES_BASE}/${encodeURIComponent(encId)}/name`, { name }, freshIdempotencyKey());
|
|
3185
|
+
await personalPut(opts, `${import_core45.PERSONAL_RESUMES_BASE}/${encodeURIComponent(encId)}/name`, { name }, freshIdempotencyKey());
|
|
4239
3186
|
}
|
|
4240
3187
|
function toWorkExperienceWriteItem(item) {
|
|
4241
3188
|
const { is_current, ...rest } = item;
|
|
@@ -4247,8 +3194,8 @@ function splitItemEncId(item) {
|
|
|
4247
3194
|
return [valid, rest];
|
|
4248
3195
|
}
|
|
4249
3196
|
async function writeSection(opts, encId, key, value, mode) {
|
|
4250
|
-
const plan = SECTION_WRITE_PLAN[key];
|
|
4251
|
-
const base = `${PERSONAL_RESUMES_BASE}/${encodeURIComponent(encId)}`;
|
|
3197
|
+
const plan = import_core45.SECTION_WRITE_PLAN[key];
|
|
3198
|
+
const base = `${import_core45.PERSONAL_RESUMES_BASE}/${encodeURIComponent(encId)}`;
|
|
4252
3199
|
switch (plan.kind) {
|
|
4253
3200
|
case "per-item-post": {
|
|
4254
3201
|
for (const item of value) {
|
|
@@ -4315,7 +3262,7 @@ async function createAggregate(opts, aggregate) {
|
|
|
4315
3262
|
if (aggregate.name !== void 0) {
|
|
4316
3263
|
reports.push(await attemptStep("name", () => renameResume(opts, encId, aggregate.name)));
|
|
4317
3264
|
}
|
|
4318
|
-
for (const section of SECTIONS) {
|
|
3265
|
+
for (const section of import_core46.SECTIONS) {
|
|
4319
3266
|
const value = aggregate[section.key];
|
|
4320
3267
|
if (value === void 0) continue;
|
|
4321
3268
|
reports.push(await attemptStep(section.key, () => writeSection(opts, encId, section.key, value, "create")));
|
|
@@ -4325,9 +3272,9 @@ async function createAggregate(opts, aggregate) {
|
|
|
4325
3272
|
async function updateAggregate(opts, encId, aggregate, onlySection) {
|
|
4326
3273
|
const reports = [];
|
|
4327
3274
|
if (onlySection !== void 0) {
|
|
4328
|
-
const section = getSection(onlySection);
|
|
3275
|
+
const section = (0, import_core46.getSection)(onlySection);
|
|
4329
3276
|
if (!section) {
|
|
4330
|
-
const allowed = SECTIONS.map((s) => s.key).join(", ");
|
|
3277
|
+
const allowed = import_core46.SECTIONS.map((s) => s.key).join(", ");
|
|
4331
3278
|
throw new CliError(`Unknown section "${onlySection}". Allowed: ${allowed}`, ExitCode.InvalidArgument);
|
|
4332
3279
|
}
|
|
4333
3280
|
const value = aggregate[onlySection];
|
|
@@ -4340,7 +3287,7 @@ async function updateAggregate(opts, encId, aggregate, onlySection) {
|
|
|
4340
3287
|
if (aggregate.name !== void 0) {
|
|
4341
3288
|
reports.push(await attemptStep("name", () => renameResume(opts, encId, aggregate.name)));
|
|
4342
3289
|
}
|
|
4343
|
-
for (const section of SECTIONS) {
|
|
3290
|
+
for (const section of import_core46.SECTIONS) {
|
|
4344
3291
|
const value = aggregate[section.key];
|
|
4345
3292
|
if (value === void 0) continue;
|
|
4346
3293
|
reports.push(await attemptStep(section.key, () => writeSection(opts, encId, section.key, value, "update")));
|
|
@@ -4351,7 +3298,7 @@ async function updateAggregate(opts, encId, aggregate, onlySection) {
|
|
|
4351
3298
|
// src/commands/personal/resumes/create.ts
|
|
4352
3299
|
async function runResumesCreate(ctx, filePath) {
|
|
4353
3300
|
const input = readJsonObject(filePath, { timeoutMs: ctx.timeoutMs });
|
|
4354
|
-
const issues = validateAggregate(input);
|
|
3301
|
+
const issues = (0, import_core47.validateAggregate)(input);
|
|
4355
3302
|
if (issues.length > 0) {
|
|
4356
3303
|
if (ctx.format === "json") {
|
|
4357
3304
|
printJson({ valid: false, issues });
|
|
@@ -4444,6 +3391,8 @@ function registerPersonalResumesUpdate(parent) {
|
|
|
4444
3391
|
|
|
4445
3392
|
// src/commands/personal/resumes/copy.ts
|
|
4446
3393
|
var import_node_crypto12 = require("crypto");
|
|
3394
|
+
var import_core48 = require("@wport/core");
|
|
3395
|
+
var import_core49 = require("@wport/core");
|
|
4447
3396
|
function requireEncId3(encId) {
|
|
4448
3397
|
const trimmed = encId.trim();
|
|
4449
3398
|
if (!trimmed) {
|
|
@@ -4462,12 +3411,12 @@ function printCopyResult(ctx, sourceEncId, newEncId) {
|
|
|
4462
3411
|
async function runResumesCopy(ctx, encId, name) {
|
|
4463
3412
|
const trimmed = requireEncId3(encId);
|
|
4464
3413
|
const opts = { baseUrl: ctx.baseUrl, locale: ctx.locale, timeoutMs: ctx.timeoutMs };
|
|
4465
|
-
const { body } = await personalPost(opts, `${PERSONAL_RESUMES_BASE}/${encodeURIComponent(trimmed)}/duplicate`, {}, { idempotencyKey: (0, import_node_crypto12.randomUUID)() });
|
|
4466
|
-
const { enc_id: newEncId } = unwrapDataResponse(body);
|
|
3414
|
+
const { body } = await personalPost(opts, `${import_core49.PERSONAL_RESUMES_BASE}/${encodeURIComponent(trimmed)}/duplicate`, {}, { idempotencyKey: (0, import_node_crypto12.randomUUID)() });
|
|
3415
|
+
const { enc_id: newEncId } = (0, import_core48.unwrapDataResponse)(body);
|
|
4467
3416
|
printCopyResult(ctx, trimmed, newEncId);
|
|
4468
3417
|
if (name === void 0) return;
|
|
4469
3418
|
try {
|
|
4470
|
-
await personalPut(opts, `${PERSONAL_RESUMES_BASE}/${encodeURIComponent(newEncId)}/name`, { name }, { idempotencyKey: (0, import_node_crypto12.randomUUID)() });
|
|
3419
|
+
await personalPut(opts, `${import_core49.PERSONAL_RESUMES_BASE}/${encodeURIComponent(newEncId)}/name`, { name }, { idempotencyKey: (0, import_node_crypto12.randomUUID)() });
|
|
4471
3420
|
} catch (err) {
|
|
4472
3421
|
const reason = err instanceof Error ? err.message : String(err);
|
|
4473
3422
|
throw new CliError(
|
|
@@ -4484,6 +3433,8 @@ function registerPersonalResumesCopy(parent) {
|
|
|
4484
3433
|
|
|
4485
3434
|
// src/commands/personal/resumes/publish.ts
|
|
4486
3435
|
var import_node_crypto13 = require("crypto");
|
|
3436
|
+
var import_core50 = require("@wport/core");
|
|
3437
|
+
var import_core51 = require("@wport/core");
|
|
4487
3438
|
function requireEncId4(encId) {
|
|
4488
3439
|
const trimmed = encId.trim();
|
|
4489
3440
|
if (!trimmed) {
|
|
@@ -4497,11 +3448,11 @@ async function runResumesPublishTransition(ctx, encId, action) {
|
|
|
4497
3448
|
const targetStatus = action === "publish";
|
|
4498
3449
|
const { body } = await personalPatch(
|
|
4499
3450
|
opts,
|
|
4500
|
-
`${PERSONAL_RESUMES_BASE}/${encodeURIComponent(trimmed)}/published-status`,
|
|
3451
|
+
`${import_core51.PERSONAL_RESUMES_BASE}/${encodeURIComponent(trimmed)}/published-status`,
|
|
4501
3452
|
{ target_status: targetStatus },
|
|
4502
3453
|
{ idempotencyKey: (0, import_node_crypto13.randomUUID)() }
|
|
4503
3454
|
);
|
|
4504
|
-
const result = unwrapDataResponse(body);
|
|
3455
|
+
const result = (0, import_core50.unwrapDataResponse)(body);
|
|
4505
3456
|
if (ctx.format === "json") {
|
|
4506
3457
|
printJson({ enc_id: trimmed, is_published: result.is_published });
|
|
4507
3458
|
return;
|
|
@@ -4523,6 +3474,7 @@ function registerPersonalResumesUnpublish(parent) {
|
|
|
4523
3474
|
|
|
4524
3475
|
// src/commands/personal/resumes/delete.ts
|
|
4525
3476
|
var import_node_crypto14 = require("crypto");
|
|
3477
|
+
var import_core52 = require("@wport/core");
|
|
4526
3478
|
function requireEncId5(encId) {
|
|
4527
3479
|
const trimmed = encId.trim();
|
|
4528
3480
|
if (!trimmed) {
|
|
@@ -4536,7 +3488,7 @@ async function runResumesDelete(ctx, encId, confirm) {
|
|
|
4536
3488
|
}
|
|
4537
3489
|
const trimmed = requireEncId5(encId);
|
|
4538
3490
|
const opts = { baseUrl: ctx.baseUrl, locale: ctx.locale, timeoutMs: ctx.timeoutMs };
|
|
4539
|
-
await personalDelete(opts, `${PERSONAL_RESUMES_BASE}/${encodeURIComponent(trimmed)}`, { idempotencyKey: (0, import_node_crypto14.randomUUID)() });
|
|
3491
|
+
await personalDelete(opts, `${import_core52.PERSONAL_RESUMES_BASE}/${encodeURIComponent(trimmed)}`, { idempotencyKey: (0, import_node_crypto14.randomUUID)() });
|
|
4540
3492
|
if (ctx.format === "json") {
|
|
4541
3493
|
printJson({ enc_id: trimmed, deleted: true });
|
|
4542
3494
|
return;
|
|
@@ -4570,6 +3522,7 @@ function registerPersonalResumesCommand(parent) {
|
|
|
4570
3522
|
// src/commands/personal/apply/index.ts
|
|
4571
3523
|
var import_node_crypto15 = require("crypto");
|
|
4572
3524
|
var import_node_fs11 = require("fs");
|
|
3525
|
+
var import_core53 = require("@wport/core");
|
|
4573
3526
|
|
|
4574
3527
|
// src/commands/personal/apply/message-input.ts
|
|
4575
3528
|
var import_node_fs10 = require("fs");
|
|
@@ -4651,7 +3604,7 @@ async function runPersonalApply(ctx, args) {
|
|
|
4651
3604
|
const body = { enc_job_id: args.encJobId, enc_resume_id: args.encResumeId, application_message: args.message };
|
|
4652
3605
|
let result;
|
|
4653
3606
|
try {
|
|
4654
|
-
result = await personalPost(opts, PERSONAL_APPLICATIONS_BASE, body, { idempotencyKey: (0, import_node_crypto15.randomUUID)() });
|
|
3607
|
+
result = await personalPost(opts, import_core53.PERSONAL_APPLICATIONS_BASE, body, { idempotencyKey: (0, import_node_crypto15.randomUUID)() });
|
|
4655
3608
|
} catch (err) {
|
|
4656
3609
|
rethrowApplyError(err);
|
|
4657
3610
|
}
|
|
@@ -4702,7 +3655,7 @@ async function runPersonalApplyBatch(ctx, args) {
|
|
|
4702
3655
|
const opts = { baseUrl: ctx.baseUrl, locale: ctx.locale, timeoutMs: ctx.timeoutMs };
|
|
4703
3656
|
let result;
|
|
4704
3657
|
try {
|
|
4705
|
-
result = await personalPost(opts, `${PERSONAL_APPLICATIONS_BASE}/batch`, { applications: items }, { idempotencyKey: (0, import_node_crypto15.randomUUID)() });
|
|
3658
|
+
result = await personalPost(opts, `${import_core53.PERSONAL_APPLICATIONS_BASE}/batch`, { applications: items }, { idempotencyKey: (0, import_node_crypto15.randomUUID)() });
|
|
4706
3659
|
} catch (err) {
|
|
4707
3660
|
rethrowApplyError(err);
|
|
4708
3661
|
}
|
|
@@ -4730,7 +3683,7 @@ function registerPersonalCommand(program2) {
|
|
|
4730
3683
|
|
|
4731
3684
|
// src/index.ts
|
|
4732
3685
|
var program = new import_commander.Command();
|
|
4733
|
-
program.name("wport").description("wport CLI \u2014 terminal interface to the W101 Talent Search Hub public API").version("0.9.
|
|
3686
|
+
program.name("wport").description("wport CLI \u2014 terminal interface to the W101 Talent Search Hub public API").version("0.9.2", "-v, --version", "output the CLI version").option("--lang <locale>", "Accept-Language locale: zh-TW | en-US | vi-VN | th-TH | id-ID").option("--api <url>", "override API base URL").option("--output <fmt>", "output format: table | json").option("--no-color", "disable color output").option("--timeout <ms>", "HTTP timeout in milliseconds", (v) => Number(v));
|
|
4734
3687
|
registerJobsCommand(program);
|
|
4735
3688
|
registerConfigCommand(program);
|
|
4736
3689
|
registerDoctorCommand(program);
|
|
@@ -4756,6 +3709,10 @@ function handleTopLevelError(err) {
|
|
|
4756
3709
|
printError(err.message, color);
|
|
4757
3710
|
process.exit(err.exitCode);
|
|
4758
3711
|
}
|
|
3712
|
+
if ((0, import_core.isWportError)(err)) {
|
|
3713
|
+
printError(err.message, color);
|
|
3714
|
+
process.exit(exitCodeForError(err));
|
|
3715
|
+
}
|
|
4759
3716
|
const fallbackMessage = err instanceof Error ? err.message : String(err);
|
|
4760
3717
|
printError(fallbackMessage, color);
|
|
4761
3718
|
process.exit(ExitCode.ServerOrNetworkError);
|