tempest-react-sdk 0.63.0 → 0.65.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 (133) hide show
  1. package/README.md +5 -5
  2. package/dist/components/Chat/Chat.cjs +1 -1
  3. package/dist/components/Chat/Chat.cjs.map +1 -1
  4. package/dist/components/Chat/Chat.js +71 -96
  5. package/dist/components/Chat/Chat.js.map +1 -1
  6. package/dist/components/Chat/Chat.module.cjs +1 -1
  7. package/dist/components/Chat/Chat.module.cjs.map +1 -1
  8. package/dist/components/Chat/Chat.module.js +30 -8
  9. package/dist/components/Chat/Chat.module.js.map +1 -1
  10. package/dist/components/Chat/ChatActionsMenu.cjs +2 -0
  11. package/dist/components/Chat/ChatActionsMenu.cjs.map +1 -0
  12. package/dist/components/Chat/ChatActionsMenu.js +14 -0
  13. package/dist/components/Chat/ChatActionsMenu.js.map +1 -0
  14. package/dist/components/Chat/ChatAttachments.cjs +2 -0
  15. package/dist/components/Chat/ChatAttachments.cjs.map +1 -0
  16. package/dist/components/Chat/ChatAttachments.js +80 -0
  17. package/dist/components/Chat/ChatAttachments.js.map +1 -0
  18. package/dist/components/Chat/ChatBubble.cjs +2 -0
  19. package/dist/components/Chat/ChatBubble.cjs.map +1 -0
  20. package/dist/components/Chat/ChatBubble.js +155 -0
  21. package/dist/components/Chat/ChatBubble.js.map +1 -0
  22. package/dist/components/Chat/chat-groups.cjs +1 -1
  23. package/dist/components/Chat/chat-groups.cjs.map +1 -1
  24. package/dist/components/Chat/chat-groups.js +42 -2
  25. package/dist/components/Chat/chat-groups.js.map +1 -1
  26. package/dist/components/Chat/chat-receipt.cjs +2 -0
  27. package/dist/components/Chat/chat-receipt.cjs.map +1 -0
  28. package/dist/components/Chat/chat-receipt.js +14 -0
  29. package/dist/components/Chat/chat-receipt.js.map +1 -0
  30. package/dist/components/Command/Command.module.cjs.map +1 -1
  31. package/dist/components/Command/Command.module.js.map +1 -1
  32. package/dist/components/ContextMenu/ContextMenu.cjs +1 -1
  33. package/dist/components/ContextMenu/ContextMenu.cjs.map +1 -1
  34. package/dist/components/ContextMenu/ContextMenu.js +100 -48
  35. package/dist/components/ContextMenu/ContextMenu.js.map +1 -1
  36. package/dist/components/ContextMenu/ContextMenu.module.cjs.map +1 -1
  37. package/dist/components/ContextMenu/ContextMenu.module.js.map +1 -1
  38. package/dist/components/DataTable/DataTable.cjs +1 -1
  39. package/dist/components/DataTable/DataTable.cjs.map +1 -1
  40. package/dist/components/DataTable/DataTable.js +1 -0
  41. package/dist/components/DataTable/DataTable.js.map +1 -1
  42. package/dist/components/DataTable/use-dev-warnings.cjs +1 -1
  43. package/dist/components/DataTable/use-dev-warnings.cjs.map +1 -1
  44. package/dist/components/DataTable/use-dev-warnings.js +4 -3
  45. package/dist/components/DataTable/use-dev-warnings.js.map +1 -1
  46. package/dist/components/DropdownMenu/DropdownMenu.module.cjs.map +1 -1
  47. package/dist/components/DropdownMenu/DropdownMenu.module.js.map +1 -1
  48. package/dist/components/InstallBanner/InstallBanner.cjs +1 -1
  49. package/dist/components/InstallBanner/InstallBanner.cjs.map +1 -1
  50. package/dist/components/InstallBanner/InstallBanner.js +62 -37
  51. package/dist/components/InstallBanner/InstallBanner.js.map +1 -1
  52. package/dist/components/InstallBanner/InstallBanner.module.cjs +1 -1
  53. package/dist/components/InstallBanner/InstallBanner.module.cjs.map +1 -1
  54. package/dist/components/InstallBanner/InstallBanner.module.js +4 -3
  55. package/dist/components/InstallBanner/InstallBanner.module.js.map +1 -1
  56. package/dist/components/InstallButton/InstallButton.cjs +1 -1
  57. package/dist/components/InstallButton/InstallButton.cjs.map +1 -1
  58. package/dist/components/InstallButton/InstallButton.js +34 -10
  59. package/dist/components/InstallButton/InstallButton.js.map +1 -1
  60. package/dist/components/InstallButton/InstallButton.module.cjs +3 -0
  61. package/dist/components/InstallButton/InstallButton.module.cjs.map +1 -0
  62. package/dist/components/InstallButton/InstallButton.module.js +10 -0
  63. package/dist/components/InstallButton/InstallButton.module.js.map +1 -0
  64. package/dist/components/InstallButton/install-hints.cjs +2 -0
  65. package/dist/components/InstallButton/install-hints.cjs.map +1 -0
  66. package/dist/components/InstallButton/install-hints.js +32 -0
  67. package/dist/components/InstallButton/install-hints.js.map +1 -0
  68. package/dist/components/SegmentedControl/SegmentedControl.module.cjs.map +1 -1
  69. package/dist/components/SegmentedControl/SegmentedControl.module.js.map +1 -1
  70. package/dist/components/Select/Select.cjs +1 -1
  71. package/dist/components/Select/Select.cjs.map +1 -1
  72. package/dist/components/Select/Select.js +43 -40
  73. package/dist/components/Select/Select.js.map +1 -1
  74. package/dist/components/Select/Select.module.cjs +1 -1
  75. package/dist/components/Select/Select.module.cjs.map +1 -1
  76. package/dist/components/Select/Select.module.js +5 -3
  77. package/dist/components/Select/Select.module.js.map +1 -1
  78. package/dist/hooks/use-install-prompt.cjs +1 -1
  79. package/dist/hooks/use-install-prompt.cjs.map +1 -1
  80. package/dist/hooks/use-install-prompt.js +9 -2
  81. package/dist/hooks/use-install-prompt.js.map +1 -1
  82. package/dist/http/api-client.cjs +1 -1
  83. package/dist/http/api-client.cjs.map +1 -1
  84. package/dist/http/api-client.js +80 -74
  85. package/dist/http/api-client.js.map +1 -1
  86. package/dist/http/decode-response.cjs +2 -0
  87. package/dist/http/decode-response.cjs.map +1 -0
  88. package/dist/http/decode-response.js +28 -0
  89. package/dist/http/decode-response.js.map +1 -0
  90. package/dist/styles/InstallButton.css +2 -0
  91. package/dist/styles/actions.css +6 -1
  92. package/dist/styles/advanced.css +4 -2
  93. package/dist/styles/chat.css +28 -0
  94. package/dist/styles/component/Chat.css +28 -0
  95. package/dist/styles/component/Command.css +1 -1
  96. package/dist/styles/component/ContextMenu.css +3 -1
  97. package/dist/styles/component/DropdownMenu.css +1 -1
  98. package/dist/styles/component/InstallBanner.css +2 -0
  99. package/dist/styles/component/InstallButton.css +4 -0
  100. package/dist/styles/component/SegmentedControl.css +1 -1
  101. package/dist/styles/component/Select.css +4 -0
  102. package/dist/styles/core.css +2 -2
  103. package/dist/styles/forms.css +4 -0
  104. package/dist/styles/manifest.json +14 -1
  105. package/dist/styles/navigation.css +1 -1
  106. package/dist/styles/tokens.css +2 -2
  107. package/dist/styles.css +1 -1
  108. package/dist/tempest-react-sdk.cjs +1 -1
  109. package/dist/tempest-react-sdk.d.ts +511 -36
  110. package/dist/tempest-react-sdk.js +319 -316
  111. package/dist/theme/ThemeProvider.cjs +1 -1
  112. package/dist/theme/ThemeProvider.cjs.map +1 -1
  113. package/dist/theme/ThemeProvider.js +40 -45
  114. package/dist/theme/ThemeProvider.js.map +1 -1
  115. package/dist/theme/create-theme.cjs +3 -3
  116. package/dist/theme/create-theme.cjs.map +1 -1
  117. package/dist/theme/create-theme.js +109 -57
  118. package/dist/theme/create-theme.js.map +1 -1
  119. package/dist/theme/initial-theme.cjs +2 -2
  120. package/dist/theme/initial-theme.cjs.map +1 -1
  121. package/dist/theme/initial-theme.js +7 -12
  122. package/dist/theme/initial-theme.js.map +1 -1
  123. package/dist/utils/format.cjs +1 -1
  124. package/dist/utils/format.cjs.map +1 -1
  125. package/dist/utils/format.js +5 -3
  126. package/dist/utils/format.js.map +1 -1
  127. package/dist/utils/storage.cjs +1 -1
  128. package/dist/utils/storage.cjs.map +1 -1
  129. package/dist/utils/storage.js +13 -0
  130. package/dist/utils/storage.js.map +1 -1
  131. package/loader/css-loader-hooks.mjs +37 -0
  132. package/loader/css-loader.mjs +46 -0
  133. package/package.json +3 -1
@@ -1 +1 @@
1
- {"version":3,"file":"storage.cjs","names":[],"sources":["../../src/utils/storage.ts"],"sourcesContent":["/** How a {@link createJsonStorage} store turns values into text and back. */\nexport interface StorageCodec {\n /** Encode a value for storage. */\n serialize: <T>(value: T) => string;\n /** Decode a stored string. */\n deserialize: <T>(raw: string) => T;\n}\n\n/** The surface every store built by {@link createJsonStorage} exposes. */\nexport interface JsonStorage {\n /**\n * Read and decode a key.\n *\n * @typeParam T - The expected value shape.\n * @param key - Storage key.\n * @param fallback - Returned when the key is absent, unreadable, or corrupt.\n * @returns The stored value, or `fallback`.\n */\n get<T>(key: string, fallback: T): T;\n /**\n * Encode and write a key.\n *\n * @typeParam T - The value being stored.\n * @param key - Storage key.\n * @param value - Any value the codec can represent.\n */\n set<T>(key: string, value: T): void;\n /**\n * Delete a key.\n *\n * @param key - Storage key.\n */\n remove(key: string): void;\n}\n\nconst jsonCodec: StorageCodec = {\n serialize: (value) => JSON.stringify(value),\n deserialize: (raw) => JSON.parse(raw),\n};\n\n/**\n * Encode with the codec, degrading to plain JSON when the codec itself fails.\n *\n * A codec that throws — a compressor running out of room on a huge value —\n * should cost size, not the record: a slightly larger row still loads, an absent\n * one does not. `null` means not even JSON could represent the value, which is\n * the one case where dropping the write is the only option left.\n *\n * @param codec - The store's codec.\n * @param value - The value to encode.\n * @returns The encoded string, or `null` when the value cannot be represented.\n */\nfunction encode<T>(codec: StorageCodec, value: T): string | null {\n try {\n return codec.serialize(value);\n } catch {\n try {\n return JSON.stringify(value);\n } catch {\n return null;\n }\n }\n}\n\n/**\n * Build a typed `localStorage` wrapper around a codec.\n *\n * One implementation behind every store the SDK ships, so they cannot drift in\n * surface. {@link storage} and {@link compressedStorage} are both this function —\n * before it, the compressed one was a hand-written copy of the same guards and\n * had no `remove`, while its own docstring promised the two were interchangeable\n * at the call site. They were not, and the promise failed exactly where somebody\n * followed it.\n *\n * @example\n * const session = createJsonStorage();\n * session.set(\"draft\", { title: \"Sem título\" });\n *\n * @example\n * const packed = createJsonStorage(compressedStorageCodec);\n *\n * @param codec - Encoder pair. Defaults to plain JSON.\n * @returns A store with `get` / `set` / `remove`.\n *\n * @tempest-limits empty-catch — every method is best-effort by contract:\n * `localStorage` throws on quota exhaustion, in Safari private mode, and when a\n * cross-origin frame has storage blocked. A caller persisting a preference has no\n * recovery to run and no user-facing message to show, so the write is dropped and\n * the app keeps the value in memory for the session.\n */\nexport function createJsonStorage(codec: StorageCodec = jsonCodec): JsonStorage {\n return {\n get<T>(key: string, fallback: T): T {\n if (typeof window === \"undefined\") return fallback;\n try {\n const raw = window.localStorage.getItem(key);\n return raw === null ? fallback : codec.deserialize<T>(raw);\n } catch {\n return fallback;\n }\n },\n\n set<T>(key: string, value: T): void {\n if (typeof window === \"undefined\") return;\n const encoded = encode(codec, value);\n if (encoded === null) return;\n try {\n window.localStorage.setItem(key, encoded);\n } catch {\n /* empty */\n }\n },\n\n remove(key: string): void {\n if (typeof window === \"undefined\") return;\n try {\n window.localStorage.removeItem(key);\n } catch {\n /* empty */\n }\n },\n };\n}\n\n/**\n * Typed wrapper around `localStorage` that JSON-encodes values and silently\n * handles environments where storage is unavailable (SSR, private mode).\n */\nexport const storage: JsonStorage = createJsonStorage();\n"],"mappings":"AAmCA,IAAM,EAA0B,CAC5B,UAAY,GAAU,KAAK,UAAU,CAAK,EAC1C,YAAc,GAAQ,KAAK,MAAM,CAAG,CACxC,EAcA,SAAS,EAAU,EAAqB,EAAyB,CAC7D,GAAI,CACA,OAAO,EAAM,UAAU,CAAK,CAChC,MAAQ,CACJ,GAAI,CACA,OAAO,KAAK,UAAU,CAAK,CAC/B,MAAQ,CACJ,OAAO,IACX,CACJ,CACJ,CA4BA,SAAgB,EAAkB,EAAsB,EAAwB,CAC5E,MAAO,CACH,IAAO,EAAa,EAAgB,CAChC,GAAI,OAAO,OAAW,IAAa,OAAO,EAC1C,GAAI,CACA,IAAM,EAAM,OAAO,aAAa,QAAQ,CAAG,EAC3C,OAAO,IAAQ,KAAO,EAAW,EAAM,YAAe,CAAG,CAC7D,MAAQ,CACJ,OAAO,CACX,CACJ,EAEA,IAAO,EAAa,EAAgB,CAChC,GAAI,OAAO,OAAW,IAAa,OACnC,IAAM,EAAU,EAAO,EAAO,CAAK,EAC/B,OAAY,KAChB,GAAI,CACA,OAAO,aAAa,QAAQ,EAAK,CAAO,CAC5C,MAAQ,CAER,CACJ,EAEA,OAAO,EAAmB,CAClB,YAAO,OAAW,KACtB,GAAI,CACA,OAAO,aAAa,WAAW,CAAG,CACtC,MAAQ,CAER,CACJ,CACJ,CACJ,CAMA,IAAa,EAAuB,EAAkB"}
1
+ {"version":3,"file":"storage.cjs","names":[],"sources":["../../src/utils/storage.ts"],"sourcesContent":["/** How a {@link createJsonStorage} store turns values into text and back. */\nexport interface StorageCodec {\n /** Encode a value for storage. */\n serialize: <T>(value: T) => string;\n /** Decode a stored string. */\n deserialize: <T>(raw: string) => T;\n}\n\n/** The surface every store built by {@link createJsonStorage} exposes. */\nexport interface JsonStorage {\n /**\n * Read and decode a key.\n *\n * The value is decoded by the store's codec — JSON for {@link storage} —\n * which is what makes a key written as a bare string unreadable here: it is\n * not the shape this method writes. {@link JsonStorage.getRaw} reads those.\n *\n * @typeParam T - The expected value shape.\n * @param key - Storage key.\n * @param fallback - Returned when the key is absent, unreadable, or corrupt.\n * @returns The stored value, or `fallback`.\n */\n get<T>(key: string, fallback: T): T;\n /**\n * Encode and write a key.\n *\n * The value is **encoded** — `set(\"theme\", \"dark\")` stores `\"dark\"` with the\n * quotes, not `dark`. That matters when an existing key is being adopted:\n * whatever read it before will no longer recognise what this writes, and the\n * old value will no longer parse here. {@link JsonStorage.setRaw} is the\n * passthrough.\n *\n * @typeParam T - The value being stored.\n * @param key - Storage key.\n * @param value - Any value the codec can represent.\n */\n set<T>(key: string, value: T): void;\n /**\n * Read a key exactly as `localStorage` holds it, with no decoding.\n *\n * The escape hatch {@link JsonStorage.get} cannot be: `get` runs the codec,\n * so a key holding a bare `dark` — written by another library, by the app\n * before it adopted this wrapper, or by the SDK's own `ThemeProvider` —\n * fails to parse and comes back as the fallback. Reading that key is a\n * different operation, not a variant of the same one.\n *\n * @param key - Storage key.\n * @returns The stored string, or `null` when the key is absent or storage is\n * unavailable.\n */\n getRaw(key: string): string | null;\n /**\n * Write a string exactly as given, with no encoding.\n *\n * The counterpart of {@link JsonStorage.getRaw}, and what keeps adoption from\n * being a silent migration: `set(\"theme\", \"dark\")` stores `\"dark\"` **with the\n * quotes**, which the app's previous reader no longer recognises.\n *\n * @param key - Storage key.\n * @param value - The exact string to store.\n */\n setRaw(key: string, value: string): void;\n /**\n * Delete a key.\n *\n * @param key - Storage key.\n */\n remove(key: string): void;\n}\n\nconst jsonCodec: StorageCodec = {\n serialize: (value) => JSON.stringify(value),\n deserialize: (raw) => JSON.parse(raw),\n};\n\n/**\n * Encode with the codec, degrading to plain JSON when the codec itself fails.\n *\n * A codec that throws — a compressor running out of room on a huge value —\n * should cost size, not the record: a slightly larger row still loads, an absent\n * one does not. `null` means not even JSON could represent the value, which is\n * the one case where dropping the write is the only option left.\n *\n * @param codec - The store's codec.\n * @param value - The value to encode.\n * @returns The encoded string, or `null` when the value cannot be represented.\n */\nfunction encode<T>(codec: StorageCodec, value: T): string | null {\n try {\n return codec.serialize(value);\n } catch {\n try {\n return JSON.stringify(value);\n } catch {\n return null;\n }\n }\n}\n\n/**\n * Build a typed `localStorage` wrapper around a codec.\n *\n * One implementation behind every store the SDK ships, so they cannot drift in\n * surface. {@link storage} and {@link compressedStorage} are both this function —\n * before it, the compressed one was a hand-written copy of the same guards and\n * had no `remove`, while its own docstring promised the two were interchangeable\n * at the call site. They were not, and the promise failed exactly where somebody\n * followed it.\n *\n * @example\n * const session = createJsonStorage();\n * session.set(\"draft\", { title: \"Sem título\" });\n *\n * @example\n * const packed = createJsonStorage(compressedStorageCodec);\n *\n * @param codec - Encoder pair. Defaults to plain JSON.\n * @returns A store with `get` / `set` / `getRaw` / `setRaw` / `remove`.\n *\n * @tempest-limits empty-catch — every method is best-effort by contract:\n * `localStorage` throws on quota exhaustion, in Safari private mode, and when a\n * cross-origin frame has storage blocked. A caller persisting a preference has no\n * recovery to run and no user-facing message to show, so the write is dropped and\n * the app keeps the value in memory for the session.\n */\nexport function createJsonStorage(codec: StorageCodec = jsonCodec): JsonStorage {\n return {\n get<T>(key: string, fallback: T): T {\n if (typeof window === \"undefined\") return fallback;\n try {\n const raw = window.localStorage.getItem(key);\n return raw === null ? fallback : codec.deserialize<T>(raw);\n } catch {\n return fallback;\n }\n },\n\n set<T>(key: string, value: T): void {\n if (typeof window === \"undefined\") return;\n const encoded = encode(codec, value);\n if (encoded === null) return;\n try {\n window.localStorage.setItem(key, encoded);\n } catch {\n /* empty */\n }\n },\n\n getRaw(key: string): string | null {\n if (typeof window === \"undefined\") return null;\n try {\n return window.localStorage.getItem(key);\n } catch {\n return null;\n }\n },\n\n setRaw(key: string, value: string): void {\n if (typeof window === \"undefined\") return;\n try {\n window.localStorage.setItem(key, value);\n } catch {\n /* empty */\n }\n },\n\n remove(key: string): void {\n if (typeof window === \"undefined\") return;\n try {\n window.localStorage.removeItem(key);\n } catch {\n /* empty */\n }\n },\n };\n}\n\n/**\n * Typed wrapper around `localStorage` that JSON-encodes values and silently\n * handles environments where storage is unavailable (SSR, private mode).\n *\n * `get`/`set` encode; `getRaw`/`setRaw` do not. Reach for the raw pair when the\n * key is shared with something that does not speak JSON — an existing key in an\n * app adopting this wrapper, a key another library owns, or the theme\n * preference the SDK's own `ThemeProvider` stores as a bare string.\n */\nexport const storage: JsonStorage = createJsonStorage();\n"],"mappings":"AAsEA,IAAM,EAA0B,CAC5B,UAAY,GAAU,KAAK,UAAU,CAAK,EAC1C,YAAc,GAAQ,KAAK,MAAM,CAAG,CACxC,EAcA,SAAS,EAAU,EAAqB,EAAyB,CAC7D,GAAI,CACA,OAAO,EAAM,UAAU,CAAK,CAChC,MAAQ,CACJ,GAAI,CACA,OAAO,KAAK,UAAU,CAAK,CAC/B,MAAQ,CACJ,OAAO,IACX,CACJ,CACJ,CA4BA,SAAgB,EAAkB,EAAsB,EAAwB,CAC5E,MAAO,CACH,IAAO,EAAa,EAAgB,CAChC,GAAI,OAAO,OAAW,IAAa,OAAO,EAC1C,GAAI,CACA,IAAM,EAAM,OAAO,aAAa,QAAQ,CAAG,EAC3C,OAAO,IAAQ,KAAO,EAAW,EAAM,YAAe,CAAG,CAC7D,MAAQ,CACJ,OAAO,CACX,CACJ,EAEA,IAAO,EAAa,EAAgB,CAChC,GAAI,OAAO,OAAW,IAAa,OACnC,IAAM,EAAU,EAAO,EAAO,CAAK,EAC/B,OAAY,KAChB,GAAI,CACA,OAAO,aAAa,QAAQ,EAAK,CAAO,CAC5C,MAAQ,CAER,CACJ,EAEA,OAAO,EAA4B,CAC/B,GAAI,OAAO,OAAW,IAAa,OAAO,KAC1C,GAAI,CACA,OAAO,OAAO,aAAa,QAAQ,CAAG,CAC1C,MAAQ,CACJ,OAAO,IACX,CACJ,EAEA,OAAO,EAAa,EAAqB,CACjC,YAAO,OAAW,KACtB,GAAI,CACA,OAAO,aAAa,QAAQ,EAAK,CAAK,CAC1C,MAAQ,CAER,CACJ,EAEA,OAAO,EAAmB,CAClB,YAAO,OAAW,KACtB,GAAI,CACA,OAAO,aAAa,WAAW,CAAG,CACtC,MAAQ,CAER,CACJ,CACJ,CACJ,CAWA,IAAa,EAAuB,EAAkB"}
@@ -32,6 +32,19 @@ function n(n = e) {
32
32
  window.localStorage.setItem(e, i);
33
33
  } catch {}
34
34
  },
35
+ getRaw(e) {
36
+ if (typeof window > "u") return null;
37
+ try {
38
+ return window.localStorage.getItem(e);
39
+ } catch {
40
+ return null;
41
+ }
42
+ },
43
+ setRaw(e, t) {
44
+ if (!(typeof window > "u")) try {
45
+ window.localStorage.setItem(e, t);
46
+ } catch {}
47
+ },
35
48
  remove(e) {
36
49
  if (!(typeof window > "u")) try {
37
50
  window.localStorage.removeItem(e);
@@ -1 +1 @@
1
- {"version":3,"file":"storage.js","names":[],"sources":["../../src/utils/storage.ts"],"sourcesContent":["/** How a {@link createJsonStorage} store turns values into text and back. */\nexport interface StorageCodec {\n /** Encode a value for storage. */\n serialize: <T>(value: T) => string;\n /** Decode a stored string. */\n deserialize: <T>(raw: string) => T;\n}\n\n/** The surface every store built by {@link createJsonStorage} exposes. */\nexport interface JsonStorage {\n /**\n * Read and decode a key.\n *\n * @typeParam T - The expected value shape.\n * @param key - Storage key.\n * @param fallback - Returned when the key is absent, unreadable, or corrupt.\n * @returns The stored value, or `fallback`.\n */\n get<T>(key: string, fallback: T): T;\n /**\n * Encode and write a key.\n *\n * @typeParam T - The value being stored.\n * @param key - Storage key.\n * @param value - Any value the codec can represent.\n */\n set<T>(key: string, value: T): void;\n /**\n * Delete a key.\n *\n * @param key - Storage key.\n */\n remove(key: string): void;\n}\n\nconst jsonCodec: StorageCodec = {\n serialize: (value) => JSON.stringify(value),\n deserialize: (raw) => JSON.parse(raw),\n};\n\n/**\n * Encode with the codec, degrading to plain JSON when the codec itself fails.\n *\n * A codec that throws — a compressor running out of room on a huge value —\n * should cost size, not the record: a slightly larger row still loads, an absent\n * one does not. `null` means not even JSON could represent the value, which is\n * the one case where dropping the write is the only option left.\n *\n * @param codec - The store's codec.\n * @param value - The value to encode.\n * @returns The encoded string, or `null` when the value cannot be represented.\n */\nfunction encode<T>(codec: StorageCodec, value: T): string | null {\n try {\n return codec.serialize(value);\n } catch {\n try {\n return JSON.stringify(value);\n } catch {\n return null;\n }\n }\n}\n\n/**\n * Build a typed `localStorage` wrapper around a codec.\n *\n * One implementation behind every store the SDK ships, so they cannot drift in\n * surface. {@link storage} and {@link compressedStorage} are both this function —\n * before it, the compressed one was a hand-written copy of the same guards and\n * had no `remove`, while its own docstring promised the two were interchangeable\n * at the call site. They were not, and the promise failed exactly where somebody\n * followed it.\n *\n * @example\n * const session = createJsonStorage();\n * session.set(\"draft\", { title: \"Sem título\" });\n *\n * @example\n * const packed = createJsonStorage(compressedStorageCodec);\n *\n * @param codec - Encoder pair. Defaults to plain JSON.\n * @returns A store with `get` / `set` / `remove`.\n *\n * @tempest-limits empty-catch — every method is best-effort by contract:\n * `localStorage` throws on quota exhaustion, in Safari private mode, and when a\n * cross-origin frame has storage blocked. A caller persisting a preference has no\n * recovery to run and no user-facing message to show, so the write is dropped and\n * the app keeps the value in memory for the session.\n */\nexport function createJsonStorage(codec: StorageCodec = jsonCodec): JsonStorage {\n return {\n get<T>(key: string, fallback: T): T {\n if (typeof window === \"undefined\") return fallback;\n try {\n const raw = window.localStorage.getItem(key);\n return raw === null ? fallback : codec.deserialize<T>(raw);\n } catch {\n return fallback;\n }\n },\n\n set<T>(key: string, value: T): void {\n if (typeof window === \"undefined\") return;\n const encoded = encode(codec, value);\n if (encoded === null) return;\n try {\n window.localStorage.setItem(key, encoded);\n } catch {\n /* empty */\n }\n },\n\n remove(key: string): void {\n if (typeof window === \"undefined\") return;\n try {\n window.localStorage.removeItem(key);\n } catch {\n /* empty */\n }\n },\n };\n}\n\n/**\n * Typed wrapper around `localStorage` that JSON-encodes values and silently\n * handles environments where storage is unavailable (SSR, private mode).\n */\nexport const storage: JsonStorage = createJsonStorage();\n"],"mappings":";AAmCA,IAAM,IAA0B;CAC5B,YAAY,MAAU,KAAK,UAAU,CAAK;CAC1C,cAAc,MAAQ,KAAK,MAAM,CAAG;AACxC;AAcA,SAAS,EAAU,GAAqB,GAAyB;CAC7D,IAAI;EACA,OAAO,EAAM,UAAU,CAAK;CAChC,QAAQ;EACJ,IAAI;GACA,OAAO,KAAK,UAAU,CAAK;EAC/B,QAAQ;GACJ,OAAO;EACX;CACJ;AACJ;AA4BA,SAAgB,EAAkB,IAAsB,GAAwB;CAC5E,OAAO;EACH,IAAO,GAAa,GAAgB;GAChC,IAAI,OAAO,SAAW,KAAa,OAAO;GAC1C,IAAI;IACA,IAAM,IAAM,OAAO,aAAa,QAAQ,CAAG;IAC3C,OAAO,MAAQ,OAAO,IAAW,EAAM,YAAe,CAAG;GAC7D,QAAQ;IACJ,OAAO;GACX;EACJ;EAEA,IAAO,GAAa,GAAgB;GAChC,IAAI,OAAO,SAAW,KAAa;GACnC,IAAM,IAAU,EAAO,GAAO,CAAK;GAC/B,UAAY,MAChB,IAAI;IACA,OAAO,aAAa,QAAQ,GAAK,CAAO;GAC5C,QAAQ,CAER;EACJ;EAEA,OAAO,GAAmB;GAClB,aAAO,SAAW,MACtB,IAAI;IACA,OAAO,aAAa,WAAW,CAAG;GACtC,QAAQ,CAER;EACJ;CACJ;AACJ;AAMA,IAAa,IAAuB,EAAkB"}
1
+ {"version":3,"file":"storage.js","names":[],"sources":["../../src/utils/storage.ts"],"sourcesContent":["/** How a {@link createJsonStorage} store turns values into text and back. */\nexport interface StorageCodec {\n /** Encode a value for storage. */\n serialize: <T>(value: T) => string;\n /** Decode a stored string. */\n deserialize: <T>(raw: string) => T;\n}\n\n/** The surface every store built by {@link createJsonStorage} exposes. */\nexport interface JsonStorage {\n /**\n * Read and decode a key.\n *\n * The value is decoded by the store's codec — JSON for {@link storage} —\n * which is what makes a key written as a bare string unreadable here: it is\n * not the shape this method writes. {@link JsonStorage.getRaw} reads those.\n *\n * @typeParam T - The expected value shape.\n * @param key - Storage key.\n * @param fallback - Returned when the key is absent, unreadable, or corrupt.\n * @returns The stored value, or `fallback`.\n */\n get<T>(key: string, fallback: T): T;\n /**\n * Encode and write a key.\n *\n * The value is **encoded** — `set(\"theme\", \"dark\")` stores `\"dark\"` with the\n * quotes, not `dark`. That matters when an existing key is being adopted:\n * whatever read it before will no longer recognise what this writes, and the\n * old value will no longer parse here. {@link JsonStorage.setRaw} is the\n * passthrough.\n *\n * @typeParam T - The value being stored.\n * @param key - Storage key.\n * @param value - Any value the codec can represent.\n */\n set<T>(key: string, value: T): void;\n /**\n * Read a key exactly as `localStorage` holds it, with no decoding.\n *\n * The escape hatch {@link JsonStorage.get} cannot be: `get` runs the codec,\n * so a key holding a bare `dark` — written by another library, by the app\n * before it adopted this wrapper, or by the SDK's own `ThemeProvider` —\n * fails to parse and comes back as the fallback. Reading that key is a\n * different operation, not a variant of the same one.\n *\n * @param key - Storage key.\n * @returns The stored string, or `null` when the key is absent or storage is\n * unavailable.\n */\n getRaw(key: string): string | null;\n /**\n * Write a string exactly as given, with no encoding.\n *\n * The counterpart of {@link JsonStorage.getRaw}, and what keeps adoption from\n * being a silent migration: `set(\"theme\", \"dark\")` stores `\"dark\"` **with the\n * quotes**, which the app's previous reader no longer recognises.\n *\n * @param key - Storage key.\n * @param value - The exact string to store.\n */\n setRaw(key: string, value: string): void;\n /**\n * Delete a key.\n *\n * @param key - Storage key.\n */\n remove(key: string): void;\n}\n\nconst jsonCodec: StorageCodec = {\n serialize: (value) => JSON.stringify(value),\n deserialize: (raw) => JSON.parse(raw),\n};\n\n/**\n * Encode with the codec, degrading to plain JSON when the codec itself fails.\n *\n * A codec that throws — a compressor running out of room on a huge value —\n * should cost size, not the record: a slightly larger row still loads, an absent\n * one does not. `null` means not even JSON could represent the value, which is\n * the one case where dropping the write is the only option left.\n *\n * @param codec - The store's codec.\n * @param value - The value to encode.\n * @returns The encoded string, or `null` when the value cannot be represented.\n */\nfunction encode<T>(codec: StorageCodec, value: T): string | null {\n try {\n return codec.serialize(value);\n } catch {\n try {\n return JSON.stringify(value);\n } catch {\n return null;\n }\n }\n}\n\n/**\n * Build a typed `localStorage` wrapper around a codec.\n *\n * One implementation behind every store the SDK ships, so they cannot drift in\n * surface. {@link storage} and {@link compressedStorage} are both this function —\n * before it, the compressed one was a hand-written copy of the same guards and\n * had no `remove`, while its own docstring promised the two were interchangeable\n * at the call site. They were not, and the promise failed exactly where somebody\n * followed it.\n *\n * @example\n * const session = createJsonStorage();\n * session.set(\"draft\", { title: \"Sem título\" });\n *\n * @example\n * const packed = createJsonStorage(compressedStorageCodec);\n *\n * @param codec - Encoder pair. Defaults to plain JSON.\n * @returns A store with `get` / `set` / `getRaw` / `setRaw` / `remove`.\n *\n * @tempest-limits empty-catch — every method is best-effort by contract:\n * `localStorage` throws on quota exhaustion, in Safari private mode, and when a\n * cross-origin frame has storage blocked. A caller persisting a preference has no\n * recovery to run and no user-facing message to show, so the write is dropped and\n * the app keeps the value in memory for the session.\n */\nexport function createJsonStorage(codec: StorageCodec = jsonCodec): JsonStorage {\n return {\n get<T>(key: string, fallback: T): T {\n if (typeof window === \"undefined\") return fallback;\n try {\n const raw = window.localStorage.getItem(key);\n return raw === null ? fallback : codec.deserialize<T>(raw);\n } catch {\n return fallback;\n }\n },\n\n set<T>(key: string, value: T): void {\n if (typeof window === \"undefined\") return;\n const encoded = encode(codec, value);\n if (encoded === null) return;\n try {\n window.localStorage.setItem(key, encoded);\n } catch {\n /* empty */\n }\n },\n\n getRaw(key: string): string | null {\n if (typeof window === \"undefined\") return null;\n try {\n return window.localStorage.getItem(key);\n } catch {\n return null;\n }\n },\n\n setRaw(key: string, value: string): void {\n if (typeof window === \"undefined\") return;\n try {\n window.localStorage.setItem(key, value);\n } catch {\n /* empty */\n }\n },\n\n remove(key: string): void {\n if (typeof window === \"undefined\") return;\n try {\n window.localStorage.removeItem(key);\n } catch {\n /* empty */\n }\n },\n };\n}\n\n/**\n * Typed wrapper around `localStorage` that JSON-encodes values and silently\n * handles environments where storage is unavailable (SSR, private mode).\n *\n * `get`/`set` encode; `getRaw`/`setRaw` do not. Reach for the raw pair when the\n * key is shared with something that does not speak JSON — an existing key in an\n * app adopting this wrapper, a key another library owns, or the theme\n * preference the SDK's own `ThemeProvider` stores as a bare string.\n */\nexport const storage: JsonStorage = createJsonStorage();\n"],"mappings":";AAsEA,IAAM,IAA0B;CAC5B,YAAY,MAAU,KAAK,UAAU,CAAK;CAC1C,cAAc,MAAQ,KAAK,MAAM,CAAG;AACxC;AAcA,SAAS,EAAU,GAAqB,GAAyB;CAC7D,IAAI;EACA,OAAO,EAAM,UAAU,CAAK;CAChC,QAAQ;EACJ,IAAI;GACA,OAAO,KAAK,UAAU,CAAK;EAC/B,QAAQ;GACJ,OAAO;EACX;CACJ;AACJ;AA4BA,SAAgB,EAAkB,IAAsB,GAAwB;CAC5E,OAAO;EACH,IAAO,GAAa,GAAgB;GAChC,IAAI,OAAO,SAAW,KAAa,OAAO;GAC1C,IAAI;IACA,IAAM,IAAM,OAAO,aAAa,QAAQ,CAAG;IAC3C,OAAO,MAAQ,OAAO,IAAW,EAAM,YAAe,CAAG;GAC7D,QAAQ;IACJ,OAAO;GACX;EACJ;EAEA,IAAO,GAAa,GAAgB;GAChC,IAAI,OAAO,SAAW,KAAa;GACnC,IAAM,IAAU,EAAO,GAAO,CAAK;GAC/B,UAAY,MAChB,IAAI;IACA,OAAO,aAAa,QAAQ,GAAK,CAAO;GAC5C,QAAQ,CAER;EACJ;EAEA,OAAO,GAA4B;GAC/B,IAAI,OAAO,SAAW,KAAa,OAAO;GAC1C,IAAI;IACA,OAAO,OAAO,aAAa,QAAQ,CAAG;GAC1C,QAAQ;IACJ,OAAO;GACX;EACJ;EAEA,OAAO,GAAa,GAAqB;GACjC,aAAO,SAAW,MACtB,IAAI;IACA,OAAO,aAAa,QAAQ,GAAK,CAAK;GAC1C,QAAQ,CAER;EACJ;EAEA,OAAO,GAAmB;GAClB,aAAO,SAAW,MACtB,IAAI;IACA,OAAO,aAAa,WAAW,CAAG;GACtC,QAAQ,CAER;EACJ;CACJ;AACJ;AAWA,IAAa,IAAuB,EAAkB"}
@@ -0,0 +1,37 @@
1
+ /**
2
+ * ESM loader hooks that resolve a stylesheet import to an empty module.
3
+ *
4
+ * Runs on the loader thread, which is why it is a separate file from the
5
+ * `register()` call in `css-loader.mjs`.
6
+ */
7
+
8
+ const STYLESHEET = /\.(css|scss|sass|less)$/;
9
+
10
+ /**
11
+ * Resolve a stylesheet specifier without asking Node to identify its format.
12
+ *
13
+ * @param {string} specifier - The import specifier.
14
+ * @param {{ parentURL?: string }} context - Resolution context.
15
+ * @param {Function} next - The next hook in the chain.
16
+ * @returns {object} The resolution result.
17
+ */
18
+ export function resolve(specifier, context, next) {
19
+ if (!STYLESHEET.test(specifier)) return next(specifier, context);
20
+ const url = context.parentURL
21
+ ? new URL(specifier, context.parentURL).href
22
+ : new URL(specifier, "file:///").href;
23
+ return { url, format: "module", shortCircuit: true };
24
+ }
25
+
26
+ /**
27
+ * Load a stylesheet as an empty ES module.
28
+ *
29
+ * @param {string} url - The resolved URL.
30
+ * @param {object} context - Load context.
31
+ * @param {Function} next - The next hook in the chain.
32
+ * @returns {object} The load result.
33
+ */
34
+ export function load(url, context, next) {
35
+ if (!STYLESHEET.test(new URL(url).pathname)) return next(url, context);
36
+ return { format: "module", source: "", shortCircuit: true };
37
+ }
@@ -0,0 +1,46 @@
1
+ /**
2
+ * Let Node import this SDK without a bundler.
3
+ *
4
+ * Every component module imports its own stylesheet, which is what lets a bundler
5
+ * ship the CSS of the components an app mounts and drop the rest. Node has no
6
+ * loader for `.css`, so importing the package in plain Node — a script, a Jest
7
+ * suite with no stylesheet transform, anything reading the surface for
8
+ * introspection — fails at import time with:
9
+ *
10
+ * TypeError [ERR_UNKNOWN_FILE_EXTENSION]: Unknown file extension ".css"
11
+ *
12
+ * This registers the missing loader, for ESM and CommonJS both, and resolves every
13
+ * stylesheet to an empty module. Nothing about the styles is emulated: it makes the
14
+ * import a no-op, which is the correct answer in a context that paints nothing.
15
+ *
16
+ * Use it before importing the SDK:
17
+ *
18
+ * node --import tempest-react-sdk/node-css-loader your-script.mjs
19
+ *
20
+ * Or from inside a script, before the first import of the package:
21
+ *
22
+ * import "tempest-react-sdk/node-css-loader";
23
+ * const sdk = await import("tempest-react-sdk");
24
+ *
25
+ * A bundler needs none of this — it is the tool that has the CSS loader. Vitest
26
+ * handles stylesheets on its own too. This is for plain Node.
27
+ */
28
+
29
+ import { createRequire, register } from "node:module";
30
+
31
+ register("./css-loader-hooks.mjs", import.meta.url);
32
+
33
+ /**
34
+ * Teach `require` the same thing, for a CommonJS consumer.
35
+ *
36
+ * `register()` covers the ESM graph only; `require("…/Button.css")` would still
37
+ * reach the CommonJS extension table, which tries to parse the file as JavaScript.
38
+ */
39
+ const require = createRequire(import.meta.url);
40
+ /** @type {{ _extensions: Record<string, (module: { exports: unknown }, filename: string) => void> }} */
41
+ const Module = require("node:module");
42
+ for (const extension of [".css", ".scss", ".sass", ".less"]) {
43
+ Module._extensions[extension] = (module) => {
44
+ module.exports = {};
45
+ };
46
+ }
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "tempest-react-sdk",
3
- "version": "0.63.0",
3
+ "version": "0.65.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",
@@ -24,6 +24,7 @@
24
24
  "files": [
25
25
  "dist",
26
26
  "bin",
27
+ "loader",
27
28
  "template",
28
29
  "template-pwa",
29
30
  "README.md",
@@ -45,6 +46,7 @@
45
46
  "import": "./dist/tempest-react-sdk.js",
46
47
  "require": "./dist/tempest-react-sdk.cjs"
47
48
  },
49
+ "./node-css-loader": "./loader/css-loader.mjs",
48
50
  "./testing": {
49
51
  "types": "./dist/testing.d.ts",
50
52
  "import": "./dist/testing.js",