@ait-co/console-cli 0.1.11 → 0.1.12
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/dist/cli.mjs +1262 -227
- package/dist/cli.mjs.map +1 -1
- package/package.json +1 -1
package/dist/cli.mjs
CHANGED
|
@@ -161,10 +161,10 @@ async function executeAndUnwrap(url, init, fetchImpl) {
|
|
|
161
161
|
}
|
|
162
162
|
//#endregion
|
|
163
163
|
//#region src/api/mini-apps.ts
|
|
164
|
-
const BASE$
|
|
164
|
+
const BASE$4 = "https://apps-in-toss.toss.im/console/api-public/v3/appsintossconsole";
|
|
165
165
|
async function fetchMiniApps(workspaceId, cookies, opts = {}) {
|
|
166
166
|
const raw = await requestConsoleApi({
|
|
167
|
-
url: `${BASE$
|
|
167
|
+
url: `${BASE$4}/workspaces/${workspaceId}/mini-app`,
|
|
168
168
|
cookies,
|
|
169
169
|
...opts.fetchImpl ? { fetchImpl: opts.fetchImpl } : {}
|
|
170
170
|
});
|
|
@@ -187,7 +187,7 @@ function normalizeMiniApp(item, workspaceId, index) {
|
|
|
187
187
|
}
|
|
188
188
|
async function fetchReviewStatus(workspaceId, cookies, opts = {}) {
|
|
189
189
|
const raw = await requestConsoleApi({
|
|
190
|
-
url: `${BASE$
|
|
190
|
+
url: `${BASE$4}/workspaces/${workspaceId}/mini-apps/review-status`,
|
|
191
191
|
cookies,
|
|
192
192
|
...opts.fetchImpl ? { fetchImpl: opts.fetchImpl } : {}
|
|
193
193
|
});
|
|
@@ -206,7 +206,7 @@ async function fetchReviewStatus(workspaceId, cookies, opts = {}) {
|
|
|
206
206
|
}
|
|
207
207
|
async function fetchMiniAppWithDraft(workspaceId, miniAppId, cookies, opts = {}) {
|
|
208
208
|
const raw = await requestConsoleApi({
|
|
209
|
-
url: `${BASE$
|
|
209
|
+
url: `${BASE$4}/workspaces/${workspaceId}/mini-app/${miniAppId}/with-draft`,
|
|
210
210
|
cookies,
|
|
211
211
|
...opts.fetchImpl ? { fetchImpl: opts.fetchImpl } : {}
|
|
212
212
|
});
|
|
@@ -228,7 +228,7 @@ async function fetchMiniAppRatings(params, cookies, opts = {}) {
|
|
|
228
228
|
const sortField = params.sortField ?? "CREATED_AT";
|
|
229
229
|
const sortDirection = params.sortDirection ?? "DESC";
|
|
230
230
|
const raw = await requestConsoleApi({
|
|
231
|
-
url: `${BASE$
|
|
231
|
+
url: `${BASE$4}/workspaces/${params.workspaceId}/mini-app/${params.miniAppId}/app-ratings?page=${page}&size=${size}&sortField=${sortField}&sortDirection=${sortDirection}`,
|
|
232
232
|
cookies,
|
|
233
233
|
...opts.fetchImpl ? { fetchImpl: opts.fetchImpl } : {}
|
|
234
234
|
});
|
|
@@ -261,7 +261,7 @@ async function fetchUserReports(params, cookies, opts = {}) {
|
|
|
261
261
|
qs.set("pageSize", String(pageSize));
|
|
262
262
|
if (params.cursor !== void 0) qs.set("cursor", params.cursor);
|
|
263
263
|
const raw = await requestConsoleApi({
|
|
264
|
-
url: `${BASE$
|
|
264
|
+
url: `${BASE$4}/workspaces/${params.workspaceId}/mini-apps/${params.miniAppId}/user-reports?` + qs.toString(),
|
|
265
265
|
cookies,
|
|
266
266
|
...opts.fetchImpl ? { fetchImpl: opts.fetchImpl } : {}
|
|
267
267
|
});
|
|
@@ -285,7 +285,7 @@ async function fetchBundles(params, cookies, opts = {}) {
|
|
|
285
285
|
if (params.deployStatus !== void 0) qs.set("deployStatus", params.deployStatus);
|
|
286
286
|
const query = qs.toString();
|
|
287
287
|
const raw = await requestConsoleApi({
|
|
288
|
-
url: `${BASE$
|
|
288
|
+
url: `${BASE$4}/workspaces/${params.workspaceId}/mini-app/${params.miniAppId}/bundles` + (query ? `?${query}` : ""),
|
|
289
289
|
cookies,
|
|
290
290
|
...opts.fetchImpl ? { fetchImpl: opts.fetchImpl } : {}
|
|
291
291
|
});
|
|
@@ -309,7 +309,7 @@ async function fetchConversionMetrics(params, cookies, opts = {}) {
|
|
|
309
309
|
qs.set("startDate", params.startDate);
|
|
310
310
|
qs.set("endDate", params.endDate);
|
|
311
311
|
const raw = await requestConsoleApi({
|
|
312
|
-
url: `${BASE$
|
|
312
|
+
url: `${BASE$4}/workspaces/${params.workspaceId}/mini-app/${params.miniAppId}/conversion-metrics?${qs.toString()}`,
|
|
313
313
|
cookies,
|
|
314
314
|
...opts.fetchImpl ? { fetchImpl: opts.fetchImpl } : {}
|
|
315
315
|
});
|
|
@@ -327,7 +327,7 @@ async function fetchConversionMetrics(params, cookies, opts = {}) {
|
|
|
327
327
|
}
|
|
328
328
|
async function fetchCerts(workspaceId, miniAppId, cookies, opts = {}) {
|
|
329
329
|
const raw = await requestConsoleApi({
|
|
330
|
-
url: `${BASE$
|
|
330
|
+
url: `${BASE$4}/workspaces/${workspaceId}/mini-app/${miniAppId}/certs`,
|
|
331
331
|
cookies,
|
|
332
332
|
...opts.fetchImpl ? { fetchImpl: opts.fetchImpl } : {}
|
|
333
333
|
});
|
|
@@ -341,7 +341,7 @@ async function fetchShareRewards(params, cookies, opts = {}) {
|
|
|
341
341
|
const qs = new URLSearchParams();
|
|
342
342
|
qs.set("search", params.search ?? "");
|
|
343
343
|
const raw = await requestConsoleApi({
|
|
344
|
-
url: `${BASE$
|
|
344
|
+
url: `${BASE$4}/workspaces/${params.workspaceId}/mini-app/${params.miniAppId}/share-rewards?${qs.toString()}`,
|
|
345
345
|
cookies,
|
|
346
346
|
...opts.fetchImpl ? { fetchImpl: opts.fetchImpl } : {}
|
|
347
347
|
});
|
|
@@ -351,9 +351,164 @@ async function fetchShareRewards(params, cookies, opts = {}) {
|
|
|
351
351
|
return r;
|
|
352
352
|
});
|
|
353
353
|
}
|
|
354
|
+
async function fetchSmartMessageCampaigns(params, cookies, opts = {}) {
|
|
355
|
+
const page = params.page ?? 0;
|
|
356
|
+
const size = params.size ?? 20;
|
|
357
|
+
const qs = new URLSearchParams();
|
|
358
|
+
qs.set("page", String(page));
|
|
359
|
+
qs.set("size", String(size));
|
|
360
|
+
const raw = await requestConsoleApi({
|
|
361
|
+
method: "POST",
|
|
362
|
+
url: `${BASE$4}/workspaces/${params.workspaceId}/mini-app/${params.miniAppId}/smart-message/campaigns?${qs.toString()}`,
|
|
363
|
+
body: {
|
|
364
|
+
sort: params.sort ?? [{
|
|
365
|
+
field: "regTs",
|
|
366
|
+
direction: "DESC"
|
|
367
|
+
}],
|
|
368
|
+
search: params.search ?? "",
|
|
369
|
+
filters: params.filters ?? {}
|
|
370
|
+
},
|
|
371
|
+
cookies,
|
|
372
|
+
...opts.fetchImpl ? { fetchImpl: opts.fetchImpl } : {}
|
|
373
|
+
});
|
|
374
|
+
if (raw === null || typeof raw !== "object" || Array.isArray(raw)) throw new Error(`Unexpected smart-message campaigns shape for app=${params.miniAppId}`);
|
|
375
|
+
const data = raw;
|
|
376
|
+
const items = Array.isArray(data.items) ? data.items : [];
|
|
377
|
+
const rawPaging = data.paging;
|
|
378
|
+
const paging = {
|
|
379
|
+
pageNumber: typeof rawPaging?.pageNumber === "number" ? rawPaging.pageNumber : page,
|
|
380
|
+
pageSize: typeof rawPaging?.pageSize === "number" ? rawPaging.pageSize : size,
|
|
381
|
+
hasNext: Boolean(rawPaging?.hasNext),
|
|
382
|
+
totalCount: typeof rawPaging?.totalCount === "number" ? rawPaging.totalCount : items.length
|
|
383
|
+
};
|
|
384
|
+
return {
|
|
385
|
+
items: items.map((r) => r && typeof r === "object" ? r : {}),
|
|
386
|
+
paging
|
|
387
|
+
};
|
|
388
|
+
}
|
|
389
|
+
async function fetchAppEventCatalogs(params, cookies, opts = {}) {
|
|
390
|
+
const pageNumber = params.pageNumber ?? 0;
|
|
391
|
+
const pageSize = params.pageSize ?? 20;
|
|
392
|
+
const raw = await requestConsoleApi({
|
|
393
|
+
method: "POST",
|
|
394
|
+
url: `${BASE$4}/workspaces/${params.workspaceId}/mini-app/${params.miniAppId}/log/catalogs/search`,
|
|
395
|
+
body: {
|
|
396
|
+
isRefresh: params.refresh ?? false,
|
|
397
|
+
pageNumber,
|
|
398
|
+
pageSize,
|
|
399
|
+
search: params.search ?? ""
|
|
400
|
+
},
|
|
401
|
+
cookies,
|
|
402
|
+
...opts.fetchImpl ? { fetchImpl: opts.fetchImpl } : {}
|
|
403
|
+
});
|
|
404
|
+
if (raw === null || typeof raw !== "object" || Array.isArray(raw)) throw new Error(`Unexpected event-catalogs shape for app=${params.miniAppId}`);
|
|
405
|
+
const data = raw;
|
|
406
|
+
const results = Array.isArray(data.results) ? data.results : [];
|
|
407
|
+
const rawPaging = data.paging;
|
|
408
|
+
const paging = {
|
|
409
|
+
pageNumber: typeof rawPaging?.pageNumber === "number" ? rawPaging.pageNumber : pageNumber,
|
|
410
|
+
pageSize: typeof rawPaging?.pageSize === "number" ? rawPaging.pageSize : pageSize,
|
|
411
|
+
hasNext: Boolean(rawPaging?.hasNext),
|
|
412
|
+
totalCount: typeof rawPaging?.totalCount === "number" ? rawPaging.totalCount : results.length,
|
|
413
|
+
totalPages: typeof rawPaging?.totalPages === "number" ? rawPaging.totalPages : 0
|
|
414
|
+
};
|
|
415
|
+
return {
|
|
416
|
+
results: results.map((r) => r && typeof r === "object" ? r : {}),
|
|
417
|
+
cacheTime: typeof data.cacheTime === "string" ? data.cacheTime : void 0,
|
|
418
|
+
paging
|
|
419
|
+
};
|
|
420
|
+
}
|
|
421
|
+
const TEMPLATE_CONTENT_REACH_TYPES = ["FUNCTIONAL", "MARKETING"];
|
|
422
|
+
async function fetchAppTemplates(params, cookies, opts = {}) {
|
|
423
|
+
const page = params.page ?? 0;
|
|
424
|
+
const size = params.size ?? 20;
|
|
425
|
+
const qs = new URLSearchParams();
|
|
426
|
+
qs.set("page", String(page));
|
|
427
|
+
qs.set("size", String(size));
|
|
428
|
+
if (params.contentReachType) qs.set("contentReachType", params.contentReachType);
|
|
429
|
+
if (params.isSmartMessage !== void 0) qs.set("isSmartMessage", String(params.isSmartMessage));
|
|
430
|
+
const raw = await requestConsoleApi({
|
|
431
|
+
url: `${BASE$4}/workspaces/${params.workspaceId}/mini-app/${params.miniAppId}/templates/search?${qs.toString()}`,
|
|
432
|
+
cookies,
|
|
433
|
+
...opts.fetchImpl ? { fetchImpl: opts.fetchImpl } : {}
|
|
434
|
+
});
|
|
435
|
+
if (raw === null || typeof raw !== "object" || Array.isArray(raw)) throw new Error(`Unexpected templates shape for app=${params.miniAppId}`);
|
|
436
|
+
const data = raw;
|
|
437
|
+
const list = Array.isArray(data.groupSendContextSimpleView) ? data.groupSendContextSimpleView : [];
|
|
438
|
+
const pageMeta = data.page;
|
|
439
|
+
return {
|
|
440
|
+
templates: list.map((r) => r && typeof r === "object" ? r : {}),
|
|
441
|
+
totalPageCount: typeof pageMeta?.totalPageCount === "number" ? pageMeta.totalPageCount : 0
|
|
442
|
+
};
|
|
443
|
+
}
|
|
444
|
+
async function fetchImpressionCategoryList(cookies, opts = {}) {
|
|
445
|
+
const raw = await requestConsoleApi({
|
|
446
|
+
url: `${BASE$4}/impression/category-list`,
|
|
447
|
+
cookies,
|
|
448
|
+
...opts.fetchImpl ? { fetchImpl: opts.fetchImpl } : {}
|
|
449
|
+
});
|
|
450
|
+
if (!Array.isArray(raw)) throw new Error("Unexpected impression/category-list shape: not an array");
|
|
451
|
+
return raw.map((entry, i) => {
|
|
452
|
+
if (!entry || typeof entry !== "object") throw new Error(`Unexpected category-list entry at index ${i}`);
|
|
453
|
+
const e = entry;
|
|
454
|
+
const group = e.categoryGroup;
|
|
455
|
+
const list = Array.isArray(e.categoryList) ? e.categoryList : [];
|
|
456
|
+
return {
|
|
457
|
+
categoryGroup: {
|
|
458
|
+
id: typeof group?.id === "number" ? group.id : 0,
|
|
459
|
+
name: typeof group?.name === "string" ? group.name : "",
|
|
460
|
+
isSelectable: Boolean(group?.isSelectable)
|
|
461
|
+
},
|
|
462
|
+
categoryList: list.map((c) => {
|
|
463
|
+
if (!c || typeof c !== "object") return {
|
|
464
|
+
id: 0,
|
|
465
|
+
name: "",
|
|
466
|
+
isSelectable: false,
|
|
467
|
+
subCategoryList: []
|
|
468
|
+
};
|
|
469
|
+
const cr = c;
|
|
470
|
+
const subs = Array.isArray(cr.subCategoryList) ? cr.subCategoryList : [];
|
|
471
|
+
return {
|
|
472
|
+
id: typeof cr.id === "number" ? cr.id : 0,
|
|
473
|
+
name: typeof cr.name === "string" ? cr.name : "",
|
|
474
|
+
isSelectable: Boolean(cr.isSelectable),
|
|
475
|
+
subCategoryList: subs.map((s) => {
|
|
476
|
+
if (!s || typeof s !== "object") return {
|
|
477
|
+
id: 0,
|
|
478
|
+
name: "",
|
|
479
|
+
isSelectable: false
|
|
480
|
+
};
|
|
481
|
+
const sr = s;
|
|
482
|
+
return {
|
|
483
|
+
id: typeof sr.id === "number" ? sr.id : 0,
|
|
484
|
+
name: typeof sr.name === "string" ? sr.name : "",
|
|
485
|
+
isSelectable: Boolean(sr.isSelectable)
|
|
486
|
+
};
|
|
487
|
+
})
|
|
488
|
+
};
|
|
489
|
+
})
|
|
490
|
+
};
|
|
491
|
+
});
|
|
492
|
+
}
|
|
493
|
+
async function fetchAppServiceStatus(workspaceId, miniAppId, cookies, opts = {}) {
|
|
494
|
+
const raw = await requestConsoleApi({
|
|
495
|
+
url: `${BASE$4}/workspaces/${workspaceId}/mini-app/${miniAppId}/review-status`,
|
|
496
|
+
cookies,
|
|
497
|
+
...opts.fetchImpl ? { fetchImpl: opts.fetchImpl } : {}
|
|
498
|
+
});
|
|
499
|
+
if (raw === null || typeof raw !== "object" || Array.isArray(raw)) throw new Error(`Unexpected app service-status shape for app=${miniAppId}`);
|
|
500
|
+
const data = raw;
|
|
501
|
+
const serviceStatus = data.serviceStatus;
|
|
502
|
+
if (typeof serviceStatus !== "string") throw new Error(`Unexpected app service-status shape for app=${miniAppId}: missing serviceStatus`);
|
|
503
|
+
return {
|
|
504
|
+
shutdownCandidateStatus: typeof data.shutdownCandidateStatus === "string" ? data.shutdownCandidateStatus : null,
|
|
505
|
+
scheduledShutdownAt: typeof data.scheduledShutdownAt === "string" ? data.scheduledShutdownAt : null,
|
|
506
|
+
serviceStatus
|
|
507
|
+
};
|
|
508
|
+
}
|
|
354
509
|
async function fetchDeployedBundle(workspaceId, miniAppId, cookies, opts = {}) {
|
|
355
510
|
const raw = await requestConsoleApi({
|
|
356
|
-
url: `${BASE$
|
|
511
|
+
url: `${BASE$4}/workspaces/${workspaceId}/mini-app/${miniAppId}/bundles/deployed`,
|
|
357
512
|
cookies,
|
|
358
513
|
...opts.fetchImpl ? { fetchImpl: opts.fetchImpl } : {}
|
|
359
514
|
});
|
|
@@ -363,7 +518,7 @@ async function fetchDeployedBundle(workspaceId, miniAppId, cookies, opts = {}) {
|
|
|
363
518
|
}
|
|
364
519
|
async function createMiniApp(workspaceId, payload, cookies, opts = {}) {
|
|
365
520
|
return normalizeCreateResult(await requestConsoleApi({
|
|
366
|
-
url: `${BASE$
|
|
521
|
+
url: `${BASE$4}/workspaces/${workspaceId}/mini-app/review`,
|
|
367
522
|
method: "POST",
|
|
368
523
|
cookies,
|
|
369
524
|
body: payload,
|
|
@@ -396,7 +551,7 @@ function normalizeCreateResult(raw) {
|
|
|
396
551
|
* the field name is actually `file` — if so, swap it in one place here.
|
|
397
552
|
*/
|
|
398
553
|
async function uploadMiniAppResource(params, opts = {}) {
|
|
399
|
-
const url = new URL(`${BASE$
|
|
554
|
+
const url = new URL(`${BASE$4}/resource/${params.workspaceId}/upload`);
|
|
400
555
|
url.searchParams.set("validWidth", String(params.validWidth));
|
|
401
556
|
url.searchParams.set("validHeight", String(params.validHeight));
|
|
402
557
|
const form = new FormData();
|
|
@@ -2265,73 +2420,559 @@ const appCommand = defineCommand({
|
|
|
2265
2420
|
}
|
|
2266
2421
|
}) }
|
|
2267
2422
|
}),
|
|
2268
|
-
|
|
2423
|
+
messages: defineCommand({
|
|
2269
2424
|
meta: {
|
|
2270
|
-
name: "
|
|
2271
|
-
description: "
|
|
2425
|
+
name: "messages",
|
|
2426
|
+
description: "Inspect smart-message (formerly push) campaigns for a mini-app."
|
|
2272
2427
|
},
|
|
2273
|
-
|
|
2274
|
-
|
|
2275
|
-
|
|
2276
|
-
description: "
|
|
2428
|
+
subCommands: { ls: defineCommand({
|
|
2429
|
+
meta: {
|
|
2430
|
+
name: "ls",
|
|
2431
|
+
description: "List smart-message campaigns (formerly \"push\" — the 스마트 발송 menu)."
|
|
2277
2432
|
},
|
|
2278
|
-
|
|
2279
|
-
|
|
2280
|
-
|
|
2433
|
+
args: {
|
|
2434
|
+
id: {
|
|
2435
|
+
type: "positional",
|
|
2436
|
+
description: "Mini-app ID.",
|
|
2437
|
+
required: true
|
|
2438
|
+
},
|
|
2439
|
+
workspace: {
|
|
2440
|
+
type: "string",
|
|
2441
|
+
description: "Workspace ID. Defaults to the selected workspace."
|
|
2442
|
+
},
|
|
2443
|
+
page: {
|
|
2444
|
+
type: "string",
|
|
2445
|
+
description: "Page number (0-indexed).",
|
|
2446
|
+
default: "0"
|
|
2447
|
+
},
|
|
2448
|
+
size: {
|
|
2449
|
+
type: "string",
|
|
2450
|
+
description: "Page size.",
|
|
2451
|
+
default: "20"
|
|
2452
|
+
},
|
|
2453
|
+
search: {
|
|
2454
|
+
type: "string",
|
|
2455
|
+
description: "Title-contains filter. Empty matches everything."
|
|
2456
|
+
},
|
|
2457
|
+
json: {
|
|
2458
|
+
type: "boolean",
|
|
2459
|
+
description: "Emit machine-readable JSON.",
|
|
2460
|
+
default: false
|
|
2461
|
+
}
|
|
2281
2462
|
},
|
|
2282
|
-
|
|
2283
|
-
|
|
2284
|
-
|
|
2285
|
-
|
|
2463
|
+
async run({ args }) {
|
|
2464
|
+
const appId = parseAppId(args.id);
|
|
2465
|
+
if (appId === null) {
|
|
2466
|
+
if (args.json) emitJson({
|
|
2467
|
+
ok: false,
|
|
2468
|
+
reason: "invalid-id",
|
|
2469
|
+
message: `app id must be a positive integer (got ${JSON.stringify(args.id)})`
|
|
2470
|
+
});
|
|
2471
|
+
else process.stderr.write(`app messages ls: invalid id ${JSON.stringify(args.id)}\n`);
|
|
2472
|
+
return exitAfterFlush(ExitCode.Usage);
|
|
2473
|
+
}
|
|
2474
|
+
const pageResult = parseNonNegativeInt(String(args.page), "page");
|
|
2475
|
+
if ("error" in pageResult) {
|
|
2476
|
+
if (args.json) emitJson({
|
|
2477
|
+
ok: false,
|
|
2478
|
+
reason: "invalid-page",
|
|
2479
|
+
message: pageResult.error
|
|
2480
|
+
});
|
|
2481
|
+
else process.stderr.write(`${pageResult.error}\n`);
|
|
2482
|
+
return exitAfterFlush(ExitCode.Usage);
|
|
2483
|
+
}
|
|
2484
|
+
const sizeResult = parseNonNegativeInt(String(args.size), "size");
|
|
2485
|
+
if ("error" in sizeResult) {
|
|
2486
|
+
if (args.json) emitJson({
|
|
2487
|
+
ok: false,
|
|
2488
|
+
reason: "invalid-size",
|
|
2489
|
+
message: sizeResult.error
|
|
2490
|
+
});
|
|
2491
|
+
else process.stderr.write(`${sizeResult.error}\n`);
|
|
2492
|
+
return exitAfterFlush(ExitCode.Usage);
|
|
2493
|
+
}
|
|
2494
|
+
const ctx = await resolveWorkspaceContext(args);
|
|
2495
|
+
if (!ctx) return;
|
|
2496
|
+
const { session, workspaceId } = ctx;
|
|
2497
|
+
try {
|
|
2498
|
+
const result = await fetchSmartMessageCampaigns({
|
|
2499
|
+
workspaceId,
|
|
2500
|
+
miniAppId: appId,
|
|
2501
|
+
page: pageResult.value,
|
|
2502
|
+
size: sizeResult.value,
|
|
2503
|
+
...args.search !== void 0 ? { search: String(args.search) } : {}
|
|
2504
|
+
}, session.cookies);
|
|
2505
|
+
if (args.json) {
|
|
2506
|
+
emitJson({
|
|
2507
|
+
ok: true,
|
|
2508
|
+
workspaceId,
|
|
2509
|
+
appId,
|
|
2510
|
+
campaigns: result.items,
|
|
2511
|
+
paging: result.paging
|
|
2512
|
+
});
|
|
2513
|
+
return exitAfterFlush(ExitCode.Ok);
|
|
2514
|
+
}
|
|
2515
|
+
if (result.items.length === 0) {
|
|
2516
|
+
process.stdout.write(`App ${appId} (ws ${workspaceId}): no smart-message campaigns\n`);
|
|
2517
|
+
return exitAfterFlush(ExitCode.Ok);
|
|
2518
|
+
}
|
|
2519
|
+
process.stdout.write(`App ${appId} (ws ${workspaceId}): ${result.items.length} campaign(s) on page ${result.paging.pageNumber} of ${result.paging.totalCount}\n`);
|
|
2520
|
+
for (const c of result.items) {
|
|
2521
|
+
const id = typeof c.id === "string" || typeof c.id === "number" ? c.id : typeof c.campaignId === "string" || typeof c.campaignId === "number" ? c.campaignId : "-";
|
|
2522
|
+
const title = typeof c.title === "string" ? c.title : typeof c.name === "string" ? c.name : "-";
|
|
2523
|
+
const status = typeof c.status === "string" ? c.status : "-";
|
|
2524
|
+
process.stdout.write(`${id}\t${title}\t${status}\n`);
|
|
2525
|
+
}
|
|
2526
|
+
return exitAfterFlush(ExitCode.Ok);
|
|
2527
|
+
} catch (err) {
|
|
2528
|
+
return emitFailureFromError(args.json, err);
|
|
2529
|
+
}
|
|
2530
|
+
}
|
|
2531
|
+
}) }
|
|
2532
|
+
}),
|
|
2533
|
+
events: defineCommand({
|
|
2534
|
+
meta: {
|
|
2535
|
+
name: "events",
|
|
2536
|
+
description: "Inspect custom event catalogs (log search) for a mini-app."
|
|
2537
|
+
},
|
|
2538
|
+
subCommands: { ls: defineCommand({
|
|
2539
|
+
meta: {
|
|
2540
|
+
name: "ls",
|
|
2541
|
+
description: "List custom event catalogs recorded for a mini-app (the 이벤트 menu)."
|
|
2286
2542
|
},
|
|
2287
|
-
|
|
2288
|
-
|
|
2289
|
-
|
|
2290
|
-
|
|
2543
|
+
args: {
|
|
2544
|
+
id: {
|
|
2545
|
+
type: "positional",
|
|
2546
|
+
description: "Mini-app ID.",
|
|
2547
|
+
required: true
|
|
2548
|
+
},
|
|
2549
|
+
workspace: {
|
|
2550
|
+
type: "string",
|
|
2551
|
+
description: "Workspace ID. Defaults to the selected workspace."
|
|
2552
|
+
},
|
|
2553
|
+
page: {
|
|
2554
|
+
type: "string",
|
|
2555
|
+
description: "Page number (0-indexed).",
|
|
2556
|
+
default: "0"
|
|
2557
|
+
},
|
|
2558
|
+
size: {
|
|
2559
|
+
type: "string",
|
|
2560
|
+
description: "Page size.",
|
|
2561
|
+
default: "20"
|
|
2562
|
+
},
|
|
2563
|
+
search: {
|
|
2564
|
+
type: "string",
|
|
2565
|
+
description: "Event-name filter. Empty matches everything."
|
|
2566
|
+
},
|
|
2567
|
+
refresh: {
|
|
2568
|
+
type: "boolean",
|
|
2569
|
+
description: "Bypass the server cache and rebuild the catalog list.",
|
|
2570
|
+
default: false
|
|
2571
|
+
},
|
|
2572
|
+
json: {
|
|
2573
|
+
type: "boolean",
|
|
2574
|
+
description: "Emit machine-readable JSON.",
|
|
2575
|
+
default: false
|
|
2576
|
+
}
|
|
2291
2577
|
},
|
|
2292
|
-
|
|
2293
|
-
|
|
2294
|
-
|
|
2295
|
-
|
|
2578
|
+
async run({ args }) {
|
|
2579
|
+
const appId = parseAppId(args.id);
|
|
2580
|
+
if (appId === null) {
|
|
2581
|
+
if (args.json) emitJson({
|
|
2582
|
+
ok: false,
|
|
2583
|
+
reason: "invalid-id",
|
|
2584
|
+
message: `app id must be a positive integer (got ${JSON.stringify(args.id)})`
|
|
2585
|
+
});
|
|
2586
|
+
else process.stderr.write(`app events ls: invalid id ${JSON.stringify(args.id)}\n`);
|
|
2587
|
+
return exitAfterFlush(ExitCode.Usage);
|
|
2588
|
+
}
|
|
2589
|
+
const pageResult = parseNonNegativeInt(String(args.page), "page");
|
|
2590
|
+
if ("error" in pageResult) {
|
|
2591
|
+
if (args.json) emitJson({
|
|
2592
|
+
ok: false,
|
|
2593
|
+
reason: "invalid-page",
|
|
2594
|
+
message: pageResult.error
|
|
2595
|
+
});
|
|
2596
|
+
else process.stderr.write(`${pageResult.error}\n`);
|
|
2597
|
+
return exitAfterFlush(ExitCode.Usage);
|
|
2598
|
+
}
|
|
2599
|
+
const sizeResult = parseNonNegativeInt(String(args.size), "size");
|
|
2600
|
+
if ("error" in sizeResult) {
|
|
2601
|
+
if (args.json) emitJson({
|
|
2602
|
+
ok: false,
|
|
2603
|
+
reason: "invalid-size",
|
|
2604
|
+
message: sizeResult.error
|
|
2605
|
+
});
|
|
2606
|
+
else process.stderr.write(`${sizeResult.error}\n`);
|
|
2607
|
+
return exitAfterFlush(ExitCode.Usage);
|
|
2608
|
+
}
|
|
2609
|
+
const ctx = await resolveWorkspaceContext(args);
|
|
2610
|
+
if (!ctx) return;
|
|
2611
|
+
const { session, workspaceId } = ctx;
|
|
2612
|
+
try {
|
|
2613
|
+
const result = await fetchAppEventCatalogs({
|
|
2614
|
+
workspaceId,
|
|
2615
|
+
miniAppId: appId,
|
|
2616
|
+
pageNumber: pageResult.value,
|
|
2617
|
+
pageSize: sizeResult.value,
|
|
2618
|
+
...args.search !== void 0 ? { search: String(args.search) } : {},
|
|
2619
|
+
...args.refresh ? { refresh: true } : {}
|
|
2620
|
+
}, session.cookies);
|
|
2621
|
+
if (args.json) {
|
|
2622
|
+
emitJson({
|
|
2623
|
+
ok: true,
|
|
2624
|
+
workspaceId,
|
|
2625
|
+
appId,
|
|
2626
|
+
events: result.results,
|
|
2627
|
+
cacheTime: result.cacheTime ?? null,
|
|
2628
|
+
paging: result.paging
|
|
2629
|
+
});
|
|
2630
|
+
return exitAfterFlush(ExitCode.Ok);
|
|
2631
|
+
}
|
|
2632
|
+
if (result.results.length === 0) {
|
|
2633
|
+
const ct = result.cacheTime ? ` (cached ${result.cacheTime})` : "";
|
|
2634
|
+
process.stdout.write(`App ${appId} (ws ${workspaceId}): no event catalogs${ct}\n`);
|
|
2635
|
+
return exitAfterFlush(ExitCode.Ok);
|
|
2636
|
+
}
|
|
2637
|
+
process.stdout.write(`App ${appId} (ws ${workspaceId}): ${result.results.length} event(s) on page ${result.paging.pageNumber} of ${result.paging.totalPages}\n`);
|
|
2638
|
+
for (const e of result.results) {
|
|
2639
|
+
const name = typeof e.name === "string" ? e.name : typeof e.eventName === "string" ? e.eventName : "-";
|
|
2640
|
+
const count = typeof e.count === "number" ? String(e.count) : typeof e.totalCount === "number" ? String(e.totalCount) : "-";
|
|
2641
|
+
process.stdout.write(`${name}\t${count}\n`);
|
|
2642
|
+
}
|
|
2643
|
+
return exitAfterFlush(ExitCode.Ok);
|
|
2644
|
+
} catch (err) {
|
|
2645
|
+
return emitFailureFromError(args.json, err);
|
|
2646
|
+
}
|
|
2296
2647
|
}
|
|
2648
|
+
}) }
|
|
2649
|
+
}),
|
|
2650
|
+
templates: defineCommand({
|
|
2651
|
+
meta: {
|
|
2652
|
+
name: "templates",
|
|
2653
|
+
description: "Inspect smart-message composer templates available for a mini-app."
|
|
2297
2654
|
},
|
|
2298
|
-
|
|
2299
|
-
|
|
2300
|
-
|
|
2301
|
-
|
|
2302
|
-
|
|
2303
|
-
|
|
2304
|
-
|
|
2305
|
-
|
|
2306
|
-
|
|
2307
|
-
|
|
2308
|
-
|
|
2309
|
-
|
|
2310
|
-
|
|
2311
|
-
|
|
2312
|
-
|
|
2313
|
-
|
|
2314
|
-
|
|
2315
|
-
|
|
2316
|
-
|
|
2317
|
-
|
|
2318
|
-
|
|
2319
|
-
|
|
2320
|
-
|
|
2321
|
-
|
|
2322
|
-
|
|
2323
|
-
|
|
2324
|
-
|
|
2325
|
-
|
|
2326
|
-
|
|
2327
|
-
|
|
2328
|
-
|
|
2329
|
-
|
|
2330
|
-
|
|
2331
|
-
|
|
2332
|
-
|
|
2333
|
-
|
|
2334
|
-
|
|
2655
|
+
subCommands: { ls: defineCommand({
|
|
2656
|
+
meta: {
|
|
2657
|
+
name: "ls",
|
|
2658
|
+
description: "List the smart-message composer templates available for a mini-app (the 템플릿 picker in 스마트 발송)."
|
|
2659
|
+
},
|
|
2660
|
+
args: {
|
|
2661
|
+
id: {
|
|
2662
|
+
type: "positional",
|
|
2663
|
+
description: "Mini-app ID.",
|
|
2664
|
+
required: true
|
|
2665
|
+
},
|
|
2666
|
+
workspace: {
|
|
2667
|
+
type: "string",
|
|
2668
|
+
description: "Workspace ID. Defaults to the selected workspace."
|
|
2669
|
+
},
|
|
2670
|
+
page: {
|
|
2671
|
+
type: "string",
|
|
2672
|
+
description: "Page number (0-indexed).",
|
|
2673
|
+
default: "0"
|
|
2674
|
+
},
|
|
2675
|
+
size: {
|
|
2676
|
+
type: "string",
|
|
2677
|
+
description: "Page size.",
|
|
2678
|
+
default: "20"
|
|
2679
|
+
},
|
|
2680
|
+
"content-reach-type": {
|
|
2681
|
+
type: "string",
|
|
2682
|
+
description: `Template reach bucket: ${TEMPLATE_CONTENT_REACH_TYPES.join(" | ")}. Omit for all.`
|
|
2683
|
+
},
|
|
2684
|
+
"smart-message": {
|
|
2685
|
+
type: "string",
|
|
2686
|
+
description: "Filter to templates compatible with smart-message (\"true\") or legacy push (\"false\"). Omit for all."
|
|
2687
|
+
},
|
|
2688
|
+
json: {
|
|
2689
|
+
type: "boolean",
|
|
2690
|
+
description: "Emit machine-readable JSON.",
|
|
2691
|
+
default: false
|
|
2692
|
+
}
|
|
2693
|
+
},
|
|
2694
|
+
async run({ args }) {
|
|
2695
|
+
const appId = parseAppId(args.id);
|
|
2696
|
+
if (appId === null) {
|
|
2697
|
+
if (args.json) emitJson({
|
|
2698
|
+
ok: false,
|
|
2699
|
+
reason: "invalid-id",
|
|
2700
|
+
message: `app id must be a positive integer (got ${JSON.stringify(args.id)})`
|
|
2701
|
+
});
|
|
2702
|
+
else process.stderr.write(`app templates ls: invalid id ${JSON.stringify(args.id)}\n`);
|
|
2703
|
+
return exitAfterFlush(ExitCode.Usage);
|
|
2704
|
+
}
|
|
2705
|
+
const pageResult = parseNonNegativeInt(String(args.page), "page");
|
|
2706
|
+
if ("error" in pageResult) {
|
|
2707
|
+
if (args.json) emitJson({
|
|
2708
|
+
ok: false,
|
|
2709
|
+
reason: "invalid-page",
|
|
2710
|
+
message: pageResult.error
|
|
2711
|
+
});
|
|
2712
|
+
else process.stderr.write(`${pageResult.error}\n`);
|
|
2713
|
+
return exitAfterFlush(ExitCode.Usage);
|
|
2714
|
+
}
|
|
2715
|
+
const sizeResult = parseNonNegativeInt(String(args.size), "size");
|
|
2716
|
+
if ("error" in sizeResult) {
|
|
2717
|
+
if (args.json) emitJson({
|
|
2718
|
+
ok: false,
|
|
2719
|
+
reason: "invalid-size",
|
|
2720
|
+
message: sizeResult.error
|
|
2721
|
+
});
|
|
2722
|
+
else process.stderr.write(`${sizeResult.error}\n`);
|
|
2723
|
+
return exitAfterFlush(ExitCode.Usage);
|
|
2724
|
+
}
|
|
2725
|
+
let contentReachType;
|
|
2726
|
+
if (args["content-reach-type"] !== void 0) {
|
|
2727
|
+
const upper = String(args["content-reach-type"]).toUpperCase();
|
|
2728
|
+
if (TEMPLATE_CONTENT_REACH_TYPES.includes(upper)) contentReachType = upper;
|
|
2729
|
+
else {
|
|
2730
|
+
const message = `--content-reach-type must be one of: ${TEMPLATE_CONTENT_REACH_TYPES.join(", ")}`;
|
|
2731
|
+
if (args.json) emitJson({
|
|
2732
|
+
ok: false,
|
|
2733
|
+
reason: "invalid-content-reach-type",
|
|
2734
|
+
allowed: [...TEMPLATE_CONTENT_REACH_TYPES]
|
|
2735
|
+
});
|
|
2736
|
+
else process.stderr.write(`${message}\n`);
|
|
2737
|
+
return exitAfterFlush(ExitCode.Usage);
|
|
2738
|
+
}
|
|
2739
|
+
}
|
|
2740
|
+
let isSmartMessage;
|
|
2741
|
+
if (args["smart-message"] !== void 0) {
|
|
2742
|
+
const raw = String(args["smart-message"]).toLowerCase();
|
|
2743
|
+
if (raw === "true") isSmartMessage = true;
|
|
2744
|
+
else if (raw === "false") isSmartMessage = false;
|
|
2745
|
+
else {
|
|
2746
|
+
const message = "--smart-message must be \"true\" or \"false\"";
|
|
2747
|
+
if (args.json) emitJson({
|
|
2748
|
+
ok: false,
|
|
2749
|
+
reason: "invalid-smart-message",
|
|
2750
|
+
message
|
|
2751
|
+
});
|
|
2752
|
+
else process.stderr.write(`${message}\n`);
|
|
2753
|
+
return exitAfterFlush(ExitCode.Usage);
|
|
2754
|
+
}
|
|
2755
|
+
}
|
|
2756
|
+
const ctx = await resolveWorkspaceContext(args);
|
|
2757
|
+
if (!ctx) return;
|
|
2758
|
+
const { session, workspaceId } = ctx;
|
|
2759
|
+
try {
|
|
2760
|
+
const result = await fetchAppTemplates({
|
|
2761
|
+
workspaceId,
|
|
2762
|
+
miniAppId: appId,
|
|
2763
|
+
page: pageResult.value,
|
|
2764
|
+
size: sizeResult.value,
|
|
2765
|
+
...contentReachType !== void 0 ? { contentReachType } : {},
|
|
2766
|
+
...isSmartMessage !== void 0 ? { isSmartMessage } : {}
|
|
2767
|
+
}, session.cookies);
|
|
2768
|
+
if (args.json) {
|
|
2769
|
+
emitJson({
|
|
2770
|
+
ok: true,
|
|
2771
|
+
workspaceId,
|
|
2772
|
+
appId,
|
|
2773
|
+
templates: result.templates,
|
|
2774
|
+
totalPageCount: result.totalPageCount
|
|
2775
|
+
});
|
|
2776
|
+
return exitAfterFlush(ExitCode.Ok);
|
|
2777
|
+
}
|
|
2778
|
+
if (result.templates.length === 0) {
|
|
2779
|
+
process.stdout.write(`App ${appId} (ws ${workspaceId}): no templates\n`);
|
|
2780
|
+
return exitAfterFlush(ExitCode.Ok);
|
|
2781
|
+
}
|
|
2782
|
+
process.stdout.write(`App ${appId} (ws ${workspaceId}): ${result.templates.length} template(s) of ${result.totalPageCount} page(s)\n`);
|
|
2783
|
+
for (const t of result.templates) {
|
|
2784
|
+
const id = typeof t.id === "string" || typeof t.id === "number" ? t.id : typeof t.templateId === "string" || typeof t.templateId === "number" ? t.templateId : "-";
|
|
2785
|
+
const title = typeof t.title === "string" ? t.title : typeof t.name === "string" ? t.name : "-";
|
|
2786
|
+
const type = typeof t.templateType === "string" ? t.templateType : "-";
|
|
2787
|
+
process.stdout.write(`${id}\t${title}\t${type}\n`);
|
|
2788
|
+
}
|
|
2789
|
+
return exitAfterFlush(ExitCode.Ok);
|
|
2790
|
+
} catch (err) {
|
|
2791
|
+
return emitFailureFromError(args.json, err);
|
|
2792
|
+
}
|
|
2793
|
+
}
|
|
2794
|
+
}) }
|
|
2795
|
+
}),
|
|
2796
|
+
categories: defineCommand({
|
|
2797
|
+
meta: {
|
|
2798
|
+
name: "categories",
|
|
2799
|
+
description: "List the impression category tree used by `app register`'s `categoryIds` field."
|
|
2800
|
+
},
|
|
2801
|
+
args: {
|
|
2802
|
+
selectable: {
|
|
2803
|
+
type: "boolean",
|
|
2804
|
+
description: "Only show categories flagged `isSelectable: true` — the ones you can pick.",
|
|
2805
|
+
default: false
|
|
2806
|
+
},
|
|
2807
|
+
json: {
|
|
2808
|
+
type: "boolean",
|
|
2809
|
+
description: "Emit machine-readable JSON to stdout.",
|
|
2810
|
+
default: false
|
|
2811
|
+
}
|
|
2812
|
+
},
|
|
2813
|
+
async run({ args }) {
|
|
2814
|
+
const session = await readSession();
|
|
2815
|
+
if (!session) {
|
|
2816
|
+
emitNotAuthenticated(args.json);
|
|
2817
|
+
return exitAfterFlush(ExitCode.NotAuthenticated);
|
|
2818
|
+
}
|
|
2819
|
+
try {
|
|
2820
|
+
const tree = await fetchImpressionCategoryList(session.cookies);
|
|
2821
|
+
const filtered = args.selectable ? tree.filter((g) => g.categoryGroup.isSelectable).map((g) => ({
|
|
2822
|
+
...g,
|
|
2823
|
+
categoryList: g.categoryList.filter((c) => c.isSelectable).map((c) => ({
|
|
2824
|
+
...c,
|
|
2825
|
+
subCategoryList: c.subCategoryList.filter((s) => s.isSelectable)
|
|
2826
|
+
}))
|
|
2827
|
+
})) : tree;
|
|
2828
|
+
if (args.json) {
|
|
2829
|
+
emitJson({
|
|
2830
|
+
ok: true,
|
|
2831
|
+
categories: filtered
|
|
2832
|
+
});
|
|
2833
|
+
return exitAfterFlush(ExitCode.Ok);
|
|
2834
|
+
}
|
|
2835
|
+
for (const g of filtered) {
|
|
2836
|
+
const mark = g.categoryGroup.isSelectable ? "" : " (not selectable)";
|
|
2837
|
+
process.stdout.write(`[${g.categoryGroup.id}] ${g.categoryGroup.name}${mark}\n`);
|
|
2838
|
+
for (const c of g.categoryList) {
|
|
2839
|
+
const cmark = c.isSelectable ? "" : " (not selectable)";
|
|
2840
|
+
process.stdout.write(` ${c.id}\t${c.name}${cmark}\n`);
|
|
2841
|
+
for (const s of c.subCategoryList) {
|
|
2842
|
+
const smark = s.isSelectable ? "" : " (not selectable)";
|
|
2843
|
+
process.stdout.write(` ${s.id}\t${s.name}${smark}\n`);
|
|
2844
|
+
}
|
|
2845
|
+
}
|
|
2846
|
+
}
|
|
2847
|
+
return exitAfterFlush(ExitCode.Ok);
|
|
2848
|
+
} catch (err) {
|
|
2849
|
+
return emitFailureFromError(args.json, err);
|
|
2850
|
+
}
|
|
2851
|
+
}
|
|
2852
|
+
}),
|
|
2853
|
+
"service-status": defineCommand({
|
|
2854
|
+
meta: {
|
|
2855
|
+
name: "service-status",
|
|
2856
|
+
description: "Show the server-authoritative runtime status of a mini-app (serviceStatus, shutdown schedule)."
|
|
2857
|
+
},
|
|
2858
|
+
args: {
|
|
2859
|
+
id: {
|
|
2860
|
+
type: "positional",
|
|
2861
|
+
description: "Mini-app ID.",
|
|
2862
|
+
required: true
|
|
2863
|
+
},
|
|
2864
|
+
workspace: {
|
|
2865
|
+
type: "string",
|
|
2866
|
+
description: "Workspace ID. Defaults to the selected workspace."
|
|
2867
|
+
},
|
|
2868
|
+
json: {
|
|
2869
|
+
type: "boolean",
|
|
2870
|
+
description: "Emit machine-readable JSON.",
|
|
2871
|
+
default: false
|
|
2872
|
+
}
|
|
2873
|
+
},
|
|
2874
|
+
async run({ args }) {
|
|
2875
|
+
const appId = parseAppId(args.id);
|
|
2876
|
+
if (appId === null) {
|
|
2877
|
+
if (args.json) emitJson({
|
|
2878
|
+
ok: false,
|
|
2879
|
+
reason: "invalid-id",
|
|
2880
|
+
message: `app id must be a positive integer (got ${JSON.stringify(args.id)})`
|
|
2881
|
+
});
|
|
2882
|
+
else process.stderr.write(`app service-status: invalid id ${JSON.stringify(args.id)}\n`);
|
|
2883
|
+
return exitAfterFlush(ExitCode.Usage);
|
|
2884
|
+
}
|
|
2885
|
+
const ctx = await resolveWorkspaceContext(args);
|
|
2886
|
+
if (!ctx) return;
|
|
2887
|
+
const { session, workspaceId } = ctx;
|
|
2888
|
+
try {
|
|
2889
|
+
const st = await fetchAppServiceStatus(workspaceId, appId, session.cookies);
|
|
2890
|
+
if (args.json) {
|
|
2891
|
+
emitJson({
|
|
2892
|
+
ok: true,
|
|
2893
|
+
workspaceId,
|
|
2894
|
+
appId,
|
|
2895
|
+
...st
|
|
2896
|
+
});
|
|
2897
|
+
return exitAfterFlush(ExitCode.Ok);
|
|
2898
|
+
}
|
|
2899
|
+
process.stdout.write(`App ${appId} (ws ${workspaceId}):\n`);
|
|
2900
|
+
process.stdout.write(` serviceStatus: ${st.serviceStatus}\n`);
|
|
2901
|
+
process.stdout.write(` shutdownCandidateStatus: ${st.shutdownCandidateStatus ?? "null"}\n`);
|
|
2902
|
+
process.stdout.write(` scheduledShutdownAt: ${st.scheduledShutdownAt ?? "null"}\n`);
|
|
2903
|
+
return exitAfterFlush(ExitCode.Ok);
|
|
2904
|
+
} catch (err) {
|
|
2905
|
+
return emitFailureFromError(args.json, err);
|
|
2906
|
+
}
|
|
2907
|
+
}
|
|
2908
|
+
}),
|
|
2909
|
+
register: defineCommand({
|
|
2910
|
+
meta: {
|
|
2911
|
+
name: "register",
|
|
2912
|
+
description: "Register a mini-app in the selected workspace from a YAML/JSON manifest. Uploads logo/thumbnail/screenshots, then submits the create payload."
|
|
2913
|
+
},
|
|
2914
|
+
args: {
|
|
2915
|
+
workspace: {
|
|
2916
|
+
type: "string",
|
|
2917
|
+
description: "Workspace ID. Defaults to the selected workspace (`aitcc workspace use`)."
|
|
2918
|
+
},
|
|
2919
|
+
config: {
|
|
2920
|
+
type: "string",
|
|
2921
|
+
description: "Path to the app manifest. Defaults to `./aitcc.app.yaml`, then `./aitcc.app.json`."
|
|
2922
|
+
},
|
|
2923
|
+
"dry-run": {
|
|
2924
|
+
type: "boolean",
|
|
2925
|
+
description: "Validate manifest + images and print the inferred submit payload; no uploads.",
|
|
2926
|
+
default: false
|
|
2927
|
+
},
|
|
2928
|
+
"accept-terms": {
|
|
2929
|
+
type: "boolean",
|
|
2930
|
+
description: "Attest to the required console legal-agreement checkboxes (see VALIDATION-RULES.md). Required for real submits.",
|
|
2931
|
+
default: false
|
|
2932
|
+
},
|
|
2933
|
+
json: {
|
|
2934
|
+
type: "boolean",
|
|
2935
|
+
description: "Emit machine-readable JSON to stdout.",
|
|
2936
|
+
default: false
|
|
2937
|
+
}
|
|
2938
|
+
},
|
|
2939
|
+
async run({ args }) {
|
|
2940
|
+
await runRegister({
|
|
2941
|
+
json: args.json,
|
|
2942
|
+
dryRun: args["dry-run"],
|
|
2943
|
+
acceptTerms: args["accept-terms"],
|
|
2944
|
+
...args.workspace !== void 0 ? { workspace: args.workspace } : {},
|
|
2945
|
+
...args.config !== void 0 ? { config: args.config } : {}
|
|
2946
|
+
});
|
|
2947
|
+
}
|
|
2948
|
+
})
|
|
2949
|
+
}
|
|
2950
|
+
});
|
|
2951
|
+
//#endregion
|
|
2952
|
+
//#region src/api/api-keys.ts
|
|
2953
|
+
const BASE$3 = "https://apps-in-toss.toss.im/console/api-public/v3/appsintossconsole";
|
|
2954
|
+
async function fetchApiKeys(workspaceId, cookies, opts = {}) {
|
|
2955
|
+
const raw = await requestConsoleApi({
|
|
2956
|
+
url: `${BASE$3}/workspaces/${workspaceId}/api-keys`,
|
|
2957
|
+
cookies,
|
|
2958
|
+
...opts.fetchImpl ? { fetchImpl: opts.fetchImpl } : {}
|
|
2959
|
+
});
|
|
2960
|
+
if (!Array.isArray(raw)) throw new Error(`Unexpected api-keys shape for workspace=${workspaceId}: not an array`);
|
|
2961
|
+
return raw.map((entry, index) => normalizeKey(entry, workspaceId, index));
|
|
2962
|
+
}
|
|
2963
|
+
function normalizeKey(raw, workspaceId, index) {
|
|
2964
|
+
if (raw === null || typeof raw !== "object") throw new Error(`Unexpected api-key entry at index ${index} for workspace=${workspaceId}: not an object`);
|
|
2965
|
+
const rec = raw;
|
|
2966
|
+
const rawId = rec.id ?? rec.apiKeyId ?? rec.keyId;
|
|
2967
|
+
if (typeof rawId !== "string" && typeof rawId !== "number") throw new Error(`Unexpected api-key entry at index ${index} for workspace=${workspaceId}: missing id`);
|
|
2968
|
+
const rawName = rec.name ?? rec.apiKeyName ?? rec.keyName ?? rec.description;
|
|
2969
|
+
const name = typeof rawName === "string" ? rawName : void 0;
|
|
2970
|
+
const { id: _id, apiKeyId: _aid, keyId: _kid, name: _n, apiKeyName: _an, keyName: _kn, description: _d, ...extra } = rec;
|
|
2971
|
+
return {
|
|
2972
|
+
id: rawId,
|
|
2973
|
+
name,
|
|
2974
|
+
extra
|
|
2975
|
+
};
|
|
2335
2976
|
}
|
|
2336
2977
|
const keysCommand = defineCommand({
|
|
2337
2978
|
meta: {
|
|
@@ -2392,7 +3033,8 @@ const keysCommand = defineCommand({
|
|
|
2392
3033
|
});
|
|
2393
3034
|
//#endregion
|
|
2394
3035
|
//#region src/api/me.ts
|
|
2395
|
-
const
|
|
3036
|
+
const BASE$2 = "https://apps-in-toss.toss.im/console/api-public/v3/appsintossconsole";
|
|
3037
|
+
const MEMBER_USER_INFO_URL = `${BASE$2}/members/me/user-info`;
|
|
2396
3038
|
async function fetchConsoleMemberUserInfo(cookies, opts = {}) {
|
|
2397
3039
|
return requestConsoleApi({
|
|
2398
3040
|
url: MEMBER_USER_INFO_URL,
|
|
@@ -2400,6 +3042,28 @@ async function fetchConsoleMemberUserInfo(cookies, opts = {}) {
|
|
|
2400
3042
|
...opts.fetchImpl ? { fetchImpl: opts.fetchImpl } : {}
|
|
2401
3043
|
});
|
|
2402
3044
|
}
|
|
3045
|
+
async function fetchUserTerms(cookies, opts = {}) {
|
|
3046
|
+
const raw = await requestConsoleApi({
|
|
3047
|
+
url: `${BASE$2}/console-user-terms/me`,
|
|
3048
|
+
cookies,
|
|
3049
|
+
...opts.fetchImpl ? { fetchImpl: opts.fetchImpl } : {}
|
|
3050
|
+
});
|
|
3051
|
+
if (!Array.isArray(raw)) throw new Error("Unexpected user-terms shape: not an array");
|
|
3052
|
+
return raw.map((entry, i) => {
|
|
3053
|
+
if (!entry || typeof entry !== "object") throw new Error(`Unexpected user-terms entry at index ${i}`);
|
|
3054
|
+
const e = entry;
|
|
3055
|
+
return {
|
|
3056
|
+
required: Boolean(e.required),
|
|
3057
|
+
termsId: typeof e.termsId === "number" ? e.termsId : 0,
|
|
3058
|
+
revisionId: typeof e.revisionId === "number" ? e.revisionId : 0,
|
|
3059
|
+
title: typeof e.title === "string" ? e.title : "",
|
|
3060
|
+
contentsUrl: typeof e.contentsUrl === "string" ? e.contentsUrl : "",
|
|
3061
|
+
actionType: typeof e.actionType === "string" ? e.actionType : "",
|
|
3062
|
+
isAgreed: Boolean(e.isAgreed),
|
|
3063
|
+
isOneTimeConsent: Boolean(e.isOneTimeConsent)
|
|
3064
|
+
};
|
|
3065
|
+
});
|
|
3066
|
+
}
|
|
2403
3067
|
//#endregion
|
|
2404
3068
|
//#region src/cdp.ts
|
|
2405
3069
|
function isResponse(m) {
|
|
@@ -3054,27 +3718,75 @@ const logoutCommand = defineCommand({
|
|
|
3054
3718
|
}
|
|
3055
3719
|
});
|
|
3056
3720
|
//#endregion
|
|
3057
|
-
//#region src/
|
|
3058
|
-
|
|
3059
|
-
|
|
3060
|
-
const raw = await requestConsoleApi({
|
|
3061
|
-
url: `${BASE$1}/workspaces/${workspaceId}/members`,
|
|
3062
|
-
cookies,
|
|
3063
|
-
...opts.fetchImpl ? { fetchImpl: opts.fetchImpl } : {}
|
|
3064
|
-
});
|
|
3065
|
-
if (!Array.isArray(raw)) throw new Error(`Unexpected members shape for workspace=${workspaceId}: not an array`);
|
|
3066
|
-
return raw.map((entry, index) => normalizeMember(entry, workspaceId, index));
|
|
3721
|
+
//#region src/commands/me.ts
|
|
3722
|
+
function formatTermLine(t) {
|
|
3723
|
+
return ` ${t.isAgreed ? "[agreed]" : "[pending]"}${t.required ? " required" : ""} ${t.title}\n ${t.contentsUrl}\n`;
|
|
3067
3724
|
}
|
|
3068
|
-
|
|
3069
|
-
|
|
3070
|
-
|
|
3071
|
-
|
|
3072
|
-
|
|
3073
|
-
|
|
3074
|
-
|
|
3075
|
-
|
|
3076
|
-
|
|
3077
|
-
|
|
3725
|
+
const meCommand = defineCommand({
|
|
3726
|
+
meta: {
|
|
3727
|
+
name: "me",
|
|
3728
|
+
description: "Inspect account-level settings for the signed-in user."
|
|
3729
|
+
},
|
|
3730
|
+
subCommands: { terms: defineCommand({
|
|
3731
|
+
meta: {
|
|
3732
|
+
name: "terms",
|
|
3733
|
+
description: "Show the console-level terms of agreement for the signed-in account."
|
|
3734
|
+
},
|
|
3735
|
+
args: { json: {
|
|
3736
|
+
type: "boolean",
|
|
3737
|
+
description: "Emit machine-readable JSON to stdout.",
|
|
3738
|
+
default: false
|
|
3739
|
+
} },
|
|
3740
|
+
async run({ args }) {
|
|
3741
|
+
const session = await readSession();
|
|
3742
|
+
if (!session) {
|
|
3743
|
+
emitNotAuthenticated(args.json);
|
|
3744
|
+
return exitAfterFlush(ExitCode.NotAuthenticated);
|
|
3745
|
+
}
|
|
3746
|
+
try {
|
|
3747
|
+
const terms = await fetchUserTerms(session.cookies);
|
|
3748
|
+
if (args.json) {
|
|
3749
|
+
emitJson({
|
|
3750
|
+
ok: true,
|
|
3751
|
+
terms
|
|
3752
|
+
});
|
|
3753
|
+
return exitAfterFlush(ExitCode.Ok);
|
|
3754
|
+
}
|
|
3755
|
+
if (terms.length === 0) {
|
|
3756
|
+
process.stdout.write("No console-level terms required.\n");
|
|
3757
|
+
return exitAfterFlush(ExitCode.Ok);
|
|
3758
|
+
}
|
|
3759
|
+
process.stdout.write("Console account terms:\n");
|
|
3760
|
+
for (const t of terms) process.stdout.write(formatTermLine(t));
|
|
3761
|
+
return exitAfterFlush(ExitCode.Ok);
|
|
3762
|
+
} catch (err) {
|
|
3763
|
+
return emitFailureFromError(args.json, err);
|
|
3764
|
+
}
|
|
3765
|
+
}
|
|
3766
|
+
}) }
|
|
3767
|
+
});
|
|
3768
|
+
//#endregion
|
|
3769
|
+
//#region src/api/members.ts
|
|
3770
|
+
const BASE$1 = "https://apps-in-toss.toss.im/console/api-public/v3/appsintossconsole";
|
|
3771
|
+
async function fetchWorkspaceMembers(workspaceId, cookies, opts = {}) {
|
|
3772
|
+
const raw = await requestConsoleApi({
|
|
3773
|
+
url: `${BASE$1}/workspaces/${workspaceId}/members`,
|
|
3774
|
+
cookies,
|
|
3775
|
+
...opts.fetchImpl ? { fetchImpl: opts.fetchImpl } : {}
|
|
3776
|
+
});
|
|
3777
|
+
if (!Array.isArray(raw)) throw new Error(`Unexpected members shape for workspace=${workspaceId}: not an array`);
|
|
3778
|
+
return raw.map((entry, index) => normalizeMember(entry, workspaceId, index));
|
|
3779
|
+
}
|
|
3780
|
+
function normalizeMember(raw, workspaceId, index) {
|
|
3781
|
+
if (raw === null || typeof raw !== "object") throw new Error(`Unexpected member entry at index ${index} for workspace=${workspaceId}: not an object`);
|
|
3782
|
+
const rec = raw;
|
|
3783
|
+
const stringField = (k) => {
|
|
3784
|
+
const v = rec[k];
|
|
3785
|
+
if (typeof v !== "string") throw new Error(`Unexpected member entry at index ${index} for workspace=${workspaceId}: missing ${k}`);
|
|
3786
|
+
return v;
|
|
3787
|
+
};
|
|
3788
|
+
const numField = (k) => {
|
|
3789
|
+
const v = rec[k];
|
|
3078
3790
|
if (typeof v !== "number" || !Number.isFinite(v)) throw new Error(`Unexpected member entry at index ${index} for workspace=${workspaceId}: missing ${k}`);
|
|
3079
3791
|
return v;
|
|
3080
3792
|
};
|
|
@@ -3507,7 +4219,7 @@ function resolveVersion() {
|
|
|
3507
4219
|
if (typeof injected === "string" && injected.length > 0) return injected;
|
|
3508
4220
|
} catch {}
|
|
3509
4221
|
try {
|
|
3510
|
-
return "0.1.
|
|
4222
|
+
return "0.1.12";
|
|
3511
4223
|
} catch {}
|
|
3512
4224
|
return "0.0.0-dev";
|
|
3513
4225
|
}
|
|
@@ -3886,6 +4598,70 @@ async function fetchWorkspaceDetail(workspaceId, cookies, opts = {}) {
|
|
|
3886
4598
|
extra
|
|
3887
4599
|
};
|
|
3888
4600
|
}
|
|
4601
|
+
async function fetchWorkspacePartner(workspaceId, cookies, opts = {}) {
|
|
4602
|
+
const raw = await requestConsoleApi({
|
|
4603
|
+
url: `${WORKSPACES_BASE}/workspaces/${workspaceId}/partner`,
|
|
4604
|
+
cookies,
|
|
4605
|
+
...opts.fetchImpl ? { fetchImpl: opts.fetchImpl } : {}
|
|
4606
|
+
});
|
|
4607
|
+
const registered = raw.registered;
|
|
4608
|
+
if (typeof registered !== "boolean") throw new Error(`Unexpected workspace partner shape for id=${workspaceId}`);
|
|
4609
|
+
return {
|
|
4610
|
+
registered,
|
|
4611
|
+
approvalType: typeof raw.approvalType === "string" ? raw.approvalType : null,
|
|
4612
|
+
rejectMessage: typeof raw.rejectMessage === "string" ? raw.rejectMessage : null,
|
|
4613
|
+
partner: raw.partner && typeof raw.partner === "object" ? raw.partner : null
|
|
4614
|
+
};
|
|
4615
|
+
}
|
|
4616
|
+
const WORKSPACE_TERM_TYPES = [
|
|
4617
|
+
"TOSS_LOGIN",
|
|
4618
|
+
"BIZ_WORKSPACE",
|
|
4619
|
+
"TOSS_PROMOTION_MONEY",
|
|
4620
|
+
"IAA",
|
|
4621
|
+
"IAP"
|
|
4622
|
+
];
|
|
4623
|
+
const DEFAULT_SEGMENT_CATEGORY = "생성된 세그먼트";
|
|
4624
|
+
async function fetchWorkspaceSegments(params, cookies, opts = {}) {
|
|
4625
|
+
const page = params.page ?? 0;
|
|
4626
|
+
const qs = new URLSearchParams();
|
|
4627
|
+
qs.set("category", params.category ?? DEFAULT_SEGMENT_CATEGORY);
|
|
4628
|
+
qs.set("search", params.search ?? "");
|
|
4629
|
+
qs.set("page", String(page));
|
|
4630
|
+
const raw = await requestConsoleApi({
|
|
4631
|
+
url: `${WORKSPACES_BASE}/workspaces/${params.workspaceId}/segments/list?${qs.toString()}`,
|
|
4632
|
+
cookies,
|
|
4633
|
+
...opts.fetchImpl ? { fetchImpl: opts.fetchImpl } : {}
|
|
4634
|
+
});
|
|
4635
|
+
if (raw === null || typeof raw !== "object" || Array.isArray(raw)) throw new Error(`Unexpected segments shape for workspace=${params.workspaceId}`);
|
|
4636
|
+
const data = raw;
|
|
4637
|
+
return {
|
|
4638
|
+
contents: (Array.isArray(data.contents) ? data.contents : []).map((c) => c && typeof c === "object" ? c : {}),
|
|
4639
|
+
totalPage: typeof data.totalPage === "number" ? data.totalPage : 0,
|
|
4640
|
+
currentPage: typeof data.currentPage === "number" ? data.currentPage : page
|
|
4641
|
+
};
|
|
4642
|
+
}
|
|
4643
|
+
async function fetchWorkspaceTerms(workspaceId, type, cookies, opts = {}) {
|
|
4644
|
+
const raw = await requestConsoleApi({
|
|
4645
|
+
url: `${WORKSPACES_BASE}/workspaces/${workspaceId}/console-workspace-terms/${type}/skip-permission`,
|
|
4646
|
+
cookies,
|
|
4647
|
+
...opts.fetchImpl ? { fetchImpl: opts.fetchImpl } : {}
|
|
4648
|
+
});
|
|
4649
|
+
if (!Array.isArray(raw)) throw new Error(`Unexpected workspace terms shape for type=${type}`);
|
|
4650
|
+
return raw.map((entry, i) => {
|
|
4651
|
+
if (!entry || typeof entry !== "object") throw new Error(`Unexpected workspace terms entry at index ${i} for type=${type}`);
|
|
4652
|
+
const e = entry;
|
|
4653
|
+
return {
|
|
4654
|
+
required: Boolean(e.required),
|
|
4655
|
+
termsId: typeof e.termsId === "number" ? e.termsId : 0,
|
|
4656
|
+
revisionId: typeof e.revisionId === "number" ? e.revisionId : 0,
|
|
4657
|
+
title: typeof e.title === "string" ? e.title : "",
|
|
4658
|
+
contentsUrl: typeof e.contentsUrl === "string" ? e.contentsUrl : "",
|
|
4659
|
+
actionType: typeof e.actionType === "string" ? e.actionType : "",
|
|
4660
|
+
isAgreed: Boolean(e.isAgreed),
|
|
4661
|
+
isOneTimeConsent: Boolean(e.isOneTimeConsent)
|
|
4662
|
+
};
|
|
4663
|
+
});
|
|
4664
|
+
}
|
|
3889
4665
|
//#endregion
|
|
3890
4666
|
//#region src/commands/workspace.ts
|
|
3891
4667
|
function formatScalar(v) {
|
|
@@ -3893,68 +4669,282 @@ function formatScalar(v) {
|
|
|
3893
4669
|
if (typeof v === "string" || typeof v === "number" || typeof v === "boolean") return String(v);
|
|
3894
4670
|
return JSON.stringify(v);
|
|
3895
4671
|
}
|
|
4672
|
+
const lsCommand = defineCommand({
|
|
4673
|
+
meta: {
|
|
4674
|
+
name: "ls",
|
|
4675
|
+
description: "List workspaces the current user has access to."
|
|
4676
|
+
},
|
|
4677
|
+
args: { json: {
|
|
4678
|
+
type: "boolean",
|
|
4679
|
+
description: "Emit machine-readable JSON to stdout.",
|
|
4680
|
+
default: false
|
|
4681
|
+
} },
|
|
4682
|
+
async run({ args }) {
|
|
4683
|
+
const session = await readSession();
|
|
4684
|
+
if (!session) {
|
|
4685
|
+
emitNotAuthenticated(args.json);
|
|
4686
|
+
return exitAfterFlush(ExitCode.NotAuthenticated);
|
|
4687
|
+
}
|
|
4688
|
+
try {
|
|
4689
|
+
const info = await fetchConsoleMemberUserInfo(session.cookies);
|
|
4690
|
+
const current = session.currentWorkspaceId;
|
|
4691
|
+
if (args.json) {
|
|
4692
|
+
emitJson({
|
|
4693
|
+
ok: true,
|
|
4694
|
+
workspaces: info.workspaces.map((w) => ({
|
|
4695
|
+
workspaceId: w.workspaceId,
|
|
4696
|
+
workspaceName: w.workspaceName,
|
|
4697
|
+
role: w.role,
|
|
4698
|
+
current: w.workspaceId === current
|
|
4699
|
+
}))
|
|
4700
|
+
});
|
|
4701
|
+
return exitAfterFlush(ExitCode.Ok);
|
|
4702
|
+
}
|
|
4703
|
+
if (info.workspaces.length === 0) {
|
|
4704
|
+
process.stdout.write("No workspaces.\n");
|
|
4705
|
+
return exitAfterFlush(ExitCode.Ok);
|
|
4706
|
+
}
|
|
4707
|
+
for (const w of info.workspaces) {
|
|
4708
|
+
const marker = w.workspaceId === current ? "* " : " ";
|
|
4709
|
+
process.stdout.write(`${marker}${w.workspaceId} ${w.workspaceName} (${w.role})\n`);
|
|
4710
|
+
}
|
|
4711
|
+
if (current === void 0) process.stderr.write("No workspace selected. Run `aitcc workspace use <id>`.\n");
|
|
4712
|
+
return exitAfterFlush(ExitCode.Ok);
|
|
4713
|
+
} catch (err) {
|
|
4714
|
+
return emitFailureFromError(args.json, err);
|
|
4715
|
+
}
|
|
4716
|
+
}
|
|
4717
|
+
});
|
|
4718
|
+
const useCommand = defineCommand({
|
|
4719
|
+
meta: {
|
|
4720
|
+
name: "use",
|
|
4721
|
+
description: "Select the current workspace by ID. Subsequent commands use this."
|
|
4722
|
+
},
|
|
4723
|
+
args: {
|
|
4724
|
+
id: {
|
|
4725
|
+
type: "positional",
|
|
4726
|
+
description: "Workspace ID",
|
|
4727
|
+
required: true
|
|
4728
|
+
},
|
|
4729
|
+
json: {
|
|
4730
|
+
type: "boolean",
|
|
4731
|
+
description: "Emit machine-readable JSON to stdout.",
|
|
4732
|
+
default: false
|
|
4733
|
+
}
|
|
4734
|
+
},
|
|
4735
|
+
async run({ args }) {
|
|
4736
|
+
const raw = String(args.id);
|
|
4737
|
+
const parsed = parsePositiveInt$1(raw);
|
|
4738
|
+
if (parsed === null) {
|
|
4739
|
+
const message = `workspace id must be a positive integer (got ${raw})`;
|
|
4740
|
+
if (args.json) emitJson({
|
|
4741
|
+
ok: false,
|
|
4742
|
+
reason: "invalid-id",
|
|
4743
|
+
message
|
|
4744
|
+
});
|
|
4745
|
+
else process.stderr.write(`${message}\n`);
|
|
4746
|
+
return exitAfterFlush(ExitCode.Usage);
|
|
4747
|
+
}
|
|
4748
|
+
const session = await readSession();
|
|
4749
|
+
if (!session) {
|
|
4750
|
+
emitNotAuthenticated(args.json);
|
|
4751
|
+
return exitAfterFlush(ExitCode.NotAuthenticated);
|
|
4752
|
+
}
|
|
4753
|
+
try {
|
|
4754
|
+
const match = (await fetchConsoleMemberUserInfo(session.cookies)).workspaces.find((w) => w.workspaceId === parsed);
|
|
4755
|
+
if (!match) {
|
|
4756
|
+
if (args.json) emitJson({
|
|
4757
|
+
ok: false,
|
|
4758
|
+
reason: "not-found",
|
|
4759
|
+
workspaceId: parsed
|
|
4760
|
+
});
|
|
4761
|
+
else process.stderr.write(`Workspace ${parsed} is not accessible from this account. Run \`aitcc workspace ls\` to see available workspaces.\n`);
|
|
4762
|
+
return exitAfterFlush(ExitCode.Usage);
|
|
4763
|
+
}
|
|
4764
|
+
if (await setCurrentWorkspaceId(parsed) === null) {
|
|
4765
|
+
emitNotAuthenticated(args.json);
|
|
4766
|
+
return exitAfterFlush(ExitCode.NotAuthenticated);
|
|
4767
|
+
}
|
|
4768
|
+
if (args.json) emitJson({
|
|
4769
|
+
ok: true,
|
|
4770
|
+
workspaceId: match.workspaceId,
|
|
4771
|
+
workspaceName: match.workspaceName
|
|
4772
|
+
});
|
|
4773
|
+
else process.stdout.write(`Using workspace ${match.workspaceId} (${match.workspaceName}).\n`);
|
|
4774
|
+
return exitAfterFlush(ExitCode.Ok);
|
|
4775
|
+
} catch (err) {
|
|
4776
|
+
return emitFailureFromError(args.json, err);
|
|
4777
|
+
}
|
|
4778
|
+
}
|
|
4779
|
+
});
|
|
4780
|
+
const showCommand = defineCommand({
|
|
4781
|
+
meta: {
|
|
4782
|
+
name: "show",
|
|
4783
|
+
description: "Show details of the selected workspace (or the one passed with --workspace)."
|
|
4784
|
+
},
|
|
4785
|
+
args: {
|
|
4786
|
+
workspace: {
|
|
4787
|
+
type: "string",
|
|
4788
|
+
description: "Workspace ID to inspect. Defaults to the selected workspace."
|
|
4789
|
+
},
|
|
4790
|
+
json: {
|
|
4791
|
+
type: "boolean",
|
|
4792
|
+
description: "Emit machine-readable JSON to stdout.",
|
|
4793
|
+
default: false
|
|
4794
|
+
}
|
|
4795
|
+
},
|
|
4796
|
+
async run({ args }) {
|
|
4797
|
+
const session = await readSession();
|
|
4798
|
+
if (!session) {
|
|
4799
|
+
emitNotAuthenticated(args.json);
|
|
4800
|
+
return exitAfterFlush(ExitCode.NotAuthenticated);
|
|
4801
|
+
}
|
|
4802
|
+
let workspaceId;
|
|
4803
|
+
if (args.workspace) {
|
|
4804
|
+
const raw = String(args.workspace);
|
|
4805
|
+
const parsed = parsePositiveInt$1(raw);
|
|
4806
|
+
if (parsed === null) {
|
|
4807
|
+
const message = `--workspace must be a positive integer (got ${raw})`;
|
|
4808
|
+
if (args.json) emitJson({
|
|
4809
|
+
ok: false,
|
|
4810
|
+
reason: "invalid-id",
|
|
4811
|
+
message
|
|
4812
|
+
});
|
|
4813
|
+
else process.stderr.write(`${message}\n`);
|
|
4814
|
+
return exitAfterFlush(ExitCode.Usage);
|
|
4815
|
+
}
|
|
4816
|
+
workspaceId = parsed;
|
|
4817
|
+
} else workspaceId = session.currentWorkspaceId;
|
|
4818
|
+
if (workspaceId === void 0) {
|
|
4819
|
+
if (args.json) emitJson({
|
|
4820
|
+
ok: false,
|
|
4821
|
+
reason: "no-workspace-selected"
|
|
4822
|
+
});
|
|
4823
|
+
else process.stderr.write("No workspace selected. Pass `--workspace <id>` or run `aitcc workspace use <id>`.\n");
|
|
4824
|
+
return exitAfterFlush(ExitCode.Usage);
|
|
4825
|
+
}
|
|
4826
|
+
try {
|
|
4827
|
+
const detail = await fetchWorkspaceDetail(workspaceId, session.cookies);
|
|
4828
|
+
if (args.json) {
|
|
4829
|
+
emitJson({
|
|
4830
|
+
ok: true,
|
|
4831
|
+
workspaceId: detail.workspaceId,
|
|
4832
|
+
workspaceName: detail.workspaceName,
|
|
4833
|
+
extra: detail.extra ?? {}
|
|
4834
|
+
});
|
|
4835
|
+
return exitAfterFlush(ExitCode.Ok);
|
|
4836
|
+
}
|
|
4837
|
+
process.stdout.write(`Workspace ${detail.workspaceId}: ${detail.workspaceName}\n`);
|
|
4838
|
+
if (detail.extra) for (const [k, v] of Object.entries(detail.extra)) process.stdout.write(` ${k}: ${formatScalar(v)}\n`);
|
|
4839
|
+
return exitAfterFlush(ExitCode.Ok);
|
|
4840
|
+
} catch (err) {
|
|
4841
|
+
return emitFailureFromError(args.json, err);
|
|
4842
|
+
}
|
|
4843
|
+
}
|
|
4844
|
+
});
|
|
4845
|
+
async function resolveWorkspaceArg(args, selected) {
|
|
4846
|
+
if (args.workspace) {
|
|
4847
|
+
const raw = String(args.workspace);
|
|
4848
|
+
const parsed = parsePositiveInt$1(raw);
|
|
4849
|
+
if (parsed === null) {
|
|
4850
|
+
const message = `--workspace must be a positive integer (got ${raw})`;
|
|
4851
|
+
if (args.json) emitJson({
|
|
4852
|
+
ok: false,
|
|
4853
|
+
reason: "invalid-id",
|
|
4854
|
+
message
|
|
4855
|
+
});
|
|
4856
|
+
else process.stderr.write(`${message}\n`);
|
|
4857
|
+
return null;
|
|
4858
|
+
}
|
|
4859
|
+
return parsed;
|
|
4860
|
+
}
|
|
4861
|
+
if (selected === void 0) {
|
|
4862
|
+
if (args.json) emitJson({
|
|
4863
|
+
ok: false,
|
|
4864
|
+
reason: "no-workspace-selected"
|
|
4865
|
+
});
|
|
4866
|
+
else process.stderr.write("No workspace selected. Pass `--workspace <id>` or run `aitcc workspace use <id>`.\n");
|
|
4867
|
+
return null;
|
|
4868
|
+
}
|
|
4869
|
+
return selected;
|
|
4870
|
+
}
|
|
4871
|
+
const partnerCommand = defineCommand({
|
|
4872
|
+
meta: {
|
|
4873
|
+
name: "partner",
|
|
4874
|
+
description: "Show the partner (billing/payout) registration state for the selected workspace."
|
|
4875
|
+
},
|
|
4876
|
+
args: {
|
|
4877
|
+
workspace: {
|
|
4878
|
+
type: "string",
|
|
4879
|
+
description: "Workspace ID to inspect. Defaults to the selected workspace."
|
|
4880
|
+
},
|
|
4881
|
+
json: {
|
|
4882
|
+
type: "boolean",
|
|
4883
|
+
description: "Emit machine-readable JSON to stdout.",
|
|
4884
|
+
default: false
|
|
4885
|
+
}
|
|
4886
|
+
},
|
|
4887
|
+
async run({ args }) {
|
|
4888
|
+
const session = await readSession();
|
|
4889
|
+
if (!session) {
|
|
4890
|
+
emitNotAuthenticated(args.json);
|
|
4891
|
+
return exitAfterFlush(ExitCode.NotAuthenticated);
|
|
4892
|
+
}
|
|
4893
|
+
const workspaceId = await resolveWorkspaceArg(args, session.currentWorkspaceId);
|
|
4894
|
+
if (workspaceId === null) return exitAfterFlush(ExitCode.Usage);
|
|
4895
|
+
try {
|
|
4896
|
+
const state = await fetchWorkspacePartner(workspaceId, session.cookies);
|
|
4897
|
+
if (args.json) {
|
|
4898
|
+
emitJson({
|
|
4899
|
+
ok: true,
|
|
4900
|
+
workspaceId,
|
|
4901
|
+
registered: state.registered,
|
|
4902
|
+
approvalType: state.approvalType,
|
|
4903
|
+
rejectMessage: state.rejectMessage,
|
|
4904
|
+
partner: state.partner
|
|
4905
|
+
});
|
|
4906
|
+
return exitAfterFlush(ExitCode.Ok);
|
|
4907
|
+
}
|
|
4908
|
+
process.stdout.write(`Workspace ${workspaceId} partner:\n`);
|
|
4909
|
+
process.stdout.write(` registered: ${state.registered}\n`);
|
|
4910
|
+
process.stdout.write(` approvalType: ${state.approvalType ?? "null"}\n`);
|
|
4911
|
+
if (state.rejectMessage) process.stdout.write(` rejectMessage: ${state.rejectMessage}\n`);
|
|
4912
|
+
if (state.partner) {
|
|
4913
|
+
process.stdout.write(" partner:\n");
|
|
4914
|
+
for (const [k, v] of Object.entries(state.partner)) process.stdout.write(` ${k}: ${formatScalar(v)}\n`);
|
|
4915
|
+
}
|
|
4916
|
+
return exitAfterFlush(ExitCode.Ok);
|
|
4917
|
+
} catch (err) {
|
|
4918
|
+
return emitFailureFromError(args.json, err);
|
|
4919
|
+
}
|
|
4920
|
+
}
|
|
4921
|
+
});
|
|
4922
|
+
function formatTermLines(term) {
|
|
4923
|
+
return ` ${term.isAgreed ? "[agreed]" : "[pending]"}${term.required ? " required" : ""} ${term.title}\n ${term.contentsUrl}\n`;
|
|
4924
|
+
}
|
|
3896
4925
|
const workspaceCommand = defineCommand({
|
|
3897
4926
|
meta: {
|
|
3898
4927
|
name: "workspace",
|
|
3899
4928
|
description: "Inspect and switch between the workspaces this account can access."
|
|
3900
4929
|
},
|
|
3901
4930
|
subCommands: {
|
|
3902
|
-
ls:
|
|
4931
|
+
ls: lsCommand,
|
|
4932
|
+
use: useCommand,
|
|
4933
|
+
show: showCommand,
|
|
4934
|
+
partner: partnerCommand,
|
|
4935
|
+
terms: defineCommand({
|
|
3903
4936
|
meta: {
|
|
3904
|
-
name: "
|
|
3905
|
-
description: "
|
|
3906
|
-
},
|
|
3907
|
-
args: { json: {
|
|
3908
|
-
type: "boolean",
|
|
3909
|
-
description: "Emit machine-readable JSON to stdout.",
|
|
3910
|
-
default: false
|
|
3911
|
-
} },
|
|
3912
|
-
async run({ args }) {
|
|
3913
|
-
const session = await readSession();
|
|
3914
|
-
if (!session) {
|
|
3915
|
-
emitNotAuthenticated(args.json);
|
|
3916
|
-
return exitAfterFlush(ExitCode.NotAuthenticated);
|
|
3917
|
-
}
|
|
3918
|
-
try {
|
|
3919
|
-
const info = await fetchConsoleMemberUserInfo(session.cookies);
|
|
3920
|
-
const current = session.currentWorkspaceId;
|
|
3921
|
-
if (args.json) {
|
|
3922
|
-
emitJson({
|
|
3923
|
-
ok: true,
|
|
3924
|
-
workspaces: info.workspaces.map((w) => ({
|
|
3925
|
-
workspaceId: w.workspaceId,
|
|
3926
|
-
workspaceName: w.workspaceName,
|
|
3927
|
-
role: w.role,
|
|
3928
|
-
current: w.workspaceId === current
|
|
3929
|
-
}))
|
|
3930
|
-
});
|
|
3931
|
-
return exitAfterFlush(ExitCode.Ok);
|
|
3932
|
-
}
|
|
3933
|
-
if (info.workspaces.length === 0) {
|
|
3934
|
-
process.stdout.write("No workspaces.\n");
|
|
3935
|
-
return exitAfterFlush(ExitCode.Ok);
|
|
3936
|
-
}
|
|
3937
|
-
for (const w of info.workspaces) {
|
|
3938
|
-
const marker = w.workspaceId === current ? "* " : " ";
|
|
3939
|
-
process.stdout.write(`${marker}${w.workspaceId} ${w.workspaceName} (${w.role})\n`);
|
|
3940
|
-
}
|
|
3941
|
-
if (current === void 0) process.stderr.write("No workspace selected. Run `aitcc workspace use <id>`.\n");
|
|
3942
|
-
return exitAfterFlush(ExitCode.Ok);
|
|
3943
|
-
} catch (err) {
|
|
3944
|
-
return emitFailureFromError(args.json, err);
|
|
3945
|
-
}
|
|
3946
|
-
}
|
|
3947
|
-
}),
|
|
3948
|
-
use: defineCommand({
|
|
3949
|
-
meta: {
|
|
3950
|
-
name: "use",
|
|
3951
|
-
description: "Select the current workspace by ID. Subsequent commands use this."
|
|
4937
|
+
name: "terms",
|
|
4938
|
+
description: "Show the console terms-of-agreement state that gate workspace-level features (Toss login, IAP, IAA, biz workspace, promotion money)."
|
|
3952
4939
|
},
|
|
3953
4940
|
args: {
|
|
3954
|
-
|
|
3955
|
-
type: "
|
|
3956
|
-
description: "
|
|
3957
|
-
|
|
4941
|
+
type: {
|
|
4942
|
+
type: "string",
|
|
4943
|
+
description: `Term bucket to inspect: ${WORKSPACE_TERM_TYPES.join(" | ")}. Omit to query every bucket.`
|
|
4944
|
+
},
|
|
4945
|
+
workspace: {
|
|
4946
|
+
type: "string",
|
|
4947
|
+
description: "Workspace ID to inspect. Defaults to the selected workspace."
|
|
3958
4948
|
},
|
|
3959
4949
|
json: {
|
|
3960
4950
|
type: "boolean",
|
|
@@ -3963,114 +4953,158 @@ const workspaceCommand = defineCommand({
|
|
|
3963
4953
|
}
|
|
3964
4954
|
},
|
|
3965
4955
|
async run({ args }) {
|
|
3966
|
-
const
|
|
3967
|
-
|
|
3968
|
-
|
|
3969
|
-
|
|
4956
|
+
const session = await readSession();
|
|
4957
|
+
if (!session) {
|
|
4958
|
+
emitNotAuthenticated(args.json);
|
|
4959
|
+
return exitAfterFlush(ExitCode.NotAuthenticated);
|
|
4960
|
+
}
|
|
4961
|
+
const workspaceId = await resolveWorkspaceArg(args, session.currentWorkspaceId);
|
|
4962
|
+
if (workspaceId === null) return exitAfterFlush(ExitCode.Usage);
|
|
4963
|
+
const typesToQuery = (() => {
|
|
4964
|
+
if (!args.type) return WORKSPACE_TERM_TYPES;
|
|
4965
|
+
const raw = String(args.type).toUpperCase();
|
|
4966
|
+
if (WORKSPACE_TERM_TYPES.includes(raw)) return [raw];
|
|
4967
|
+
return [];
|
|
4968
|
+
})();
|
|
4969
|
+
if (typesToQuery.length === 0) {
|
|
4970
|
+
const message = `--type must be one of: ${WORKSPACE_TERM_TYPES.join(", ")}`;
|
|
3970
4971
|
if (args.json) emitJson({
|
|
3971
4972
|
ok: false,
|
|
3972
|
-
reason: "invalid-
|
|
3973
|
-
|
|
4973
|
+
reason: "invalid-type",
|
|
4974
|
+
allowed: [...WORKSPACE_TERM_TYPES]
|
|
3974
4975
|
});
|
|
3975
4976
|
else process.stderr.write(`${message}\n`);
|
|
3976
4977
|
return exitAfterFlush(ExitCode.Usage);
|
|
3977
4978
|
}
|
|
3978
|
-
const session = await readSession();
|
|
3979
|
-
if (!session) {
|
|
3980
|
-
emitNotAuthenticated(args.json);
|
|
3981
|
-
return exitAfterFlush(ExitCode.NotAuthenticated);
|
|
3982
|
-
}
|
|
3983
4979
|
try {
|
|
3984
|
-
const
|
|
3985
|
-
if (
|
|
3986
|
-
|
|
3987
|
-
|
|
3988
|
-
|
|
3989
|
-
|
|
4980
|
+
const results = await Promise.all(typesToQuery.map(async (t) => [t, await fetchWorkspaceTerms(workspaceId, t, session.cookies)]));
|
|
4981
|
+
if (typesToQuery.length === 1) {
|
|
4982
|
+
const [type, terms] = results[0];
|
|
4983
|
+
if (args.json) {
|
|
4984
|
+
emitJson({
|
|
4985
|
+
ok: true,
|
|
4986
|
+
workspaceId,
|
|
4987
|
+
type,
|
|
4988
|
+
terms
|
|
4989
|
+
});
|
|
4990
|
+
return exitAfterFlush(ExitCode.Ok);
|
|
4991
|
+
}
|
|
4992
|
+
process.stdout.write(`Workspace ${workspaceId} terms (${type}):\n`);
|
|
4993
|
+
if (terms.length === 0) process.stdout.write(" (no terms required)\n");
|
|
4994
|
+
else for (const t of terms) process.stdout.write(formatTermLines(t));
|
|
4995
|
+
return exitAfterFlush(ExitCode.Ok);
|
|
4996
|
+
}
|
|
4997
|
+
const byType = {};
|
|
4998
|
+
for (const [t, terms] of results) byType[t] = terms;
|
|
4999
|
+
if (args.json) {
|
|
5000
|
+
emitJson({
|
|
5001
|
+
ok: true,
|
|
5002
|
+
workspaceId,
|
|
5003
|
+
byType
|
|
3990
5004
|
});
|
|
3991
|
-
|
|
3992
|
-
return exitAfterFlush(ExitCode.Usage);
|
|
5005
|
+
return exitAfterFlush(ExitCode.Ok);
|
|
3993
5006
|
}
|
|
3994
|
-
|
|
3995
|
-
|
|
3996
|
-
|
|
5007
|
+
for (const [type, terms] of results) {
|
|
5008
|
+
process.stdout.write(`\n[${type}]\n`);
|
|
5009
|
+
if (terms.length === 0) process.stdout.write(" (no terms required)\n");
|
|
5010
|
+
else for (const t of terms) process.stdout.write(formatTermLines(t));
|
|
3997
5011
|
}
|
|
3998
|
-
if (args.json) emitJson({
|
|
3999
|
-
ok: true,
|
|
4000
|
-
workspaceId: match.workspaceId,
|
|
4001
|
-
workspaceName: match.workspaceName
|
|
4002
|
-
});
|
|
4003
|
-
else process.stdout.write(`Using workspace ${match.workspaceId} (${match.workspaceName}).\n`);
|
|
4004
5012
|
return exitAfterFlush(ExitCode.Ok);
|
|
4005
5013
|
} catch (err) {
|
|
4006
5014
|
return emitFailureFromError(args.json, err);
|
|
4007
5015
|
}
|
|
4008
5016
|
}
|
|
4009
5017
|
}),
|
|
4010
|
-
|
|
5018
|
+
segments: defineCommand({
|
|
4011
5019
|
meta: {
|
|
4012
|
-
name: "
|
|
4013
|
-
description: "
|
|
5020
|
+
name: "segments",
|
|
5021
|
+
description: "Inspect user segments defined in a workspace."
|
|
4014
5022
|
},
|
|
4015
|
-
|
|
4016
|
-
|
|
4017
|
-
|
|
4018
|
-
description: "
|
|
5023
|
+
subCommands: { ls: defineCommand({
|
|
5024
|
+
meta: {
|
|
5025
|
+
name: "ls",
|
|
5026
|
+
description: "List user segments in the selected workspace (the 세그먼트 menu)."
|
|
4019
5027
|
},
|
|
4020
|
-
|
|
4021
|
-
|
|
4022
|
-
|
|
4023
|
-
|
|
4024
|
-
|
|
4025
|
-
|
|
4026
|
-
|
|
4027
|
-
|
|
4028
|
-
|
|
4029
|
-
|
|
4030
|
-
|
|
4031
|
-
|
|
4032
|
-
|
|
4033
|
-
|
|
4034
|
-
|
|
4035
|
-
|
|
4036
|
-
|
|
4037
|
-
|
|
5028
|
+
args: {
|
|
5029
|
+
workspace: {
|
|
5030
|
+
type: "string",
|
|
5031
|
+
description: "Workspace ID. Defaults to the selected workspace."
|
|
5032
|
+
},
|
|
5033
|
+
category: {
|
|
5034
|
+
type: "string",
|
|
5035
|
+
description: "Category bucket (tab). Defaults to \"생성된 세그먼트\" — the UI's initial tab."
|
|
5036
|
+
},
|
|
5037
|
+
search: {
|
|
5038
|
+
type: "string",
|
|
5039
|
+
description: "Name-contains filter. Empty matches everything."
|
|
5040
|
+
},
|
|
5041
|
+
page: {
|
|
5042
|
+
type: "string",
|
|
5043
|
+
description: "Page number (0-indexed).",
|
|
5044
|
+
default: "0"
|
|
5045
|
+
},
|
|
5046
|
+
json: {
|
|
5047
|
+
type: "boolean",
|
|
5048
|
+
description: "Emit machine-readable JSON to stdout.",
|
|
5049
|
+
default: false
|
|
5050
|
+
}
|
|
5051
|
+
},
|
|
5052
|
+
async run({ args }) {
|
|
5053
|
+
const session = await readSession();
|
|
5054
|
+
if (!session) {
|
|
5055
|
+
emitNotAuthenticated(args.json);
|
|
5056
|
+
return exitAfterFlush(ExitCode.NotAuthenticated);
|
|
5057
|
+
}
|
|
5058
|
+
const workspaceId = await resolveWorkspaceArg(args, session.currentWorkspaceId);
|
|
5059
|
+
if (workspaceId === null) return exitAfterFlush(ExitCode.Usage);
|
|
5060
|
+
const pageRaw = String(args.page);
|
|
5061
|
+
const pageNum = Number(pageRaw);
|
|
5062
|
+
if (!Number.isFinite(pageNum) || !Number.isInteger(pageNum) || pageNum < 0) {
|
|
5063
|
+
const message = `--page must be a non-negative integer (got ${JSON.stringify(pageRaw)})`;
|
|
4038
5064
|
if (args.json) emitJson({
|
|
4039
5065
|
ok: false,
|
|
4040
|
-
reason: "invalid-
|
|
5066
|
+
reason: "invalid-page",
|
|
4041
5067
|
message
|
|
4042
5068
|
});
|
|
4043
5069
|
else process.stderr.write(`${message}\n`);
|
|
4044
5070
|
return exitAfterFlush(ExitCode.Usage);
|
|
4045
5071
|
}
|
|
4046
|
-
|
|
4047
|
-
|
|
4048
|
-
|
|
4049
|
-
|
|
4050
|
-
|
|
4051
|
-
|
|
4052
|
-
|
|
4053
|
-
|
|
4054
|
-
|
|
4055
|
-
|
|
4056
|
-
|
|
4057
|
-
|
|
4058
|
-
|
|
4059
|
-
|
|
4060
|
-
|
|
4061
|
-
|
|
4062
|
-
|
|
4063
|
-
|
|
4064
|
-
}
|
|
5072
|
+
try {
|
|
5073
|
+
const page = await fetchWorkspaceSegments({
|
|
5074
|
+
workspaceId,
|
|
5075
|
+
...args.category !== void 0 ? { category: String(args.category) } : {},
|
|
5076
|
+
...args.search !== void 0 ? { search: String(args.search) } : {},
|
|
5077
|
+
page: pageNum
|
|
5078
|
+
}, session.cookies);
|
|
5079
|
+
const category = args.category !== void 0 ? String(args.category) : "생성된 세그먼트";
|
|
5080
|
+
if (args.json) {
|
|
5081
|
+
emitJson({
|
|
5082
|
+
ok: true,
|
|
5083
|
+
workspaceId,
|
|
5084
|
+
category,
|
|
5085
|
+
segments: page.contents,
|
|
5086
|
+
totalPage: page.totalPage,
|
|
5087
|
+
currentPage: page.currentPage
|
|
5088
|
+
});
|
|
5089
|
+
return exitAfterFlush(ExitCode.Ok);
|
|
5090
|
+
}
|
|
5091
|
+
if (page.contents.length === 0) {
|
|
5092
|
+
process.stdout.write(`Workspace ${workspaceId} (${category}): no segments on page ${page.currentPage}\n`);
|
|
5093
|
+
return exitAfterFlush(ExitCode.Ok);
|
|
5094
|
+
}
|
|
5095
|
+
process.stdout.write(`Workspace ${workspaceId} (${category}): ${page.contents.length} segment(s), page ${page.currentPage} of ${page.totalPage}\n`);
|
|
5096
|
+
for (const s of page.contents) {
|
|
5097
|
+
const id = typeof s.id === "string" || typeof s.id === "number" ? s.id : typeof s.segmentId === "string" || typeof s.segmentId === "number" ? s.segmentId : "-";
|
|
5098
|
+
const name = typeof s.name === "string" ? s.name : typeof s.title === "string" ? s.title : "-";
|
|
5099
|
+
const userCount = typeof s.userCount === "number" ? String(s.userCount) : typeof s.count === "number" ? String(s.count) : "-";
|
|
5100
|
+
process.stdout.write(`${id}\t${name}\t${userCount}\n`);
|
|
5101
|
+
}
|
|
4065
5102
|
return exitAfterFlush(ExitCode.Ok);
|
|
5103
|
+
} catch (err) {
|
|
5104
|
+
return emitFailureFromError(args.json, err);
|
|
4066
5105
|
}
|
|
4067
|
-
process.stdout.write(`Workspace ${detail.workspaceId}: ${detail.workspaceName}\n`);
|
|
4068
|
-
if (detail.extra) for (const [k, v] of Object.entries(detail.extra)) process.stdout.write(` ${k}: ${formatScalar(v)}\n`);
|
|
4069
|
-
return exitAfterFlush(ExitCode.Ok);
|
|
4070
|
-
} catch (err) {
|
|
4071
|
-
return emitFailureFromError(args.json, err);
|
|
4072
5106
|
}
|
|
4073
|
-
}
|
|
5107
|
+
}) }
|
|
4074
5108
|
})
|
|
4075
5109
|
}
|
|
4076
5110
|
});
|
|
@@ -4091,7 +5125,8 @@ runMain(defineCommand({
|
|
|
4091
5125
|
app: appCommand,
|
|
4092
5126
|
members: membersCommand,
|
|
4093
5127
|
keys: keysCommand,
|
|
4094
|
-
notices: noticesCommand
|
|
5128
|
+
notices: noticesCommand,
|
|
5129
|
+
me: meCommand
|
|
4095
5130
|
}
|
|
4096
5131
|
}));
|
|
4097
5132
|
//#endregion
|