Compare commits

...

4 Commits

Author SHA1 Message Date
Huakun Shen
acc1e7ffae
feat: enhance command handling and update SDK version 2025-03-26 08:43:33 -04:00
Huakun Shen
0c9d9d5373
more types fixed 2025-03-26 07:58:33 -04:00
Huakun Shen
67807b229d
format 2025-03-26 07:31:12 -04:00
Huakun Shen
e413121cd1
fix type errors after removing supabase 2025-03-26 07:30:52 -04:00
23 changed files with 183 additions and 244 deletions

View File

@ -1,3 +1,4 @@
import { IconType } from "@kksh/api/models"
import { getExtensionsLatestPublishByIdentifier } from "@kksh/sdk" import { getExtensionsLatestPublishByIdentifier } from "@kksh/sdk"
const latestPublish = await getExtensionsLatestPublishByIdentifier({ const latestPublish = await getExtensionsLatestPublishByIdentifier({
@ -6,3 +7,7 @@ const latestPublish = await getExtensionsLatestPublishByIdentifier({
} }
}) })
console.log(latestPublish) console.log(latestPublish)
// latestPublish
// console.log(typeof IconEnum.Iconify)
console.log(IconType.options)

View File

@ -12,7 +12,7 @@ import { onQuickLinkSelect } from "./quick-links"
const onExtCmdSelect: OnExtCmdSelect = ( const onExtCmdSelect: OnExtCmdSelect = (
ext: ExtPackageJsonExtra, ext: ExtPackageJsonExtra,
cmd: CustomUiCmd | TemplateUiCmd, cmd: CustomUiCmd | TemplateUiCmd | HeadlessCmd,
{ isDev, hmr }: { isDev: boolean; hmr: boolean } { isDev, hmr }: { isDev: boolean; hmr: boolean }
) => { ) => {
switch (cmd.type) { switch (cmd.type) {

View File

@ -3,16 +3,16 @@
* It's designed to allow all components to access a shared state. * It's designed to allow all components to access a shared state.
* With context, we can avoid prop drilling, and avoid using stores which makes components hard to encapsulate. * With context, we can avoid prop drilling, and avoid using stores which makes components hard to encapsulate.
*/ */
import type { AppConfig } from "@/types/appConfig" import type { AppConfigState } from "@kksh/types"
import { getContext, setContext } from "svelte" import { getContext, setContext } from "svelte"
import type { Writable } from "svelte/store" import type { Writable } from "svelte/store"
export const APP_CONFIG_CONTEXT_KEY = Symbol("appConfig") export const APP_CONFIG_CONTEXT_KEY = Symbol("appConfig")
export function getAppConfigContext(): Writable<AppConfig> { export function getAppConfigContext(): Writable<AppConfigState> {
return getContext(APP_CONFIG_CONTEXT_KEY) return getContext(APP_CONFIG_CONTEXT_KEY)
} }
export function setAppConfigContext(appConfig: Writable<AppConfig>) { export function setAppConfigContext(appConfig: Writable<AppConfigState>) {
setContext(APP_CONFIG_CONTEXT_KEY, appConfig) setContext(APP_CONFIG_CONTEXT_KEY, appConfig)
} }

View File

@ -1,4 +1,4 @@
import type { AppState } from "@/types/appState" import type { AppState } from "@kksh/types"
import { getContext, setContext } from "svelte" import { getContext, setContext } from "svelte"
import type { Writable } from "svelte/store" import type { Writable } from "svelte/store"

View File

@ -7,7 +7,7 @@ import Fuse from "fuse.js"
import { derived, get, writable } from "svelte/store" import { derived, get, writable } from "svelte/store"
import { appState } from "./appState" import { appState } from "./appState"
export const fuse = new Fuse<AppInfo>([], { const fuse = new Fuse<AppInfo>([], {
includeScore: true, includeScore: true,
threshold: 0.2, threshold: 0.2,
keys: ["name"] keys: ["name"]

View File

@ -6,7 +6,7 @@ import Fuse from "fuse.js"
import { derived, get, writable, type Writable } from "svelte/store" import { derived, get, writable, type Writable } from "svelte/store"
import { appState } from "./appState" import { appState } from "./appState"
export const fuse = new Fuse<QuickLink>([], { const fuse = new Fuse<QuickLink>([], {
includeScore: true, includeScore: true,
threshold: 0.2, threshold: 0.2,
keys: ["name"] keys: ["name"]

View File

@ -82,7 +82,7 @@
}) })
if (error) if (error)
return toast.error("Fail to get latest extension", { return toast.error("Fail to get latest extension", {
description: error as string description: error.error
}) })
const installExtras = await getInstallExtras(data?.metadata) const installExtras = await getInstallExtras(data?.metadata)
return extensions return extensions
@ -100,7 +100,7 @@
}) })
if (error) if (error)
return toast.error("Fail to get latest extension", { return toast.error("Fail to get latest extension", {
description: error description: error.error
}) })
const installExtras = await getInstallExtras(data?.metadata) const installExtras = await getInstallExtras(data?.metadata)
@ -164,7 +164,7 @@
}) })
</script> </script>
<svelte:window on:keydown={onkeydown} /> <svelte:window {onkeydown} />
{#snippet leftSlot()} {#snippet leftSlot()}
<Button <Button
variant="outline" variant="outline"

View File

@ -21,7 +21,6 @@ export const load: PageLoad = (): Promise<{
if (error) { if (error) {
toast.error(`Failed to load extension store: ${error} (${response.status})`) toast.error(`Failed to load extension store: ${error} (${response.status})`)
goHome() goHome()
return
} }
const storeExtsMap = Object.fromEntries(storeExtList.map((ext) => [ext.identifier, ext])) const storeExtsMap = Object.fromEntries(storeExtList.map((ext) => [ext.identifier, ext]))
const installedExtsMap = derived(installedStoreExts, ($exts) => const installedExtsMap = derived(installedStoreExts, ($exts) =>

View File

@ -2,7 +2,7 @@
import { getExtensionsFolder } from "@/constants.js" import { getExtensionsFolder } from "@/constants.js"
import { i18n } from "@/i18n.js" import { i18n } from "@/i18n.js"
import { extensions, installedStoreExts } from "@/stores/extensions.js" import { extensions, installedStoreExts } from "@/stores/extensions.js"
import { ExtensionStoreListItem, ExtPackageJson, ExtPublish } from "@kksh/api/models" import { DBExtension, ExtensionStoreListItem, ExtPackageJson, ExtPublish } from "@kksh/api/models"
import { postExtensionsIncrementDownloads } from "@kksh/sdk" import { postExtensionsIncrementDownloads } from "@kksh/sdk"
import { Button } from "@kksh/svelte5" import { Button } from "@kksh/svelte5"
import { cn } from "@kksh/svelte5/utils" import { cn } from "@kksh/svelte5/utils"
@ -19,8 +19,8 @@
import { getInstallExtras } from "./helper" import { getInstallExtras } from "./helper"
const { data } = $props() const { data } = $props()
const extPublish: ExtPublish = $derived(data.extPublish) const extPublish = $derived(data.extPublish)
const ext: ExtensionStoreListItem = $derived(data.ext) const ext = $derived(data.ext)
const manifest = $derived(data.manifest) const manifest = $derived(data.manifest)
const installedExt = storeDerived(installedStoreExts, ($e) => { const installedExt = storeDerived(installedStoreExts, ($e) => {
return $e.find((e) => e.kunkun.identifier === extPublish.identifier) return $e.find((e) => e.kunkun.identifier === extPublish.identifier)

View File

@ -1,28 +1,16 @@
import { appState, extensions } from "@/stores" import { appState } from "@/stores"
import { import { DBExtension, ExtPublish, KunkunExtManifest } from "@kksh/api/models"
ExtensionStoreListItem, import { getExtensionsByIdentifier, getExtensionsLatestPublishByIdentifier } from "@kksh/sdk"
ExtPublish,
KunkunExtManifest,
type ExtPackageJsonExtra
} from "@kksh/api/models"
import {
getExtensionsByIdentifier,
getExtensionsLatestPublishByIdentifier,
type GetExtensionsByIdentifierResponse,
type GetExtensionsLatestPublishByIdentifierResponse,
type GetExtensionsLatestPublishByIdentifierResponses
} from "@kksh/sdk"
import { error } from "@sveltejs/kit" import { error } from "@sveltejs/kit"
import { toast } from "svelte-sonner"
import * as v from "valibot" import * as v from "valibot"
import type { PageLoad } from "./$types" import type { PageLoad } from "./$types"
export const load: PageLoad = ({ export const load: PageLoad = ({
params params
}): Promise<{ }): Promise<{
// extPublish: GetExtensionsLatestPublishByIdentifierResponses['200'] extPublish: ExtPublish
ext: GetExtensionsByIdentifierResponse ext: DBExtension
manifest: GetExtensionsLatestPublishByIdentifierResponse["manifest"] manifest: KunkunExtManifest
params: { params: {
identifier: string identifier: string
} }
@ -35,27 +23,29 @@ export const load: PageLoad = ({
}) })
.then(async ({ data: extPublish, error: err, response }) => { .then(async ({ data: extPublish, error: err, response }) => {
if (err || !extPublish) { if (err || !extPublish) {
console.error(err) return error(response.status, {
return error(400, {
message: "Failed to get extension publish" message: "Failed to get extension publish"
}) })
} }
const { data: ext, error: extError } = await getExtensionsByIdentifier({ const {
data: ext,
error: extError,
response: extRes
} = await getExtensionsByIdentifier({
path: { path: {
identifier: params.identifier identifier: params.identifier
} }
}) })
if (extError) { if (extError || !ext) {
console.error(extError) console.error(extError)
return error(400, { return error(extRes.status, {
message: "Failed to get extension" message: extError.error || "Failed to get extension"
}) })
} }
return { return {
// extPublish, extPublish: v.parse(ExtPublish, extPublish),
ext, ext,
manifest: extPublish.manifest, manifest: v.parse(KunkunExtManifest, extPublish.manifest),
params params
} }
}) })

View File

@ -1,11 +1,9 @@
import type { ExtPublishMetadata } from "@kunkunapi/src/models" import type { ExtPublishMetadata } from "@kunkunapi/src/models"
export async function getInstallExtras( export async function getInstallExtras(extMetadata?: {
extMetadata?: { sourceType?: string
sourceType?: string source?: string
source?: string }): Promise<{ overwritePackageJson?: string }> {
}
): Promise<{ overwritePackageJson?: string }> {
const extras: { overwritePackageJson?: string } = {} const extras: { overwritePackageJson?: string } = {}
if (extMetadata?.sourceType) { if (extMetadata?.sourceType) {
if (extMetadata?.sourceType === "jsr") { if (extMetadata?.sourceType === "jsr") {

View File

@ -9,7 +9,8 @@
"skipLibCheck": true, "skipLibCheck": true,
"sourceMap": true, "sourceMap": true,
"strict": true, "strict": true,
"moduleResolution": "bundler" "moduleResolution": "bundler",
"allowImportingTsExtensions": true
}, },
// Path aliases are handled by https://kit.svelte.dev/docs/configuration#alias // Path aliases are handled by https://kit.svelte.dev/docs/configuration#alias
// except $lib which is handled by https://kit.svelte.dev/docs/configuration#files // except $lib which is handled by https://kit.svelte.dev/docs/configuration#files

View File

@ -28,8 +28,9 @@
}, },
"dependencies": { "dependencies": {
"@changesets/cli": "^2.28.1", "@changesets/cli": "^2.28.1",
"@hey-api/client-fetch": "^0.8.3",
"@iconify/svelte": "^4.2.0", "@iconify/svelte": "^4.2.0",
"@kksh/sdk": "^0.0.1", "@kksh/sdk": "^0.0.3",
"@supabase/supabase-js": "^2.49.1", "@supabase/supabase-js": "^2.49.1",
"@tauri-apps/api": "^2.3.0", "@tauri-apps/api": "^2.3.0",
"@tauri-apps/cli": "^2.3.1", "@tauri-apps/cli": "^2.3.1",

View File

@ -1,91 +1,78 @@
import { import * as v from "valibot"
any,
array,
boolean,
date,
enum_,
function_,
nullable,
number,
object,
optional,
record,
string,
type InferOutput
} from "valibot"
import { Icon } from "./icon" import { Icon } from "./icon"
/** /**
* Map window label to extension * Map window label to extension
*/ */
export const ExtensionLabelMap = record( export const ExtensionLabelMap = v.record(
string("Window label"), v.string("Window label"),
object({ v.object({
path: string("Path to the extension"), path: v.string("Path to the extension"),
processes: array(number()), processes: v.array(v.number()),
dist: optional(nullable(string())) dist: v.optional(v.nullable(v.string()))
}) })
) )
export type ExtensionLabelMap = InferOutput<typeof ExtensionLabelMap> export type ExtensionLabelMap = v.InferOutput<typeof ExtensionLabelMap>
export const Ext = object({ export const Ext = v.object({
extId: number(), extId: v.number(),
identifier: string(), identifier: v.string(),
version: string(), version: v.string(),
enabled: boolean(), enabled: v.boolean(),
installed_at: string(), installed_at: v.string(),
path: nullable(string()), path: v.optional(v.nullable(v.string())),
data: nullable(any()) data: v.optional(v.any())
}) })
export type Ext = InferOutput<typeof Ext> export type Ext = v.InferOutput<typeof Ext>
export enum CmdTypeEnum { export const CmdTypeEnum = {
HeadlessWorker = "headless_worker", HeadlessWorker: "headless_worker",
Builtin = "builtin", Builtin: "builtin",
System = "system", System: "system",
UiWorker = "ui_worker", UiWorker: "ui_worker",
UiIframe = "ui_iframe", UiIframe: "ui_iframe",
QuickLink = "quick_link", QuickLink: "quick_link",
Remote = "remote" Remote: "remote"
} }
export const CmdType = enum_(CmdTypeEnum) export const CmdType = v.picklist(Object.values(CmdTypeEnum))
export type CmdType = InferOutput<typeof CmdType>
export const ExtCmd = object({ export type CmdType = v.InferOutput<typeof CmdType>
cmdId: number(), export const ExtCmd = v.object({
extId: number(), cmdId: v.number(),
name: string(), extId: v.number(),
name: v.string(),
type: CmdType, type: CmdType,
data: string(), data: v.string(),
alias: nullable(optional(string())), alias: v.optional(v.nullable(v.string())),
hotkey: nullable(optional(string())), hotkey: v.optional(v.nullable(v.string())),
enabled: boolean() enabled: v.boolean()
}) })
export type ExtCmd = InferOutput<typeof ExtCmd> export type ExtCmd = v.InferOutput<typeof ExtCmd>
export const QuickLinkCmd = object({ export const QuickLinkCmd = v.object({
...ExtCmd.entries, ...ExtCmd.entries,
data: object({ link: string(), icon: Icon }) data: v.object({ link: v.string(), icon: Icon })
}) })
export type QuickLinkCmd = InferOutput<typeof QuickLinkCmd> export type QuickLinkCmd = v.InferOutput<typeof QuickLinkCmd>
export const ExtData = object({ export const ExtData = v.object({
dataId: number(), dataId: v.number(),
extId: number(), extId: v.number(),
dataType: string(), dataType: v.string(),
data: optional(string()), data: v.optional(v.string()),
searchText: optional(string()), searchText: v.optional(v.string()),
createdAt: date(), createdAt: v.date(),
updatedAt: date() updatedAt: v.date()
}) })
export type ExtData = InferOutput<typeof ExtData> export type ExtData = v.InferOutput<typeof ExtData>
export const SysCommand = object({ export const SysCommand = v.object({
name: string(), name: v.string(),
value: string(), value: v.string(),
icon: nullable(Icon), icon: v.optional(v.nullable(Icon)),
keywords: nullable(array(string())), keywords: v.optional(v.nullable(v.array(v.string()))),
function: function_(), function: v.function_(),
confirmRequired: boolean() confirmRequired: v.boolean()
}) })
export type SysCommand = InferOutput<typeof SysCommand> export type SysCommand = v.InferOutput<typeof SysCommand>

View File

@ -4,22 +4,21 @@ import { NodeName, NodeNameEnum } from "./constants"
/* -------------------------------------------------------------------------- */ /* -------------------------------------------------------------------------- */
/* Icon */ /* Icon */
/* -------------------------------------------------------------------------- */ /* -------------------------------------------------------------------------- */
export enum IconEnum { // export enum IconEnum {
Iconify = "iconify", // Iconify = "iconify",
RemoteUrl = "remote-url", // RemoteUrl = "remote-url",
Svg = "svg", // Svg = "svg",
Base64PNG = "base64-png", // Base64PNG = "base64-png",
Text = "text" // Text = "text"
// }
export const IconEnum = {
Iconify: "iconify",
RemoteUrl: "remote-url",
Svg: "svg",
Base64PNG: "base64-png",
Text: "text"
} }
// export const IconType = v.enum(IconEnum) export const IconType = v.picklist(Object.values(IconEnum))
export const IconType = v.union([
v.literal(IconEnum.Iconify),
v.literal(IconEnum.RemoteUrl),
v.literal(IconEnum.Svg),
v.literal(IconEnum.Base64PNG),
v.literal(IconEnum.Text)
])
export type IconType = v.InferOutput<typeof IconType> export type IconType = v.InferOutput<typeof IconType>
export type Icon = { export type Icon = {

View File

@ -1,4 +1,3 @@
import { FsPermissionSchema } from "tauri-api-adapter/permissions"
import * as v from "valibot" import * as v from "valibot"
import { import {
AllKunkunPermission, AllKunkunPermission,
@ -8,29 +7,29 @@ import {
OpenPermissionScopedSchema, OpenPermissionScopedSchema,
ShellPermissionScopedSchema ShellPermissionScopedSchema
} from "../permissions" } from "../permissions"
import { CmdType } from "./extension" import { CmdType, CmdTypeEnum } from "./extension"
import { BaseIcon as Icon } from "./icon" import { BaseIcon as Icon } from "./icon"
export enum OSPlatformEnum { export const OSPlatformEnum = {
linux = "linux", linux: "linux",
macos = "macos", macos: "macos",
windows = "windows" windows: "windows"
} }
export const OSPlatform = v.enum_(OSPlatformEnum) export const OSPlatform = v.picklist(Object.values(OSPlatformEnum))
export type OSPlatform = v.InferOutput<typeof OSPlatform> export type OSPlatform = v.InferOutput<typeof OSPlatform>
const allPlatforms = Object.values(OSPlatformEnum)
export const TriggerCmd = v.object({ export const TriggerCmd = v.object({
type: v.union([v.literal("text"), v.literal("regex")]), type: v.union([v.literal("text"), v.literal("regex")]),
value: v.string() value: v.string()
}) })
export type TriggerCmd = v.InferOutput<typeof TriggerCmd> export type TriggerCmd = v.InferOutput<typeof TriggerCmd>
export enum TitleBarStyleEnum { export const TitleBarStyleEnum = {
"visible" = "visible", visible: "visible",
"transparent" = "transparent", transparent: "transparent",
"overlay" = "overlay" overlay: "overlay"
} }
export const TitleBarStyle = v.enum_(TitleBarStyleEnum) export type TitleBarStyle = v.InferOutput<typeof TitleBarStyle>
export const TitleBarStyle = v.picklist(Object.values(TitleBarStyleEnum))
// JS new WebViewWindow only accepts lowercase, while manifest loaded from Rust is capitalized. I run toLowerCase() on the value before passing it to the WebViewWindow. // JS new WebViewWindow only accepts lowercase, while manifest loaded from Rust is capitalized. I run toLowerCase() on the value before passing it to the WebViewWindow.
// This lowercase title bar style schema is used to validate and set the type so TypeScript won't complaint // This lowercase title bar style schema is used to validate and set the type so TypeScript won't complaint
// export const TitleBarStyleAllLower = z.enum(["visible", "transparent", "overlay"]); // export const TitleBarStyleAllLower = z.enum(["visible", "transparent", "overlay"]);
@ -71,37 +70,33 @@ export const WindowConfig = v.object({
export type WindowConfig = v.InferOutput<typeof WindowConfig> export type WindowConfig = v.InferOutput<typeof WindowConfig>
export const BaseCmd = v.object({ export const BaseCmd = v.object({
main: v.string("HTML file to load, e.g. dist/index.html"), main: v.string("HTML file to load, e.g. dist/index.html"),
description: v.optional(v.nullable(v.string("Description of the Command"), ""), ""), description: v.optional(v.nullable(v.string("Description of the Command"), "")),
name: v.string("Name of the command"), name: v.string("Name of the command"),
cmds: v.array(TriggerCmd, "Commands to trigger the UI"), cmds: v.array(TriggerCmd, "Commands to trigger the UI"),
icon: v.optional(Icon), icon: v.optional(Icon),
platforms: v.optional( platforms: v.optional(
v.nullable( v.array(OSPlatform, "Platforms available on. Leave empty for all platforms.")
v.array(OSPlatform, "Platforms available on. Leave empty for all platforms."),
allPlatforms
),
allPlatforms
) )
}) })
export const CustomUiCmd = v.object({ export const CustomUiCmd = v.object({
...BaseCmd.entries, ...BaseCmd.entries,
type: v.optional(CmdType, CmdType.enum.UiIframe),
dist: v.string("Dist folder to load, e.g. dist, build, out"), dist: v.string("Dist folder to load, e.g. dist, build, out"),
devMain: v.string( devMain: v.string(
"URL to load in development to support live reload, e.g. http://localhost:5173/" "URL to load in development to support live reload, e.g. http://localhost:5173/"
), ),
window: v.optional(v.nullable(WindowConfig)) window: v.optional(v.nullable(WindowConfig)),
type: v.optional(CmdType, CmdTypeEnum.UiIframe)
}) })
export type CustomUiCmd = v.InferOutput<typeof CustomUiCmd> export type CustomUiCmd = v.InferOutput<typeof CustomUiCmd>
export const TemplateUiCmd = v.object({ export const TemplateUiCmd = v.object({
...BaseCmd.entries, ...BaseCmd.entries,
type: v.optional(CmdType, CmdType.enum.UiWorker), type: v.optional(CmdType, CmdTypeEnum.UiWorker),
window: v.optional(v.nullable(WindowConfig)) window: v.optional(v.nullable(WindowConfig))
}) })
export const HeadlessCmd = v.object({ export const HeadlessCmd = v.object({
...BaseCmd.entries, ...BaseCmd.entries,
type: v.optional(CmdType, CmdType.enum.HeadlessWorker) type: v.optional(CmdType, CmdTypeEnum.HeadlessWorker)
}) })
export type HeadlessCmd = v.InferOutput<typeof HeadlessCmd> export type HeadlessCmd = v.InferOutput<typeof HeadlessCmd>
export type TemplateUiCmd = v.InferOutput<typeof TemplateUiCmd> export type TemplateUiCmd = v.InferOutput<typeof TemplateUiCmd>

View File

@ -2,14 +2,14 @@ import * as v from "valibot"
import { BaseIcon } from "./icon" import { BaseIcon } from "./icon"
import { ExtPackageJson, KunkunExtManifest } from "./manifest" import { ExtPackageJson, KunkunExtManifest } from "./manifest"
export enum ExtPublishSourceTypeEnum { export const ExtPublishSourceTypeEnum = {
jsr = "jsr", jsr: "jsr",
npm = "npm" npm: "npm"
} }
export const ExtPublishMetadata = v.object({ export const ExtPublishMetadata = v.object({
source: v.optional(v.string("Source of the extension (e.g. url to package)")), source: v.optional(v.string("Source of the extension (e.g. url to package)")),
sourceType: v.optional(v.enum(ExtPublishSourceTypeEnum)), sourceType: v.optional(v.picklist(Object.values(ExtPublishSourceTypeEnum))),
rekorLogIndex: v.optional(v.string("Rekor log index of the extension")), rekorLogIndex: v.optional(v.string("Rekor log index of the extension")),
git: v.optional( git: v.optional(
v.object({ v.object({
@ -44,13 +44,13 @@ export const ExtensionStoreListItem = v.object({
export type ExtensionStoreListItem = v.InferOutput<typeof ExtensionStoreListItem> export type ExtensionStoreListItem = v.InferOutput<typeof ExtensionStoreListItem>
export enum PublishStateEnum { export const PublishStateEnum = {
public = "public", public: "public",
pending = "pending", pending: "pending",
under_review = "under_review", under_review: "under_review",
private = "private" private: "private"
} }
export const ExtensionPublishState = v.enum(PublishStateEnum) export const ExtensionPublishState = v.picklist(Object.values(PublishStateEnum))
export const ExtPublish = v.object({ export const ExtPublish = v.object({
id: v.number(), id: v.number(),
@ -76,7 +76,7 @@ export type ExtPublish = v.InferOutput<typeof ExtPublish>
export const DBExtension = v.object({ export const DBExtension = v.object({
api_version: v.string(), api_version: v.string(),
author_id: v.nullable(v.string()), author_id: v.string(),
created_at: v.string(), created_at: v.string(),
downloads: v.number(), downloads: v.number(),
icon: BaseIcon, icon: BaseIcon,

View File

@ -11,14 +11,15 @@
"./install": "./src/install.ts" "./install": "./src/install.ts"
}, },
"devDependencies": { "devDependencies": {
"@types/bun": "latest" "@types/bun": "latest",
"@types/semver": "^7.5.8"
}, },
"dependencies": { "dependencies": {
"@kksh/api": "workspace:*", "@kksh/api": "workspace:*",
"@std/semver": "npm:@jsr/std__semver@^1.0.3", "@std/semver": "npm:@jsr/std__semver@^1.0.4",
"@tauri-apps/plugin-upload": "^2.2.1", "@tauri-apps/plugin-upload": "^2.2.1",
"semver": "^7.7.1", "semver": "^7.7.1",
"uuid": "^11.0.3" "uuid": "^11.1.0"
}, },
"peerDependencies": { "peerDependencies": {
"typescript": "^5.0.0" "typescript": "^5.0.0"

View File

@ -1,4 +1,5 @@
import type { WindowConfig } from "@kksh/api/models" import type { TitleBarStyle, WindowConfig } from "@kksh/api/models"
import { TitleBarStyleEnum } from "@kksh/api/models"
import { WebviewWindow } from "@tauri-apps/api/webviewWindow" import { WebviewWindow } from "@tauri-apps/api/webviewWindow"
export function launchNewExtWindow(windowLabel: string, url: string, windowConfig?: WindowConfig) { export function launchNewExtWindow(windowLabel: string, url: string, windowConfig?: WindowConfig) {
@ -26,7 +27,8 @@ export function launchNewExtWindow(windowLabel: string, url: string, windowConfi
skipTaskbar: windowConfig?.skipTaskbar ?? undefined, skipTaskbar: windowConfig?.skipTaskbar ?? undefined,
shadow: windowConfig?.shadow ?? undefined, shadow: windowConfig?.shadow ?? undefined,
// theme: windowConfig?.theme ?? undefined, // theme: windowConfig?.theme ?? undefined,
titleBarStyle: windowConfig?.titleBarStyle ?? undefined, titleBarStyle:
(windowConfig?.titleBarStyle as keyof typeof TitleBarStyleEnum | undefined) ?? undefined,
hiddenTitle: windowConfig?.hiddenTitle ?? undefined, hiddenTitle: windowConfig?.hiddenTitle ?? undefined,
tabbingIdentifier: windowConfig?.tabbingIdentifier ?? undefined, tabbingIdentifier: windowConfig?.tabbingIdentifier ?? undefined,
maximizable: windowConfig?.maximizable ?? undefined, maximizable: windowConfig?.maximizable ?? undefined,

View File

@ -1,8 +1,8 @@
<script lang="ts"> <script lang="ts">
import { IconEnum, OSPlatformEnum } from "@kksh/api/models" import { IconEnum, OSPlatform, OSPlatformEnum } from "@kksh/api/models"
import { IconMultiplexer } from "@kksh/ui" import { IconMultiplexer } from "@kksh/ui"
const { platforms }: { platforms: OSPlatformEnum[] } = $props() const { platforms }: { platforms: OSPlatform[] } = $props()
</script> </script>
<div class="flex gap-2"> <div class="flex gap-2">

View File

@ -1,20 +1,20 @@
<script lang="ts"> <script lang="ts">
import { IconEnum, type KunkunExtManifest } from "@kksh/api/models" import { IconEnum, PermissionUnion, type KunkunExtManifest } from "@kksh/api/models"
import { permissionDescriptions } from "@kksh/api/permissions" import { permissionDescriptions } from "@kksh/api/permissions"
import { HoverCard, ScrollArea } from "@kksh/svelte5" import { HoverCard, ScrollArea } from "@kksh/svelte5"
import { IconMultiplexer, Shiki } from "@kksh/ui" import { IconMultiplexer, Shiki } from "@kksh/ui"
const { const {
manifest, permissions,
class: className class: className
}: { }: {
manifest: KunkunExtManifest permissions?: PermissionUnion[]
class?: string class?: string
} = $props() } = $props()
</script> </script>
<ul class={className}> <ul class={className}>
{#each manifest?.permissions || [] as perm} {#each permissions || [] as perm}
<li class="flex h-8 items-center gap-2"> <li class="flex h-8 items-center gap-2">
<span class="font-mono text-sm">{typeof perm === "string" ? perm : perm.permission}</span> <span class="font-mono text-sm">{typeof perm === "string" ? perm : perm.permission}</span>
<HoverCard.Root> <HoverCard.Root>

View File

@ -42,6 +42,7 @@
imageDialogOpen = $bindable(false) imageDialogOpen = $bindable(false)
}: { }: {
extPublish: ExtPublish extPublish: ExtPublish
// extPublish: GetExtensionsLatestPublishByIdentifierResponse
ext: { ext: {
author_id: string author_id: string
downloads: number downloads: number
@ -256,7 +257,7 @@
<Separator class="my-3" /> <Separator class="my-3" />
<h2 class="text-lg font-bold">Security and Privacy</h2> <h2 class="text-lg font-bold">Security and Privacy</h2>
<PermissionInspector {manifest} /> <PermissionInspector permissions={manifest.permissions} />
<Separator class="my-3" /> <Separator class="my-3" />
<h2 class="text-lg font-bold">Description</h2> <h2 class="text-lg font-bold">Description</h2>
@ -278,7 +279,7 @@
<span class="text-dm">{cmd.name}</span> <span class="text-dm">{cmd.name}</span>
<h2 class="text-xs">{cmd.description}</h2> <h2 class="text-xs">{cmd.description}</h2>
</div> </div>
<PlatformsIcons platforms={cmd.platforms} /> <PlatformsIcons platforms={cmd.platforms ?? []} />
</div> </div>
<Separator class="my-3" /> <Separator class="my-3" />
</li> </li>

86
pnpm-lock.yaml generated
View File

@ -11,12 +11,15 @@ importers:
'@changesets/cli': '@changesets/cli':
specifier: ^2.28.1 specifier: ^2.28.1
version: 2.28.1 version: 2.28.1
'@hey-api/client-fetch':
specifier: ^0.8.3
version: 0.8.3
'@iconify/svelte': '@iconify/svelte':
specifier: ^4.2.0 specifier: ^4.2.0
version: 4.2.0(svelte@5.20.5) version: 4.2.0(svelte@5.20.5)
'@kksh/sdk': '@kksh/sdk':
specifier: ^0.0.1 specifier: ^0.0.3
version: 0.0.1(typescript@5.7.3) version: 0.0.3(@hey-api/client-fetch@0.8.3)(typescript@5.7.3)
'@supabase/supabase-js': '@supabase/supabase-js':
specifier: ^2.49.1 specifier: ^2.49.1
version: 2.49.1 version: 2.49.1
@ -212,9 +215,6 @@ importers:
'@kksh/extension': '@kksh/extension':
specifier: workspace:* specifier: workspace:*
version: link:../../packages/extension version: link:../../packages/extension
'@kksh/sdk':
specifier: ^0.0.1
version: 0.0.1(typescript@5.6.3)
'@kksh/svelte5': '@kksh/svelte5':
specifier: ^0.1.15 specifier: ^0.1.15
version: 0.1.15(lucide-svelte@0.474.0(svelte@5.20.5))(svelte-sonner@0.3.28(svelte@5.20.5))(svelte@5.20.5)(sveltekit-superforms@2.23.1(@sveltejs/kit@2.17.3(@sveltejs/vite-plugin-svelte@5.0.3(svelte@5.20.5)(vite@6.2.0(@types/node@22.13.1)(jiti@2.4.0)(terser@5.36.0)(yaml@2.6.1)))(svelte@5.20.5)(vite@6.2.0(@types/node@22.13.1)(jiti@2.4.0)(terser@5.36.0)(yaml@2.6.1)))(@types/json-schema@7.0.15)(svelte@5.20.5)(typescript@5.6.3))(typescript@5.6.3) version: 0.1.15(lucide-svelte@0.474.0(svelte@5.20.5))(svelte-sonner@0.3.28(svelte@5.20.5))(svelte@5.20.5)(sveltekit-superforms@2.23.1(@sveltejs/kit@2.17.3(@sveltejs/vite-plugin-svelte@5.0.3(svelte@5.20.5)(vite@6.2.0(@types/node@22.13.1)(jiti@2.4.0)(terser@5.36.0)(yaml@2.6.1)))(svelte@5.20.5)(vite@6.2.0(@types/node@22.13.1)(jiti@2.4.0)(terser@5.36.0)(yaml@2.6.1)))(@types/json-schema@7.0.15)(svelte@5.20.5)(typescript@5.6.3))(typescript@5.6.3)
@ -341,7 +341,7 @@ importers:
version: 8.25.0(eslint@9.21.0(jiti@2.4.0))(typescript@5.6.3) version: 8.25.0(eslint@9.21.0(jiti@2.4.0))(typescript@5.6.3)
autoprefixer: autoprefixer:
specifier: ^10.4.20 specifier: ^10.4.20
version: 10.4.20(postcss@8.5.3) version: 10.4.20(postcss@8.4.49)
bits-ui: bits-ui:
specifier: 1.0.0-next.86 specifier: 1.0.0-next.86
version: 1.0.0-next.86(svelte@5.20.5) version: 1.0.0-next.86(svelte@5.20.5)
@ -546,7 +546,7 @@ importers:
specifier: workspace:* specifier: workspace:*
version: link:../api version: link:../api
'@std/semver': '@std/semver':
specifier: npm:@jsr/std__semver@^1.0.3 specifier: npm:@jsr/std__semver@^1.0.4
version: '@jsr/std__semver@1.0.3' version: '@jsr/std__semver@1.0.3'
'@tauri-apps/plugin-upload': '@tauri-apps/plugin-upload':
specifier: ^2.2.1 specifier: ^2.2.1
@ -558,12 +558,15 @@ importers:
specifier: ^5.0.0 specifier: ^5.0.0
version: 5.5.4 version: 5.5.4
uuid: uuid:
specifier: ^11.0.3 specifier: ^11.1.0
version: 11.0.3 version: 11.1.0
devDependencies: devDependencies:
'@types/bun': '@types/bun':
specifier: latest specifier: latest
version: 1.2.6 version: 1.2.6
'@types/semver':
specifier: ^7.5.8
version: 7.5.8
packages/extensions/demo-worker-template-ext: packages/extensions/demo-worker-template-ext:
dependencies: dependencies:
@ -775,25 +778,6 @@ importers:
specifier: 1.0.0 specifier: 1.0.0
version: 1.0.0(valibot@1.0.0(typescript@5.7.3)) version: 1.0.0(valibot@1.0.0(typescript@5.7.3))
packages/supabase:
dependencies:
'@kksh/api':
specifier: workspace:*
version: link:../api
'@supabase/ssr':
specifier: ^0.5.2
version: 0.5.2(@supabase/supabase-js@2.48.0)
'@supabase/supabase-js':
specifier: ^2.48.0
version: 2.48.0
typescript:
specifier: ^5.0.0
version: 5.5.4
devDependencies:
'@types/bun':
specifier: latest
version: 1.2.6
packages/svelte-animation: packages/svelte-animation:
dependencies: dependencies:
typescript: typescript:
@ -1432,7 +1416,7 @@ importers:
specifier: ^2.2.0 specifier: ^2.2.0
version: 2.2.0 version: 2.2.0
valibot: valibot:
specifier: ^1.0.0 specifier: ^1.0.0-beta.10
version: 1.0.0(typescript@5.7.2) version: 1.0.0(typescript@5.7.2)
devDependencies: devDependencies:
'@rollup/plugin-typescript': '@rollup/plugin-typescript':
@ -2650,6 +2634,9 @@ packages:
'@hey-api/client-fetch@0.6.0': '@hey-api/client-fetch@0.6.0':
resolution: {integrity: sha512-FlhFsVeH8RxJe/nq8xUzxNbiOpe+GadxlD2pfvDyOyLdCTU4o/LRv46ZVWstaW7DgF4nxhI328chy3+AulwVXw==} resolution: {integrity: sha512-FlhFsVeH8RxJe/nq8xUzxNbiOpe+GadxlD2pfvDyOyLdCTU4o/LRv46ZVWstaW7DgF4nxhI328chy3+AulwVXw==}
'@hey-api/client-fetch@0.8.3':
resolution: {integrity: sha512-EBVa8wwUMyBSeQ32PtCz6u5bFQZIMAufvwCT1ZtpjqT3caJQEza4NokbGU50q1ZVrMsM5Ot6GuDNJOF3TMo26Q==}
'@hookform/resolvers@3.9.1': '@hookform/resolvers@3.9.1':
resolution: {integrity: sha512-ud2HqmGBM0P0IABqoskKWI6PEf6ZDDBZkFqe2Vnl+mTHCEHzr3ISjjZyCwTjC/qpL25JC9aIDkloQejvMeq0ug==} resolution: {integrity: sha512-ud2HqmGBM0P0IABqoskKWI6PEf6ZDDBZkFqe2Vnl+mTHCEHzr3ISjjZyCwTjC/qpL25JC9aIDkloQejvMeq0ug==}
peerDependencies: peerDependencies:
@ -3009,9 +2996,10 @@ packages:
react: ^18.2.0 react: ^18.2.0
react-dom: ^18.2.0 react-dom: ^18.2.0
'@kksh/sdk@0.0.1': '@kksh/sdk@0.0.3':
resolution: {integrity: sha512-G+ZnrPOBmu4IwpcWsgxgK1C6bZrldzEEK1jxM0YgmI8ITLUkDAMnXM1GoQKoRUvcMQPUIQcun2ApLIQPK7uWpA==} resolution: {integrity: sha512-he5/VSiIfEuXQlGWGxoIurrq/wbddbvZiHbKIGAFTS1DljCHjnAjEajueCkz9M3sbn+WGylS8VSVAFSCWdCfPg==}
peerDependencies: peerDependencies:
'@hey-api/client-fetch': ^0.8.3
typescript: ^5 typescript: ^5
'@kksh/svelte5@0.1.15': '@kksh/svelte5@0.1.15':
@ -4977,11 +4965,6 @@ packages:
'@supabase/realtime-js@2.11.2': '@supabase/realtime-js@2.11.2':
resolution: {integrity: sha512-u/XeuL2Y0QEhXSoIPZZwR6wMXgB+RQbJzG9VErA3VghVt7uRfSVsjeqd7m5GhX3JR6dM/WRmLbVR8URpDWG4+w==} resolution: {integrity: sha512-u/XeuL2Y0QEhXSoIPZZwR6wMXgB+RQbJzG9VErA3VghVt7uRfSVsjeqd7m5GhX3JR6dM/WRmLbVR8URpDWG4+w==}
'@supabase/ssr@0.5.2':
resolution: {integrity: sha512-n3plRhr2Bs8Xun1o4S3k1CDv17iH5QY9YcoEvXX3bxV1/5XSasA0mNXYycFmADIdtdE6BG9MRjP5CGIs8qxC8A==}
peerDependencies:
'@supabase/supabase-js': ^2.43.4
'@supabase/storage-js@2.7.1': '@supabase/storage-js@2.7.1':
resolution: {integrity: sha512-asYHcyDR1fKqrMpytAS1zjyEfvxuOIp1CIXX7ji4lHHcJKqyk+sLl/Vxgm4sN6u8zvuUtae9e4kDxQP2qrwWBA==} resolution: {integrity: sha512-asYHcyDR1fKqrMpytAS1zjyEfvxuOIp1CIXX7ji4lHHcJKqyk+sLl/Vxgm4sN6u8zvuUtae9e4kDxQP2qrwWBA==}
@ -6736,10 +6719,6 @@ packages:
resolution: {integrity: sha512-U71cyTamuh1CRNCfpGY6to28lxvNwPG4Guz/EVjgf3Jmzv0vlDp1atT9eS5dDjMYHucpHbWns6Lwf3BKz6svdw==} resolution: {integrity: sha512-U71cyTamuh1CRNCfpGY6to28lxvNwPG4Guz/EVjgf3Jmzv0vlDp1atT9eS5dDjMYHucpHbWns6Lwf3BKz6svdw==}
engines: {node: '>= 0.6'} engines: {node: '>= 0.6'}
cookie@0.7.2:
resolution: {integrity: sha512-yki5XnKuf750l50uGTllt6kKILY4nQ1eNIQatoXEByZ5dWgnKqbnqmTrBE5B4N7lrMJKQ2ytWMiTO2o0v6Ew/w==}
engines: {node: '>= 0.6'}
cookies@0.9.1: cookies@0.9.1:
resolution: {integrity: sha512-TG2hpqe4ELx54QER/S3HQ9SRVnQnGBtKUz5bLQWtYAQ+o6GpgMs6sYUvaiJjVxb+UXwhRhAEP3m7LbsIZ77Hmw==} resolution: {integrity: sha512-TG2hpqe4ELx54QER/S3HQ9SRVnQnGBtKUz5bLQWtYAQ+o6GpgMs6sYUvaiJjVxb+UXwhRhAEP3m7LbsIZ77Hmw==}
engines: {node: '>= 0.8'} engines: {node: '>= 0.8'}
@ -13961,6 +13940,8 @@ snapshots:
'@hey-api/client-fetch@0.6.0': {} '@hey-api/client-fetch@0.6.0': {}
'@hey-api/client-fetch@0.8.3': {}
'@hookform/resolvers@3.9.1(react-hook-form@7.53.2(react@18.3.1))': '@hookform/resolvers@3.9.1(react-hook-form@7.53.2(react@18.3.1))':
dependencies: dependencies:
react-hook-form: 7.53.2(react@18.3.1) react-hook-form: 7.53.2(react@18.3.1)
@ -14628,12 +14609,9 @@ snapshots:
- '@types/react-dom' - '@types/react-dom'
- tailwindcss - tailwindcss
'@kksh/sdk@0.0.1(typescript@5.6.3)': '@kksh/sdk@0.0.3(@hey-api/client-fetch@0.8.3)(typescript@5.7.3)':
dependencies:
typescript: 5.6.3
'@kksh/sdk@0.0.1(typescript@5.7.3)':
dependencies: dependencies:
'@hey-api/client-fetch': 0.8.3
typescript: 5.7.3 typescript: 5.7.3
'@kksh/svelte5@0.1.15(lucide-svelte@0.469.0(svelte@5.16.6))(svelte-sonner@0.3.28(svelte@5.16.6))(svelte@5.16.6)(sveltekit-superforms@2.23.1(@sveltejs/kit@2.15.2(@sveltejs/vite-plugin-svelte@5.0.3(svelte@5.16.6)(vite@6.0.7(@types/node@22.13.1)(jiti@2.4.0)(terser@5.36.0)(yaml@2.6.1)))(svelte@5.16.6)(vite@6.0.7(@types/node@22.13.1)(jiti@2.4.0)(terser@5.36.0)(yaml@2.6.1)))(@types/json-schema@7.0.15)(svelte@5.16.6)(typescript@5.7.2))(typescript@5.7.2)': '@kksh/svelte5@0.1.15(lucide-svelte@0.469.0(svelte@5.16.6))(svelte-sonner@0.3.28(svelte@5.16.6))(svelte@5.16.6)(sveltekit-superforms@2.23.1(@sveltejs/kit@2.15.2(@sveltejs/vite-plugin-svelte@5.0.3(svelte@5.16.6)(vite@6.0.7(@types/node@22.13.1)(jiti@2.4.0)(terser@5.36.0)(yaml@2.6.1)))(svelte@5.16.6)(vite@6.0.7(@types/node@22.13.1)(jiti@2.4.0)(terser@5.36.0)(yaml@2.6.1)))(@types/json-schema@7.0.15)(svelte@5.16.6)(typescript@5.7.2))(typescript@5.7.2)':
@ -17035,12 +17013,6 @@ snapshots:
- bufferutil - bufferutil
- utf-8-validate - utf-8-validate
'@supabase/ssr@0.5.2(@supabase/supabase-js@2.48.0)':
dependencies:
'@supabase/supabase-js': 2.48.0
'@types/cookie': 0.6.0
cookie: 0.7.2
'@supabase/storage-js@2.7.1': '@supabase/storage-js@2.7.1':
dependencies: dependencies:
'@supabase/node-fetch': 2.6.15 '@supabase/node-fetch': 2.6.15
@ -18871,16 +18843,6 @@ snapshots:
postcss: 8.5.1 postcss: 8.5.1
postcss-value-parser: 4.2.0 postcss-value-parser: 4.2.0
autoprefixer@10.4.20(postcss@8.5.3):
dependencies:
browserslist: 4.24.2
caniuse-lite: 1.0.30001676
fraction.js: 4.3.7
normalize-range: 0.1.2
picocolors: 1.1.1
postcss: 8.5.3
postcss-value-parser: 4.2.0
available-typed-arrays@1.0.7: available-typed-arrays@1.0.7:
dependencies: dependencies:
possible-typed-array-names: 1.0.0 possible-typed-array-names: 1.0.0
@ -19319,8 +19281,6 @@ snapshots:
cookie@0.6.0: {} cookie@0.6.0: {}
cookie@0.7.2: {}
cookies@0.9.1: cookies@0.9.1:
dependencies: dependencies:
depd: 2.0.0 depd: 2.0.0