feat(sdk): P3.4 @insignia/iios-inbox-web + kernel-client inbox REST

RestClient.listInboxItems/patchInboxItem + InboxItem type; iios-inbox-web
InboxProvider + useInbox (poll + snooze/done/reopen). Boundary allowlist extended.

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
This commit is contained in:
2026-07-01 04:30:42 +05:30
parent 20c8f15dff
commit 0a1631dbc0
9 changed files with 170 additions and 1 deletions
+27
View File
@@ -0,0 +1,27 @@
{
"name": "@insignia/iios-inbox-web",
"version": "0.0.0",
"private": true,
"type": "module",
"main": "dist/index.js",
"module": "dist/index.js",
"types": "dist/index.d.ts",
"exports": { ".": { "types": "./dist/index.d.ts", "import": "./dist/index.js" } },
"files": ["dist"],
"scripts": {
"build": "tsup",
"typecheck": "tsc --noEmit"
},
"dependencies": {
"@insignia/iios-kernel-client": "workspace:*"
},
"peerDependencies": {
"react": ">=18"
},
"devDependencies": {
"@types/react": "^19.0.0",
"react": "^19.0.0",
"tsup": "^8.3.5",
"typescript": "^5.7.3"
}
}
+2
View File
@@ -0,0 +1,2 @@
export { InboxProvider, useInbox } from './react';
export type { InboxItem, InboxState } from '@insignia/iios-kernel-client';
+63
View File
@@ -0,0 +1,63 @@
import React, { createContext, useCallback, useContext, useEffect, useMemo, useState } from 'react';
import { RestClient, type InboxItem, type InboxState } from '@insignia/iios-kernel-client';
const InboxContext = createContext<RestClient | null>(null);
/** Provides an inbox REST client to the inbox hooks. */
export function InboxProvider({
serviceUrl,
token,
children,
}: {
serviceUrl: string;
token: string;
children: React.ReactNode;
}): React.ReactElement {
const client = useMemo(() => new RestClient({ serviceUrl, token }), [serviceUrl, token]);
return <InboxContext.Provider value={client}>{children}</InboxContext.Provider>;
}
function useClient(): RestClient {
const c = useContext(InboxContext);
if (!c) throw new Error('useInbox must be used within <InboxProvider>');
return c;
}
/** The caller's inbox items + actions. Polls on an interval (default 3s). */
export function useInbox(opts?: { state?: InboxState; pollMs?: number }): {
items: InboxItem[];
refresh: () => Promise<void>;
snooze: (id: string) => Promise<void>;
done: (id: string) => Promise<void>;
reopen: (id: string) => Promise<void>;
} {
const client = useClient();
const [items, setItems] = useState<InboxItem[]>([]);
const refresh = useCallback(async () => {
try {
setItems(await client.listInboxItems(opts?.state));
} catch {
/* transient — keep last items */
}
}, [client, opts?.state]);
useEffect(() => {
void refresh();
const t = setInterval(() => void refresh(), opts?.pollMs ?? 3000);
return () => clearInterval(t);
}, [refresh, opts?.pollMs]);
const patch = async (id: string, state: InboxState): Promise<void> => {
await client.patchInboxItem(id, { state });
await refresh();
};
return {
items,
refresh,
snooze: (id) => patch(id, 'SNOOZED'),
done: (id) => patch(id, 'DONE'),
reopen: (id) => patch(id, 'OPEN'),
};
}
+14
View File
@@ -0,0 +1,14 @@
{
"extends": "../../tsconfig.base.json",
"compilerOptions": {
"outDir": "./dist",
"rootDir": "./src",
"module": "ESNext",
"moduleResolution": "bundler",
"lib": ["ES2022", "DOM"],
"jsx": "react-jsx",
"types": ["react"]
},
"include": ["src/**/*.ts", "src/**/*.tsx"],
"exclude": ["src/**/*.test.ts", "src/**/*.test.tsx"]
}
+9
View File
@@ -0,0 +1,9 @@
import { defineConfig } from 'tsup';
export default defineConfig({
entry: ['src/index.ts'],
format: ['esm'],
dts: true,
clean: true,
external: ['react', 'react-dom', '@insignia/iios-kernel-client'],
});