summaryrefslogtreecommitdiffhomepage
path: root/packages/app/src/context
diff options
context:
space:
mode:
authorDavid Hill <[email protected]>2025-09-23 18:36:27 +0100
committerDavid Hill <[email protected]>2025-09-23 18:36:27 +0100
commit9d53628e192065cd20f5fbae3712dae43b92b1e3 (patch)
tree14e7ac5201c56d011932f1c54a33b975c9cd6e47 /packages/app/src/context
parent869b4761455672535eba878aa90edf21ab6fecec (diff)
parent5ead6d7dd50e96c3cd6213c9be540c1ca8ac2fe5 (diff)
downloadopencode-9d53628e192065cd20f5fbae3712dae43b92b1e3.tar.gz
opencode-9d53628e192065cd20f5fbae3712dae43b92b1e3.zip
Merge branch 'dev' of https://github.com/sst/opencode into dev
Diffstat (limited to 'packages/app/src/context')
-rw-r--r--packages/app/src/context/event.tsx34
-rw-r--r--packages/app/src/context/index.ts3
-rw-r--r--packages/app/src/context/local.tsx51
-rw-r--r--packages/app/src/context/marked.tsx40
-rw-r--r--packages/app/src/context/shiki.tsx582
-rw-r--r--packages/app/src/context/sync.tsx106
6 files changed, 737 insertions, 79 deletions
diff --git a/packages/app/src/context/event.tsx b/packages/app/src/context/event.tsx
new file mode 100644
index 000000000..a2aa54181
--- /dev/null
+++ b/packages/app/src/context/event.tsx
@@ -0,0 +1,34 @@
+import { createContext, useContext, type ParentProps } from "solid-js"
+import { createEventBus } from "@solid-primitives/event-bus"
+import type { Event as SDKEvent } from "@opencode-ai/sdk"
+import { useSDK } from "@/context"
+
+export type Event = SDKEvent // can extend with custom events later
+
+function init() {
+ const sdk = useSDK()
+ const bus = createEventBus<Event>()
+ sdk.event.subscribe().then(async (events) => {
+ for await (const event of events.stream) {
+ bus.emit(event)
+ }
+ })
+ return bus
+}
+
+type EventContext = ReturnType<typeof init>
+
+const ctx = createContext<EventContext>()
+
+export function EventProvider(props: ParentProps) {
+ const value = init()
+ return <ctx.Provider value={value}>{props.children}</ctx.Provider>
+}
+
+export function useEvent() {
+ const value = useContext(ctx)
+ if (!value) {
+ throw new Error("useEvent must be used within a EventProvider")
+ }
+ return value
+}
diff --git a/packages/app/src/context/index.ts b/packages/app/src/context/index.ts
index ef2bbd9c3..bc4bf3b1d 100644
--- a/packages/app/src/context/index.ts
+++ b/packages/app/src/context/index.ts
@@ -1,4 +1,7 @@
+export { EventProvider, useEvent } from "./event"
export { LocalProvider, useLocal } from "./local"
+export { MarkedProvider, useMarked } from "./marked"
export { SDKProvider, useSDK } from "./sdk"
+export { ShikiProvider, useShiki } from "./shiki"
export { SyncProvider, useSync } from "./sync"
export { ThemeProvider, useTheme } from "./theme"
diff --git a/packages/app/src/context/local.tsx b/packages/app/src/context/local.tsx
index eff152642..825023616 100644
--- a/packages/app/src/context/local.tsx
+++ b/packages/app/src/context/local.tsx
@@ -1,9 +1,8 @@
import { createStore, produce, reconcile } from "solid-js/store"
import { batch, createContext, createEffect, createMemo, useContext, type ParentProps } from "solid-js"
-import { useSync } from "./sync"
import { uniqueBy } from "remeda"
import type { FileContent, FileNode } from "@opencode-ai/sdk"
-import { useSDK } from "./sdk"
+import { useSDK, useEvent, useSync } from "@/context"
export type LocalFile = FileNode &
Partial<{
@@ -165,17 +164,19 @@ function init() {
})
}
- const load = async (path: string) =>
- sdk.file.read({ query: { path } }).then((x) => {
+ const load = async (path: string) => {
+ const relative = path.replace(sync.data.path.directory + "/", "")
+ sdk.file.read({ query: { path: relative } }).then((x) => {
setStore(
"node",
- path,
+ relative,
produce((draft) => {
draft.loaded = true
draft.content = x.data
}),
)
})
+ }
const open = async (path: string) => {
const relative = path.replace(sync.data.path.directory + "/", "")
@@ -213,27 +214,27 @@ function init() {
})
}
- sdk.event.subscribe().then(async (events) => {
- for await (const event of events.stream) {
- switch (event.type) {
- case "message.part.updated":
- const part = event.properties.part
- if (part.type === "tool" && part.state.status === "completed") {
- switch (part.tool) {
- case "read":
- console.log("read", part.state.input)
- break
- case "edit":
- const absolute = part.state.input["filePath"] as string
- const path = absolute.replace(sync.data.path.directory + "/", "")
- load(path)
- break
- default:
- break
- }
+ const bus = useEvent()
+ bus.listen((event) => {
+ switch (event.type) {
+ case "message.part.updated":
+ const part = event.properties.part
+ if (part.type === "tool" && part.state.status === "completed") {
+ switch (part.tool) {
+ case "read":
+ console.log("read", part.state.input)
+ break
+ case "edit":
+ load(part.state.input["filePath"] as string)
+ break
+ default:
+ break
}
- break
- }
+ }
+ break
+ case "file.watcher.updated":
+ load(event.properties.file)
+ break
}
})
diff --git a/packages/app/src/context/marked.tsx b/packages/app/src/context/marked.tsx
new file mode 100644
index 000000000..33fea8db6
--- /dev/null
+++ b/packages/app/src/context/marked.tsx
@@ -0,0 +1,40 @@
+import { createContext, useContext, type ParentProps } from "solid-js"
+import { useShiki } from "@/context"
+import { marked } from "marked"
+import markedShiki from "marked-shiki"
+import type { BundledLanguage } from "shiki"
+
+function init(highlighter: ReturnType<typeof useShiki>) {
+ return marked.use(
+ markedShiki({
+ async highlight(code, lang) {
+ if (!highlighter.getLoadedLanguages().includes(lang)) {
+ await highlighter.loadLanguage(lang as BundledLanguage)
+ }
+ return highlighter.codeToHtml(code, {
+ lang: lang || "text",
+ theme: "opencode",
+ tabindex: false,
+ })
+ },
+ }),
+ )
+}
+
+type MarkedContext = ReturnType<typeof init>
+
+const ctx = createContext<MarkedContext>()
+
+export function MarkedProvider(props: ParentProps) {
+ const highlighter = useShiki()
+ const value = init(highlighter)
+ return <ctx.Provider value={value}>{props.children}</ctx.Provider>
+}
+
+export function useMarked() {
+ const value = useContext(ctx)
+ if (!value) {
+ throw new Error("useMarked must be used within a MarkedProvider")
+ }
+ return value
+}
diff --git a/packages/app/src/context/shiki.tsx b/packages/app/src/context/shiki.tsx
new file mode 100644
index 000000000..1930b907c
--- /dev/null
+++ b/packages/app/src/context/shiki.tsx
@@ -0,0 +1,582 @@
+import { createHighlighter, type ThemeInput } from "shiki"
+import { createContext, useContext, type ParentProps } from "solid-js"
+
+const theme: ThemeInput = {
+ colors: {
+ "actionBar.toggledBackground": "var(--theme-background-element)",
+ "activityBarBadge.background": "var(--theme-accent)",
+ "checkbox.border": "var(--theme-border)",
+ "editor.background": "transparent",
+ "editor.foreground": "var(--theme-text)",
+ "editor.inactiveSelectionBackground": "var(--theme-background-element)",
+ "editor.selectionHighlightBackground": "var(--theme-border-active)",
+ "editorIndentGuide.activeBackground1": "var(--theme-border-subtle)",
+ "editorIndentGuide.background1": "var(--theme-border-subtle)",
+ "input.placeholderForeground": "var(--theme-text-muted)",
+ "list.activeSelectionIconForeground": "var(--theme-text)",
+ "list.dropBackground": "var(--theme-background-element)",
+ "menu.background": "var(--theme-background-panel)",
+ "menu.border": "var(--theme-border)",
+ "menu.foreground": "var(--theme-text)",
+ "menu.selectionBackground": "var(--theme-primary)",
+ "menu.separatorBackground": "var(--theme-border)",
+ "ports.iconRunningProcessForeground": "var(--theme-success)",
+ "sideBarSectionHeader.background": "transparent",
+ "sideBarSectionHeader.border": "var(--theme-border-subtle)",
+ "sideBarTitle.foreground": "var(--theme-text-muted)",
+ "statusBarItem.remoteBackground": "var(--theme-success)",
+ "statusBarItem.remoteForeground": "var(--theme-text)",
+ "tab.lastPinnedBorder": "var(--theme-border-subtle)",
+ "tab.selectedBackground": "var(--theme-background-element)",
+ "tab.selectedForeground": "var(--theme-text-muted)",
+ "terminal.inactiveSelectionBackground": "var(--theme-background-element)",
+ "widget.border": "var(--theme-border)",
+ },
+ displayName: "opencode",
+ name: "opencode",
+ semanticHighlighting: true,
+ semanticTokenColors: {
+ customLiteral: "var(--theme-syntax-function)",
+ newOperator: "var(--theme-syntax-operator)",
+ numberLiteral: "var(--theme-syntax-number)",
+ stringLiteral: "var(--theme-syntax-string)",
+ },
+ tokenColors: [
+ {
+ scope: [
+ "meta.embedded",
+ "source.groovy.embedded",
+ "string meta.image.inline.markdown",
+ "variable.legacy.builtin.python",
+ ],
+ settings: {
+ foreground: "var(--theme-text)",
+ },
+ },
+ {
+ scope: "emphasis",
+ settings: {
+ fontStyle: "italic",
+ },
+ },
+ {
+ scope: "strong",
+ settings: {
+ fontStyle: "bold",
+ },
+ },
+ {
+ scope: "header",
+ settings: {
+ foreground: "var(--theme-markdown-heading)",
+ },
+ },
+ {
+ scope: "comment",
+ settings: {
+ foreground: "var(--theme-syntax-comment)",
+ },
+ },
+ {
+ scope: "constant.language",
+ settings: {
+ foreground: "var(--theme-syntax-keyword)",
+ },
+ },
+ {
+ scope: [
+ "constant.numeric",
+ "variable.other.enummember",
+ "keyword.operator.plus.exponent",
+ "keyword.operator.minus.exponent",
+ ],
+ settings: {
+ foreground: "var(--theme-syntax-number)",
+ },
+ },
+ {
+ scope: "constant.regexp",
+ settings: {
+ foreground: "var(--theme-syntax-operator)",
+ },
+ },
+ {
+ scope: "entity.name.tag",
+ settings: {
+ foreground: "var(--theme-syntax-keyword)",
+ },
+ },
+ {
+ scope: ["entity.name.tag.css", "entity.name.tag.less"],
+ settings: {
+ foreground: "var(--theme-syntax-operator)",
+ },
+ },
+ {
+ scope: "entity.other.attribute-name",
+ settings: {
+ foreground: "var(--theme-syntax-variable)",
+ },
+ },
+ {
+ scope: [
+ "entity.other.attribute-name.class.css",
+ "source.css entity.other.attribute-name.class",
+ "entity.other.attribute-name.id.css",
+ "entity.other.attribute-name.parent-selector.css",
+ "entity.other.attribute-name.parent.less",
+ "source.css entity.other.attribute-name.pseudo-class",
+ "entity.other.attribute-name.pseudo-element.css",
+ "source.css.less entity.other.attribute-name.id",
+ "entity.other.attribute-name.scss",
+ ],
+ settings: {
+ foreground: "var(--theme-syntax-operator)",
+ },
+ },
+ {
+ scope: "invalid",
+ settings: {
+ foreground: "var(--theme-error)",
+ },
+ },
+ {
+ scope: "markup.underline",
+ settings: {
+ fontStyle: "underline",
+ },
+ },
+ {
+ scope: "markup.bold",
+ settings: {
+ fontStyle: "bold",
+ foreground: "var(--theme-markdown-strong)",
+ },
+ },
+ {
+ scope: "markup.heading",
+ settings: {
+ fontStyle: "bold",
+ foreground: "var(--theme-markdown-heading)",
+ },
+ },
+ {
+ scope: "markup.italic",
+ settings: {
+ fontStyle: "italic",
+ },
+ },
+ {
+ scope: "markup.strikethrough",
+ settings: {
+ fontStyle: "strikethrough",
+ },
+ },
+ {
+ scope: "markup.inserted",
+ settings: {
+ foreground: "var(--theme-diff-added)",
+ },
+ },
+ {
+ scope: "markup.deleted",
+ settings: {
+ foreground: "var(--theme-diff-removed)",
+ },
+ },
+ {
+ scope: "markup.changed",
+ settings: {
+ foreground: "var(--theme-diff-context)",
+ },
+ },
+ {
+ scope: "punctuation.definition.quote.begin.markdown",
+ settings: {
+ foreground: "var(--theme-markdown-block-quote)",
+ },
+ },
+ {
+ scope: "punctuation.definition.list.begin.markdown",
+ settings: {
+ foreground: "var(--theme-markdown-list-enumeration)",
+ },
+ },
+ {
+ scope: "markup.inline.raw",
+ settings: {
+ foreground: "var(--theme-markdown-code)",
+ },
+ },
+ {
+ scope: "punctuation.definition.tag",
+ settings: {
+ foreground: "var(--theme-syntax-punctuation)",
+ },
+ },
+ {
+ scope: ["meta.preprocessor", "entity.name.function.preprocessor"],
+ settings: {
+ foreground: "var(--theme-syntax-keyword)",
+ },
+ },
+ {
+ scope: "meta.preprocessor.string",
+ settings: {
+ foreground: "var(--theme-syntax-string)",
+ },
+ },
+ {
+ scope: "meta.preprocessor.numeric",
+ settings: {
+ foreground: "var(--theme-syntax-number)",
+ },
+ },
+ {
+ scope: "meta.structure.dictionary.key.python",
+ settings: {
+ foreground: "var(--theme-syntax-variable)",
+ },
+ },
+ {
+ scope: "meta.diff.header",
+ settings: {
+ foreground: "var(--theme-diff-hunk-header)",
+ },
+ },
+ {
+ scope: "storage",
+ settings: {
+ foreground: "var(--theme-syntax-keyword)",
+ },
+ },
+ {
+ scope: "storage.type",
+ settings: {
+ foreground: "var(--theme-syntax-keyword)",
+ },
+ },
+ {
+ scope: ["storage.modifier", "keyword.operator.noexcept"],
+ settings: {
+ foreground: "var(--theme-syntax-keyword)",
+ },
+ },
+ {
+ scope: ["string", "meta.embedded.assembly"],
+ settings: {
+ foreground: "var(--theme-syntax-string)",
+ },
+ },
+ {
+ scope: "string.tag",
+ settings: {
+ foreground: "var(--theme-syntax-string)",
+ },
+ },
+ {
+ scope: "string.value",
+ settings: {
+ foreground: "var(--theme-syntax-string)",
+ },
+ },
+ {
+ scope: "string.regexp",
+ settings: {
+ foreground: "var(--theme-syntax-operator)",
+ },
+ },
+ {
+ scope: [
+ "punctuation.definition.template-expression.begin",
+ "punctuation.definition.template-expression.end",
+ "punctuation.section.embedded",
+ ],
+ settings: {
+ foreground: "var(--theme-syntax-keyword)",
+ },
+ },
+ {
+ scope: ["meta.template.expression"],
+ settings: {
+ foreground: "var(--theme-text)",
+ },
+ },
+ {
+ scope: [
+ "support.type.vendored.property-name",
+ "support.type.property-name",
+ "source.css variable",
+ "source.coffee.embedded",
+ ],
+ settings: {
+ foreground: "var(--theme-syntax-variable)",
+ },
+ },
+ {
+ scope: "keyword",
+ settings: {
+ foreground: "var(--theme-syntax-keyword)",
+ },
+ },
+ {
+ scope: "keyword.control",
+ settings: {
+ foreground: "var(--theme-syntax-keyword)",
+ },
+ },
+ {
+ scope: "keyword.operator",
+ settings: {
+ foreground: "var(--theme-syntax-operator)",
+ },
+ },
+ {
+ scope: [
+ "keyword.operator.new",
+ "keyword.operator.expression",
+ "keyword.operator.cast",
+ "keyword.operator.sizeof",
+ "keyword.operator.alignof",
+ "keyword.operator.typeid",
+ "keyword.operator.alignas",
+ "keyword.operator.instanceof",
+ "keyword.operator.logical.python",
+ "keyword.operator.wordlike",
+ ],
+ settings: {
+ foreground: "var(--theme-syntax-keyword)",
+ },
+ },
+ {
+ scope: "keyword.other.unit",
+ settings: {
+ foreground: "var(--theme-syntax-number)",
+ },
+ },
+ {
+ scope: ["punctuation.section.embedded.begin.php", "punctuation.section.embedded.end.php"],
+ settings: {
+ foreground: "var(--theme-syntax-keyword)",
+ },
+ },
+ {
+ scope: "support.function.git-rebase",
+ settings: {
+ foreground: "var(--theme-syntax-variable)",
+ },
+ },
+ {
+ scope: "constant.sha.git-rebase",
+ settings: {
+ foreground: "var(--theme-syntax-number)",
+ },
+ },
+ {
+ scope: ["storage.modifier.import.java", "variable.language.wildcard.java", "storage.modifier.package.java"],
+ settings: {
+ foreground: "var(--theme-text)",
+ },
+ },
+ {
+ scope: "variable.language",
+ settings: {
+ foreground: "var(--theme-syntax-keyword)",
+ },
+ },
+ {
+ scope: [
+ "entity.name.function",
+ "support.function",
+ "support.constant.handlebars",
+ "source.powershell variable.other.member",
+ "entity.name.operator.custom-literal",
+ ],
+ settings: {
+ foreground: "var(--theme-syntax-function)",
+ },
+ },
+ {
+ scope: [
+ "support.class",
+ "support.type",
+ "entity.name.type",
+ "entity.name.namespace",
+ "entity.other.attribute",
+ "entity.name.scope-resolution",
+ "entity.name.class",
+ "storage.type.numeric.go",
+ "storage.type.byte.go",
+ "storage.type.boolean.go",
+ "storage.type.string.go",
+ "storage.type.uintptr.go",
+ "storage.type.error.go",
+ "storage.type.rune.go",
+ "storage.type.cs",
+ "storage.type.generic.cs",
+ "storage.type.modifier.cs",
+ "storage.type.variable.cs",
+ "storage.type.annotation.java",
+ "storage.type.generic.java",
+ "storage.type.java",
+ "storage.type.object.array.java",
+ "storage.type.primitive.array.java",
+ "storage.type.primitive.java",
+ "storage.type.token.java",
+ "storage.type.groovy",
+ "storage.type.annotation.groovy",
+ "storage.type.parameters.groovy",
+ "storage.type.generic.groovy",
+ "storage.type.object.array.groovy",
+ "storage.type.primitive.array.groovy",
+ "storage.type.primitive.groovy",
+ ],
+ settings: {
+ foreground: "var(--theme-syntax-type)",
+ },
+ },
+ {
+ scope: [
+ "meta.type.cast.expr",
+ "meta.type.new.expr",
+ "support.constant.math",
+ "support.constant.dom",
+ "support.constant.json",
+ "entity.other.inherited-class",
+ "punctuation.separator.namespace.ruby",
+ ],
+ settings: {
+ foreground: "var(--theme-syntax-type)",
+ },
+ },
+ {
+ scope: [
+ "keyword.control",
+ "source.cpp keyword.operator.new",
+ "keyword.operator.delete",
+ "keyword.other.using",
+ "keyword.other.directive.using",
+ "keyword.other.operator",
+ "entity.name.operator",
+ ],
+ settings: {
+ foreground: "var(--theme-syntax-operator)",
+ },
+ },
+ {
+ scope: [
+ "variable",
+ "meta.definition.variable.name",
+ "support.variable",
+ "entity.name.variable",
+ "constant.other.placeholder",
+ ],
+ settings: {
+ foreground: "var(--theme-syntax-variable)",
+ },
+ },
+ {
+ scope: ["variable.other.constant", "variable.other.enummember"],
+ settings: {
+ foreground: "var(--theme-syntax-variable)",
+ },
+ },
+ {
+ scope: ["meta.object-literal.key"],
+ settings: {
+ foreground: "var(--theme-syntax-variable)",
+ },
+ },
+ {
+ scope: [
+ "support.constant.property-value",
+ "support.constant.font-name",
+ "support.constant.media-type",
+ "support.constant.media",
+ "constant.other.color.rgb-value",
+ "constant.other.rgb-value",
+ "support.constant.color",
+ ],
+ settings: {
+ foreground: "var(--theme-syntax-string)",
+ },
+ },
+ {
+ scope: [
+ "punctuation.definition.group.regexp",
+ "punctuation.definition.group.assertion.regexp",
+ "punctuation.definition.character-class.regexp",
+ "punctuation.character.set.begin.regexp",
+ "punctuation.character.set.end.regexp",
+ "keyword.operator.negation.regexp",
+ "support.other.parenthesis.regexp",
+ ],
+ settings: {
+ foreground: "var(--theme-syntax-string)",
+ },
+ },
+ {
+ scope: [
+ "constant.character.character-class.regexp",
+ "constant.other.character-class.set.regexp",
+ "constant.other.character-class.regexp",
+ "constant.character.set.regexp",
+ ],
+ settings: {
+ foreground: "var(--theme-syntax-operator)",
+ },
+ },
+ {
+ scope: ["keyword.operator.or.regexp", "keyword.control.anchor.regexp"],
+ settings: {
+ foreground: "var(--theme-syntax-operator)",
+ },
+ },
+ {
+ scope: "keyword.operator.quantifier.regexp",
+ settings: {
+ foreground: "var(--theme-syntax-operator)",
+ },
+ },
+ {
+ scope: ["constant.character", "constant.other.option"],
+ settings: {
+ foreground: "var(--theme-syntax-keyword)",
+ },
+ },
+ {
+ scope: "constant.character.escape",
+ settings: {
+ foreground: "var(--theme-syntax-operator)",
+ },
+ },
+ {
+ scope: "entity.name.label",
+ settings: {
+ foreground: "var(--theme-text-muted)",
+ },
+ },
+ ],
+ type: "dark",
+}
+
+const highlighter = await createHighlighter({
+ themes: [theme],
+ langs: [],
+})
+
+type ShikiContext = typeof highlighter
+
+const ctx = createContext<ShikiContext>()
+
+export function ShikiProvider(props: ParentProps) {
+ return <ctx.Provider value={highlighter}>{props.children}</ctx.Provider>
+}
+
+export function useShiki() {
+ const value = useContext(ctx)
+ if (!value) {
+ throw new Error("useShiki must be used within a ShikiProvider")
+ }
+ return value
+}
diff --git a/packages/app/src/context/sync.tsx b/packages/app/src/context/sync.tsx
index 22140683d..907071d75 100644
--- a/packages/app/src/context/sync.tsx
+++ b/packages/app/src/context/sync.tsx
@@ -1,7 +1,7 @@
import type { Message, Agent, Provider, Session, Part, Config, Path, File, FileNode } from "@opencode-ai/sdk"
import { createStore, produce, reconcile } from "solid-js/store"
-import { useSDK } from "./sdk"
import { createContext, Show, useContext, type ParentProps } from "solid-js"
+import { useSDK, useEvent } from "@/context"
import { Binary } from "@/utils/binary"
function init() {
@@ -33,69 +33,67 @@ function init() {
changes: [],
})
- const sdk = useSDK()
-
- sdk.event.subscribe().then(async (events) => {
- for await (const event of events.stream) {
- switch (event.type) {
- case "session.updated": {
- const result = Binary.search(store.session, event.properties.info.id, (s) => s.id)
- if (result.found) {
- setStore("session", result.index, reconcile(event.properties.info))
- break
- }
- setStore(
- "session",
- produce((draft) => {
- draft.splice(result.index, 0, event.properties.info)
- }),
- )
+ const bus = useEvent()
+ bus.listen((event) => {
+ switch (event.type) {
+ case "session.updated": {
+ const result = Binary.search(store.session, event.properties.info.id, (s) => s.id)
+ if (result.found) {
+ setStore("session", result.index, reconcile(event.properties.info))
break
}
- case "message.updated": {
- const messages = store.message[event.properties.info.sessionID]
- if (!messages) {
- setStore("message", event.properties.info.sessionID, [event.properties.info])
- break
- }
- const result = Binary.search(messages, event.properties.info.id, (m) => m.id)
- if (result.found) {
- setStore("message", event.properties.info.sessionID, result.index, reconcile(event.properties.info))
- break
- }
- setStore(
- "message",
- event.properties.info.sessionID,
- produce((draft) => {
- draft.splice(result.index, 0, event.properties.info)
- }),
- )
+ setStore(
+ "session",
+ produce((draft) => {
+ draft.splice(result.index, 0, event.properties.info)
+ }),
+ )
+ break
+ }
+ case "message.updated": {
+ const messages = store.message[event.properties.info.sessionID]
+ if (!messages) {
+ setStore("message", event.properties.info.sessionID, [event.properties.info])
break
}
- case "message.part.updated": {
- const parts = store.part[event.properties.part.messageID]
- if (!parts) {
- setStore("part", event.properties.part.messageID, [event.properties.part])
- break
- }
- const result = Binary.search(parts, event.properties.part.id, (p) => p.id)
- if (result.found) {
- setStore("part", event.properties.part.messageID, result.index, reconcile(event.properties.part))
- break
- }
- setStore(
- "part",
- event.properties.part.messageID,
- produce((draft) => {
- draft.splice(result.index, 0, event.properties.part)
- }),
- )
+ const result = Binary.search(messages, event.properties.info.id, (m) => m.id)
+ if (result.found) {
+ setStore("message", event.properties.info.sessionID, result.index, reconcile(event.properties.info))
break
}
+ setStore(
+ "message",
+ event.properties.info.sessionID,
+ produce((draft) => {
+ draft.splice(result.index, 0, event.properties.info)
+ }),
+ )
+ break
+ }
+ case "message.part.updated": {
+ const parts = store.part[event.properties.part.messageID]
+ if (!parts) {
+ setStore("part", event.properties.part.messageID, [event.properties.part])
+ break
+ }
+ const result = Binary.search(parts, event.properties.part.id, (p) => p.id)
+ if (result.found) {
+ setStore("part", event.properties.part.messageID, result.index, reconcile(event.properties.part))
+ break
+ }
+ setStore(
+ "part",
+ event.properties.part.messageID,
+ produce((draft) => {
+ draft.splice(result.index, 0, event.properties.part)
+ }),
+ )
+ break
}
}
})
+ const sdk = useSDK()
Promise.all([
sdk.config.providers().then((x) => setStore("provider", x.data!.providers)),
sdk.path.get().then((x) => setStore("path", x.data!)),