Update UI permissions for SDK 1.0.166

Handle permission.asked events and requestID replies while keeping legacy compatibility.
This commit is contained in:
Shantur Rathore
2026-01-04 20:50:25 +00:00
parent c2df32ec8b
commit fcb5998474
11 changed files with 226 additions and 66 deletions

2
package-lock.json generated
View File

@@ -7476,7 +7476,7 @@
"dependencies": { "dependencies": {
"@git-diff-view/solid": "^0.0.8", "@git-diff-view/solid": "^0.0.8",
"@kobalte/core": "0.13.11", "@kobalte/core": "0.13.11",
"@opencode-ai/sdk": "^1.0.138", "@opencode-ai/sdk": "1.0.166",
"@solidjs/router": "^0.13.0", "@solidjs/router": "^0.13.0",
"@suid/icons-material": "^0.9.0", "@suid/icons-material": "^0.9.0",
"@suid/material": "^0.19.0", "@suid/material": "^0.19.0",

View File

@@ -12,7 +12,7 @@
"dependencies": { "dependencies": {
"@git-diff-view/solid": "^0.0.8", "@git-diff-view/solid": "^0.0.8",
"@kobalte/core": "0.13.11", "@kobalte/core": "0.13.11",
"@opencode-ai/sdk": "^1.0.138", "@opencode-ai/sdk": "1.0.166",
"@solidjs/router": "^0.13.0", "@solidjs/router": "^0.13.0",
"@suid/icons-material": "^0.9.0", "@suid/icons-material": "^0.9.0",
"@suid/material": "^0.19.0", "@suid/material": "^0.19.0",

View File

@@ -7,6 +7,7 @@ import { useGlobalCache } from "../lib/hooks/use-global-cache"
import { useConfig } from "../stores/preferences" import { useConfig } from "../stores/preferences"
import type { DiffViewMode } from "../stores/preferences" import type { DiffViewMode } from "../stores/preferences"
import { sendPermissionResponse } from "../stores/instances" import { sendPermissionResponse } from "../stores/instances"
import { getPermissionDisplayTitle, getPermissionKind, getPermissionSessionId } from "../types/permission"
import type { TextPart, RenderCache } from "../types/message" import type { TextPart, RenderCache } from "../types/message"
import { resolveToolRenderer } from "./tool-call/renderers" import { resolveToolRenderer } from "./tool-call/renderers"
import type { import type {
@@ -837,7 +838,7 @@ export default function ToolCall(props: ToolCallProps) {
setPermissionSubmitting(true) setPermissionSubmitting(true)
setPermissionError(null) setPermissionError(null)
try { try {
const sessionId = permission.sessionID || props.sessionId const sessionId = getPermissionSessionId(permission) || props.sessionId
await sendPermissionResponse(props.instanceId, sessionId, permission.id, response) await sendPermissionResponse(props.instanceId, sessionId, permission.id, response)
} catch (error) { } catch (error) {
log.error("Failed to send permission response", error) log.error("Failed to send permission response", error)
@@ -882,11 +883,11 @@ export default function ToolCall(props: ToolCallProps) {
<div class={`tool-call-permission ${active ? "tool-call-permission-active" : "tool-call-permission-queued"}`}> <div class={`tool-call-permission ${active ? "tool-call-permission-active" : "tool-call-permission-queued"}`}>
<div class="tool-call-permission-header"> <div class="tool-call-permission-header">
<span class="tool-call-permission-label">{active ? "Permission Required" : "Permission Queued"}</span> <span class="tool-call-permission-label">{active ? "Permission Required" : "Permission Queued"}</span>
<span class="tool-call-permission-type">{permission.type}</span> <span class="tool-call-permission-type">{getPermissionKind(permission)}</span>
</div> </div>
<div class="tool-call-permission-body"> <div class="tool-call-permission-body">
<div class="tool-call-permission-title"> <div class="tool-call-permission-title">
<code>{permission.title}</code> <code>{getPermissionDisplayTitle(permission)}</code>
</div> </div>
<Show when={diffPayload}> <Show when={diffPayload}>
{(payload) => ( {(payload) => (

View File

@@ -7,8 +7,7 @@ import {
} from "../types/message" } from "../types/message"
import type { import type {
EventLspUpdated, EventLspUpdated,
EventPermissionReplied,
EventPermissionUpdated,
EventSessionCompacted, EventSessionCompacted,
EventSessionError, EventSessionError,
EventSessionIdle, EventSessionIdle,
@@ -62,8 +61,8 @@ type SSEEvent =
| EventSessionCompacted | EventSessionCompacted
| EventSessionError | EventSessionError
| EventSessionIdle | EventSessionIdle
| EventPermissionUpdated | { type: "permission.updated" | "permission.asked"; properties?: any }
| EventPermissionReplied | { type: "permission.replied"; properties?: any }
| EventLspUpdated | EventLspUpdated
| TuiToastEvent | TuiToastEvent
| BackgroundProcessUpdatedEvent | BackgroundProcessUpdatedEvent
@@ -139,10 +138,11 @@ class SSEManager {
this.onSessionStatus?.(instanceId, event as EventSessionStatus) this.onSessionStatus?.(instanceId, event as EventSessionStatus)
break break
case "permission.updated": case "permission.updated":
this.onPermissionUpdated?.(instanceId, event as EventPermissionUpdated) case "permission.asked":
this.onPermissionUpdated?.(instanceId, event as any)
break break
case "permission.replied": case "permission.replied":
this.onPermissionReplied?.(instanceId, event as EventPermissionReplied) this.onPermissionReplied?.(instanceId, event as any)
break break
case "lsp.updated": case "lsp.updated":
this.onLspUpdated?.(instanceId, event as EventLspUpdated) this.onLspUpdated?.(instanceId, event as EventLspUpdated)
@@ -176,8 +176,8 @@ class SSEManager {
onTuiToast?: (instanceId: string, event: TuiToastEvent) => void onTuiToast?: (instanceId: string, event: TuiToastEvent) => void
onSessionIdle?: (instanceId: string, event: EventSessionIdle) => void onSessionIdle?: (instanceId: string, event: EventSessionIdle) => void
onSessionStatus?: (instanceId: string, event: EventSessionStatus) => void onSessionStatus?: (instanceId: string, event: EventSessionStatus) => void
onPermissionUpdated?: (instanceId: string, event: EventPermissionUpdated) => void onPermissionUpdated?: (instanceId: string, event: any) => void
onPermissionReplied?: (instanceId: string, event: EventPermissionReplied) => void onPermissionReplied?: (instanceId: string, event: any) => void
onLspUpdated?: (instanceId: string, event: EventLspUpdated) => void onLspUpdated?: (instanceId: string, event: EventLspUpdated) => void
onBackgroundProcessUpdated?: (instanceId: string, event: BackgroundProcessUpdatedEvent) => void onBackgroundProcessUpdated?: (instanceId: string, event: BackgroundProcessUpdatedEvent) => void
onBackgroundProcessRemoved?: (instanceId: string, event: BackgroundProcessRemovedEvent) => void onBackgroundProcessRemoved?: (instanceId: string, event: BackgroundProcessRemovedEvent) => void

View File

@@ -1,6 +1,8 @@
import { createSignal } from "solid-js" import { createSignal } from "solid-js"
import type { Instance, LogEntry } from "../types/instance" import type { Instance, LogEntry } from "../types/instance"
import type { LspStatus, Permission } from "@opencode-ai/sdk" import type { LspStatus } from "@opencode-ai/sdk"
import type { PermissionReply, PermissionRequestLike } from "../types/permission"
import { getPermissionCreatedAt, getPermissionSessionId } from "../types/permission"
import { sdkManager } from "../lib/sdk-manager" import { sdkManager } from "../lib/sdk-manager"
import { sseManager } from "../lib/sse-manager" import { sseManager } from "../lib/sse-manager"
import { serverApi } from "../lib/api-client" import { serverApi } from "../lib/api-client"
@@ -31,7 +33,7 @@ const [instanceLogs, setInstanceLogs] = createSignal<Map<string, LogEntry[]>>(ne
const [logStreamingState, setLogStreamingState] = createSignal<Map<string, boolean>>(new Map()) const [logStreamingState, setLogStreamingState] = createSignal<Map<string, boolean>>(new Map())
// Permission queue management per instance // Permission queue management per instance
const [permissionQueues, setPermissionQueues] = createSignal<Map<string, Permission[]>>(new Map()) const [permissionQueues, setPermissionQueues] = createSignal<Map<string, PermissionRequestLike[]>>(new Map())
const [activePermissionId, setActivePermissionId] = createSignal<Map<string, string | null>>(new Map()) const [activePermissionId, setActivePermissionId] = createSignal<Map<string, string | null>>(new Map())
const permissionSessionCounts = new Map<string, Map<string, number>>() const permissionSessionCounts = new Map<string, Map<string, number>>()
@@ -382,7 +384,7 @@ function clearLogs(id: string) {
} }
// Permission management functions // Permission management functions
function getPermissionQueue(instanceId: string): Permission[] { function getPermissionQueue(instanceId: string): PermissionRequestLike[] {
const queue = permissionQueues().get(instanceId) const queue = permissionQueues().get(instanceId)
if (!queue) { if (!queue) {
return [] return []
@@ -429,7 +431,7 @@ function clearSessionPendingCounts(instanceId: string): void {
permissionSessionCounts.delete(instanceId) permissionSessionCounts.delete(instanceId)
} }
function addPermissionToQueue(instanceId: string, permission: Permission): void { function addPermissionToQueue(instanceId: string, permission: PermissionRequestLike): void {
let inserted = false let inserted = false
setPermissionQueues((prev) => { setPermissionQueues((prev) => {
@@ -440,7 +442,7 @@ function addPermissionToQueue(instanceId: string, permission: Permission): void
return next return next
} }
const updatedQueue = [...queue, permission].sort((a, b) => a.time.created - b.time.created) const updatedQueue = [...queue, permission].sort((a, b) => getPermissionCreatedAt(a) - getPermissionCreatedAt(b))
next.set(instanceId, updatedQueue) next.set(instanceId, updatedQueue)
inserted = true inserted = true
return next return next
@@ -459,17 +461,19 @@ function addPermissionToQueue(instanceId: string, permission: Permission): void
}) })
const sessionId = getPermissionSessionId(permission) const sessionId = getPermissionSessionId(permission)
incrementSessionPendingCount(instanceId, sessionId) if (sessionId) {
setSessionPendingPermission(instanceId, sessionId, true) incrementSessionPendingCount(instanceId, sessionId)
setSessionPendingPermission(instanceId, sessionId, true)
}
} }
function removePermissionFromQueue(instanceId: string, permissionId: string): void { function removePermissionFromQueue(instanceId: string, permissionId: string): void {
let removedPermission: Permission | null = null let removedPermission: PermissionRequestLike | null = null
setPermissionQueues((prev) => { setPermissionQueues((prev) => {
const next = new Map(prev) const next = new Map(prev)
const queue = next.get(instanceId) ?? [] const queue = next.get(instanceId) ?? []
const filtered: Permission[] = [] const filtered: PermissionRequestLike[] = []
for (const item of queue) { for (const item of queue) {
if (item.id === permissionId) { if (item.id === permissionId) {
@@ -493,7 +497,7 @@ function removePermissionFromQueue(instanceId: string, permissionId: string): vo
const next = new Map(prev) const next = new Map(prev)
const activeId = next.get(instanceId) const activeId = next.get(instanceId)
if (activeId === permissionId) { if (activeId === permissionId) {
const nextPermission = updatedQueue.length > 0 ? (updatedQueue[0] as Permission) : null const nextPermission = updatedQueue.length > 0 ? (updatedQueue[0] as PermissionRequestLike) : null
next.set(instanceId, nextPermission?.id ?? null) next.set(instanceId, nextPermission?.id ?? null)
} }
return next return next
@@ -502,8 +506,10 @@ function removePermissionFromQueue(instanceId: string, permissionId: string): vo
const removed = removedPermission const removed = removedPermission
if (removed) { if (removed) {
const removedSessionId = getPermissionSessionId(removed) const removedSessionId = getPermissionSessionId(removed)
const remaining = decrementSessionPendingCount(instanceId, removedSessionId) if (removedSessionId) {
setSessionPendingPermission(instanceId, removedSessionId, remaining > 0) const remaining = decrementSessionPendingCount(instanceId, removedSessionId)
setSessionPendingPermission(instanceId, removedSessionId, remaining > 0)
}
} }
} }
@@ -521,29 +527,55 @@ function clearPermissionQueue(instanceId: string): void {
clearSessionPendingCounts(instanceId) clearSessionPendingCounts(instanceId)
} }
function getPermissionSessionId(permission: Permission): string {
return (permission as any).sessionID
}
async function sendPermissionResponse( async function sendPermissionResponse(
instanceId: string, instanceId: string,
sessionId: string, sessionId: string,
permissionId: string, requestId: string,
response: "once" | "always" | "reject" reply: PermissionReply
): Promise<void> { ): Promise<void> {
const instance = instances().get(instanceId) const instance = instances().get(instanceId)
if (!instance?.client) { if (!instance?.client) {
throw new Error("Instance not ready") throw new Error("Instance not ready")
} }
const client: any = instance.client
try { try {
await instance.client.postSessionIdPermissionsPermissionId({ // New API (preferred): POST /permission/:requestID/reply
path: { id: sessionId, permissionID: permissionId }, if (typeof client.postPermissionRequestIdReply === "function") {
body: { response }, await client.postPermissionRequestIdReply({
}) path: { requestID: requestId },
body: { reply },
})
} else if (typeof client.postPermissionRequestIDReply === "function") {
await client.postPermissionRequestIDReply({
path: { requestID: requestId },
body: { reply },
})
} else if (typeof client.postPermissionRequestIdReply2 === "function") {
await client.postPermissionRequestIdReply2({
path: { requestID: requestId },
body: { reply },
})
} else if (client.permission && typeof client.permission.reply === "function") {
await client.permission.reply({
path: { requestID: requestId },
body: { reply },
})
} else if (typeof client.postSessionIdPermissionsPermissionId === "function") {
// Legacy API fallback: POST /session/:sessionID/permissions/:permissionID
await client.postSessionIdPermissionsPermissionId({
path: { id: sessionId, permissionID: requestId },
body: { response: reply },
})
} else {
throw new Error("Unsupported permissions API in client")
}
// Remove from queue after successful response // Remove from queue after successful response
removePermissionFromQueue(instanceId, permissionId) removePermissionFromQueue(instanceId, requestId)
} catch (error) { } catch (error) {
log.error("Failed to send permission response", error) log.error("Failed to send permission response", error)
throw error throw error

View File

@@ -1,4 +1,5 @@
import type { Permission } from "@opencode-ai/sdk" import type { PermissionRequestLike } from "../../types/permission"
import { getPermissionCallId, getPermissionMessageId } from "../../types/permission"
import type { Message, MessageInfo, ClientPart } from "../../types/message" import type { Message, MessageInfo, ClientPart } from "../../types/message"
import type { Session } from "../../types/session" import type { Session } from "../../types/session"
import { messageStoreBus } from "./bus" import { messageStoreBus } from "./bus"
@@ -107,11 +108,11 @@ export function replaceMessageIdV2(instanceId: string, oldId: string, newId: str
store.replaceMessageId({ oldId, newId }) store.replaceMessageId({ oldId, newId })
} }
function extractPermissionMessageId(permission: Permission): string | undefined { function extractPermissionMessageId(permission: PermissionRequestLike): string | undefined {
return (permission as any).messageID || (permission as any).messageId return getPermissionMessageId(permission)
} }
function extractPermissionPartId(permission: Permission): string | undefined { function extractPermissionPartId(permission: PermissionRequestLike): string | undefined {
const metadata = (permission as any).metadata || {} const metadata = (permission as any).metadata || {}
return ( return (
(permission as any).partID || (permission as any).partID ||
@@ -122,17 +123,8 @@ function extractPermissionPartId(permission: Permission): string | undefined {
) )
} }
function extractPermissionCallId(permission: Permission): string | undefined { function extractPermissionCallId(permission: PermissionRequestLike): string | undefined {
const metadata = (permission as any).metadata || {} return getPermissionCallId(permission)
return (
(permission as any).callID ||
(permission as any).callId ||
(permission as any).toolCallID ||
(permission as any).toolCallId ||
metadata.callID ||
metadata.callId ||
undefined
)
} }
function resolvePartIdFromCallId(store: ReturnType<typeof messageStoreBus.getOrCreate>, messageId?: string, callId?: string): string | undefined { function resolvePartIdFromCallId(store: ReturnType<typeof messageStoreBus.getOrCreate>, messageId?: string, callId?: string): string | undefined {
@@ -155,7 +147,7 @@ function resolvePartIdFromCallId(store: ReturnType<typeof messageStoreBus.getOrC
return undefined return undefined
} }
export function upsertPermissionV2(instanceId: string, permission: Permission): void { export function upsertPermissionV2(instanceId: string, permission: PermissionRequestLike): void {
if (!permission) return if (!permission) return
const store = messageStoreBus.getOrCreate(instanceId) const store = messageStoreBus.getOrCreate(instanceId)
const messageId = extractPermissionMessageId(permission) const messageId = extractPermissionMessageId(permission)

View File

@@ -521,6 +521,8 @@ export function createInstanceMessageStore(instanceId: string, hooks?: MessageSt
for (const [key, entry] of Object.entries(draft)) { for (const [key, entry] of Object.entries(draft)) {
if (!entry || entry.partId) continue if (!entry || entry.partId) continue
const permissionCallId = const permissionCallId =
(entry.permission as any).tool?.callID ??
(entry.permission as any).tool?.callId ??
(entry.permission as any).callID ?? (entry.permission as any).callID ??
(entry.permission as any).callId ?? (entry.permission as any).callId ??
(entry.permission as any).toolCallID ?? (entry.permission as any).toolCallID ??

View File

@@ -1,5 +1,5 @@
import type { ClientPart } from "../../types/message" import type { ClientPart } from "../../types/message"
import type { Permission } from "@opencode-ai/sdk" import type { PermissionRequestLike } from "../../types/permission"
export type MessageStatus = "sending" | "sent" | "streaming" | "complete" | "error" export type MessageStatus = "sending" | "sent" | "streaming" | "complete" | "error"
export type MessageRole = "user" | "assistant" export type MessageRole = "user" | "assistant"
@@ -47,7 +47,7 @@ export interface PendingPartEntry {
} }
export interface PermissionEntry { export interface PermissionEntry {
permission: Permission permission: PermissionRequestLike
messageId?: string messageId?: string
partId?: string partId?: string
enqueuedAt: number enqueuedAt: number

View File

@@ -6,8 +6,6 @@ import type {
MessageUpdateEvent, MessageUpdateEvent,
} from "../types/message" } from "../types/message"
import type { import type {
EventPermissionReplied,
EventPermissionUpdated,
EventSessionCompacted, EventSessionCompacted,
EventSessionError, EventSessionError,
EventSessionIdle, EventSessionIdle,
@@ -17,6 +15,8 @@ import type {
import type { MessageStatus } from "./message-v2/types" import type { MessageStatus } from "./message-v2/types"
import { getLogger } from "../lib/logger" import { getLogger } from "../lib/logger"
import { getPermissionId, getPermissionKind, getRequestIdFromPermissionReply } from "../types/permission"
import type { PermissionReplyEventPropertiesLike, PermissionRequestLike } from "../types/permission"
import { showToastNotification, ToastVariant } from "../lib/notifications" import { showToastNotification, ToastVariant } from "../lib/notifications"
import { instances, addPermissionToQueue, removePermissionFromQueue } from "./instances" import { instances, addPermissionToQueue, removePermissionFromQueue } from "./instances"
import { showAlertDialog } from "./alerts" import { showAlertDialog } from "./alerts"
@@ -442,22 +442,23 @@ function handleTuiToast(_instanceId: string, event: TuiToastEvent): void {
}) })
} }
function handlePermissionUpdated(instanceId: string, event: EventPermissionUpdated): void { function handlePermissionUpdated(instanceId: string, event: { type: string; properties?: PermissionRequestLike } | any): void {
const permission = event.properties const permission = event?.properties as PermissionRequestLike | undefined
if (!permission) return if (!permission) return
log.info(`[SSE] Permission updated: ${permission.id} (${permission.type})`) log.info(`[SSE] Permission request: ${getPermissionId(permission)} (${getPermissionKind(permission)})`)
addPermissionToQueue(instanceId, permission) addPermissionToQueue(instanceId, permission)
upsertPermissionV2(instanceId, permission) upsertPermissionV2(instanceId, permission)
} }
function handlePermissionReplied(instanceId: string, event: EventPermissionReplied): void { function handlePermissionReplied(instanceId: string, event: { type: string; properties?: PermissionReplyEventPropertiesLike } | any): void {
const { permissionID } = event.properties const properties = event?.properties as PermissionReplyEventPropertiesLike | undefined
if (!permissionID) return const requestId = getRequestIdFromPermissionReply(properties)
if (!requestId) return
log.info(`[SSE] Permission replied: ${permissionID}`) log.info(`[SSE] Permission replied: ${requestId}`)
removePermissionFromQueue(instanceId, permissionID) removePermissionFromQueue(instanceId, requestId)
removePermissionV2(instanceId, permissionID) removePermissionV2(instanceId, requestId)
} }
export { export {

View File

@@ -6,9 +6,10 @@ import type {
EventMessagePartRemoved as MessagePartRemovedEvent, EventMessagePartRemoved as MessagePartRemovedEvent,
Part as SDKPart, Part as SDKPart,
Message as SDKMessage, Message as SDKMessage,
Permission,
} from "@opencode-ai/sdk" } from "@opencode-ai/sdk"
import type { PermissionRequestLike } from "./permission"
// Re-export for other modules // Re-export for other modules
export type { export type {
MessageUpdateEvent, MessageUpdateEvent,
@@ -27,7 +28,7 @@ export interface RenderCache {
} }
export interface PendingPermissionState { export interface PendingPermissionState {
permission: Permission permission: PermissionRequestLike
active: boolean active: boolean
} }

View File

@@ -0,0 +1,131 @@
export type PermissionReply = "once" | "always" | "reject"
export interface PermissionToolRefLike {
messageID?: string
messageId?: string
callID?: string
callId?: string
}
// Compat type that covers both the legacy Permission.Info payload and the new
// PermissionNext.Request payload.
export interface PermissionRequestLike {
id: string
// Legacy fields
type?: string
pattern?: string
title?: string
sessionID?: string
messageID?: string
messageId?: string
callID?: string
callId?: string
metadata?: Record<string, unknown>
time?: { created?: number }
// New fields
permission?: string
patterns?: string[]
always?: string[]
tool?: PermissionToolRefLike
}
export interface PermissionReplyEventPropertiesLike {
sessionID?: string
sessionId?: string
permissionID?: string
permissionId?: string
requestID?: string
requestId?: string
response?: PermissionReply
reply?: PermissionReply
}
export function getPermissionId(permission: PermissionRequestLike | null | undefined): string {
return permission?.id ?? ""
}
export function getPermissionSessionId(permission: PermissionRequestLike | null | undefined): string | undefined {
return (
(permission as any)?.sessionID ??
(permission as any)?.sessionId ??
undefined
)
}
export function getPermissionMessageId(permission: PermissionRequestLike | null | undefined): string | undefined {
const tool = (permission as any)?.tool as PermissionToolRefLike | undefined
return (
tool?.messageID ??
tool?.messageId ??
(permission as any)?.messageID ??
(permission as any)?.messageId ??
undefined
)
}
export function getPermissionCallId(permission: PermissionRequestLike | null | undefined): string | undefined {
const tool = (permission as any)?.tool as PermissionToolRefLike | undefined
const metadata = (permission as any)?.metadata || {}
return (
tool?.callID ??
tool?.callId ??
(permission as any)?.callID ??
(permission as any)?.callId ??
(permission as any)?.toolCallID ??
(permission as any)?.toolCallId ??
metadata.callID ??
metadata.callId ??
undefined
)
}
export function getPermissionCreatedAt(permission: PermissionRequestLike | null | undefined): number {
const created = (permission as any)?.time?.created
return typeof created === "number" ? created : Date.now()
}
export function getPermissionKind(permission: PermissionRequestLike | null | undefined): string {
return (
(permission as any)?.permission ??
(permission as any)?.type ??
"permission"
)
}
export function getPermissionPatterns(permission: PermissionRequestLike | null | undefined): string[] {
const patterns = (permission as any)?.patterns
if (Array.isArray(patterns)) {
return patterns.filter((value) => typeof value === "string")
}
const pattern = (permission as any)?.pattern
if (typeof pattern === "string" && pattern.length > 0) {
return [pattern]
}
return []
}
export function getPermissionDisplayTitle(permission: PermissionRequestLike | null | undefined): string {
const title = (permission as any)?.title
if (typeof title === "string" && title.trim().length > 0) {
return title
}
const kind = getPermissionKind(permission)
const patterns = getPermissionPatterns(permission)
if (patterns.length > 0) {
return `${kind}: ${patterns.join(", ")}`
}
return kind
}
export function getRequestIdFromPermissionReply(properties: PermissionReplyEventPropertiesLike | null | undefined): string | undefined {
return (
(properties as any)?.requestID ??
(properties as any)?.requestId ??
(properties as any)?.permissionID ??
(properties as any)?.permissionId ??
undefined
)
}