@iota-uz/sdk 0.3.4 → 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 (66) hide show
  1. package/README.md +117 -0
  2. package/dist/applet/core.cjs +251 -0
  3. package/dist/applet/core.cjs.map +1 -0
  4. package/dist/applet/core.d.cts +172 -0
  5. package/dist/applet/core.d.ts +172 -0
  6. package/dist/applet/core.mjs +237 -0
  7. package/dist/applet/core.mjs.map +1 -0
  8. package/dist/applet/devtools.cjs +131 -0
  9. package/dist/applet/devtools.cjs.map +1 -0
  10. package/dist/applet/devtools.d.cts +7 -0
  11. package/dist/applet/devtools.d.ts +7 -0
  12. package/dist/applet/devtools.mjs +128 -0
  13. package/dist/applet/devtools.mjs.map +1 -0
  14. package/dist/applet/host.cjs +256 -0
  15. package/dist/applet/host.cjs.map +1 -0
  16. package/dist/applet/host.d.cts +62 -0
  17. package/dist/applet/host.d.ts +62 -0
  18. package/dist/applet/host.mjs +251 -0
  19. package/dist/applet/host.mjs.map +1 -0
  20. package/dist/bichat/index.cjs +352 -409
  21. package/dist/bichat/index.cjs.map +1 -1
  22. package/dist/bichat/index.d.cts +8 -116
  23. package/dist/bichat/index.d.ts +8 -116
  24. package/dist/bichat/index.mjs +354 -403
  25. package/dist/bichat/index.mjs.map +1 -1
  26. package/dist/fonts/Actay/Actay-Regular.otf +0 -0
  27. package/dist/fonts/Actay/Actay-RegularItalic.otf +0 -0
  28. package/dist/fonts/Actay/ActayCondensed-Thin.otf +0 -0
  29. package/dist/fonts/Actay/ActayCondensed-ThinItalic.otf +0 -0
  30. package/dist/fonts/Actay/ActayWide-Bold.otf +0 -0
  31. package/dist/fonts/Actay/ActayWide-BoldItalic.otf +0 -0
  32. package/dist/fonts/Gilroy/Gilroy-Black.woff2 +0 -0
  33. package/dist/fonts/Gilroy/Gilroy-BlackItalic.woff2 +0 -0
  34. package/dist/fonts/Gilroy/Gilroy-Bold.woff2 +0 -0
  35. package/dist/fonts/Gilroy/Gilroy-BoldItalic.woff2 +0 -0
  36. package/dist/fonts/Gilroy/Gilroy-Extrabold.woff2 +0 -0
  37. package/dist/fonts/Gilroy/Gilroy-ExtraboldItalic.woff2 +0 -0
  38. package/dist/fonts/Gilroy/Gilroy-Heavy.woff2 +0 -0
  39. package/dist/fonts/Gilroy/Gilroy-HeavyItalic.woff2 +0 -0
  40. package/dist/fonts/Gilroy/Gilroy-Light.woff2 +0 -0
  41. package/dist/fonts/Gilroy/Gilroy-LightItalic.woff2 +0 -0
  42. package/dist/fonts/Gilroy/Gilroy-Medium.woff2 +0 -0
  43. package/dist/fonts/Gilroy/Gilroy-MediumItalic.woff2 +0 -0
  44. package/dist/fonts/Gilroy/Gilroy-Regular.woff2 +0 -0
  45. package/dist/fonts/Gilroy/Gilroy-RegularItalic.woff2 +0 -0
  46. package/dist/fonts/Gilroy/Gilroy-Semibold.woff2 +0 -0
  47. package/dist/fonts/Gilroy/Gilroy-SemiboldItalic.woff2 +0 -0
  48. package/dist/fonts/Gilroy/Gilroy-Thin.woff2 +0 -0
  49. package/dist/fonts/Gilroy/Gilroy-ThinItalic.woff2 +0 -0
  50. package/dist/fonts/Gilroy/Gilroy-UltraLight.woff2 +0 -0
  51. package/dist/fonts/Gilroy/Gilroy-UltraLightItalic.woff2 +0 -0
  52. package/dist/fonts/Inter.var.woff2 +0 -0
  53. package/dist/{index-B73-BCi-.d.cts → index-Cs_xWkhC.d.cts} +1 -1
  54. package/dist/{index-B73-BCi-.d.ts → index-Cs_xWkhC.d.ts} +1 -1
  55. package/dist/index.cjs +52 -4
  56. package/dist/index.cjs.map +1 -1
  57. package/dist/index.d.cts +6 -232
  58. package/dist/index.d.ts +6 -232
  59. package/dist/index.mjs +52 -4
  60. package/dist/index.mjs.map +1 -1
  61. package/package.json +45 -14
  62. package/tailwind/compiled.css +1 -1
  63. package/tailwind/create-config.cjs +16 -135
  64. package/tailwind/sdk-theme.cjs +99 -0
  65. package/LICENSE +0 -201
  66. package/README.MD +0 -166
package/README.md ADDED
@@ -0,0 +1,117 @@
1
+ # Applets
2
+
3
+ Go library and CLI for the applet framework, plus the **@iota-uz/sdk** npm package (applet context, host, UI components, Tailwind helpers). Consumed by [iota-sdk](https://github.com/iota-uz/iota-sdk) and EAI to build and run applets (e.g. BiChat).
4
+
5
+ Full architecture and development guides live in [iota-sdk docs](https://github.com/iota-uz/iota-sdk).
6
+
7
+ ---
8
+
9
+ ## Go
10
+
11
+ Add the module to your project:
12
+
13
+ ```bash
14
+ go get github.com/iota-uz/applets@latest
15
+ ```
16
+
17
+ Import the public API from the root package:
18
+
19
+ ```go
20
+ import "github.com/iota-uz/applets"
21
+ ```
22
+
23
+ Use `Registry`, `Controller`, RPC types, context helpers, and options as needed. For local development with a clone of this repo, use a [Go workspace](https://go.dev/ref/mod#workspaces) in your project with `use` pointing at the applets directory.
24
+
25
+ ---
26
+
27
+ ## NPM
28
+
29
+ Install the SDK in your applet frontend (e.g. Vite/React):
30
+
31
+ ```bash
32
+ pnpm add @iota-uz/sdk
33
+ ```
34
+
35
+ Use applet context, host utilities, BiChat UI components, and Tailwind configuration from the package.
36
+
37
+ ---
38
+
39
+ ## Applet CLI
40
+
41
+ Install the CLI (ensure `$GOBIN` is on your PATH):
42
+
43
+ ```bash
44
+ go install github.com/iota-uz/applets/cmd/applet@latest
45
+ ```
46
+
47
+ From a repo that contains an applet (e.g. iota-sdk or EAI):
48
+
49
+ ```bash
50
+ applet doctor # environment and config diagnostics
51
+ applet rpc gen --name <applet-name>
52
+ applet rpc check --name <applet-name>
53
+ applet deps check
54
+ applet check # deps + RPC drift for all applets
55
+ applet dev [name] # start dev environment
56
+ applet build [name] # build production bundle
57
+ applet list # list configured applets
58
+ ```
59
+
60
+ - **Specific version:** `go install github.com/iota-uz/applets/cmd/applet@v0.4.4`
61
+ - **Shell completion:** `applet completion bash`, `applet completion zsh`, or `applet completion fish` — see `applet completion --help` for install instructions.
62
+
63
+ ---
64
+
65
+ ## Configuration
66
+
67
+ The CLI expects a project root where `.applets/config.toml` exists (or, for `applet deps check`, a repo with a `go.mod` for `github.com/iota-uz/iota-sdk` or `github.com/iota-uz/eai`).
68
+
69
+ Example `.applets/config.toml` with all options documented in comments:
70
+
71
+ ```toml
72
+ # --- Dev (project-level) ---
73
+ [dev]
74
+ # Backend port for dev manifest. Default: 3200
75
+ backend_port = 3200
76
+
77
+ # Project-level processes (e.g. air, templ). At least one required.
78
+ # Each process: name (required), command (required), args (optional), critical (optional), env (optional).
79
+ [[dev.processes]]
80
+ name = "air"
81
+ command = "air"
82
+ args = ["-c", ".air.toml"]
83
+ critical = true
84
+ # env = { FOO = "bar" }
85
+
86
+ [[dev.processes]]
87
+ name = "templ"
88
+ command = "templ"
89
+ args = ["generate", "--watch"]
90
+
91
+ # --- Applets (per-app) ---
92
+ # Each applet: base_path (required), module, web, entry (optional; see defaults below).
93
+ [applets.bichat]
94
+ base_path = "/bi-chat"
95
+ # module = "modules/bichat" # default: modules/<name>
96
+ # web = "modules/bichat/presentation/web" # default: modules/<name>/presentation/web
97
+ # entry = "/src/main.tsx" # default: /src/main.tsx
98
+
99
+ [applets.bichat.dev]
100
+ # Vite dev server port. Default: unique per applet (5173, 5174, …)
101
+ vite_port = 5173
102
+
103
+ [applets.bichat.rpc]
104
+ # Go function name for RPC codegen. Default: "Router"
105
+ router_func = "Router"
106
+ # If true, the applet module re-exports the RPC contract from the SDK package. Default: false
107
+ needs_reexport_shim = false
108
+
109
+ # Second applet: only required fields + overrides; rest use defaults
110
+ [applets.otherapp]
111
+ base_path = "/other"
112
+ module = "modules/otherapp"
113
+ web = "modules/otherapp/frontend"
114
+ # dev.vite_port and rpc.* use defaults (unique port, Router, false)
115
+ ```
116
+
117
+ Defaults are applied in sorted applet name order; `vite_port` is made unique when not set to avoid conflicts. Run `applet doctor` to validate config and environment.
@@ -0,0 +1,251 @@
1
+ 'use strict';
2
+
3
+ var react = require('react');
4
+ var jsxRuntime = require('react/jsx-runtime');
5
+
6
+ // ui/src/applet-core/context/AppletContext.tsx
7
+ var AppletContext = react.createContext(null);
8
+ var REQUIRED_KEYS = ["user", "tenant", "locale", "config", "route", "session"];
9
+ function validateInitialContext(value, windowKey) {
10
+ if (!value || typeof value !== "object") {
11
+ throw new Error(`${windowKey}: expected an object, got ${typeof value}`);
12
+ }
13
+ const obj = value;
14
+ const missing = REQUIRED_KEYS.filter((k) => !(k in obj));
15
+ if (missing.length > 0) {
16
+ throw new Error(`${windowKey}: missing required keys: ${missing.join(", ")}`);
17
+ }
18
+ const user = obj.user;
19
+ if (!user || typeof user !== "object") {
20
+ throw new Error(`${windowKey}.user: expected an object, got ${typeof user}`);
21
+ }
22
+ if (typeof user.id !== "number") {
23
+ throw new Error(`${windowKey}.user.id: expected number, got ${typeof user.id}`);
24
+ }
25
+ if (!Array.isArray(user.permissions)) {
26
+ throw new Error(`${windowKey}.user.permissions: expected array, got ${typeof user.permissions}`);
27
+ }
28
+ const tenant = obj.tenant;
29
+ if (!tenant || typeof tenant !== "object") {
30
+ throw new Error(`${windowKey}.tenant: expected an object, got ${typeof tenant}`);
31
+ }
32
+ if (typeof tenant.id !== "string") {
33
+ throw new Error(`${windowKey}.tenant.id: expected string, got ${typeof tenant.id}`);
34
+ }
35
+ const session = obj.session;
36
+ if (!session || typeof session !== "object") {
37
+ throw new Error(`${windowKey}.session: expected an object, got ${typeof session}`);
38
+ }
39
+ if (typeof session.csrfToken !== "string") {
40
+ throw new Error(`${windowKey}.session.csrfToken: expected string, got ${typeof session.csrfToken}`);
41
+ }
42
+ if (typeof session.expiresAt !== "number") {
43
+ throw new Error(`${windowKey}.session.expiresAt: expected number, got ${typeof session.expiresAt}`);
44
+ }
45
+ if (typeof session.refreshURL !== "string") {
46
+ throw new Error(`${windowKey}.session.refreshURL: expected string, got ${typeof session.refreshURL}`);
47
+ }
48
+ const config = obj.config;
49
+ if (!config || typeof config !== "object") {
50
+ throw new Error(`${windowKey}.config: expected object, got ${typeof config}`);
51
+ }
52
+ return value;
53
+ }
54
+ function AppletProvider({ children, windowKey, context }) {
55
+ const raw = context ?? window[windowKey];
56
+ if (!raw) {
57
+ throw new Error(`${windowKey} not found on window. Ensure backend context injection is working.`);
58
+ }
59
+ const initialContext = validateInitialContext(raw, windowKey);
60
+ return /* @__PURE__ */ jsxRuntime.jsx(AppletContext.Provider, { value: initialContext, children });
61
+ }
62
+ function useAppletContext() {
63
+ const context = react.useContext(AppletContext);
64
+ if (!context) {
65
+ throw new Error("useAppletContext must be used within AppletProvider");
66
+ }
67
+ return context;
68
+ }
69
+ var ConfigContext = react.createContext(null);
70
+ function ConfigProvider({ children, config }) {
71
+ return /* @__PURE__ */ jsxRuntime.jsx(ConfigContext.Provider, { value: config, children });
72
+ }
73
+ function useConfigContext() {
74
+ const context = react.useContext(ConfigContext);
75
+ if (!context) {
76
+ throw new Error("useConfigContext must be used within ConfigProvider");
77
+ }
78
+ return context;
79
+ }
80
+
81
+ // ui/src/applet-core/hooks/useAppletContext.ts
82
+ function useAppletContext2(windowKey) {
83
+ const context = window[windowKey];
84
+ if (!context) {
85
+ throw new Error(`${windowKey} not found on window. Ensure backend context injection is working.`);
86
+ }
87
+ return context;
88
+ }
89
+
90
+ // ui/src/applet-core/hooks/useConfig.ts
91
+ function useConfig() {
92
+ const { config } = useAppletContext();
93
+ return config;
94
+ }
95
+
96
+ // ui/src/applet-core/hooks/useUser.ts
97
+ function useUser() {
98
+ const { user } = useAppletContext();
99
+ return user;
100
+ }
101
+
102
+ // ui/src/applet-core/hooks/usePermissions.ts
103
+ function usePermissions() {
104
+ const { user } = useAppletContext();
105
+ const hasPermission = (permission) => {
106
+ return user.permissions.includes(permission);
107
+ };
108
+ const hasAnyPermission = (...permissions) => {
109
+ return permissions.some((p) => user.permissions.includes(p));
110
+ };
111
+ return {
112
+ hasPermission,
113
+ hasAnyPermission,
114
+ permissions: user.permissions
115
+ };
116
+ }
117
+
118
+ // ui/src/applet-core/hooks/useTranslation.ts
119
+ function useTranslation() {
120
+ const { locale } = useAppletContext();
121
+ const t = (key, params) => {
122
+ let text = locale.translations[key] || key;
123
+ if (params) {
124
+ Object.entries(params).forEach(([k, v]) => {
125
+ text = text.replace(new RegExp(`\\{${k}\\}`, "g"), String(v));
126
+ });
127
+ }
128
+ return text;
129
+ };
130
+ return {
131
+ t,
132
+ language: locale.language
133
+ };
134
+ }
135
+ function useSession(options) {
136
+ const { session } = useAppletContext();
137
+ const loginPath = options?.loginPath ?? "/login";
138
+ const isExpiringSoon = react.useMemo(() => {
139
+ const bufferMs = 5 * 60 * 1e3;
140
+ return session.expiresAt - Date.now() < bufferMs;
141
+ }, [session.expiresAt]);
142
+ const refreshSession = async () => {
143
+ const response = await fetch(session.refreshURL, {
144
+ method: "POST",
145
+ headers: {
146
+ "X-CSRF-Token": session.csrfToken
147
+ }
148
+ });
149
+ if (!response.ok) {
150
+ const returnUrl = encodeURIComponent(window.location.pathname);
151
+ window.location.href = `${loginPath}?redirect=${returnUrl}`;
152
+ return;
153
+ }
154
+ const newToken = response.headers.get("X-CSRF-Token");
155
+ if (newToken) {
156
+ window.dispatchEvent(
157
+ new CustomEvent("iota:csrf-refresh", {
158
+ detail: { token: newToken }
159
+ })
160
+ );
161
+ }
162
+ };
163
+ return {
164
+ isExpiringSoon,
165
+ refreshSession,
166
+ csrfToken: session.csrfToken,
167
+ expiresAt: session.expiresAt
168
+ };
169
+ }
170
+
171
+ // ui/src/applet-core/hooks/useRoute.ts
172
+ function useRoute() {
173
+ const { route } = useAppletContext();
174
+ return route;
175
+ }
176
+ function useStreaming() {
177
+ const [isStreaming, setIsStreaming] = react.useState(false);
178
+ const abortControllerRef = react.useRef(null);
179
+ const processStream = react.useCallback(
180
+ async (generator, onChunk, signal) => {
181
+ setIsStreaming(true);
182
+ const controller = new AbortController();
183
+ abortControllerRef.current = controller;
184
+ if (signal) {
185
+ signal.addEventListener("abort", () => {
186
+ controller.abort();
187
+ });
188
+ }
189
+ try {
190
+ for await (const chunk of generator) {
191
+ if (controller.signal.aborted) {
192
+ break;
193
+ }
194
+ onChunk(chunk);
195
+ }
196
+ } catch (error) {
197
+ if (controller.signal.aborted) {
198
+ return;
199
+ }
200
+ throw error;
201
+ } finally {
202
+ setIsStreaming(false);
203
+ abortControllerRef.current = null;
204
+ }
205
+ },
206
+ []
207
+ );
208
+ const cancel = react.useCallback(() => {
209
+ if (abortControllerRef.current) {
210
+ abortControllerRef.current.abort();
211
+ }
212
+ setIsStreaming(false);
213
+ }, []);
214
+ const reset = react.useCallback(() => {
215
+ abortControllerRef.current = null;
216
+ setIsStreaming(false);
217
+ }, []);
218
+ return {
219
+ isStreaming,
220
+ processStream,
221
+ cancel,
222
+ reset
223
+ };
224
+ }
225
+
226
+ // ui/src/applet-core/hooks/useAppletRuntime.ts
227
+ function useAppletRuntime() {
228
+ const config = useConfig();
229
+ const basePath = config.basePath ?? "";
230
+ const normalizedBasePath = basePath.endsWith("/") ? basePath.slice(0, -1) : basePath;
231
+ const assetsBasePath = config.assetsBasePath ?? `${normalizedBasePath || ""}/assets`;
232
+ const rpcEndpoint = config.rpcUIEndpoint;
233
+ const shellMode = config.shellMode;
234
+ return { basePath: normalizedBasePath, assetsBasePath, rpcEndpoint, shellMode };
235
+ }
236
+
237
+ exports.AppletProvider = AppletProvider;
238
+ exports.ConfigProvider = ConfigProvider;
239
+ exports.useAppletContext = useAppletContext;
240
+ exports.useAppletContextDirect = useAppletContext2;
241
+ exports.useAppletRuntime = useAppletRuntime;
242
+ exports.useConfig = useConfig;
243
+ exports.useConfigContext = useConfigContext;
244
+ exports.usePermissions = usePermissions;
245
+ exports.useRoute = useRoute;
246
+ exports.useSession = useSession;
247
+ exports.useStreaming = useStreaming;
248
+ exports.useTranslation = useTranslation;
249
+ exports.useUser = useUser;
250
+ //# sourceMappingURL=core.cjs.map
251
+ //# sourceMappingURL=core.cjs.map
@@ -0,0 +1 @@
1
+ {"version":3,"sources":["../../ui/src/applet-core/context/AppletContext.tsx","../../ui/src/applet-core/context/ConfigProvider.tsx","../../ui/src/applet-core/hooks/useAppletContext.ts","../../ui/src/applet-core/hooks/useConfig.ts","../../ui/src/applet-core/hooks/useUser.ts","../../ui/src/applet-core/hooks/usePermissions.ts","../../ui/src/applet-core/hooks/useTranslation.ts","../../ui/src/applet-core/hooks/useSession.ts","../../ui/src/applet-core/hooks/useRoute.ts","../../ui/src/applet-core/hooks/useStreaming.ts","../../ui/src/applet-core/hooks/useAppletRuntime.ts"],"names":["createContext","useContext","jsx","useAppletContext","useMemo","useState","useRef","useCallback"],"mappings":"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","file":"core.cjs","sourcesContent":["import { createContext, useContext, ReactNode } from 'react'\nimport type { InitialContext } from '../types'\n\n/**\n * AppletContext provides access to the global context injected by the backend.\n * The context is read from window.__*_CONTEXT__ (configured via windowKey).\n */\nconst AppletContext = createContext<InitialContext | null>(null)\n\nconst REQUIRED_KEYS: Array<keyof InitialContext> = ['user', 'tenant', 'locale', 'config', 'route', 'session']\n\nfunction validateInitialContext(value: unknown, windowKey: string): InitialContext {\n if (!value || typeof value !== 'object') {\n throw new Error(`${windowKey}: expected an object, got ${typeof value}`)\n }\n const obj = value as Record<string, unknown>\n const missing = REQUIRED_KEYS.filter((k) => !(k in obj))\n if (missing.length > 0) {\n throw new Error(`${windowKey}: missing required keys: ${missing.join(', ')}`)\n }\n\n // Deep validation for nested required fields\n const user = obj.user as Record<string, unknown> | undefined\n if (!user || typeof user !== 'object') {\n throw new Error(`${windowKey}.user: expected an object, got ${typeof user}`)\n }\n if (typeof user.id !== 'number') {\n throw new Error(`${windowKey}.user.id: expected number, got ${typeof user.id}`)\n }\n if (!Array.isArray(user.permissions)) {\n throw new Error(`${windowKey}.user.permissions: expected array, got ${typeof user.permissions}`)\n }\n\n const tenant = obj.tenant as Record<string, unknown> | undefined\n if (!tenant || typeof tenant !== 'object') {\n throw new Error(`${windowKey}.tenant: expected an object, got ${typeof tenant}`)\n }\n if (typeof tenant.id !== 'string') {\n throw new Error(`${windowKey}.tenant.id: expected string, got ${typeof tenant.id}`)\n }\n\n const session = obj.session as Record<string, unknown> | undefined\n if (!session || typeof session !== 'object') {\n throw new Error(`${windowKey}.session: expected an object, got ${typeof session}`)\n }\n if (typeof session.csrfToken !== 'string') {\n throw new Error(`${windowKey}.session.csrfToken: expected string, got ${typeof session.csrfToken}`)\n }\n if (typeof session.expiresAt !== 'number') {\n throw new Error(`${windowKey}.session.expiresAt: expected number, got ${typeof session.expiresAt}`)\n }\n if (typeof session.refreshURL !== 'string') {\n throw new Error(`${windowKey}.session.refreshURL: expected string, got ${typeof session.refreshURL}`)\n }\n\n const config = obj.config\n if (!config || typeof config !== 'object') {\n throw new Error(`${windowKey}.config: expected object, got ${typeof config}`)\n }\n\n return value as InitialContext\n}\n\nexport interface AppletProviderProps {\n children: ReactNode\n windowKey: string\n context?: InitialContext\n}\n\n/**\n * AppletProvider reads context from window global and provides it to hooks.\n *\n * Usage:\n * <AppletProvider windowKey=\"__BICHAT_CONTEXT__\">\n * <App />\n * </AppletProvider>\n */\nexport function AppletProvider({ children, windowKey, context }: AppletProviderProps) {\n // Use provided context or read from window global\n const raw = context ?? (window as any)[windowKey]\n\n if (!raw) {\n throw new Error(`${windowKey} not found on window. Ensure backend context injection is working.`)\n }\n\n const initialContext = validateInitialContext(raw, windowKey)\n\n return (\n <AppletContext.Provider value={initialContext}>\n {children}\n </AppletContext.Provider>\n )\n}\n\n/**\n * useAppletContext provides access to the full applet context.\n * Use specialized hooks (useUser, useConfig, etc.) for specific context parts.\n */\nexport function useAppletContext<T = InitialContext>(): T {\n const context = useContext(AppletContext)\n if (!context) {\n throw new Error('useAppletContext must be used within AppletProvider')\n }\n return context as T\n}\n","import { createContext, useContext, ReactNode } from 'react'\nimport type { InitialContext } from '../types'\n\n/**\n * ConfigProvider is an alternative to AppletProvider that accepts context via props\n * instead of reading from window global. Useful for testing and server-side rendering.\n */\n\nconst ConfigContext = createContext<InitialContext | null>(null)\n\nexport interface ConfigProviderProps {\n children: ReactNode\n config: InitialContext\n}\n\n/**\n * ConfigProvider accepts context configuration via props.\n *\n * Usage:\n * <ConfigProvider config={initialContext}>\n * <App />\n * </ConfigProvider>\n */\nexport function ConfigProvider({ children, config }: ConfigProviderProps) {\n return (\n <ConfigContext.Provider value={config}>\n {children}\n </ConfigContext.Provider>\n )\n}\n\n/**\n * useConfigContext provides access to the applet context when using ConfigProvider.\n */\nexport function useConfigContext<T = InitialContext>(): T {\n const context = useContext(ConfigContext)\n if (!context) {\n throw new Error('useConfigContext must be used within ConfigProvider')\n }\n return context as T\n}\n","import type { InitialContext } from '../types'\n\n/**\n * useAppletContext provides direct access to the window global context.\n * This is a standalone version that doesn't require AppletProvider.\n *\n * Usage:\n * const context = useAppletContext('__BICHAT_CONTEXT__')\n *\n * Note: Prefer using AppletProvider + context hooks for better type safety\n * and testability. Use this hook only when provider setup is not possible.\n */\nexport function useAppletContext<T = InitialContext>(windowKey: string): T {\n const context = (window as any)[windowKey]\n\n if (!context) {\n throw new Error(`${windowKey} not found on window. Ensure backend context injection is working.`)\n }\n\n return context as T\n}\n","import { useAppletContext } from '../context/AppletContext'\nimport type { AppConfig } from '../types'\n\n/**\n * useConfig provides access to applet configuration (endpoints, etc.)\n *\n * Usage:\n * const { graphQLEndpoint, streamEndpoint } = useConfig()\n */\nexport function useConfig(): AppConfig {\n const { config } = useAppletContext()\n return config\n}\n","import { useAppletContext } from '../context/AppletContext'\nimport type { UserContext } from '../types'\n\n/**\n * useUser provides access to current user information.\n *\n * Usage:\n * const { id, email, firstName, lastName, permissions } = useUser()\n */\nexport function useUser(): UserContext {\n const { user } = useAppletContext()\n return user\n}\n","import { useAppletContext } from '../context/AppletContext'\nimport type { PermissionsHook } from '../types'\n\n/**\n * usePermissions provides permission checking utilities.\n * All user permissions are automatically passed from backend.\n *\n * Usage:\n * const { hasPermission, hasAnyPermission } = usePermissions()\n *\n * if (hasPermission('BiChat.Access')) {\n * // User has bichat access\n * }\n *\n * if (hasAnyPermission('finance.view', 'finance.edit')) {\n * // User has at least one of these permissions\n * }\n */\nexport function usePermissions(): PermissionsHook {\n const { user } = useAppletContext()\n\n const hasPermission = (permission: string): boolean => {\n return user.permissions.includes(permission)\n }\n\n const hasAnyPermission = (...permissions: string[]): boolean => {\n return permissions.some(p => user.permissions.includes(p))\n }\n\n return {\n hasPermission,\n hasAnyPermission,\n permissions: user.permissions\n }\n}\n","import { useAppletContext } from '../context/AppletContext'\nimport type { TranslationHook } from '../types'\n\n/**\n * useTranslation provides i18n translation utilities.\n * All translations are automatically passed from backend locale bundle.\n *\n * Usage:\n * const { t, language } = useTranslation()\n *\n * // Simple translation\n * t('BiChat.Title') // Returns translated text\n *\n * // Translation with interpolation\n * t('Common.WelcomeMessage', { name: 'John' })\n * // If translation is \"Welcome {name}!\" -> Returns \"Welcome John!\"\n *\n * React uses same keys as Go backend:\n * Go: pageCtx.T(\"BiChat.Title\")\n * React: t(\"BiChat.Title\")\n */\nexport function useTranslation(): TranslationHook {\n const { locale } = useAppletContext()\n\n const t = (key: string, params?: Record<string, unknown>): string => {\n let text = locale.translations[key] || key\n\n // Simple interpolation: \"Hello {name}\" with {name: \"World\"}\n if (params) {\n Object.entries(params).forEach(([k, v]) => {\n text = text.replace(new RegExp(`\\\\{${k}\\\\}`, 'g'), String(v))\n })\n }\n\n return text\n }\n\n return {\n t,\n language: locale.language\n }\n}\n","import { useMemo } from 'react'\nimport { useAppletContext } from '../context/AppletContext'\nimport type { SessionHook } from '../types'\n\nexport interface UseSessionOptions {\n loginPath?: string\n}\n\n/**\n * useSession provides session and authentication handling utilities.\n *\n * Usage:\n * const { isExpiringSoon, refreshSession, csrfToken } = useSession()\n *\n * // Check if session is expiring soon (5 min buffer)\n * if (isExpiringSoon) {\n * await refreshSession()\n * }\n *\n * // Include CSRF token in requests\n * fetch('/api/endpoint', {\n * headers: { 'X-CSRF-Token': csrfToken }\n * })\n */\nexport function useSession(options?: UseSessionOptions): SessionHook {\n const { session } = useAppletContext()\n const loginPath = options?.loginPath ?? '/login'\n\n // Check if session is expiring soon (5 minute buffer)\n const isExpiringSoon = useMemo(() => {\n const bufferMs = 5 * 60 * 1000 // 5 minutes\n return session.expiresAt - Date.now() < bufferMs\n }, [session.expiresAt])\n\n const refreshSession = async (): Promise<void> => {\n const response = await fetch(session.refreshURL, {\n method: 'POST',\n headers: {\n 'X-CSRF-Token': session.csrfToken\n }\n })\n\n if (!response.ok) {\n // Session refresh failed - redirect to login with return URL\n const returnUrl = encodeURIComponent(window.location.pathname)\n window.location.href = `${loginPath}?redirect=${returnUrl}`\n return\n }\n\n // Dispatch event for CSRF token update\n const newToken = response.headers.get('X-CSRF-Token')\n if (newToken) {\n window.dispatchEvent(\n new CustomEvent('iota:csrf-refresh', {\n detail: { token: newToken }\n })\n )\n }\n }\n\n return {\n isExpiringSoon,\n refreshSession,\n csrfToken: session.csrfToken,\n expiresAt: session.expiresAt\n }\n}\n","import { useAppletContext } from '../context/AppletContext'\nimport type { RouteContext } from '../types'\n\n/**\n * useRoute provides access to the current route context.\n * Route context is initialized from the backend and includes path, params, and query.\n *\n * Usage:\n * const { path, params, query } = useRoute()\n *\n * // Example values:\n * // path: \"/sessions/123\"\n * // params: { id: \"123\" }\n * // query: { tab: \"history\" }\n */\nexport function useRoute(): RouteContext {\n const { route } = useAppletContext()\n return route\n}\n","import { useState, useRef, useCallback } from 'react'\nimport type { StreamingHook } from '../types'\n\n/**\n * useStreaming provides SSE (Server-Sent Events) streaming utilities with cancellation support.\n *\n * Usage:\n * const { isStreaming, processStream, cancel, reset } = useStreaming()\n *\n * // Process async generator stream\n * await processStream(messageStream, (chunk) => {\n * console.log('Received:', chunk)\n * })\n *\n * // Cancel ongoing stream\n * cancel()\n *\n * // Reset state after stream completion\n * reset()\n */\nexport function useStreaming(): StreamingHook {\n const [isStreaming, setIsStreaming] = useState(false)\n const abortControllerRef = useRef<AbortController | null>(null)\n\n const processStream = useCallback(\n async <T,>(\n generator: AsyncGenerator<T>,\n onChunk: (chunk: T) => void,\n signal?: AbortSignal\n ): Promise<void> => {\n setIsStreaming(true)\n\n // Create abort controller if not provided\n const controller = new AbortController()\n abortControllerRef.current = controller\n\n // Listen to external signal if provided\n if (signal) {\n signal.addEventListener('abort', () => {\n controller.abort()\n })\n }\n\n try {\n for await (const chunk of generator) {\n // Check if stream was cancelled\n if (controller.signal.aborted) {\n break\n }\n\n onChunk(chunk)\n }\n } catch (error) {\n // Stream was cancelled or errored\n if (controller.signal.aborted) {\n // Cancellation is expected, don't throw\n return\n }\n throw error\n } finally {\n setIsStreaming(false)\n abortControllerRef.current = null\n }\n },\n []\n )\n\n const cancel = useCallback(() => {\n if (abortControllerRef.current) {\n abortControllerRef.current.abort()\n }\n setIsStreaming(false)\n }, [])\n\n const reset = useCallback(() => {\n abortControllerRef.current = null\n setIsStreaming(false)\n }, [])\n\n return {\n isStreaming,\n processStream,\n cancel,\n reset\n }\n}\n","import { useConfig } from './useConfig'\n\nexport type ShellMode = 'embedded' | 'standalone'\n\nexport interface AppletRuntime {\n basePath: string\n assetsBasePath: string\n rpcEndpoint?: string\n shellMode?: ShellMode\n}\n\nexport function useAppletRuntime(): AppletRuntime {\n const config = useConfig()\n\n const basePath = config.basePath ?? ''\n const normalizedBasePath = basePath.endsWith('/') ? basePath.slice(0, -1) : basePath\n const assetsBasePath = config.assetsBasePath ?? `${normalizedBasePath || ''}/assets`\n const rpcEndpoint = config.rpcUIEndpoint\n const shellMode = config.shellMode\n\n return { basePath: normalizedBasePath, assetsBasePath, rpcEndpoint, shellMode }\n}\n"]}
@@ -0,0 +1,172 @@
1
+ import * as react_jsx_runtime from 'react/jsx-runtime';
2
+ import { ReactNode } from 'react';
3
+ import { I as InitialContext, A as AppConfig, U as UserContext, P as PermissionsHook, c as TranslationHook, a as SessionHook, R as RouteContext, b as StreamingHook } from '../index-Cs_xWkhC.cjs';
4
+ export { L as LocaleContext, S as SessionContext, T as TenantContext } from '../index-Cs_xWkhC.cjs';
5
+
6
+ interface AppletProviderProps {
7
+ children: ReactNode;
8
+ windowKey: string;
9
+ context?: InitialContext;
10
+ }
11
+ /**
12
+ * AppletProvider reads context from window global and provides it to hooks.
13
+ *
14
+ * Usage:
15
+ * <AppletProvider windowKey="__BICHAT_CONTEXT__">
16
+ * <App />
17
+ * </AppletProvider>
18
+ */
19
+ declare function AppletProvider({ children, windowKey, context }: AppletProviderProps): react_jsx_runtime.JSX.Element;
20
+ /**
21
+ * useAppletContext provides access to the full applet context.
22
+ * Use specialized hooks (useUser, useConfig, etc.) for specific context parts.
23
+ */
24
+ declare function useAppletContext$1<T = InitialContext>(): T;
25
+
26
+ interface ConfigProviderProps {
27
+ children: ReactNode;
28
+ config: InitialContext;
29
+ }
30
+ /**
31
+ * ConfigProvider accepts context configuration via props.
32
+ *
33
+ * Usage:
34
+ * <ConfigProvider config={initialContext}>
35
+ * <App />
36
+ * </ConfigProvider>
37
+ */
38
+ declare function ConfigProvider({ children, config }: ConfigProviderProps): react_jsx_runtime.JSX.Element;
39
+ /**
40
+ * useConfigContext provides access to the applet context when using ConfigProvider.
41
+ */
42
+ declare function useConfigContext<T = InitialContext>(): T;
43
+
44
+ /**
45
+ * useAppletContext provides direct access to the window global context.
46
+ * This is a standalone version that doesn't require AppletProvider.
47
+ *
48
+ * Usage:
49
+ * const context = useAppletContext('__BICHAT_CONTEXT__')
50
+ *
51
+ * Note: Prefer using AppletProvider + context hooks for better type safety
52
+ * and testability. Use this hook only when provider setup is not possible.
53
+ */
54
+ declare function useAppletContext<T = InitialContext>(windowKey: string): T;
55
+
56
+ /**
57
+ * useConfig provides access to applet configuration (endpoints, etc.)
58
+ *
59
+ * Usage:
60
+ * const { graphQLEndpoint, streamEndpoint } = useConfig()
61
+ */
62
+ declare function useConfig(): AppConfig;
63
+
64
+ /**
65
+ * useUser provides access to current user information.
66
+ *
67
+ * Usage:
68
+ * const { id, email, firstName, lastName, permissions } = useUser()
69
+ */
70
+ declare function useUser(): UserContext;
71
+
72
+ /**
73
+ * usePermissions provides permission checking utilities.
74
+ * All user permissions are automatically passed from backend.
75
+ *
76
+ * Usage:
77
+ * const { hasPermission, hasAnyPermission } = usePermissions()
78
+ *
79
+ * if (hasPermission('BiChat.Access')) {
80
+ * // User has bichat access
81
+ * }
82
+ *
83
+ * if (hasAnyPermission('finance.view', 'finance.edit')) {
84
+ * // User has at least one of these permissions
85
+ * }
86
+ */
87
+ declare function usePermissions(): PermissionsHook;
88
+
89
+ /**
90
+ * useTranslation provides i18n translation utilities.
91
+ * All translations are automatically passed from backend locale bundle.
92
+ *
93
+ * Usage:
94
+ * const { t, language } = useTranslation()
95
+ *
96
+ * // Simple translation
97
+ * t('BiChat.Title') // Returns translated text
98
+ *
99
+ * // Translation with interpolation
100
+ * t('Common.WelcomeMessage', { name: 'John' })
101
+ * // If translation is "Welcome {name}!" -> Returns "Welcome John!"
102
+ *
103
+ * React uses same keys as Go backend:
104
+ * Go: pageCtx.T("BiChat.Title")
105
+ * React: t("BiChat.Title")
106
+ */
107
+ declare function useTranslation(): TranslationHook;
108
+
109
+ interface UseSessionOptions {
110
+ loginPath?: string;
111
+ }
112
+ /**
113
+ * useSession provides session and authentication handling utilities.
114
+ *
115
+ * Usage:
116
+ * const { isExpiringSoon, refreshSession, csrfToken } = useSession()
117
+ *
118
+ * // Check if session is expiring soon (5 min buffer)
119
+ * if (isExpiringSoon) {
120
+ * await refreshSession()
121
+ * }
122
+ *
123
+ * // Include CSRF token in requests
124
+ * fetch('/api/endpoint', {
125
+ * headers: { 'X-CSRF-Token': csrfToken }
126
+ * })
127
+ */
128
+ declare function useSession(options?: UseSessionOptions): SessionHook;
129
+
130
+ /**
131
+ * useRoute provides access to the current route context.
132
+ * Route context is initialized from the backend and includes path, params, and query.
133
+ *
134
+ * Usage:
135
+ * const { path, params, query } = useRoute()
136
+ *
137
+ * // Example values:
138
+ * // path: "/sessions/123"
139
+ * // params: { id: "123" }
140
+ * // query: { tab: "history" }
141
+ */
142
+ declare function useRoute(): RouteContext;
143
+
144
+ /**
145
+ * useStreaming provides SSE (Server-Sent Events) streaming utilities with cancellation support.
146
+ *
147
+ * Usage:
148
+ * const { isStreaming, processStream, cancel, reset } = useStreaming()
149
+ *
150
+ * // Process async generator stream
151
+ * await processStream(messageStream, (chunk) => {
152
+ * console.log('Received:', chunk)
153
+ * })
154
+ *
155
+ * // Cancel ongoing stream
156
+ * cancel()
157
+ *
158
+ * // Reset state after stream completion
159
+ * reset()
160
+ */
161
+ declare function useStreaming(): StreamingHook;
162
+
163
+ type ShellMode = 'embedded' | 'standalone';
164
+ interface AppletRuntime {
165
+ basePath: string;
166
+ assetsBasePath: string;
167
+ rpcEndpoint?: string;
168
+ shellMode?: ShellMode;
169
+ }
170
+ declare function useAppletRuntime(): AppletRuntime;
171
+
172
+ export { AppConfig, AppletProvider, ConfigProvider, InitialContext, PermissionsHook, RouteContext, SessionHook, StreamingHook, TranslationHook, UserContext, useAppletContext$1 as useAppletContext, useAppletContext as useAppletContextDirect, useAppletRuntime, useConfig, useConfigContext, usePermissions, useRoute, useSession, useStreaming, useTranslation, useUser };