@valbuild/server 0.113.0 → 0.115.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.
@@ -5318,13 +5318,6 @@ class ValOpsFS extends ValOps {
5318
5318
  };
5319
5319
  }
5320
5320
  }
5321
- async getCommitSummary() {
5322
- return {
5323
- error: {
5324
- message: "Val is in development / local mode. Cannot generate summary"
5325
- }
5326
- };
5327
- }
5328
5321
  async getStat(params) {
5329
5322
  // In ValOpsFS, we don't have a websocket server to listen to file changes so we use long-polling.
5330
5323
  // If a file that Val depends on changes, we break the connection and tell the client to request again to get the latest values.
@@ -6502,9 +6495,6 @@ const MetadataRes = z.object({
6502
6495
  metadata: Metadata,
6503
6496
  type: z.union([z.literal("file"), z.literal("image")]).nullable()
6504
6497
  });
6505
- const SummaryResponse = z.object({
6506
- commitSummary: z.string()
6507
- });
6508
6498
  const GetApplicablePatches = z.object({
6509
6499
  patches: z.array(z.object({
6510
6500
  path: z.string(),
@@ -6691,69 +6681,6 @@ class ValOpsHttp extends ValOps {
6691
6681
  };
6692
6682
  }
6693
6683
  }
6694
- async getCommitSummary(preparedCommit) {
6695
- try {
6696
- var _res$headers$get2;
6697
- const res = await fetch(`${this.contentUrl}/v1/${this.project}/commit-summary`, {
6698
- method: "POST",
6699
- headers: {
6700
- ...this.authHeaders,
6701
- "Content-Type": "application/json"
6702
- },
6703
- body: JSON.stringify({
6704
- patchedSourceFiles: preparedCommit.patchedSourceFiles,
6705
- previousSourceFiles: preparedCommit.previousSourceFiles
6706
- })
6707
- });
6708
- if (res.ok) {
6709
- const json = await res.json();
6710
- const parsed = SummaryResponse.safeParse(json);
6711
- if (parsed.success) {
6712
- return {
6713
- commitSummary: parsed.data.commitSummary
6714
- };
6715
- }
6716
- console.error(`Could not parse summary response. Error: ${fromError(parsed.error).toString()}`);
6717
- return {
6718
- error: {
6719
- message: `Cannot get the summary of your changes. An error has been logged. Possible cause: the current version of Val might be too old. Please try again later or contact the developers on your team.`
6720
- }
6721
- };
6722
- }
6723
- if (res.status === 401) {
6724
- console.error("Unauthorized to get summary");
6725
- return {
6726
- error: {
6727
- message: "Could not get summary. Although your user is authorized, the application has authorization issues. Contact the developers on your team and ask them to verify the api keys."
6728
- }
6729
- };
6730
- }
6731
- const unknownErrorMessage = `Could not get summary. HTTP error: ${res.status} ${res.statusText}`;
6732
- if ((_res$headers$get2 = res.headers.get("Content-Type")) !== null && _res$headers$get2 !== void 0 && _res$headers$get2.includes("application/json")) {
6733
- const json = await res.json();
6734
- const message = getErrorMessageFromUnknownJson(json, unknownErrorMessage);
6735
- console.error("Summary error:", message);
6736
- return {
6737
- error: {
6738
- message
6739
- }
6740
- };
6741
- }
6742
- console.error(unknownErrorMessage);
6743
- return {
6744
- error: {
6745
- message: unknownErrorMessage
6746
- }
6747
- };
6748
- } catch (e) {
6749
- console.error("Could not get summary (connection error?):", e);
6750
- return {
6751
- error: {
6752
- message: `Could not get summary. Error: ${e instanceof Error ? e.message : JSON.stringify(e)}`
6753
- }
6754
- };
6755
- }
6756
- }
6757
6684
  async getStat(params) {
6758
6685
  if (!(params !== null && params !== void 0 && params.profileId)) {
6759
6686
  return {
@@ -7081,7 +7008,7 @@ class ValOpsHttp extends ValOps {
7081
7008
  coreVersion: Internal.VERSION.core
7082
7009
  })
7083
7010
  }).then(async res => {
7084
- var _res$headers$get3;
7011
+ var _res$headers$get2;
7085
7012
  if (res.ok) {
7086
7013
  const parsed = SavePatchResponse.safeParse(await res.json());
7087
7014
  if (parsed.success) {
@@ -7100,7 +7027,7 @@ class ValOpsHttp extends ValOps {
7100
7027
  message: "Conflict: " + (await res.text())
7101
7028
  });
7102
7029
  }
7103
- if ((_res$headers$get3 = res.headers.get("Content-Type")) !== null && _res$headers$get3 !== void 0 && _res$headers$get3.includes("application/json")) {
7030
+ if ((_res$headers$get2 = res.headers.get("Content-Type")) !== null && _res$headers$get2 !== void 0 && _res$headers$get2.includes("application/json")) {
7104
7031
  const json = await res.json();
7105
7032
  const message = getErrorMessageFromUnknownJson(json, "Unknown error");
7106
7033
  return result.err({
@@ -7383,51 +7310,9 @@ class ValOpsHttp extends ValOps {
7383
7310
  };
7384
7311
  });
7385
7312
  }
7386
- async getCommitMessage(preparedCommit) {
7387
- var _res$headers$get4;
7388
- const res = await fetch(`${this.contentUrl}/v1/${this.project}/commit-summary`, {
7389
- method: "POST",
7390
- headers: {
7391
- ...this.authHeaders,
7392
- "Content-Type": "application/json"
7393
- },
7394
- body: JSON.stringify({
7395
- patchedSourceFiles: preparedCommit.patchedSourceFiles,
7396
- previousSourceFiles: preparedCommit.previousSourceFiles
7397
- })
7398
- });
7399
- if (res.ok) {
7400
- const json = await res.json();
7401
- const parsed = SummaryResponse.safeParse(json);
7402
- if (parsed.success) {
7403
- return {
7404
- commitSummary: parsed.data.commitSummary
7405
- };
7406
- }
7407
- return {
7408
- error: {
7409
- message: `Could not parse commit summary response. Error: ${fromError(parsed.error)}`
7410
- }
7411
- };
7412
- }
7413
- if ((_res$headers$get4 = res.headers.get("Content-Type")) !== null && _res$headers$get4 !== void 0 && _res$headers$get4.includes("application/json")) {
7414
- const json = await res.json();
7415
- const message = getErrorMessageFromUnknownJson(json, "Unknown error");
7416
- return {
7417
- error: {
7418
- message
7419
- }
7420
- };
7421
- }
7422
- return {
7423
- error: {
7424
- message: "Could not get commit message. HTTP error: " + res.status + " " + res.statusText
7425
- }
7426
- };
7427
- }
7428
7313
  async commit(prepared, message, committer, filesDirectory, newBranch) {
7429
7314
  try {
7430
- var _res$headers$get5;
7315
+ var _res$headers$get3;
7431
7316
  const existingBranch = this.branch;
7432
7317
  const res = await fetch(`${this.contentUrl}/v1/${this.project}/commit`, {
7433
7318
  method: "POST",
@@ -7464,7 +7349,7 @@ class ValOpsHttp extends ValOps {
7464
7349
  }
7465
7350
  };
7466
7351
  }
7467
- if ((_res$headers$get5 = res.headers.get("Content-Type")) !== null && _res$headers$get5 !== void 0 && _res$headers$get5.includes("application/json")) {
7352
+ if ((_res$headers$get3 = res.headers.get("Content-Type")) !== null && _res$headers$get3 !== void 0 && _res$headers$get3.includes("application/json")) {
7468
7353
  const json = z.object({
7469
7354
  isNotFastForward: z.boolean().optional()
7470
7355
  }).safeParse(await res.json());
@@ -9117,49 +9002,6 @@ const ValServer = (valModules, options, callbacks) => {
9117
9002
  });
9118
9003
  }
9119
9004
  },
9120
- "/commit-summary": {
9121
- GET: async req => {
9122
- const cookies = req.cookies;
9123
- const auth = getAuth(cookies);
9124
- if (auth.error) {
9125
- return {
9126
- status: 401,
9127
- json: {
9128
- message: auth.error
9129
- }
9130
- };
9131
- }
9132
- const query = req.query;
9133
- const patchIds = query.patch_id;
9134
- const patches = await serverOps.fetchPatches({
9135
- patchIds,
9136
- excludePatchOps: false
9137
- });
9138
- const analysis = serverOps.analyzePatches(patches.patches, patches.commits, commit);
9139
- const preparedCommit = await serverOps.prepare({
9140
- ...analysis,
9141
- ...patches
9142
- });
9143
- const res = await serverOps.getCommitSummary(preparedCommit);
9144
- if (res.error) {
9145
- console.error("Failed to summarize", res.error);
9146
- return {
9147
- status: 400,
9148
- json: {
9149
- message: res.error.message
9150
- }
9151
- };
9152
- }
9153
- return {
9154
- status: 200,
9155
- json: {
9156
- baseSha: await serverOps.getBaseSha(),
9157
- patchIds,
9158
- commitSummary: res.commitSummary
9159
- }
9160
- };
9161
- }
9162
- },
9163
9005
  "/save": {
9164
9006
  POST: async req => {
9165
9007
  const cookies = req.cookies;
@@ -9442,11 +9284,18 @@ const ValServer = (valModules, options, callbacks) => {
9442
9284
  }
9443
9285
  const json = await upstreamRes.json();
9444
9286
  const wsUrl = options.valContentUrl.replace(/^https:/, "wss:").replace(/^http:/, "ws:") + `/v1/${options.project}/ai/connect`;
9287
+ // Forwarded as-is, minus anything that is not a string: which
9288
+ // providers are reachable is the content server's to decide, and
9289
+ // this only has to carry the answer without editorialising.
9290
+ const providers = Array.isArray(json.providers) ? json.providers.filter(provider => typeof provider === "string") : undefined;
9445
9291
  return {
9446
9292
  status: 200,
9447
9293
  json: {
9448
9294
  nonce: json.nonce,
9449
- wsUrl
9295
+ wsUrl,
9296
+ ...(providers ? {
9297
+ providers
9298
+ } : {})
9450
9299
  }
9451
9300
  };
9452
9301
  } catch (err) {
@@ -10464,6 +10313,10 @@ async function initHandlerOptions(route, opts, config) {
10464
10313
  const maybeValProject = opts.project || process.env.VAL_PROJECT;
10465
10314
  const valBuildUrl = opts.valBuildUrl || process.env.VAL_BUILD_URL || "https://admin.val.build";
10466
10315
  const valContentUrl = opts.valContentUrl || process.env.VAL_CONTENT_URL || DEFAULT_CONTENT_HOST;
10316
+ warnIfInsecureUrls({
10317
+ valBuildUrl,
10318
+ valContentUrl
10319
+ });
10467
10320
  if (isProxyMode) {
10468
10321
  var _opts$versions, _opts$versions2;
10469
10322
  if (!maybeApiKey || !maybeValSecret) {
@@ -10505,7 +10358,6 @@ async function initHandlerOptions(route, opts, config) {
10505
10358
  };
10506
10359
  } else {
10507
10360
  const cwd = process.cwd();
10508
- const valBuildUrl = opts.valBuildUrl || process.env.VAL_BUILD_URL || "https://admin.val.build";
10509
10361
  return {
10510
10362
  mode: "fs",
10511
10363
  cwd,
@@ -10522,6 +10374,84 @@ async function initHandlerOptions(route, opts, config) {
10522
10374
  }
10523
10375
  }
10524
10376
 
10377
+ /**
10378
+ * Hosts we send credentials to, and what each one puts at risk. They differ:
10379
+ * only `valBuildUrl` hands back the app token that becomes the session cookie,
10380
+ * so a single shared sentence would overstate one and understate the other.
10381
+ */
10382
+
10383
+ const CREDENTIAL_BEARING_URLS = ["valBuildUrl", "valContentUrl"];
10384
+ const WHAT_IS_AT_RISK = {
10385
+ valBuildUrl: "Val's api key is sent to this host, and the token it returns is what this server signs into the session cookie, " + "so both can be read - and the token replaced - by anyone on the network path.",
10386
+ valContentUrl: "Val's api key, or the caller's personal access token, is sent to this host, " + "so it can be read by anyone on the network path."
10387
+ };
10388
+
10389
+ // NOTE: `URL.hostname` keeps the brackets on an IPv6 literal, so this is
10390
+ // "[::1]" and not "::1" - and `http://[0:0:0:0:0:0:0:1]` normalises to the
10391
+ // same short form before it gets here. Dropping the brackets looks like a
10392
+ // tidy-up and silently stops matching IPv6 loopback.
10393
+ const LOOPBACK_HOSTNAMES = ["localhost", "127.0.0.1", "[::1]"];
10394
+
10395
+ /**
10396
+ * The URL as it is safe to print. `http://user:pass@host` is a legal override,
10397
+ * and a warning about credential exposure that puts the password in the log
10398
+ * would be the very thing it is warning about.
10399
+ */
10400
+ function forLog(parsed) {
10401
+ if (!parsed.username && !parsed.password) {
10402
+ return parsed.href;
10403
+ }
10404
+ const redacted = new URL(parsed.href);
10405
+ redacted.username = "";
10406
+ redacted.password = "";
10407
+ return `${redacted.href} (credentials redacted)`;
10408
+ }
10409
+
10410
+ /**
10411
+ * Returns a warning if `url` would send credentials somewhere they can be read
10412
+ * off the wire, or null if it is fine.
10413
+ *
10414
+ * Both URLs default to https, but each is overridable - `opts.valBuildUrl` /
10415
+ * `VAL_BUILD_URL`, `opts.valContentUrl` / `VAL_CONTENT_URL` - and neither
10416
+ * override has ever been scheme-checked. Point one at a plain http host and the
10417
+ * api key goes out in clear text, and whatever comes back is whatever the
10418
+ * network says: for `valBuildUrl` that includes the app token this server
10419
+ * re-signs into the session cookie.
10420
+ *
10421
+ * Loopback over http is exempt: that is a val.build running on the developer's
10422
+ * own machine, and there is no network to be on the wrong side of.
10423
+ *
10424
+ * This warns rather than throws. Both overrides are set by the operator, not by
10425
+ * an attacker, so this is a misconfiguration to surface - not untrusted input to
10426
+ * reject - and refusing to boot would break anyone deliberately pointing at an
10427
+ * internal http host today.
10428
+ */
10429
+ function insecureUrlWarning(name, url) {
10430
+ let parsed;
10431
+ try {
10432
+ parsed = new URL(url);
10433
+ } catch {
10434
+ // NOTE: the URL is not echoed here. It did not parse, so there is nothing
10435
+ // to redact with, and an unparseable string can still hold a password.
10436
+ return `Val: ${name} is not a valid URL.`;
10437
+ }
10438
+ if (parsed.protocol === "https:") {
10439
+ return null;
10440
+ }
10441
+ if (parsed.protocol === "http:" && (LOOPBACK_HOSTNAMES.includes(parsed.hostname) || parsed.hostname.endsWith(".localhost"))) {
10442
+ return null;
10443
+ }
10444
+ return `Val: ${name} is set to ${forLog(parsed)}, which is not https. ` + `${WHAT_IS_AT_RISK[name]} ` + `Use https, or a loopback address for local development.`;
10445
+ }
10446
+ function warnIfInsecureUrls(urls) {
10447
+ for (const name of CREDENTIAL_BEARING_URLS) {
10448
+ const warning = insecureUrlWarning(name, urls[name]);
10449
+ if (warning) {
10450
+ console.warn(warning);
10451
+ }
10452
+ }
10453
+ }
10454
+
10525
10455
  // TODO: remove
10526
10456
  async function safeReadGit(cwd) {
10527
10457
  async function findGitHead(currentDir, depth) {
@@ -12525,7 +12455,17 @@ async function findAndEvalValConfigFile(projectRoot) {
12525
12455
  }
12526
12456
 
12527
12457
  /**
12528
- * The Val login device flow, as reusable primitives.
12458
+ * The Val login flow, as reusable primitives.
12459
+ *
12460
+ * This is an RFC 8628 device authorization grant. The shape that matters:
12461
+ * {@link ValDeviceAuthorization.deviceCode} is a secret this process holds and
12462
+ * polls with, while {@link ValDeviceAuthorization.userCode} is the short string
12463
+ * the human reads out of the terminal and types into a browser. Only the device
12464
+ * code can collect a token.
12465
+ *
12466
+ * Keep them apart. Show the user code; never print, log or put the device code
12467
+ * in a URL. An earlier version of this flow used one value for both jobs, which
12468
+ * meant anyone who saw the verification link could collect the token it led to.
12529
12469
  *
12530
12470
  * The CLI wraps these with terminal output, and `@valbuild/language-server`
12531
12471
  * wraps them with LSP `window/showDocument` and progress reporting. Neither the
@@ -12539,6 +12479,21 @@ const DEFAULT_LOGIN_HOST = "https://admin.val.build";
12539
12479
  function defaultHost() {
12540
12480
  return process.env.VAL_BUILD_URL || DEFAULT_LOGIN_HOST;
12541
12481
  }
12482
+
12483
+ /**
12484
+ * What gets shown on the approval screen so the person can tell which terminal
12485
+ * is asking. Self-reported and therefore a hint, not proof — the server treats
12486
+ * it as untrusted display text.
12487
+ */
12488
+ function defaultDeviceName() {
12489
+ try {
12490
+ return `${os.hostname()} (${os.platform()})`;
12491
+ } catch {
12492
+ // hostname() can throw on locked-down containers. A missing device name is
12493
+ // not worth failing a login over; the server renders "Unknown".
12494
+ return "";
12495
+ }
12496
+ }
12542
12497
  class ValLoginError extends Error {
12543
12498
  constructor(code, message, details) {
12544
12499
  super(message);
@@ -12548,20 +12503,24 @@ class ValLoginError extends Error {
12548
12503
  }
12549
12504
  }
12550
12505
 
12551
- /** A login attempt that is waiting for the user to confirm in a browser. */
12506
+ /** A login attempt that is waiting for the user to approve it in a browser. */
12552
12507
 
12553
12508
  /**
12554
- * Begin a login attempt. The caller is responsible for getting
12555
- * {@link ValLoginSession.url} in front of the user.
12509
+ * Begin a login attempt. The caller is responsible for getting the user code
12510
+ * and verification URL in front of the user.
12556
12511
  */
12557
12512
  async function startValLogin(options = {}) {
12558
12513
  var _response$headers$get;
12559
12514
  const host = options.host ?? defaultHost();
12515
+ const deviceName = options.deviceName ?? defaultDeviceName();
12560
12516
  const response = await fetch(`${host}/api/login`, {
12561
12517
  method: "POST",
12562
12518
  headers: {
12563
12519
  "Content-Type": "application/json"
12564
- }
12520
+ },
12521
+ body: JSON.stringify(deviceName ? {
12522
+ device_name: deviceName
12523
+ } : {})
12565
12524
  });
12566
12525
  if (response.status >= 500) {
12567
12526
  const text = await response.text().catch(() => "");
@@ -12572,42 +12531,63 @@ async function startValLogin(options = {}) {
12572
12531
  throw new ValLoginError("unexpected-content-type", "Unexpected failure while trying to login (content type was not JSON).", text ? `Server response: ${text} (status: ${response.status})` : `Status: ${response.status}`);
12573
12532
  }
12574
12533
  const json = await response.json();
12575
- const nonce = json === null || json === void 0 ? void 0 : json.nonce;
12576
- const url = json === null || json === void 0 ? void 0 : json.url;
12577
- if (typeof nonce !== "string" || typeof url !== "string") {
12578
- throw new ValLoginError("unexpected-response", "Unexpected response from the server.", JSON.stringify(json));
12534
+ const deviceCode = json === null || json === void 0 ? void 0 : json.device_code;
12535
+ const userCode = json === null || json === void 0 ? void 0 : json.user_code;
12536
+ const verificationUri = json === null || json === void 0 ? void 0 : json.verification_uri;
12537
+ if (typeof deviceCode !== "string" || typeof userCode !== "string" || typeof verificationUri !== "string") {
12538
+ throw new ValLoginError("unexpected-response", "Unexpected response from the server. This version of Val may be too old for the login flow on this host — try updating @valbuild/cli.", JSON.stringify(json));
12579
12539
  }
12580
12540
  return {
12581
- nonce,
12582
- url
12541
+ deviceCode,
12542
+ userCode,
12543
+ verificationUri,
12544
+ verificationUriComplete: typeof (json === null || json === void 0 ? void 0 : json.verification_uri_complete) === "string" ? json.verification_uri_complete : verificationUri,
12545
+ expiresInSeconds: typeof (json === null || json === void 0 ? void 0 : json.expires_in) === "number" ? json.expires_in : DEFAULT_LOGIN_EXPIRES_IN_SECONDS,
12546
+ intervalSeconds: typeof (json === null || json === void 0 ? void 0 : json.interval) === "number" ? json.interval : DEFAULT_LOGIN_POLL_INTERVAL_SECONDS
12583
12547
  };
12584
12548
  }
12585
- const DEFAULT_LOGIN_MAX_DURATION = 5 * 60 * 1000; // 5 minutes
12586
- const DEFAULT_LOGIN_POLL_INTERVAL = 1000;
12549
+
12550
+ /** Fallbacks for a server that omits the optional RFC 8628 timing fields. */
12551
+ const DEFAULT_LOGIN_EXPIRES_IN_SECONDS = 600;
12552
+ const DEFAULT_LOGIN_POLL_INTERVAL_SECONDS = 5;
12587
12553
 
12588
12554
  /**
12589
- * Poll until the user confirms the login in their browser.
12555
+ * How much to add to the poll interval when the server answers `slow_down`.
12556
+ * RFC 8628 section 3.5 specifies 5 seconds.
12557
+ */
12558
+ const SLOW_DOWN_INCREMENT_SECONDS = 5;
12559
+
12560
+ /**
12561
+ * Poll until the user approves the login in their browser.
12590
12562
  *
12591
12563
  * Accepts an `AbortSignal` so an editor can cancel the flow when the user
12592
- * dismisses the prompt, instead of leaving a poll loop running for 5 minutes.
12564
+ * dismisses the prompt, instead of leaving a poll loop running to expiry.
12593
12565
  */
12594
- async function awaitValLoginConfirmation(nonce, options = {}) {
12566
+ async function awaitValLoginConfirmation(authorization, options = {}) {
12595
12567
  const host = options.host ?? defaultHost();
12596
- const maxDuration = options.maxDurationMs ?? DEFAULT_LOGIN_MAX_DURATION;
12597
- const pollInterval = options.pollIntervalMs ?? DEFAULT_LOGIN_POLL_INTERVAL;
12568
+ const maxDuration = options.maxDurationMs ?? authorization.expiresInSeconds * 1000;
12598
12569
  const now = options.now ?? (() => Date.now());
12570
+ // Mutable: `slow_down` widens it as we go, and never narrows it again.
12571
+ let intervalMs = authorization.intervalSeconds * 1000;
12599
12572
  const start = now();
12600
12573
  while (now() - start < maxDuration) {
12601
12574
  var _options$signal, _options$signal2;
12602
12575
  if ((_options$signal = options.signal) !== null && _options$signal !== void 0 && _options$signal.aborted) {
12603
12576
  throw new ValLoginError("aborted", "Login was cancelled.");
12604
12577
  }
12605
- await new Promise(resolve => setTimeout(resolve, pollInterval));
12578
+ // Wait first: the user has not had time to approve anything yet.
12579
+ await new Promise(resolve => setTimeout(resolve, intervalMs));
12606
12580
  if ((_options$signal2 = options.signal) !== null && _options$signal2 !== void 0 && _options$signal2.aborted) {
12607
12581
  throw new ValLoginError("aborted", "Login was cancelled.");
12608
12582
  }
12609
- const response = await fetch(`${host}/api/login?token=${nonce}&consume=true`, {
12610
- method: "POST"
12583
+ const response = await fetch(`${host}/api/login`, {
12584
+ method: "POST",
12585
+ headers: {
12586
+ "Content-Type": "application/json"
12587
+ },
12588
+ body: JSON.stringify({
12589
+ device_code: authorization.deviceCode
12590
+ })
12611
12591
  });
12612
12592
  if (response.status >= 500) {
12613
12593
  throw new ValLoginError("server-error", "An error occurred on the server.", `Status: ${response.status}`);
@@ -12625,6 +12605,23 @@ async function awaitValLoginConfirmation(nonce, options = {}) {
12625
12605
  }
12626
12606
  throw new ValLoginError("unexpected-response", "Unexpected response from the server.", JSON.stringify(json));
12627
12607
  }
12608
+ const json = await response.json().catch(() => null);
12609
+ const error = typeof (json === null || json === void 0 ? void 0 : json.error) === "string" ? json.error : null;
12610
+ const description = typeof (json === null || json === void 0 ? void 0 : json.error_description) === "string" ? json.error_description : undefined;
12611
+ if (error === "authorization_pending") {
12612
+ continue;
12613
+ }
12614
+ if (error === "slow_down" || response.status === 429) {
12615
+ intervalMs += SLOW_DOWN_INCREMENT_SECONDS * 1000;
12616
+ continue;
12617
+ }
12618
+ if (error === "access_denied") {
12619
+ throw new ValLoginError("access-denied", "The login was declined in the browser.", description);
12620
+ }
12621
+ if (error === "expired_token") {
12622
+ throw new ValLoginError("expired", "The login code expired before it was approved.", description);
12623
+ }
12624
+ throw new ValLoginError("unexpected-response", "Unexpected response from the server.", JSON.stringify(json));
12628
12625
  }
12629
12626
  throw new ValLoginError("timeout", "Login confirmation timed out.");
12630
12627
  }
@@ -12926,4 +12923,4 @@ function readCapturedReport(snapshotDir) {
12926
12923
  return JSON.parse(fs.readFileSync(reportPath, "utf-8"));
12927
12924
  }
12928
12925
 
12929
- export { DEFAULT_LOGIN_HOST, DEFAULT_LOGIN_MAX_DURATION, DEFAULT_LOGIN_POLL_INTERVAL, Service, ValFSHost, ValLoginError, ValModuleLoader, ValOpsFS, ValOpsHttp, ValSourceFileHandler, analyzeValModule, awaitValLoginConfirmation, checkRemoteRef, classifyJsonValuesOp, compareWithCapturedReport, createDefaultValFSHost, createFixPatch, createJsonEntryPathMap, createModulePathMap, createService, createValApiRouter, createValModuleFileInspector, createValServer, currentFixHandlers, decodeJwtWithoutVerifying, describePatchStoreProblems, downloadFileFromRemote, encodeJwt, evalValConfigFile, extractFileMetadata, extractImageMetadata, extractJsonValuesEntry, findAndEvalValConfigFile, findJsonEntryFilePath, fixHandlers, formatPatchSourceError, formatSyntaxErrorTree, getCachedRemoteFileDir, getCachedRemoteFilePath, getCompilerOptions, getExpire, getFileExt, getModulePathRange, getPersonalAccessTokenPath, getSettings, getValidationErrorFileRef, handleCheckAllFiles, handleFileMetadata, handleJsonValuesExtractEntry, handleRemoteFileCheck, handleRemoteFileDownload, handleRemoteFileUpload, handleRemoteGalleryFileUpload, handleUniqueFolderCheck, loadValModules, parsePersonalAccessTokenFile, patchSourceFile, persistPersonalAccessToken, readCapturedReport, readPatchStore, rebaseContentOp, replaySnapshot, safeReadGit, startValLogin, uploadRemoteFile, validateMetadata, verifyJwt };
12926
+ export { DEFAULT_LOGIN_EXPIRES_IN_SECONDS, DEFAULT_LOGIN_HOST, DEFAULT_LOGIN_POLL_INTERVAL_SECONDS, Service, ValFSHost, ValLoginError, ValModuleLoader, ValOpsFS, ValOpsHttp, ValSourceFileHandler, analyzeValModule, awaitValLoginConfirmation, checkRemoteRef, classifyJsonValuesOp, compareWithCapturedReport, createDefaultValFSHost, createFixPatch, createJsonEntryPathMap, createModulePathMap, createService, createValApiRouter, createValModuleFileInspector, createValServer, currentFixHandlers, decodeJwtWithoutVerifying, describePatchStoreProblems, downloadFileFromRemote, encodeJwt, evalValConfigFile, extractFileMetadata, extractImageMetadata, extractJsonValuesEntry, findAndEvalValConfigFile, findJsonEntryFilePath, fixHandlers, formatPatchSourceError, formatSyntaxErrorTree, getCachedRemoteFileDir, getCachedRemoteFilePath, getCompilerOptions, getExpire, getFileExt, getModulePathRange, getPersonalAccessTokenPath, getSettings, getValidationErrorFileRef, handleCheckAllFiles, handleFileMetadata, handleJsonValuesExtractEntry, handleRemoteFileCheck, handleRemoteFileDownload, handleRemoteFileUpload, handleRemoteGalleryFileUpload, handleUniqueFolderCheck, loadValModules, parsePersonalAccessTokenFile, patchSourceFile, persistPersonalAccessToken, readCapturedReport, readPatchStore, rebaseContentOp, replaySnapshot, safeReadGit, startValLogin, uploadRemoteFile, validateMetadata, verifyJwt };
package/package.json CHANGED
@@ -16,7 +16,7 @@
16
16
  "./package.json": "./package.json"
17
17
  },
18
18
  "types": "dist/valbuild-server.cjs.d.ts",
19
- "version": "0.113.0",
19
+ "version": "0.115.0",
20
20
  "devDependencies": {
21
21
  "@prettier/sync": "^0.6.1",
22
22
  "@types/jest": "^30.0.0"
@@ -29,9 +29,9 @@
29
29
  "typescript": "^6.0.3",
30
30
  "zod": "^4.4.3",
31
31
  "zod-validation-error": "^5.0.0",
32
- "@valbuild/shared": "0.113.0",
33
- "@valbuild/ui": "0.113.0",
34
- "@valbuild/core": "0.111.0"
32
+ "@valbuild/shared": "0.114.0",
33
+ "@valbuild/core": "0.111.0",
34
+ "@valbuild/ui": "0.114.0"
35
35
  },
36
36
  "engines": {
37
37
  "node": "^20.19.0 || >=22"