skybridge 0.0.0-dev.8ead776 → 0.0.0-dev.8ec5383
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.
- package/dist/server/index.d.ts +1 -1
- package/dist/server/index.js.map +1 -1
- package/dist/server/register-tool.test.js +0 -23
- package/dist/server/register-tool.test.js.map +1 -1
- package/dist/server/requestOrigin.js +22 -4
- package/dist/server/requestOrigin.js.map +1 -1
- package/dist/server/requestOrigin.test.js +28 -0
- package/dist/server/requestOrigin.test.js.map +1 -0
- package/dist/server/server.d.ts +0 -41
- package/dist/server/server.js +0 -32
- package/dist/server/server.js.map +1 -1
- package/dist/web/bridges/adaptor.d.ts +1 -6
- package/dist/web/bridges/adaptor.js +0 -79
- package/dist/web/bridges/adaptor.js.map +1 -1
- package/dist/web/bridges/types.d.ts +0 -30
- package/dist/web/bridges/types.js.map +1 -1
- package/dist/web/hooks/index.d.ts +0 -1
- package/dist/web/hooks/index.js +0 -1
- package/dist/web/hooks/index.js.map +1 -1
- package/package.json +1 -1
- package/dist/web/hooks/use-file-resource.d.ts +0 -37
- package/dist/web/hooks/use-file-resource.js +0 -101
- package/dist/web/hooks/use-file-resource.js.map +0 -1
- package/dist/web/hooks/use-file-resource.test.js +0 -65
- package/dist/web/hooks/use-file-resource.test.js.map +0 -1
- /package/dist/{web/hooks/use-file-resource.test.d.ts → server/requestOrigin.test.d.ts} +0 -0
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"adaptor.js","sourceRoot":"","sources":["../../../src/web/bridges/adaptor.ts"],"names":[],"mappings":"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","sourcesContent":["import { ResultSchema } from \"@modelcontextprotocol/core\";\nimport * as z from \"zod/v4\";\nimport { warnOnLargeViewState } from \"../../context-warnings.js\";\nimport { AppsSdkBridge } from \"./apps-sdk/bridge.js\";\nimport type { AppsSdkWidgetState } from \"./apps-sdk/types.js\";\nimport { McpAppBridge } from \"./mcp-app/bridge.js\";\nimport type {\n Adaptor,\n AnyViewToolHandler,\n CallToolOptions,\n CallToolResponse,\n DownloadParams,\n DownloadResult,\n FileMetadata,\n FileResource,\n FileResourceContent,\n FileResourceWriteResult,\n FollowUpMessage,\n HostContext,\n HostContextStore,\n ModelContextParams,\n OpenExternalOptions,\n RequestDisplayMode,\n RequestModalOptions,\n RequestSizeOptions,\n ResourceRepresentation,\n SendFollowUpMessageOptions,\n SetViewStateAction,\n UploadFileOptions,\n ViewToolConfig,\n} from \"./types.js\";\nimport { NotSupportedError } from \"./types.js\";\n\nconst ResourceMetaSchema = z\n .object({ writable: z.boolean().optional(), etag: z.string().optional() })\n .optional();\n\nconst WriteResultSchema = z.discriminatedUnion(\"outcome\", [\n z.object({ outcome: z.enum([\"saved\", \"conflict\"]), etag: z.string() }),\n z.object({ outcome: z.literal(\"too-large\"), maxBytes: z.number() }),\n]);\n\nconst STORAGE_PREFIX = \"sb:\";\nconst MAX_STORAGE_ENTRIES = 200;\n\nfunction isImage(mimeType: string | undefined): boolean {\n return mimeType?.startsWith(\"image/\") ?? false;\n}\n\nfunction findStorageKey(viewUUID: string): string | undefined {\n const suffix = `:${viewUUID}`;\n for (let i = 0; i < localStorage.length; i++) {\n const key = localStorage.key(i);\n if (key?.startsWith(STORAGE_PREFIX) && key.endsWith(suffix)) {\n return key;\n }\n }\n return undefined;\n}\n\n/**\n * @internal\n * Single composite implementation of {@link Adaptor}. Composes the MCP App\n * bridge (always present) with an optional `window.openai` overlay. Per-method\n * routing rules are encoded inline.\n */\nexport class HostAdaptor implements Adaptor {\n private static instance: HostAdaptor | null = null;\n\n static getInstance(): HostAdaptor {\n if (!HostAdaptor.instance) {\n HostAdaptor.instance = new HostAdaptor();\n }\n return HostAdaptor.instance;\n }\n\n static resetInstance(): void {\n HostAdaptor.instance?.cleanup();\n HostAdaptor.instance = null;\n }\n\n private readonly mcp: McpAppBridge;\n private readonly openai: typeof window.openai | null = null;\n\n private readonly stores: { [K in keyof HostContext]: HostContextStore<K> };\n\n private _viewState: HostContext[\"viewState\"] = null;\n private readonly viewStateListeners = new Set<() => void>();\n private _viewUUID: string | null = null;\n private _modelContext: ModelContextParams | null = null;\n private readonly resourceListeners = new Map<string, Set<() => void>>();\n private listeningToResources = false;\n\n private _polyfillDisplay: HostContext[\"display\"] = { mode: \"inline\" };\n private readonly polyfillDisplayListeners = new Set<() => void>();\n\n private readonly polyfillDisplayStore: HostContextStore<\"display\">;\n private readonly polyfillViewStateStore: HostContextStore<\"viewState\">;\n\n private unsubscribeViewUUID: (() => void) | null = null;\n private unsubscribeModelContext: (() => void) | null = null;\n\n constructor() {\n this.mcp = McpAppBridge.getInstance();\n\n let overlayStores: ReturnType<AppsSdkBridge[\"createOverlayStores\"]> | null =\n null;\n if (typeof window !== \"undefined\" && window.openai !== undefined) {\n this.openai = window.openai;\n overlayStores = AppsSdkBridge.getInstance().createOverlayStores();\n }\n\n // Built once so that getHostContextStore returns stable references — required\n // by useSyncExternalStore to avoid resubscribing on every render.\n this.polyfillDisplayStore = {\n subscribe: (onChange: () => void) => {\n this.polyfillDisplayListeners.add(onChange);\n return () => {\n this.polyfillDisplayListeners.delete(onChange);\n };\n },\n getSnapshot: () => this._polyfillDisplay,\n };\n this.polyfillViewStateStore = {\n subscribe: (onChange: () => void) => {\n this.viewStateListeners.add(onChange);\n return () => {\n this.viewStateListeners.delete(onChange);\n };\n },\n getSnapshot: () => this._viewState,\n };\n\n this.stores = {\n ...this.mcp.createContextStores(),\n display: overlayStores?.display ?? this.polyfillDisplayStore,\n viewState: overlayStores?.viewState ?? this.polyfillViewStateStore,\n };\n\n this.subscribeToViewUUID();\n this.unsubscribeModelContext = this.mcp.subscribe(\"openai/modelContext\")(\n () => {\n if (this.mcp.getSnapshot(\"openai/modelContext\") === null) {\n this._modelContext = null;\n }\n },\n );\n }\n\n /** @internal Release any subscriptions held on the underlying bridges. */\n public cleanup(): void {\n this.unsubscribeViewUUID?.();\n this.unsubscribeViewUUID = null;\n this.unsubscribeModelContext?.();\n this.unsubscribeModelContext = null;\n }\n\n // ---- Adaptor interface ----\n\n public getHostContextStore = <K extends keyof HostContext>(\n key: K,\n ): HostContextStore<K> => this.stores[key];\n\n public callTool = async <\n ToolArgs extends Record<string, unknown> | null = null,\n ToolResponse extends CallToolResponse = CallToolResponse,\n >(\n name: string,\n args: ToolArgs,\n options?: CallToolOptions,\n ): Promise<ToolResponse> => {\n const timeout = options?.timeout;\n if (timeout !== undefined && (!Number.isFinite(timeout) || timeout <= 0)) {\n throw new RangeError(\n \"Tool call timeout must be a positive, finite number of milliseconds.\",\n );\n }\n const app = await this.mcp.getApp();\n const params = { name, arguments: args ?? undefined };\n const response = await app.callServerTool(params, { timeout });\n return {\n content: response.content,\n structuredContent: response.structuredContent ?? {},\n isError: response.isError ?? false,\n meta: response._meta ?? {},\n } as ToolResponse;\n };\n\n public registerViewTool = (\n config: ViewToolConfig,\n handler: AnyViewToolHandler,\n ): (() => void) => {\n return this.mcp.registerViewTool(config, handler);\n };\n\n public requestDisplayMode = async (mode: RequestDisplayMode) => {\n const app = await this.mcp.getApp();\n return app.requestDisplayMode({ mode });\n };\n\n public requestClose = async (): Promise<void> => {\n if (this.openai) {\n await this.openai.requestClose();\n }\n const app = await this.mcp.getApp();\n await app.requestTeardown();\n };\n\n public requestSize = async (size: RequestSizeOptions): Promise<void> => {\n const app = await this.mcp.getApp();\n await app.sendSizeChanged(size);\n };\n\n public sendFollowUpMessage = async (\n prompt: FollowUpMessage,\n options?: SendFollowUpMessageOptions,\n ): Promise<void> => {\n const target = options?.target;\n if (this.openai && typeof prompt === \"string\" && target !== \"new\") {\n await this.openai.sendFollowUpMessage({\n prompt,\n scrollToBottom: options?.scrollToBottom,\n });\n return;\n }\n const app = await this.mcp.getApp();\n if (\n target === \"new\" &&\n !app.getHostCapabilities()?.experimental?.[\"openai/message\"]\n ) {\n throw new NotSupportedError(\n \"sendFollowUpMessage\",\n \"the host does not advertise openai/message, so it can't open a new conversation\",\n );\n }\n const result = await app.sendMessage({\n role: \"user\",\n content:\n typeof prompt === \"string\" ? [{ type: \"text\", text: prompt }] : prompt,\n ...(target === \"new\" && { _meta: { \"openai/message\": { target } } }),\n });\n if (result?.isError) {\n throw new Error(\"The host rejected the follow-up message.\");\n }\n };\n\n public openExternal = (href: string, options?: OpenExternalOptions): void => {\n if (this.openai) {\n this.openai.openExternal({ href, ...options });\n return;\n }\n this.mcp\n .getApp()\n .then((app) => app.openLink({ url: href }))\n .catch((err) => {\n console.error(\"Failed to open external link:\", err);\n });\n };\n\n public download = async (params: DownloadParams): Promise<DownloadResult> => {\n const app = await this.mcp.getApp();\n if (!app.getHostCapabilities()?.downloadFile) {\n console.error(\n \"[skybridge] download: host does not support ui/download-file\",\n );\n return { isError: true };\n }\n return app.downloadFile(params);\n };\n\n public setViewState = async (\n stateOrUpdater: SetViewStateAction,\n ): Promise<void> => {\n if (this.openai) {\n const modelContent =\n typeof stateOrUpdater === \"function\"\n ? stateOrUpdater(this.openai.widgetState?.modelContent ?? null)\n : stateOrUpdater;\n warnOnLargeViewState(modelContent, \"setWidgetState\");\n await this.openai.setWidgetState({\n privateContent: {},\n ...this.openai.widgetState,\n modelContent,\n });\n return;\n }\n\n const newState =\n typeof stateOrUpdater === \"function\"\n ? stateOrUpdater(this._viewState)\n : stateOrUpdater;\n warnOnLargeViewState(newState, \"setViewState\");\n\n // update local state immediately so successive calls see fresh state\n this._viewState = newState;\n this.viewStateListeners.forEach((l) => {\n l();\n });\n\n this.persistToLocalStorage(newState);\n\n try {\n await this.sendModelContext();\n } catch (error) {\n console.error(\"Failed to update view state in MCP App.\", error);\n }\n };\n\n public updateModelContext = async (\n params: ModelContextParams,\n ): Promise<string | undefined> => {\n const app = await this.mcp.getApp();\n const capabilities = app.getHostCapabilities();\n if (\n !capabilities?.updateModelContext &&\n !capabilities?.experimental?.[\"openai/modelContext\"]\n ) {\n throw new NotSupportedError(\n \"updateModelContext\",\n \"the host does not advertise updateModelContext\",\n );\n }\n const previous = this._modelContext;\n this._modelContext = params;\n const result = await this.sendModelContext().catch((error: unknown) => {\n if (this._modelContext === params) {\n this._modelContext = previous;\n }\n throw error;\n });\n const parsed = z\n .object({ updateId: z.string() })\n .safeParse(result._meta?.[\"openai/modelContext\"]);\n return parsed.success ? parsed.data.updateId : undefined;\n };\n\n private async sendModelContext() {\n const viewState = this.openai ? null : this._viewState;\n const extra = this._modelContext;\n const collisions = Object.keys(extra?.structuredContent ?? {}).filter(\n (key) => viewState !== null && key in viewState,\n );\n if (collisions.length > 0) {\n console.warn(\n `skybridge: view state overrides model context keys ${collisions.join(\", \")}.`,\n );\n }\n const structuredContent = { ...extra?.structuredContent, ...viewState };\n const app = await this.mcp.getApp();\n return app.updateModelContext({\n ...(Object.keys(structuredContent).length > 0 && { structuredContent }),\n content: [\n ...(viewState === null\n ? []\n : [\n {\n type: \"text\" as const,\n text: JSON.stringify(viewState),\n annotations: { audience: [\"assistant\" as const] },\n },\n ]),\n ...(extra?.content ?? []),\n ],\n });\n }\n\n public openFile = async (path: string): Promise<void> => {\n const app = await this.mcp.getApp();\n if (!app.getHostCapabilities()?.experimental?.[\"openai/files\"]) {\n throw new NotSupportedError(\n \"openFile\",\n \"the host does not advertise openai/files\",\n );\n }\n await app.request(\n { method: \"openai/files/open\", params: { path } },\n ResultSchema,\n );\n };\n\n public readResource = async (\n uri: string,\n representation?: ResourceRepresentation,\n ): Promise<FileResource> => {\n const app = await this.mcp.getApp();\n const { contents } = await app.readServerResource({\n uri,\n ...(representation && {\n _meta: { \"openai/resource\": { representation } },\n }),\n });\n const item = contents.find((content) => content.uri === uri) ?? contents[0];\n if (!item) {\n throw new Error(`The host returned no contents for ${uri}.`);\n }\n const { data: meta } = ResourceMetaSchema.safeParse(\n item._meta?.[\"openai/resource\"],\n );\n return {\n ...(\"text\" in item ? { text: item.text } : { blob: item.blob }),\n mimeType: item.mimeType,\n writable: meta?.writable ?? false,\n etag: meta?.etag,\n };\n };\n\n public watchResource = (uri: string, onUpdate: () => void): (() => void) => {\n const app = this.mcp\n .getApp()\n .then((app) =>\n app.getHostCapabilities()?.experimental?.[\"openai/resource\"]\n ? app\n : undefined,\n );\n const listeners = this.resourceListeners.get(uri) ?? new Set<() => void>();\n if (listeners.size === 0) {\n this.resourceListeners.set(uri, listeners);\n app\n .then((app) => {\n if (!app) {\n return;\n }\n if (!this.listeningToResources) {\n app.setNotificationHandler(\n \"notifications/resources/updated\",\n (notification) => {\n this.resourceListeners\n .get(notification.params.uri)\n ?.forEach((l) => {\n l();\n });\n },\n );\n this.listeningToResources = true;\n }\n return app.request(\n { method: \"resources/subscribe\", params: { uri } },\n ResultSchema,\n );\n })\n .catch((error: unknown) => {\n console.warn(`Failed to subscribe to ${uri}.`, error);\n });\n }\n listeners.add(onUpdate);\n return () => {\n if (listeners.delete(onUpdate) && listeners.size === 0) {\n this.resourceListeners.delete(uri);\n app\n .then((app) =>\n app?.request(\n { method: \"resources/unsubscribe\", params: { uri } },\n ResultSchema,\n ),\n )\n .catch(() => {});\n }\n };\n };\n\n public writeResource = async (\n uri: string,\n content: FileResourceContent,\n ifMatch?: string,\n ): Promise<FileResourceWriteResult> => {\n const app = await this.mcp.getApp();\n if (!app.getHostCapabilities()?.experimental?.[\"openai/resource\"]) {\n throw new NotSupportedError(\n \"writeResource\",\n \"the host does not advertise openai/resource\",\n );\n }\n return app.request(\n {\n method: \"openai/resources/write\",\n params: { uri, ...content, ...(ifMatch && { ifMatch }) },\n },\n WriteResultSchema,\n );\n };\n\n public uploadFile = async (\n file: File,\n options?: UploadFileOptions,\n ): Promise<FileMetadata> => {\n if (!this.openai) {\n throw new NotSupportedError(\"uploadFile\");\n }\n const metadata = await this.openai.uploadFile(file, options);\n if (isImage(metadata.mimeType ?? file.type)) {\n await this.trackFileIds(metadata.fileId);\n }\n return metadata;\n };\n\n public getFileDownloadUrl = (\n file: FileMetadata,\n ): Promise<{ downloadUrl: string }> => {\n if (!this.openai) {\n return Promise.reject(new NotSupportedError(\"getFileDownloadUrl\"));\n }\n return this.openai.getFileDownloadUrl(file);\n };\n\n public selectFiles = async (): Promise<FileMetadata[]> => {\n if (!this.openai) {\n throw new NotSupportedError(\"selectFiles\");\n }\n if (!this.openai.selectFiles) {\n throw new Error(\n \"selectFiles is not supported by the current host version.\",\n );\n }\n const files = await this.openai.selectFiles();\n const imageIds: string[] = [];\n for (const file of files) {\n if (isImage(file.mimeType)) {\n imageIds.push(file.fileId);\n }\n }\n if (imageIds.length > 0) {\n await this.trackFileIds(...imageIds);\n }\n return files;\n };\n\n public openModal = (options: RequestModalOptions): void => {\n if (this.openai) {\n this.openai.requestModal(options);\n return;\n }\n this._polyfillDisplay = { mode: \"modal\", params: options.params };\n this.polyfillDisplayListeners.forEach((l) => {\n l();\n });\n };\n\n public setOpenInAppUrl = (href: string): Promise<void> => {\n if (!this.openai) {\n return Promise.reject(new NotSupportedError(\"setOpenInAppUrl\"));\n }\n const trimmed = href.trim();\n if (!trimmed) {\n return Promise.reject(new Error(\"The href parameter is required.\"));\n }\n return this.openai.setOpenInAppUrl({ href: trimmed });\n };\n\n public closeModal = (): void => {\n if (this.openai) {\n return; // host owns modal lifecycle\n }\n this._polyfillDisplay = { mode: \"inline\" };\n this.polyfillDisplayListeners.forEach((l) => {\n l();\n });\n };\n\n private async trackFileIds(...fileIds: string[]): Promise<void> {\n if (!this.openai) {\n return;\n }\n const current = this.openai.widgetState;\n const state: AppsSdkWidgetState = current\n ? { ...current }\n : { modelContent: {}, privateContent: {} };\n if (!state.imageIds) {\n state.imageIds = [];\n }\n state.imageIds.push(...fileIds);\n await this.openai.setWidgetState(state);\n }\n\n // ---- viewState persistence helpers ----\n\n private subscribeToViewUUID(): void {\n this.unsubscribeViewUUID = this.mcp.subscribe(\"toolResult\")(() => {\n const toolResult = this.mcp.getSnapshot(\"toolResult\");\n const viewUUID = (\n toolResult?._meta as Record<string, unknown> | undefined\n )?.viewUUID as string | undefined;\n if (viewUUID && viewUUID !== this._viewUUID) {\n this._viewUUID = viewUUID;\n this.restoreFromLocalStorage(viewUUID);\n }\n });\n }\n\n private restoreFromLocalStorage(viewUUID: string): void {\n try {\n const existingKey = findStorageKey(viewUUID);\n if (existingKey) {\n const stored = localStorage.getItem(existingKey);\n if (stored !== null) {\n this._viewState = JSON.parse(stored);\n this.viewStateListeners.forEach((l) => {\n l();\n });\n }\n }\n } catch (err) {\n console.error(err);\n }\n }\n\n protected persistToLocalStorage(state: Record<string, unknown> | null): void {\n if (!this._viewUUID || state === null) {\n return;\n }\n try {\n const oldKey = findStorageKey(this._viewUUID);\n if (oldKey) {\n localStorage.removeItem(oldKey);\n }\n const newKey = `${STORAGE_PREFIX}${Date.now()}:${this._viewUUID}`;\n localStorage.setItem(newKey, JSON.stringify(state));\n const keys: string[] = [];\n for (let i = 0; i < localStorage.length; i++) {\n const key = localStorage.key(i);\n if (key?.startsWith(STORAGE_PREFIX)) {\n keys.push(key);\n }\n }\n if (keys.length <= MAX_STORAGE_ENTRIES) {\n return;\n }\n keys.sort();\n const toRemove = keys.slice(0, keys.length - MAX_STORAGE_ENTRIES);\n for (const key of toRemove) {\n localStorage.removeItem(key);\n }\n } catch (err) {\n console.error(err);\n }\n }\n}\n"]}
|
|
1
|
+
{"version":3,"file":"adaptor.js","sourceRoot":"","sources":["../../../src/web/bridges/adaptor.ts"],"names":[],"mappings":"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","sourcesContent":["import { ResultSchema } from \"@modelcontextprotocol/core\";\nimport * as z from \"zod/v4\";\nimport { warnOnLargeViewState } from \"../../context-warnings.js\";\nimport { AppsSdkBridge } from \"./apps-sdk/bridge.js\";\nimport type { AppsSdkWidgetState } from \"./apps-sdk/types.js\";\nimport { McpAppBridge } from \"./mcp-app/bridge.js\";\nimport type {\n Adaptor,\n AnyViewToolHandler,\n CallToolOptions,\n CallToolResponse,\n DownloadParams,\n DownloadResult,\n FileMetadata,\n FollowUpMessage,\n HostContext,\n HostContextStore,\n ModelContextParams,\n OpenExternalOptions,\n RequestDisplayMode,\n RequestModalOptions,\n RequestSizeOptions,\n SendFollowUpMessageOptions,\n SetViewStateAction,\n UploadFileOptions,\n ViewToolConfig,\n} from \"./types.js\";\nimport { NotSupportedError } from \"./types.js\";\n\nconst STORAGE_PREFIX = \"sb:\";\nconst MAX_STORAGE_ENTRIES = 200;\n\nfunction isImage(mimeType: string | undefined): boolean {\n return mimeType?.startsWith(\"image/\") ?? false;\n}\n\nfunction findStorageKey(viewUUID: string): string | undefined {\n const suffix = `:${viewUUID}`;\n for (let i = 0; i < localStorage.length; i++) {\n const key = localStorage.key(i);\n if (key?.startsWith(STORAGE_PREFIX) && key.endsWith(suffix)) {\n return key;\n }\n }\n return undefined;\n}\n\n/**\n * @internal\n * Single composite implementation of {@link Adaptor}. Composes the MCP App\n * bridge (always present) with an optional `window.openai` overlay. Per-method\n * routing rules are encoded inline.\n */\nexport class HostAdaptor implements Adaptor {\n private static instance: HostAdaptor | null = null;\n\n static getInstance(): HostAdaptor {\n if (!HostAdaptor.instance) {\n HostAdaptor.instance = new HostAdaptor();\n }\n return HostAdaptor.instance;\n }\n\n static resetInstance(): void {\n HostAdaptor.instance?.cleanup();\n HostAdaptor.instance = null;\n }\n\n private readonly mcp: McpAppBridge;\n private readonly openai: typeof window.openai | null = null;\n\n private readonly stores: { [K in keyof HostContext]: HostContextStore<K> };\n\n private _viewState: HostContext[\"viewState\"] = null;\n private readonly viewStateListeners = new Set<() => void>();\n private _viewUUID: string | null = null;\n private _modelContext: ModelContextParams | null = null;\n\n private _polyfillDisplay: HostContext[\"display\"] = { mode: \"inline\" };\n private readonly polyfillDisplayListeners = new Set<() => void>();\n\n private readonly polyfillDisplayStore: HostContextStore<\"display\">;\n private readonly polyfillViewStateStore: HostContextStore<\"viewState\">;\n\n private unsubscribeViewUUID: (() => void) | null = null;\n private unsubscribeModelContext: (() => void) | null = null;\n\n constructor() {\n this.mcp = McpAppBridge.getInstance();\n\n let overlayStores: ReturnType<AppsSdkBridge[\"createOverlayStores\"]> | null =\n null;\n if (typeof window !== \"undefined\" && window.openai !== undefined) {\n this.openai = window.openai;\n overlayStores = AppsSdkBridge.getInstance().createOverlayStores();\n }\n\n // Built once so that getHostContextStore returns stable references — required\n // by useSyncExternalStore to avoid resubscribing on every render.\n this.polyfillDisplayStore = {\n subscribe: (onChange: () => void) => {\n this.polyfillDisplayListeners.add(onChange);\n return () => {\n this.polyfillDisplayListeners.delete(onChange);\n };\n },\n getSnapshot: () => this._polyfillDisplay,\n };\n this.polyfillViewStateStore = {\n subscribe: (onChange: () => void) => {\n this.viewStateListeners.add(onChange);\n return () => {\n this.viewStateListeners.delete(onChange);\n };\n },\n getSnapshot: () => this._viewState,\n };\n\n this.stores = {\n ...this.mcp.createContextStores(),\n display: overlayStores?.display ?? this.polyfillDisplayStore,\n viewState: overlayStores?.viewState ?? this.polyfillViewStateStore,\n };\n\n this.subscribeToViewUUID();\n this.unsubscribeModelContext = this.mcp.subscribe(\"openai/modelContext\")(\n () => {\n if (this.mcp.getSnapshot(\"openai/modelContext\") === null) {\n this._modelContext = null;\n }\n },\n );\n }\n\n /** @internal Release any subscriptions held on the underlying bridges. */\n public cleanup(): void {\n this.unsubscribeViewUUID?.();\n this.unsubscribeViewUUID = null;\n this.unsubscribeModelContext?.();\n this.unsubscribeModelContext = null;\n }\n\n // ---- Adaptor interface ----\n\n public getHostContextStore = <K extends keyof HostContext>(\n key: K,\n ): HostContextStore<K> => this.stores[key];\n\n public callTool = async <\n ToolArgs extends Record<string, unknown> | null = null,\n ToolResponse extends CallToolResponse = CallToolResponse,\n >(\n name: string,\n args: ToolArgs,\n options?: CallToolOptions,\n ): Promise<ToolResponse> => {\n const timeout = options?.timeout;\n if (timeout !== undefined && (!Number.isFinite(timeout) || timeout <= 0)) {\n throw new RangeError(\n \"Tool call timeout must be a positive, finite number of milliseconds.\",\n );\n }\n const app = await this.mcp.getApp();\n const params = { name, arguments: args ?? undefined };\n const response = await app.callServerTool(params, { timeout });\n return {\n content: response.content,\n structuredContent: response.structuredContent ?? {},\n isError: response.isError ?? false,\n meta: response._meta ?? {},\n } as ToolResponse;\n };\n\n public registerViewTool = (\n config: ViewToolConfig,\n handler: AnyViewToolHandler,\n ): (() => void) => {\n return this.mcp.registerViewTool(config, handler);\n };\n\n public requestDisplayMode = async (mode: RequestDisplayMode) => {\n const app = await this.mcp.getApp();\n return app.requestDisplayMode({ mode });\n };\n\n public requestClose = async (): Promise<void> => {\n if (this.openai) {\n await this.openai.requestClose();\n }\n const app = await this.mcp.getApp();\n await app.requestTeardown();\n };\n\n public requestSize = async (size: RequestSizeOptions): Promise<void> => {\n const app = await this.mcp.getApp();\n await app.sendSizeChanged(size);\n };\n\n public sendFollowUpMessage = async (\n prompt: FollowUpMessage,\n options?: SendFollowUpMessageOptions,\n ): Promise<void> => {\n const target = options?.target;\n if (this.openai && typeof prompt === \"string\" && target !== \"new\") {\n await this.openai.sendFollowUpMessage({\n prompt,\n scrollToBottom: options?.scrollToBottom,\n });\n return;\n }\n const app = await this.mcp.getApp();\n if (\n target === \"new\" &&\n !app.getHostCapabilities()?.experimental?.[\"openai/message\"]\n ) {\n throw new NotSupportedError(\n \"sendFollowUpMessage\",\n \"the host does not advertise openai/message, so it can't open a new conversation\",\n );\n }\n const result = await app.sendMessage({\n role: \"user\",\n content:\n typeof prompt === \"string\" ? [{ type: \"text\", text: prompt }] : prompt,\n ...(target === \"new\" && { _meta: { \"openai/message\": { target } } }),\n });\n if (result?.isError) {\n throw new Error(\"The host rejected the follow-up message.\");\n }\n };\n\n public openExternal = (href: string, options?: OpenExternalOptions): void => {\n if (this.openai) {\n this.openai.openExternal({ href, ...options });\n return;\n }\n this.mcp\n .getApp()\n .then((app) => app.openLink({ url: href }))\n .catch((err) => {\n console.error(\"Failed to open external link:\", err);\n });\n };\n\n public download = async (params: DownloadParams): Promise<DownloadResult> => {\n const app = await this.mcp.getApp();\n if (!app.getHostCapabilities()?.downloadFile) {\n console.error(\n \"[skybridge] download: host does not support ui/download-file\",\n );\n return { isError: true };\n }\n return app.downloadFile(params);\n };\n\n public setViewState = async (\n stateOrUpdater: SetViewStateAction,\n ): Promise<void> => {\n if (this.openai) {\n const modelContent =\n typeof stateOrUpdater === \"function\"\n ? stateOrUpdater(this.openai.widgetState?.modelContent ?? null)\n : stateOrUpdater;\n warnOnLargeViewState(modelContent, \"setWidgetState\");\n await this.openai.setWidgetState({\n privateContent: {},\n ...this.openai.widgetState,\n modelContent,\n });\n return;\n }\n\n const newState =\n typeof stateOrUpdater === \"function\"\n ? stateOrUpdater(this._viewState)\n : stateOrUpdater;\n warnOnLargeViewState(newState, \"setViewState\");\n\n // update local state immediately so successive calls see fresh state\n this._viewState = newState;\n this.viewStateListeners.forEach((l) => {\n l();\n });\n\n this.persistToLocalStorage(newState);\n\n try {\n await this.sendModelContext();\n } catch (error) {\n console.error(\"Failed to update view state in MCP App.\", error);\n }\n };\n\n public updateModelContext = async (\n params: ModelContextParams,\n ): Promise<string | undefined> => {\n const app = await this.mcp.getApp();\n const capabilities = app.getHostCapabilities();\n if (\n !capabilities?.updateModelContext &&\n !capabilities?.experimental?.[\"openai/modelContext\"]\n ) {\n throw new NotSupportedError(\n \"updateModelContext\",\n \"the host does not advertise updateModelContext\",\n );\n }\n const previous = this._modelContext;\n this._modelContext = params;\n const result = await this.sendModelContext().catch((error: unknown) => {\n if (this._modelContext === params) {\n this._modelContext = previous;\n }\n throw error;\n });\n const parsed = z\n .object({ updateId: z.string() })\n .safeParse(result._meta?.[\"openai/modelContext\"]);\n return parsed.success ? parsed.data.updateId : undefined;\n };\n\n private async sendModelContext() {\n const viewState = this.openai ? null : this._viewState;\n const extra = this._modelContext;\n const collisions = Object.keys(extra?.structuredContent ?? {}).filter(\n (key) => viewState !== null && key in viewState,\n );\n if (collisions.length > 0) {\n console.warn(\n `skybridge: view state overrides model context keys ${collisions.join(\", \")}.`,\n );\n }\n const structuredContent = { ...extra?.structuredContent, ...viewState };\n const app = await this.mcp.getApp();\n return app.updateModelContext({\n ...(Object.keys(structuredContent).length > 0 && { structuredContent }),\n content: [\n ...(viewState === null\n ? []\n : [\n {\n type: \"text\" as const,\n text: JSON.stringify(viewState),\n annotations: { audience: [\"assistant\" as const] },\n },\n ]),\n ...(extra?.content ?? []),\n ],\n });\n }\n\n public openFile = async (path: string): Promise<void> => {\n const app = await this.mcp.getApp();\n if (!app.getHostCapabilities()?.experimental?.[\"openai/files\"]) {\n throw new NotSupportedError(\n \"openFile\",\n \"the host does not advertise openai/files\",\n );\n }\n await app.request(\n { method: \"openai/files/open\", params: { path } },\n ResultSchema,\n );\n };\n\n public uploadFile = async (\n file: File,\n options?: UploadFileOptions,\n ): Promise<FileMetadata> => {\n if (!this.openai) {\n throw new NotSupportedError(\"uploadFile\");\n }\n const metadata = await this.openai.uploadFile(file, options);\n if (isImage(metadata.mimeType ?? file.type)) {\n await this.trackFileIds(metadata.fileId);\n }\n return metadata;\n };\n\n public getFileDownloadUrl = (\n file: FileMetadata,\n ): Promise<{ downloadUrl: string }> => {\n if (!this.openai) {\n return Promise.reject(new NotSupportedError(\"getFileDownloadUrl\"));\n }\n return this.openai.getFileDownloadUrl(file);\n };\n\n public selectFiles = async (): Promise<FileMetadata[]> => {\n if (!this.openai) {\n throw new NotSupportedError(\"selectFiles\");\n }\n if (!this.openai.selectFiles) {\n throw new Error(\n \"selectFiles is not supported by the current host version.\",\n );\n }\n const files = await this.openai.selectFiles();\n const imageIds: string[] = [];\n for (const file of files) {\n if (isImage(file.mimeType)) {\n imageIds.push(file.fileId);\n }\n }\n if (imageIds.length > 0) {\n await this.trackFileIds(...imageIds);\n }\n return files;\n };\n\n public openModal = (options: RequestModalOptions): void => {\n if (this.openai) {\n this.openai.requestModal(options);\n return;\n }\n this._polyfillDisplay = { mode: \"modal\", params: options.params };\n this.polyfillDisplayListeners.forEach((l) => {\n l();\n });\n };\n\n public setOpenInAppUrl = (href: string): Promise<void> => {\n if (!this.openai) {\n return Promise.reject(new NotSupportedError(\"setOpenInAppUrl\"));\n }\n const trimmed = href.trim();\n if (!trimmed) {\n return Promise.reject(new Error(\"The href parameter is required.\"));\n }\n return this.openai.setOpenInAppUrl({ href: trimmed });\n };\n\n public closeModal = (): void => {\n if (this.openai) {\n return; // host owns modal lifecycle\n }\n this._polyfillDisplay = { mode: \"inline\" };\n this.polyfillDisplayListeners.forEach((l) => {\n l();\n });\n };\n\n private async trackFileIds(...fileIds: string[]): Promise<void> {\n if (!this.openai) {\n return;\n }\n const current = this.openai.widgetState;\n const state: AppsSdkWidgetState = current\n ? { ...current }\n : { modelContent: {}, privateContent: {} };\n if (!state.imageIds) {\n state.imageIds = [];\n }\n state.imageIds.push(...fileIds);\n await this.openai.setWidgetState(state);\n }\n\n // ---- viewState persistence helpers ----\n\n private subscribeToViewUUID(): void {\n this.unsubscribeViewUUID = this.mcp.subscribe(\"toolResult\")(() => {\n const toolResult = this.mcp.getSnapshot(\"toolResult\");\n const viewUUID = (\n toolResult?._meta as Record<string, unknown> | undefined\n )?.viewUUID as string | undefined;\n if (viewUUID && viewUUID !== this._viewUUID) {\n this._viewUUID = viewUUID;\n this.restoreFromLocalStorage(viewUUID);\n }\n });\n }\n\n private restoreFromLocalStorage(viewUUID: string): void {\n try {\n const existingKey = findStorageKey(viewUUID);\n if (existingKey) {\n const stored = localStorage.getItem(existingKey);\n if (stored !== null) {\n this._viewState = JSON.parse(stored);\n this.viewStateListeners.forEach((l) => {\n l();\n });\n }\n }\n } catch (err) {\n console.error(err);\n }\n }\n\n protected persistToLocalStorage(state: Record<string, unknown> | null): void {\n if (!this._viewUUID || state === null) {\n return;\n }\n try {\n const oldKey = findStorageKey(this._viewUUID);\n if (oldKey) {\n localStorage.removeItem(oldKey);\n }\n const newKey = `${STORAGE_PREFIX}${Date.now()}:${this._viewUUID}`;\n localStorage.setItem(newKey, JSON.stringify(state));\n const keys: string[] = [];\n for (let i = 0; i < localStorage.length; i++) {\n const key = localStorage.key(i);\n if (key?.startsWith(STORAGE_PREFIX)) {\n keys.push(key);\n }\n }\n if (keys.length <= MAX_STORAGE_ENTRIES) {\n return;\n }\n keys.sort();\n const toRemove = keys.slice(0, keys.length - MAX_STORAGE_ENTRIES);\n for (const key of toRemove) {\n localStorage.removeItem(key);\n }\n } catch (err) {\n console.error(err);\n }\n }\n}\n"]}
|
|
@@ -149,33 +149,6 @@ export type SendFollowUpMessageOptions = {
|
|
|
149
149
|
*/
|
|
150
150
|
target?: "active" | "new";
|
|
151
151
|
};
|
|
152
|
-
/** How the host should return a file resource's contents. */
|
|
153
|
-
export type ResourceRepresentation = "text" | "blob";
|
|
154
|
-
/** Contents of a file resource: text, or a base64 `blob`. */
|
|
155
|
-
export type FileResourceContent = {
|
|
156
|
-
text: string;
|
|
157
|
-
} | {
|
|
158
|
-
blob: string;
|
|
159
|
-
};
|
|
160
|
-
/** A file resource as read from the host. */
|
|
161
|
-
export type FileResource = FileResourceContent & {
|
|
162
|
-
mimeType?: string;
|
|
163
|
-
/** Whether the host accepts writes to this resource. */
|
|
164
|
-
writable: boolean;
|
|
165
|
-
/** Version token of these contents, sent back as `ifMatch` on write. */
|
|
166
|
-
etag?: string;
|
|
167
|
-
};
|
|
168
|
-
/** Result of `openai/resources/write`. */
|
|
169
|
-
export type FileResourceWriteResult = {
|
|
170
|
-
outcome: "saved";
|
|
171
|
-
etag: string;
|
|
172
|
-
} | {
|
|
173
|
-
outcome: "conflict";
|
|
174
|
-
etag: string;
|
|
175
|
-
} | {
|
|
176
|
-
outcome: "too-large";
|
|
177
|
-
maxBytes: number;
|
|
178
|
-
};
|
|
179
152
|
/**
|
|
180
153
|
* A follow-up message: plain text, or content blocks. On ChatGPT, a text or
|
|
181
154
|
* image block with `_meta["openai/title"]` becomes a labeled item the user can
|
|
@@ -251,9 +224,6 @@ export interface Adaptor {
|
|
|
251
224
|
setViewState(stateOrUpdater: SetViewStateAction): Promise<void>;
|
|
252
225
|
updateModelContext(params: ModelContextParams): Promise<string | undefined>;
|
|
253
226
|
openFile(path: string): Promise<void>;
|
|
254
|
-
readResource(uri: string, representation?: ResourceRepresentation): Promise<FileResource>;
|
|
255
|
-
watchResource(uri: string, onUpdate: () => void): () => void;
|
|
256
|
-
writeResource(uri: string, content: FileResourceContent, ifMatch?: string): Promise<FileResourceWriteResult>;
|
|
257
227
|
uploadFile(file: File, options?: UploadFileOptions): Promise<FileMetadata>;
|
|
258
228
|
getFileDownloadUrl(file: FileMetadata): Promise<{
|
|
259
229
|
downloadUrl: string;
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"types.js","sourceRoot":"","sources":["../../../src/web/bridges/types.ts"],"names":[],"mappings":"AAsUA;;;GAGG;AACH,MAAM,OAAO,iBAAkB,SAAQ,KAAK;IAExB;IACA;IAFlB,YACkB,MAAc,EACd,MAAe;QAE/B,KAAK,CACH,GAAG,MAAM,oCAAoC,MAAM,CAAC,CAAC,CAAC,KAAK,MAAM,EAAE,CAAC,CAAC,CAAC,EAAE,EAAE,CAC3E,CAAC;QALc,WAAM,GAAN,MAAM,CAAQ;QACd,WAAM,GAAN,MAAM,CAAS;QAK/B,IAAI,CAAC,IAAI,GAAG,mBAAmB,CAAC;IAClC,CAAC;CACF","sourcesContent":["import type {\n CallToolResult,\n ContentBlock,\n EmbeddedResource,\n ResourceLink,\n ToolAnnotations,\n} from \"@modelcontextprotocol/client\";\nimport type { McpUiUpdateModelContextRequest } from \"@modelcontextprotocol/ext-apps\";\nimport type { useSyncExternalStore } from \"react\";\nimport type { output as ZodOutput, ZodType } from \"zod/v4\";\n\n/**\n * Globals injected on `window.skybridge` by the host. Tells the view where to\n * reach the MCP server.\n */\nexport type SkybridgeProperties = {\n serverUrl: string;\n};\n\ndeclare global {\n interface Window {\n skybridge: SkybridgeProperties;\n }\n}\n\n/** Arguments passed to a tool call. `null` for tools that take no input. */\nexport type CallToolArgs = Record<string, unknown> | null;\n\n/** Options for a tool call made from the view. */\nexport type CallToolOptions = {\n /**\n * Request timeout in milliseconds. Omit it to keep the SDK default (60s).\n * Raise it for tools that wait on the user, such as ChatGPT forms.\n */\n timeout?: number;\n};\n\n/** Payload of `ui/update-model-context`. Content blocks may carry `_meta`. */\nexport type ModelContextParams = McpUiUpdateModelContextRequest[\"params\"];\n\n/**\n * Result of a tool call as surfaced to the view: MCP `content` blocks plus\n * the typed `structuredContent` and optional `meta`. `isError` is set when\n * the server marks the call as failed.\n */\nexport type CallToolResponse = {\n content: CallToolResult[\"content\"];\n structuredContent: NonNullable<CallToolResult[\"structuredContent\"]>;\n isError: NonNullable<CallToolResult[\"isError\"]>;\n meta?: CallToolResult[\"_meta\"];\n};\n\n/**\n * How the view is laid out by the host. `\"modal\"` is host-driven (see\n * {@link useRequestModal}); `\"pip\"`, `\"inline\"`, and `\"fullscreen\"` are\n * requestable via {@link useDisplayMode}.\n */\nexport type DisplayMode = \"pip\" | \"inline\" | \"fullscreen\" | \"modal\";\n/** Subset of {@link DisplayMode} that the view can request from the host. */\nexport type RequestDisplayMode = Exclude<DisplayMode, \"modal\">;\n\n/** Host theme. Mirror this in your view's styling for a native feel. */\nexport type Theme = \"light\" | \"dark\";\n\n/** Coarse device class reported by the host. `\"unknown\"` when unavailable. */\nexport type DeviceType = \"mobile\" | \"tablet\" | \"desktop\" | \"unknown\";\n\n/** Pixel insets the view should keep clear of (notches, home indicators, etc.). */\nexport type SafeAreaInsets = {\n top: number;\n right: number;\n bottom: number;\n left: number;\n};\n\n/** Wrapper around {@link SafeAreaInsets} exposed via {@link useViewport}. */\nexport type SafeArea = {\n insets: SafeAreaInsets;\n};\n\n/** Device and input-capability hints exposed via {@link useUser}. */\nexport type UserAgent = {\n device: {\n type: DeviceType;\n };\n capabilities: {\n hover: boolean;\n touch: boolean;\n };\n};\n\n/**\n * Full snapshot of state the host exposes to the view. Most fields are\n * better accessed through their dedicated hooks (`useViewport`, `useUser`,\n * `useToolInfo`, etc.) — read this directly only for advanced cases.\n */\nexport interface HostContext {\n theme: Theme;\n locale: string;\n displayMode: DisplayMode;\n safeArea: SafeArea;\n maxHeight: number | undefined;\n userAgent: UserAgent;\n toolInput: Record<string, unknown> | null;\n toolOutput: Record<string, unknown> | null;\n toolResponseMetadata: Record<string, unknown> | null;\n display: {\n mode: DisplayMode;\n params?: Record<string, unknown>;\n };\n viewState: Record<string, unknown> | null;\n}\n\n/** @internal `useSyncExternalStore` subscribe signature, re-exported for bridge implementations. */\nexport type Subscribe = Parameters<typeof useSyncExternalStore>[0];\n\n/** @internal Bridge contract implemented by per-host bridge classes. */\nexport interface Bridge<Context> {\n subscribe(key: keyof Context): Subscribe;\n subscribe(keys: readonly (keyof Context)[]): Subscribe;\n getSnapshot<K extends keyof Context>(key: K): Context[K] | undefined;\n}\n\n/** @internal Per-key snapshot store backing {@link useHostContext}. */\nexport type HostContextStore<K extends keyof HostContext> = {\n subscribe: Subscribe;\n getSnapshot: () => HostContext[K];\n};\n\n/** Persisted view state shape (a plain object). See {@link useViewState}. */\nexport type ViewState = Record<string, unknown>;\n\n/** Updater form accepted when writing to view state. */\nexport type SetViewStateAction =\n | ViewState\n | ((prevState: ViewState | null) => ViewState);\n\n/** Reference to a host-managed file (returned by {@link useFiles}). */\nexport type FileMetadata = {\n fileId: string;\n fileName?: string;\n mimeType?: string;\n};\n\n/** Options for {@link useFiles}'s `upload`. `library: true` saves into the user's library when supported. */\nexport type UploadFileOptions = { library?: boolean };\n\n/** Options for {@link useRequestModal}'s `open` call. */\nexport type RequestModalOptions = {\n title?: string;\n params?: Record<string, unknown>;\n template?: string;\n anchor?: { top?: number; left?: number; width?: number; height?: number };\n};\n\n/**\n * Options for {@link useOpenExternal}. Set `redirectUrl: false` to tell the\n * host not to append its `?redirectUrl=…` tracking query parameter when\n * opening allowlisted targets.\n */\nexport type OpenExternalOptions = {\n redirectUrl?: false;\n};\n\n/** Options for {@link useSendFollowUpMessage}. */\nexport type SendFollowUpMessageOptions = {\n /** Apps SDK only: set to `false` to keep the chat scroll position. */\n scrollToBottom?: boolean;\n /**\n * ChatGPT only, from the OpenAI MCP extensions: `\"new\"` starts a new\n * conversation with the message. Defaults to the active conversation.\n * Rejects on hosts that don't advertise `openai/message`.\n */\n target?: \"active\" | \"new\";\n};\n\n/** How the host should return a file resource's contents. */\nexport type ResourceRepresentation = \"text\" | \"blob\";\n\n/** Contents of a file resource: text, or a base64 `blob`. */\nexport type FileResourceContent = { text: string } | { blob: string };\n\n/** A file resource as read from the host. */\nexport type FileResource = FileResourceContent & {\n mimeType?: string;\n /** Whether the host accepts writes to this resource. */\n writable: boolean;\n /** Version token of these contents, sent back as `ifMatch` on write. */\n etag?: string;\n};\n\n/** Result of `openai/resources/write`. */\nexport type FileResourceWriteResult =\n | { outcome: \"saved\"; etag: string }\n | { outcome: \"conflict\"; etag: string }\n | { outcome: \"too-large\"; maxBytes: number };\n\n/**\n * A follow-up message: plain text, or content blocks. On ChatGPT, a text or\n * image block with `_meta[\"openai/title\"]` becomes a labeled item the user can\n * remove.\n */\nexport type FollowUpMessage = string | ContentBlock[];\n\n/** Options for {@link useRequestSize}. Omit a dimension to leave it unchanged. */\nexport type RequestSizeOptions = {\n width?: number;\n height?: number;\n};\n\nexport type DownloadParams = {\n contents: (EmbeddedResource | ResourceLink)[];\n};\n\nexport type DownloadResult = {\n isError?: boolean;\n};\n\n/**\n * Shape of a view tool's `inputSchema`: a map of zod schemas. Narrower than\n * the server's `Record<string, StandardSchemaWithJSON>` input shape because the MCP Apps bridge validates with\n * `z.object()` at runtime — other Standard Schema libraries would type-check\n * but throw on the first call.\n */\nexport type ViewToolInputShape = Record<string, ZodType>;\n\n/**\n * Args passed to a {@link ViewToolHandler}, inferred from the tool's\n * `inputSchema` (optionality preserved). Mirrors the server's `registerTool`.\n */\nexport type InferViewToolArgs<Shape extends ViewToolInputShape> = {\n [K in keyof Shape as undefined extends ZodOutput<Shape[K]>\n ? never\n : K]: ZodOutput<Shape[K]>;\n} & {\n [K in keyof Shape as undefined extends ZodOutput<Shape[K]>\n ? K\n : never]?: ZodOutput<Shape[K]>;\n};\n\n/**\n * Declares a tool the view exposes to the host/model (the MCP Apps\n * \"app-provided tools\" feature). Mirrors the server-side `registerTool` config.\n * Namespace `name` (e.g. `chess_make_move`) to avoid clashing with server tools.\n */\nexport type ViewToolConfig<\n TInput extends ViewToolInputShape = ViewToolInputShape,\n> = {\n name: string;\n title?: string;\n description?: string;\n inputSchema?: TInput;\n annotations?: ToolAnnotations;\n};\n\n/**\n * Value a {@link ViewToolHandler} returns — a standard MCP `CallToolResult`\n * (`content` blocks plus optional `structuredContent` / `isError` / `_meta`),\n * exactly as `ext-apps`' app tool callbacks return it.\n */\nexport type ViewToolResult = CallToolResult;\n\n/** Handler run when the host calls a view tool. Receives validated, typed args. */\nexport type ViewToolHandler<\n TInput extends ViewToolInputShape = ViewToolInputShape,\n> = (\n args: InferViewToolArgs<TInput>,\n) => ViewToolResult | Promise<ViewToolResult>;\n\n/** @internal Untyped handler signature stored by the adaptor/bridge after type erasure. */\nexport type AnyViewToolHandler = (\n args: Record<string, unknown>,\n) => ViewToolResult | Promise<ViewToolResult>;\n\n/**\n * @internal\n * Low-level interface every host bridge implements. End-user code should use\n * the React hooks (`useCallTool`, `useViewState`, `useFiles`, …) rather than\n * calling this directly.\n */\nexport interface Adaptor {\n getHostContextStore<K extends keyof HostContext>(key: K): HostContextStore<K>;\n callTool<\n ToolArgs extends CallToolArgs = null,\n ToolResponse extends CallToolResponse = CallToolResponse,\n >(\n name: string,\n args: ToolArgs,\n options?: CallToolOptions,\n ): Promise<ToolResponse>;\n requestDisplayMode(mode: RequestDisplayMode): Promise<{\n mode: RequestDisplayMode;\n }>;\n requestClose(): Promise<void>;\n requestSize(size: RequestSizeOptions): Promise<void>;\n sendFollowUpMessage(\n prompt: FollowUpMessage,\n options?: SendFollowUpMessageOptions,\n ): Promise<void>;\n openExternal(href: string, options?: OpenExternalOptions): void;\n download(params: DownloadParams): Promise<DownloadResult>;\n setViewState(stateOrUpdater: SetViewStateAction): Promise<void>;\n updateModelContext(params: ModelContextParams): Promise<string | undefined>;\n openFile(path: string): Promise<void>;\n readResource(\n uri: string,\n representation?: ResourceRepresentation,\n ): Promise<FileResource>;\n watchResource(uri: string, onUpdate: () => void): () => void;\n writeResource(\n uri: string,\n content: FileResourceContent,\n ifMatch?: string,\n ): Promise<FileResourceWriteResult>;\n uploadFile(file: File, options?: UploadFileOptions): Promise<FileMetadata>;\n getFileDownloadUrl(file: FileMetadata): Promise<{ downloadUrl: string }>;\n selectFiles(): Promise<FileMetadata[]>;\n openModal(options: RequestModalOptions): void;\n setOpenInAppUrl(href: string): Promise<void>;\n closeModal(): void;\n registerViewTool(\n config: ViewToolConfig,\n handler: AnyViewToolHandler,\n ): () => void;\n}\n\n/**\n * Thrown when a host bridge method is called in a runtime that doesn't\n * support it (e.g. `uploadFile` outside the ChatGPT runtime).\n */\nexport class NotSupportedError extends Error {\n constructor(\n public readonly method: string,\n public readonly reason?: string,\n ) {\n super(\n `${method} is not supported in this runtime${reason ? `: ${reason}` : \"\"}`,\n );\n this.name = \"NotSupportedError\";\n }\n}\n"]}
|
|
1
|
+
{"version":3,"file":"types.js","sourceRoot":"","sources":["../../../src/web/bridges/types.ts"],"names":[],"mappings":"AAuSA;;;GAGG;AACH,MAAM,OAAO,iBAAkB,SAAQ,KAAK;IAExB;IACA;IAFlB,YACkB,MAAc,EACd,MAAe;QAE/B,KAAK,CACH,GAAG,MAAM,oCAAoC,MAAM,CAAC,CAAC,CAAC,KAAK,MAAM,EAAE,CAAC,CAAC,CAAC,EAAE,EAAE,CAC3E,CAAC;QALc,WAAM,GAAN,MAAM,CAAQ;QACd,WAAM,GAAN,MAAM,CAAS;QAK/B,IAAI,CAAC,IAAI,GAAG,mBAAmB,CAAC;IAClC,CAAC;CACF","sourcesContent":["import type {\n CallToolResult,\n ContentBlock,\n EmbeddedResource,\n ResourceLink,\n ToolAnnotations,\n} from \"@modelcontextprotocol/client\";\nimport type { McpUiUpdateModelContextRequest } from \"@modelcontextprotocol/ext-apps\";\nimport type { useSyncExternalStore } from \"react\";\nimport type { output as ZodOutput, ZodType } from \"zod/v4\";\n\n/**\n * Globals injected on `window.skybridge` by the host. Tells the view where to\n * reach the MCP server.\n */\nexport type SkybridgeProperties = {\n serverUrl: string;\n};\n\ndeclare global {\n interface Window {\n skybridge: SkybridgeProperties;\n }\n}\n\n/** Arguments passed to a tool call. `null` for tools that take no input. */\nexport type CallToolArgs = Record<string, unknown> | null;\n\n/** Options for a tool call made from the view. */\nexport type CallToolOptions = {\n /**\n * Request timeout in milliseconds. Omit it to keep the SDK default (60s).\n * Raise it for tools that wait on the user, such as ChatGPT forms.\n */\n timeout?: number;\n};\n\n/** Payload of `ui/update-model-context`. Content blocks may carry `_meta`. */\nexport type ModelContextParams = McpUiUpdateModelContextRequest[\"params\"];\n\n/**\n * Result of a tool call as surfaced to the view: MCP `content` blocks plus\n * the typed `structuredContent` and optional `meta`. `isError` is set when\n * the server marks the call as failed.\n */\nexport type CallToolResponse = {\n content: CallToolResult[\"content\"];\n structuredContent: NonNullable<CallToolResult[\"structuredContent\"]>;\n isError: NonNullable<CallToolResult[\"isError\"]>;\n meta?: CallToolResult[\"_meta\"];\n};\n\n/**\n * How the view is laid out by the host. `\"modal\"` is host-driven (see\n * {@link useRequestModal}); `\"pip\"`, `\"inline\"`, and `\"fullscreen\"` are\n * requestable via {@link useDisplayMode}.\n */\nexport type DisplayMode = \"pip\" | \"inline\" | \"fullscreen\" | \"modal\";\n/** Subset of {@link DisplayMode} that the view can request from the host. */\nexport type RequestDisplayMode = Exclude<DisplayMode, \"modal\">;\n\n/** Host theme. Mirror this in your view's styling for a native feel. */\nexport type Theme = \"light\" | \"dark\";\n\n/** Coarse device class reported by the host. `\"unknown\"` when unavailable. */\nexport type DeviceType = \"mobile\" | \"tablet\" | \"desktop\" | \"unknown\";\n\n/** Pixel insets the view should keep clear of (notches, home indicators, etc.). */\nexport type SafeAreaInsets = {\n top: number;\n right: number;\n bottom: number;\n left: number;\n};\n\n/** Wrapper around {@link SafeAreaInsets} exposed via {@link useViewport}. */\nexport type SafeArea = {\n insets: SafeAreaInsets;\n};\n\n/** Device and input-capability hints exposed via {@link useUser}. */\nexport type UserAgent = {\n device: {\n type: DeviceType;\n };\n capabilities: {\n hover: boolean;\n touch: boolean;\n };\n};\n\n/**\n * Full snapshot of state the host exposes to the view. Most fields are\n * better accessed through their dedicated hooks (`useViewport`, `useUser`,\n * `useToolInfo`, etc.) — read this directly only for advanced cases.\n */\nexport interface HostContext {\n theme: Theme;\n locale: string;\n displayMode: DisplayMode;\n safeArea: SafeArea;\n maxHeight: number | undefined;\n userAgent: UserAgent;\n toolInput: Record<string, unknown> | null;\n toolOutput: Record<string, unknown> | null;\n toolResponseMetadata: Record<string, unknown> | null;\n display: {\n mode: DisplayMode;\n params?: Record<string, unknown>;\n };\n viewState: Record<string, unknown> | null;\n}\n\n/** @internal `useSyncExternalStore` subscribe signature, re-exported for bridge implementations. */\nexport type Subscribe = Parameters<typeof useSyncExternalStore>[0];\n\n/** @internal Bridge contract implemented by per-host bridge classes. */\nexport interface Bridge<Context> {\n subscribe(key: keyof Context): Subscribe;\n subscribe(keys: readonly (keyof Context)[]): Subscribe;\n getSnapshot<K extends keyof Context>(key: K): Context[K] | undefined;\n}\n\n/** @internal Per-key snapshot store backing {@link useHostContext}. */\nexport type HostContextStore<K extends keyof HostContext> = {\n subscribe: Subscribe;\n getSnapshot: () => HostContext[K];\n};\n\n/** Persisted view state shape (a plain object). See {@link useViewState}. */\nexport type ViewState = Record<string, unknown>;\n\n/** Updater form accepted when writing to view state. */\nexport type SetViewStateAction =\n | ViewState\n | ((prevState: ViewState | null) => ViewState);\n\n/** Reference to a host-managed file (returned by {@link useFiles}). */\nexport type FileMetadata = {\n fileId: string;\n fileName?: string;\n mimeType?: string;\n};\n\n/** Options for {@link useFiles}'s `upload`. `library: true` saves into the user's library when supported. */\nexport type UploadFileOptions = { library?: boolean };\n\n/** Options for {@link useRequestModal}'s `open` call. */\nexport type RequestModalOptions = {\n title?: string;\n params?: Record<string, unknown>;\n template?: string;\n anchor?: { top?: number; left?: number; width?: number; height?: number };\n};\n\n/**\n * Options for {@link useOpenExternal}. Set `redirectUrl: false` to tell the\n * host not to append its `?redirectUrl=…` tracking query parameter when\n * opening allowlisted targets.\n */\nexport type OpenExternalOptions = {\n redirectUrl?: false;\n};\n\n/** Options for {@link useSendFollowUpMessage}. */\nexport type SendFollowUpMessageOptions = {\n /** Apps SDK only: set to `false` to keep the chat scroll position. */\n scrollToBottom?: boolean;\n /**\n * ChatGPT only, from the OpenAI MCP extensions: `\"new\"` starts a new\n * conversation with the message. Defaults to the active conversation.\n * Rejects on hosts that don't advertise `openai/message`.\n */\n target?: \"active\" | \"new\";\n};\n\n/**\n * A follow-up message: plain text, or content blocks. On ChatGPT, a text or\n * image block with `_meta[\"openai/title\"]` becomes a labeled item the user can\n * remove.\n */\nexport type FollowUpMessage = string | ContentBlock[];\n\n/** Options for {@link useRequestSize}. Omit a dimension to leave it unchanged. */\nexport type RequestSizeOptions = {\n width?: number;\n height?: number;\n};\n\nexport type DownloadParams = {\n contents: (EmbeddedResource | ResourceLink)[];\n};\n\nexport type DownloadResult = {\n isError?: boolean;\n};\n\n/**\n * Shape of a view tool's `inputSchema`: a map of zod schemas. Narrower than\n * the server's `Record<string, StandardSchemaWithJSON>` input shape because the MCP Apps bridge validates with\n * `z.object()` at runtime — other Standard Schema libraries would type-check\n * but throw on the first call.\n */\nexport type ViewToolInputShape = Record<string, ZodType>;\n\n/**\n * Args passed to a {@link ViewToolHandler}, inferred from the tool's\n * `inputSchema` (optionality preserved). Mirrors the server's `registerTool`.\n */\nexport type InferViewToolArgs<Shape extends ViewToolInputShape> = {\n [K in keyof Shape as undefined extends ZodOutput<Shape[K]>\n ? never\n : K]: ZodOutput<Shape[K]>;\n} & {\n [K in keyof Shape as undefined extends ZodOutput<Shape[K]>\n ? K\n : never]?: ZodOutput<Shape[K]>;\n};\n\n/**\n * Declares a tool the view exposes to the host/model (the MCP Apps\n * \"app-provided tools\" feature). Mirrors the server-side `registerTool` config.\n * Namespace `name` (e.g. `chess_make_move`) to avoid clashing with server tools.\n */\nexport type ViewToolConfig<\n TInput extends ViewToolInputShape = ViewToolInputShape,\n> = {\n name: string;\n title?: string;\n description?: string;\n inputSchema?: TInput;\n annotations?: ToolAnnotations;\n};\n\n/**\n * Value a {@link ViewToolHandler} returns — a standard MCP `CallToolResult`\n * (`content` blocks plus optional `structuredContent` / `isError` / `_meta`),\n * exactly as `ext-apps`' app tool callbacks return it.\n */\nexport type ViewToolResult = CallToolResult;\n\n/** Handler run when the host calls a view tool. Receives validated, typed args. */\nexport type ViewToolHandler<\n TInput extends ViewToolInputShape = ViewToolInputShape,\n> = (\n args: InferViewToolArgs<TInput>,\n) => ViewToolResult | Promise<ViewToolResult>;\n\n/** @internal Untyped handler signature stored by the adaptor/bridge after type erasure. */\nexport type AnyViewToolHandler = (\n args: Record<string, unknown>,\n) => ViewToolResult | Promise<ViewToolResult>;\n\n/**\n * @internal\n * Low-level interface every host bridge implements. End-user code should use\n * the React hooks (`useCallTool`, `useViewState`, `useFiles`, …) rather than\n * calling this directly.\n */\nexport interface Adaptor {\n getHostContextStore<K extends keyof HostContext>(key: K): HostContextStore<K>;\n callTool<\n ToolArgs extends CallToolArgs = null,\n ToolResponse extends CallToolResponse = CallToolResponse,\n >(\n name: string,\n args: ToolArgs,\n options?: CallToolOptions,\n ): Promise<ToolResponse>;\n requestDisplayMode(mode: RequestDisplayMode): Promise<{\n mode: RequestDisplayMode;\n }>;\n requestClose(): Promise<void>;\n requestSize(size: RequestSizeOptions): Promise<void>;\n sendFollowUpMessage(\n prompt: FollowUpMessage,\n options?: SendFollowUpMessageOptions,\n ): Promise<void>;\n openExternal(href: string, options?: OpenExternalOptions): void;\n download(params: DownloadParams): Promise<DownloadResult>;\n setViewState(stateOrUpdater: SetViewStateAction): Promise<void>;\n updateModelContext(params: ModelContextParams): Promise<string | undefined>;\n openFile(path: string): Promise<void>;\n uploadFile(file: File, options?: UploadFileOptions): Promise<FileMetadata>;\n getFileDownloadUrl(file: FileMetadata): Promise<{ downloadUrl: string }>;\n selectFiles(): Promise<FileMetadata[]>;\n openModal(options: RequestModalOptions): void;\n setOpenInAppUrl(href: string): Promise<void>;\n closeModal(): void;\n registerViewTool(\n config: ViewToolConfig,\n handler: AnyViewToolHandler,\n ): () => void;\n}\n\n/**\n * Thrown when a host bridge method is called in a runtime that doesn't\n * support it (e.g. `uploadFile` outside the ChatGPT runtime).\n */\nexport class NotSupportedError extends Error {\n constructor(\n public readonly method: string,\n public readonly reason?: string,\n ) {\n super(\n `${method} is not supported in this runtime${reason ? `: ${reason}` : \"\"}`,\n );\n this.name = \"NotSupportedError\";\n }\n}\n"]}
|
|
@@ -2,7 +2,6 @@ export { type CallToolAsyncFn, type CallToolFn, type CallToolState, type SideEff
|
|
|
2
2
|
export { useDeepLink } from "./use-deep-link.js";
|
|
3
3
|
export { useDisplayMode } from "./use-display-mode.js";
|
|
4
4
|
export { type DownloadFn, useDownload } from "./use-download.js";
|
|
5
|
-
export { type FileResourceState, useFileResource, } from "./use-file-resource.js";
|
|
6
5
|
export { useFiles } from "./use-files.js";
|
|
7
6
|
export { type Host, type HostInfo, type OpenAIHostCapabilities, useHost, } from "./use-host.js";
|
|
8
7
|
export { type ModelContextState, useModelContext, } from "./use-model-context.js";
|
package/dist/web/hooks/index.js
CHANGED
|
@@ -2,7 +2,6 @@ export { useCallTool, } from "./use-call-tool.js";
|
|
|
2
2
|
export { useDeepLink } from "./use-deep-link.js";
|
|
3
3
|
export { useDisplayMode } from "./use-display-mode.js";
|
|
4
4
|
export { useDownload } from "./use-download.js";
|
|
5
|
-
export { useFileResource, } from "./use-file-resource.js";
|
|
6
5
|
export { useFiles } from "./use-files.js";
|
|
7
6
|
export { useHost, } from "./use-host.js";
|
|
8
7
|
export { useModelContext, } from "./use-model-context.js";
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"index.js","sourceRoot":"","sources":["../../../src/web/hooks/index.ts"],"names":[],"mappings":"AAAA,OAAO,EAKL,WAAW,GACZ,MAAM,oBAAoB,CAAC;AAC5B,OAAO,EAAE,WAAW,EAAE,MAAM,oBAAoB,CAAC;AACjD,OAAO,EAAE,cAAc,EAAE,MAAM,uBAAuB,CAAC;AACvD,OAAO,EAAmB,WAAW,EAAE,MAAM,mBAAmB,CAAC;AACjE,OAAO,
|
|
1
|
+
{"version":3,"file":"index.js","sourceRoot":"","sources":["../../../src/web/hooks/index.ts"],"names":[],"mappings":"AAAA,OAAO,EAKL,WAAW,GACZ,MAAM,oBAAoB,CAAC;AAC5B,OAAO,EAAE,WAAW,EAAE,MAAM,oBAAoB,CAAC;AACjD,OAAO,EAAE,cAAc,EAAE,MAAM,uBAAuB,CAAC;AACvD,OAAO,EAAmB,WAAW,EAAE,MAAM,mBAAmB,CAAC;AACjE,OAAO,EAAE,QAAQ,EAAE,MAAM,gBAAgB,CAAC;AAC1C,OAAO,EAIL,OAAO,GACR,MAAM,eAAe,CAAC;AACvB,OAAO,EAEL,eAAe,GAChB,MAAM,wBAAwB,CAAC;AAChC,OAAO,EAAuB,eAAe,EAAE,MAAM,wBAAwB,CAAC;AAC9E,OAAO,EAAE,WAAW,EAAE,MAAM,oBAAoB,CAAC;AACjD,OAAO,EAAE,mBAAmB,EAAE,MAAM,6BAA6B,CAAC;AAClE,OAAO,EAAuB,eAAe,EAAE,MAAM,wBAAwB,CAAC;AAC9E,OAAO,EAAE,eAAe,EAAE,MAAM,wBAAwB,CAAC;AACzD,OAAO,EAAsB,cAAc,EAAE,MAAM,uBAAuB,CAAC;AAC3E,OAAO,EAAE,sBAAsB,EAAE,MAAM,iCAAiC,CAAC;AACzE,OAAO,EAAE,kBAAkB,EAAE,MAAM,8BAA8B,CAAC;AAClE,OAAO,EAAE,WAAW,EAAE,MAAM,oBAAoB,CAAC;AACjD,OAAO,EAAkB,OAAO,EAAE,MAAM,eAAe,CAAC;AACxD,OAAO,EAAE,YAAY,EAAE,MAAM,qBAAqB,CAAC;AACnD,OAAO,EAAE,WAAW,EAAsB,MAAM,mBAAmB,CAAC","sourcesContent":["export {\n type CallToolAsyncFn,\n type CallToolFn,\n type CallToolState,\n type SideEffects,\n useCallTool,\n} from \"./use-call-tool.js\";\nexport { useDeepLink } from \"./use-deep-link.js\";\nexport { useDisplayMode } from \"./use-display-mode.js\";\nexport { type DownloadFn, useDownload } from \"./use-download.js\";\nexport { useFiles } from \"./use-files.js\";\nexport {\n type Host,\n type HostInfo,\n type OpenAIHostCapabilities,\n useHost,\n} from \"./use-host.js\";\nexport {\n type ModelContextState,\n useModelContext,\n} from \"./use-model-context.js\";\nexport { type OpenExternalFn, useOpenExternal } from \"./use-open-external.js\";\nexport { useOpenFile } from \"./use-open-file.js\";\nexport { useRegisterViewTool } from \"./use-register-view-tool.js\";\nexport { type RequestCloseFn, useRequestClose } from \"./use-request-close.js\";\nexport { useRequestModal } from \"./use-request-modal.js\";\nexport { type RequestSizeFn, useRequestSize } from \"./use-request-size.js\";\nexport { useSendFollowUpMessage } from \"./use-send-follow-up-message.js\";\nexport { useSetOpenInAppUrl } from \"./use-set-open-in-app-url.js\";\nexport { useToolInfo } from \"./use-tool-info.js\";\nexport { type UserState, useUser } from \"./use-user.js\";\nexport { useViewState } from \"./use-view-state.js\";\nexport { useViewport, type ViewportState } from \"./use-viewport.js\";\n"]}
|
package/package.json
CHANGED
|
@@ -1,37 +0,0 @@
|
|
|
1
|
-
import { type FileResource, type FileResourceContent, type FileResourceWriteResult, type ResourceRepresentation } from "../bridges/index.js";
|
|
2
|
-
/** State and actions returned by {@link useFileResource}. */
|
|
3
|
-
export type FileResourceState = {
|
|
4
|
-
data: FileResource | undefined;
|
|
5
|
-
isLoading: boolean;
|
|
6
|
-
error: unknown;
|
|
7
|
-
write: (content: FileResourceContent) => Promise<FileResourceWriteResult>;
|
|
8
|
-
};
|
|
9
|
-
/**
|
|
10
|
-
* Read a resource by URI, re-read it whenever the host reports a change, and
|
|
11
|
-
* write it back. Built for the file a ChatGPT file entrypoint opened, whose
|
|
12
|
-
* `resourceUri` arrives in the tool input as `file.resourceUri`.
|
|
13
|
-
*
|
|
14
|
-
* Reading uses the standard `resources/read`. `representation` asks ChatGPT
|
|
15
|
-
* for text or a base64 blob. `write` uses the OpenAI MCP extensions
|
|
16
|
-
* (`openai/resources/write`) and always sends the current `etag` as
|
|
17
|
-
* `ifMatch`, so it resolves with `conflict` instead of overwriting a newer
|
|
18
|
-
* version, and then re-reads the latest one. It rejects with
|
|
19
|
-
* `NotSupportedError` when the host doesn't advertise `openai/resource` or the
|
|
20
|
-
* resource isn't writable.
|
|
21
|
-
*
|
|
22
|
-
* Pass `undefined` or an empty string as `uri` to do nothing, for example outside a file
|
|
23
|
-
* entrypoint.
|
|
24
|
-
*
|
|
25
|
-
* @example
|
|
26
|
-
* ```tsx
|
|
27
|
-
* const { input } = useToolInfo<"open-part">();
|
|
28
|
-
* const { data, write } = useFileResource(input.file?.resourceUri, {
|
|
29
|
-
* representation: "text",
|
|
30
|
-
* });
|
|
31
|
-
* ```
|
|
32
|
-
*
|
|
33
|
-
* @see https://docs.skybridge.tech/api-reference/use-file-resource
|
|
34
|
-
*/
|
|
35
|
-
export declare function useFileResource(uri: string | undefined, options?: {
|
|
36
|
-
representation?: ResourceRepresentation;
|
|
37
|
-
}): FileResourceState;
|
|
@@ -1,101 +0,0 @@
|
|
|
1
|
-
import { useCallback, useEffect, useRef, useState } from "react";
|
|
2
|
-
import { getAdaptor, NotSupportedError, } from "../bridges/index.js";
|
|
3
|
-
/**
|
|
4
|
-
* Read a resource by URI, re-read it whenever the host reports a change, and
|
|
5
|
-
* write it back. Built for the file a ChatGPT file entrypoint opened, whose
|
|
6
|
-
* `resourceUri` arrives in the tool input as `file.resourceUri`.
|
|
7
|
-
*
|
|
8
|
-
* Reading uses the standard `resources/read`. `representation` asks ChatGPT
|
|
9
|
-
* for text or a base64 blob. `write` uses the OpenAI MCP extensions
|
|
10
|
-
* (`openai/resources/write`) and always sends the current `etag` as
|
|
11
|
-
* `ifMatch`, so it resolves with `conflict` instead of overwriting a newer
|
|
12
|
-
* version, and then re-reads the latest one. It rejects with
|
|
13
|
-
* `NotSupportedError` when the host doesn't advertise `openai/resource` or the
|
|
14
|
-
* resource isn't writable.
|
|
15
|
-
*
|
|
16
|
-
* Pass `undefined` or an empty string as `uri` to do nothing, for example outside a file
|
|
17
|
-
* entrypoint.
|
|
18
|
-
*
|
|
19
|
-
* @example
|
|
20
|
-
* ```tsx
|
|
21
|
-
* const { input } = useToolInfo<"open-part">();
|
|
22
|
-
* const { data, write } = useFileResource(input.file?.resourceUri, {
|
|
23
|
-
* representation: "text",
|
|
24
|
-
* });
|
|
25
|
-
* ```
|
|
26
|
-
*
|
|
27
|
-
* @see https://docs.skybridge.tech/api-reference/use-file-resource
|
|
28
|
-
*/
|
|
29
|
-
export function useFileResource(uri, options) {
|
|
30
|
-
const representation = options?.representation;
|
|
31
|
-
const [state, setState] = useState();
|
|
32
|
-
const sequence = useRef(0);
|
|
33
|
-
const current = uri && state?.uri === uri ? state : undefined;
|
|
34
|
-
const currentRef = useRef(current);
|
|
35
|
-
currentRef.current = current;
|
|
36
|
-
const read = useCallback(() => {
|
|
37
|
-
if (!uri) {
|
|
38
|
-
return;
|
|
39
|
-
}
|
|
40
|
-
const id = ++sequence.current;
|
|
41
|
-
getAdaptor()
|
|
42
|
-
.readResource(uri, representation)
|
|
43
|
-
.then((resource) => ({ resource, error: undefined }), (error) => ({ error }))
|
|
44
|
-
.then((next) => {
|
|
45
|
-
if (id === sequence.current) {
|
|
46
|
-
setState((previous) => ({
|
|
47
|
-
...(previous?.uri === uri && previous),
|
|
48
|
-
uri,
|
|
49
|
-
...next,
|
|
50
|
-
}));
|
|
51
|
-
}
|
|
52
|
-
});
|
|
53
|
-
}, [uri, representation]);
|
|
54
|
-
useEffect(() => {
|
|
55
|
-
if (!uri) {
|
|
56
|
-
return;
|
|
57
|
-
}
|
|
58
|
-
read();
|
|
59
|
-
const stopWatching = getAdaptor().watchResource(uri, read);
|
|
60
|
-
return () => {
|
|
61
|
-
sequence.current++;
|
|
62
|
-
stopWatching();
|
|
63
|
-
};
|
|
64
|
-
}, [uri, read]);
|
|
65
|
-
const write = useCallback(async (content) => {
|
|
66
|
-
const loaded = currentRef.current;
|
|
67
|
-
const resource = loaded?.resource;
|
|
68
|
-
if (!loaded || loaded.uri !== uri || !resource?.writable) {
|
|
69
|
-
throw new NotSupportedError("writeResource", "the resource is not loaded or not writable");
|
|
70
|
-
}
|
|
71
|
-
const result = await getAdaptor().writeResource(loaded.uri, content, resource.etag);
|
|
72
|
-
if (currentRef.current?.uri !== loaded.uri) {
|
|
73
|
-
return result;
|
|
74
|
-
}
|
|
75
|
-
if (result.outcome === "saved") {
|
|
76
|
-
sequence.current++;
|
|
77
|
-
setState((previous) => previous?.uri === loaded.uri
|
|
78
|
-
? {
|
|
79
|
-
uri: loaded.uri,
|
|
80
|
-
resource: {
|
|
81
|
-
...content,
|
|
82
|
-
mimeType: resource.mimeType,
|
|
83
|
-
writable: true,
|
|
84
|
-
etag: result.etag,
|
|
85
|
-
},
|
|
86
|
-
}
|
|
87
|
-
: previous);
|
|
88
|
-
}
|
|
89
|
-
else if (result.outcome === "conflict") {
|
|
90
|
-
read();
|
|
91
|
-
}
|
|
92
|
-
return result;
|
|
93
|
-
}, [uri, read]);
|
|
94
|
-
return {
|
|
95
|
-
data: current?.resource,
|
|
96
|
-
isLoading: Boolean(uri) && current === undefined,
|
|
97
|
-
error: current?.error,
|
|
98
|
-
write,
|
|
99
|
-
};
|
|
100
|
-
}
|
|
101
|
-
//# sourceMappingURL=use-file-resource.js.map
|
|
@@ -1 +0,0 @@
|
|
|
1
|
-
{"version":3,"file":"use-file-resource.js","sourceRoot":"","sources":["../../../src/web/hooks/use-file-resource.ts"],"names":[],"mappings":"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","sourcesContent":["import { useCallback, useEffect, useRef, useState } from \"react\";\nimport {\n type FileResource,\n type FileResourceContent,\n type FileResourceWriteResult,\n getAdaptor,\n NotSupportedError,\n type ResourceRepresentation,\n} from \"../bridges/index.js\";\n\n/** State and actions returned by {@link useFileResource}. */\nexport type FileResourceState = {\n data: FileResource | undefined;\n isLoading: boolean;\n error: unknown;\n write: (content: FileResourceContent) => Promise<FileResourceWriteResult>;\n};\n\n/**\n * Read a resource by URI, re-read it whenever the host reports a change, and\n * write it back. Built for the file a ChatGPT file entrypoint opened, whose\n * `resourceUri` arrives in the tool input as `file.resourceUri`.\n *\n * Reading uses the standard `resources/read`. `representation` asks ChatGPT\n * for text or a base64 blob. `write` uses the OpenAI MCP extensions\n * (`openai/resources/write`) and always sends the current `etag` as\n * `ifMatch`, so it resolves with `conflict` instead of overwriting a newer\n * version, and then re-reads the latest one. It rejects with\n * `NotSupportedError` when the host doesn't advertise `openai/resource` or the\n * resource isn't writable.\n *\n * Pass `undefined` or an empty string as `uri` to do nothing, for example outside a file\n * entrypoint.\n *\n * @example\n * ```tsx\n * const { input } = useToolInfo<\"open-part\">();\n * const { data, write } = useFileResource(input.file?.resourceUri, {\n * representation: \"text\",\n * });\n * ```\n *\n * @see https://docs.skybridge.tech/api-reference/use-file-resource\n */\nexport function useFileResource(\n uri: string | undefined,\n options?: { representation?: ResourceRepresentation },\n): FileResourceState {\n const representation = options?.representation;\n const [state, setState] = useState<{\n uri: string;\n resource?: FileResource;\n error?: unknown;\n }>();\n const sequence = useRef(0);\n const current = uri && state?.uri === uri ? state : undefined;\n const currentRef = useRef(current);\n currentRef.current = current;\n\n const read = useCallback(() => {\n if (!uri) {\n return;\n }\n const id = ++sequence.current;\n getAdaptor()\n .readResource(uri, representation)\n .then(\n (resource) => ({ resource, error: undefined }),\n (error: unknown) => ({ error }),\n )\n .then((next) => {\n if (id === sequence.current) {\n setState((previous) => ({\n ...(previous?.uri === uri && previous),\n uri,\n ...next,\n }));\n }\n });\n }, [uri, representation]);\n\n useEffect(() => {\n if (!uri) {\n return;\n }\n read();\n const stopWatching = getAdaptor().watchResource(uri, read);\n return () => {\n sequence.current++;\n stopWatching();\n };\n }, [uri, read]);\n\n const write = useCallback(\n async (content: FileResourceContent) => {\n const loaded = currentRef.current;\n const resource = loaded?.resource;\n if (!loaded || loaded.uri !== uri || !resource?.writable) {\n throw new NotSupportedError(\n \"writeResource\",\n \"the resource is not loaded or not writable\",\n );\n }\n const result = await getAdaptor().writeResource(\n loaded.uri,\n content,\n resource.etag,\n );\n if (currentRef.current?.uri !== loaded.uri) {\n return result;\n }\n if (result.outcome === \"saved\") {\n sequence.current++;\n setState((previous) =>\n previous?.uri === loaded.uri\n ? {\n uri: loaded.uri,\n resource: {\n ...content,\n mimeType: resource.mimeType,\n writable: true,\n etag: result.etag,\n },\n }\n : previous,\n );\n } else if (result.outcome === \"conflict\") {\n read();\n }\n return result;\n },\n [uri, read],\n );\n\n return {\n data: current?.resource,\n isLoading: Boolean(uri) && current === undefined,\n error: current?.error,\n write,\n };\n}\n"]}
|
|
@@ -1,65 +0,0 @@
|
|
|
1
|
-
import { act, renderHook, waitFor } from "@testing-library/react";
|
|
2
|
-
import { afterEach, beforeEach, describe, expect, it, vi } from "vitest";
|
|
3
|
-
import { HostAdaptor } from "../bridges/adaptor.js";
|
|
4
|
-
import { getAdaptor } from "../bridges/get-adaptor.js";
|
|
5
|
-
import { McpAppBridge } from "../bridges/mcp-app/bridge.js";
|
|
6
|
-
import { useFileResource } from "./use-file-resource.js";
|
|
7
|
-
describe("useFileResource", () => {
|
|
8
|
-
beforeEach(() => {
|
|
9
|
-
vi.stubGlobal("parent", { postMessage: vi.fn() });
|
|
10
|
-
vi.stubGlobal("skybridge", {});
|
|
11
|
-
vi.stubGlobal("openai", undefined);
|
|
12
|
-
});
|
|
13
|
-
afterEach(() => {
|
|
14
|
-
vi.unstubAllGlobals();
|
|
15
|
-
HostAdaptor.resetInstance();
|
|
16
|
-
McpAppBridge.resetInstance();
|
|
17
|
-
});
|
|
18
|
-
it("reads the resource, re-reads it on update and writes with the current etag", async () => {
|
|
19
|
-
let version = 1;
|
|
20
|
-
let onUpdated = () => { };
|
|
21
|
-
const request = vi.fn(async ({ method }) => method === "openai/resources/write"
|
|
22
|
-
? { outcome: "saved", etag: "v3" }
|
|
23
|
-
: {});
|
|
24
|
-
const app = {
|
|
25
|
-
getHostCapabilities: () => ({ experimental: { "openai/resource": {} } }),
|
|
26
|
-
readServerResource: vi.fn(async ({ uri }) => ({
|
|
27
|
-
contents: [
|
|
28
|
-
{
|
|
29
|
-
uri,
|
|
30
|
-
text: `version ${version}`,
|
|
31
|
-
_meta: {
|
|
32
|
-
"openai/resource": { writable: true, etag: `v${version}` },
|
|
33
|
-
},
|
|
34
|
-
},
|
|
35
|
-
],
|
|
36
|
-
})),
|
|
37
|
-
setNotificationHandler: (_method, handler) => {
|
|
38
|
-
onUpdated = handler;
|
|
39
|
-
},
|
|
40
|
-
request,
|
|
41
|
-
};
|
|
42
|
-
getAdaptor().mcp.getApp = () => Promise.resolve(app);
|
|
43
|
-
const { result } = renderHook(() => useFileResource("host-resource://part", { representation: "text" }));
|
|
44
|
-
await waitFor(() => expect(result.current.data).toMatchObject({
|
|
45
|
-
text: "version 1",
|
|
46
|
-
etag: "v1",
|
|
47
|
-
}));
|
|
48
|
-
await waitFor(() => expect(request).toHaveBeenCalledWith({
|
|
49
|
-
method: "resources/subscribe",
|
|
50
|
-
params: { uri: "host-resource://part" },
|
|
51
|
-
}, expect.anything()));
|
|
52
|
-
version = 2;
|
|
53
|
-
act(() => onUpdated({ params: { uri: "host-resource://part" } }));
|
|
54
|
-
await waitFor(() => expect(result.current.data).toMatchObject({ etag: "v2" }));
|
|
55
|
-
await act(async () => {
|
|
56
|
-
await result.current.write({ text: "edited" });
|
|
57
|
-
});
|
|
58
|
-
expect(request).toHaveBeenCalledWith({
|
|
59
|
-
method: "openai/resources/write",
|
|
60
|
-
params: { uri: "host-resource://part", text: "edited", ifMatch: "v2" },
|
|
61
|
-
}, expect.anything());
|
|
62
|
-
expect(result.current.data).toMatchObject({ text: "edited", etag: "v3" });
|
|
63
|
-
});
|
|
64
|
-
});
|
|
65
|
-
//# sourceMappingURL=use-file-resource.test.js.map
|
|
@@ -1 +0,0 @@
|
|
|
1
|
-
{"version":3,"file":"use-file-resource.test.js","sourceRoot":"","sources":["../../../src/web/hooks/use-file-resource.test.ts"],"names":[],"mappings":"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","sourcesContent":["import { act, renderHook, waitFor } from \"@testing-library/react\";\nimport { afterEach, beforeEach, describe, expect, it, vi } from \"vitest\";\nimport { HostAdaptor } from \"../bridges/adaptor.js\";\nimport { getAdaptor } from \"../bridges/get-adaptor.js\";\nimport { McpAppBridge } from \"../bridges/mcp-app/bridge.js\";\nimport { useFileResource } from \"./use-file-resource.js\";\n\ndescribe(\"useFileResource\", () => {\n beforeEach(() => {\n vi.stubGlobal(\"parent\", { postMessage: vi.fn() });\n vi.stubGlobal(\"skybridge\", {});\n vi.stubGlobal(\"openai\", undefined);\n });\n\n afterEach(() => {\n vi.unstubAllGlobals();\n HostAdaptor.resetInstance();\n McpAppBridge.resetInstance();\n });\n\n it(\"reads the resource, re-reads it on update and writes with the current etag\", async () => {\n let version = 1;\n let onUpdated: (notification: { params: { uri: string } }) => void =\n () => {};\n const request = vi.fn(async ({ method }: { method: string }) =>\n method === \"openai/resources/write\"\n ? { outcome: \"saved\", etag: \"v3\" }\n : {},\n );\n const app = {\n getHostCapabilities: () => ({ experimental: { \"openai/resource\": {} } }),\n readServerResource: vi.fn(async ({ uri }: { uri: string }) => ({\n contents: [\n {\n uri,\n text: `version ${version}`,\n _meta: {\n \"openai/resource\": { writable: true, etag: `v${version}` },\n },\n },\n ],\n })),\n setNotificationHandler: (_method: string, handler: typeof onUpdated) => {\n onUpdated = handler;\n },\n request,\n };\n (\n getAdaptor() as unknown as { mcp: { getApp: () => Promise<object> } }\n ).mcp.getApp = () => Promise.resolve(app);\n\n const { result } = renderHook(() =>\n useFileResource(\"host-resource://part\", { representation: \"text\" }),\n );\n await waitFor(() =>\n expect(result.current.data).toMatchObject({\n text: \"version 1\",\n etag: \"v1\",\n }),\n );\n await waitFor(() =>\n expect(request).toHaveBeenCalledWith(\n {\n method: \"resources/subscribe\",\n params: { uri: \"host-resource://part\" },\n },\n expect.anything(),\n ),\n );\n\n version = 2;\n act(() => onUpdated({ params: { uri: \"host-resource://part\" } }));\n await waitFor(() =>\n expect(result.current.data).toMatchObject({ etag: \"v2\" }),\n );\n\n await act(async () => {\n await result.current.write({ text: \"edited\" });\n });\n expect(request).toHaveBeenCalledWith(\n {\n method: \"openai/resources/write\",\n params: { uri: \"host-resource://part\", text: \"edited\", ifMatch: \"v2\" },\n },\n expect.anything(),\n );\n expect(result.current.data).toMatchObject({ text: \"edited\", etag: \"v3\" });\n });\n});\n"]}
|
|
File without changes
|