@wport/cli 0.9.1-dev.0 → 0.9.1
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/CHANGELOG.md +11 -0
- package/README.md +11 -11
- package/dist/index.js +235 -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;
|
|
@@ -478,16 +382,17 @@ function registerJobsSearch(parent) {
|
|
|
478
382
|
const ctx = resolveContext(command);
|
|
479
383
|
const fields = resolveSearchFields(flags);
|
|
480
384
|
const query = buildQuery(flags);
|
|
481
|
-
const client = createApiClient({
|
|
385
|
+
const client = (0, import_core2.createApiClient)({
|
|
482
386
|
baseUrl: ctx.baseUrl,
|
|
483
387
|
locale: ctx.locale,
|
|
484
|
-
timeoutMs: ctx.timeoutMs
|
|
388
|
+
timeoutMs: ctx.timeoutMs,
|
|
389
|
+
userAgent: (0, import_core2.buildUserAgent)("wport-cli", "0.9.1")
|
|
485
390
|
});
|
|
486
391
|
const { data, error, response } = await client.GET("/api/jobs/search", {
|
|
487
392
|
params: { query }
|
|
488
393
|
});
|
|
489
|
-
if (!response.ok) throwForHttpStatus(response.status, error);
|
|
490
|
-
const paged = asPaginatedBody(data);
|
|
394
|
+
if (!response.ok) (0, import_core2.throwForHttpStatus)(response.status, error);
|
|
395
|
+
const paged = (0, import_core2.asPaginatedBody)(data);
|
|
491
396
|
if (ctx.format === "json") {
|
|
492
397
|
const body = fields ? { ...paged, data: paged.data.map((item) => pickPaths(item, fields)) } : paged;
|
|
493
398
|
printJson(body);
|
|
@@ -564,21 +469,9 @@ function formatDate(s) {
|
|
|
564
469
|
return m ? m[1] : s;
|
|
565
470
|
}
|
|
566
471
|
|
|
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
|
-
}
|
|
472
|
+
// src/commands/jobs/view.ts
|
|
473
|
+
var import_core3 = require("@wport/core");
|
|
474
|
+
var import_core4 = require("@wport/core");
|
|
582
475
|
|
|
583
476
|
// src/lib/io-helpers.ts
|
|
584
477
|
var import_node_fs3 = require("fs");
|
|
@@ -733,10 +626,11 @@ function registerJobsView(parent) {
|
|
|
733
626
|
ExitCode.InvalidArgument
|
|
734
627
|
);
|
|
735
628
|
}
|
|
736
|
-
const client = createApiClient({
|
|
629
|
+
const client = (0, import_core3.createApiClient)({
|
|
737
630
|
baseUrl: ctx.baseUrl,
|
|
738
631
|
locale: ctx.locale,
|
|
739
|
-
timeoutMs: ctx.timeoutMs
|
|
632
|
+
timeoutMs: ctx.timeoutMs,
|
|
633
|
+
userAgent: (0, import_core3.buildUserAgent)("wport-cli", "0.9.1")
|
|
740
634
|
});
|
|
741
635
|
if (flags.batch) {
|
|
742
636
|
await runBatchView(encIdArg, flags, client, ctx.timeoutMs);
|
|
@@ -749,8 +643,8 @@ function registerJobsView(parent) {
|
|
|
749
643
|
const { data, error, response } = await client.GET("/api/jobs/{encId}/view", {
|
|
750
644
|
params: { path: { encId } }
|
|
751
645
|
});
|
|
752
|
-
if (!response.ok) throwForHttpStatus(response.status, error);
|
|
753
|
-
const job = unwrapDataResponse(data);
|
|
646
|
+
if (!response.ok) (0, import_core3.throwForHttpStatus)(response.status, error);
|
|
647
|
+
const job = (0, import_core3.unwrapDataResponse)(data);
|
|
754
648
|
if (flags.fields) {
|
|
755
649
|
printJson(pickPaths(job, parseFieldsList(flags.fields)));
|
|
756
650
|
return;
|
|
@@ -788,11 +682,11 @@ async function fetchJob(client, encId) {
|
|
|
788
682
|
const { data, error, response } = await client.GET("/api/jobs/{encId}/view", {
|
|
789
683
|
params: { path: { encId } }
|
|
790
684
|
});
|
|
791
|
-
if (!response.ok) throwForHttpStatus(response.status, error);
|
|
792
|
-
return unwrapDataResponse(data);
|
|
685
|
+
if (!response.ok) (0, import_core3.throwForHttpStatus)(response.status, error);
|
|
686
|
+
return (0, import_core3.unwrapDataResponse)(data);
|
|
793
687
|
}
|
|
794
688
|
async function runBatch(encIds, concurrency, fetchOne, project) {
|
|
795
|
-
return mapWithConcurrency(encIds, concurrency, async (encId) => {
|
|
689
|
+
return (0, import_core4.mapWithConcurrency)(encIds, concurrency, async (encId) => {
|
|
796
690
|
try {
|
|
797
691
|
const job = await fetchOne(encId);
|
|
798
692
|
return { enc_id: encId, ok: true, data: project(job) };
|
|
@@ -989,6 +883,7 @@ function registerConfigCommand(program2) {
|
|
|
989
883
|
|
|
990
884
|
// src/commands/doctor.ts
|
|
991
885
|
var import_node_fs6 = require("fs");
|
|
886
|
+
var import_core7 = require("@wport/core");
|
|
992
887
|
|
|
993
888
|
// src/lib/credentials-store.ts
|
|
994
889
|
var import_node_fs5 = require("fs");
|
|
@@ -1165,24 +1060,9 @@ function ensureFormat(key, source) {
|
|
|
1165
1060
|
}
|
|
1166
1061
|
}
|
|
1167
1062
|
|
|
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
1063
|
// src/lib/oauth.ts
|
|
1064
|
+
var import_core5 = require("@wport/core");
|
|
1065
|
+
var import_core6 = require("@wport/core");
|
|
1186
1066
|
var EXPIRED_MESSAGE = "The device code expired before authorization completed. Run `wport login` to try again.";
|
|
1187
1067
|
async function oauthPost(opts, path, body) {
|
|
1188
1068
|
const url = new URL(`${opts.baseUrl}${path}`);
|
|
@@ -1190,13 +1070,13 @@ async function oauthPost(opts, path, body) {
|
|
|
1190
1070
|
method: "POST",
|
|
1191
1071
|
headers: {
|
|
1192
1072
|
"Accept-Language": opts.locale,
|
|
1193
|
-
"User-Agent": buildUserAgent(),
|
|
1073
|
+
"User-Agent": (0, import_core5.buildUserAgent)("wport-cli", "0.9.1"),
|
|
1194
1074
|
Accept: "application/json",
|
|
1195
1075
|
"Content-Type": "application/json"
|
|
1196
1076
|
},
|
|
1197
1077
|
body: JSON.stringify(body)
|
|
1198
1078
|
});
|
|
1199
|
-
const res = await fetchWithTimeout(request, opts.timeoutMs);
|
|
1079
|
+
const res = await (0, import_core5.fetchWithTimeout)(request, opts.timeoutMs);
|
|
1200
1080
|
const respBody = await res.json().catch(() => null);
|
|
1201
1081
|
return { status: res.status, body: respBody };
|
|
1202
1082
|
}
|
|
@@ -1209,15 +1089,15 @@ function oauthErrorCode(body) {
|
|
|
1209
1089
|
async function requestDeviceCode(opts, deviceName) {
|
|
1210
1090
|
const body = {};
|
|
1211
1091
|
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);
|
|
1092
|
+
const { status, body: respBody } = await oauthPost(opts, `${import_core6.OAUTH_BASE}/device/code`, body);
|
|
1093
|
+
if (status < 200 || status >= 300) (0, import_core5.throwForHttpStatus)(status, respBody);
|
|
1214
1094
|
return respBody;
|
|
1215
1095
|
}
|
|
1216
1096
|
async function pollForToken(opts, device, sleep = (ms) => new Promise((resolve) => setTimeout(resolve, ms))) {
|
|
1217
1097
|
let intervalSec = device.interval;
|
|
1218
1098
|
const deadline = Date.now() + device.expires_in * 1e3;
|
|
1219
1099
|
for (; ; ) {
|
|
1220
|
-
const { status, body } = await oauthPost(opts, `${OAUTH_BASE}/token`, {
|
|
1100
|
+
const { status, body } = await oauthPost(opts, `${import_core6.OAUTH_BASE}/token`, {
|
|
1221
1101
|
grant_type: "urn:ietf:params:oauth:grant-type:device_code",
|
|
1222
1102
|
device_code: device.device_code
|
|
1223
1103
|
});
|
|
@@ -1230,14 +1110,14 @@ async function pollForToken(opts, device, sleep = (ms) => new Promise((resolve)
|
|
|
1230
1110
|
} else if (code === "expired_token") {
|
|
1231
1111
|
throw new CliError(EXPIRED_MESSAGE, ExitCode.ServerClientError);
|
|
1232
1112
|
} else if (code !== "authorization_pending") {
|
|
1233
|
-
throwForHttpStatus(status, body);
|
|
1113
|
+
(0, import_core5.throwForHttpStatus)(status, body);
|
|
1234
1114
|
}
|
|
1235
1115
|
if (Date.now() >= deadline) throw new CliError(EXPIRED_MESSAGE, ExitCode.ServerClientError);
|
|
1236
1116
|
await sleep(intervalSec * 1e3);
|
|
1237
1117
|
}
|
|
1238
1118
|
}
|
|
1239
1119
|
async function refreshAccessToken(opts, refreshToken) {
|
|
1240
|
-
const { status, body } = await oauthPost(opts, `${OAUTH_BASE}/token`, {
|
|
1120
|
+
const { status, body } = await oauthPost(opts, `${import_core6.OAUTH_BASE}/token`, {
|
|
1241
1121
|
grant_type: "refresh_token",
|
|
1242
1122
|
refresh_token: refreshToken
|
|
1243
1123
|
});
|
|
@@ -1245,11 +1125,11 @@ async function refreshAccessToken(opts, refreshToken) {
|
|
|
1245
1125
|
if (oauthErrorCode(body) === "invalid_grant") {
|
|
1246
1126
|
throw new CliError("Your session is no longer valid. Run `wport login` to sign in again.", ExitCode.ServerClientError);
|
|
1247
1127
|
}
|
|
1248
|
-
throwForHttpStatus(status, body);
|
|
1128
|
+
(0, import_core5.throwForHttpStatus)(status, body);
|
|
1249
1129
|
}
|
|
1250
1130
|
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);
|
|
1131
|
+
const { status, body } = await oauthPost(opts, `${import_core6.OAUTH_BASE}/revoke`, { token: refreshToken });
|
|
1132
|
+
if (status < 200 || status >= 300) (0, import_core5.throwForHttpStatus)(status, body);
|
|
1253
1133
|
}
|
|
1254
1134
|
|
|
1255
1135
|
// src/commands/doctor.ts
|
|
@@ -1272,7 +1152,7 @@ function registerDoctorCommand(program2) {
|
|
|
1272
1152
|
}
|
|
1273
1153
|
async function runDoctor(ctx) {
|
|
1274
1154
|
const line = (s = "") => process.stdout.write(s + "\n");
|
|
1275
|
-
line(`wport-cli ${"0.9.1
|
|
1155
|
+
line(`wport-cli ${"0.9.1"}`);
|
|
1276
1156
|
line(` bundled schema fingerprint: ${"839e8a891dfb"}`);
|
|
1277
1157
|
line("");
|
|
1278
1158
|
line("Resolved configuration:");
|
|
@@ -1328,7 +1208,12 @@ function describePersonalLoginLines() {
|
|
|
1328
1208
|
}
|
|
1329
1209
|
async function probeServer(ctx, line) {
|
|
1330
1210
|
try {
|
|
1331
|
-
const client =
|
|
1211
|
+
const client = (0, import_core7.createApiClient)({
|
|
1212
|
+
baseUrl: ctx.baseUrl,
|
|
1213
|
+
locale: ctx.locale,
|
|
1214
|
+
timeoutMs: ctx.timeoutMs,
|
|
1215
|
+
userAgent: (0, import_core7.buildUserAgent)("wport-cli", "0.9.1")
|
|
1216
|
+
});
|
|
1332
1217
|
const { response } = await client.GET("/api/jobs/search", { params: { query: { pageSize: 1 } } });
|
|
1333
1218
|
if (response.ok) {
|
|
1334
1219
|
line(` \u2713 reachable (HTTP ${response.status})`);
|
|
@@ -1353,81 +1238,39 @@ async function probeAuthServer(ctx, line) {
|
|
|
1353
1238
|
}
|
|
1354
1239
|
|
|
1355
1240
|
// 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(
|
|
1241
|
+
var import_core8 = require("@wport/core");
|
|
1242
|
+
var transport = __toESM(require("@wport/core"));
|
|
1243
|
+
function withUserAgent(opts) {
|
|
1244
|
+
return { ...opts, userAgent: (0, import_core8.buildUserAgent)("wport-cli", "0.9.1") };
|
|
1245
|
+
}
|
|
1246
|
+
function decorateEnterpriseError(err) {
|
|
1247
|
+
if (!(err instanceof import_core8.WportHttpError)) return err;
|
|
1248
|
+
const base = err.message;
|
|
1249
|
+
if (err.status === 401) {
|
|
1250
|
+
return new import_core8.WportHttpError(
|
|
1411
1251
|
`${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
|
-
|
|
1252
|
+
err.status,
|
|
1253
|
+
err.body
|
|
1413
1254
|
);
|
|
1414
1255
|
}
|
|
1415
|
-
if (status === 403) {
|
|
1416
|
-
|
|
1256
|
+
if (err.status === 403) {
|
|
1257
|
+
return new import_core8.WportHttpError(
|
|
1417
1258
|
`${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
|
-
|
|
1259
|
+
err.status,
|
|
1260
|
+
err.body
|
|
1419
1261
|
);
|
|
1420
1262
|
}
|
|
1421
|
-
if (status === 400) {
|
|
1422
|
-
const missingFields = extractMissingFields(body);
|
|
1263
|
+
if (err.status === 400) {
|
|
1264
|
+
const missingFields = extractMissingFields(err.body);
|
|
1423
1265
|
if (missingFields.length > 0) {
|
|
1424
|
-
|
|
1266
|
+
return new import_core8.WportHttpError(
|
|
1425
1267
|
`${base} \u2014 Missing required fields: ${missingFields.join(", ")}. Fill them via \`wport enterprise jobs update <enc_id> ...\` (or the web console), then publish.`,
|
|
1426
|
-
|
|
1268
|
+
err.status,
|
|
1269
|
+
err.body
|
|
1427
1270
|
);
|
|
1428
1271
|
}
|
|
1429
1272
|
}
|
|
1430
|
-
|
|
1273
|
+
return err;
|
|
1431
1274
|
}
|
|
1432
1275
|
function extractMissingFields(body) {
|
|
1433
1276
|
if (!body || typeof body !== "object") return [];
|
|
@@ -1444,6 +1287,28 @@ function warnIfRateLimitLow(headers) {
|
|
|
1444
1287
|
printWarn(`Rate limit nearly exhausted: ${remaining}/${limit} requests remaining this window.`, false);
|
|
1445
1288
|
}
|
|
1446
1289
|
}
|
|
1290
|
+
async function wrap(p) {
|
|
1291
|
+
let res;
|
|
1292
|
+
try {
|
|
1293
|
+
res = await p;
|
|
1294
|
+
} catch (err) {
|
|
1295
|
+
throw decorateEnterpriseError(err);
|
|
1296
|
+
}
|
|
1297
|
+
warnIfRateLimitLow(res.headers);
|
|
1298
|
+
return res;
|
|
1299
|
+
}
|
|
1300
|
+
function enterpriseGet2(opts, path, query) {
|
|
1301
|
+
return wrap(transport.enterpriseGet(withUserAgent(opts), path, query));
|
|
1302
|
+
}
|
|
1303
|
+
function enterprisePost2(opts, path, body, extra) {
|
|
1304
|
+
return wrap(transport.enterprisePost(withUserAgent(opts), path, body, extra));
|
|
1305
|
+
}
|
|
1306
|
+
function enterprisePatch2(opts, path, body, extra) {
|
|
1307
|
+
return wrap(transport.enterprisePatch(withUserAgent(opts), path, body, extra));
|
|
1308
|
+
}
|
|
1309
|
+
function enterpriseDelete2(opts, path, extra) {
|
|
1310
|
+
return wrap(transport.enterpriseDelete(withUserAgent(opts), path, extra));
|
|
1311
|
+
}
|
|
1447
1312
|
|
|
1448
1313
|
// src/commands/enterprise/login.ts
|
|
1449
1314
|
async function performLogin(ctx, key) {
|
|
@@ -1455,7 +1320,7 @@ async function performLogin(ctx, key) {
|
|
|
1455
1320
|
ExitCode.InvalidArgument
|
|
1456
1321
|
);
|
|
1457
1322
|
}
|
|
1458
|
-
const { body } = await
|
|
1323
|
+
const { body } = await enterpriseGet2({ ...ctx, apiKey: key }, "/me");
|
|
1459
1324
|
saveCredentials({
|
|
1460
1325
|
api_key: key,
|
|
1461
1326
|
company_name: extractCompanyName(body),
|
|
@@ -1520,15 +1385,16 @@ function registerEnterpriseWhoami(parent) {
|
|
|
1520
1385
|
}
|
|
1521
1386
|
|
|
1522
1387
|
// src/commands/enterprise/usage.ts
|
|
1388
|
+
var import_core9 = require("@wport/core");
|
|
1523
1389
|
function num(value) {
|
|
1524
1390
|
return typeof value === "number" && Number.isFinite(value) ? String(value) : "\u2014";
|
|
1525
1391
|
}
|
|
1526
1392
|
async function runUsage(ctx, apiKey) {
|
|
1527
|
-
const { body } = await
|
|
1393
|
+
const { body } = await enterpriseGet2(
|
|
1528
1394
|
{ baseUrl: ctx.baseUrl, locale: ctx.locale, timeoutMs: ctx.timeoutMs, apiKey },
|
|
1529
1395
|
"/usage"
|
|
1530
1396
|
);
|
|
1531
|
-
const usage = unwrapDataResponse(body);
|
|
1397
|
+
const usage = (0, import_core9.unwrapDataResponse)(body);
|
|
1532
1398
|
if (ctx.format === "json") {
|
|
1533
1399
|
printJson(usage);
|
|
1534
1400
|
return;
|
|
@@ -1555,6 +1421,7 @@ function registerEnterpriseUsage(parent) {
|
|
|
1555
1421
|
}
|
|
1556
1422
|
|
|
1557
1423
|
// src/commands/enterprise/jobs/list.ts
|
|
1424
|
+
var import_core10 = require("@wport/core");
|
|
1558
1425
|
var STATUS_MAP = { published: 1, unpublished: 0 };
|
|
1559
1426
|
var MINIMAL_LIST_FIELDS = ["enc_id", "job_title", "status", "updated_at"];
|
|
1560
1427
|
function mapStatusFlag(raw) {
|
|
@@ -1580,7 +1447,7 @@ async function runEnterpriseJobsList(ctx, apiKey, flags) {
|
|
|
1580
1447
|
if (flags.fields && flags.minimal) {
|
|
1581
1448
|
throw new CliError("Use either --fields or --minimal, not both", ExitCode.InvalidArgument);
|
|
1582
1449
|
}
|
|
1583
|
-
const { body } = await
|
|
1450
|
+
const { body } = await enterpriseGet2(
|
|
1584
1451
|
{ baseUrl: ctx.baseUrl, locale: ctx.locale, timeoutMs: ctx.timeoutMs, apiKey },
|
|
1585
1452
|
"/jobs",
|
|
1586
1453
|
{
|
|
@@ -1590,7 +1457,7 @@ async function runEnterpriseJobsList(ctx, apiKey, flags) {
|
|
|
1590
1457
|
status: mapStatusFlag(flags.status)
|
|
1591
1458
|
}
|
|
1592
1459
|
);
|
|
1593
|
-
const paged = asPaginatedBody(body);
|
|
1460
|
+
const paged = (0, import_core10.asPaginatedBody)(body);
|
|
1594
1461
|
const projection = flags.minimal ? MINIMAL_LIST_FIELDS : flags.fields ? parseFieldsList(flags.fields) : void 0;
|
|
1595
1462
|
if (projection || ctx.format === "json") {
|
|
1596
1463
|
printJson(projection ? { ...paged, data: paged.data.map((row) => pickPaths(row, projection)) } : paged);
|
|
@@ -1622,6 +1489,7 @@ function registerEnterpriseJobsList(parent) {
|
|
|
1622
1489
|
}
|
|
1623
1490
|
|
|
1624
1491
|
// src/commands/enterprise/jobs/view.ts
|
|
1492
|
+
var import_core11 = require("@wport/core");
|
|
1625
1493
|
var DETAIL_FIELDS = ["enc_id", "job_title", "code", "status", "created_at", "updated_at"];
|
|
1626
1494
|
function renderDetailLines(job) {
|
|
1627
1495
|
const pad = Math.max(...DETAIL_FIELDS.map((f) => f.length)) + 1;
|
|
@@ -1642,11 +1510,11 @@ function registerEnterpriseJobsView(parent) {
|
|
|
1642
1510
|
}
|
|
1643
1511
|
const globals = command.optsWithGlobals();
|
|
1644
1512
|
const { key } = resolveApiKey(globals.apiKey);
|
|
1645
|
-
const { body } = await
|
|
1513
|
+
const { body } = await enterpriseGet2(
|
|
1646
1514
|
{ baseUrl: ctx.baseUrl, locale: ctx.locale, timeoutMs: ctx.timeoutMs, apiKey: key },
|
|
1647
1515
|
`/jobs/${encodeURIComponent(encId.trim())}`
|
|
1648
1516
|
);
|
|
1649
|
-
const job = unwrapDataResponse(body);
|
|
1517
|
+
const job = (0, import_core11.unwrapDataResponse)(body);
|
|
1650
1518
|
if (flags.fields) {
|
|
1651
1519
|
printJson(pickPaths(job, parseFieldsList(flags.fields)));
|
|
1652
1520
|
return;
|
|
@@ -1661,15 +1529,16 @@ function registerEnterpriseJobsView(parent) {
|
|
|
1661
1529
|
|
|
1662
1530
|
// src/commands/enterprise/jobs/create.ts
|
|
1663
1531
|
var import_node_crypto = require("crypto");
|
|
1532
|
+
var import_core12 = require("@wport/core");
|
|
1664
1533
|
async function runJobsCreate(ctx, apiKey, source, idempotencyKey) {
|
|
1665
1534
|
const jobBody = readJsonObject(source, { timeoutMs: ctx.timeoutMs });
|
|
1666
|
-
const { body } = await
|
|
1535
|
+
const { body } = await enterprisePost2(
|
|
1667
1536
|
{ baseUrl: ctx.baseUrl, locale: ctx.locale, timeoutMs: ctx.timeoutMs, apiKey },
|
|
1668
1537
|
"/jobs",
|
|
1669
1538
|
jobBody,
|
|
1670
1539
|
{ idempotencyKey }
|
|
1671
1540
|
);
|
|
1672
|
-
const created = unwrapDataResponse(body);
|
|
1541
|
+
const created = (0, import_core12.unwrapDataResponse)(body);
|
|
1673
1542
|
if (ctx.format === "json") {
|
|
1674
1543
|
printJson(created);
|
|
1675
1544
|
return;
|
|
@@ -1688,6 +1557,7 @@ function registerEnterpriseJobsCreate(parent) {
|
|
|
1688
1557
|
|
|
1689
1558
|
// src/commands/enterprise/jobs/update.ts
|
|
1690
1559
|
var import_node_crypto2 = require("crypto");
|
|
1560
|
+
var import_core13 = require("@wport/core");
|
|
1691
1561
|
|
|
1692
1562
|
// src/commands/enterprise/jobs/write-shared.ts
|
|
1693
1563
|
function requireEncId(encId) {
|
|
@@ -1700,13 +1570,13 @@ function requireEncId(encId) {
|
|
|
1700
1570
|
async function runJobsUpdate(ctx, apiKey, encId, source, idempotencyKey, ifMatch) {
|
|
1701
1571
|
const trimmed = requireEncId(encId);
|
|
1702
1572
|
const jobBody = readJsonObject(source, { timeoutMs: ctx.timeoutMs });
|
|
1703
|
-
const { body } = await
|
|
1573
|
+
const { body } = await enterprisePatch2(
|
|
1704
1574
|
{ baseUrl: ctx.baseUrl, locale: ctx.locale, timeoutMs: ctx.timeoutMs, apiKey },
|
|
1705
1575
|
`/jobs/${encodeURIComponent(trimmed)}`,
|
|
1706
1576
|
jobBody,
|
|
1707
1577
|
{ idempotencyKey, ifMatch }
|
|
1708
1578
|
);
|
|
1709
|
-
const updated = unwrapDataResponse(body);
|
|
1579
|
+
const updated = (0, import_core13.unwrapDataResponse)(body);
|
|
1710
1580
|
if (ctx.format === "json") {
|
|
1711
1581
|
printJson(updated);
|
|
1712
1582
|
return;
|
|
@@ -1725,15 +1595,16 @@ function registerEnterpriseJobsUpdate(parent) {
|
|
|
1725
1595
|
|
|
1726
1596
|
// src/commands/enterprise/jobs/lifecycle.ts
|
|
1727
1597
|
var import_node_crypto3 = require("crypto");
|
|
1598
|
+
var import_core14 = require("@wport/core");
|
|
1728
1599
|
async function runJobsTransition(ctx, apiKey, encId, action, idempotencyKey) {
|
|
1729
1600
|
const trimmed = requireEncId(encId);
|
|
1730
|
-
const { body } = await
|
|
1601
|
+
const { body } = await enterprisePatch2(
|
|
1731
1602
|
{ baseUrl: ctx.baseUrl, locale: ctx.locale, timeoutMs: ctx.timeoutMs, apiKey },
|
|
1732
1603
|
`/jobs/${encodeURIComponent(trimmed)}/${action}`,
|
|
1733
1604
|
{},
|
|
1734
1605
|
{ idempotencyKey }
|
|
1735
1606
|
);
|
|
1736
|
-
const result = unwrapDataResponse(body);
|
|
1607
|
+
const result = (0, import_core14.unwrapDataResponse)(body);
|
|
1737
1608
|
if (ctx.format === "json") {
|
|
1738
1609
|
printJson(result);
|
|
1739
1610
|
return;
|
|
@@ -1747,7 +1618,7 @@ async function runJobsDelete(ctx, apiKey, encId, confirm, idempotencyKey) {
|
|
|
1747
1618
|
throw new CliError("Refusing to delete without --confirm (destructive, irreversible)", ExitCode.InvalidArgument);
|
|
1748
1619
|
}
|
|
1749
1620
|
const trimmed = requireEncId(encId);
|
|
1750
|
-
await
|
|
1621
|
+
await enterpriseDelete2(
|
|
1751
1622
|
{ baseUrl: ctx.baseUrl, locale: ctx.locale, timeoutMs: ctx.timeoutMs, apiKey },
|
|
1752
1623
|
`/jobs/${encodeURIComponent(trimmed)}`,
|
|
1753
1624
|
{ idempotencyKey }
|
|
@@ -1761,13 +1632,13 @@ async function runJobsDelete(ctx, apiKey, encId, confirm, idempotencyKey) {
|
|
|
1761
1632
|
}
|
|
1762
1633
|
async function runJobsCopy(ctx, apiKey, encId, idempotencyKey) {
|
|
1763
1634
|
const trimmed = requireEncId(encId);
|
|
1764
|
-
const { body } = await
|
|
1635
|
+
const { body } = await enterprisePost2(
|
|
1765
1636
|
{ baseUrl: ctx.baseUrl, locale: ctx.locale, timeoutMs: ctx.timeoutMs, apiKey },
|
|
1766
1637
|
`/jobs/${encodeURIComponent(trimmed)}/copy`,
|
|
1767
1638
|
{},
|
|
1768
1639
|
{ idempotencyKey }
|
|
1769
1640
|
);
|
|
1770
|
-
const result = unwrapDataResponse(body);
|
|
1641
|
+
const result = (0, import_core14.unwrapDataResponse)(body);
|
|
1771
1642
|
if (ctx.format === "json") {
|
|
1772
1643
|
printJson(result);
|
|
1773
1644
|
return;
|
|
@@ -1821,6 +1692,7 @@ function registerEnterpriseJobsDelete(parent) {
|
|
|
1821
1692
|
|
|
1822
1693
|
// src/commands/enterprise/jobs/batch.ts
|
|
1823
1694
|
var import_node_crypto4 = require("crypto");
|
|
1695
|
+
var import_core15 = require("@wport/core");
|
|
1824
1696
|
var BATCH_MIN = 1;
|
|
1825
1697
|
var BATCH_MAX = 10;
|
|
1826
1698
|
async function runJobsBatch(ctx, apiKey, source, confirm, idempotencyKey) {
|
|
@@ -1835,13 +1707,13 @@ async function runJobsBatch(ctx, apiKey, source, confirm, idempotencyKey) {
|
|
|
1835
1707
|
ExitCode.InvalidArgument
|
|
1836
1708
|
);
|
|
1837
1709
|
}
|
|
1838
|
-
const { body } = await
|
|
1710
|
+
const { body } = await enterprisePost2(
|
|
1839
1711
|
{ baseUrl: ctx.baseUrl, locale: ctx.locale, timeoutMs: ctx.timeoutMs, apiKey },
|
|
1840
1712
|
"/jobs/batch",
|
|
1841
1713
|
payload,
|
|
1842
1714
|
{ idempotencyKey }
|
|
1843
1715
|
);
|
|
1844
|
-
const result = unwrapDataResponse(body);
|
|
1716
|
+
const result = (0, import_core15.unwrapDataResponse)(body);
|
|
1845
1717
|
const succeeded = result.succeeded ?? [];
|
|
1846
1718
|
const failed = result.failed ?? [];
|
|
1847
1719
|
if (ctx.format === "json") {
|
|
@@ -1884,6 +1756,7 @@ function registerEnterpriseJobsCommand(parent) {
|
|
|
1884
1756
|
}
|
|
1885
1757
|
|
|
1886
1758
|
// src/commands/enterprise/keys/list.ts
|
|
1759
|
+
var import_core16 = require("@wport/core");
|
|
1887
1760
|
function formatDate3(value) {
|
|
1888
1761
|
return value ? String(value).slice(0, 10) : "";
|
|
1889
1762
|
}
|
|
@@ -1891,11 +1764,11 @@ function formatScopes(scopes) {
|
|
|
1891
1764
|
return Array.isArray(scopes) ? scopes.join(",") : "";
|
|
1892
1765
|
}
|
|
1893
1766
|
async function runKeysList(ctx, apiKey) {
|
|
1894
|
-
const { body } = await
|
|
1767
|
+
const { body } = await enterpriseGet2(
|
|
1895
1768
|
{ baseUrl: ctx.baseUrl, locale: ctx.locale, timeoutMs: ctx.timeoutMs, apiKey },
|
|
1896
1769
|
"/keys"
|
|
1897
1770
|
);
|
|
1898
|
-
const keys = unwrapDataArray(body);
|
|
1771
|
+
const keys = (0, import_core16.unwrapDataArray)(body);
|
|
1899
1772
|
if (ctx.format === "json") {
|
|
1900
1773
|
printJson(keys);
|
|
1901
1774
|
return;
|
|
@@ -1926,6 +1799,7 @@ function registerEnterpriseKeysList(parent) {
|
|
|
1926
1799
|
}
|
|
1927
1800
|
|
|
1928
1801
|
// src/commands/enterprise/keys/rotate.ts
|
|
1802
|
+
var import_core17 = require("@wport/core");
|
|
1929
1803
|
var ENTERPRISE_KEY_EXPIRY_DAYS = [30, 60, 90];
|
|
1930
1804
|
function validateExpiryDays(raw) {
|
|
1931
1805
|
if (raw === void 0) return void 0;
|
|
@@ -1943,12 +1817,12 @@ async function runKeysRotate(ctx, apiKey, encId, flags) {
|
|
|
1943
1817
|
const expiryDays = validateExpiryDays(flags.expiryDays);
|
|
1944
1818
|
const requestBody = {};
|
|
1945
1819
|
if (expiryDays !== void 0) requestBody.expiry_days = expiryDays;
|
|
1946
|
-
const { body } = await
|
|
1820
|
+
const { body } = await enterprisePost2(
|
|
1947
1821
|
{ baseUrl: ctx.baseUrl, locale: ctx.locale, timeoutMs: ctx.timeoutMs, apiKey },
|
|
1948
1822
|
`/keys/${encodeURIComponent(trimmed)}/rotate`,
|
|
1949
1823
|
requestBody
|
|
1950
1824
|
);
|
|
1951
|
-
const issued = unwrapDataResponse(body);
|
|
1825
|
+
const issued = (0, import_core17.unwrapDataResponse)(body);
|
|
1952
1826
|
if (ctx.format === "json") {
|
|
1953
1827
|
printJson(issued);
|
|
1954
1828
|
} else {
|
|
@@ -1987,6 +1861,7 @@ function registerEnterpriseKeysCommand(parent) {
|
|
|
1987
1861
|
}
|
|
1988
1862
|
|
|
1989
1863
|
// src/commands/enterprise/company/view.ts
|
|
1864
|
+
var import_core18 = require("@wport/core");
|
|
1990
1865
|
var COMPANY_STATUS_LABELS = {
|
|
1991
1866
|
0: "not_submitted",
|
|
1992
1867
|
1: "pending_review",
|
|
@@ -2042,11 +1917,11 @@ function renderDetailLines2(company) {
|
|
|
2042
1917
|
return lines;
|
|
2043
1918
|
}
|
|
2044
1919
|
async function runCompanyView(ctx, apiKey, flags) {
|
|
2045
|
-
const { body } = await
|
|
1920
|
+
const { body } = await enterpriseGet2(
|
|
2046
1921
|
{ baseUrl: ctx.baseUrl, locale: ctx.locale, timeoutMs: ctx.timeoutMs, apiKey },
|
|
2047
1922
|
"/company"
|
|
2048
1923
|
);
|
|
2049
|
-
const company = unwrapDataResponse(body);
|
|
1924
|
+
const company = (0, import_core18.unwrapDataResponse)(body);
|
|
2050
1925
|
if (flags.fields) {
|
|
2051
1926
|
printJson(pickPaths(company, parseFieldsList(flags.fields)));
|
|
2052
1927
|
return;
|
|
@@ -2068,6 +1943,7 @@ function registerEnterpriseCompanyView(parent) {
|
|
|
2068
1943
|
|
|
2069
1944
|
// src/commands/enterprise/company/update.ts
|
|
2070
1945
|
var import_node_crypto5 = require("crypto");
|
|
1946
|
+
var import_core19 = require("@wport/core");
|
|
2071
1947
|
|
|
2072
1948
|
// src/commands/enterprise/company/types.ts
|
|
2073
1949
|
var BASIC_FIELDS = [
|
|
@@ -2133,11 +2009,11 @@ async function buildCompanyUpdatePayloads(input, ctx, apiKey) {
|
|
|
2133
2009
|
if (!inputHasBasicField && !inputHasDescriptionField) {
|
|
2134
2010
|
throw new InvalidArgumentError("No writable company fields provided");
|
|
2135
2011
|
}
|
|
2136
|
-
const { body } = await
|
|
2012
|
+
const { body } = await enterpriseGet2(
|
|
2137
2013
|
{ baseUrl: ctx.baseUrl, locale: ctx.locale, timeoutMs: ctx.timeoutMs, apiKey },
|
|
2138
2014
|
"/company"
|
|
2139
2015
|
);
|
|
2140
|
-
const current = unwrapDataResponse(body);
|
|
2016
|
+
const current = (0, import_core19.unwrapDataResponse)(body);
|
|
2141
2017
|
const missingContractFields = CONTRACT_REQUIRED_GET_FIELDS.filter((f) => !(f in current));
|
|
2142
2018
|
if (missingContractFields.length > 0) {
|
|
2143
2019
|
throw new CliError(
|
|
@@ -2204,23 +2080,23 @@ async function runCompanyUpdate(ctx, apiKey, source, idempotencyFlags, options =
|
|
|
2204
2080
|
const requestOpts = { baseUrl: ctx.baseUrl, locale: ctx.locale, timeoutMs: ctx.timeoutMs, apiKey };
|
|
2205
2081
|
let basicResultCompany;
|
|
2206
2082
|
if (needsBasic) {
|
|
2207
|
-
const { body } = await
|
|
2083
|
+
const { body } = await enterprisePatch2(requestOpts, "/company/basic", payloads.basic, {
|
|
2208
2084
|
idempotencyKey: basicKey
|
|
2209
2085
|
});
|
|
2210
|
-
basicResultCompany = unwrapDataResponse(body);
|
|
2086
|
+
basicResultCompany = (0, import_core19.unwrapDataResponse)(body);
|
|
2211
2087
|
}
|
|
2212
2088
|
if (!needsDescriptions) {
|
|
2213
2089
|
printCompanyResult(basicResultCompany, ctx.format);
|
|
2214
2090
|
return;
|
|
2215
2091
|
}
|
|
2216
2092
|
try {
|
|
2217
|
-
const { body } = await
|
|
2093
|
+
const { body } = await enterprisePatch2(
|
|
2218
2094
|
requestOpts,
|
|
2219
2095
|
"/company/descriptions",
|
|
2220
2096
|
payloads.descriptions,
|
|
2221
2097
|
{ idempotencyKey: descriptionsKey }
|
|
2222
2098
|
);
|
|
2223
|
-
const result = unwrapDataResponse(body);
|
|
2099
|
+
const result = (0, import_core19.unwrapDataResponse)(body);
|
|
2224
2100
|
printCompanyResult(result.company, ctx.format);
|
|
2225
2101
|
} catch (err) {
|
|
2226
2102
|
if (!needsBasic) {
|
|
@@ -2279,6 +2155,7 @@ function registerEnterpriseCompanyUpdate(parent) {
|
|
|
2279
2155
|
var import_node_crypto6 = require("crypto");
|
|
2280
2156
|
var import_node_fs7 = require("fs");
|
|
2281
2157
|
var import_node_path3 = require("path");
|
|
2158
|
+
var import_core20 = require("@wport/core");
|
|
2282
2159
|
var EXTENSION_TO_CONTENT_TYPE = {
|
|
2283
2160
|
".png": "image/png",
|
|
2284
2161
|
".jpg": "image/jpeg",
|
|
@@ -2330,29 +2207,29 @@ async function runCompanyLogoUpload(ctx, apiKey, path, idempotencyFlags) {
|
|
|
2330
2207
|
const { contentType, fileSize, bytes } = inspectLocalFile(path);
|
|
2331
2208
|
const { presignKey, confirmKey } = resolveLogoIdempotencyKeys(idempotencyFlags);
|
|
2332
2209
|
const requestOpts = { baseUrl: ctx.baseUrl, locale: ctx.locale, timeoutMs: ctx.timeoutMs, apiKey };
|
|
2333
|
-
const { body: presignBody } = await
|
|
2210
|
+
const { body: presignBody } = await enterprisePost2(
|
|
2334
2211
|
requestOpts,
|
|
2335
2212
|
"/company/logo/presign",
|
|
2336
2213
|
{ content_type: contentType, file_size: fileSize },
|
|
2337
2214
|
{ idempotencyKey: presignKey }
|
|
2338
2215
|
);
|
|
2339
|
-
const presign = unwrapDataResponse(presignBody);
|
|
2216
|
+
const presign = (0, import_core20.unwrapDataResponse)(presignBody);
|
|
2340
2217
|
const putRequest = new Request(presign.upload_url, {
|
|
2341
2218
|
method: "PUT",
|
|
2342
2219
|
headers: { "Content-Type": contentType },
|
|
2343
2220
|
body: bytes
|
|
2344
2221
|
});
|
|
2345
|
-
const putResponse = await fetchWithTimeout(putRequest, ctx.timeoutMs);
|
|
2222
|
+
const putResponse = await (0, import_core20.fetchWithTimeout)(putRequest, ctx.timeoutMs);
|
|
2346
2223
|
if (!putResponse.ok) {
|
|
2347
2224
|
throw new NetworkError(`Failed to upload file to S3: HTTP ${putResponse.status}`);
|
|
2348
2225
|
}
|
|
2349
|
-
const { body: confirmBody } = await
|
|
2226
|
+
const { body: confirmBody } = await enterprisePost2(
|
|
2350
2227
|
requestOpts,
|
|
2351
2228
|
"/company/logo/confirm",
|
|
2352
2229
|
{ s3_key: presign.s3_key },
|
|
2353
2230
|
{ idempotencyKey: confirmKey }
|
|
2354
2231
|
);
|
|
2355
|
-
const result = unwrapDataResponse(confirmBody);
|
|
2232
|
+
const result = (0, import_core20.unwrapDataResponse)(confirmBody);
|
|
2356
2233
|
printLogoResult(result, ctx.format);
|
|
2357
2234
|
}
|
|
2358
2235
|
function registerEnterpriseCompanyLogo(parent) {
|
|
@@ -2374,6 +2251,7 @@ function registerEnterpriseCompanyCommand(parent) {
|
|
|
2374
2251
|
}
|
|
2375
2252
|
|
|
2376
2253
|
// src/commands/enterprise/talents/list.ts
|
|
2254
|
+
var import_core21 = require("@wport/core");
|
|
2377
2255
|
var DEFAULT_PAGE_SIZE = 20;
|
|
2378
2256
|
var MINIMAL_LIST_FIELDS2 = ["enc_resume_id", "candidate_name", "applied_job_title", "applied_at"];
|
|
2379
2257
|
function formatDate4(value) {
|
|
@@ -2383,7 +2261,7 @@ async function runEnterpriseTalentsList(ctx, apiKey, flags) {
|
|
|
2383
2261
|
if (flags.fields && flags.minimal) {
|
|
2384
2262
|
throw new CliError("Use either --fields or --minimal, not both", ExitCode.InvalidArgument);
|
|
2385
2263
|
}
|
|
2386
|
-
const { body } = await
|
|
2264
|
+
const { body } = await enterpriseGet2(
|
|
2387
2265
|
{ baseUrl: ctx.baseUrl, locale: ctx.locale, timeoutMs: ctx.timeoutMs, apiKey },
|
|
2388
2266
|
"/talents",
|
|
2389
2267
|
{
|
|
@@ -2396,7 +2274,7 @@ async function runEnterpriseTalentsList(ctx, apiKey, flags) {
|
|
|
2396
2274
|
pageSize: flags.pageSize ?? DEFAULT_PAGE_SIZE
|
|
2397
2275
|
}
|
|
2398
2276
|
);
|
|
2399
|
-
const paged = asPaginatedBody(body);
|
|
2277
|
+
const paged = (0, import_core21.asPaginatedBody)(body);
|
|
2400
2278
|
const projection = flags.minimal ? MINIMAL_LIST_FIELDS2 : flags.fields ? parseFieldsList(flags.fields) : void 0;
|
|
2401
2279
|
if (projection || ctx.format === "json") {
|
|
2402
2280
|
printJson(projection ? { ...paged, data: paged.data.map((row) => pickPaths(row, projection)) } : paged);
|
|
@@ -2429,16 +2307,17 @@ function registerEnterpriseTalentsList(parent) {
|
|
|
2429
2307
|
}
|
|
2430
2308
|
|
|
2431
2309
|
// src/commands/enterprise/talents/view.ts
|
|
2310
|
+
var import_core22 = require("@wport/core");
|
|
2432
2311
|
async function runEnterpriseTalentsView(ctx, apiKey, encResumeId, flags) {
|
|
2433
2312
|
const trimmed = encResumeId.trim();
|
|
2434
2313
|
if (!trimmed) {
|
|
2435
2314
|
throw new CliError("enc_resume_id must not be empty", ExitCode.InvalidArgument);
|
|
2436
2315
|
}
|
|
2437
|
-
const { body } = await
|
|
2316
|
+
const { body } = await enterpriseGet2(
|
|
2438
2317
|
{ baseUrl: ctx.baseUrl, locale: ctx.locale, timeoutMs: ctx.timeoutMs, apiKey },
|
|
2439
2318
|
`/talents/${encodeURIComponent(trimmed)}`
|
|
2440
2319
|
);
|
|
2441
|
-
const resume = unwrapDataResponse(body);
|
|
2320
|
+
const resume = (0, import_core22.unwrapDataResponse)(body);
|
|
2442
2321
|
if (flags.fields) {
|
|
2443
2322
|
printJson(pickPaths(resume, parseFieldsList(flags.fields)));
|
|
2444
2323
|
return;
|
|
@@ -2456,6 +2335,7 @@ function registerEnterpriseTalentsView(parent) {
|
|
|
2456
2335
|
|
|
2457
2336
|
// src/commands/enterprise/talents/respond.ts
|
|
2458
2337
|
var import_node_crypto7 = require("crypto");
|
|
2338
|
+
var import_core23 = require("@wport/core");
|
|
2459
2339
|
function resolveRespondBody(flags, options = {}) {
|
|
2460
2340
|
const hasBody = flags.body !== void 0;
|
|
2461
2341
|
const hasBodyFile = flags.bodyFile !== void 0;
|
|
@@ -2481,13 +2361,13 @@ async function runEnterpriseTalentsRespond(ctx, apiKey, encResumeId, flags, idem
|
|
|
2481
2361
|
const encJobId = flags.encJobId?.trim();
|
|
2482
2362
|
const payload = { subject, body };
|
|
2483
2363
|
if (encJobId) payload.enc_job_id = encJobId;
|
|
2484
|
-
const { body: respBody } = await
|
|
2364
|
+
const { body: respBody } = await enterprisePost2(
|
|
2485
2365
|
{ baseUrl: ctx.baseUrl, locale: ctx.locale, timeoutMs: ctx.timeoutMs, apiKey },
|
|
2486
2366
|
`/talents/${encodeURIComponent(trimmedId)}/respond`,
|
|
2487
2367
|
payload,
|
|
2488
2368
|
{ idempotencyKey }
|
|
2489
2369
|
);
|
|
2490
|
-
const result = unwrapDataResponse(respBody);
|
|
2370
|
+
const result = (0, import_core23.unwrapDataResponse)(respBody);
|
|
2491
2371
|
if (ctx.format === "json") {
|
|
2492
2372
|
printJson(result);
|
|
2493
2373
|
return;
|
|
@@ -2516,15 +2396,16 @@ function registerEnterpriseTalentsCommand(parent) {
|
|
|
2516
2396
|
|
|
2517
2397
|
// src/commands/enterprise/campaigns/create.ts
|
|
2518
2398
|
var import_node_crypto8 = require("crypto");
|
|
2399
|
+
var import_core24 = require("@wport/core");
|
|
2519
2400
|
async function runCampaignCreate(ctx, apiKey, source, idempotencyKey) {
|
|
2520
2401
|
const campaignBody = readJsonObject(source, { timeoutMs: ctx.timeoutMs });
|
|
2521
|
-
const { body } = await
|
|
2402
|
+
const { body } = await enterprisePost2(
|
|
2522
2403
|
{ baseUrl: ctx.baseUrl, locale: ctx.locale, timeoutMs: ctx.timeoutMs, apiKey },
|
|
2523
2404
|
"/campaigns",
|
|
2524
2405
|
campaignBody,
|
|
2525
2406
|
{ idempotencyKey }
|
|
2526
2407
|
);
|
|
2527
|
-
const created = unwrapDataResponse(body);
|
|
2408
|
+
const created = (0, import_core24.unwrapDataResponse)(body);
|
|
2528
2409
|
if (ctx.format === "json") {
|
|
2529
2410
|
printJson(created);
|
|
2530
2411
|
return;
|
|
@@ -2542,6 +2423,7 @@ function registerEnterpriseCampaignsCreate(parent) {
|
|
|
2542
2423
|
}
|
|
2543
2424
|
|
|
2544
2425
|
// src/commands/enterprise/campaigns/list.ts
|
|
2426
|
+
var import_core25 = require("@wport/core");
|
|
2545
2427
|
var STATUS_MAP2 = { open: 1, closed: 0 };
|
|
2546
2428
|
var MINIMAL_LIST_FIELDS3 = ["enc_id", "name", "status", "job_count"];
|
|
2547
2429
|
function mapStatusFlag2(raw) {
|
|
@@ -2561,7 +2443,7 @@ async function runEnterpriseCampaignsList(ctx, apiKey, flags) {
|
|
|
2561
2443
|
if (flags.fields && flags.minimal) {
|
|
2562
2444
|
throw new CliError("Use either --fields or --minimal, not both", ExitCode.InvalidArgument);
|
|
2563
2445
|
}
|
|
2564
|
-
const { body } = await
|
|
2446
|
+
const { body } = await enterpriseGet2(
|
|
2565
2447
|
{ baseUrl: ctx.baseUrl, locale: ctx.locale, timeoutMs: ctx.timeoutMs, apiKey },
|
|
2566
2448
|
"/campaigns",
|
|
2567
2449
|
{
|
|
@@ -2571,7 +2453,7 @@ async function runEnterpriseCampaignsList(ctx, apiKey, flags) {
|
|
|
2571
2453
|
status: mapStatusFlag2(flags.status)
|
|
2572
2454
|
}
|
|
2573
2455
|
);
|
|
2574
|
-
const paged = asPaginatedBody(body);
|
|
2456
|
+
const paged = (0, import_core25.asPaginatedBody)(body);
|
|
2575
2457
|
const projection = flags.minimal ? MINIMAL_LIST_FIELDS3 : flags.fields ? parseFieldsList(flags.fields) : void 0;
|
|
2576
2458
|
if (projection || ctx.format === "json") {
|
|
2577
2459
|
printJson(projection ? { ...paged, data: paged.data.map((row) => pickPaths(row, projection)) } : paged);
|
|
@@ -2604,15 +2486,16 @@ function registerEnterpriseCampaignsList(parent) {
|
|
|
2604
2486
|
|
|
2605
2487
|
// src/commands/enterprise/campaigns/lifecycle.ts
|
|
2606
2488
|
var import_node_crypto9 = require("crypto");
|
|
2489
|
+
var import_core26 = require("@wport/core");
|
|
2607
2490
|
async function runCampaignTransition(ctx, apiKey, encId, action, idempotencyKey) {
|
|
2608
2491
|
const trimmed = requireEncId(encId);
|
|
2609
|
-
const { body } = await
|
|
2492
|
+
const { body } = await enterprisePatch2(
|
|
2610
2493
|
{ baseUrl: ctx.baseUrl, locale: ctx.locale, timeoutMs: ctx.timeoutMs, apiKey },
|
|
2611
2494
|
`/campaigns/${encodeURIComponent(trimmed)}/${action}`,
|
|
2612
2495
|
{},
|
|
2613
2496
|
{ idempotencyKey }
|
|
2614
2497
|
);
|
|
2615
|
-
const result = unwrapDataResponse(body);
|
|
2498
|
+
const result = (0, import_core26.unwrapDataResponse)(body);
|
|
2616
2499
|
if (ctx.format === "json") {
|
|
2617
2500
|
printJson(result);
|
|
2618
2501
|
return;
|
|
@@ -2638,16 +2521,17 @@ function registerEnterpriseCampaignsUnpublish(parent) {
|
|
|
2638
2521
|
|
|
2639
2522
|
// src/commands/enterprise/campaigns/update.ts
|
|
2640
2523
|
var import_node_crypto10 = require("crypto");
|
|
2524
|
+
var import_core27 = require("@wport/core");
|
|
2641
2525
|
async function runCampaignUpdate(ctx, apiKey, encId, source, idempotencyKey) {
|
|
2642
2526
|
const trimmed = requireEncId(encId);
|
|
2643
2527
|
const campaignBody = readJsonObject(source, { timeoutMs: ctx.timeoutMs });
|
|
2644
|
-
const { body } = await
|
|
2528
|
+
const { body } = await enterprisePatch2(
|
|
2645
2529
|
{ baseUrl: ctx.baseUrl, locale: ctx.locale, timeoutMs: ctx.timeoutMs, apiKey },
|
|
2646
2530
|
`/campaigns/${encodeURIComponent(trimmed)}`,
|
|
2647
2531
|
campaignBody,
|
|
2648
2532
|
{ idempotencyKey }
|
|
2649
2533
|
);
|
|
2650
|
-
const updated = unwrapDataResponse(body);
|
|
2534
|
+
const updated = (0, import_core27.unwrapDataResponse)(body);
|
|
2651
2535
|
if (ctx.format === "json") {
|
|
2652
2536
|
printJson(updated);
|
|
2653
2537
|
return;
|
|
@@ -2665,16 +2549,17 @@ function registerEnterpriseCampaignsUpdate(parent) {
|
|
|
2665
2549
|
}
|
|
2666
2550
|
|
|
2667
2551
|
// src/commands/enterprise/campaigns/view.ts
|
|
2552
|
+
var import_core28 = require("@wport/core");
|
|
2668
2553
|
async function runEnterpriseCampaignsView(ctx, apiKey, encId, flags) {
|
|
2669
2554
|
const trimmed = encId.trim();
|
|
2670
2555
|
if (!trimmed) {
|
|
2671
2556
|
throw new CliError("enc_id must not be empty", ExitCode.InvalidArgument);
|
|
2672
2557
|
}
|
|
2673
|
-
const { body } = await
|
|
2558
|
+
const { body } = await enterpriseGet2(
|
|
2674
2559
|
{ baseUrl: ctx.baseUrl, locale: ctx.locale, timeoutMs: ctx.timeoutMs, apiKey },
|
|
2675
2560
|
`/campaigns/${encodeURIComponent(trimmed)}`
|
|
2676
2561
|
);
|
|
2677
|
-
const campaign = unwrapDataResponse(body);
|
|
2562
|
+
const campaign = (0, import_core28.unwrapDataResponse)(body);
|
|
2678
2563
|
if (flags.fields) {
|
|
2679
2564
|
printJson(pickPaths(campaign, parseFieldsList(flags.fields)));
|
|
2680
2565
|
return;
|
|
@@ -2818,7 +2703,11 @@ function registerLoginCommand(program2) {
|
|
|
2818
2703
|
});
|
|
2819
2704
|
}
|
|
2820
2705
|
|
|
2706
|
+
// src/commands/auth/whoami.ts
|
|
2707
|
+
var import_core30 = require("@wport/core");
|
|
2708
|
+
|
|
2821
2709
|
// src/lib/personal-client.ts
|
|
2710
|
+
var import_core29 = require("@wport/core");
|
|
2822
2711
|
var EXPIRY_SKEW_MS = 3e4;
|
|
2823
2712
|
var NOT_LOGGED_IN_MESSAGE = "Not logged in. Run `wport login`.";
|
|
2824
2713
|
async function ensureFreshCredentials(opts) {
|
|
@@ -2847,7 +2736,7 @@ async function attemptRequest(opts, method, path, accessToken, body, query, extr
|
|
|
2847
2736
|
const headers = {
|
|
2848
2737
|
Authorization: `Bearer ${accessToken}`,
|
|
2849
2738
|
"Accept-Language": opts.locale,
|
|
2850
|
-
"User-Agent": buildUserAgent(),
|
|
2739
|
+
"User-Agent": (0, import_core29.buildUserAgent)("wport-cli", "0.9.1"),
|
|
2851
2740
|
Accept: "application/json"
|
|
2852
2741
|
};
|
|
2853
2742
|
if (body !== void 0) headers["Content-Type"] = "application/json";
|
|
@@ -2857,7 +2746,7 @@ async function attemptRequest(opts, method, path, accessToken, body, query, extr
|
|
|
2857
2746
|
headers,
|
|
2858
2747
|
body: body !== void 0 ? JSON.stringify(body) : void 0
|
|
2859
2748
|
});
|
|
2860
|
-
const res = await fetchWithTimeout(request, opts.timeoutMs);
|
|
2749
|
+
const res = await (0, import_core29.fetchWithTimeout)(request, opts.timeoutMs);
|
|
2861
2750
|
const respBody = await res.json().catch(() => null);
|
|
2862
2751
|
return { status: res.status, body: respBody, headers: res.headers };
|
|
2863
2752
|
}
|
|
@@ -2889,13 +2778,13 @@ function personalDelete(opts, path, extra) {
|
|
|
2889
2778
|
}
|
|
2890
2779
|
function throwPersonalHttpError(status, body) {
|
|
2891
2780
|
if (status === 401) {
|
|
2892
|
-
const base = extractErrorMessage(body) ?? `HTTP ${status}`;
|
|
2781
|
+
const base = (0, import_core29.extractErrorMessage)(body) ?? `HTTP ${status}`;
|
|
2893
2782
|
throw new CliError(
|
|
2894
2783
|
`${base} \u2014 Your session may have expired or the request was rejected. Run \`wport login\` to sign in again.`,
|
|
2895
2784
|
ExitCode.ServerClientError
|
|
2896
2785
|
);
|
|
2897
2786
|
}
|
|
2898
|
-
throwForHttpStatus(status, body);
|
|
2787
|
+
(0, import_core29.throwForHttpStatus)(status, body);
|
|
2899
2788
|
}
|
|
2900
2789
|
function warnIfRateLimitLow2(headers) {
|
|
2901
2790
|
const remaining = Number(headers.get("x-ratelimit-remaining"));
|
|
@@ -2906,6 +2795,7 @@ function warnIfRateLimitLow2(headers) {
|
|
|
2906
2795
|
}
|
|
2907
2796
|
|
|
2908
2797
|
// src/commands/auth/whoami.ts
|
|
2798
|
+
var import_core31 = require("@wport/core");
|
|
2909
2799
|
var PLACEHOLDER = "\u2014";
|
|
2910
2800
|
function display(value) {
|
|
2911
2801
|
const clean = sanitizeForTerminal(value ?? "");
|
|
@@ -2913,8 +2803,8 @@ function display(value) {
|
|
|
2913
2803
|
}
|
|
2914
2804
|
async function performWhoami(ctx) {
|
|
2915
2805
|
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);
|
|
2806
|
+
const { body } = await personalGet(opts, import_core31.OAUTH_SESSIONS_BASE);
|
|
2807
|
+
const sessions = (0, import_core30.unwrapDataArray)(body);
|
|
2918
2808
|
const current = sessions.find((s) => s.is_current);
|
|
2919
2809
|
const localLoginAt = loadPersonalCredentials()?.session_created_at ?? null;
|
|
2920
2810
|
if (ctx.format === "json") {
|
|
@@ -2966,13 +2856,15 @@ function registerLogoutCommand(program2) {
|
|
|
2966
2856
|
}
|
|
2967
2857
|
|
|
2968
2858
|
// src/commands/sessions/list.ts
|
|
2859
|
+
var import_core32 = require("@wport/core");
|
|
2860
|
+
var import_core33 = require("@wport/core");
|
|
2969
2861
|
function formatDate5(value) {
|
|
2970
2862
|
return value ? String(value).slice(0, 10) : "";
|
|
2971
2863
|
}
|
|
2972
2864
|
async function runSessionsList(ctx) {
|
|
2973
2865
|
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);
|
|
2866
|
+
const { body } = await personalGet(opts, import_core33.OAUTH_SESSIONS_BASE);
|
|
2867
|
+
const sessions = (0, import_core32.unwrapDataArray)(body);
|
|
2976
2868
|
if (ctx.format === "json") {
|
|
2977
2869
|
printJson(sessions);
|
|
2978
2870
|
return;
|
|
@@ -2996,6 +2888,8 @@ function registerSessionsList(parent) {
|
|
|
2996
2888
|
}
|
|
2997
2889
|
|
|
2998
2890
|
// src/commands/sessions/revoke.ts
|
|
2891
|
+
var import_core34 = require("@wport/core");
|
|
2892
|
+
var import_core35 = require("@wport/core");
|
|
2999
2893
|
async function runSessionsRevoke(ctx, encId, allOthers) {
|
|
3000
2894
|
const hasEncId = encId !== void 0;
|
|
3001
2895
|
if (hasEncId === allOthers) {
|
|
@@ -3003,8 +2897,8 @@ async function runSessionsRevoke(ctx, encId, allOthers) {
|
|
|
3003
2897
|
}
|
|
3004
2898
|
const opts = { baseUrl: ctx.baseUrl, locale: ctx.locale, timeoutMs: ctx.timeoutMs };
|
|
3005
2899
|
if (allOthers) {
|
|
3006
|
-
const { body } = await personalDelete(opts, `${OAUTH_SESSIONS_BASE}/others`);
|
|
3007
|
-
const result = unwrapDataResponse(body);
|
|
2900
|
+
const { body } = await personalDelete(opts, `${import_core34.OAUTH_SESSIONS_BASE}/others`);
|
|
2901
|
+
const result = (0, import_core35.unwrapDataResponse)(body);
|
|
3008
2902
|
if (ctx.format === "json") {
|
|
3009
2903
|
printJson(result);
|
|
3010
2904
|
return;
|
|
@@ -3015,7 +2909,7 @@ async function runSessionsRevoke(ctx, encId, allOthers) {
|
|
|
3015
2909
|
}
|
|
3016
2910
|
const trimmed = encId.trim();
|
|
3017
2911
|
if (!trimmed) throw new CliError("enc_id must not be empty", ExitCode.InvalidArgument);
|
|
3018
|
-
await personalDelete(opts, `${OAUTH_SESSIONS_BASE}/${encodeURIComponent(trimmed)}`);
|
|
2912
|
+
await personalDelete(opts, `${import_core34.OAUTH_SESSIONS_BASE}/${encodeURIComponent(trimmed)}`);
|
|
3019
2913
|
if (ctx.format === "json") {
|
|
3020
2914
|
printJson({ enc_id: trimmed, revoked: true });
|
|
3021
2915
|
return;
|
|
@@ -3037,949 +2931,19 @@ function registerSessionsCommand(program2) {
|
|
|
3037
2931
|
registerSessionsRevoke(sessions);
|
|
3038
2932
|
}
|
|
3039
2933
|
|
|
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
2934
|
// src/commands/personal/resumes/schema.ts
|
|
2935
|
+
var import_core36 = require("@wport/core");
|
|
3736
2936
|
function registerPersonalResumesSchema(parent) {
|
|
3737
2937
|
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);
|
|
2938
|
+
printJson((0, import_core36.buildAggregateJsonSchema)(opts.section));
|
|
3904
2939
|
});
|
|
3905
2940
|
}
|
|
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
2941
|
|
|
3979
2942
|
// src/commands/personal/resumes/validate.ts
|
|
2943
|
+
var import_core37 = require("@wport/core");
|
|
3980
2944
|
function runResumesValidate(ctx, filePath) {
|
|
3981
2945
|
const input = readJsonInput(filePath, { timeoutMs: ctx.timeoutMs });
|
|
3982
|
-
const issues = validateAggregate(input);
|
|
2946
|
+
const issues = (0, import_core37.validateAggregate)(input);
|
|
3983
2947
|
if (issues.length === 0) {
|
|
3984
2948
|
if (ctx.format === "json") {
|
|
3985
2949
|
printJson({ valid: true });
|
|
@@ -4007,43 +2971,9 @@ function registerPersonalResumesValidate(parent) {
|
|
|
4007
2971
|
|
|
4008
2972
|
// src/commands/personal/resumes/template.ts
|
|
4009
2973
|
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
|
|
2974
|
+
var import_core38 = require("@wport/core");
|
|
4045
2975
|
function runResumesTemplate(outPath) {
|
|
4046
|
-
const template = buildTemplate();
|
|
2976
|
+
const template = (0, import_core38.buildTemplate)();
|
|
4047
2977
|
if (outPath === void 0) {
|
|
4048
2978
|
printJson(template);
|
|
4049
2979
|
return;
|
|
@@ -4067,6 +2997,8 @@ function registerPersonalResumesTemplate(parent) {
|
|
|
4067
2997
|
}
|
|
4068
2998
|
|
|
4069
2999
|
// src/commands/personal/resumes/list.ts
|
|
3000
|
+
var import_core39 = require("@wport/core");
|
|
3001
|
+
var import_core40 = require("@wport/core");
|
|
4070
3002
|
var MINIMAL_LIST_FIELDS4 = ["enc_id", "name", "updated_at", "is_complete", "is_published"];
|
|
4071
3003
|
function formatDate6(value) {
|
|
4072
3004
|
return value ? String(value).slice(0, 10) : "";
|
|
@@ -4076,8 +3008,8 @@ function formatQuotaLine(quota) {
|
|
|
4076
3008
|
return `${quota.used}/${quota.max_resumes} used, ${status}.`;
|
|
4077
3009
|
}
|
|
4078
3010
|
async function fetchResumeList(opts) {
|
|
4079
|
-
const { body } = await personalGet(opts, PERSONAL_RESUMES_BASE);
|
|
4080
|
-
return unwrapDataResponse(body);
|
|
3011
|
+
const { body } = await personalGet(opts, import_core40.PERSONAL_RESUMES_BASE);
|
|
3012
|
+
return (0, import_core39.unwrapDataResponse)(body);
|
|
4081
3013
|
}
|
|
4082
3014
|
async function runResumesList(ctx, flags) {
|
|
4083
3015
|
if (flags.fields && flags.minimal) {
|
|
@@ -4110,17 +3042,20 @@ function registerPersonalResumesList(parent) {
|
|
|
4110
3042
|
}
|
|
4111
3043
|
|
|
4112
3044
|
// src/commands/personal/resumes/view.ts
|
|
3045
|
+
var import_core41 = require("@wport/core");
|
|
3046
|
+
var import_core42 = require("@wport/core");
|
|
3047
|
+
var import_core43 = require("@wport/core");
|
|
4113
3048
|
async function fetchResumeAggregate(opts, encId) {
|
|
4114
3049
|
const trimmed = encId.trim();
|
|
4115
3050
|
if (!trimmed) {
|
|
4116
3051
|
throw new CliError("enc_id must not be empty", ExitCode.InvalidArgument);
|
|
4117
3052
|
}
|
|
4118
|
-
const { body } = await personalGet(opts, `${PERSONAL_RESUMES_BASE}/${encodeURIComponent(trimmed)}`);
|
|
4119
|
-
return unwrapDataResponse(body);
|
|
3053
|
+
const { body } = await personalGet(opts, `${import_core42.PERSONAL_RESUMES_BASE}/${encodeURIComponent(trimmed)}`);
|
|
3054
|
+
return (0, import_core41.unwrapDataResponse)(body);
|
|
4120
3055
|
}
|
|
4121
3056
|
function summarizeSections(resume) {
|
|
4122
3057
|
const rows = [{ section: "name", summary: resume.name }];
|
|
4123
|
-
for (const def of SECTIONS) {
|
|
3058
|
+
for (const def of import_core43.SECTIONS) {
|
|
4124
3059
|
rows.push({ section: def.key, summary: summarizeSection(def, resume) });
|
|
4125
3060
|
}
|
|
4126
3061
|
return rows;
|
|
@@ -4197,8 +3132,14 @@ function registerPersonalResumesExport(parent) {
|
|
|
4197
3132
|
});
|
|
4198
3133
|
}
|
|
4199
3134
|
|
|
3135
|
+
// src/commands/personal/resumes/create.ts
|
|
3136
|
+
var import_core47 = require("@wport/core");
|
|
3137
|
+
|
|
4200
3138
|
// src/lib/resume-orchestrator.ts
|
|
4201
3139
|
var import_node_crypto11 = require("crypto");
|
|
3140
|
+
var import_core44 = require("@wport/core");
|
|
3141
|
+
var import_core45 = require("@wport/core");
|
|
3142
|
+
var import_core46 = require("@wport/core");
|
|
4202
3143
|
function freshIdempotencyKey() {
|
|
4203
3144
|
return { idempotencyKey: (0, import_node_crypto11.randomUUID)() };
|
|
4204
3145
|
}
|
|
@@ -4213,8 +3154,8 @@ function extractErrorCode(body) {
|
|
|
4213
3154
|
}
|
|
4214
3155
|
async function createShell(opts) {
|
|
4215
3156
|
try {
|
|
4216
|
-
const { body } = await personalPost(opts, PERSONAL_RESUMES_BASE, {}, freshIdempotencyKey());
|
|
4217
|
-
return unwrapDataResponse(body).enc_id;
|
|
3157
|
+
const { body } = await personalPost(opts, import_core45.PERSONAL_RESUMES_BASE, {}, freshIdempotencyKey());
|
|
3158
|
+
return (0, import_core44.unwrapDataResponse)(body).enc_id;
|
|
4218
3159
|
} catch (err) {
|
|
4219
3160
|
if (err instanceof ServerClientHttpError) {
|
|
4220
3161
|
const code = extractErrorCode(err.body);
|
|
@@ -4235,7 +3176,7 @@ async function createShell(opts) {
|
|
|
4235
3176
|
}
|
|
4236
3177
|
}
|
|
4237
3178
|
async function renameResume(opts, encId, name) {
|
|
4238
|
-
await personalPut(opts, `${PERSONAL_RESUMES_BASE}/${encodeURIComponent(encId)}/name`, { name }, freshIdempotencyKey());
|
|
3179
|
+
await personalPut(opts, `${import_core45.PERSONAL_RESUMES_BASE}/${encodeURIComponent(encId)}/name`, { name }, freshIdempotencyKey());
|
|
4239
3180
|
}
|
|
4240
3181
|
function toWorkExperienceWriteItem(item) {
|
|
4241
3182
|
const { is_current, ...rest } = item;
|
|
@@ -4247,8 +3188,8 @@ function splitItemEncId(item) {
|
|
|
4247
3188
|
return [valid, rest];
|
|
4248
3189
|
}
|
|
4249
3190
|
async function writeSection(opts, encId, key, value, mode) {
|
|
4250
|
-
const plan = SECTION_WRITE_PLAN[key];
|
|
4251
|
-
const base = `${PERSONAL_RESUMES_BASE}/${encodeURIComponent(encId)}`;
|
|
3191
|
+
const plan = import_core45.SECTION_WRITE_PLAN[key];
|
|
3192
|
+
const base = `${import_core45.PERSONAL_RESUMES_BASE}/${encodeURIComponent(encId)}`;
|
|
4252
3193
|
switch (plan.kind) {
|
|
4253
3194
|
case "per-item-post": {
|
|
4254
3195
|
for (const item of value) {
|
|
@@ -4315,7 +3256,7 @@ async function createAggregate(opts, aggregate) {
|
|
|
4315
3256
|
if (aggregate.name !== void 0) {
|
|
4316
3257
|
reports.push(await attemptStep("name", () => renameResume(opts, encId, aggregate.name)));
|
|
4317
3258
|
}
|
|
4318
|
-
for (const section of SECTIONS) {
|
|
3259
|
+
for (const section of import_core46.SECTIONS) {
|
|
4319
3260
|
const value = aggregate[section.key];
|
|
4320
3261
|
if (value === void 0) continue;
|
|
4321
3262
|
reports.push(await attemptStep(section.key, () => writeSection(opts, encId, section.key, value, "create")));
|
|
@@ -4325,9 +3266,9 @@ async function createAggregate(opts, aggregate) {
|
|
|
4325
3266
|
async function updateAggregate(opts, encId, aggregate, onlySection) {
|
|
4326
3267
|
const reports = [];
|
|
4327
3268
|
if (onlySection !== void 0) {
|
|
4328
|
-
const section = getSection(onlySection);
|
|
3269
|
+
const section = (0, import_core46.getSection)(onlySection);
|
|
4329
3270
|
if (!section) {
|
|
4330
|
-
const allowed = SECTIONS.map((s) => s.key).join(", ");
|
|
3271
|
+
const allowed = import_core46.SECTIONS.map((s) => s.key).join(", ");
|
|
4331
3272
|
throw new CliError(`Unknown section "${onlySection}". Allowed: ${allowed}`, ExitCode.InvalidArgument);
|
|
4332
3273
|
}
|
|
4333
3274
|
const value = aggregate[onlySection];
|
|
@@ -4340,7 +3281,7 @@ async function updateAggregate(opts, encId, aggregate, onlySection) {
|
|
|
4340
3281
|
if (aggregate.name !== void 0) {
|
|
4341
3282
|
reports.push(await attemptStep("name", () => renameResume(opts, encId, aggregate.name)));
|
|
4342
3283
|
}
|
|
4343
|
-
for (const section of SECTIONS) {
|
|
3284
|
+
for (const section of import_core46.SECTIONS) {
|
|
4344
3285
|
const value = aggregate[section.key];
|
|
4345
3286
|
if (value === void 0) continue;
|
|
4346
3287
|
reports.push(await attemptStep(section.key, () => writeSection(opts, encId, section.key, value, "update")));
|
|
@@ -4351,7 +3292,7 @@ async function updateAggregate(opts, encId, aggregate, onlySection) {
|
|
|
4351
3292
|
// src/commands/personal/resumes/create.ts
|
|
4352
3293
|
async function runResumesCreate(ctx, filePath) {
|
|
4353
3294
|
const input = readJsonObject(filePath, { timeoutMs: ctx.timeoutMs });
|
|
4354
|
-
const issues = validateAggregate(input);
|
|
3295
|
+
const issues = (0, import_core47.validateAggregate)(input);
|
|
4355
3296
|
if (issues.length > 0) {
|
|
4356
3297
|
if (ctx.format === "json") {
|
|
4357
3298
|
printJson({ valid: false, issues });
|
|
@@ -4444,6 +3385,8 @@ function registerPersonalResumesUpdate(parent) {
|
|
|
4444
3385
|
|
|
4445
3386
|
// src/commands/personal/resumes/copy.ts
|
|
4446
3387
|
var import_node_crypto12 = require("crypto");
|
|
3388
|
+
var import_core48 = require("@wport/core");
|
|
3389
|
+
var import_core49 = require("@wport/core");
|
|
4447
3390
|
function requireEncId3(encId) {
|
|
4448
3391
|
const trimmed = encId.trim();
|
|
4449
3392
|
if (!trimmed) {
|
|
@@ -4462,12 +3405,12 @@ function printCopyResult(ctx, sourceEncId, newEncId) {
|
|
|
4462
3405
|
async function runResumesCopy(ctx, encId, name) {
|
|
4463
3406
|
const trimmed = requireEncId3(encId);
|
|
4464
3407
|
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);
|
|
3408
|
+
const { body } = await personalPost(opts, `${import_core49.PERSONAL_RESUMES_BASE}/${encodeURIComponent(trimmed)}/duplicate`, {}, { idempotencyKey: (0, import_node_crypto12.randomUUID)() });
|
|
3409
|
+
const { enc_id: newEncId } = (0, import_core48.unwrapDataResponse)(body);
|
|
4467
3410
|
printCopyResult(ctx, trimmed, newEncId);
|
|
4468
3411
|
if (name === void 0) return;
|
|
4469
3412
|
try {
|
|
4470
|
-
await personalPut(opts, `${PERSONAL_RESUMES_BASE}/${encodeURIComponent(newEncId)}/name`, { name }, { idempotencyKey: (0, import_node_crypto12.randomUUID)() });
|
|
3413
|
+
await personalPut(opts, `${import_core49.PERSONAL_RESUMES_BASE}/${encodeURIComponent(newEncId)}/name`, { name }, { idempotencyKey: (0, import_node_crypto12.randomUUID)() });
|
|
4471
3414
|
} catch (err) {
|
|
4472
3415
|
const reason = err instanceof Error ? err.message : String(err);
|
|
4473
3416
|
throw new CliError(
|
|
@@ -4484,6 +3427,8 @@ function registerPersonalResumesCopy(parent) {
|
|
|
4484
3427
|
|
|
4485
3428
|
// src/commands/personal/resumes/publish.ts
|
|
4486
3429
|
var import_node_crypto13 = require("crypto");
|
|
3430
|
+
var import_core50 = require("@wport/core");
|
|
3431
|
+
var import_core51 = require("@wport/core");
|
|
4487
3432
|
function requireEncId4(encId) {
|
|
4488
3433
|
const trimmed = encId.trim();
|
|
4489
3434
|
if (!trimmed) {
|
|
@@ -4497,11 +3442,11 @@ async function runResumesPublishTransition(ctx, encId, action) {
|
|
|
4497
3442
|
const targetStatus = action === "publish";
|
|
4498
3443
|
const { body } = await personalPatch(
|
|
4499
3444
|
opts,
|
|
4500
|
-
`${PERSONAL_RESUMES_BASE}/${encodeURIComponent(trimmed)}/published-status`,
|
|
3445
|
+
`${import_core51.PERSONAL_RESUMES_BASE}/${encodeURIComponent(trimmed)}/published-status`,
|
|
4501
3446
|
{ target_status: targetStatus },
|
|
4502
3447
|
{ idempotencyKey: (0, import_node_crypto13.randomUUID)() }
|
|
4503
3448
|
);
|
|
4504
|
-
const result = unwrapDataResponse(body);
|
|
3449
|
+
const result = (0, import_core50.unwrapDataResponse)(body);
|
|
4505
3450
|
if (ctx.format === "json") {
|
|
4506
3451
|
printJson({ enc_id: trimmed, is_published: result.is_published });
|
|
4507
3452
|
return;
|
|
@@ -4523,6 +3468,7 @@ function registerPersonalResumesUnpublish(parent) {
|
|
|
4523
3468
|
|
|
4524
3469
|
// src/commands/personal/resumes/delete.ts
|
|
4525
3470
|
var import_node_crypto14 = require("crypto");
|
|
3471
|
+
var import_core52 = require("@wport/core");
|
|
4526
3472
|
function requireEncId5(encId) {
|
|
4527
3473
|
const trimmed = encId.trim();
|
|
4528
3474
|
if (!trimmed) {
|
|
@@ -4536,7 +3482,7 @@ async function runResumesDelete(ctx, encId, confirm) {
|
|
|
4536
3482
|
}
|
|
4537
3483
|
const trimmed = requireEncId5(encId);
|
|
4538
3484
|
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)() });
|
|
3485
|
+
await personalDelete(opts, `${import_core52.PERSONAL_RESUMES_BASE}/${encodeURIComponent(trimmed)}`, { idempotencyKey: (0, import_node_crypto14.randomUUID)() });
|
|
4540
3486
|
if (ctx.format === "json") {
|
|
4541
3487
|
printJson({ enc_id: trimmed, deleted: true });
|
|
4542
3488
|
return;
|
|
@@ -4570,6 +3516,7 @@ function registerPersonalResumesCommand(parent) {
|
|
|
4570
3516
|
// src/commands/personal/apply/index.ts
|
|
4571
3517
|
var import_node_crypto15 = require("crypto");
|
|
4572
3518
|
var import_node_fs11 = require("fs");
|
|
3519
|
+
var import_core53 = require("@wport/core");
|
|
4573
3520
|
|
|
4574
3521
|
// src/commands/personal/apply/message-input.ts
|
|
4575
3522
|
var import_node_fs10 = require("fs");
|
|
@@ -4651,7 +3598,7 @@ async function runPersonalApply(ctx, args) {
|
|
|
4651
3598
|
const body = { enc_job_id: args.encJobId, enc_resume_id: args.encResumeId, application_message: args.message };
|
|
4652
3599
|
let result;
|
|
4653
3600
|
try {
|
|
4654
|
-
result = await personalPost(opts, PERSONAL_APPLICATIONS_BASE, body, { idempotencyKey: (0, import_node_crypto15.randomUUID)() });
|
|
3601
|
+
result = await personalPost(opts, import_core53.PERSONAL_APPLICATIONS_BASE, body, { idempotencyKey: (0, import_node_crypto15.randomUUID)() });
|
|
4655
3602
|
} catch (err) {
|
|
4656
3603
|
rethrowApplyError(err);
|
|
4657
3604
|
}
|
|
@@ -4702,7 +3649,7 @@ async function runPersonalApplyBatch(ctx, args) {
|
|
|
4702
3649
|
const opts = { baseUrl: ctx.baseUrl, locale: ctx.locale, timeoutMs: ctx.timeoutMs };
|
|
4703
3650
|
let result;
|
|
4704
3651
|
try {
|
|
4705
|
-
result = await personalPost(opts, `${PERSONAL_APPLICATIONS_BASE}/batch`, { applications: items }, { idempotencyKey: (0, import_node_crypto15.randomUUID)() });
|
|
3652
|
+
result = await personalPost(opts, `${import_core53.PERSONAL_APPLICATIONS_BASE}/batch`, { applications: items }, { idempotencyKey: (0, import_node_crypto15.randomUUID)() });
|
|
4706
3653
|
} catch (err) {
|
|
4707
3654
|
rethrowApplyError(err);
|
|
4708
3655
|
}
|
|
@@ -4730,7 +3677,7 @@ function registerPersonalCommand(program2) {
|
|
|
4730
3677
|
|
|
4731
3678
|
// src/index.ts
|
|
4732
3679
|
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.1
|
|
3680
|
+
program.name("wport").description("wport CLI \u2014 terminal interface to the W101 Talent Search Hub public API").version("0.9.1", "-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
3681
|
registerJobsCommand(program);
|
|
4735
3682
|
registerConfigCommand(program);
|
|
4736
3683
|
registerDoctorCommand(program);
|
|
@@ -4756,6 +3703,10 @@ function handleTopLevelError(err) {
|
|
|
4756
3703
|
printError(err.message, color);
|
|
4757
3704
|
process.exit(err.exitCode);
|
|
4758
3705
|
}
|
|
3706
|
+
if ((0, import_core.isWportError)(err)) {
|
|
3707
|
+
printError(err.message, color);
|
|
3708
|
+
process.exit(exitCodeForError(err));
|
|
3709
|
+
}
|
|
4759
3710
|
const fallbackMessage = err instanceof Error ? err.message : String(err);
|
|
4760
3711
|
printError(fallbackMessage, color);
|
|
4761
3712
|
process.exit(ExitCode.ServerOrNetworkError);
|