@vegastack/design 0.8.39 → 0.8.41

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.
@@ -30,6 +30,7 @@ import {
30
30
  rewriteRegistryAliases,
31
31
  stripShadcnLeadingCommentPrologue,
32
32
  } from "./verify-registry-item.mjs";
33
+ import { fetchRegistryWithRetry } from "./registry-fetch.mjs";
33
34
 
34
35
  const ITEM_NAME_SOURCE = "[a-z0-9]+(?:-[a-z0-9]+)*";
35
36
  const VERSION_SOURCE =
@@ -319,13 +320,15 @@ function assertRegistryRequest(url, headers) {
319
320
  return parsed;
320
321
  }
321
322
 
323
+ // Transient failures (network errors, a cut-off body, 5xx, 429) are retried with backoff before
324
+ // the caller reports the registry unreachable; a 404 or any other answer returns at once.
322
325
  async function fetchRegistry(url, headers) {
323
326
  assertRegistryRequest(url, headers);
324
- return fetch(url, {
325
- headers: nonEmptyHeaders(headers),
326
- redirect: "error",
327
- signal: AbortSignal.timeout(REQUEST_TIMEOUT_MS),
328
- });
327
+ return fetchRegistryWithRetry(
328
+ url,
329
+ { headers: nonEmptyHeaders(headers), redirect: "error" },
330
+ { timeoutMs: REQUEST_TIMEOUT_MS },
331
+ );
329
332
  }
330
333
 
331
334
  // Resolve { urlTemplate, headers } in precedence order: --registry > components.json > env.
@@ -0,0 +1,115 @@
1
+ // Registry fetch with retries — shared by `check-updates` and `verify-registry-item`.
2
+ //
3
+ // A CI runner's network flakes several times a day: "fetch failed" (a reset socket, a DNS blip),
4
+ // "terminated" (the body stream cut off mid-read) or a 5xx or 429 from the edge. None of those says
5
+ // anything about drift, so one of them must not fail a `check-updates --fail-on-update` run. Each
6
+ // request gets a timeout and up to `attempts` tries with jittered exponential backoff (a 429's
7
+ // `Retry-After` is honoured, capped); the body is read inside the attempt, so a stream cut off
8
+ // mid-read is retried too. Only after the last try does the caller see the failure and report the
9
+ // registry unreachable. Anything else — a 404, a 401/403, a 4xx — is an answer, returned at once,
10
+ // and integrity checks run on the body exactly as before.
11
+
12
+ /** How many tries a request gets before its failure is reported. */
13
+ export const REGISTRY_FETCH_ATTEMPTS = 3;
14
+
15
+ /** The first retry's base delay; each later one doubles it (jittered ±50%). Read per retry. */
16
+ function baseDelayMs() {
17
+ const value = Number(process.env.VEGASTACK_REGISTRY_RETRY_BASE_MS);
18
+ return Number.isFinite(value) && value >= 0 ? value : 400;
19
+ }
20
+
21
+ /** The longest a `Retry-After` is waited for. */
22
+ const MAX_RETRY_AFTER_MS = 5_000;
23
+
24
+ /** A status worth another try: the edge or the origin had a moment, not an answer. */
25
+ export function isTransientStatus(status) {
26
+ return status === 429 || status === 408 || (status >= 500 && status <= 599);
27
+ }
28
+
29
+ /** A thrown fetch or body-read error worth another try (network, reset, cut-off stream, timeout). */
30
+ export function isTransientError(error) {
31
+ if (!error) return false;
32
+ if (error.name === "AbortError" || error.name === "TimeoutError") return true;
33
+ if (error.name === "TypeError") return true; // undici: "fetch failed"
34
+ const text = `${error.message ?? ""} ${error.cause?.code ?? ""} ${error.cause?.message ?? ""}`;
35
+ return /terminated|fetch failed|socket|ECONNRESET|ECONNREFUSED|ETIMEDOUT|EAI_AGAIN|ENOTFOUND|EPIPE|UND_ERR/i.test(
36
+ text,
37
+ );
38
+ }
39
+
40
+ function sleep(ms) {
41
+ return new Promise((resolve) => setTimeout(resolve, ms));
42
+ }
43
+
44
+ /** A `Retry-After` in milliseconds — delta-seconds or an HTTP date — or undefined when absent/bad. */
45
+ export function retryAfterMs(value, now = Date.now()) {
46
+ if (value == null || value === "") return undefined;
47
+ const seconds = Number(value);
48
+ if (Number.isFinite(seconds) && seconds >= 0) return seconds * 1000;
49
+ const at = Date.parse(value);
50
+ return Number.isFinite(at) ? Math.max(0, at - now) : undefined;
51
+ }
52
+
53
+ /** How long to wait before try `attempt + 1`: the server's `Retry-After` (capped), else backoff. */
54
+ export function backoff(attempt, retryAfter) {
55
+ const asked = retryAfterMs(retryAfter);
56
+ if (asked !== undefined) return Math.min(asked, MAX_RETRY_AFTER_MS);
57
+ return baseDelayMs() * 2 ** attempt * (0.5 + Math.random());
58
+ }
59
+
60
+ /** A Response-like whose body was read as `body` (or is read once, lazily, from `response`). */
61
+ function settled(response, body) {
62
+ let pending = body === undefined ? undefined : Promise.resolve(body);
63
+ const read = () => (pending ??= response.text().catch(() => ""));
64
+ return {
65
+ ok: response.ok,
66
+ status: response.status,
67
+ statusText: response.statusText,
68
+ headers: response.headers,
69
+ text: () => read(),
70
+ json: async () => JSON.parse(await read()),
71
+ };
72
+ }
73
+
74
+ /**
75
+ * Fetch `url`, retrying transient failures. Resolves to a small Response-like object: a 2xx's body
76
+ * is already read (so a cut-off body is retried); any other answer's is read once, lazily, and
77
+ * never retried. Rejects with the last error when every try failed at the network level.
78
+ *
79
+ * @param {string | URL} url
80
+ * @param {RequestInit} init headers and redirect policy; the timeout signal is added per try
81
+ * @param {{ timeoutMs?: number, attempts?: number }} [options]
82
+ */
83
+ export async function fetchRegistryWithRetry(url, init, options = {}) {
84
+ const attempts = options.attempts ?? REGISTRY_FETCH_ATTEMPTS;
85
+ const timeoutMs = options.timeoutMs ?? 15_000;
86
+ let lastError;
87
+ for (let attempt = 0; attempt < attempts; attempt++) {
88
+ const last = attempt === attempts - 1;
89
+ try {
90
+ const response = await fetch(url, {
91
+ ...init,
92
+ signal: AbortSignal.timeout(timeoutMs),
93
+ });
94
+ if (isTransientStatus(response.status) && !last) {
95
+ // Drain so the socket is released, then try again.
96
+ await response.text?.().catch(() => {});
97
+ await sleep(backoff(attempt, response.headers?.get?.("retry-after")));
98
+ continue;
99
+ }
100
+ // A stub (or an odd runtime) may offer only `json()`: hand it back untouched, so its parse
101
+ // still happens — and its errors are still redacted — at the caller.
102
+ if (typeof response.text !== "function") return response;
103
+ // Any other non-2xx (a 404, a 401/403, the last 5xx) is an answer: returned at once, its
104
+ // body read lazily and never retried — a body cut off mid-read can't turn it into a retry.
105
+ if (!response.ok) return settled(response);
106
+ // A 2xx's body is read inside the try, so a stream cut off mid-read ("terminated") retries.
107
+ return settled(response, await response.text());
108
+ } catch (error) {
109
+ lastError = error;
110
+ if (!isTransientError(error) || last) throw error;
111
+ await sleep(backoff(attempt));
112
+ }
113
+ }
114
+ throw lastError;
115
+ }
@@ -69,6 +69,7 @@ import { pathToFileURL } from "node:url";
69
69
  import { join, resolve, basename, relative, isAbsolute, sep } from "node:path";
70
70
  import { createHash } from "node:crypto";
71
71
  import tsconfigPaths from "tsconfig-paths";
72
+ import { fetchRegistryWithRetry } from "./registry-fetch.mjs";
72
73
 
73
74
  const { loadConfig: loadTsconfigPaths } = tsconfigPaths;
74
75
 
@@ -271,11 +272,12 @@ async function fetchRegistryText(url, headers, label) {
271
272
  assertRegistryRequest(url, headers);
272
273
  let response;
273
274
  try {
274
- response = await fetch(url, {
275
- headers,
276
- redirect: "error",
277
- signal: AbortSignal.timeout(REQUEST_TIMEOUT_MS),
278
- });
275
+ // Transient failures are retried with backoff first (see registry-fetch.mjs).
276
+ response = await fetchRegistryWithRetry(
277
+ url,
278
+ { headers, redirect: "error" },
279
+ { timeoutMs: REQUEST_TIMEOUT_MS },
280
+ );
279
281
  } catch (error) {
280
282
  throw new RegistryAccessError(`${label} request failed: ${error.message}`);
281
283
  }
@@ -85,9 +85,11 @@ var prose = {
85
85
  // take the radius so a header or selected fill never pokes past the curve. Cells take
86
86
  // `break-word`, not the root's `anywhere`, so a column keeps its words whole and the table scrolls
87
87
  // in its box rather than crushing to one character per line.
88
- table: "[&_table]:w-full [&_table]:border-separate [&_table]:border-spacing-0 [&_table]:rounded-lg [&_table]:border [&_table]:border-border",
89
- tableRules: "[&_th]:border-e [&_th]:border-b [&_th]:border-border [&_td]:border-e [&_td]:border-b [&_td]:border-border [&_tr>*:last-child]:border-e-0 [&_tbody>tr:last-child>*]:border-b-0 [&_tr:first-child>*:first-child]:rounded-ss-lg [&_tr:first-child>*:last-child]:rounded-se-lg [&_tbody>tr:last-child>*:first-child]:rounded-es-lg [&_tbody>tr:last-child>*:last-child]:rounded-ee-lg",
90
- tableCells: "[&_th]:bg-muted/50 [&_th]:px-3 [&_th]:py-2 [&_th]:text-start [&_th]:align-top [&_th]:font-medium [&_td]:px-3 [&_td]:py-2 [&_td]:align-top [&_td_p]:my-0 [&_th_p]:my-0 [&_th]:wrap-break-word [&_td]:wrap-break-word",
88
+ // A table a component draws inside prose (an embedded DataGrid in a live block) is its own:
89
+ // anything under `[data-prose="off"]` is left alone by every table rule here.
90
+ table: "[&_table:not([data-prose=off]_*)]:w-full [&_table:not([data-prose=off]_*)]:border-separate [&_table:not([data-prose=off]_*)]:border-spacing-0 [&_table:not([data-prose=off]_*)]:rounded-lg [&_table:not([data-prose=off]_*)]:border [&_table:not([data-prose=off]_*)]:border-border",
91
+ tableRules: "[&_th:not([data-prose=off]_*)]:border-e [&_th:not([data-prose=off]_*)]:border-b [&_th:not([data-prose=off]_*)]:border-border [&_td:not([data-prose=off]_*)]:border-e [&_td:not([data-prose=off]_*)]:border-b [&_td:not([data-prose=off]_*)]:border-border [&_tr:not([data-prose=off]_*)>*:last-child]:border-e-0 [&_tbody:not([data-prose=off]_*)>tr:last-child>*]:border-b-0 [&_tr:not([data-prose=off]_*):first-child>*:first-child]:rounded-ss-lg [&_tr:not([data-prose=off]_*):first-child>*:last-child]:rounded-se-lg [&_tbody:not([data-prose=off]_*)>tr:last-child>*:first-child]:rounded-es-lg [&_tbody:not([data-prose=off]_*)>tr:last-child>*:last-child]:rounded-ee-lg",
92
+ tableCells: "[&_th:not([data-prose=off]_*)]:bg-muted/50 [&_th:not([data-prose=off]_*)]:px-3 [&_th:not([data-prose=off]_*)]:py-2 [&_th:not([data-prose=off]_*)]:text-start [&_th:not([data-prose=off]_*)]:align-top [&_th:not([data-prose=off]_*)]:font-medium [&_td:not([data-prose=off]_*)]:px-3 [&_td:not([data-prose=off]_*)]:py-2 [&_td:not([data-prose=off]_*)]:align-top [&_td_p:not([data-prose=off]_*)]:my-0 [&_th_p:not([data-prose=off]_*)]:my-0 [&_th:not([data-prose=off]_*)]:wrap-break-word [&_td:not([data-prose=off]_*)]:wrap-break-word",
91
93
  img: "[&_img]:my-2 [&_img]:max-w-full [&_img]:rounded-lg [&_img]:border [&_img]:border-border"
92
94
  };
93
95
  var proseClassName = Object.values(prose).join(" ");
@@ -125,9 +125,11 @@ var prose = {
125
125
  // take the radius so a header or selected fill never pokes past the curve. Cells take
126
126
  // `break-word`, not the root's `anywhere`, so a column keeps its words whole and the table scrolls
127
127
  // in its box rather than crushing to one character per line.
128
- table: "[&_table]:w-full [&_table]:border-separate [&_table]:border-spacing-0 [&_table]:rounded-lg [&_table]:border [&_table]:border-border",
129
- tableRules: "[&_th]:border-e [&_th]:border-b [&_th]:border-border [&_td]:border-e [&_td]:border-b [&_td]:border-border [&_tr>*:last-child]:border-e-0 [&_tbody>tr:last-child>*]:border-b-0 [&_tr:first-child>*:first-child]:rounded-ss-lg [&_tr:first-child>*:last-child]:rounded-se-lg [&_tbody>tr:last-child>*:first-child]:rounded-es-lg [&_tbody>tr:last-child>*:last-child]:rounded-ee-lg",
130
- tableCells: "[&_th]:bg-muted/50 [&_th]:px-3 [&_th]:py-2 [&_th]:text-start [&_th]:align-top [&_th]:font-medium [&_td]:px-3 [&_td]:py-2 [&_td]:align-top [&_td_p]:my-0 [&_th_p]:my-0 [&_th]:wrap-break-word [&_td]:wrap-break-word",
128
+ // A table a component draws inside prose (an embedded DataGrid in a live block) is its own:
129
+ // anything under `[data-prose="off"]` is left alone by every table rule here.
130
+ table: "[&_table:not([data-prose=off]_*)]:w-full [&_table:not([data-prose=off]_*)]:border-separate [&_table:not([data-prose=off]_*)]:border-spacing-0 [&_table:not([data-prose=off]_*)]:rounded-lg [&_table:not([data-prose=off]_*)]:border [&_table:not([data-prose=off]_*)]:border-border",
131
+ tableRules: "[&_th:not([data-prose=off]_*)]:border-e [&_th:not([data-prose=off]_*)]:border-b [&_th:not([data-prose=off]_*)]:border-border [&_td:not([data-prose=off]_*)]:border-e [&_td:not([data-prose=off]_*)]:border-b [&_td:not([data-prose=off]_*)]:border-border [&_tr:not([data-prose=off]_*)>*:last-child]:border-e-0 [&_tbody:not([data-prose=off]_*)>tr:last-child>*]:border-b-0 [&_tr:not([data-prose=off]_*):first-child>*:first-child]:rounded-ss-lg [&_tr:not([data-prose=off]_*):first-child>*:last-child]:rounded-se-lg [&_tbody:not([data-prose=off]_*)>tr:last-child>*:first-child]:rounded-es-lg [&_tbody:not([data-prose=off]_*)>tr:last-child>*:last-child]:rounded-ee-lg",
132
+ tableCells: "[&_th:not([data-prose=off]_*)]:bg-muted/50 [&_th:not([data-prose=off]_*)]:px-3 [&_th:not([data-prose=off]_*)]:py-2 [&_th:not([data-prose=off]_*)]:text-start [&_th:not([data-prose=off]_*)]:align-top [&_th:not([data-prose=off]_*)]:font-medium [&_td:not([data-prose=off]_*)]:px-3 [&_td:not([data-prose=off]_*)]:py-2 [&_td:not([data-prose=off]_*)]:align-top [&_td_p:not([data-prose=off]_*)]:my-0 [&_th_p:not([data-prose=off]_*)]:my-0 [&_th:not([data-prose=off]_*)]:wrap-break-word [&_td:not([data-prose=off]_*)]:wrap-break-word",
131
133
  img: "[&_img]:my-2 [&_img]:max-w-full [&_img]:rounded-lg [&_img]:border [&_img]:border-border"
132
134
  };
133
135
  var proseClassName = Object.values(prose).join(" ");
@@ -1,7 +1,7 @@
1
1
  "use client";
2
2
  import {
3
3
  cn
4
- } from "./chunk-DG7GQHEH.js";
4
+ } from "./chunk-TJIBDRBZ.js";
5
5
 
6
6
  // src/icons/create-animated-icon.tsx
7
7
  import * as React from "react";
@@ -139,9 +139,11 @@ var prose = {
139
139
  // take the radius so a header or selected fill never pokes past the curve. Cells take
140
140
  // `break-word`, not the root's `anywhere`, so a column keeps its words whole and the table scrolls
141
141
  // in its box rather than crushing to one character per line.
142
- table: "[&_table]:w-full [&_table]:border-separate [&_table]:border-spacing-0 [&_table]:rounded-lg [&_table]:border [&_table]:border-border",
143
- tableRules: "[&_th]:border-e [&_th]:border-b [&_th]:border-border [&_td]:border-e [&_td]:border-b [&_td]:border-border [&_tr>*:last-child]:border-e-0 [&_tbody>tr:last-child>*]:border-b-0 [&_tr:first-child>*:first-child]:rounded-ss-lg [&_tr:first-child>*:last-child]:rounded-se-lg [&_tbody>tr:last-child>*:first-child]:rounded-es-lg [&_tbody>tr:last-child>*:last-child]:rounded-ee-lg",
144
- tableCells: "[&_th]:bg-muted/50 [&_th]:px-3 [&_th]:py-2 [&_th]:text-start [&_th]:align-top [&_th]:font-medium [&_td]:px-3 [&_td]:py-2 [&_td]:align-top [&_td_p]:my-0 [&_th_p]:my-0 [&_th]:wrap-break-word [&_td]:wrap-break-word",
142
+ // A table a component draws inside prose (an embedded DataGrid in a live block) is its own:
143
+ // anything under `[data-prose="off"]` is left alone by every table rule here.
144
+ table: "[&_table:not([data-prose=off]_*)]:w-full [&_table:not([data-prose=off]_*)]:border-separate [&_table:not([data-prose=off]_*)]:border-spacing-0 [&_table:not([data-prose=off]_*)]:rounded-lg [&_table:not([data-prose=off]_*)]:border [&_table:not([data-prose=off]_*)]:border-border",
145
+ tableRules: "[&_th:not([data-prose=off]_*)]:border-e [&_th:not([data-prose=off]_*)]:border-b [&_th:not([data-prose=off]_*)]:border-border [&_td:not([data-prose=off]_*)]:border-e [&_td:not([data-prose=off]_*)]:border-b [&_td:not([data-prose=off]_*)]:border-border [&_tr:not([data-prose=off]_*)>*:last-child]:border-e-0 [&_tbody:not([data-prose=off]_*)>tr:last-child>*]:border-b-0 [&_tr:not([data-prose=off]_*):first-child>*:first-child]:rounded-ss-lg [&_tr:not([data-prose=off]_*):first-child>*:last-child]:rounded-se-lg [&_tbody:not([data-prose=off]_*)>tr:last-child>*:first-child]:rounded-es-lg [&_tbody:not([data-prose=off]_*)>tr:last-child>*:last-child]:rounded-ee-lg",
146
+ tableCells: "[&_th:not([data-prose=off]_*)]:bg-muted/50 [&_th:not([data-prose=off]_*)]:px-3 [&_th:not([data-prose=off]_*)]:py-2 [&_th:not([data-prose=off]_*)]:text-start [&_th:not([data-prose=off]_*)]:align-top [&_th:not([data-prose=off]_*)]:font-medium [&_td:not([data-prose=off]_*)]:px-3 [&_td:not([data-prose=off]_*)]:py-2 [&_td:not([data-prose=off]_*)]:align-top [&_td_p:not([data-prose=off]_*)]:my-0 [&_th_p:not([data-prose=off]_*)]:my-0 [&_th:not([data-prose=off]_*)]:wrap-break-word [&_td:not([data-prose=off]_*)]:wrap-break-word",
145
147
  img: "[&_img]:my-2 [&_img]:max-w-full [&_img]:rounded-lg [&_img]:border [&_img]:border-border"
146
148
  };
147
149
  var proseClassName = Object.values(prose).join(" ");
@@ -1,6 +1,6 @@
1
1
  import {
2
2
  cn
3
- } from "../chunk-DG7GQHEH.js";
3
+ } from "../chunk-TJIBDRBZ.js";
4
4
 
5
5
  // src/icons/icon.tsx
6
6
  import "react";
package/dist/index.cjs CHANGED
@@ -116,9 +116,11 @@ var prose = {
116
116
  // take the radius so a header or selected fill never pokes past the curve. Cells take
117
117
  // `break-word`, not the root's `anywhere`, so a column keeps its words whole and the table scrolls
118
118
  // in its box rather than crushing to one character per line.
119
- table: "[&_table]:w-full [&_table]:border-separate [&_table]:border-spacing-0 [&_table]:rounded-lg [&_table]:border [&_table]:border-border",
120
- tableRules: "[&_th]:border-e [&_th]:border-b [&_th]:border-border [&_td]:border-e [&_td]:border-b [&_td]:border-border [&_tr>*:last-child]:border-e-0 [&_tbody>tr:last-child>*]:border-b-0 [&_tr:first-child>*:first-child]:rounded-ss-lg [&_tr:first-child>*:last-child]:rounded-se-lg [&_tbody>tr:last-child>*:first-child]:rounded-es-lg [&_tbody>tr:last-child>*:last-child]:rounded-ee-lg",
121
- tableCells: "[&_th]:bg-muted/50 [&_th]:px-3 [&_th]:py-2 [&_th]:text-start [&_th]:align-top [&_th]:font-medium [&_td]:px-3 [&_td]:py-2 [&_td]:align-top [&_td_p]:my-0 [&_th_p]:my-0 [&_th]:wrap-break-word [&_td]:wrap-break-word",
119
+ // A table a component draws inside prose (an embedded DataGrid in a live block) is its own:
120
+ // anything under `[data-prose="off"]` is left alone by every table rule here.
121
+ table: "[&_table:not([data-prose=off]_*)]:w-full [&_table:not([data-prose=off]_*)]:border-separate [&_table:not([data-prose=off]_*)]:border-spacing-0 [&_table:not([data-prose=off]_*)]:rounded-lg [&_table:not([data-prose=off]_*)]:border [&_table:not([data-prose=off]_*)]:border-border",
122
+ tableRules: "[&_th:not([data-prose=off]_*)]:border-e [&_th:not([data-prose=off]_*)]:border-b [&_th:not([data-prose=off]_*)]:border-border [&_td:not([data-prose=off]_*)]:border-e [&_td:not([data-prose=off]_*)]:border-b [&_td:not([data-prose=off]_*)]:border-border [&_tr:not([data-prose=off]_*)>*:last-child]:border-e-0 [&_tbody:not([data-prose=off]_*)>tr:last-child>*]:border-b-0 [&_tr:not([data-prose=off]_*):first-child>*:first-child]:rounded-ss-lg [&_tr:not([data-prose=off]_*):first-child>*:last-child]:rounded-se-lg [&_tbody:not([data-prose=off]_*)>tr:last-child>*:first-child]:rounded-es-lg [&_tbody:not([data-prose=off]_*)>tr:last-child>*:last-child]:rounded-ee-lg",
123
+ tableCells: "[&_th:not([data-prose=off]_*)]:bg-muted/50 [&_th:not([data-prose=off]_*)]:px-3 [&_th:not([data-prose=off]_*)]:py-2 [&_th:not([data-prose=off]_*)]:text-start [&_th:not([data-prose=off]_*)]:align-top [&_th:not([data-prose=off]_*)]:font-medium [&_td:not([data-prose=off]_*)]:px-3 [&_td:not([data-prose=off]_*)]:py-2 [&_td:not([data-prose=off]_*)]:align-top [&_td_p:not([data-prose=off]_*)]:my-0 [&_th_p:not([data-prose=off]_*)]:my-0 [&_th:not([data-prose=off]_*)]:wrap-break-word [&_td:not([data-prose=off]_*)]:wrap-break-word",
122
124
  img: "[&_img]:my-2 [&_img]:max-w-full [&_img]:rounded-lg [&_img]:border [&_img]:border-border"
123
125
  };
124
126
  var proseClassName = Object.values(prose).join(" ");
package/dist/index.d.cts CHANGED
@@ -81,9 +81,9 @@ declare const prose: {
81
81
  readonly pre: "[&_pre:not([data-slot='code-block-pre'])]:my-2 [&_pre:not([data-slot='code-block-pre'])]:overflow-x-auto [&_pre:not([data-slot='code-block-pre'])]:rounded-lg [&_pre:not([data-slot='code-block-pre'])]:border [&_pre:not([data-slot='code-block-pre'])]:border-border [&_pre:not([data-slot='code-block-pre'])]:bg-muted [&_pre:not([data-slot='code-block-pre'])]:p-4 [&_pre:not([data-slot='code-block-pre'])]:text-foreground";
82
82
  readonly preCode: "[&_pre_code]:bg-transparent [&_pre_code]:p-0 [&_pre_code]:font-mono [&_pre_code]:text-sm [&_pre_code]:text-foreground";
83
83
  readonly hr: "[&_hr]:my-4 [&_hr]:border-border";
84
- readonly table: "[&_table]:w-full [&_table]:border-separate [&_table]:border-spacing-0 [&_table]:rounded-lg [&_table]:border [&_table]:border-border";
85
- readonly tableRules: "[&_th]:border-e [&_th]:border-b [&_th]:border-border [&_td]:border-e [&_td]:border-b [&_td]:border-border [&_tr>*:last-child]:border-e-0 [&_tbody>tr:last-child>*]:border-b-0 [&_tr:first-child>*:first-child]:rounded-ss-lg [&_tr:first-child>*:last-child]:rounded-se-lg [&_tbody>tr:last-child>*:first-child]:rounded-es-lg [&_tbody>tr:last-child>*:last-child]:rounded-ee-lg";
86
- readonly tableCells: "[&_th]:bg-muted/50 [&_th]:px-3 [&_th]:py-2 [&_th]:text-start [&_th]:align-top [&_th]:font-medium [&_td]:px-3 [&_td]:py-2 [&_td]:align-top [&_td_p]:my-0 [&_th_p]:my-0 [&_th]:wrap-break-word [&_td]:wrap-break-word";
84
+ readonly table: "[&_table:not([data-prose=off]_*)]:w-full [&_table:not([data-prose=off]_*)]:border-separate [&_table:not([data-prose=off]_*)]:border-spacing-0 [&_table:not([data-prose=off]_*)]:rounded-lg [&_table:not([data-prose=off]_*)]:border [&_table:not([data-prose=off]_*)]:border-border";
85
+ readonly tableRules: "[&_th:not([data-prose=off]_*)]:border-e [&_th:not([data-prose=off]_*)]:border-b [&_th:not([data-prose=off]_*)]:border-border [&_td:not([data-prose=off]_*)]:border-e [&_td:not([data-prose=off]_*)]:border-b [&_td:not([data-prose=off]_*)]:border-border [&_tr:not([data-prose=off]_*)>*:last-child]:border-e-0 [&_tbody:not([data-prose=off]_*)>tr:last-child>*]:border-b-0 [&_tr:not([data-prose=off]_*):first-child>*:first-child]:rounded-ss-lg [&_tr:not([data-prose=off]_*):first-child>*:last-child]:rounded-se-lg [&_tbody:not([data-prose=off]_*)>tr:last-child>*:first-child]:rounded-es-lg [&_tbody:not([data-prose=off]_*)>tr:last-child>*:last-child]:rounded-ee-lg";
86
+ readonly tableCells: "[&_th:not([data-prose=off]_*)]:bg-muted/50 [&_th:not([data-prose=off]_*)]:px-3 [&_th:not([data-prose=off]_*)]:py-2 [&_th:not([data-prose=off]_*)]:text-start [&_th:not([data-prose=off]_*)]:align-top [&_th:not([data-prose=off]_*)]:font-medium [&_td:not([data-prose=off]_*)]:px-3 [&_td:not([data-prose=off]_*)]:py-2 [&_td:not([data-prose=off]_*)]:align-top [&_td_p:not([data-prose=off]_*)]:my-0 [&_th_p:not([data-prose=off]_*)]:my-0 [&_th:not([data-prose=off]_*)]:wrap-break-word [&_td:not([data-prose=off]_*)]:wrap-break-word";
87
87
  readonly img: "[&_img]:my-2 [&_img]:max-w-full [&_img]:rounded-lg [&_img]:border [&_img]:border-border";
88
88
  };
89
89
  /** The element roles the prose recipe covers. */
package/dist/index.d.ts CHANGED
@@ -81,9 +81,9 @@ declare const prose: {
81
81
  readonly pre: "[&_pre:not([data-slot='code-block-pre'])]:my-2 [&_pre:not([data-slot='code-block-pre'])]:overflow-x-auto [&_pre:not([data-slot='code-block-pre'])]:rounded-lg [&_pre:not([data-slot='code-block-pre'])]:border [&_pre:not([data-slot='code-block-pre'])]:border-border [&_pre:not([data-slot='code-block-pre'])]:bg-muted [&_pre:not([data-slot='code-block-pre'])]:p-4 [&_pre:not([data-slot='code-block-pre'])]:text-foreground";
82
82
  readonly preCode: "[&_pre_code]:bg-transparent [&_pre_code]:p-0 [&_pre_code]:font-mono [&_pre_code]:text-sm [&_pre_code]:text-foreground";
83
83
  readonly hr: "[&_hr]:my-4 [&_hr]:border-border";
84
- readonly table: "[&_table]:w-full [&_table]:border-separate [&_table]:border-spacing-0 [&_table]:rounded-lg [&_table]:border [&_table]:border-border";
85
- readonly tableRules: "[&_th]:border-e [&_th]:border-b [&_th]:border-border [&_td]:border-e [&_td]:border-b [&_td]:border-border [&_tr>*:last-child]:border-e-0 [&_tbody>tr:last-child>*]:border-b-0 [&_tr:first-child>*:first-child]:rounded-ss-lg [&_tr:first-child>*:last-child]:rounded-se-lg [&_tbody>tr:last-child>*:first-child]:rounded-es-lg [&_tbody>tr:last-child>*:last-child]:rounded-ee-lg";
86
- readonly tableCells: "[&_th]:bg-muted/50 [&_th]:px-3 [&_th]:py-2 [&_th]:text-start [&_th]:align-top [&_th]:font-medium [&_td]:px-3 [&_td]:py-2 [&_td]:align-top [&_td_p]:my-0 [&_th_p]:my-0 [&_th]:wrap-break-word [&_td]:wrap-break-word";
84
+ readonly table: "[&_table:not([data-prose=off]_*)]:w-full [&_table:not([data-prose=off]_*)]:border-separate [&_table:not([data-prose=off]_*)]:border-spacing-0 [&_table:not([data-prose=off]_*)]:rounded-lg [&_table:not([data-prose=off]_*)]:border [&_table:not([data-prose=off]_*)]:border-border";
85
+ readonly tableRules: "[&_th:not([data-prose=off]_*)]:border-e [&_th:not([data-prose=off]_*)]:border-b [&_th:not([data-prose=off]_*)]:border-border [&_td:not([data-prose=off]_*)]:border-e [&_td:not([data-prose=off]_*)]:border-b [&_td:not([data-prose=off]_*)]:border-border [&_tr:not([data-prose=off]_*)>*:last-child]:border-e-0 [&_tbody:not([data-prose=off]_*)>tr:last-child>*]:border-b-0 [&_tr:not([data-prose=off]_*):first-child>*:first-child]:rounded-ss-lg [&_tr:not([data-prose=off]_*):first-child>*:last-child]:rounded-se-lg [&_tbody:not([data-prose=off]_*)>tr:last-child>*:first-child]:rounded-es-lg [&_tbody:not([data-prose=off]_*)>tr:last-child>*:last-child]:rounded-ee-lg";
86
+ readonly tableCells: "[&_th:not([data-prose=off]_*)]:bg-muted/50 [&_th:not([data-prose=off]_*)]:px-3 [&_th:not([data-prose=off]_*)]:py-2 [&_th:not([data-prose=off]_*)]:text-start [&_th:not([data-prose=off]_*)]:align-top [&_th:not([data-prose=off]_*)]:font-medium [&_td:not([data-prose=off]_*)]:px-3 [&_td:not([data-prose=off]_*)]:py-2 [&_td:not([data-prose=off]_*)]:align-top [&_td_p:not([data-prose=off]_*)]:my-0 [&_th_p:not([data-prose=off]_*)]:my-0 [&_th:not([data-prose=off]_*)]:wrap-break-word [&_td:not([data-prose=off]_*)]:wrap-break-word";
87
87
  readonly img: "[&_img]:my-2 [&_img]:max-w-full [&_img]:rounded-lg [&_img]:border [&_img]:border-border";
88
88
  };
89
89
  /** The element roles the prose recipe covers. */
package/dist/index.js CHANGED
@@ -7,7 +7,7 @@ import {
7
7
  proseClassName,
8
8
  proseDocument,
9
9
  proseDocumentClassName
10
- } from "./chunk-DG7GQHEH.js";
10
+ } from "./chunk-TJIBDRBZ.js";
11
11
  export {
12
12
  FLOATING,
13
13
  TIMINGS,
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@vegastack/design",
3
- "version": "0.8.39",
3
+ "version": "0.8.41",
4
4
  "description": "VegaStack design system — cn utility, icon runtime, Tailwind v4 preset, and the vegastack-design CLI (tokens ship separately as @vegastack/design-tokens)",
5
5
  "license": "MIT",
6
6
  "repository": {
@@ -67,7 +67,7 @@
67
67
  "lint": "eslint . && node ../../tooling/design-lint.mjs src && pnpm run verify",
68
68
  "verify": "node ../../tooling/verify-preset-source.mjs",
69
69
  "typecheck": "tsc --noEmit",
70
- "test": "node test/compare.test.mjs && node test/check-updates.test.mjs && node test/skills-install.test.mjs && node test/doctor.test.mjs && node --test test/merge-refs.test.mjs test/registry-credentials.test.mjs"
70
+ "test": "node test/compare.test.mjs && node test/check-updates.test.mjs && node test/skills-install.test.mjs && node test/doctor.test.mjs && node --test test/merge-refs.test.mjs test/registry-credentials.test.mjs test/registry-fetch.test.mjs"
71
71
  },
72
72
  "dependencies": {
73
73
  "@vegastack/design-tokens": "^0.8.38",