@jini-ai/ui 0.4.6 → 0.4.8

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 (151) hide show
  1. package/README.md +33 -0
  2. package/dist/features/admin-widgets/components/InfoTip.d.ts +23 -2
  3. package/dist/features/admin-widgets/components/InfoTip.hooks.d.ts +22 -2
  4. package/dist/features/admin-widgets/components/InfoTip.hooks.js +75 -28
  5. package/dist/features/admin-widgets/components/InfoTip.js +12 -4
  6. package/dist/features/admin-widgets/components/InfoTip.rules.d.ts +72 -0
  7. package/dist/features/admin-widgets/components/InfoTip.rules.js +68 -0
  8. package/dist/features/admin-widgets/components/SuggestInput/SuggestInput.d.ts +36 -0
  9. package/dist/features/admin-widgets/components/SuggestInput/SuggestInput.hooks.d.ts +58 -0
  10. package/dist/features/admin-widgets/components/SuggestInput/SuggestInput.hooks.js +66 -0
  11. package/dist/features/admin-widgets/components/SuggestInput/SuggestInput.js +24 -0
  12. package/dist/features/admin-widgets/components/useDebouncedHtmlPreview.hooks.d.ts +23 -0
  13. package/dist/features/admin-widgets/components/useDebouncedHtmlPreview.hooks.js +28 -0
  14. package/dist/features/admin-widgets/index.d.ts +9 -0
  15. package/dist/features/admin-widgets/index.js +5 -0
  16. package/dist/features/execution/constants.js +11 -10
  17. package/dist/features/execution/http-adapter.d.ts +3 -1
  18. package/dist/features/execution/http-adapter.js +9 -4
  19. package/dist/features/execution/index.d.ts +1 -1
  20. package/dist/features/execution/index.js +1 -1
  21. package/dist/features/execution/react/components/ByokProviderForm.d.ts +18 -1
  22. package/dist/features/execution/react/components/ByokProviderForm.js +14 -16
  23. package/dist/features/execution/react/components/LocalCliAgentCard.d.ts +5 -1
  24. package/dist/features/execution/react/components/LocalCliAgentCard.js +12 -87
  25. package/dist/features/execution/react/components/LocalCliAgentList.d.ts +4 -1
  26. package/dist/features/execution/react/components/LocalCliAgentList.js +13 -4
  27. package/dist/features/execution/react/components/LocalCliAgentSettings.d.ts +20 -0
  28. package/dist/features/execution/react/components/LocalCliAgentSettings.js +20 -0
  29. package/dist/features/execution/react/hooks/use-byok-field-validation.hooks.d.ts +24 -0
  30. package/dist/features/execution/react/hooks/use-byok-field-validation.hooks.js +27 -0
  31. package/dist/features/execution/react/hooks/useExecutionTab.js +10 -1
  32. package/dist/features/execution/react/hooks/useLocalCliAgentCard.d.ts +48 -0
  33. package/dist/features/execution/react/hooks/useLocalCliAgentCard.js +110 -0
  34. package/dist/features/execution/react/hooks/useLocalCliAgentList.d.ts +19 -0
  35. package/dist/features/execution/react/hooks/useLocalCliAgentList.js +13 -0
  36. package/dist/features/execution/rules.d.ts +13 -0
  37. package/dist/features/execution/rules.js +14 -0
  38. package/dist/features/execution/types.d.ts +2 -0
  39. package/dist/features/html-editor/canvas-embed-placeholders.d.ts +13 -1
  40. package/dist/features/html-editor/canvas-embed-placeholders.js +61 -12
  41. package/dist/features/html-editor/dom.d.ts +5 -0
  42. package/dist/features/html-editor/dom.js +10 -0
  43. package/dist/features/html-editor/editor-blocks.d.ts +71 -0
  44. package/dist/features/html-editor/editor-blocks.js +185 -0
  45. package/dist/features/html-editor/editor-serialization.d.ts +24 -0
  46. package/dist/features/html-editor/editor-serialization.js +110 -0
  47. package/dist/features/html-editor/index.d.ts +5 -0
  48. package/dist/features/html-editor/index.js +3 -0
  49. package/dist/features/html-editor/protected-elements.d.ts +64 -0
  50. package/dist/features/html-editor/protected-elements.js +189 -0
  51. package/dist/features/html-editor/react/components/InteractiveHtmlEditor.d.ts +6 -4
  52. package/dist/features/html-editor/react/components/InteractiveHtmlEditor.js +3 -3
  53. package/dist/features/html-editor/react/hooks/useInteractiveHtmlEditor.d.ts +9 -1
  54. package/dist/features/html-editor/react/hooks/useInteractiveHtmlEditor.js +107 -196
  55. package/dist/features/html-editor/source-splice.d.ts +23 -0
  56. package/dist/features/html-editor/source-splice.js +45 -0
  57. package/dist/features/i18n/dictionaries/settings-dialog.ar.js +4 -0
  58. package/dist/features/i18n/dictionaries/settings-dialog.bn.js +4 -0
  59. package/dist/features/i18n/dictionaries/settings-dialog.de.js +4 -0
  60. package/dist/features/i18n/dictionaries/settings-dialog.en.js +4 -0
  61. package/dist/features/i18n/dictionaries/settings-dialog.es.js +4 -0
  62. package/dist/features/i18n/dictionaries/settings-dialog.fa.js +4 -0
  63. package/dist/features/i18n/dictionaries/settings-dialog.fr.js +4 -0
  64. package/dist/features/i18n/dictionaries/settings-dialog.hi.js +4 -0
  65. package/dist/features/i18n/dictionaries/settings-dialog.hu.js +4 -0
  66. package/dist/features/i18n/dictionaries/settings-dialog.id.js +4 -0
  67. package/dist/features/i18n/dictionaries/settings-dialog.it.js +4 -0
  68. package/dist/features/i18n/dictionaries/settings-dialog.ja.js +4 -0
  69. package/dist/features/i18n/dictionaries/settings-dialog.ko.js +4 -0
  70. package/dist/features/i18n/dictionaries/settings-dialog.pl.js +4 -0
  71. package/dist/features/i18n/dictionaries/settings-dialog.pt-BR.js +4 -0
  72. package/dist/features/i18n/dictionaries/settings-dialog.ru.js +4 -0
  73. package/dist/features/i18n/dictionaries/settings-dialog.th.js +4 -0
  74. package/dist/features/i18n/dictionaries/settings-dialog.tr.js +4 -0
  75. package/dist/features/i18n/dictionaries/settings-dialog.uk.js +4 -0
  76. package/dist/features/i18n/dictionaries/settings-dialog.ur.js +4 -0
  77. package/dist/features/i18n/dictionaries/settings-dialog.zh-CN.js +4 -0
  78. package/dist/features/i18n/dictionaries/settings-dialog.zh-TW.js +4 -0
  79. package/dist/features/interactive-ui/interactive-ui.css +1 -1
  80. package/dist/features/interactive-ui/providers/native/data-table.js +8 -1
  81. package/dist/features/interactive-ui/providers/native/data-table.manifest.d.ts +3 -5
  82. package/dist/features/interactive-ui/providers/native/data-table.manifest.js +5 -7
  83. package/dist/features/interactive-ui/providers/recharts/bar-chart.js +8 -3
  84. package/dist/features/interactive-ui/providers/recharts/chart-config.d.ts +40 -0
  85. package/dist/features/interactive-ui/providers/recharts/chart-config.js +32 -0
  86. package/dist/features/interactive-ui/providers/recharts/chart-tokens.d.ts +18 -12
  87. package/dist/features/interactive-ui/providers/recharts/chart-tokens.js +6 -11
  88. package/dist/features/interactive-ui/providers/recharts/chart.d.ts +31 -0
  89. package/dist/features/interactive-ui/providers/recharts/chart.js +34 -0
  90. package/dist/features/interactive-ui/providers/recharts/line-chart.js +10 -3
  91. package/dist/features/interactive-ui/providers/recharts/pie-chart.js +8 -3
  92. package/dist/features/interactive-ui/providers/shadcn/button.d.ts +1 -1
  93. package/dist/features/interactive-ui/providers/shadcn/data-table.d.ts +5 -1
  94. package/dist/features/interactive-ui/providers/shadcn/data-table.js +26 -2
  95. package/dist/features/interactive-ui/providers/shadcn/data-table.manifest.d.ts +8 -1
  96. package/dist/features/interactive-ui/providers/shadcn/data-table.manifest.js +6 -3
  97. package/dist/features/interactive-ui/table-data.d.ts +25 -0
  98. package/dist/features/interactive-ui/table-data.js +36 -0
  99. package/dist/features/mcp-ui/escape.js +2 -6
  100. package/dist/features/mcp-ui/sandbox-proxy-link-forwarder.d.ts +26 -0
  101. package/dist/features/mcp-ui/sandbox-proxy-link-forwarder.js +40 -0
  102. package/dist/features/mcp-ui/sandbox-proxy.d.ts +5 -1
  103. package/dist/features/mcp-ui/sandbox-proxy.js +11 -0
  104. package/dist/features/mcp-ui/surfaces/bridge.js +9 -3
  105. package/dist/features/mcp-ui/surfaces/document.d.ts +11 -4
  106. package/dist/features/mcp-ui/surfaces/document.js +25 -3
  107. package/dist/features/mcp-ui/surfaces/outcome.js +1 -1
  108. package/dist/features/media-providers/constants.d.ts +0 -7
  109. package/dist/features/media-providers/constants.js +7 -15
  110. package/dist/features/media-providers/react/components/MediaProvidersTab.js +3 -2
  111. package/dist/features/media-providers/react/hooks/useMediaProvidersTab.js +6 -3
  112. package/dist/features/memory/dependencies.d.ts +2 -0
  113. package/dist/features/memory/dependencies.js +9 -25
  114. package/dist/features/memory/index.d.ts +1 -0
  115. package/dist/features/memory/index.js +1 -0
  116. package/dist/features/memory/react/MemoryPorts.d.ts +17 -0
  117. package/dist/features/memory/react/MemoryPorts.js +15 -0
  118. package/dist/features/memory/react/hooks/useMemoryConfig.hooks.d.ts +2 -2
  119. package/dist/features/memory/react/hooks/useMemoryConfig.hooks.js +7 -7
  120. package/dist/features/memory/react/hooks/useMemoryConnectors.hooks.d.ts +2 -3
  121. package/dist/features/memory/react/hooks/useMemoryConnectors.hooks.js +4 -5
  122. package/dist/features/memory/react/hooks/useMemoryEntries.hooks.d.ts +2 -3
  123. package/dist/features/memory/react/hooks/useMemoryEntries.hooks.js +4 -5
  124. package/dist/features/memory/react/hooks/useMemoryExtractions.hooks.js +2 -2
  125. package/dist/features/panel-kit/fetch-query/adapter.react.d.ts +2 -2
  126. package/dist/features/panel-kit/fetch-query/adapter.react.js +5 -3
  127. package/dist/features/panel-kit/fetch-query/adapter.tanstack.d.ts +11 -0
  128. package/dist/features/panel-kit/fetch-query/adapter.tanstack.js +212 -0
  129. package/dist/features/panel-kit/fetch-query/binding.react.d.ts +17 -0
  130. package/dist/features/panel-kit/fetch-query/binding.react.js +24 -0
  131. package/dist/features/panel-kit/fetch-query/environment.browser.d.ts +1 -1
  132. package/dist/features/panel-kit/fetch-query/index.d.ts +6 -3
  133. package/dist/features/panel-kit/fetch-query/index.js +2 -1
  134. package/dist/features/panel-kit/fetch-query/tanstack.d.ts +8 -0
  135. package/dist/features/panel-kit/fetch-query/tanstack.js +4 -0
  136. package/dist/features/panel-kit/helpers/standing-draft-recovery-message.d.ts +3 -1
  137. package/dist/features/panel-kit/helpers/standing-draft-recovery-message.js +9 -2
  138. package/dist/features/settings/dialog/styles/settings-dialog.css +169 -21
  139. package/dist/features/tabbed-dialog/styles/tabbed-dialog.css +91 -0
  140. package/dist/react/components/RemixIcon.d.ts +1 -41
  141. package/dist/react/components/RemixIcon.js +3 -176
  142. package/dist/react/components/RemixIcon.stylesheet.d.ts +84 -0
  143. package/dist/react/components/RemixIcon.stylesheet.js +208 -0
  144. package/dist/react/components/remixicon-font-recovery.d.ts +55 -0
  145. package/dist/react/components/remixicon-font-recovery.js +110 -0
  146. package/dist/styles/admin.css +8 -2
  147. package/package.json +25 -8
  148. package/dist/features/panel-kit/fetch-query/cache.d.ts +0 -123
  149. package/dist/features/panel-kit/fetch-query/cache.js +0 -231
  150. package/dist/features/panel-kit/fetch-query/types.d.ts +0 -91
  151. package/dist/features/panel-kit/fetch-query/types.js +0 -2
@@ -0,0 +1,55 @@
1
+ /** Native font/timer ports keep retries testable without module mocks or a real clock. */
2
+ export interface RemixIconFontSet {
3
+ load(font: string, text?: string): Promise<FontFace[]>;
4
+ check(font: string, text?: string): boolean;
5
+ add(face: FontFace): void;
6
+ }
7
+ export interface FontRetryTimers {
8
+ setTimeout(run: () => void, delay: number): unknown;
9
+ clearTimeout(handle: unknown): void;
10
+ }
11
+ interface RecoveryInput {
12
+ fonts: RemixIconFontSet;
13
+ timers: FontRetryTimers;
14
+ createFace(input: {
15
+ attempt: number;
16
+ }): Pick<FontFace, 'load'>;
17
+ }
18
+ /**
19
+ * Probe the existing icon face once, then retry with fresh faces after bounded backoff.
20
+ * A failed FontFace retains its rejected load promise, so loading that same face again cannot
21
+ * recover. Adding the loaded replacement to the set makes existing icons repaint automatically.
22
+ * Network/parse failures are consumed; exhaustion leaves the existing fallback in place.
23
+ * @param input Explicit font set, fresh-face factory, and timer ports.
24
+ * @param options Backoff delays in milliseconds, defaulting to 1s, 3s, 10s.
25
+ * @returns Dispose function cancelling pending work and suppressing late font registration.
26
+ * @complexity O(r) attempts and O(1) working space, where r is the supplied retry count.
27
+ * @example startRemixIconFontRecovery({ fonts, timers, createFace });
28
+ */
29
+ export declare function startRemixIconFontRecovery({ fonts, timers, createFace }: RecoveryInput, { retryDelays }?: {
30
+ retryDelays?: readonly number[];
31
+ }): () => void;
32
+ interface StylesheetRecoveryInput {
33
+ stylesheet: HTMLStyleElement | HTMLLinkElement;
34
+ fonts: RemixIconFontSet;
35
+ timers: FontRetryTimers;
36
+ baseUrl: string;
37
+ createFontFace(input: {
38
+ family: string;
39
+ source: string;
40
+ descriptors: FontFaceDescriptors;
41
+ }): FontFace;
42
+ }
43
+ /**
44
+ * Recover this package's single WOFF2 face using the owning stylesheet's resolved URL.
45
+ * CSSOM, rather than a bundled-module URL, preserves host asset rewriting and linked CSS bases.
46
+ * Cross-origin inaccessible sheets and overrides without our face are left to their owner.
47
+ * @returns Retry disposer, or a no-op when this sheet does not expose the RemixIcon face.
48
+ * @complexity O(n + r), where n is the owning sheet's rule count and r is the retry count.
49
+ * @example startRemixIconStylesheetRecovery({ stylesheet, fonts, timers, baseUrl, createFontFace });
50
+ */
51
+ export declare function startRemixIconStylesheetRecovery({ stylesheet, fonts, timers, baseUrl, createFontFace }: StylesheetRecoveryInput, options?: {
52
+ retryDelays?: readonly number[];
53
+ }): () => void;
54
+ export {};
55
+ //# sourceMappingURL=remixicon-font-recovery.d.ts.map
@@ -0,0 +1,110 @@
1
+ const FONT = '16px "remixicon"';
2
+ // Use a real private-use glyph: FontFaceSet.check alone also returns true for absent fonts.
3
+ const GLYPH = '\uea01';
4
+ /**
5
+ * Probe the existing icon face once, then retry with fresh faces after bounded backoff.
6
+ * A failed FontFace retains its rejected load promise, so loading that same face again cannot
7
+ * recover. Adding the loaded replacement to the set makes existing icons repaint automatically.
8
+ * Network/parse failures are consumed; exhaustion leaves the existing fallback in place.
9
+ * @param input Explicit font set, fresh-face factory, and timer ports.
10
+ * @param options Backoff delays in milliseconds, defaulting to 1s, 3s, 10s.
11
+ * @returns Dispose function cancelling pending work and suppressing late font registration.
12
+ * @complexity O(r) attempts and O(1) working space, where r is the supplied retry count.
13
+ * @example startRemixIconFontRecovery({ fonts, timers, createFace });
14
+ */
15
+ export function startRemixIconFontRecovery({ fonts, timers, createFace }, { retryDelays = [1000, 3000, 10000] } = {}) {
16
+ let stopped = false;
17
+ let attempt = 0;
18
+ let pending;
19
+ function scheduleRetry() {
20
+ if (stopped)
21
+ return;
22
+ const delay = retryDelays[attempt];
23
+ if (delay === undefined) {
24
+ stopped = true;
25
+ return;
26
+ }
27
+ pending = timers.setTimeout(() => {
28
+ pending = undefined;
29
+ void retry();
30
+ }, delay);
31
+ }
32
+ async function retry() {
33
+ if (stopped)
34
+ return;
35
+ attempt++;
36
+ try {
37
+ const face = await createFace({ attempt }).load();
38
+ if (stopped)
39
+ return;
40
+ fonts.add(face);
41
+ stopped = true;
42
+ }
43
+ catch {
44
+ scheduleRetry();
45
+ }
46
+ }
47
+ async function probe() {
48
+ try {
49
+ const faces = await fonts.load(FONT, GLYPH);
50
+ if (stopped)
51
+ return;
52
+ if (faces.length > 0 && fonts.check(FONT, GLYPH)) {
53
+ stopped = true;
54
+ return;
55
+ }
56
+ scheduleRetry();
57
+ }
58
+ catch {
59
+ scheduleRetry();
60
+ }
61
+ }
62
+ void probe();
63
+ return () => {
64
+ stopped = true;
65
+ if (pending !== undefined)
66
+ timers.clearTimeout(pending);
67
+ };
68
+ }
69
+ /**
70
+ * Recover this package's single WOFF2 face using the owning stylesheet's resolved URL.
71
+ * CSSOM, rather than a bundled-module URL, preserves host asset rewriting and linked CSS bases.
72
+ * Cross-origin inaccessible sheets and overrides without our face are left to their owner.
73
+ * @returns Retry disposer, or a no-op when this sheet does not expose the RemixIcon face.
74
+ * @complexity O(n + r), where n is the owning sheet's rule count and r is the retry count.
75
+ * @example startRemixIconStylesheetRecovery({ stylesheet, fonts, timers, baseUrl, createFontFace });
76
+ */
77
+ export function startRemixIconStylesheetRecovery({ stylesheet, fonts, timers, baseUrl, createFontFace }, options = {}) {
78
+ let rules;
79
+ try {
80
+ rules = stylesheet.sheet?.cssRules;
81
+ }
82
+ catch {
83
+ return () => { };
84
+ }
85
+ if (!rules)
86
+ return () => { };
87
+ for (const rule of Array.from(rules)) {
88
+ if (rule.type !== 5)
89
+ continue; // CSSRule.FONT_FACE_RULE (no global constructor in SSR/fakes).
90
+ const style = rule.style;
91
+ const family = style.getPropertyValue('font-family').replace(/["']/g, '').trim();
92
+ if (family !== 'remixicon')
93
+ continue;
94
+ // This package owns one url(...) WOFF2 source, not a general CSS font-source parser.
95
+ const source = style.getPropertyValue('src').match(/url\(\s*["']?([^"')]+)["']?\s*\)/)?.[1];
96
+ if (!source)
97
+ return () => { };
98
+ const url = new URL(source.trim(), stylesheet.sheet?.href ?? baseUrl);
99
+ return startRemixIconFontRecovery({ fonts, timers, createFace({ attempt }) {
100
+ // A distinct URL also bypasses the browser's cached failed font resource after a restart.
101
+ const freshUrl = new URL(url.href);
102
+ if (freshUrl.protocol === 'http:' || freshUrl.protocol === 'https:') {
103
+ freshUrl.searchParams.set('jini-font-retry', String(attempt));
104
+ }
105
+ return createFontFace({ family: 'remixicon', source: `url("${freshUrl.href}") format("woff2")`, descriptors: { display: 'swap' } });
106
+ } }, options);
107
+ }
108
+ return () => { };
109
+ }
110
+ //# sourceMappingURL=remixicon-font-recovery.js.map
@@ -188,6 +188,12 @@
188
188
  }
189
189
 
190
190
  .info-tip { position: relative; display: inline-flex; margin-left: 0.35rem; vertical-align: middle; }
191
+ /* In a wrapping label row, inline help takes a full row and pushes fields down safely. */
192
+ .info-tip.info-tip--inline { display: contents; }
193
+ .info-tip-inline-copy {
194
+ flex-basis: 100%; font-size: var(--jini-font-size-xs, 12px); font-weight: 400;
195
+ line-height: 1.5; color: var(--jini-text-muted); overflow-wrap: anywhere;
196
+ }
191
197
  .info-tip-icon {
192
198
  display: inline-flex; align-items: center; justify-content: center;
193
199
  width: 1.1rem; height: 1.1rem; border-radius: 50%; color: var(--jini-text-disabled);
@@ -197,14 +203,14 @@
197
203
  .info-tip-icon:focus-visible { outline: 2px solid var(--jini-accent); outline-offset: 2px; border-radius: 50%; }
198
204
  .info-tip-bubble {
199
205
  position: fixed; transform: translate(-50%, calc(-100% - 8px));
200
- width: max-content; max-width: 18rem; padding: 0.55rem 0.75rem; border-radius: var(--jini-radius-sm);
206
+ width: max-content; max-width: min(18rem, calc(100vw - 16px)); padding: 0.55rem 0.75rem; border-radius: var(--jini-radius-sm);
201
207
  background: var(--jini-bg-panel); color: var(--jini-text); font-size: 0.78rem; font-weight: 400;
202
208
  line-height: 1.4; letter-spacing: normal; text-transform: none;
203
209
  box-shadow: 0 4px 16px var(--jini-backdrop); border: 1px solid var(--jini-border);
204
210
  pointer-events: none; z-index: 1000;
205
211
  }
206
212
  .info-tip-bubble::after {
207
- content: ""; position: absolute; top: 100%; left: 50%; transform: translateX(-50%);
213
+ content: ""; position: absolute; top: 100%; left: var(--info-tip-arrow-left, 50%); transform: translateX(-50%);
208
214
  border: 5px solid transparent; border-top-color: var(--jini-bg-panel);
209
215
  }
210
216
 
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@jini-ai/ui",
3
- "version": "0.4.6",
3
+ "version": "0.4.8",
4
4
  "description": "Generic, product-neutral React UI primitives and feature domains. Framework-free types, decision rules, catalogs, and host port contracts live behind ./core (no React, no DOM). The Excalidraw and Lexical editors live behind ./sketch-editor and ./lexical-rich-text-editor; the GrapesJS-backed inline HTML editor lives behind ./html-editor.",
5
5
  "license": "Apache-2.0",
6
6
  "repository": {
@@ -32,6 +32,7 @@
32
32
  "./admin-widgets": "browser",
33
33
  "./panel-kit": "browser",
34
34
  "./fetch-query": "browser",
35
+ "./fetch-query/tanstack": "browser",
35
36
  "./tab-strip": "browser",
36
37
  "./admin-widgets.css": "browser",
37
38
  "./theme": "browser",
@@ -39,7 +40,8 @@
39
40
  },
40
41
  "isolation": {
41
42
  "entries": {
42
- "./fetch-query": "panel-kit"
43
+ "./fetch-query": "panel-kit",
44
+ "./fetch-query/tanstack": "panel-kit"
43
45
  },
44
46
  "shared": [
45
47
  "src/theme/default.ts",
@@ -140,6 +142,11 @@
140
142
  "import": "./dist/features/panel-kit/fetch-query/index.js",
141
143
  "default": "./dist/features/panel-kit/fetch-query/index.js"
142
144
  },
145
+ "./fetch-query/tanstack": {
146
+ "types": "./dist/features/panel-kit/fetch-query/tanstack.d.ts",
147
+ "import": "./dist/features/panel-kit/fetch-query/tanstack.js",
148
+ "default": "./dist/features/panel-kit/fetch-query/tanstack.js"
149
+ },
143
150
  "./tab-strip": {
144
151
  "types": "./dist/features/tab-strip/index.d.ts",
145
152
  "import": "./dist/features/tab-strip/index.js",
@@ -171,6 +178,7 @@
171
178
  "registry": "https://registry.npmjs.org"
172
179
  },
173
180
  "devDependencies": {
181
+ "@tanstack/react-query": "^5.0.0",
174
182
  "@excalidraw/excalidraw": "0.18.1",
175
183
  "@lexical/react": "0.36.2",
176
184
  "@lexical/utils": "0.36.2",
@@ -202,14 +210,17 @@
202
210
  "shiki": "^1.24.4",
203
211
  "tailwind-merge": "^2.6.0",
204
212
  "zod": "^3.25.76",
205
- "@jini-ai/platform": "^0.5.2",
206
- "@jini-ai/agentic": "^0.4.3",
207
- "@jini-ai/core": "^0.4.2"
213
+ "@jini-ai/integrations": "^0.4.2",
214
+ "@jini-ai/platform": "^0.5.3",
215
+ "@jini-ai/core": "^0.4.3",
216
+ "@jini-ai/agentic": "^0.4.4"
208
217
  },
209
218
  "dependencies": {
210
- "@jini-ai/core": "^0.4.2"
219
+ "@jini-ai/core": "^0.4.3"
211
220
  },
212
221
  "peerDependencies": {
222
+ "@jini-ai/integrations": "^0.4.2",
223
+ "@tanstack/react-query": "^5.0.0",
213
224
  "@excalidraw/excalidraw": "0.18.1",
214
225
  "@lexical/react": "0.36.2",
215
226
  "@lexical/utils": "0.36.2",
@@ -224,8 +235,8 @@
224
235
  "react": "^18.3.0 || ^19.0.0",
225
236
  "react-dom": "^18.3.0 || ^19.0.0",
226
237
  "recharts": "^3.10.1",
227
- "@jini-ai/platform": "^0.5.1",
228
- "@jini-ai/agentic": "^0.4.2",
238
+ "@jini-ai/platform": "^0.5.3",
239
+ "@jini-ai/agentic": "^0.4.4",
229
240
  "class-variance-authority": "^0.7.1",
230
241
  "clsx": "^2.1.1",
231
242
  "micromark": "^4.0.0",
@@ -236,6 +247,12 @@
236
247
  "zod": "^3.25.76"
237
248
  },
238
249
  "peerDependenciesMeta": {
250
+ "@jini-ai/integrations": {
251
+ "optional": true
252
+ },
253
+ "@tanstack/react-query": {
254
+ "optional": true
255
+ },
239
256
  "@excalidraw/excalidraw": {
240
257
  "optional": true
241
258
  },
@@ -1,123 +0,0 @@
1
- import type { Clock } from '@jini-ai/core/primitives';
2
- import type { QueryKey } from './types.js';
3
- /**
4
- * Ten seconds covers reading, closing and reopening a record or bouncing between screens
5
- * without paying for another identical request. Five seconds was too short for that read
6
- * cycle; thirty seconds exposed more other-operator staleness than the conservative initial
7
- * shared default should allow. There is no default polling/focus refresh, so this bounds
8
- * the extra exposure on a quick revisit. Write invalidation bypasses freshness; reads that
9
- * must be fresh on every mount can choose staleTime: 0 without lowering every query default.
10
- */
11
- export declare const DEFAULT_STALE_TIME = 10000;
12
- export interface QueryCacheSchedulerPort {
13
- schedule(required: {
14
- callback: () => void;
15
- delayMs: number;
16
- }): unknown;
17
- cancel(required: {
18
- handle: unknown;
19
- }): void;
20
- }
21
- /** Host connectivity and focus signals; the cache itself has no DOM dependency. */
22
- export interface FetchQueryEnvironmentPort {
23
- isOnline(): boolean;
24
- subscribeOnline(required: {
25
- listener: (online: boolean) => void;
26
- }): () => void;
27
- subscribeFocus(required: {
28
- listener: () => void;
29
- }): () => void;
30
- }
31
- export interface FetchQueryCacheOptions {
32
- clock?: Clock;
33
- scheduler?: QueryCacheSchedulerPort;
34
- environment?: FetchQueryEnvironmentPort;
35
- }
36
- export interface QueryState {
37
- data: unknown;
38
- error: Error | null;
39
- status: 'pending' | 'success' | 'error';
40
- isFetching: boolean;
41
- }
42
- export interface QueryObserver {
43
- fetch: () => Promise<unknown>;
44
- staleTime: number;
45
- focus: boolean;
46
- }
47
- export interface CacheEntry {
48
- key: QueryKey;
49
- state: QueryState;
50
- updatedAt: number;
51
- invalidated: boolean;
52
- replacement: number;
53
- pending: Promise<unknown> | undefined;
54
- refreshAfterPending: boolean;
55
- listeners: Set<() => void>;
56
- observers: Set<QueryObserver>;
57
- retention: number;
58
- eviction: unknown;
59
- }
60
- export declare function toQueryError(value: unknown): Error;
61
- /** One provider-owned cache. Requests are shared by structural primitive keys.
62
- * Failed reads retain earlier data; replacement writes supersede older requests.
63
- * Idle entries live for at least five minutes or their declared freshness period. */
64
- export declare class FetchQueryCache {
65
- private readonly entries;
66
- private disposed;
67
- private readonly clock;
68
- private readonly scheduler;
69
- private readonly environment;
70
- private online;
71
- private readonly onlineWaiters;
72
- private releaseEnvironment;
73
- constructor(_required?: Record<string, never>, { clock, scheduler, environment }?: FetchQueryCacheOptions);
74
- entry({ key }: {
75
- key: QueryKey;
76
- }, { staleTime }?: {
77
- staleTime?: number;
78
- }): CacheEntry;
79
- fresh({ entry, staleTime }: {
80
- entry: CacheEntry;
81
- staleTime: number;
82
- }): boolean;
83
- subscribe({ entry, listener }: {
84
- entry: CacheEntry;
85
- listener: () => void;
86
- }): () => void;
87
- observe({ entry, observer }: {
88
- entry: CacheEntry;
89
- observer: QueryObserver;
90
- }): () => void;
91
- /** Cache hits respect freshness; explicit refreshes restart background reads.
92
- * Initial reads still deduplicate because no earlier successful data exists to refresh. */
93
- load<T>({ entry, fetch, staleTime }: {
94
- entry: CacheEntry;
95
- fetch: () => Promise<T>;
96
- staleTime: number;
97
- }, { force }?: {
98
- force?: boolean;
99
- }): Promise<T>;
100
- replace({ entry, data }: {
101
- entry: CacheEntry;
102
- data: unknown;
103
- }): void;
104
- invalidate({ prefix }: {
105
- prefix: QueryKey;
106
- }): void;
107
- onFocus(): void;
108
- /** Execute a read/write once connectivity returns; failures are not retried.
109
- * @param required.run Operation to invoke online.
110
- * @returns The operation's original result or rejection. */
111
- runOnline<T>({ run }: {
112
- run: () => Promise<T>;
113
- }): Promise<T>;
114
- /** Stop timers on provider disposal; reactivate for React's effect replay. */
115
- activate(): void;
116
- dispose(): void;
117
- private onOnline;
118
- private refresh;
119
- private publish;
120
- private cancelEviction;
121
- private scheduleEviction;
122
- }
123
- //# sourceMappingURL=cache.d.ts.map
@@ -1,231 +0,0 @@
1
- /**
2
- * Ten seconds covers reading, closing and reopening a record or bouncing between screens
3
- * without paying for another identical request. Five seconds was too short for that read
4
- * cycle; thirty seconds exposed more other-operator staleness than the conservative initial
5
- * shared default should allow. There is no default polling/focus refresh, so this bounds
6
- * the extra exposure on a quick revisit. Write invalidation bypasses freshness; reads that
7
- * must be fresh on every mount can choose staleTime: 0 without lowering every query default.
8
- */
9
- export const DEFAULT_STALE_TIME = 10_000;
10
- const IDLE_RETENTION = 5 * 60_000;
11
- const browserScheduler = {
12
- schedule: ({ callback, delayMs }) => setTimeout(callback, delayMs),
13
- cancel: ({ handle }) => clearTimeout(handle),
14
- };
15
- // Normalize unknown promise rejections once so consumers receive Error without repeating
16
- // the same narrowing boilerplate at every read and write call site.
17
- export function toQueryError(value) {
18
- return value instanceof Error ? value : new Error(typeof value === 'string' && value.trim() ? value : 'request failed');
19
- }
20
- /** One provider-owned cache. Requests are shared by structural primitive keys.
21
- * Failed reads retain earlier data; replacement writes supersede older requests.
22
- * Idle entries live for at least five minutes or their declared freshness period. */
23
- export class FetchQueryCache {
24
- entries = new Map();
25
- disposed = false;
26
- clock;
27
- scheduler;
28
- environment;
29
- online;
30
- onlineWaiters = new Set();
31
- releaseEnvironment;
32
- constructor(_required = {}, { clock = { nowMs: () => Date.now() }, scheduler = browserScheduler, environment } = {}) {
33
- this.clock = clock;
34
- this.scheduler = scheduler;
35
- this.environment = environment;
36
- this.online = environment?.isOnline() ?? true;
37
- }
38
- entry({ key }, { staleTime = DEFAULT_STALE_TIME } = {}) {
39
- const hash = JSON.stringify(key);
40
- let entry = this.entries.get(hash);
41
- if (!entry) {
42
- entry = {
43
- key: [...key], state: { data: undefined, error: null, status: 'pending', isFetching: false },
44
- updatedAt: 0, invalidated: false, replacement: 0, pending: undefined,
45
- refreshAfterPending: false, listeners: new Set(), observers: new Set(),
46
- retention: IDLE_RETENTION, eviction: undefined,
47
- };
48
- this.entries.set(hash, entry);
49
- }
50
- // An imperative load has no standing observer: idle eviction must not drop a value
51
- // earlier than its declared freshness and unexpectedly force another network request.
52
- entry.retention = Math.max(entry.retention, staleTime);
53
- return entry;
54
- }
55
- fresh({ entry, staleTime }) {
56
- return entry.state.data !== undefined && !entry.invalidated && this.clock.nowMs() - entry.updatedAt < staleTime;
57
- }
58
- subscribe({ entry, listener }) {
59
- this.cancelEviction(entry);
60
- entry.listeners.add(listener);
61
- return () => { entry.listeners.delete(listener); this.scheduleEviction(entry); };
62
- }
63
- observe({ entry, observer }) {
64
- entry.observers.add(observer);
65
- return () => { entry.observers.delete(observer); this.scheduleEviction(entry); };
66
- }
67
- /** Cache hits respect freshness; explicit refreshes restart background reads.
68
- * Initial reads still deduplicate because no earlier successful data exists to refresh. */
69
- load({ entry, fetch, staleTime }, { force = false } = {}) {
70
- this.cancelEviction(entry);
71
- if (entry.pending && (!force || entry.state.data === undefined))
72
- return entry.pending;
73
- if (!force && this.fresh({ entry: entry, staleTime: staleTime })) {
74
- this.scheduleEviction(entry);
75
- return Promise.resolve(entry.state.data);
76
- }
77
- // Shared per key across loader instances: a replacement while this request is out
78
- // must win over its older answer, not just protect the instance that issued the write.
79
- const replacement = entry.replacement;
80
- const run = () => {
81
- // A queued offline refresh may have been superseded before reconnection.
82
- if (entry.pending !== pending)
83
- return (entry.pending ?? Promise.resolve(entry.state.data));
84
- this.publish(entry, { ...entry.state, isFetching: true });
85
- return fetch();
86
- };
87
- const pending = Promise.resolve().then(() => {
88
- if (this.online)
89
- return run();
90
- this.publish(entry, { ...entry.state, isFetching: false });
91
- return this.runOnline({ run });
92
- }).then(value => {
93
- const data = replacement === entry.replacement ? value : entry.state.data;
94
- // Undefined is never successful query data, including an initial or background read.
95
- if (data === undefined)
96
- throw new Error(`${JSON.stringify(entry.key)} data is undefined`);
97
- return data;
98
- }).then(data => {
99
- // Only the current request may publish or clear invalidation. An older transport
100
- // need not support abort: its callers follow the replacement request instead.
101
- if (entry.pending !== pending)
102
- return (entry.pending ?? entry.state.data);
103
- entry.updatedAt = this.clock.nowMs();
104
- entry.invalidated = false;
105
- this.publish(entry, { data, error: null, status: 'success', isFetching: false });
106
- return data;
107
- }, error => {
108
- if (entry.pending !== pending)
109
- return (entry.pending ?? entry.state.data);
110
- // A replacement write is newer than this read's failure as well as its data.
111
- // Keep the write's timestamp and freshness; only settle the obsolete fetch flag.
112
- if (replacement !== entry.replacement) {
113
- this.publish(entry, { ...entry.state, isFetching: false });
114
- return entry.state.data;
115
- }
116
- entry.invalidated = true;
117
- this.publish(entry, { ...entry.state, error: toQueryError(error), status: 'error', isFetching: false });
118
- throw error;
119
- }).finally(() => {
120
- if (entry.pending !== pending)
121
- return;
122
- entry.pending = undefined;
123
- if (entry.refreshAfterPending) {
124
- entry.refreshAfterPending = false;
125
- this.refresh(entry);
126
- }
127
- this.scheduleEviction(entry);
128
- });
129
- entry.pending = pending;
130
- // Mark handled even when a UI caller deliberately discards the promise.
131
- void pending.catch(() => { });
132
- // Like TanStack's background refetches, retain the last error until success clears it
133
- // or another failure replaces it. Extend that rule to retries without cached data:
134
- // starting a request is not evidence of recovery; isFetching reports its progress.
135
- const state = entry.state.data === undefined ? { ...entry.state, status: 'pending' } : entry.state;
136
- this.publish(entry, { ...state, isFetching: this.online });
137
- return pending;
138
- }
139
- replace({ entry, data }) {
140
- entry.replacement += 1;
141
- entry.updatedAt = this.clock.nowMs();
142
- entry.invalidated = false;
143
- this.publish(entry, { data, error: null, status: 'success', isFetching: entry.state.isFetching });
144
- this.scheduleEviction(entry);
145
- }
146
- invalidate({ prefix }) {
147
- for (const entry of this.entries.values()) {
148
- if (!prefix.every((part, index) => entry.key[index] === part))
149
- continue;
150
- entry.invalidated = true;
151
- this.refresh(entry);
152
- }
153
- }
154
- onFocus() {
155
- for (const entry of this.entries.values()) {
156
- const observer = [...entry.observers].find(value => value.focus && !this.fresh({ entry: entry, staleTime: value.staleTime }));
157
- // Environmental refreshes share a request already underway, unlike an explicit gesture.
158
- if (observer && !entry.pending)
159
- void this.load({ entry: entry, fetch: observer.fetch, staleTime: observer.staleTime });
160
- }
161
- }
162
- /** Execute a read/write once connectivity returns; failures are not retried.
163
- * @param required.run Operation to invoke online.
164
- * @returns The operation's original result or rejection. */
165
- runOnline({ run }) {
166
- if (this.online)
167
- return Promise.resolve().then(() => {
168
- // Connectivity may change between queuing the operation and its invocation.
169
- if (!this.online)
170
- return this.runOnline({ run });
171
- return run();
172
- });
173
- return new Promise(resolve => { this.onlineWaiters.add(resolve); }).then(() => this.runOnline({ run }));
174
- }
175
- /** Stop timers on provider disposal; reactivate for React's effect replay. */
176
- activate() {
177
- this.disposed = false;
178
- if (!this.environment || this.releaseEnvironment)
179
- return;
180
- const releaseOnline = this.environment.subscribeOnline({ listener: online => this.onOnline({ online }) });
181
- const releaseFocus = this.environment.subscribeFocus({ listener: () => this.onFocus() });
182
- this.releaseEnvironment = () => { releaseOnline(); releaseFocus(); };
183
- this.onOnline({ online: this.environment.isOnline() });
184
- }
185
- dispose() {
186
- this.disposed = true;
187
- this.releaseEnvironment?.();
188
- this.releaseEnvironment = undefined;
189
- for (const entry of this.entries.values())
190
- this.cancelEviction(entry);
191
- }
192
- onOnline({ online }) {
193
- const reconnect = online && !this.online;
194
- this.online = online;
195
- if (!online)
196
- return;
197
- for (const resume of this.onlineWaiters)
198
- resume();
199
- this.onlineWaiters.clear();
200
- if (!reconnect)
201
- return;
202
- for (const entry of this.entries.values()) {
203
- const observer = [...entry.observers].find(value => !this.fresh({ entry, staleTime: value.staleTime }));
204
- // A paused request already owns its resumption; restarting it here would double-fetch.
205
- if (observer && !entry.pending)
206
- void this.load({ entry, fetch: observer.fetch, staleTime: observer.staleTime });
207
- }
208
- }
209
- refresh(entry) {
210
- const observer = entry.observers.values().next().value;
211
- if (observer)
212
- void this.load({ entry: entry, fetch: observer.fetch, staleTime: observer.staleTime }, { force: true });
213
- }
214
- publish(entry, state) {
215
- entry.state = state;
216
- for (const listener of entry.listeners)
217
- listener();
218
- }
219
- cancelEviction(entry) {
220
- if (entry.eviction !== undefined)
221
- this.scheduler.cancel({ handle: entry.eviction });
222
- entry.eviction = undefined;
223
- }
224
- scheduleEviction(entry) {
225
- this.cancelEviction(entry);
226
- if (this.disposed || entry.listeners.size || entry.observers.size || entry.pending || !Number.isFinite(entry.retention))
227
- return;
228
- entry.eviction = this.scheduler.schedule({ callback: () => this.entries.delete(JSON.stringify(entry.key)), delayMs: entry.retention });
229
- }
230
- }
231
- //# sourceMappingURL=cache.js.map