neonctl 2.37.1 → 2.38.0

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.
Files changed (159) hide show
  1. package/README.md +15 -700
  2. package/bin/cli.js +3 -0
  3. package/package.json +8 -75
  4. package/dist/analytics.js +0 -168
  5. package/dist/api.js +0 -720
  6. package/dist/auth.js +0 -125
  7. package/dist/callback.html +0 -60
  8. package/dist/cli.js +0 -9
  9. package/dist/commands/api.js +0 -278
  10. package/dist/commands/auth.js +0 -214
  11. package/dist/commands/bootstrap.js +0 -481
  12. package/dist/commands/branches.js +0 -488
  13. package/dist/commands/bucket.js +0 -549
  14. package/dist/commands/checkout.js +0 -321
  15. package/dist/commands/config.js +0 -626
  16. package/dist/commands/connection_string.js +0 -172
  17. package/dist/commands/data_api.js +0 -284
  18. package/dist/commands/databases.js +0 -82
  19. package/dist/commands/deploy.js +0 -26
  20. package/dist/commands/dev.js +0 -698
  21. package/dist/commands/diff.js +0 -222
  22. package/dist/commands/env.js +0 -189
  23. package/dist/commands/functions.js +0 -373
  24. package/dist/commands/index.js +0 -62
  25. package/dist/commands/init.js +0 -73
  26. package/dist/commands/inspect.js +0 -65
  27. package/dist/commands/ip_allow.js +0 -137
  28. package/dist/commands/link.js +0 -1121
  29. package/dist/commands/neon_auth.js +0 -1028
  30. package/dist/commands/operations.js +0 -28
  31. package/dist/commands/orgs.js +0 -24
  32. package/dist/commands/projects.js +0 -413
  33. package/dist/commands/psql.js +0 -62
  34. package/dist/commands/roles.js +0 -65
  35. package/dist/commands/schema_diff.js +0 -151
  36. package/dist/commands/set_context.js +0 -29
  37. package/dist/commands/snapshots.js +0 -455
  38. package/dist/commands/status.js +0 -40
  39. package/dist/commands/user.js +0 -15
  40. package/dist/commands/vpc_endpoints.js +0 -134
  41. package/dist/config.js +0 -11
  42. package/dist/config_format.js +0 -72
  43. package/dist/context.js +0 -231
  44. package/dist/current_branch_fast_path.js +0 -55
  45. package/dist/dev/env.js +0 -244
  46. package/dist/dev/functions.js +0 -70
  47. package/dist/dev/inputs.js +0 -63
  48. package/dist/dev/runtime.js +0 -146
  49. package/dist/env.js +0 -36
  50. package/dist/env_file.js +0 -159
  51. package/dist/errors.js +0 -80
  52. package/dist/functions_api.js +0 -48
  53. package/dist/help.js +0 -146
  54. package/dist/index.js +0 -240
  55. package/dist/log.js +0 -18
  56. package/dist/parameters.gen.js +0 -480
  57. package/dist/pkg.js +0 -25
  58. package/dist/psql/cli.js +0 -53
  59. package/dist/psql/command/cmd_cond.js +0 -437
  60. package/dist/psql/command/cmd_connect.js +0 -820
  61. package/dist/psql/command/cmd_copy.js +0 -1035
  62. package/dist/psql/command/cmd_describe.js +0 -1815
  63. package/dist/psql/command/cmd_format.js +0 -948
  64. package/dist/psql/command/cmd_io.js +0 -2193
  65. package/dist/psql/command/cmd_lo.js +0 -393
  66. package/dist/psql/command/cmd_meta.js +0 -969
  67. package/dist/psql/command/cmd_misc.js +0 -187
  68. package/dist/psql/command/cmd_pipeline.js +0 -1148
  69. package/dist/psql/command/cmd_restrict.js +0 -171
  70. package/dist/psql/command/cmd_show.js +0 -766
  71. package/dist/psql/command/dispatch.js +0 -343
  72. package/dist/psql/command/inputQueue.js +0 -42
  73. package/dist/psql/command/shared.js +0 -71
  74. package/dist/psql/complete/filenames.js +0 -139
  75. package/dist/psql/complete/index.js +0 -104
  76. package/dist/psql/complete/matcher.js +0 -315
  77. package/dist/psql/complete/psqlVars.js +0 -249
  78. package/dist/psql/complete/queries.js +0 -493
  79. package/dist/psql/complete/rules.js +0 -2424
  80. package/dist/psql/core/common.js +0 -1253
  81. package/dist/psql/core/help.js +0 -576
  82. package/dist/psql/core/mainloop.js +0 -1360
  83. package/dist/psql/core/prompt.js +0 -439
  84. package/dist/psql/core/settings.js +0 -686
  85. package/dist/psql/core/sqlHelp.js +0 -1066
  86. package/dist/psql/core/startup.js +0 -846
  87. package/dist/psql/core/syncVars.js +0 -116
  88. package/dist/psql/core/variables.js +0 -287
  89. package/dist/psql/describe/formatters.js +0 -1330
  90. package/dist/psql/describe/processNamePattern.js +0 -270
  91. package/dist/psql/describe/queries.js +0 -2452
  92. package/dist/psql/describe/versionGate.js +0 -44
  93. package/dist/psql/index.js +0 -2030
  94. package/dist/psql/io/history.js +0 -299
  95. package/dist/psql/io/input.js +0 -120
  96. package/dist/psql/io/lineEditor/buffer.js +0 -325
  97. package/dist/psql/io/lineEditor/complete.js +0 -227
  98. package/dist/psql/io/lineEditor/filename.js +0 -159
  99. package/dist/psql/io/lineEditor/index.js +0 -893
  100. package/dist/psql/io/lineEditor/keymap.js +0 -745
  101. package/dist/psql/io/lineEditor/vt100.js +0 -363
  102. package/dist/psql/io/pgpass.js +0 -202
  103. package/dist/psql/io/pgservice.js +0 -194
  104. package/dist/psql/io/psqlrc.js +0 -422
  105. package/dist/psql/print/aligned.js +0 -1748
  106. package/dist/psql/print/asciidoc.js +0 -230
  107. package/dist/psql/print/crosstab.js +0 -463
  108. package/dist/psql/print/csv.js +0 -76
  109. package/dist/psql/print/html.js +0 -240
  110. package/dist/psql/print/json.js +0 -96
  111. package/dist/psql/print/latex.js +0 -379
  112. package/dist/psql/print/pager.js +0 -267
  113. package/dist/psql/print/troff.js +0 -240
  114. package/dist/psql/print/unaligned.js +0 -99
  115. package/dist/psql/print/units.js +0 -188
  116. package/dist/psql/scanner/slash.js +0 -515
  117. package/dist/psql/scanner/sql.js +0 -914
  118. package/dist/psql/scanner/stringutils.js +0 -394
  119. package/dist/psql/types/backslash.js +0 -1
  120. package/dist/psql/types/connection.js +0 -1
  121. package/dist/psql/types/index.js +0 -7
  122. package/dist/psql/types/printer.js +0 -1
  123. package/dist/psql/types/repl.js +0 -1
  124. package/dist/psql/types/scanner.js +0 -24
  125. package/dist/psql/types/settings.js +0 -1
  126. package/dist/psql/types/variables.js +0 -1
  127. package/dist/psql/wire/connection.js +0 -2857
  128. package/dist/psql/wire/copy.js +0 -108
  129. package/dist/psql/wire/notify.js +0 -59
  130. package/dist/psql/wire/pipeline.js +0 -521
  131. package/dist/psql/wire/protocol.js +0 -466
  132. package/dist/psql/wire/sasl.js +0 -294
  133. package/dist/psql/wire/tls.js +0 -602
  134. package/dist/storage_api.js +0 -147
  135. package/dist/test_utils/fixtures.js +0 -121
  136. package/dist/test_utils/oauth_server.js +0 -9
  137. package/dist/types.js +0 -1
  138. package/dist/utils/ai_gateway_notice.js +0 -180
  139. package/dist/utils/api_enums.js +0 -33
  140. package/dist/utils/auth.js +0 -5
  141. package/dist/utils/branch_notice.js +0 -22
  142. package/dist/utils/branch_picker.js +0 -103
  143. package/dist/utils/compute_units.js +0 -28
  144. package/dist/utils/config_diff.js +0 -185
  145. package/dist/utils/enrichers.js +0 -161
  146. package/dist/utils/esbuild.js +0 -158
  147. package/dist/utils/formats.js +0 -18
  148. package/dist/utils/git_diff.js +0 -90
  149. package/dist/utils/inspect_db.js +0 -153
  150. package/dist/utils/inspect_queries.js +0 -372
  151. package/dist/utils/middlewares.js +0 -20
  152. package/dist/utils/openapi.js +0 -114
  153. package/dist/utils/package_manager.js +0 -68
  154. package/dist/utils/point_in_time.js +0 -56
  155. package/dist/utils/psql.js +0 -120
  156. package/dist/utils/string.js +0 -5
  157. package/dist/utils/ui.js +0 -59
  158. package/dist/utils/zip.js +0 -4
  159. package/dist/writer.js +0 -97
@@ -1,68 +0,0 @@
1
- import { spawn } from "node:child_process";
2
- import which from "which";
3
- import { log } from "../log.js";
4
- // npm first so it's the default/preselected choice; the rest follow in rough
5
- // popularity order.
6
- export const PACKAGE_MANAGERS = [
7
- "npm",
8
- "pnpm",
9
- "yarn",
10
- "bun",
11
- ];
12
- /**
13
- * The package manager the CLI was invoked through, read from the
14
- * `npm_config_user_agent` npm sets for `npm exec`/`npx`, `pnpm dlx`, `yarn
15
- * dlx`, and `bunx` (so `pnpm dlx neonctl …` installs with pnpm). Returns
16
- * undefined when there's nothing to infer from — e.g. a globally-installed
17
- * `neon`/`neonctl` — so the caller can ask (or fall back) instead of silently
18
- * assuming npm.
19
- */
20
- export const detectPackageManager = () => {
21
- const ua = process.env.npm_config_user_agent ?? "";
22
- if (ua.startsWith("pnpm"))
23
- return "pnpm";
24
- if (ua.startsWith("yarn"))
25
- return "yarn";
26
- if (ua.startsWith("bun"))
27
- return "bun";
28
- if (ua.startsWith("npm"))
29
- return "npm";
30
- return undefined;
31
- };
32
- /** The package managers actually on PATH, in {@link PACKAGE_MANAGERS} order. */
33
- export const installedPackageManagers = () => PACKAGE_MANAGERS.filter((pm) => which.sync(pm, { nothrow: true }) !== null);
34
- /**
35
- * Pick a package manager without prompting: the one the CLI was invoked through,
36
- * else the first one installed, else npm. Used by non-interactive flows (e.g.
37
- * `config init`) where there's no scaffold prompt to hang a picker off.
38
- */
39
- export const resolvePackageManager = () => detectPackageManager() ?? installedPackageManagers()[0] ?? "npm";
40
- /**
41
- * The argv that adds `packages` as runtime dependencies with `pm`. npm spells it
42
- * `install`; pnpm/yarn/bun use `add`.
43
- */
44
- export const addDependenciesArgs = (pm, packages) => (pm === "npm" ? ["install", ...packages] : ["add", ...packages]);
45
- /**
46
- * Run a command inheriting our stdio so the user sees install / link output
47
- * live and can answer any prompts the child raises. Resolves to whether it
48
- * exited cleanly; a non-zero exit is reported but never throws — the caller
49
- * decides whether to treat it as fatal.
50
- */
51
- export const runCommand = (cmd, args, cwd) => new Promise((resolvePromise) => {
52
- // npm/pnpm/yarn ship as .cmd shims on Windows, which need a shell to run.
53
- const child = spawn(cmd, args, {
54
- cwd,
55
- stdio: "inherit",
56
- shell: process.platform === "win32",
57
- });
58
- child.on("error", (err) => {
59
- log.warning("Could not run `%s %s`: %s", cmd, args.join(" "), err instanceof Error ? err.message : String(err));
60
- resolvePromise(false);
61
- });
62
- child.on("close", (code) => {
63
- if (code !== 0) {
64
- log.warning("`%s %s` exited with code %d.", cmd, args.join(" "), code);
65
- }
66
- resolvePromise(code === 0);
67
- });
68
- });
@@ -1,56 +0,0 @@
1
- import { branchIdResolve } from "./enrichers.js";
2
- import { looksLikeLSN, looksLikeTimestamp } from "./formats.js";
3
- export class PointInTimeParseError extends Error {
4
- constructor(message) {
5
- super(message);
6
- this.name = "PointInTimeParseError";
7
- }
8
- }
9
- export const parsePITBranch = (input) => {
10
- const splitIndex = input.lastIndexOf("@");
11
- const sourceBranch = splitIndex === -1 ? input : input.slice(0, splitIndex);
12
- const exactPIT = splitIndex === -1 ? null : input.slice(splitIndex + 1);
13
- const result = {
14
- branch: sourceBranch,
15
- ...(exactPIT === null
16
- ? { tag: "head" }
17
- : looksLikeLSN(exactPIT)
18
- ? { tag: "lsn", lsn: exactPIT }
19
- : { tag: "timestamp", timestamp: exactPIT }),
20
- };
21
- if (result.tag === "timestamp") {
22
- const timestamp = result.timestamp;
23
- if (!looksLikeTimestamp(timestamp)) {
24
- throw new PointInTimeParseError(`Invalid source branch format - ${input}`);
25
- }
26
- if (Date.parse(timestamp) > Date.now()) {
27
- throw new PointInTimeParseError(`Timestamp can not be in future - ${input}`);
28
- }
29
- }
30
- return result;
31
- };
32
- export const parsePointInTime = async ({ pointInTime, targetBranchId, projectId, api, }) => {
33
- const parsedPIT = parsePITBranch(pointInTime);
34
- let branchId = "";
35
- if (parsedPIT.branch === "^self") {
36
- branchId = targetBranchId;
37
- }
38
- else if (parsedPIT.branch === "^parent") {
39
- const { data } = await api.getProjectBranch(projectId, targetBranchId);
40
- const { parent_id: parentId } = data.branch;
41
- if (parentId == null) {
42
- throw new PointInTimeParseError("Branch has no parent");
43
- }
44
- branchId = parentId;
45
- }
46
- else {
47
- branchId = await branchIdResolve({
48
- branch: parsedPIT.branch,
49
- projectId,
50
- apiClient: api,
51
- });
52
- }
53
- // @ts-expect-error extracting pit from parsedPIT
54
- delete parsedPIT.branch;
55
- return { ...parsedPIT, branchId };
56
- };
@@ -1,120 +0,0 @@
1
- import { spawn } from "child_process";
2
- import which from "which";
3
- import { closeAnalytics, trackEvent } from "../analytics.js";
4
- import { log } from "../log.js";
5
- const FALLBACK_ENV = "NEONCTL_PSQL_FALLBACK";
6
- /** Max time we wait for the analytics flush before handing off to psql. */
7
- const ANALYTICS_FLUSH_TIMEOUT_MS = 3000;
8
- /**
9
- * Decide which psql implementation will run, and why. The PATH probe is
10
- * skipped when TS is forced (flag or env) — we don't need it and it'd be a
11
- * wasted lookup — so `nativeAvailable` is `null` ("not checked") in those
12
- * cases rather than a misleading `false`.
13
- */
14
- const planPsql = async (opts) => {
15
- if (opts.mode === "ts") {
16
- return {
17
- implementation: "ts",
18
- reason: "forced_flag",
19
- nativeAvailable: null,
20
- nativePath: null,
21
- };
22
- }
23
- if (process.env[FALLBACK_ENV] === "1") {
24
- return {
25
- implementation: "ts",
26
- reason: "forced_env",
27
- nativeAvailable: null,
28
- nativePath: null,
29
- };
30
- }
31
- const nativePath = await which("psql", { nothrow: true });
32
- const nativeAvailable = nativePath !== null;
33
- if (opts.mode === "native") {
34
- return {
35
- implementation: "native",
36
- reason: "forced_native",
37
- nativeAvailable,
38
- nativePath,
39
- };
40
- }
41
- // 'auto' (or unset): strict fallback — prefer native, TS only if missing.
42
- return nativeAvailable
43
- ? {
44
- implementation: "native",
45
- reason: "native_available",
46
- nativeAvailable,
47
- nativePath,
48
- }
49
- : {
50
- implementation: "ts",
51
- reason: "fallback_no_native",
52
- nativeAvailable,
53
- nativePath,
54
- };
55
- };
56
- /**
57
- * Record which psql implementation is about to run, then flush analytics.
58
- *
59
- * Both exec paths below call `process.exit()`, which short-circuits the
60
- * main loop's `closeAnalytics()` — so without flushing here the event (and
61
- * any earlier queued events, e.g. `CLI Started`) would be dropped. The
62
- * flush is bounded by {@link ANALYTICS_FLUSH_TIMEOUT_MS} so a slow or
63
- * unreachable analytics endpoint can't stall the psql launch. No-ops when
64
- * analytics is disabled (`--analytics false`), since the client is absent.
65
- */
66
- const reportPsqlInvocation = async (plan) => {
67
- trackEvent("psql_invoked", {
68
- implementation: plan.implementation,
69
- reason: plan.reason,
70
- nativeAvailable: plan.nativeAvailable,
71
- });
72
- await closeAnalytics({ timeout: ANALYTICS_FLUSH_TIMEOUT_MS });
73
- };
74
- const execNative = async (binary, connection_uri, args) => {
75
- log.info("Connecting to the database using psql...");
76
- const child = spawn(binary, [connection_uri, ...args], {
77
- stdio: "inherit",
78
- });
79
- for (const signame of ["SIGINT", "SIGTERM"]) {
80
- process.on(signame, (code) => {
81
- if (!child.killed && code !== null) {
82
- child.kill(code);
83
- }
84
- });
85
- }
86
- return new Promise((_, reject) => {
87
- child.on("exit", (code) => {
88
- process.exit(code === null ? 1 : code);
89
- });
90
- child.on("error", reject);
91
- });
92
- };
93
- const execTs = async (connection_uri, args) => {
94
- log.info("Connecting to the database using embedded psql (TypeScript)...");
95
- const { runPsql } = await import("../psql/index.js");
96
- const code = await runPsql([connection_uri, ...args], {
97
- stdin: process.stdin,
98
- stdout: process.stdout,
99
- stderr: process.stderr,
100
- });
101
- process.exit(code);
102
- };
103
- export const psql = async (connection_uri, args = [], opts = {}) => {
104
- const plan = await planPsql(opts);
105
- await reportPsqlInvocation(plan);
106
- if (plan.implementation === "ts") {
107
- if (plan.reason === "fallback_no_native") {
108
- log.info("psql binary not found on PATH; falling back to embedded TypeScript psql");
109
- }
110
- return execTs(connection_uri, args);
111
- }
112
- // implementation === 'native'
113
- if (plan.nativePath === null) {
114
- // Only reachable when native was explicitly requested (mode: 'native')
115
- // but no binary is on PATH.
116
- log.error(`psql is not available in the PATH`);
117
- process.exit(1);
118
- }
119
- return execNative(plan.nativePath, connection_uri, args);
120
- };
@@ -1,5 +0,0 @@
1
- export const toSnakeCase = (str) => str
2
- .split(" ")
3
- .map((word) => word.toLowerCase())
4
- .join("_");
5
- export const isObject = (value) => value != null && value === Object(value);
package/dist/utils/ui.js DELETED
@@ -1,59 +0,0 @@
1
- // returns the next string if matches the given matcher,
2
- // otherwise returns null
3
- // consumes the line from the lines array
4
- export const consumeNextMatching = (lines, matcher) => {
5
- while (lines.length > 0) {
6
- const line = lines.shift().trim();
7
- if (line === "") {
8
- continue;
9
- }
10
- if (matcher.test(line)) {
11
- return line;
12
- }
13
- return null;
14
- }
15
- return null;
16
- };
17
- // returns strings if next non-empty line matches the given matcher,
18
- // otherwise returns empty array
19
- // consumes the lines from the lines array
20
- export const consumeBlockIfMatches = (lines, matcher) => {
21
- const result = [];
22
- if (lines.length === 0) {
23
- return result;
24
- }
25
- let line = lines.shift();
26
- while (line.trim() === "") {
27
- line = lines.shift();
28
- }
29
- if (!matcher.test(line)) {
30
- lines.unshift(line);
31
- return result;
32
- }
33
- result.push(line);
34
- while (lines.length > 0) {
35
- line = lines.shift();
36
- if (line.trim() === "") {
37
- break;
38
- }
39
- result.push(line);
40
- }
41
- return result;
42
- };
43
- export const splitColumns = (line) => {
44
- const result = line.trim().split(/\s{2,}/);
45
- result[1] = result[1] ?? "";
46
- if (result.length > 2) {
47
- result[1] = result.slice(1).join(" ");
48
- }
49
- return result;
50
- };
51
- export const drawPointer = (width) => {
52
- const result = [];
53
- result.push("└");
54
- for (let i = 0; i < width - 4; i++) {
55
- result.push("─");
56
- }
57
- result.push(">");
58
- return result.join("");
59
- };
package/dist/utils/zip.js DELETED
@@ -1,4 +0,0 @@
1
- import { zipSync } from "fflate";
2
- // Zip the esbuild output (index.mjs) into the archive the Functions deploy endpoint
3
- // expects. Compression level 6 matches the previous bundler.
4
- export const zipBundle = (entries) => zipSync(entries, { level: 6 });
package/dist/writer.js DELETED
@@ -1,97 +0,0 @@
1
- import chalk from "chalk";
2
- import Table from "cli-table";
3
- import YAML from "yaml";
4
- import { isCi } from "./env.js";
5
- import { isObject, toSnakeCase } from "./utils/string.js";
6
- const writeYaml = (chunks) => {
7
- return YAML.stringify(chunks.length === 1
8
- ? chunks[0].data
9
- : Object.fromEntries(chunks.map(({ config, data }, idx) => [
10
- config.title ? toSnakeCase(config.title) : idx,
11
- data,
12
- ])), null, 2);
13
- };
14
- const writeJson = (chunks) => {
15
- return JSON.stringify(chunks.length === 1
16
- ? chunks[0].data
17
- : Object.fromEntries(chunks.map(({ config, data }, idx) => [
18
- config.title ? toSnakeCase(config.title) : idx,
19
- data,
20
- ])), null, 2);
21
- };
22
- const writeTable = (chunks, out) => {
23
- chunks.forEach(({ data, config: { emptyMessage, fields, title, renderColumns = {} }, }) => {
24
- const arrayData = Array.isArray(data) ? data : [data];
25
- if (!arrayData.length && emptyMessage) {
26
- out.write("\n" + emptyMessage + "\n");
27
- return;
28
- }
29
- const fieldsFiltered = fields.filter((field) => arrayData.some((item) => item[field] !== undefined && item[field] !== ""));
30
- const table = new Table({
31
- style: {
32
- head: ["green"],
33
- },
34
- head: fieldsFiltered.map((field) => field
35
- .split("_")
36
- .map((word) => word[0].toUpperCase() + word.slice(1))
37
- .join(" ")),
38
- });
39
- arrayData.forEach((item) => {
40
- table.push(fieldsFiltered.map((field) => {
41
- const value = item[field];
42
- if (renderColumns[field]) {
43
- return renderColumns[field]?.(item);
44
- }
45
- return Array.isArray(value)
46
- ? value.join("\n")
47
- : isObject(value)
48
- ? JSON.stringify(value, null, 2)
49
- : (value ?? "");
50
- }));
51
- });
52
- if (title) {
53
- out.write((isCi() ? title : chalk.bold(title)) + "\n");
54
- }
55
- out.write(table.toString());
56
- out.write("\n");
57
- });
58
- };
59
- /**
60
- *
61
- * Parses the output format, takes data and writes the output to stdout.
62
- *
63
- * @example
64
- * const { data } = await props.apiClient.listProjectBranches(props.project.id);
65
- * // to output single data
66
- * writer(props).end(data, { fields: ['id', 'name', 'created_at'] })
67
- * // to output multiple data
68
- * writer(props)
69
- * .write(data, { fields: ['id', 'name', 'created_at'], title: 'branches' })
70
- * .write(data, { fields: ['id', 'created_at'], title: 'endpoints' })
71
- * .end()
72
- */
73
- export const writer = (props) => {
74
- const out = props.out ?? process.stdout;
75
- const chunks = [];
76
- return {
77
- write(data, config) {
78
- chunks.push({ data, config });
79
- return this;
80
- },
81
- text(data) {
82
- return out.write(data);
83
- },
84
- end: (...args) => {
85
- if (args.length === 2) {
86
- chunks.push({ data: args[0], config: args[1] });
87
- }
88
- if (props.output == "yaml") {
89
- return out.write(writeYaml(chunks));
90
- }
91
- if (props.output == "json") {
92
- return out.write(writeJson(chunks));
93
- }
94
- writeTable(chunks, out);
95
- },
96
- };
97
- };