tempest-react-sdk 0.79.0 → 0.81.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 (131) hide show
  1. package/README.md +35 -4
  2. package/bin/lib/component/generate.test.mjs +13 -1
  3. package/bin/lib/openapi/generate.hostile.test.mjs +58 -5
  4. package/bin/lib/openapi/generate.mjs +145 -34
  5. package/bin/lib/openapi/generate.test.mjs +216 -5
  6. package/bin/lib/openapi/schema-to-zod.mjs +4 -3
  7. package/dist/auth/create-tempest-auth.cjs +1 -1
  8. package/dist/auth/create-tempest-auth.cjs.map +1 -1
  9. package/dist/auth/create-tempest-auth.js +172 -103
  10. package/dist/auth/create-tempest-auth.js.map +1 -1
  11. package/dist/br/boleto.cjs +1 -1
  12. package/dist/br/boleto.cjs.map +1 -1
  13. package/dist/br/boleto.js +2 -1
  14. package/dist/br/boleto.js.map +1 -1
  15. package/dist/br.d.ts +22 -3
  16. package/dist/components/AuthForm/AuthFieldControl.cjs +2 -0
  17. package/dist/components/AuthForm/AuthFieldControl.cjs.map +1 -0
  18. package/dist/components/AuthForm/AuthFieldControl.js +85 -0
  19. package/dist/components/AuthForm/AuthFieldControl.js.map +1 -0
  20. package/dist/components/AuthForm/AuthForm.cjs +2 -0
  21. package/dist/components/AuthForm/AuthForm.cjs.map +1 -0
  22. package/dist/components/AuthForm/AuthForm.js +83 -0
  23. package/dist/components/AuthForm/AuthForm.js.map +1 -0
  24. package/dist/components/AuthForm/AuthForm.module.cjs +3 -0
  25. package/dist/components/AuthForm/AuthForm.module.cjs.map +1 -0
  26. package/dist/components/AuthForm/AuthForm.module.js +14 -0
  27. package/dist/components/AuthForm/AuthForm.module.js.map +1 -0
  28. package/dist/components/AuthForm/AuthLinks.cjs +2 -0
  29. package/dist/components/AuthForm/AuthLinks.cjs.map +1 -0
  30. package/dist/components/AuthForm/AuthLinks.js +29 -0
  31. package/dist/components/AuthForm/AuthLinks.js.map +1 -0
  32. package/dist/components/AuthForm/ForgotPasswordForm.cjs +2 -0
  33. package/dist/components/AuthForm/ForgotPasswordForm.cjs.map +1 -0
  34. package/dist/components/AuthForm/ForgotPasswordForm.js +32 -0
  35. package/dist/components/AuthForm/ForgotPasswordForm.js.map +1 -0
  36. package/dist/components/AuthForm/LoginForm.cjs +2 -0
  37. package/dist/components/AuthForm/LoginForm.cjs.map +1 -0
  38. package/dist/components/AuthForm/LoginForm.js +39 -0
  39. package/dist/components/AuthForm/LoginForm.js.map +1 -0
  40. package/dist/components/AuthForm/ResetPasswordForm.cjs +2 -0
  41. package/dist/components/AuthForm/ResetPasswordForm.cjs.map +1 -0
  42. package/dist/components/AuthForm/ResetPasswordForm.js +39 -0
  43. package/dist/components/AuthForm/ResetPasswordForm.js.map +1 -0
  44. package/dist/components/AuthForm/SignUpForm.cjs +2 -0
  45. package/dist/components/AuthForm/SignUpForm.cjs.map +1 -0
  46. package/dist/components/AuthForm/SignUpForm.js +32 -0
  47. package/dist/components/AuthForm/SignUpForm.js.map +1 -0
  48. package/dist/components/AuthForm/auth-defaults.cjs +2 -0
  49. package/dist/components/AuthForm/auth-defaults.cjs.map +1 -0
  50. package/dist/components/AuthForm/auth-defaults.js +54 -0
  51. package/dist/components/AuthForm/auth-defaults.js.map +1 -0
  52. package/dist/components/AuthForm/auth-schemas.cjs +2 -0
  53. package/dist/components/AuthForm/auth-schemas.cjs.map +1 -0
  54. package/dist/components/AuthForm/auth-schemas.js +26 -0
  55. package/dist/components/AuthForm/auth-schemas.js.map +1 -0
  56. package/dist/components/AuthPage/AuthPage.cjs +2 -0
  57. package/dist/components/AuthPage/AuthPage.cjs.map +1 -0
  58. package/dist/components/AuthPage/AuthPage.js +91 -0
  59. package/dist/components/AuthPage/AuthPage.js.map +1 -0
  60. package/dist/components/AuthPage/AuthPage.module.cjs +3 -0
  61. package/dist/components/AuthPage/AuthPage.module.cjs.map +1 -0
  62. package/dist/components/AuthPage/AuthPage.module.js +24 -0
  63. package/dist/components/AuthPage/AuthPage.module.js.map +1 -0
  64. package/dist/components/FilterBar/filter-apply.cjs +1 -1
  65. package/dist/components/FilterBar/filter-apply.cjs.map +1 -1
  66. package/dist/components/FilterBar/filter-apply.js +7 -7
  67. package/dist/forms/index.js +7 -7
  68. package/dist/forms/masked-inputs.cjs +1 -1
  69. package/dist/forms/masked-inputs.cjs.map +1 -1
  70. package/dist/forms/masked-inputs.js +15 -15
  71. package/dist/http/api-client.cjs +1 -1
  72. package/dist/http/api-client.cjs.map +1 -1
  73. package/dist/http/api-client.js +104 -97
  74. package/dist/http/api-client.js.map +1 -1
  75. package/dist/http/build-url.cjs +1 -1
  76. package/dist/http/build-url.cjs.map +1 -1
  77. package/dist/http/build-url.js +3 -1
  78. package/dist/http/build-url.js.map +1 -1
  79. package/dist/http/presigned-post.cjs +2 -0
  80. package/dist/http/presigned-post.cjs.map +1 -0
  81. package/dist/http/presigned-post.js +73 -0
  82. package/dist/http/presigned-post.js.map +1 -0
  83. package/dist/http/resumable-upload.cjs +1 -1
  84. package/dist/http/resumable-upload.cjs.map +1 -1
  85. package/dist/http/resumable-upload.js +97 -97
  86. package/dist/http/resumable-upload.js.map +1 -1
  87. package/dist/http/upload-with-progress.cjs +1 -1
  88. package/dist/http/upload-with-progress.cjs.map +1 -1
  89. package/dist/http/upload-with-progress.js +12 -12
  90. package/dist/http/use-describe-api-error.cjs +1 -1
  91. package/dist/http/use-describe-api-error.cjs.map +1 -1
  92. package/dist/http/use-describe-api-error.js +9 -9
  93. package/dist/offline/create-offline-sync.cjs +1 -1
  94. package/dist/offline/create-offline-sync.cjs.map +1 -1
  95. package/dist/offline/create-offline-sync.js +78 -56
  96. package/dist/offline/create-offline-sync.js.map +1 -1
  97. package/dist/sse/create-event-stream.cjs +1 -1
  98. package/dist/sse/create-event-stream.cjs.map +1 -1
  99. package/dist/sse/create-event-stream.js +44 -30
  100. package/dist/sse/create-event-stream.js.map +1 -1
  101. package/dist/sse/ticket-event-stream.cjs +2 -0
  102. package/dist/sse/ticket-event-stream.cjs.map +1 -0
  103. package/dist/sse/ticket-event-stream.js +41 -0
  104. package/dist/sse/ticket-event-stream.js.map +1 -0
  105. package/dist/sse/use-event-stream.cjs +1 -1
  106. package/dist/sse/use-event-stream.cjs.map +1 -1
  107. package/dist/sse/use-event-stream.js +7 -4
  108. package/dist/sse/use-event-stream.js.map +1 -1
  109. package/dist/styles/AuthForm.css +2 -0
  110. package/dist/styles/AuthPage.css +2 -0
  111. package/dist/styles/component/AuthForm.css +9 -0
  112. package/dist/styles/component/AuthPage.css +29 -0
  113. package/dist/styles/forms.css +36 -0
  114. package/dist/styles/manifest.json +63 -0
  115. package/dist/styles.css +1 -1
  116. package/dist/sw/background-sync.cjs +1 -1
  117. package/dist/sw/background-sync.cjs.map +1 -1
  118. package/dist/sw/background-sync.js +124 -106
  119. package/dist/sw/background-sync.js.map +1 -1
  120. package/dist/sw.d.ts +49 -15
  121. package/dist/tempest-react-sdk.cjs +1 -1
  122. package/dist/tempest-react-sdk.d.ts +809 -22
  123. package/dist/tempest-react-sdk.js +373 -363
  124. package/dist/utils/format.cjs +1 -1
  125. package/dist/utils/format.cjs.map +1 -1
  126. package/dist/utils/format.js +25 -25
  127. package/dist/utils/numbers.cjs +1 -1
  128. package/dist/utils/numbers.cjs.map +1 -1
  129. package/dist/utils/numbers.js +7 -7
  130. package/package.json +1 -1
  131. package/template-pwa/src/sw.ts +10 -6
@@ -1,2 +1,2 @@
1
- const e=require("./absent.cjs"),t=require("./intl-cache.cjs");function n(n,r){return e.isAbsent(n)||!Number.isFinite(n)?e.fallbackText(r):t.numberFormat(`pt-BR`,{style:`currency`,currency:`BRL`}).format(n)}function r(n,r){if(e.isAbsent(n))return e.fallbackText(r);let i=typeof n==`string`?new Date(n):n;return Number.isNaN(i.getTime())?``:t.dateTimeFormat(`pt-BR`).format(i)}function i(t,n){if(e.isAbsent(t))return e.fallbackText(n,``);if(typeof t==`string`&&/^\d{4}-\d{2}-\d{2}$/.test(t))return t;let r=typeof t==`string`?new Date(t):t;if(Number.isNaN(r.getTime()))return``;let i=`${r.getMonth()+1}`.padStart(2,`0`),a=`${r.getDate()}`.padStart(2,`0`);return`${r.getFullYear()}-${i}-${a}`}function a(t,n){if(e.isAbsent(t))return e.fallbackText(n,``);if(typeof t==`string`&&/^\d{4}-\d{2}-\d{2}T\d{2}:\d{2}$/.test(t))return t;let r=typeof t==`string`?new Date(t):t;if(Number.isNaN(r.getTime()))return``;let i=`${r.getMonth()+1}`.padStart(2,`0`),a=`${r.getDate()}`.padStart(2,`0`),o=`${r.getHours()}`.padStart(2,`0`),s=`${r.getMinutes()}`.padStart(2,`0`);return`${r.getFullYear()}-${i}-${a}T${o}:${s}`}function o(n,r){if(e.isAbsent(n))return e.fallbackText(r);let i=typeof n==`string`?new Date(n):n;return Number.isNaN(i.getTime())?``:t.dateTimeFormat(`pt-BR`,{dateStyle:`short`,timeStyle:`short`}).format(i)}function s(e,t={}){let n=e.replace(/\D/g,``).slice(0,11);if(!t.mobile)return n.length<=10?n.replace(/(\d{2})(\d)/,`($1) $2`).replace(/(\d{4})(\d)/,`$1-$2`):n.replace(/(\d{2})(\d)/,`($1) $2`).replace(/(\d{5})(\d)/,`$1-$2`);if(n.length<=2)return n;let r=n.slice(0,2),i=n.slice(2);i[0]!==`9`&&(i=`9${i}`),i=i.slice(0,9);let a=i.slice(0,5),o=i.slice(5);return o?`(${r}) ${a}-${o}`:`(${r}) ${a}`}function c(e){return e.replace(/\D/g,``).slice(0,11).replace(/(\d{3})(\d)/,`$1.$2`).replace(/(\d{3})(\d)/,`$1.$2`).replace(/(\d{3})(\d{1,2})$/,`$1-$2`)}function l(n,r={}){if(e.isAbsent(n)||!Number.isFinite(n))return e.fallbackText(r);let i=r.decimals??1;return t.numberFormat(`pt-BR`,{style:`percent`,minimumFractionDigits:i,maximumFractionDigits:i}).format(n)}exports.formatCPF=c,exports.formatCurrency=n,exports.formatDate=r,exports.formatDateForInput=i,exports.formatDateTime=o,exports.formatDateTimeForInput=a,exports.formatPercent=l,exports.formatPhone=s;
1
+ const e=require("./intl-cache.cjs"),t=require("./absent.cjs");function n(n,r){return t.isAbsent(n)||!Number.isFinite(n)?t.fallbackText(r):e.numberFormat(`pt-BR`,{style:`currency`,currency:`BRL`}).format(n)}function r(n,r){if(t.isAbsent(n))return t.fallbackText(r);let i=typeof n==`string`?new Date(n):n;return Number.isNaN(i.getTime())?``:e.dateTimeFormat(`pt-BR`).format(i)}function i(e,n){if(t.isAbsent(e))return t.fallbackText(n,``);if(typeof e==`string`&&/^\d{4}-\d{2}-\d{2}$/.test(e))return e;let r=typeof e==`string`?new Date(e):e;if(Number.isNaN(r.getTime()))return``;let i=`${r.getMonth()+1}`.padStart(2,`0`),a=`${r.getDate()}`.padStart(2,`0`);return`${r.getFullYear()}-${i}-${a}`}function a(e,n){if(t.isAbsent(e))return t.fallbackText(n,``);if(typeof e==`string`&&/^\d{4}-\d{2}-\d{2}T\d{2}:\d{2}$/.test(e))return e;let r=typeof e==`string`?new Date(e):e;if(Number.isNaN(r.getTime()))return``;let i=`${r.getMonth()+1}`.padStart(2,`0`),a=`${r.getDate()}`.padStart(2,`0`),o=`${r.getHours()}`.padStart(2,`0`),s=`${r.getMinutes()}`.padStart(2,`0`);return`${r.getFullYear()}-${i}-${a}T${o}:${s}`}function o(n,r){if(t.isAbsent(n))return t.fallbackText(r);let i=typeof n==`string`?new Date(n):n;return Number.isNaN(i.getTime())?``:e.dateTimeFormat(`pt-BR`,{dateStyle:`short`,timeStyle:`short`}).format(i)}function s(e,t={}){let n=e.replace(/\D/g,``).slice(0,11);if(!t.mobile)return n.length<=10?n.replace(/(\d{2})(\d)/,`($1) $2`).replace(/(\d{4})(\d)/,`$1-$2`):n.replace(/(\d{2})(\d)/,`($1) $2`).replace(/(\d{5})(\d)/,`$1-$2`);if(n.length<=2)return n;let r=n.slice(0,2),i=n.slice(2);i[0]!==`9`&&(i=`9${i}`),i=i.slice(0,9);let a=i.slice(0,5),o=i.slice(5);return o?`(${r}) ${a}-${o}`:`(${r}) ${a}`}function c(e){return e.replace(/\D/g,``).slice(0,11).replace(/(\d{3})(\d)/,`$1.$2`).replace(/(\d{3})(\d)/,`$1.$2`).replace(/(\d{3})(\d{1,2})$/,`$1-$2`)}function l(n,r={}){if(t.isAbsent(n)||!Number.isFinite(n))return t.fallbackText(r);let i=r.decimals??1;return e.numberFormat(`pt-BR`,{style:`percent`,minimumFractionDigits:i,maximumFractionDigits:i}).format(n)}exports.formatCPF=c,exports.formatCurrency=n,exports.formatDate=r,exports.formatDateForInput=i,exports.formatDateTime=o,exports.formatDateTimeForInput=a,exports.formatPercent=l,exports.formatPhone=s;
2
2
  //# sourceMappingURL=format.cjs.map
@@ -1 +1 @@
1
- {"version":3,"file":"format.cjs","names":["isAbsent","fallbackText","numberFormat","dateTimeFormat","require_absent","require_intl_cache","formatCurrency","value","options","formatDate","date","formatDateForInput","month","day","formatDateTimeForInput","hours","minutes","formatDateTime","formatPhone","digits","area","subscriber","prefix","suffix","formatCPF","formatPercent","decimals"],"sources":["../../src/utils/format.ts"],"sourcesContent":["import { fallbackText, isAbsent, type FormatFallbackOptions } from \"@/utils/absent\";\nimport { dateTimeFormat, numberFormat } from \"@/utils/intl-cache\";\n\n/**\n * Format a number as Brazilian Real currency.\n *\n * An absent or unrepresentable amount renders as `\"—\"` rather than as a number.\n * That branch is a data-correctness fix, not cosmetics: `Intl` coerces `null` to\n * zero, so an amount the backend left out used to reach the screen as\n * **`\"R$ 0,00\"`** — a plausible figure a reader has no way to question — and\n * `undefined` as `\"R$ NaN\"`.\n *\n * @example\n * ```typescript\n * formatCurrency(1234.56); // \"R$ 1.234,56\"\n * formatCurrency(null); // \"—\"\n * formatCurrency(null, { fallback: \"sem valor\" }); // \"sem valor\"\n * ```\n *\n * @param value - The amount in BRL, or `null`/`undefined` when there is none.\n * @param options - Text to render when there is nothing to format.\n * @returns A locale-formatted string, e.g. \"R$ 1.234,56\".\n */\nexport function formatCurrency(\n value: number | null | undefined,\n options?: FormatFallbackOptions,\n): string {\n if (isAbsent(value) || !Number.isFinite(value)) return fallbackText(options);\n return numberFormat(\"pt-BR\", { style: \"currency\", currency: \"BRL\" }).format(value);\n}\n\n/**\n * Format an ISO date or Date instance as `dd/MM/yyyy`.\n *\n * Absent input answers `\"—\"`. It used to **throw**: `new Date(null)` is epoch and\n * `null.getTime` is a `TypeError`, so a nullable column — which is every\n * `deleted_at`, `expires_at` and half the `updated_at` a FastAPI backend sends —\n * took the screen down instead of rendering a gap.\n *\n * A value that is present and unparseable still answers `\"\"`, deliberately: on a\n * screen that reads a log, \"nobody filled this in\" and \"what they filled in is\n * broken\" are different findings, and the second is the one worth chasing.\n *\n * @example\n * ```typescript\n * formatDate(\"2026-05-16T12:00:00Z\"); // \"16/05/2026\"\n * formatDate(null); // \"—\"\n * formatDate(\"banana\"); // \"\"\n * ```\n *\n * @param value - ISO string, Date, or `null`/`undefined`.\n * @param options - Text to render when the value is absent.\n * @returns Formatted date string, the fallback when absent, or empty string when\n * the value is present and invalid.\n */\nexport function formatDate(\n value: string | Date | null | undefined,\n options?: FormatFallbackOptions,\n): string {\n if (isAbsent(value)) return fallbackText(options);\n const date = typeof value === \"string\" ? new Date(value) : value;\n if (Number.isNaN(date.getTime())) return \"\";\n return dateTimeFormat(\"pt-BR\").format(date);\n}\n\n/**\n * Format an ISO date or Date instance as `yyyy-MM-dd`, the value an\n * `<input type=\"date\">` accepts.\n *\n * Built from the **local** calendar parts rather than `toISOString().slice(0, 10)`,\n * which is the reflex and which is wrong: `toISOString` converts to UTC first, so\n * anything after 21:00 in UTC-3 reports the next day and the form opens on the\n * wrong date. `formatDate` cannot fill this role because a date input rejects\n * `dd/MM/yyyy` outright.\n *\n * A value that is already `yyyy-MM-dd` is returned untouched, and that shortcut\n * is load-bearing rather than an optimisation: `new Date(\"2026-05-16\")` is parsed\n * as **UTC** midnight, which in UTC-3 is the 15th at 21:00, so round-tripping the\n * exact value a backend sent would move it back a day.\n *\n * @example\n * <input type=\"date\" defaultValue={formatDateForInput(order.createdAt)} />\n *\n * Absent input answers `\"\"` here — **not** the em dash the reading formatters\n * use — because that is what an input reads as \"no value\"; an em dash would\n * arrive as content the user has to delete before typing a date.\n *\n * @param value - ISO string, Date, or `null`/`undefined`.\n * @param options - Text for an absent value; defaults to `\"\"`.\n * @returns The `yyyy-MM-dd` value, or an empty string when the input is invalid —\n * which is what a date input reads as \"no value\", unlike `\"Invalid Date\"`.\n */\nexport function formatDateForInput(\n value: string | Date | null | undefined,\n options?: FormatFallbackOptions,\n): string {\n if (isAbsent(value)) return fallbackText(options, \"\");\n if (typeof value === \"string\" && /^\\d{4}-\\d{2}-\\d{2}$/.test(value)) return value;\n const date = typeof value === \"string\" ? new Date(value) : value;\n if (Number.isNaN(date.getTime())) return \"\";\n const month = `${date.getMonth() + 1}`.padStart(2, \"0\");\n const day = `${date.getDate()}`.padStart(2, \"0\");\n return `${date.getFullYear()}-${month}-${day}`;\n}\n\n/**\n * Format an ISO date or Date instance as `yyyy-MM-ddTHH:mm`, the value an\n * `<input type=\"datetime-local\">` accepts.\n *\n * The sibling of {@link formatDateForInput}, and it exists for the same reason:\n * `toISOString().slice(0, 16)` is the reflex and it is wrong. `toISOString`\n * converts to UTC first, so a 22:00 appointment in UTC-3 opens the form on the\n * next day at 01:00 — here the trap costs the hour as well as the date.\n *\n * A value already in `yyyy-MM-ddTHH:mm` is returned untouched. A value carrying\n * a zone (`...Z`, `...-03:00`) deliberately does **not** take that shortcut: it\n * is a different instant from the naive string that looks like it, so it is\n * converted to the local calendar parts the input has to show.\n *\n * Seconds are dropped. A `datetime-local` steps by the minute unless the app\n * sets `step`, so a `:ss` the field cannot represent would be silently discarded\n * on the first edit anyway — truncating here keeps the rendered value and the\n * submitted value the same.\n *\n * @example\n * <input\n * type=\"datetime-local\"\n * defaultValue={formatDateTimeForInput(appointment.startsAt)}\n * />\n *\n * @param value - ISO string or Date.\n * @returns The `yyyy-MM-ddTHH:mm` value, or an empty string when the input is\n * invalid — which is what a datetime input reads as \"no value\", unlike\n * `\"Invalid Date\"`.\n */\nexport function formatDateTimeForInput(\n value: string | Date | null | undefined,\n options?: FormatFallbackOptions,\n): string {\n if (isAbsent(value)) return fallbackText(options, \"\");\n if (typeof value === \"string\" && /^\\d{4}-\\d{2}-\\d{2}T\\d{2}:\\d{2}$/.test(value)) return value;\n const date = typeof value === \"string\" ? new Date(value) : value;\n if (Number.isNaN(date.getTime())) return \"\";\n const month = `${date.getMonth() + 1}`.padStart(2, \"0\");\n const day = `${date.getDate()}`.padStart(2, \"0\");\n const hours = `${date.getHours()}`.padStart(2, \"0\");\n const minutes = `${date.getMinutes()}`.padStart(2, \"0\");\n return `${date.getFullYear()}-${month}-${day}T${hours}:${minutes}`;\n}\n\n/**\n * Format an ISO date or Date instance as `dd/MM/yyyy HH:mm`.\n *\n * Same contract as {@link formatDate}: absent answers the fallback (`\"—\"` by\n * default) instead of throwing, and present-but-invalid answers `\"\"`.\n *\n * @param value - ISO string, Date, or `null`/`undefined`.\n * @param options - Text to render when the value is absent.\n * @returns Formatted datetime string, the fallback when absent, or empty string\n * when the value is present and invalid.\n */\nexport function formatDateTime(\n value: string | Date | null | undefined,\n options?: FormatFallbackOptions,\n): string {\n if (isAbsent(value)) return fallbackText(options);\n const date = typeof value === \"string\" ? new Date(value) : value;\n if (Number.isNaN(date.getTime())) return \"\";\n return dateTimeFormat(\"pt-BR\", { dateStyle: \"short\", timeStyle: \"short\" }).format(date);\n}\n\nexport interface FormatPhoneOptions {\n /**\n * Treat the number as a mobile line: insert the mandatory `9` after the area\n * code when it is missing, and group the subscriber part `5+4` from the\n * first digit typed instead of waiting for the eleventh.\n *\n * Default `false`, which keeps the length-based behaviour: `4+4` up to ten\n * digits, `5+4` at eleven.\n */\n mobile?: boolean;\n}\n\n/**\n * Apply the Brazilian phone mask `(XX) XXXXX-XXXX` or `(XX) XXXX-XXXX`.\n *\n * By default the grouping is decided by **length**, which is what a field\n * accepting both landlines and mobiles needs.\n *\n * `mobile: true` is for a field that only accepts mobile numbers, and it exists\n * because the default is wrong as an as-you-type mask there. Reading anything up\n * to ten digits as a landline puts the hyphen after the fourth subscriber digit,\n * so a half-typed mobile renders `(11) 9123-4`; it only becomes `(11) 91234-5`\n * once the eleventh digit lands. The separator visibly jumps backwards while the\n * user is still typing. With `mobile`, the same input reads `(11) 91234` and the\n * hyphen never moves. It also inserts the leading `9` every Brazilian mobile\n * carries, so a ten-digit number gets corrected rather than masked as a landline.\n *\n * @param value - Raw digits or partially masked string.\n * @param options - Masking options.\n * @returns Masked phone string.\n *\n * @example\n * formatPhone(\"1191234\"); // \"(11) 9123-4\"\n * formatPhone(\"1191234\", { mobile: true }); // \"(11) 91234\"\n * formatPhone(\"1112345678\", { mobile: true }); // \"(11) 91234-5678\" — 9 inserted\n */\nexport function formatPhone(value: string, options: FormatPhoneOptions = {}): string {\n const digits = value.replace(/\\D/g, \"\").slice(0, 11);\n\n if (!options.mobile) {\n if (digits.length <= 10) {\n return digits.replace(/(\\d{2})(\\d)/, \"($1) $2\").replace(/(\\d{4})(\\d)/, \"$1-$2\");\n }\n return digits.replace(/(\\d{2})(\\d)/, \"($1) $2\").replace(/(\\d{5})(\\d)/, \"$1-$2\");\n }\n\n if (digits.length <= 2) return digits;\n\n const area = digits.slice(0, 2);\n let subscriber = digits.slice(2);\n if (subscriber[0] !== \"9\") subscriber = `9${subscriber}`;\n subscriber = subscriber.slice(0, 9);\n\n const prefix = subscriber.slice(0, 5);\n const suffix = subscriber.slice(5);\n return suffix ? `(${area}) ${prefix}-${suffix}` : `(${area}) ${prefix}`;\n}\n\n/**\n * Apply the Brazilian CPF mask `XXX.XXX.XXX-XX`.\n *\n * @param value - Raw digits or partially masked string.\n * @returns Masked CPF string.\n */\nexport function formatCPF(value: string): string {\n return value\n .replace(/\\D/g, \"\")\n .slice(0, 11)\n .replace(/(\\d{3})(\\d)/, \"$1.$2\")\n .replace(/(\\d{3})(\\d)/, \"$1.$2\")\n .replace(/(\\d{3})(\\d{1,2})$/, \"$1-$2\");\n}\n\n/** How {@link formatPercent} renders a fraction. */\nexport interface FormatPercentOptions extends FormatFallbackOptions {\n /**\n * Decimal places to show, fixed (padded as well as truncated).\n *\n * Defaults to `1`, which is what the function always did. Two is the case\n * that produced this option: a confidence of 98,74% and one of 98,7% are the\n * same number on a summary card and two different readings on a detail\n * screen, so the precision belongs to the call site.\n */\n decimals?: number;\n}\n\n/**\n * Format a fraction (0-1) as a percentage.\n *\n * A non-finite input renders as `\"—\"` rather than `\"NaN%\"` or `\"∞%\"`, which is\n * what `Intl.NumberFormat` produces and what a division by zero upstream puts on\n * the screen. It matches `formatDurationMs`, which already answers that way.\n *\n * @example\n * ```typescript\n * formatPercent(0.9874); // \"98,7%\"\n * formatPercent(0.9874, { decimals: 2 }); // \"98,74%\"\n * formatPercent(0 / 0); // \"—\"\n * ```\n *\n * @param value - Fraction between 0 and 1.\n * @param options - Rendering options; `decimals` defaults to 1.\n * @returns Formatted percent string, e.g. \"12,5%\", or `\"—\"` for a non-finite input.\n */\nexport function formatPercent(\n value: number | null | undefined,\n options: FormatPercentOptions = {},\n): string {\n if (isAbsent(value) || !Number.isFinite(value)) return fallbackText(options);\n const decimals = options.decimals ?? 1;\n return numberFormat(\"pt-BR\", {\n style: \"percent\",\n minimumFractionDigits: decimals,\n maximumFractionDigits: decimals,\n }).format(value);\n}\n"],"mappings":"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"}
1
+ {"version":3,"file":"format.cjs","names":["isAbsent","fallbackText","numberFormat","dateTimeFormat","require_intl_cache","require_absent","formatCurrency","value","options","formatDate","date","formatDateForInput","month","day","formatDateTimeForInput","hours","minutes","formatDateTime","formatPhone","digits","area","subscriber","prefix","suffix","formatCPF","formatPercent","decimals"],"sources":["../../src/utils/format.ts"],"sourcesContent":["import { fallbackText, isAbsent, type FormatFallbackOptions } from \"@/utils/absent\";\nimport { dateTimeFormat, numberFormat } from \"@/utils/intl-cache\";\n\n/**\n * Format a number as Brazilian Real currency.\n *\n * An absent or unrepresentable amount renders as `\"—\"` rather than as a number.\n * That branch is a data-correctness fix, not cosmetics: `Intl` coerces `null` to\n * zero, so an amount the backend left out used to reach the screen as\n * **`\"R$ 0,00\"`** — a plausible figure a reader has no way to question — and\n * `undefined` as `\"R$ NaN\"`.\n *\n * @example\n * ```typescript\n * formatCurrency(1234.56); // \"R$ 1.234,56\"\n * formatCurrency(null); // \"—\"\n * formatCurrency(null, { fallback: \"sem valor\" }); // \"sem valor\"\n * ```\n *\n * @param value - The amount in BRL, or `null`/`undefined` when there is none.\n * @param options - Text to render when there is nothing to format.\n * @returns A locale-formatted string, e.g. \"R$ 1.234,56\".\n */\nexport function formatCurrency(\n value: number | null | undefined,\n options?: FormatFallbackOptions,\n): string {\n if (isAbsent(value) || !Number.isFinite(value)) return fallbackText(options);\n return numberFormat(\"pt-BR\", { style: \"currency\", currency: \"BRL\" }).format(value);\n}\n\n/**\n * Format an ISO date or Date instance as `dd/MM/yyyy`.\n *\n * Absent input answers `\"—\"`. It used to **throw**: `new Date(null)` is epoch and\n * `null.getTime` is a `TypeError`, so a nullable column — which is every\n * `deleted_at`, `expires_at` and half the `updated_at` a FastAPI backend sends —\n * took the screen down instead of rendering a gap.\n *\n * A value that is present and unparseable still answers `\"\"`, deliberately: on a\n * screen that reads a log, \"nobody filled this in\" and \"what they filled in is\n * broken\" are different findings, and the second is the one worth chasing.\n *\n * @example\n * ```typescript\n * formatDate(\"2026-05-16T12:00:00Z\"); // \"16/05/2026\"\n * formatDate(null); // \"—\"\n * formatDate(\"banana\"); // \"\"\n * ```\n *\n * @param value - ISO string, Date, or `null`/`undefined`.\n * @param options - Text to render when the value is absent.\n * @returns Formatted date string, the fallback when absent, or empty string when\n * the value is present and invalid.\n */\nexport function formatDate(\n value: string | Date | null | undefined,\n options?: FormatFallbackOptions,\n): string {\n if (isAbsent(value)) return fallbackText(options);\n const date = typeof value === \"string\" ? new Date(value) : value;\n if (Number.isNaN(date.getTime())) return \"\";\n return dateTimeFormat(\"pt-BR\").format(date);\n}\n\n/**\n * Format an ISO date or Date instance as `yyyy-MM-dd`, the value an\n * `<input type=\"date\">` accepts.\n *\n * Built from the **local** calendar parts rather than `toISOString().slice(0, 10)`,\n * which is the reflex and which is wrong: `toISOString` converts to UTC first, so\n * anything after 21:00 in UTC-3 reports the next day and the form opens on the\n * wrong date. `formatDate` cannot fill this role because a date input rejects\n * `dd/MM/yyyy` outright.\n *\n * A value that is already `yyyy-MM-dd` is returned untouched, and that shortcut\n * is load-bearing rather than an optimisation: `new Date(\"2026-05-16\")` is parsed\n * as **UTC** midnight, which in UTC-3 is the 15th at 21:00, so round-tripping the\n * exact value a backend sent would move it back a day.\n *\n * @example\n * <input type=\"date\" defaultValue={formatDateForInput(order.createdAt)} />\n *\n * Absent input answers `\"\"` here — **not** the em dash the reading formatters\n * use — because that is what an input reads as \"no value\"; an em dash would\n * arrive as content the user has to delete before typing a date.\n *\n * @param value - ISO string, Date, or `null`/`undefined`.\n * @param options - Text for an absent value; defaults to `\"\"`.\n * @returns The `yyyy-MM-dd` value, or an empty string when the input is invalid —\n * which is what a date input reads as \"no value\", unlike `\"Invalid Date\"`.\n */\nexport function formatDateForInput(\n value: string | Date | null | undefined,\n options?: FormatFallbackOptions,\n): string {\n if (isAbsent(value)) return fallbackText(options, \"\");\n if (typeof value === \"string\" && /^\\d{4}-\\d{2}-\\d{2}$/.test(value)) return value;\n const date = typeof value === \"string\" ? new Date(value) : value;\n if (Number.isNaN(date.getTime())) return \"\";\n const month = `${date.getMonth() + 1}`.padStart(2, \"0\");\n const day = `${date.getDate()}`.padStart(2, \"0\");\n return `${date.getFullYear()}-${month}-${day}`;\n}\n\n/**\n * Format an ISO date or Date instance as `yyyy-MM-ddTHH:mm`, the value an\n * `<input type=\"datetime-local\">` accepts.\n *\n * The sibling of {@link formatDateForInput}, and it exists for the same reason:\n * `toISOString().slice(0, 16)` is the reflex and it is wrong. `toISOString`\n * converts to UTC first, so a 22:00 appointment in UTC-3 opens the form on the\n * next day at 01:00 — here the trap costs the hour as well as the date.\n *\n * A value already in `yyyy-MM-ddTHH:mm` is returned untouched. A value carrying\n * a zone (`...Z`, `...-03:00`) deliberately does **not** take that shortcut: it\n * is a different instant from the naive string that looks like it, so it is\n * converted to the local calendar parts the input has to show.\n *\n * Seconds are dropped. A `datetime-local` steps by the minute unless the app\n * sets `step`, so a `:ss` the field cannot represent would be silently discarded\n * on the first edit anyway — truncating here keeps the rendered value and the\n * submitted value the same.\n *\n * @example\n * <input\n * type=\"datetime-local\"\n * defaultValue={formatDateTimeForInput(appointment.startsAt)}\n * />\n *\n * @param value - ISO string or Date.\n * @returns The `yyyy-MM-ddTHH:mm` value, or an empty string when the input is\n * invalid — which is what a datetime input reads as \"no value\", unlike\n * `\"Invalid Date\"`.\n */\nexport function formatDateTimeForInput(\n value: string | Date | null | undefined,\n options?: FormatFallbackOptions,\n): string {\n if (isAbsent(value)) return fallbackText(options, \"\");\n if (typeof value === \"string\" && /^\\d{4}-\\d{2}-\\d{2}T\\d{2}:\\d{2}$/.test(value)) return value;\n const date = typeof value === \"string\" ? new Date(value) : value;\n if (Number.isNaN(date.getTime())) return \"\";\n const month = `${date.getMonth() + 1}`.padStart(2, \"0\");\n const day = `${date.getDate()}`.padStart(2, \"0\");\n const hours = `${date.getHours()}`.padStart(2, \"0\");\n const minutes = `${date.getMinutes()}`.padStart(2, \"0\");\n return `${date.getFullYear()}-${month}-${day}T${hours}:${minutes}`;\n}\n\n/**\n * Format an ISO date or Date instance as `dd/MM/yyyy HH:mm`.\n *\n * Same contract as {@link formatDate}: absent answers the fallback (`\"—\"` by\n * default) instead of throwing, and present-but-invalid answers `\"\"`.\n *\n * @param value - ISO string, Date, or `null`/`undefined`.\n * @param options - Text to render when the value is absent.\n * @returns Formatted datetime string, the fallback when absent, or empty string\n * when the value is present and invalid.\n */\nexport function formatDateTime(\n value: string | Date | null | undefined,\n options?: FormatFallbackOptions,\n): string {\n if (isAbsent(value)) return fallbackText(options);\n const date = typeof value === \"string\" ? new Date(value) : value;\n if (Number.isNaN(date.getTime())) return \"\";\n return dateTimeFormat(\"pt-BR\", { dateStyle: \"short\", timeStyle: \"short\" }).format(date);\n}\n\nexport interface FormatPhoneOptions {\n /**\n * Treat the number as a mobile line: insert the mandatory `9` after the area\n * code when it is missing, and group the subscriber part `5+4` from the\n * first digit typed instead of waiting for the eleventh.\n *\n * Default `false`, which keeps the length-based behaviour: `4+4` up to ten\n * digits, `5+4` at eleven.\n */\n mobile?: boolean;\n}\n\n/**\n * Apply the Brazilian phone mask `(XX) XXXXX-XXXX` or `(XX) XXXX-XXXX`.\n *\n * By default the grouping is decided by **length**, which is what a field\n * accepting both landlines and mobiles needs.\n *\n * `mobile: true` is for a field that only accepts mobile numbers, and it exists\n * because the default is wrong as an as-you-type mask there. Reading anything up\n * to ten digits as a landline puts the hyphen after the fourth subscriber digit,\n * so a half-typed mobile renders `(11) 9123-4`; it only becomes `(11) 91234-5`\n * once the eleventh digit lands. The separator visibly jumps backwards while the\n * user is still typing. With `mobile`, the same input reads `(11) 91234` and the\n * hyphen never moves. It also inserts the leading `9` every Brazilian mobile\n * carries, so a ten-digit number gets corrected rather than masked as a landline.\n *\n * @param value - Raw digits or partially masked string.\n * @param options - Masking options.\n * @returns Masked phone string.\n *\n * @example\n * formatPhone(\"1191234\"); // \"(11) 9123-4\"\n * formatPhone(\"1191234\", { mobile: true }); // \"(11) 91234\"\n * formatPhone(\"1112345678\", { mobile: true }); // \"(11) 91234-5678\" — 9 inserted\n */\nexport function formatPhone(value: string, options: FormatPhoneOptions = {}): string {\n const digits = value.replace(/\\D/g, \"\").slice(0, 11);\n\n if (!options.mobile) {\n if (digits.length <= 10) {\n return digits.replace(/(\\d{2})(\\d)/, \"($1) $2\").replace(/(\\d{4})(\\d)/, \"$1-$2\");\n }\n return digits.replace(/(\\d{2})(\\d)/, \"($1) $2\").replace(/(\\d{5})(\\d)/, \"$1-$2\");\n }\n\n if (digits.length <= 2) return digits;\n\n const area = digits.slice(0, 2);\n let subscriber = digits.slice(2);\n if (subscriber[0] !== \"9\") subscriber = `9${subscriber}`;\n subscriber = subscriber.slice(0, 9);\n\n const prefix = subscriber.slice(0, 5);\n const suffix = subscriber.slice(5);\n return suffix ? `(${area}) ${prefix}-${suffix}` : `(${area}) ${prefix}`;\n}\n\n/**\n * Apply the Brazilian CPF mask `XXX.XXX.XXX-XX`.\n *\n * @param value - Raw digits or partially masked string.\n * @returns Masked CPF string.\n */\nexport function formatCPF(value: string): string {\n return value\n .replace(/\\D/g, \"\")\n .slice(0, 11)\n .replace(/(\\d{3})(\\d)/, \"$1.$2\")\n .replace(/(\\d{3})(\\d)/, \"$1.$2\")\n .replace(/(\\d{3})(\\d{1,2})$/, \"$1-$2\");\n}\n\n/** How {@link formatPercent} renders a fraction. */\nexport interface FormatPercentOptions extends FormatFallbackOptions {\n /**\n * Decimal places to show, fixed (padded as well as truncated).\n *\n * Defaults to `1`, which is what the function always did. Two is the case\n * that produced this option: a confidence of 98,74% and one of 98,7% are the\n * same number on a summary card and two different readings on a detail\n * screen, so the precision belongs to the call site.\n */\n decimals?: number;\n}\n\n/**\n * Format a fraction (0-1) as a percentage.\n *\n * A non-finite input renders as `\"—\"` rather than `\"NaN%\"` or `\"∞%\"`, which is\n * what `Intl.NumberFormat` produces and what a division by zero upstream puts on\n * the screen. It matches `formatDurationMs`, which already answers that way.\n *\n * @example\n * ```typescript\n * formatPercent(0.9874); // \"98,7%\"\n * formatPercent(0.9874, { decimals: 2 }); // \"98,74%\"\n * formatPercent(0 / 0); // \"—\"\n * ```\n *\n * @param value - Fraction between 0 and 1.\n * @param options - Rendering options; `decimals` defaults to 1.\n * @returns Formatted percent string, e.g. \"12,5%\", or `\"—\"` for a non-finite input.\n */\nexport function formatPercent(\n value: number | null | undefined,\n options: FormatPercentOptions = {},\n): string {\n if (isAbsent(value) || !Number.isFinite(value)) return fallbackText(options);\n const decimals = options.decimals ?? 1;\n return numberFormat(\"pt-BR\", {\n style: \"percent\",\n minimumFractionDigits: decimals,\n maximumFractionDigits: decimals,\n }).format(value);\n}\n"],"mappings":"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"}
@@ -1,37 +1,37 @@
1
- import { fallbackText as e, isAbsent as t } from "./absent.js";
2
- import { dateTimeFormat as n, numberFormat as r } from "./intl-cache.js";
1
+ import { dateTimeFormat as e, numberFormat as t } from "./intl-cache.js";
2
+ import { fallbackText as n, isAbsent as r } from "./absent.js";
3
3
  //#region src/utils/format.ts
4
- function i(n, i) {
5
- return t(n) || !Number.isFinite(n) ? e(i) : r("pt-BR", {
4
+ function i(e, i) {
5
+ return r(e) || !Number.isFinite(e) ? n(i) : t("pt-BR", {
6
6
  style: "currency",
7
7
  currency: "BRL"
8
- }).format(n);
8
+ }).format(e);
9
9
  }
10
- function a(r, i) {
11
- if (t(r)) return e(i);
12
- let a = typeof r == "string" ? new Date(r) : r;
13
- return Number.isNaN(a.getTime()) ? "" : n("pt-BR").format(a);
10
+ function a(t, i) {
11
+ if (r(t)) return n(i);
12
+ let a = typeof t == "string" ? new Date(t) : t;
13
+ return Number.isNaN(a.getTime()) ? "" : e("pt-BR").format(a);
14
14
  }
15
- function o(n, r) {
16
- if (t(n)) return e(r, "");
17
- if (typeof n == "string" && /^\d{4}-\d{2}-\d{2}$/.test(n)) return n;
18
- let i = typeof n == "string" ? new Date(n) : n;
15
+ function o(e, t) {
16
+ if (r(e)) return n(t, "");
17
+ if (typeof e == "string" && /^\d{4}-\d{2}-\d{2}$/.test(e)) return e;
18
+ let i = typeof e == "string" ? new Date(e) : e;
19
19
  if (Number.isNaN(i.getTime())) return "";
20
20
  let a = `${i.getMonth() + 1}`.padStart(2, "0"), o = `${i.getDate()}`.padStart(2, "0");
21
21
  return `${i.getFullYear()}-${a}-${o}`;
22
22
  }
23
- function s(n, r) {
24
- if (t(n)) return e(r, "");
25
- if (typeof n == "string" && /^\d{4}-\d{2}-\d{2}T\d{2}:\d{2}$/.test(n)) return n;
26
- let i = typeof n == "string" ? new Date(n) : n;
23
+ function s(e, t) {
24
+ if (r(e)) return n(t, "");
25
+ if (typeof e == "string" && /^\d{4}-\d{2}-\d{2}T\d{2}:\d{2}$/.test(e)) return e;
26
+ let i = typeof e == "string" ? new Date(e) : e;
27
27
  if (Number.isNaN(i.getTime())) return "";
28
28
  let a = `${i.getMonth() + 1}`.padStart(2, "0"), o = `${i.getDate()}`.padStart(2, "0"), s = `${i.getHours()}`.padStart(2, "0"), c = `${i.getMinutes()}`.padStart(2, "0");
29
29
  return `${i.getFullYear()}-${a}-${o}T${s}:${c}`;
30
30
  }
31
- function c(r, i) {
32
- if (t(r)) return e(i);
33
- let a = typeof r == "string" ? new Date(r) : r;
34
- return Number.isNaN(a.getTime()) ? "" : n("pt-BR", {
31
+ function c(t, i) {
32
+ if (r(t)) return n(i);
33
+ let a = typeof t == "string" ? new Date(t) : t;
34
+ return Number.isNaN(a.getTime()) ? "" : e("pt-BR", {
35
35
  dateStyle: "short",
36
36
  timeStyle: "short"
37
37
  }).format(a);
@@ -48,14 +48,14 @@ function l(e, t = {}) {
48
48
  function u(e) {
49
49
  return e.replace(/\D/g, "").slice(0, 11).replace(/(\d{3})(\d)/, "$1.$2").replace(/(\d{3})(\d)/, "$1.$2").replace(/(\d{3})(\d{1,2})$/, "$1-$2");
50
50
  }
51
- function d(n, i = {}) {
52
- if (t(n) || !Number.isFinite(n)) return e(i);
51
+ function d(e, i = {}) {
52
+ if (r(e) || !Number.isFinite(e)) return n(i);
53
53
  let a = i.decimals ?? 1;
54
- return r("pt-BR", {
54
+ return t("pt-BR", {
55
55
  style: "percent",
56
56
  minimumFractionDigits: a,
57
57
  maximumFractionDigits: a
58
- }).format(n);
58
+ }).format(e);
59
59
  }
60
60
  //#endregion
61
61
  export { u as formatCPF, i as formatCurrency, a as formatDate, o as formatDateForInput, c as formatDateTime, s as formatDateTimeForInput, d as formatPercent, l as formatPhone };
@@ -1,2 +1,2 @@
1
- const e=require("./absent.cjs"),t=require("./intl-cache.cjs");function n(e,t,n){if(Number.isNaN(e))return e;if(t>n){let e=t;t=n,n=e}return e<t?t:e>n?n:e}function r(t,n=1,r){if(e.isAbsent(t)||!Number.isFinite(t))return e.fallbackText(r);if(t===0)return`0 B`;let i=[`B`,`KB`,`MB`,`GB`,`TB`],a=1024,o=Math.min(Math.floor(Math.log(Math.abs(t))/Math.log(a)),i.length-1),s=t/a**o,c=o===0?0:Math.max(0,n);return`${parseFloat(s.toFixed(c)).toString()} ${i[o]}`}function i(e,t){return!Number.isFinite(e)||!Number.isFinite(t)||t===0?0:e/t*100}function a(n,r=`en-US`,i){return e.isAbsent(n)||!Number.isFinite(n)?e.fallbackText(i):t.numberFormat(r,{notation:`compact`,maximumFractionDigits:1}).format(n)}exports.clamp=n,exports.formatBytes=r,exports.formatCompactNumber=a,exports.percentOf=i;
1
+ const e=require("./intl-cache.cjs"),t=require("./absent.cjs");function n(e,t,n){if(Number.isNaN(e))return e;if(t>n){let e=t;t=n,n=e}return e<t?t:e>n?n:e}function r(e,n=1,r){if(t.isAbsent(e)||!Number.isFinite(e))return t.fallbackText(r);if(e===0)return`0 B`;let i=[`B`,`KB`,`MB`,`GB`,`TB`],a=1024,o=Math.min(Math.floor(Math.log(Math.abs(e))/Math.log(a)),i.length-1),s=e/a**o,c=o===0?0:Math.max(0,n);return`${parseFloat(s.toFixed(c)).toString()} ${i[o]}`}function i(e,t){return!Number.isFinite(e)||!Number.isFinite(t)||t===0?0:e/t*100}function a(n,r=`en-US`,i){return t.isAbsent(n)||!Number.isFinite(n)?t.fallbackText(i):e.numberFormat(r,{notation:`compact`,maximumFractionDigits:1}).format(n)}exports.clamp=n,exports.formatBytes=r,exports.formatCompactNumber=a,exports.percentOf=i;
2
2
  //# sourceMappingURL=numbers.cjs.map
@@ -1 +1 @@
1
- {"version":3,"file":"numbers.cjs","names":["isAbsent","fallbackText","numberFormat","require_absent","require_intl_cache","clamp","value","min","max","swap","formatBytes","bytes","options","units","base","exponent","digits","decimals","percentOf","part","total","formatCompactNumber","locale"],"sources":["../../src/utils/numbers.ts"],"sourcesContent":["import { fallbackText, isAbsent, type FormatFallbackOptions } from \"@/utils/absent\";\nimport { numberFormat } from \"@/utils/intl-cache\";\n/**\n * Clamp `value` between `min` and `max` (inclusive).\n *\n * @example\n * clamp(120, 0, 100); // 100\n * clamp(-5, 0, 100); // 0\n * clamp(42, 0, 100); // 42\n */\nexport function clamp(value: number, min: number, max: number): number {\n if (Number.isNaN(value)) return value;\n if (min > max) {\n const swap = min;\n min = max;\n max = swap;\n }\n if (value < min) return min;\n if (value > max) return max;\n return value;\n}\n\n/**\n * Format a byte count as a human-readable size string.\n *\n * Scales through B, KB, MB, GB and TB using 1024 as the base. `decimals`\n * controls the fractional digits for scaled units (default 1); `0` bytes\n * always renders as `\"0 B\"`.\n *\n * An absent or unrepresentable count renders as `\"—\"`. It used to render as\n * **`\"NaN undefined\"`**: `Math.log(NaN)` walks the exponent off the end of the\n * unit table, so the unit itself came out `undefined` — the size was not merely\n * unreadable, it claimed a unit that does not exist.\n *\n * @example\n * formatBytes(0); // \"0 B\"\n * formatBytes(1536); // \"1.5 KB\"\n * formatBytes(1048576); // \"1 MB\"\n * formatBytes(1536, 2); // \"1.50 KB\"\n * formatBytes(null); // \"—\"\n */\nexport function formatBytes(\n bytes: number | null | undefined,\n decimals: number = 1,\n options?: FormatFallbackOptions,\n): string {\n if (isAbsent(bytes) || !Number.isFinite(bytes)) return fallbackText(options);\n if (bytes === 0) return \"0 B\";\n\n const units = [\"B\", \"KB\", \"MB\", \"GB\", \"TB\"];\n const base = 1024;\n const exponent = Math.min(\n Math.floor(Math.log(Math.abs(bytes)) / Math.log(base)),\n units.length - 1,\n );\n const value = bytes / base ** exponent;\n const digits = exponent === 0 ? 0 : Math.max(0, decimals);\n const formatted = parseFloat(value.toFixed(digits)).toString();\n\n return `${formatted} ${units[exponent]}`;\n}\n\n/**\n * What percentage of `total` is `part`, with an empty base yielding `0`.\n *\n * The guard is the whole point: `(part / total) * 100` produces `NaN` when the\n * base is zero and `Infinity` when only the base is missing, and both reach the\n * screen as a broken label — `NaN%` on an empty dashboard is the single most\n * common way a panel announces that it has no data yet.\n *\n * Returns a **0–100** number, which is what a bar width and a label want.\n * `formatPercent` takes a 0–1 fraction instead, so pair them as\n * `formatPercent(percentOf(a, b) / 100)` — or skip `percentOf` and pass the\n * fraction straight in.\n *\n * The result is not clamped: 120% of a target is a real number somebody wants to\n * see, and capping it would hide the interesting case.\n *\n * @example\n * percentOf(3, 4); // 75\n * percentOf(5, 0); // 0\n * percentOf(12, 8); // 150\n *\n * @param part - The measured amount.\n * @param total - The base it is measured against.\n * @returns The percentage, or `0` when the base is zero or either input is not finite.\n */\nexport function percentOf(part: number, total: number): number {\n if (!Number.isFinite(part) || !Number.isFinite(total) || total === 0) return 0;\n return (part / total) * 100;\n}\n\n/**\n * Format a number using compact notation (e.g. `1.2K`, `3.4M`).\n *\n * Wraps `Intl.NumberFormat` with `notation: \"compact\"`. The `locale` defaults\n * to `\"en-US\"`.\n *\n * An absent or unrepresentable value renders as `\"—\"`. The `null` case is the\n * one that matters: `Intl` coerces it to zero, so a count the backend left out\n * used to read as **`\"0\"`** — a number the reader has no reason to doubt.\n *\n * @example\n * formatCompactNumber(1234); // \"1.2K\"\n * formatCompactNumber(5600000); // \"5.6M\"\n * formatCompactNumber(1234, \"pt-BR\"); // \"1,2 mil\"\n * formatCompactNumber(null); // \"—\"\n */\nexport function formatCompactNumber(\n value: number | null | undefined,\n locale: string = \"en-US\",\n options?: FormatFallbackOptions,\n): string {\n if (isAbsent(value) || !Number.isFinite(value)) return fallbackText(options);\n return numberFormat(locale, { notation: \"compact\", maximumFractionDigits: 1 }).format(value);\n}\n"],"mappings":"A,8DAUA,SAAgBK,EAAM,EAAe,EAAa,EAAqB,CACnE,GAAI,OAAO,MAAMC,CAAK,EAAG,OAAOA,EAChC,GAAIC,EAAMC,EAAK,CACX,IAAMC,EAAOF,EACb,EAAMC,EACN,EAAMC,CACV,CAGA,OAFIH,EAAQC,EAAYA,EACpBD,EAAQE,EAAYA,EACjBF,CACX,CAqBA,SAAgBI,EACZ,EACA,EAAmB,EACnB,EACM,CACN,GAAIV,EAAAA,SAASW,CAAK,GAAK,CAAC,OAAO,SAASA,CAAK,EAAG,OAAOV,EAAAA,aAAaW,CAAO,EAC3E,GAAID,IAAU,EAAG,MAAO,MAExB,IAAME,EAAQ,CAAC,IAAK,KAAM,KAAM,KAAM,IAAI,EACpCC,EAAO,KACPC,EAAW,KAAK,IAClB,KAAK,MAAM,KAAK,IAAI,KAAK,IAAIJ,CAAK,CAAC,EAAI,KAAK,IAAIG,CAAI,CAAC,EACrDD,EAAM,OAAS,CACnB,EACMP,EAAQK,EAAQG,GAAQC,EACxBC,EAASD,IAAa,EAAI,EAAI,KAAK,IAAI,EAAGE,CAAQ,EAGxD,MAAO,GAFW,WAAWX,EAAM,QAAQU,CAAM,CAAC,CAAC,CAAC,SAE1C,EAAU,GAAGH,EAAME,IACjC,CA2BA,SAAgBG,EAAU,EAAc,EAAuB,CAE3D,MADI,CAAC,OAAO,SAASC,CAAI,GAAK,CAAC,OAAO,SAASC,CAAK,GAAKA,IAAU,EAAU,EACrED,EAAOC,EAAS,GAC5B,CAkBA,SAAgBC,EACZ,EACA,EAAiB,QACjB,EACM,CAEN,OADIrB,EAAAA,SAASM,CAAK,GAAK,CAAC,OAAO,SAASA,CAAK,EAAUL,EAAAA,aAAaW,CAAO,EACpEV,EAAAA,aAAaoB,EAAQ,CAAE,SAAU,UAAW,sBAAuB,CAAE,CAAC,CAAC,CAAC,OAAOhB,CAAK,CAC/F,C"}
1
+ {"version":3,"file":"numbers.cjs","names":["isAbsent","fallbackText","numberFormat","require_intl_cache","require_absent","clamp","value","min","max","swap","formatBytes","bytes","options","units","base","exponent","digits","decimals","percentOf","part","total","formatCompactNumber","locale"],"sources":["../../src/utils/numbers.ts"],"sourcesContent":["import { fallbackText, isAbsent, type FormatFallbackOptions } from \"@/utils/absent\";\nimport { numberFormat } from \"@/utils/intl-cache\";\n/**\n * Clamp `value` between `min` and `max` (inclusive).\n *\n * @example\n * clamp(120, 0, 100); // 100\n * clamp(-5, 0, 100); // 0\n * clamp(42, 0, 100); // 42\n */\nexport function clamp(value: number, min: number, max: number): number {\n if (Number.isNaN(value)) return value;\n if (min > max) {\n const swap = min;\n min = max;\n max = swap;\n }\n if (value < min) return min;\n if (value > max) return max;\n return value;\n}\n\n/**\n * Format a byte count as a human-readable size string.\n *\n * Scales through B, KB, MB, GB and TB using 1024 as the base. `decimals`\n * controls the fractional digits for scaled units (default 1); `0` bytes\n * always renders as `\"0 B\"`.\n *\n * An absent or unrepresentable count renders as `\"—\"`. It used to render as\n * **`\"NaN undefined\"`**: `Math.log(NaN)` walks the exponent off the end of the\n * unit table, so the unit itself came out `undefined` — the size was not merely\n * unreadable, it claimed a unit that does not exist.\n *\n * @example\n * formatBytes(0); // \"0 B\"\n * formatBytes(1536); // \"1.5 KB\"\n * formatBytes(1048576); // \"1 MB\"\n * formatBytes(1536, 2); // \"1.50 KB\"\n * formatBytes(null); // \"—\"\n */\nexport function formatBytes(\n bytes: number | null | undefined,\n decimals: number = 1,\n options?: FormatFallbackOptions,\n): string {\n if (isAbsent(bytes) || !Number.isFinite(bytes)) return fallbackText(options);\n if (bytes === 0) return \"0 B\";\n\n const units = [\"B\", \"KB\", \"MB\", \"GB\", \"TB\"];\n const base = 1024;\n const exponent = Math.min(\n Math.floor(Math.log(Math.abs(bytes)) / Math.log(base)),\n units.length - 1,\n );\n const value = bytes / base ** exponent;\n const digits = exponent === 0 ? 0 : Math.max(0, decimals);\n const formatted = parseFloat(value.toFixed(digits)).toString();\n\n return `${formatted} ${units[exponent]}`;\n}\n\n/**\n * What percentage of `total` is `part`, with an empty base yielding `0`.\n *\n * The guard is the whole point: `(part / total) * 100` produces `NaN` when the\n * base is zero and `Infinity` when only the base is missing, and both reach the\n * screen as a broken label — `NaN%` on an empty dashboard is the single most\n * common way a panel announces that it has no data yet.\n *\n * Returns a **0–100** number, which is what a bar width and a label want.\n * `formatPercent` takes a 0–1 fraction instead, so pair them as\n * `formatPercent(percentOf(a, b) / 100)` — or skip `percentOf` and pass the\n * fraction straight in.\n *\n * The result is not clamped: 120% of a target is a real number somebody wants to\n * see, and capping it would hide the interesting case.\n *\n * @example\n * percentOf(3, 4); // 75\n * percentOf(5, 0); // 0\n * percentOf(12, 8); // 150\n *\n * @param part - The measured amount.\n * @param total - The base it is measured against.\n * @returns The percentage, or `0` when the base is zero or either input is not finite.\n */\nexport function percentOf(part: number, total: number): number {\n if (!Number.isFinite(part) || !Number.isFinite(total) || total === 0) return 0;\n return (part / total) * 100;\n}\n\n/**\n * Format a number using compact notation (e.g. `1.2K`, `3.4M`).\n *\n * Wraps `Intl.NumberFormat` with `notation: \"compact\"`. The `locale` defaults\n * to `\"en-US\"`.\n *\n * An absent or unrepresentable value renders as `\"—\"`. The `null` case is the\n * one that matters: `Intl` coerces it to zero, so a count the backend left out\n * used to read as **`\"0\"`** — a number the reader has no reason to doubt.\n *\n * @example\n * formatCompactNumber(1234); // \"1.2K\"\n * formatCompactNumber(5600000); // \"5.6M\"\n * formatCompactNumber(1234, \"pt-BR\"); // \"1,2 mil\"\n * formatCompactNumber(null); // \"—\"\n */\nexport function formatCompactNumber(\n value: number | null | undefined,\n locale: string = \"en-US\",\n options?: FormatFallbackOptions,\n): string {\n if (isAbsent(value) || !Number.isFinite(value)) return fallbackText(options);\n return numberFormat(locale, { notation: \"compact\", maximumFractionDigits: 1 }).format(value);\n}\n"],"mappings":"A,8DAUA,SAAgBK,EAAM,EAAe,EAAa,EAAqB,CACnE,GAAI,OAAO,MAAMC,CAAK,EAAG,OAAOA,EAChC,GAAIC,EAAMC,EAAK,CACX,IAAMC,EAAOF,EACb,EAAMC,EACN,EAAMC,CACV,CAGA,OAFIH,EAAQC,EAAYA,EACpBD,EAAQE,EAAYA,EACjBF,CACX,CAqBA,SAAgBI,EACZ,EACA,EAAmB,EACnB,EACM,CACN,GAAIV,EAAAA,SAASW,CAAK,GAAK,CAAC,OAAO,SAASA,CAAK,EAAG,OAAOV,EAAAA,aAAaW,CAAO,EAC3E,GAAID,IAAU,EAAG,MAAO,MAExB,IAAME,EAAQ,CAAC,IAAK,KAAM,KAAM,KAAM,IAAI,EACpCC,EAAO,KACPC,EAAW,KAAK,IAClB,KAAK,MAAM,KAAK,IAAI,KAAK,IAAIJ,CAAK,CAAC,EAAI,KAAK,IAAIG,CAAI,CAAC,EACrDD,EAAM,OAAS,CACnB,EACMP,EAAQK,EAAQG,GAAQC,EACxBC,EAASD,IAAa,EAAI,EAAI,KAAK,IAAI,EAAGE,CAAQ,EAGxD,MAAO,GAFW,WAAWX,EAAM,QAAQU,CAAM,CAAC,CAAC,CAAC,SAE1C,EAAU,GAAGH,EAAME,IACjC,CA2BA,SAAgBG,EAAU,EAAc,EAAuB,CAE3D,MADI,CAAC,OAAO,SAASC,CAAI,GAAK,CAAC,OAAO,SAASC,CAAK,GAAKA,IAAU,EAAU,EACrED,EAAOC,EAAS,GAC5B,CAkBA,SAAgBC,EACZ,EACA,EAAiB,QACjB,EACM,CAEN,OADIrB,EAAAA,SAASM,CAAK,GAAK,CAAC,OAAO,SAASA,CAAK,EAAUL,EAAAA,aAAaW,CAAO,EACpEV,EAAAA,aAAaoB,EAAQ,CAAE,SAAU,UAAW,sBAAuB,CAAE,CAAC,CAAC,CAAC,OAAOhB,CAAK,CAC/F,C"}
@@ -1,5 +1,5 @@
1
- import { fallbackText as e, isAbsent as t } from "./absent.js";
2
- import { numberFormat as n } from "./intl-cache.js";
1
+ import { numberFormat as e } from "./intl-cache.js";
2
+ import { fallbackText as t, isAbsent as n } from "./absent.js";
3
3
  //#region src/utils/numbers.ts
4
4
  function r(e, t, n) {
5
5
  if (Number.isNaN(e)) return e;
@@ -9,23 +9,23 @@ function r(e, t, n) {
9
9
  }
10
10
  return e < t ? t : e > n ? n : e;
11
11
  }
12
- function i(n, r = 1, i) {
13
- if (t(n) || !Number.isFinite(n)) return e(i);
14
- if (n === 0) return "0 B";
12
+ function i(e, r = 1, i) {
13
+ if (n(e) || !Number.isFinite(e)) return t(i);
14
+ if (e === 0) return "0 B";
15
15
  let a = [
16
16
  "B",
17
17
  "KB",
18
18
  "MB",
19
19
  "GB",
20
20
  "TB"
21
- ], o = 1024, s = Math.min(Math.floor(Math.log(Math.abs(n)) / Math.log(o)), a.length - 1), c = n / o ** s, l = s === 0 ? 0 : Math.max(0, r);
21
+ ], o = 1024, s = Math.min(Math.floor(Math.log(Math.abs(e)) / Math.log(o)), a.length - 1), c = e / o ** s, l = s === 0 ? 0 : Math.max(0, r);
22
22
  return `${parseFloat(c.toFixed(l)).toString()} ${a[s]}`;
23
23
  }
24
24
  function a(e, t) {
25
25
  return !Number.isFinite(e) || !Number.isFinite(t) || t === 0 ? 0 : e / t * 100;
26
26
  }
27
27
  function o(r, i = "en-US", a) {
28
- return t(r) || !Number.isFinite(r) ? e(a) : n(i, {
28
+ return n(r) || !Number.isFinite(r) ? t(a) : e(i, {
29
29
  notation: "compact",
30
30
  maximumFractionDigits: 1
31
31
  }).format(r);
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "tempest-react-sdk",
3
- "version": "0.79.0",
3
+ "version": "0.81.0",
4
4
  "description": "SDK público da Tempest com componentes, hooks e integrações para projetos React.",
5
5
  "type": "module",
6
6
  "license": "MIT",
@@ -14,12 +14,14 @@ import {
14
14
  *
15
15
  * Layers, in order:
16
16
  * 1. Push + notifications + skip-waiting (the SDK push helpers).
17
- * 2. Background sync — failed POST/PUT/PATCH/DELETE to `/api` are queued and
18
- * replayed online. Credential headers are never stored; on replay the
19
- * worker asks the open pages for the current ones and for who is signed in,
20
- * which `src/pwa.tsx` answers from the auth store
17
+ * 2. Background sync — failed POST/PUT/PATCH/DELETE to this origin's `/api`
18
+ * are queued and replayed online. Credential headers are never stored; on
19
+ * replay the worker asks the open pages for the current ones and for who
20
+ * is signed in, which `src/pwa.tsx` answers from the auth store
21
21
  * (`provideBackgroundSyncCredentials`). Remove that and queued
22
- * authenticated mutations never replay.
22
+ * authenticated mutations never replay. The credential only goes back to
23
+ * this origin: an API on another host goes in both the `match` and
24
+ * `trustedOrigins`, or its credentialed entries are dropped on replay.
23
25
  * 3. Runtime caching: unauthenticated API GETs (network-first) + media
24
26
  * (cache-first with Range support, so audio/video seeking works offline).
25
27
  * Every request the API client sends with a bearer (`Authorization`, or any
@@ -53,7 +55,9 @@ installPushHandler({
53
55
  installNotificationClickHandler();
54
56
  installSkipWaitingListener();
55
57
 
56
- installBackgroundSync({ match: (url) => url.pathname.startsWith("/api/") });
58
+ installBackgroundSync({
59
+ match: (url) => url.origin === self.location.origin && url.pathname.startsWith("/api/"),
60
+ });
57
61
 
58
62
  installRuntimeCache([
59
63
  {