neon 8.4.3 → 8.4.4

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/analytics.js CHANGED
@@ -2,7 +2,7 @@ import { a as OAUTH, t as storeFor } from "./_chunks/credential_io-ByNuojoE.js";
2
2
  import { getCliAgent, getGithubEnvVars, isCi } from "./env.js";
3
3
  import { log } from "./log.js";
4
4
  import pkg_default from "./pkg.js";
5
- import { getApiClient, isNeonApiError } from "./api.js";
5
+ import { UnreadableResponseError, getApiClient, isNeonApiError } from "./api.js";
6
6
  import { getAuthContext } from "./auth_context.js";
7
7
  import { n as credentialsPath } from "./_chunks/paths-DMq0Lt7a.js";
8
8
  import "./config.js";
@@ -271,7 +271,7 @@ const sendError = (err, errCode) => {
271
271
  });
272
272
  });
273
273
  log.debug("Sent CLI error event: %s", errCode);
274
- if (errCode === "UNKNOWN_ERROR" && isUnexpectedError(err)) {
274
+ if (errCode === "UNKNOWN_ERROR" && isUnexpectedError(err) || err instanceof UnreadableResponseError) {
275
275
  const report = import("./error_reporting.js").then(({ reportUnexpectedError }) => reportUnexpectedError(err, redactCredentialTokenIds)).catch((reportError) => {
276
276
  log.debug("Could not report the error to Sentry: %s", reportError);
277
277
  });
package/dist/api.js CHANGED
@@ -42,6 +42,16 @@ var NeonApiError = class extends Error {
42
42
  this.code = init.code;
43
43
  }
44
44
  };
45
+ /**
46
+ * A 2xx response whose body could not be read or parsed. The request succeeded, so this is
47
+ * reported to Sentry as well as counted as an API error.
48
+ */
49
+ var UnreadableResponseError = class extends NeonApiError {
50
+ constructor(message, init) {
51
+ super(message, init);
52
+ this.name = "UnreadableResponseError";
53
+ }
54
+ };
45
55
  /** Narrow an unknown error to a {@link NeonApiError}. */
46
56
  function isNeonApiError(err) {
47
57
  return err instanceof NeonApiError;
@@ -170,6 +180,20 @@ function httpError(response, body) {
170
180
  });
171
181
  }
172
182
  /**
183
+ * The cause's message is left out: `JSON.parse` quotes the input, and the body can carry a
184
+ * password or token that would reach stderr and analytics.
185
+ */
186
+ function unreadableBodyError(response, cause) {
187
+ const base = httpError(response, void 0);
188
+ const reason = cause instanceof SyntaxError ? "the body is not valid JSON" : "the body could not be read";
189
+ return new UnreadableResponseError(`Could not read the Neon API response (${response.status} ${response.statusText}) to ${base.requestPath ?? "the request"}: ${reason}`, {
190
+ status: base.status,
191
+ statusText: base.statusText,
192
+ headers: base.headers,
193
+ requestPath: base.requestPath
194
+ });
195
+ }
196
+ /**
173
197
  * Translate a thrown `fetch` failure into a {@link NeonApiError}. A request
174
198
  * timeout uses `ECONNABORTED` (matching the old axios behaviour, and excluded
175
199
  * from `isNetworkError`'s connectivity codes so it's still reported as a
@@ -283,6 +307,7 @@ const getApiClient = ({ apiKey, apiHost, requestTimeoutMs = REQUEST_TIMEOUT_MS }
283
307
  const response = result.response;
284
308
  if (!response) throw networkError(result.error ?? /* @__PURE__ */ new Error("No response from Neon API"));
285
309
  if (!response.ok) throw httpError(response, rawErrorBody(result.error) ?? result.data);
310
+ if (result.error !== void 0 && result.error !== null) throw unreadableBodyError(response, rawErrorBody(result.error));
286
311
  return {
287
312
  data: result.data,
288
313
  status: response.status,
@@ -978,4 +1003,4 @@ const getApiClient = ({ apiKey, apiHost, requestTimeoutMs = REQUEST_TIMEOUT_MS }
978
1003
  };
979
1004
  };
980
1005
  //#endregion
981
- export { ContentType, NeonApiError, codeFromBody, getApiClient, isNeonApiError, messageFromBody, retryOnLock };
1006
+ export { ContentType, NeonApiError, UnreadableResponseError, codeFromBody, getApiClient, isNeonApiError, messageFromBody, retryOnLock };
@@ -4,11 +4,11 @@ import { isClaimableEnvTarget } from "../claimable/state.js";
4
4
  import { getCliName } from "../utils/cli_name.js";
5
5
  import { readEnvFile, resolveEnvFilePath } from "../env_file.js";
6
6
  import { l as functionBaseUrlKey } from "../_chunks/env-BpP3Dqpe.js";
7
- import { branchIdResolve } from "../utils/enrichers.js";
8
- import { bundleEntry } from "../utils/esbuild.js";
9
7
  import { a as resolveDevEnv } from "../_chunks/env-4WGRW2nw.js";
10
8
  import { findConfigFunctionBySource, resolveFunctionsFromConfig } from "../dev/functions.js";
11
9
  import { resolveWatchInputs } from "../dev/inputs.js";
10
+ import { branchIdResolve } from "../utils/enrichers.js";
11
+ import { bundleEntry } from "../utils/esbuild.js";
12
12
  import { existsSync, mkdirSync, rmSync, statSync, writeFileSync } from "node:fs";
13
13
  import { basename, dirname, join, relative, resolve } from "node:path";
14
14
  import { fileURLToPath } from "node:url";
@@ -8,9 +8,9 @@ import { mergeEnvFile, readEnvFile, resolveEnvFilePath } from "../env_file.js";
8
8
  import { t as NEON_ENV_VAR_KEYS, u as isFunctionBaseUrlKey } from "../_chunks/env-BpP3Dqpe.js";
9
9
  import { ENV_PULL_KEY_HELP, ENV_PULL_SERVICES, envKeysForSelection, envPullFlagValue, ownedEnvServiceKeys, parseEnvPullKeys } from "../env_services.js";
10
10
  import { listedServices } from "../utils/staging.js";
11
+ import { i as dropClaimableUnsupported, o as resolveNeonEnvVars } from "../_chunks/env-4WGRW2nw.js";
11
12
  import { fillSingleProject, resolveBranchRef } from "../utils/enrichers.js";
12
13
  import { warnAiGateway } from "../utils/ai_gateway_notice.js";
13
- import { i as dropClaimableUnsupported, o as resolveNeonEnvVars } from "../_chunks/env-4WGRW2nw.js";
14
14
  import { formatPulledEnv, pulledBranch } from "./env_output.js";
15
15
  import { existsSync } from "node:fs";
16
16
  import chalk from "chalk";
@@ -1,7 +1,7 @@
1
1
  import { t as __exportAll } from "../_chunks/rolldown-runtime-8H4AJuhK.js";
2
2
  import { writer } from "../writer.js";
3
- import { branchIdFromProps, fillSingleProject } from "../utils/enrichers.js";
4
3
  import { o as resolveNeonEnvVars } from "../_chunks/env-4WGRW2nw.js";
4
+ import { branchIdFromProps, fillSingleProject } from "../utils/enrichers.js";
5
5
  import YAML from "yaml";
6
6
  //#region src/commands/subscribe.ts
7
7
  var subscribe_exports = /* @__PURE__ */ __exportAll({
@@ -302,27 +302,24 @@ const rowFields = (rows) => {
302
302
  for (const row of rows) for (const key of Object.keys(row)) seen.add(key);
303
303
  return [...seen];
304
304
  };
305
- const consumeSnapshots = async (subscription, render, signal) => consumeSubscription(subscription, (fail) => [subscription.onReset(() => attempt(fail, () => {
306
- const rows = subscription.getSnapshot().data;
307
- if (rows !== void 0) render({
308
- type: "snapshot",
309
- rows
310
- });
311
- })), subscription.onBatch(() => attempt(fail, () => {
305
+ const consumeSnapshots = async (subscription, render, signal) => consumeSubscription(subscription, (fail) => [subscription.onUpdate(() => attempt(fail, () => {
312
306
  const rows = subscription.getSnapshot().data;
313
307
  if (rows !== void 0) render({
314
308
  type: "snapshot",
315
309
  rows
316
310
  });
317
311
  }))], render, signal);
318
- const consumeChanges = async (subscription, render, signal) => consumeSubscription(subscription, (fail) => [subscription.onReset((rows) => attempt(fail, () => render({
319
- type: "reset",
320
- rows
321
- }))), subscription.onBatch((changes, batch) => attempt(fail, () => render({
322
- type: "batch",
323
- txids: batch.txids,
324
- changes
325
- })))], render, signal);
312
+ const consumeChanges = async (subscription, render, signal) => consumeSubscription(subscription, (fail) => [subscription.onUpdate((update) => {
313
+ if (update.type === "rows") attempt(fail, () => render({
314
+ type: "reset",
315
+ rows: update.rows
316
+ }));
317
+ else attempt(fail, () => render({
318
+ type: "batch",
319
+ txids: update.batch.txids,
320
+ changes: update.changes
321
+ }));
322
+ })], render, signal);
326
323
  const consumeSubscription = (subscription, listenForData, render, signal) => new Promise((resolve, reject) => {
327
324
  let settled = false;
328
325
  let detachData = [];
package/dist/index.js CHANGED
@@ -1,6 +1,6 @@
1
1
  import { log } from "./log.js";
2
2
  import pkg_default from "./pkg.js";
3
- import { codeFromBody, isNeonApiError, messageFromBody } from "./api.js";
3
+ import { UnreadableResponseError, codeFromBody, isNeonApiError, messageFromBody } from "./api.js";
4
4
  import { getAuthContext } from "./auth_context.js";
5
5
  import { r as defaultDir } from "./_chunks/paths-DMq0Lt7a.js";
6
6
  import { ensureConfigDir } from "./config.js";
@@ -188,6 +188,7 @@ async function handleError(msg, err, canRetry) {
188
188
  } else {
189
189
  const serverMessage = messageFromBody(err.data);
190
190
  if (serverMessage) log.error(serverMessage);
191
+ else if (err instanceof UnreadableResponseError) log.error(err.message);
191
192
  else log.error([`HTTP ${err.status ?? ""} ${err.statusText ?? ""}`.trim(), err.requestPath].filter(Boolean).join(" | "));
192
193
  log.debug("status: %d %s | path: %s", err.status, err.statusText, err.requestPath);
193
194
  sendError(err, "API_ERROR");
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "neon",
3
- "version": "8.4.3",
3
+ "version": "8.4.4",
4
4
  "description": "CLI tool for Neon, the cloud backend primitives built around Lakebase Postgres",
5
5
  "keywords": [
6
6
  "neon",
@@ -66,10 +66,10 @@
66
66
  "yaml": "^2.9.0",
67
67
  "yargs": "17.7.2",
68
68
  "yoctocolors": "^2.1.2",
69
- "@neon/config-runtime": "1.9.1",
70
69
  "@neon/config": "1.9.1",
71
- "@neon/sdk": "7.2.0",
72
- "@neon/realtime": "0.0.1"
70
+ "@neon/config-runtime": "1.9.1",
71
+ "@neon/realtime": "0.0.3",
72
+ "@neon/sdk": "7.2.0"
73
73
  },
74
74
  "optionalDependencies": {
75
75
  "@napi-rs/keyring": "1.3.0",