@ait-co/console-cli 0.1.26 → 0.1.28

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 CHANGED
@@ -2448,7 +2448,7 @@ function optionalPathArray(input, key, configDir) {
2448
2448
  });
2449
2449
  }
2450
2450
  const EMAIL_REGEX = /^(([^<>()[\]\\.,;:\s@"]+(\.[^<>()[\]\\.,;:\s@"]+)*)|(".+"))@((\[[0-9]{1,3}\.[0-9]{1,3}\.[0-9]{1,3}\.[0-9]{1,3}])|(([a-zA-Z\-0-9]+\.)+[a-zA-Z]{2,}))$/;
2451
- function isValidEmail(v) {
2451
+ function isValidEmail$1(v) {
2452
2452
  return EMAIL_REGEX.test(v.toLowerCase());
2453
2453
  }
2454
2454
  const TITLE_KO_REGEX = /^[가-힣A-Za-z0-9 :·?]+$/;
@@ -2491,6 +2491,11 @@ function isValidHttpUrl(v) {
2491
2491
  }
2492
2492
  }
2493
2493
  function validateManifest(raw, configDir) {
2494
+ let miniAppId;
2495
+ if (raw.miniAppId !== void 0 && raw.miniAppId !== null) {
2496
+ if (typeof raw.miniAppId !== "number" || !Number.isInteger(raw.miniAppId) || raw.miniAppId <= 0) throw new ManifestError("invalid-config", `miniAppId must be a positive integer (got ${JSON.stringify(raw.miniAppId)})`, "miniAppId");
2497
+ miniAppId = raw.miniAppId;
2498
+ }
2494
2499
  const titleKo = requireString(raw, "titleKo");
2495
2500
  if (!TITLE_KO_REGEX.test(titleKo)) throw new ManifestError("invalid-config", `titleKo may only contain Korean/English letters, digits, spaces, and ":·?" (got "${titleKo}"; server-side rule, errorCode: miniApp.InvalidTitle)`, "titleKo");
2496
2501
  const titleKoLen = codePointsExcludingSpaces(titleKo);
@@ -2505,7 +2510,7 @@ function validateManifest(raw, configDir) {
2505
2510
  }
2506
2511
  const appName = requireString(raw, "appName");
2507
2512
  const csEmail = requireString(raw, "csEmail");
2508
- if (!isValidEmail(csEmail)) throw new ManifestError("invalid-config", `csEmail is not a valid email address (got ${csEmail})`, "csEmail");
2513
+ if (!isValidEmail$1(csEmail)) throw new ManifestError("invalid-config", `csEmail is not a valid email address (got ${csEmail})`, "csEmail");
2509
2514
  const subtitle = requireString(raw, "subtitle");
2510
2515
  if (subtitle.length > MANIFEST_LIMITS.subtitleMaxChars) throw new ManifestError("invalid-config", `subtitle must be ${MANIFEST_LIMITS.subtitleMaxChars} characters or fewer (got ${subtitle.length})`, "subtitle");
2511
2516
  const description = requireString(raw, "description");
@@ -2513,21 +2518,29 @@ function validateManifest(raw, configDir) {
2513
2518
  if (descriptionCodepoints > DETAIL_DESCRIPTION_MAX_CODEPOINTS) throw new ManifestError("invalid-config", `description must be ${DETAIL_DESCRIPTION_MAX_CODEPOINTS} characters or fewer (got ${descriptionCodepoints})`, "description");
2514
2519
  const homePageUri = optionalString(raw, "homePageUri");
2515
2520
  if (homePageUri !== void 0 && !isValidHttpUrl(homePageUri)) throw new ManifestError("invalid-config", `homePageUri must be a http(s) URL (got ${homePageUri})`, "homePageUri");
2521
+ const logo = requirePath(raw, "logo", configDir);
2522
+ const logoDarkMode = optionalPath(raw, "logoDarkMode", configDir);
2523
+ const horizontalThumbnail = requirePath(raw, "horizontalThumbnail", configDir);
2524
+ const categoryIds = requireNumberArray(raw, "categoryIds", { min: 1 });
2525
+ const keywords = optionalStringArray(raw, "keywords", { max: 10 });
2526
+ const verticalScreenshots = requirePathArray(raw, "verticalScreenshots", configDir, { min: 3 });
2527
+ const horizontalScreenshots = optionalPathArray(raw, "horizontalScreenshots", configDir);
2516
2528
  return {
2529
+ miniAppId,
2517
2530
  titleKo,
2518
2531
  titleEn,
2519
2532
  appName,
2520
2533
  homePageUri,
2521
2534
  csEmail,
2522
- logo: requirePath(raw, "logo", configDir),
2523
- logoDarkMode: optionalPath(raw, "logoDarkMode", configDir),
2524
- horizontalThumbnail: requirePath(raw, "horizontalThumbnail", configDir),
2525
- categoryIds: requireNumberArray(raw, "categoryIds", { min: 1 }),
2535
+ logo,
2536
+ logoDarkMode,
2537
+ horizontalThumbnail,
2538
+ categoryIds,
2526
2539
  subtitle,
2527
2540
  description,
2528
- keywords: optionalStringArray(raw, "keywords", { max: 10 }),
2529
- verticalScreenshots: requirePathArray(raw, "verticalScreenshots", configDir, { min: 3 }),
2530
- horizontalScreenshots: optionalPathArray(raw, "horizontalScreenshots", configDir)
2541
+ keywords,
2542
+ verticalScreenshots,
2543
+ horizontalScreenshots
2531
2544
  };
2532
2545
  }
2533
2546
  //#endregion
@@ -2779,7 +2792,7 @@ function validateAppName(raw) {
2779
2792
  return true;
2780
2793
  }
2781
2794
  function validateEmail(raw) {
2782
- if (!isValidEmail(raw)) return "not a valid email address";
2795
+ if (!isValidEmail$1(raw)) return "not a valid email address";
2783
2796
  return true;
2784
2797
  }
2785
2798
  function validateSubtitle(raw) {
@@ -2904,6 +2917,7 @@ function buildSubmitPayload(manifest, urls) {
2904
2917
  description: manifest.subtitle,
2905
2918
  detailDescription: manifest.description,
2906
2919
  images,
2920
+ ...manifest.miniAppId !== void 0 ? { miniAppId: manifest.miniAppId } : {},
2907
2921
  ...urls.logoDarkMode !== void 0 ? { darkModeIconUri: urls.logoDarkMode } : {},
2908
2922
  ...manifest.homePageUri !== void 0 ? { homePageUri: manifest.homePageUri } : {}
2909
2923
  },
@@ -2925,6 +2939,7 @@ async function runRegister(args, deps = {}) {
2925
2939
  printContextHeader(ctx, { json: args.json });
2926
2940
  const manifest = await loadAndValidateManifest(args, deps);
2927
2941
  if (!manifest) return;
2942
+ if (manifest.miniAppId !== void 0 && !args.json) process.stderr.write(`[mode: update · miniAppId ${manifest.miniAppId}] existing app draft will be overwritten and re-enter the review queue.\n`);
2928
2943
  if (!args.dryRun && !args.acceptTerms) {
2929
2944
  emitTermsNotAccepted(args.json);
2930
2945
  await exitAfterFlush(ExitCode.Usage);
@@ -8680,6 +8695,46 @@ async function fetchWorkspaceMembers(workspaceId, cookies, opts = {}) {
8680
8695
  if (!Array.isArray(raw)) throw new Error(`Unexpected members shape for workspace=${workspaceId}: not an array`);
8681
8696
  return raw.map((entry, index) => normalizeMember(entry, workspaceId, index));
8682
8697
  }
8698
+ /**
8699
+ * Invite a user by email to the workspace.
8700
+ *
8701
+ * Maps to `POST /workspaces/:wid/invites/send/by-email`. Payload shape is
8702
+ * inferred from static bundle analysis (PR #118); `role` is optional —
8703
+ * omit to use the server default.
8704
+ *
8705
+ * ⚠️ Inferred endpoint: method/path confirmed, payload/response/errorCodes
8706
+ * not live-captured. See docs/api/members.md "Invite 관련 endpoint".
8707
+ */
8708
+ async function inviteMember(workspaceId, email, role, cookies, opts = {}) {
8709
+ const url = `${BASE$1}/workspaces/${workspaceId}/invites/send/by-email`;
8710
+ const body = { email };
8711
+ if (role !== void 0) body.role = role;
8712
+ return { raw: await requestConsoleApi({
8713
+ method: "POST",
8714
+ url,
8715
+ cookies,
8716
+ body,
8717
+ ...opts.fetchImpl ? { fetchImpl: opts.fetchImpl } : {}
8718
+ }) };
8719
+ }
8720
+ /**
8721
+ * Remove a member from the workspace by their `bizUserNo`.
8722
+ *
8723
+ * Maps to `DELETE /workspaces/:wid/members/:memberBizUserNo`. The path
8724
+ * param name `memberBizUserNo` is confirmed from bundle analysis (PR #118).
8725
+ * Response body shape is uncaptured; we treat any SUCCESS as success.
8726
+ *
8727
+ * ⚠️ Inferred endpoint: method/path confirmed, response/errorCodes not
8728
+ * live-captured. See docs/api/members.md "DELETE …/members/<memberBizUserNo>".
8729
+ */
8730
+ async function removeMember(workspaceId, memberBizUserNo, cookies, opts = {}) {
8731
+ await requestConsoleApi({
8732
+ method: "DELETE",
8733
+ url: `${BASE$1}/workspaces/${workspaceId}/members/${memberBizUserNo}`,
8734
+ cookies,
8735
+ ...opts.fetchImpl ? { fetchImpl: opts.fetchImpl } : {}
8736
+ });
8737
+ }
8683
8738
  function normalizeMember(raw, workspaceId, index) {
8684
8739
  if (raw === null || typeof raw !== "object") throw new Error(`Unexpected member entry at index ${index} for workspace=${workspaceId}: not an object`);
8685
8740
  const rec = raw;
@@ -8704,60 +8759,185 @@ function normalizeMember(raw, workspaceId, index) {
8704
8759
  isAdult: Boolean(rec.isAdult)
8705
8760
  };
8706
8761
  }
8762
+ //#endregion
8763
+ //#region src/commands/members.ts
8764
+ const lsCommand$2 = defineCommand({
8765
+ meta: {
8766
+ name: "ls",
8767
+ description: "List members of the selected workspace."
8768
+ },
8769
+ args: {
8770
+ workspace: {
8771
+ type: "string",
8772
+ description: "Workspace ID. Defaults to the selected workspace (`aitcc workspace use`)."
8773
+ },
8774
+ json: {
8775
+ type: "boolean",
8776
+ description: "Emit machine-readable JSON to stdout.",
8777
+ default: false
8778
+ }
8779
+ },
8780
+ async run({ args }) {
8781
+ const ctx = await resolveWorkspaceContext(args);
8782
+ if (!ctx) return;
8783
+ const { session, workspaceId } = ctx;
8784
+ printContextHeader(ctx, { json: args.json });
8785
+ try {
8786
+ const members = await fetchWorkspaceMembers(workspaceId, session.cookies);
8787
+ if (args.json) {
8788
+ emitJson({
8789
+ ok: true,
8790
+ workspaceId,
8791
+ members: members.map((m) => ({
8792
+ bizUserNo: m.bizUserNo,
8793
+ name: m.name,
8794
+ email: m.email,
8795
+ status: m.status,
8796
+ role: m.role,
8797
+ isOwnerDelegationRequested: m.isOwnerDelegationRequested
8798
+ }))
8799
+ });
8800
+ return exitAfterFlush(ExitCode.Ok);
8801
+ }
8802
+ if (members.length === 0) {
8803
+ process.stdout.write(`No members in workspace ${workspaceId}.\n`);
8804
+ return exitAfterFlush(ExitCode.Ok);
8805
+ }
8806
+ for (const m of members) process.stdout.write(`${m.bizUserNo}\t${m.name}\t${m.email}\t${m.role}\t${m.status}\n`);
8807
+ return exitAfterFlush(ExitCode.Ok);
8808
+ } catch (err) {
8809
+ return emitFailureFromError(args.json, err);
8810
+ }
8811
+ }
8812
+ });
8813
+ function isValidEmail(email) {
8814
+ const at = email.indexOf("@");
8815
+ if (at <= 0) return false;
8816
+ const domain = email.slice(at + 1);
8817
+ return domain.length > 0 && domain.includes(".");
8818
+ }
8707
8819
  const membersCommand = defineCommand({
8708
8820
  meta: {
8709
8821
  name: "members",
8710
- description: "Inspect workspace members."
8822
+ description: "Inspect and manage workspace members."
8711
8823
  },
8712
- subCommands: { ls: defineCommand({
8713
- meta: {
8714
- name: "ls",
8715
- description: "List members of the selected workspace."
8716
- },
8717
- args: {
8718
- workspace: {
8719
- type: "string",
8720
- description: "Workspace ID. Defaults to the selected workspace (`aitcc workspace use`)."
8824
+ subCommands: {
8825
+ ls: lsCommand$2,
8826
+ invite: defineCommand({
8827
+ meta: {
8828
+ name: "invite",
8829
+ description: "Invite a user to the workspace by email."
8721
8830
  },
8722
- json: {
8723
- type: "boolean",
8724
- description: "Emit machine-readable JSON to stdout.",
8725
- default: false
8726
- }
8727
- },
8728
- async run({ args }) {
8729
- const ctx = await resolveWorkspaceContext(args);
8730
- if (!ctx) return;
8731
- const { session, workspaceId } = ctx;
8732
- printContextHeader(ctx, { json: args.json });
8733
- try {
8734
- const members = await fetchWorkspaceMembers(workspaceId, session.cookies);
8735
- if (args.json) {
8736
- emitJson({
8737
- ok: true,
8738
- workspaceId,
8739
- members: members.map((m) => ({
8740
- bizUserNo: m.bizUserNo,
8741
- name: m.name,
8742
- email: m.email,
8743
- status: m.status,
8744
- role: m.role,
8745
- isOwnerDelegationRequested: m.isOwnerDelegationRequested
8746
- }))
8831
+ args: {
8832
+ email: {
8833
+ type: "positional",
8834
+ required: true,
8835
+ description: "Email address of the user to invite."
8836
+ },
8837
+ role: {
8838
+ type: "string",
8839
+ description: "Role to assign (default: server default). Example: MEMBER."
8840
+ },
8841
+ workspace: {
8842
+ type: "string",
8843
+ description: "Workspace ID. Defaults to the selected workspace (`aitcc workspace use`)."
8844
+ },
8845
+ json: {
8846
+ type: "boolean",
8847
+ description: "Emit machine-readable JSON to stdout.",
8848
+ default: false
8849
+ }
8850
+ },
8851
+ async run({ args }) {
8852
+ const ctx = await resolveWorkspaceContext(args);
8853
+ if (!ctx) return;
8854
+ const { session, workspaceId } = ctx;
8855
+ printContextHeader(ctx, { json: args.json });
8856
+ const email = String(args.email).trim();
8857
+ if (!isValidEmail(email)) {
8858
+ const message = `<email> must be a valid email address (got ${JSON.stringify(email)})`;
8859
+ if (args.json) emitJson({
8860
+ ok: false,
8861
+ reason: "invalid-email",
8862
+ message
8747
8863
  });
8864
+ else process.stderr.write(`${message}\n`);
8865
+ return exitAfterFlush(ExitCode.Usage);
8866
+ }
8867
+ const role = args.role ? String(args.role).trim() : void 0;
8868
+ try {
8869
+ await inviteMember(workspaceId, email, role, session.cookies);
8870
+ if (args.json) {
8871
+ emitJson({
8872
+ ok: true,
8873
+ workspaceId,
8874
+ email
8875
+ });
8876
+ return exitAfterFlush(ExitCode.Ok);
8877
+ }
8878
+ process.stdout.write(`Invited ${email} to workspace ${workspaceId}.\n`);
8748
8879
  return exitAfterFlush(ExitCode.Ok);
8880
+ } catch (err) {
8881
+ return emitFailureFromError(args.json, err);
8749
8882
  }
8750
- if (members.length === 0) {
8751
- process.stdout.write(`No members in workspace ${workspaceId}.\n`);
8883
+ }
8884
+ }),
8885
+ remove: defineCommand({
8886
+ meta: {
8887
+ name: "remove",
8888
+ description: "Remove a member from the workspace by their bizUserNo."
8889
+ },
8890
+ args: {
8891
+ bizUserNo: {
8892
+ type: "positional",
8893
+ required: true,
8894
+ description: "bizUserNo of the member to remove (from `aitcc members ls`)."
8895
+ },
8896
+ workspace: {
8897
+ type: "string",
8898
+ description: "Workspace ID. Defaults to the selected workspace (`aitcc workspace use`)."
8899
+ },
8900
+ json: {
8901
+ type: "boolean",
8902
+ description: "Emit machine-readable JSON to stdout.",
8903
+ default: false
8904
+ }
8905
+ },
8906
+ async run({ args }) {
8907
+ const ctx = await resolveWorkspaceContext(args);
8908
+ if (!ctx) return;
8909
+ const { session, workspaceId } = ctx;
8910
+ printContextHeader(ctx, { json: args.json });
8911
+ const rawId = String(args.bizUserNo);
8912
+ const parsed = parsePositiveInt$1(rawId);
8913
+ if (parsed === null) {
8914
+ const message = `<bizUserNo> must be a positive integer (got ${JSON.stringify(rawId)})`;
8915
+ if (args.json) emitJson({
8916
+ ok: false,
8917
+ reason: "invalid-id",
8918
+ message
8919
+ });
8920
+ else process.stderr.write(`${message}\n`);
8921
+ return exitAfterFlush(ExitCode.Usage);
8922
+ }
8923
+ try {
8924
+ await removeMember(workspaceId, parsed, session.cookies);
8925
+ if (args.json) {
8926
+ emitJson({
8927
+ ok: true,
8928
+ workspaceId,
8929
+ bizUserNo: parsed
8930
+ });
8931
+ return exitAfterFlush(ExitCode.Ok);
8932
+ }
8933
+ process.stdout.write(`Removed member ${parsed} from workspace ${workspaceId}.\n`);
8752
8934
  return exitAfterFlush(ExitCode.Ok);
8935
+ } catch (err) {
8936
+ return emitFailureFromError(args.json, err);
8753
8937
  }
8754
- for (const m of members) process.stdout.write(`${m.bizUserNo}\t${m.name}\t${m.email}\t${m.role}\t${m.status}\n`);
8755
- return exitAfterFlush(ExitCode.Ok);
8756
- } catch (err) {
8757
- return emitFailureFromError(args.json, err);
8758
8938
  }
8759
- }
8760
- }) }
8939
+ })
8940
+ }
8761
8941
  });
8762
8942
  const BASE = "https://api-public.toss.im/api-public/v3/ipd-thor/api/v1";
8763
8943
  async function fetchNotices(params, cookies, opts = {}) {
@@ -9151,7 +9331,7 @@ function resolveVersion() {
9151
9331
  if (typeof injected === "string" && injected.length > 0) return injected;
9152
9332
  } catch {}
9153
9333
  try {
9154
- return "0.1.26";
9334
+ return "0.1.28";
9155
9335
  } catch {}
9156
9336
  return "0.0.0-dev";
9157
9337
  }