@putdotio/cli 1.0.10 → 1.0.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/README.md CHANGED
@@ -100,10 +100,10 @@ Link your account:
100
100
  putio auth login
101
101
  ```
102
102
 
103
- Check the account:
103
+ Check the auth source:
104
104
 
105
105
  ```bash
106
- putio whoami --output json
106
+ putio whoami --fields auth --output json
107
107
  ```
108
108
 
109
109
  Read a small JSON result:
package/dist/bin.mjs CHANGED
@@ -1,5 +1,5 @@
1
1
  #!/usr/bin/env node
2
- import { A as translate, C as CliOutput, D as CliConfigLive, E as renderJson, O as CliRuntime, S as CliSdkLive, T as detectOutputModeFromArgv, a as searchCommand, c as brandCommand, i as filesCommand, j as version, k as CliRuntimeLive, l as versionCommand, m as CliStateLive, n as whoamiCommand, o as eventsCommand, r as transfersCommand, s as downloadLinksCommand, t as describeCli, u as makeAuthCommand, w as CliOutputLive } from "./metadata-CP3-u5nn.mjs";
2
+ import { A as translate, C as CliOutput, D as CliConfigLive, E as renderJson, O as CliRuntime, S as CliSdkLive, T as detectOutputModeFromArgv, a as searchCommand, c as brandCommand, i as filesCommand, j as version, k as CliRuntimeLive, l as versionCommand, m as CliStateLive, n as whoamiCommand, o as eventsCommand, r as transfersCommand, s as downloadLinksCommand, t as describeCli, u as makeAuthCommand, w as CliOutputLive } from "./metadata-Bf6lftdl.mjs";
3
3
  import { Cause, Console, Effect, Layer } from "effect";
4
4
  import { Command } from "@effect/cli";
5
5
  import { NodeContext, NodeRuntime } from "@effect/platform-node";
package/dist/index.mjs CHANGED
@@ -1,2 +1,2 @@
1
- import { _ as clearPersistedState, b as resolveAuthState, d as AuthStateError, f as AuthStatusSchema, g as ResolvedAuthStateSchema, h as PutioCliConfigSchema, m as CliStateLive, p as CliState, t as describeCli, v as getAuthStatus, x as savePersistedState, y as loadPersistedState } from "./metadata-CP3-u5nn.mjs";
1
+ import { _ as clearPersistedState, b as resolveAuthState, d as AuthStateError, f as AuthStatusSchema, g as ResolvedAuthStateSchema, h as PutioCliConfigSchema, m as CliStateLive, p as CliState, t as describeCli, v as getAuthStatus, x as savePersistedState, y as loadPersistedState } from "./metadata-Bf6lftdl.mjs";
2
2
  export { AuthStateError, AuthStatusSchema, CliState, CliStateLive, PutioCliConfigSchema, ResolvedAuthStateSchema, clearPersistedState, describeCli, getAuthStatus, loadPersistedState, resolveAuthState, savePersistedState };
@@ -13,7 +13,7 @@ import * as FileSystem from "@effect/platform/FileSystem";
13
13
  import { SystemError } from "@effect/platform/Error";
14
14
  //#region package.json
15
15
  var name = "@putdotio/cli";
16
- var version = "1.0.10";
16
+ var version = "1.0.12";
17
17
  //#endregion
18
18
  //#region src/i18n/translate.ts
19
19
  const resources = { en: { translation: {
@@ -1290,15 +1290,28 @@ const SAFE_SENSITIVE_SENTINEL_VALUES = new Set([
1290
1290
  REDACTED_VALUE
1291
1291
  ]);
1292
1292
  const PROMPT_INJECTION_PATTERN = /\b(ignore (?:all|any|previous|above)|system prompt|developer message|tool call|function call|follow these instructions|you are chatgpt|you are an ai)\b/iu;
1293
- const isPlainObject = (value) => typeof value === "object" && value !== null && !Array.isArray(value);
1294
- const sanitizeTerminalText = (value) => value.replace(/(Authorization\s*:\s*Bearer\s+)([A-Za-z0-9._~+/=-]+)/gi, (_match, prefix) => `${prefix}${REDACTED_VALUE}`).replace(/((?:auth_?token|access_?token|refresh_?token|oauth_?token|token|password|secret|cookie)["']?\s*[:=]\s*["']?)([^"'&,\s}]+)/gi, (_match, prefix) => `${prefix}${REDACTED_VALUE}`).replace(/(Bearer\s+)([A-Za-z0-9._~+/=-]+)/gi, (_match, prefix) => `${prefix}${REDACTED_VALUE}`).replace(/([?&](?:auth_?token|access_?token|refresh_?token|oauth_?token|token)=)([^&\s]+)/gi, (_match, prefix) => `${prefix}${REDACTED_VALUE}`);
1293
+ const TERMINAL_ESCAPE_PATTERN = new RegExp(String.raw`\u001B(?:\][^\u0007]*(?:\u0007|\u001B\\)|\[[0-?]*[ -/]*[@-~]|[@-Z\\-_])`, "gu");
1294
+ const TERMINAL_CONTROL_PATTERN = new RegExp(String.raw`[\u0000-\u0008\u000B-\u001F\u007F-\u009F]`, "gu");
1295
+ const isPlainObject = (value) => {
1296
+ if (typeof value !== "object" || value === null || Array.isArray(value)) return false;
1297
+ const prototype = Object.getPrototypeOf(value);
1298
+ return prototype === Object.prototype || prototype === null;
1299
+ };
1300
+ const redactSensitiveText = (value) => value.replace(/(Authorization\s*:\s*Bearer\s+)([A-Za-z0-9._~+/=-]+)/gi, (_match, prefix) => `${prefix}${REDACTED_VALUE}`).replace(/((?:auth_?token|access_?token|refresh_?token|oauth_?token|token|password|secret|cookie)["']?\s*[:=]\s*["']?)([^"'&,\s}]+)/gi, (_match, prefix) => `${prefix}${REDACTED_VALUE}`).replace(/(Bearer\s+)([A-Za-z0-9._~+/=-]+)/gi, (_match, prefix) => `${prefix}${REDACTED_VALUE}`).replace(/([?&](?:auth_?token|access_?token|refresh_?token|oauth_?token|token)=)([^&\s]+)/gi, (_match, prefix) => `${prefix}${REDACTED_VALUE}`);
1301
+ const sanitizeTerminalText = (value) => redactSensitiveText(value).replace(TERMINAL_ESCAPE_PATTERN, "").replace(TERMINAL_CONTROL_PATTERN, "");
1302
+ const sanitizeTerminalValue = (value) => {
1303
+ if (typeof value === "string") return sanitizeTerminalText(value);
1304
+ if (Array.isArray(value)) return value.map(sanitizeTerminalValue);
1305
+ if (isPlainObject(value)) return Object.fromEntries(Object.entries(value).map(([key, nestedValue]) => [key, SENSITIVE_KEY_PATTERN.test(key) && typeof nestedValue === "string" ? SAFE_SENSITIVE_SENTINEL_VALUES.has(nestedValue) ? nestedValue : REDACTED_VALUE : sanitizeTerminalValue(nestedValue)]));
1306
+ return value;
1307
+ };
1295
1308
  const joinPath = (segments) => segments.reduce((path, segment) => {
1296
1309
  if (segment.startsWith("[")) return `${path}${segment}`;
1297
1310
  return path === "$" ? `$.${segment}` : `${path}.${segment}`;
1298
1311
  }, "$");
1299
1312
  const sanitizeStructuredValueInternal = (value, path) => {
1300
1313
  if (typeof value === "string") {
1301
- const sanitized = sanitizeTerminalText(value);
1314
+ const sanitized = redactSensitiveText(value);
1302
1315
  return {
1303
1316
  untrustedTextPaths: PROMPT_INJECTION_PATTERN.test(sanitized) ? [joinPath(path)] : [],
1304
1317
  value: sanitized
@@ -1356,7 +1369,7 @@ const sanitizeStructuredValueInternal = (value, path) => {
1356
1369
  const sanitizeStructuredValue = (value) => sanitizeStructuredValueInternal(value, []).value;
1357
1370
  const renderJson = (value) => JSON.stringify(sanitizeStructuredValue(value), null, 2);
1358
1371
  const renderNdjson = (value) => JSON.stringify(sanitizeStructuredValue(value));
1359
- const renderTerminal = (value, renderTerminalValue) => sanitizeTerminalText(renderTerminalValue(value));
1372
+ const renderTerminal = (value, renderTerminalValue) => redactSensitiveText(renderTerminalValue(sanitizeTerminalValue(value)));
1360
1373
  const toCliErrorView = (error) => {
1361
1374
  const meta = error.meta;
1362
1375
  return {
@@ -1381,7 +1394,7 @@ const toCliErrorJson = (error) => {
1381
1394
  };
1382
1395
  const localizeError = (error) => isLocalizedError(error) ? error : localizeCliError(error);
1383
1396
  const formatCliError = (error) => {
1384
- return sanitizeTerminalText(renderCliErrorTerminal(toCliErrorView(localizeError(error))));
1397
+ return redactSensitiveText(renderCliErrorTerminal(sanitizeTerminalValue(toCliErrorView(localizeError(error)))));
1385
1398
  };
1386
1399
  const formatCliErrorJson = (error) => {
1387
1400
  return renderJson(toCliErrorJson(isLocalizedError(error) ? error : localizeCliError(error)));
@@ -1596,6 +1609,8 @@ var CliCommandInputError = class extends Data.TaggedError("CliCommandInputError"
1596
1609
  const PATH_TRAVERSAL_PATTERN = /(?:^|[\\/])\.\.(?:[\\/]|$)|%2e/iu;
1597
1610
  const QUERY_OR_FRAGMENT_PATTERN = /[?#]/u;
1598
1611
  const TOP_LEVEL_FIELD_PATTERN = /^[A-Za-z0-9_-]+$/u;
1612
+ const MAX_CURSOR_PAGES = 1e3;
1613
+ const MAX_CURSOR_ITEMS = 1e5;
1599
1614
  const ownKeys = (value) => Object.keys(value);
1600
1615
  const hasControlCharacters = (value) => [...value].some((character) => {
1601
1616
  const codePoint = character.codePointAt(0);
@@ -1620,10 +1635,10 @@ const validateNameLikeInput = (label, value) => validateSafeString({
1620
1635
  const parseRequestedFields = (raw) => {
1621
1636
  const parts = raw.split(",").map((part) => part.trim());
1622
1637
  if (parts.length === 0 || parts.some((part) => part.length === 0)) throw new CliCommandInputError({ message: "Expected `--fields` to be a comma-separated list of top-level field names." });
1623
- return [...new Set(parts.map((part) => validateSafeString({
1624
- label: `\`--fields\` selector \`${part}\``,
1638
+ return [...new Set(parts.map((part, index) => validateSafeString({
1639
+ label: `\`--fields\` selector #${index + 1}`,
1625
1640
  pattern: TOP_LEVEL_FIELD_PATTERN,
1626
- patternMessage: "`--fields` only accepts top-level field names without dots, brackets, or slashes.",
1641
+ patternMessage: `\`--fields\` selector #${index + 1} only accepts top-level field names without dots, brackets, or slashes.`,
1627
1642
  value: part
1628
1643
  })))];
1629
1644
  };
@@ -1637,6 +1652,17 @@ const readPageItems = (value, itemKey, command) => {
1637
1652
  if (!Array.isArray(items)) throw new CliCommandInputError({ message: `Expected \`${command}\` responses to include an array at \`${itemKey}\`.` });
1638
1653
  return items;
1639
1654
  };
1655
+ const assertCursorPageBudget = (input) => {
1656
+ if (input.pageCount > MAX_CURSOR_PAGES) throw new CliCommandInputError({ message: `\`${input.command}\` pagination exceeded ${MAX_CURSOR_PAGES} pages.` });
1657
+ if (input.itemCount > MAX_CURSOR_ITEMS) throw new CliCommandInputError({ message: `\`${input.command}\` pagination exceeded ${MAX_CURSOR_ITEMS} items.` });
1658
+ };
1659
+ const assertCursorNotSeen = (input) => {
1660
+ if (input.seenCursors.has(input.cursor)) throw new CliCommandInputError({ message: `\`${input.command}\` pagination returned a repeated cursor.` });
1661
+ input.seenCursors.add(input.cursor);
1662
+ };
1663
+ const assertCursorNotRepeated = (input) => {
1664
+ if (input.cursor !== null && input.seenCursors.has(input.cursor)) throw new CliCommandInputError({ message: `\`${input.command}\` pagination returned a repeated cursor.` });
1665
+ };
1640
1666
  const integerPattern = /^-?\d+$/;
1641
1667
  const parseRepeatedIntegers = (values) => {
1642
1668
  const parsed = [];
@@ -1701,11 +1727,36 @@ const selectTopLevelFields = (input) => Effect.try({
1701
1727
  const collectAllCursorPages = (input) => Effect.gen(function* () {
1702
1728
  if (!input.pageAll) return input.initial;
1703
1729
  const collectedItems = [...readPageItems(input.initial, input.itemKey, input.command)];
1730
+ const seenCursors = /* @__PURE__ */ new Set();
1704
1731
  let cursor = readCursor(input.initial);
1732
+ let pageCount = 1;
1733
+ assertCursorPageBudget({
1734
+ command: input.command,
1735
+ itemCount: collectedItems.length,
1736
+ pageCount
1737
+ });
1705
1738
  while (cursor !== null) {
1739
+ assertCursorNotSeen({
1740
+ command: input.command,
1741
+ cursor,
1742
+ seenCursors
1743
+ });
1706
1744
  const nextPage = yield* input.continueWithCursor(cursor);
1707
- collectedItems.push(...readPageItems(nextPage, input.itemKey, input.command));
1708
- cursor = readCursor(nextPage);
1745
+ const nextCursor = readCursor(nextPage);
1746
+ assertCursorNotRepeated({
1747
+ command: input.command,
1748
+ cursor: nextCursor,
1749
+ seenCursors
1750
+ });
1751
+ const pageItems = readPageItems(nextPage, input.itemKey, input.command);
1752
+ pageCount += 1;
1753
+ collectedItems.push(...pageItems);
1754
+ assertCursorPageBudget({
1755
+ command: input.command,
1756
+ itemCount: collectedItems.length,
1757
+ pageCount
1758
+ });
1759
+ cursor = nextCursor;
1709
1760
  }
1710
1761
  return {
1711
1762
  ...input.initial,
@@ -1740,7 +1791,18 @@ const writeReadPages = (input) => Effect.gen(function* () {
1740
1791
  });
1741
1792
  }
1742
1793
  let current = input.initial;
1794
+ const seenCursors = /* @__PURE__ */ new Set();
1795
+ let pageCount = 1;
1796
+ let streamedItemCount = 0;
1743
1797
  while (true) {
1798
+ if (input.itemKey) {
1799
+ streamedItemCount += readPageItems(current, input.itemKey, input.command).length;
1800
+ assertCursorPageBudget({
1801
+ command: input.command,
1802
+ itemCount: streamedItemCount,
1803
+ pageCount
1804
+ });
1805
+ }
1744
1806
  yield* writeOutput(yield* selectTopLevelFields({
1745
1807
  command: input.command,
1746
1808
  requestedFields: input.controls.requestedFields,
@@ -1749,7 +1811,19 @@ const writeReadPages = (input) => Effect.gen(function* () {
1749
1811
  if (!input.controls.pageAll || !input.continueWithCursor || !input.itemKey) return;
1750
1812
  const cursor = readCursor(current);
1751
1813
  if (cursor === null) return;
1752
- current = yield* input.continueWithCursor(cursor);
1814
+ assertCursorNotSeen({
1815
+ command: input.command,
1816
+ cursor,
1817
+ seenCursors
1818
+ });
1819
+ const nextPage = yield* input.continueWithCursor(cursor);
1820
+ assertCursorNotRepeated({
1821
+ command: input.command,
1822
+ cursor: readCursor(nextPage),
1823
+ seenCursors
1824
+ });
1825
+ current = nextPage;
1826
+ pageCount += 1;
1753
1827
  }
1754
1828
  });
1755
1829
  const renderDryRunPlanTerminal = (value) => [
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@putdotio/cli",
3
- "version": "1.0.10",
3
+ "version": "1.0.12",
4
4
  "description": "Agent-first CLI for the put.io API.",
5
5
  "homepage": "https://github.com/putdotio/putio-cli#readme",
6
6
  "bugs": {
@@ -30,7 +30,7 @@
30
30
  },
31
31
  "scripts": {
32
32
  "build": "vp pack",
33
- "build:sea": "node ./scripts/build-sea.mjs",
33
+ "build:sea": "node ./scripts/build-sea.mts",
34
34
  "check": "vp check .",
35
35
  "coverage": "vp test --coverage",
36
36
  "dev": "vp pack --watch",
@@ -52,20 +52,14 @@
52
52
  },
53
53
  "devDependencies": {
54
54
  "@types/node": "^24.0.0",
55
- "@vitest/coverage-v8": "^4.1.0",
55
+ "@vitest/coverage-v8": "^4.1.5",
56
56
  "esbuild": "^0.27.0",
57
57
  "postject": "^1.0.0-alpha.6",
58
58
  "typescript": "^5.9.3",
59
- "vite-plus": "0.1.14"
59
+ "vite-plus": "0.1.20"
60
60
  },
61
61
  "engines": {
62
62
  "node": ">=24.14.0 <25"
63
63
  },
64
- "packageManager": "pnpm@10.32.1",
65
- "pnpm": {
66
- "overrides": {
67
- "vite": "npm:@voidzero-dev/vite-plus-core@0.1.14",
68
- "vitest": "npm:@voidzero-dev/vite-plus-test@0.1.14"
69
- }
70
- }
64
+ "packageManager": "pnpm@11.0.0"
71
65
  }