Compare commits

..

No commits in common. "5d5cbcdeb744c13183388c504d23ed8bc4d1b0f9" and "20449b846b73bf8c1a1a088cb94c510c35c6b623" have entirely different histories.

65 changed files with 1216 additions and 1121 deletions

View File

@ -11,9 +11,11 @@
"jarvis", "jarvis",
"form-view", "form-view",
"@kksh/desktop", "@kksh/desktop",
"@kksh/supabase",
"@kksh/utils", "@kksh/utils",
"@kksh/extension", "@kksh/extension",
"@kksh/schema", "@kksh/schema",
"@kksh/supabase",
"@kksh/ui" "@kksh/ui"
] ]
} }

View File

@ -31,7 +31,7 @@
"debug": "^4.4.0", "debug": "^4.4.0",
"fs-extra": "^11.2.0", "fs-extra": "^11.2.0",
"inquirer": "^10.1.2", "inquirer": "^10.1.2",
"valibot": "^1.0.0" "valibot": "^1.0.0-rc.4"
}, },
"files": [ "files": [
"dist" "dist"

View File

@ -27,7 +27,7 @@
"commander": "^12.1.0", "commander": "^12.1.0",
"fs-extra": "^11.2.0", "fs-extra": "^11.2.0",
"handlebars": "^4.7.8", "handlebars": "^4.7.8",
"valibot": "^1.0.0" "valibot": "^1.0.0-rc.4"
}, },
"files": [ "files": [
"dist" "dist"

View File

@ -1,13 +0,0 @@
import { IconType } from "@kksh/api/models"
import { getExtensionsLatestPublishByIdentifier } from "@kksh/sdk"
const latestPublish = await getExtensionsLatestPublishByIdentifier({
path: {
identifier: "RAG1"
}
})
console.log(latestPublish)
// latestPublish
// console.log(typeof IconEnum.Iconify)
console.log(IconType.options)

View File

@ -19,6 +19,7 @@
"@inlang/paraglide-sveltekit": "0.16.0", "@inlang/paraglide-sveltekit": "0.16.0",
"@kksh/drizzle": "workspace:*", "@kksh/drizzle": "workspace:*",
"@kksh/extension": "workspace:*", "@kksh/extension": "workspace:*",
"@kksh/supabase": "workspace:*",
"@kksh/svelte5": "^0.1.15", "@kksh/svelte5": "^0.1.15",
"@kksh/ui": "workspace:*", "@kksh/ui": "workspace:*",
"@kksh/utils": "workspace:*", "@kksh/utils": "workspace:*",
@ -39,7 +40,7 @@
"lz-string": "^1.5.0", "lz-string": "^1.5.0",
"pretty-bytes": "^6.1.1", "pretty-bytes": "^6.1.1",
"semver": "^7.7.1", "semver": "^7.7.1",
"svelte-inspect-value": "^0.5.0", "svelte-inspect-value": "^0.3.0",
"svelte-sonner": "^0.3.28", "svelte-sonner": "^0.3.28",
"sveltekit-superforms": "^2.23.1", "sveltekit-superforms": "^2.23.1",
"tauri-plugin-clipboard-api": "^2.1.11", "tauri-plugin-clipboard-api": "^2.1.11",

View File

@ -242,23 +242,6 @@ export const rawBuiltinCmds: BuiltinCmd[] = [
}, },
keywords: ["extension", "troubleshooter"] keywords: ["extension", "troubleshooter"]
}, },
{
name: "ORM Troubleshooter",
icon: {
type: IconEnum.Iconify,
value: "material-symbols:database"
},
description: "",
flags: {
developer: true,
dev: true
},
function: async () => {
appState.clearSearchTerm()
goto(i18n.resolveRoute("/app/troubleshooters/orm"))
},
keywords: ["extension", "troubleshooter", "database", "orm"]
},
{ {
name: "Create Quicklink", name: "Create Quicklink",
icon: { icon: {

View File

@ -12,7 +12,7 @@ import { onQuickLinkSelect } from "./quick-links"
const onExtCmdSelect: OnExtCmdSelect = ( const onExtCmdSelect: OnExtCmdSelect = (
ext: ExtPackageJsonExtra, ext: ExtPackageJsonExtra,
cmd: CustomUiCmd | TemplateUiCmd | HeadlessCmd, cmd: CustomUiCmd | TemplateUiCmd,
{ 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 { AppConfigState } from "@kksh/types" import type { AppConfig } from "@/types/appConfig"
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<AppConfigState> { export function getAppConfigContext(): Writable<AppConfig> {
return getContext(APP_CONFIG_CONTEXT_KEY) return getContext(APP_CONFIG_CONTEXT_KEY)
} }
export function setAppConfigContext(appConfig: Writable<AppConfigState>) { export function setAppConfigContext(appConfig: Writable<AppConfig>) {
setContext(APP_CONFIG_CONTEXT_KEY, appConfig) setContext(APP_CONFIG_CONTEXT_KEY, appConfig)
} }

View File

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

View File

@ -1,355 +0,0 @@
import * as relations from "@kksh/drizzle/relations"
import * as schema from "@kksh/drizzle/schema"
import {
CmdType,
Ext,
ExtCmd,
ExtData,
SearchMode,
SearchModeEnum,
SQLSortOrder,
SQLSortOrderEnum
} from "@kunkunapi/src/models"
import * as orm from "drizzle-orm"
import type { SelectedFields } from "drizzle-orm/sqlite-core"
import * as v from "valibot"
import { db } from "./database"
/* -------------------------------------------------------------------------- */
/* Built-in Extensions */
/* -------------------------------------------------------------------------- */
/* -------------------------------------------------------------------------- */
/* Extension CRUD */
/* -------------------------------------------------------------------------- */
export async function getUniqueExtensionByIdentifier(identifier: string): Promise<Ext | undefined> {
const ext = await db
.select()
.from(schema.extensions)
.where(orm.eq(schema.extensions.identifier, identifier))
.get()
return v.parse(v.optional(Ext), ext)
}
/**
* Use this function when you expect the extension to exist. Such as builtin extensions.
* @param identifier
* @returns
*/
export function getExtensionByIdentifierExpectExists(identifier: string): Promise<Ext> {
return getUniqueExtensionByIdentifier(identifier).then((ext) => {
if (!ext) {
throw new Error(`Unexpexted Error: Extension ${identifier} not found`)
}
return ext
})
}
export async function getAllExtensions(): Promise<Ext[]> {
const exts = await db.select().from(schema.extensions).all()
return v.parse(v.array(Ext), exts)
}
/**
* There can be duplicate extensions with the same identifier. Store and Dev extensions can have the same identifier.
* But install path must be unique.
* @param path
*/
export async function getUniqueExtensionByPath(path: string) {
const ext = await db
.select()
.from(schema.extensions)
.where(orm.eq(schema.extensions.path, path))
.get()
return v.parse(Ext, ext)
}
export function getAllExtensionsByIdentifier(identifier: string): Promise<Ext[]> {
return db
.select()
.from(schema.extensions)
.where(orm.eq(schema.extensions.identifier, identifier))
.all()
.then((exts) => v.parse(v.array(Ext), exts))
}
export function deleteExtensionByPath(path: string): Promise<void> {
return db
.delete(schema.extensions)
.where(orm.eq(schema.extensions.path, path))
.run()
.then(() => undefined)
}
export function deleteExtensionByExtId(extId: number): Promise<void> {
return db
.delete(schema.extensions)
.where(orm.eq(schema.extensions.extId, extId))
.run()
.then(() => undefined)
}
/* -------------------------------------------------------------------------- */
/* Extension Command CRUD */
/* -------------------------------------------------------------------------- */
// export async function getExtensionWithCmdsByIdentifier(identifier: string): Promise<ExtWithCmds> {
// const ext = await db
// .select({
// ...schema.extensions,
// commands: relations.commandsRelations
// })
// .from(schema.extensions)
// .leftJoin(schema.commands, orm.eq(schema.extensions.extId, schema.commands.extId))
// .where(orm.eq(schema.extensions.identifier, identifier))
// .get()
// // return v.parse(v.nullable(ExtWithCmds), ext);
// }
export async function getCmdById(cmdId: number): Promise<ExtCmd> {
const cmd = await db
.select()
.from(schema.commands)
.where(orm.eq(schema.commands.cmdId, cmdId))
.get()
return v.parse(ExtCmd, cmd)
}
export async function getAllCmds(): Promise<ExtCmd[]> {
const cmds = await db.select().from(schema.commands).all()
return v.parse(v.array(ExtCmd), cmds)
}
export function getCommandsByExtId(extId: number) {
return db
.select()
.from(schema.commands)
.where(orm.eq(schema.commands.extId, extId))
.all()
.then((cmds) => v.parse(v.array(ExtCmd), cmds))
}
export function deleteCmdById(cmdId: number) {
return db
.delete(schema.commands)
.where(orm.eq(schema.commands.cmdId, cmdId))
.run()
.then(() => undefined)
}
export function updateCmdByID(data: {
cmdId: number
name: string
cmdType: CmdType
data: string
alias?: string
hotkey?: string
enabled: boolean
}) {
return db
.update(schema.commands)
.set({
name: data.name,
type: data.cmdType,
data: data.data,
alias: data.alias, // optional
hotkey: data.hotkey, // optional
enabled: data.enabled
// in drizzle schema, use integer({ mode: 'boolean' }) for boolean sqlite
// enabled: data.enabled ? String(data.enabled) : undefined
})
.where(orm.eq(schema.commands.cmdId, data.cmdId))
.run()
.then(() => undefined)
}
/* -------------------------------------------------------------------------- */
/* Extension Data CRUD */
/* -------------------------------------------------------------------------- */
export const ExtDataField = v.union([v.literal("data"), v.literal("search_text")])
export type ExtDataField = v.InferOutput<typeof ExtDataField>
function convertRawExtDataToExtData(rawData?: {
createdAt: string
updatedAt: string
data: null | string
searchText?: null | string
dataId: number
extId: number
dataType: string
}): ExtData | undefined {
if (!rawData) {
return rawData
}
const parsedRes = v.safeParse(ExtData, {
...rawData,
createdAt: new Date(rawData.createdAt),
updatedAt: new Date(rawData.updatedAt),
data: rawData.data ?? undefined,
searchText: rawData.searchText ?? undefined
})
if (parsedRes.success) {
return parsedRes.output
} else {
console.error("Extension Data Parse Failure", parsedRes.issues)
throw new Error("Fail to parse extension data")
}
}
export function createExtensionData(data: {
extId: number
dataType: string
data: string
searchText?: string
}) {
return db.insert(schema.extensionData).values(data).run()
}
export function getExtensionDataById(dataId: number, fields?: ExtDataField[]) {
const _fields = fields ?? []
const selectQuery: SelectedFields = {
dataId: schema.extensionData.dataId,
extId: schema.extensionData.extId,
dataType: schema.extensionData.dataType,
metadata: schema.extensionData.metadata,
createdAt: schema.extensionData.createdAt,
updatedAt: schema.extensionData.updatedAt
// data: schema.extensionData.data,
// searchText: schema.extensionData.searchText
}
if (_fields.includes("data")) {
selectQuery["data"] = schema.extensionData.data
}
if (_fields.includes("search_text")) {
selectQuery["searchText"] = schema.extensionData.searchText
}
return db
.select(selectQuery)
.from(schema.extensionData)
.where(orm.eq(schema.extensionData.dataId, dataId))
.get()
.then((rawData) => {
console.log("Raw Data", rawData)
// @ts-expect-error - rawData is unknown, but will be safe parsed with valibot
return convertRawExtDataToExtData(rawData)
})
}
export async function searchExtensionData(searchParams: {
extId: number
searchMode: SearchMode
dataId?: number
dataType?: string
searchText?: string
afterCreatedAt?: string
beforeCreatedAt?: string
limit?: number
offset?: number
orderByCreatedAt?: SQLSortOrder
orderByUpdatedAt?: SQLSortOrder
fields?: ExtDataField[]
}): Promise<ExtData[]> {
const fields = v.parse(v.optional(v.array(ExtDataField), []), searchParams.fields)
const _fields = fields ?? []
// Build the select query based on fields
const selectQuery: SelectedFields = {
dataId: schema.extensionData.dataId,
extId: schema.extensionData.extId,
dataType: schema.extensionData.dataType,
createdAt: schema.extensionData.createdAt,
updatedAt: schema.extensionData.updatedAt
}
if (_fields.includes("data")) {
selectQuery["data"] = schema.extensionData.data
}
if (_fields.includes("search_text")) {
selectQuery["searchText"] = schema.extensionData.searchText
}
// Build the query
let baseQuery = db.select(selectQuery).from(schema.extensionData)
// Add FTS join if needed
if (searchParams.searchMode === SearchModeEnum.FTS && searchParams.searchText) {
// @ts-expect-error - The join type is correct but TypeScript can't infer it properly
baseQuery = baseQuery.innerJoin(
schema.extensionDataFts,
orm.eq(schema.extensionData.dataId, schema.extensionDataFts.dataId)
)
}
// Add conditions
const conditions = [orm.eq(schema.extensionData.extId, searchParams.extId)]
if (searchParams.dataId) {
conditions.push(orm.eq(schema.extensionData.dataId, searchParams.dataId))
}
if (searchParams.dataType) {
conditions.push(orm.eq(schema.extensionData.dataType, searchParams.dataType))
}
if (searchParams.searchText) {
switch (searchParams.searchMode) {
case SearchModeEnum.ExactMatch:
conditions.push(orm.eq(schema.extensionData.searchText, searchParams.searchText))
break
case SearchModeEnum.Like:
conditions.push(orm.like(schema.extensionData.searchText, `%${searchParams.searchText}%`))
break
case SearchModeEnum.FTS:
conditions.push(
orm.sql`${schema.extensionDataFts.searchText} MATCH ${searchParams.searchText}`
)
break
}
}
if (searchParams.afterCreatedAt) {
conditions.push(orm.gt(schema.extensionData.createdAt, searchParams.afterCreatedAt))
}
if (searchParams.beforeCreatedAt) {
conditions.push(orm.lt(schema.extensionData.createdAt, searchParams.beforeCreatedAt))
}
// Build the final query with all conditions and modifiers
const query = baseQuery
.where(orm.and(...conditions))
.orderBy(
searchParams.orderByCreatedAt
? searchParams.orderByCreatedAt === SQLSortOrderEnum.Asc
? orm.asc(schema.extensionData.createdAt)
: orm.desc(schema.extensionData.createdAt)
: searchParams.orderByUpdatedAt
? searchParams.orderByUpdatedAt === SQLSortOrderEnum.Asc
? orm.asc(schema.extensionData.updatedAt)
: orm.desc(schema.extensionData.updatedAt)
: orm.asc(schema.extensionData.createdAt) // Default ordering
)
.limit(searchParams.limit ?? 100) // Default limit
.offset(searchParams.offset ?? 0) // Default offset
// Execute query and convert results
const results = await query.all()
return results
.map((rawData) => {
// @ts-expect-error - rawData is unknown, but will be safe parsed with valibot
return convertRawExtDataToExtData(rawData)
})
.filter((item): item is ExtData => item !== undefined)
}
// export async function getNCommands(n: number):
// export function createExtension(ext: {
// identifier: string
// version: string
// enabled?: boolean
// path?: string
// data?: any
// }) {
// return invoke<void>(generateJarvisPluginCommand("create_extension"), ext)
// }

View File

@ -1,7 +1,6 @@
/* eslint-disable @typescript-eslint/no-explicit-any */ /* eslint-disable @typescript-eslint/no-explicit-any */
import { db as dbCmd } from "@kksh/api/commands"
import * as schema from "@kksh/drizzle/schema" import * as schema from "@kksh/drizzle/schema"
import { error } from "@tauri-apps/plugin-log" import * as dbCmd from "@kunkunapi/src/commands/db"
import { drizzle } from "drizzle-orm/sqlite-proxy" import { drizzle } from "drizzle-orm/sqlite-proxy"
/** /**
@ -16,22 +15,21 @@ export const db = drizzle<typeof schema>(
async (sql, params, method) => { async (sql, params, method) => {
let rows: any = [] let rows: any = []
let results = [] let results = []
console.log({ // console.log({
sql, // sql,
params, // params,
method // method
}) // })
console.log(sql)
// If the query is a SELECT, use the select method // If the query is a SELECT, use the select method
if (isSelectQuery(sql)) { if (isSelectQuery(sql)) {
rows = await dbCmd.select(sql, params).catch((e) => { rows = await dbCmd.select(sql, params).catch((e) => {
error("SQL Error:", e) console.error("SQL Error:", e)
return [] return []
}) })
} else { } else {
// Otherwise, use the execute method // Otherwise, use the execute method
rows = await dbCmd.execute(sql, params).catch((e) => { rows = await dbCmd.execute(sql, params).catch((e) => {
error("SQL Error:", e) console.error("SQL Error:", e)
return [] return []
}) })
return { rows: [] } return { rows: [] }

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"
const fuse = new Fuse<AppInfo>([], { export 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"
const fuse = new Fuse<QuickLink>([], { export const fuse = new Fuse<QuickLink>([], {
includeScore: true, includeScore: true,
threshold: 0.2, threshold: 0.2,
keys: ["name"] keys: ["name"]

View File

@ -1,13 +1,19 @@
import { SupabaseAPI } from "@kksh/supabase/api"
import type { Database } from "@kksh/supabase/types"
import * as sb from "@supabase/supabase-js" import * as sb from "@supabase/supabase-js"
import { SUPABASE_ANON_KEY, SUPABASE_URL } from "./constants" import { SUPABASE_ANON_KEY, SUPABASE_URL } from "./constants"
// export const supabase = createSB(SUPABASE_URL, SUPABASE_ANON_KEY) // export const supabase = createSB(SUPABASE_URL, SUPABASE_ANON_KEY)
export const supabase: sb.SupabaseClient = sb.createClient(SUPABASE_URL, SUPABASE_ANON_KEY, { export const supabase: sb.SupabaseClient<Database> = sb.createClient<Database>(
SUPABASE_URL,
SUPABASE_ANON_KEY,
{
auth: { auth: {
flowType: "pkce" flowType: "pkce"
} }
}) }
)
export const storage = supabase.storage export const storage = supabase.storage
export const supabaseExtensionsStorage = supabase.storage.from("extensions") export const supabaseExtensionsStorage = supabase.storage.from("extensions")
// export const supabaseAPI = new SupabaseAPI(supabase) export const supabaseAPI = new SupabaseAPI(supabase)

View File

@ -1,7 +1,8 @@
import { extensions } from "@/stores" import { extensions } from "@/stores"
import { supabaseAPI } from "@/supabase"
import { isCompatible } from "@kksh/api" import { isCompatible } from "@kksh/api"
import type { ExtPackageJsonExtra } from "@kksh/api/models" import type { ExtPackageJsonExtra } from "@kksh/api/models"
import { getExtensionsLatestPublishByIdentifier } from "@kksh/sdk" import { greaterThan } from "@std/semver"
import { relaunch } from "@tauri-apps/plugin-process" import { relaunch } from "@tauri-apps/plugin-process"
import { check } from "@tauri-apps/plugin-updater" import { check } from "@tauri-apps/plugin-updater"
import { gt } from "semver" import { gt } from "semver"
@ -31,22 +32,11 @@ export async function checkSingleExtensionUpdate(
installedExt: ExtPackageJsonExtra, installedExt: ExtPackageJsonExtra,
autoupgrade: boolean autoupgrade: boolean
) { ) {
const { const { data: sbExt, error } = await supabaseAPI.getLatestExtPublish(
data: sbExt, installedExt.kunkun.identifier
error,
response
} = await getExtensionsLatestPublishByIdentifier({
path: {
identifier: "RAG"
}
})
// const { data: sbExt, error } = await supabaseAPI.getLatestExtPublish(
// installedExt.kunkun.identifier
// )
if (error) {
return toast.error(
`Failed to check update for ${installedExt.kunkun.identifier}: ${error} (${response.status})`
) )
if (error) {
return toast.error(`Failed to check update for ${installedExt.kunkun.identifier}: ${error}`)
} }
if (!sbExt) { if (!sbExt) {
@ -59,7 +49,10 @@ export async function checkSingleExtensionUpdate(
) { ) {
if (autoupgrade) { if (autoupgrade) {
await extensions await extensions
.upgradeStoreExtension(sbExt.identifier, sbExt.tarball_path) .upgradeStoreExtension(
sbExt.identifier,
supabaseAPI.translateExtensionFilePathToUrl(sbExt.tarball_path)
)
.then(() => { .then(() => {
toast.success(`${sbExt.name} upgraded`, { toast.success(`${sbExt.name} upgraded`, {
description: `From ${installedExt.version} to ${sbExt.version}` description: `From ${installedExt.version} to ${sbExt.version}`

View File

@ -5,7 +5,6 @@
import { systemCommands, systemCommandsFiltered } from "@/cmds/system" import { systemCommands, systemCommandsFiltered } from "@/cmds/system"
import AppsCmds from "@/components/main/AppsCmds.svelte" import AppsCmds from "@/components/main/AppsCmds.svelte"
import { i18n } from "@/i18n" import { i18n } from "@/i18n"
import { getUniqueExtensionByIdentifier } from "@/orm/cmds"
import { db } from "@/orm/database" import { db } from "@/orm/database"
import * as m from "@/paraglide/messages" import * as m from "@/paraglide/messages"
import { import {
@ -33,7 +32,6 @@
SystemCmds SystemCmds
} from "@kksh/ui/main" } from "@kksh/ui/main"
import { cn } from "@kksh/ui/utils" import { cn } from "@kksh/ui/utils"
import { Ext } from "@kunkunapi/src/models/extension"
import { getCurrentWebviewWindow } from "@tauri-apps/api/webviewWindow" import { getCurrentWebviewWindow } from "@tauri-apps/api/webviewWindow"
import { getCurrentWindow, Window } from "@tauri-apps/api/window" import { getCurrentWindow, Window } from "@tauri-apps/api/window"
import { platform } from "@tauri-apps/plugin-os" import { platform } from "@tauri-apps/plugin-os"
@ -48,7 +46,6 @@
} from "lucide-svelte" } from "lucide-svelte"
import { onMount } from "svelte" import { onMount } from "svelte"
import { Inspect } from "svelte-inspect-value" import { Inspect } from "svelte-inspect-value"
import * as v from "valibot"
const win = getCurrentWindow() const win = getCurrentWindow()
let inputEle: HTMLInputElement | null = $state(null) let inputEle: HTMLInputElement | null = $state(null)

View File

@ -2,13 +2,14 @@
import { getExtensionsFolder } from "@/constants" import { getExtensionsFolder } from "@/constants"
import { appState, extensions } from "@/stores" import { appState, extensions } from "@/stores"
import { keys } from "@/stores/keys" import { keys } from "@/stores/keys"
import { supabaseAPI } from "@/supabase"
import { goBackOnEscapeClearSearchTerm, goHomeOnEscapeClearSearchTerm } from "@/utils/key"
import { goBack, goHome } from "@/utils/route" import { goBack, goHome } from "@/utils/route"
import { Action as ActionSchema, ExtensionStoreListItem, ExtPublish } from "@kksh/api/models" import { Action as ActionSchema } from "@kksh/api/models"
import { Action } from "@kksh/api/ui" import { Action } from "@kksh/api/ui"
import { import { SBExt } from "@kksh/supabase/models"
getExtensionsLatestPublishByIdentifier, import type { ExtPublishMetadata } from "@kksh/supabase/models"
postExtensionsIncrementDownloads import { type Tables } from "@kksh/supabase/types"
} from "@kksh/sdk"
import { Button, Command } from "@kksh/svelte5" import { Button, Command } from "@kksh/svelte5"
import { Constants } from "@kksh/ui" import { Constants } from "@kksh/ui"
import { ExtListItem } from "@kksh/ui/extension" import { ExtListItem } from "@kksh/ui/extension"
@ -70,57 +71,51 @@
} }
}) })
function onExtItemSelected(ext: ExtensionStoreListItem) { function onExtItemSelected(ext: SBExt) {
goto(`./store/${ext.identifier}`) goto(`./store/${ext.identifier}`)
} }
async function onExtItemUpgrade(ext: ExtensionStoreListItem) { async function onExtItemUpgrade(ext: SBExt) {
const { data, error, response } = await getExtensionsLatestPublishByIdentifier({ const res = await supabaseAPI.getLatestExtPublish(ext.identifier)
path: { if (res.error)
identifier: ext.identifier
}
})
if (error)
return toast.error("Fail to get latest extension", { return toast.error("Fail to get latest extension", {
description: error.error description: res.error.message
}) })
const installExtras = await getInstallExtras(data?.metadata) const tarballUrl = res.data.tarball_path.startsWith("http")
? res.data.tarball_path
: supabaseAPI.translateExtensionFilePathToUrl(res.data.tarball_path)
const installExtras = await getInstallExtras(
res.data as Tables<"ext_publish"> & { metadata: ExtPublishMetadata }
)
return extensions return extensions
.upgradeStoreExtension(ext.identifier, data.tarball_path, installExtras) .upgradeStoreExtension(ext.identifier, tarballUrl, installExtras)
.then((newExt) => { .then((newExt) => {
toast.success(`${ext.name} Upgraded to ${newExt.version}`) toast.success(`${ext.name} Upgraded to ${newExt.version}`)
}) })
} }
async function onExtItemInstall(ext: ExtensionStoreListItem) { async function onExtItemInstall(ext: SBExt) {
const { data, error, response } = await getExtensionsLatestPublishByIdentifier({ const res = await supabaseAPI.getLatestExtPublish(ext.identifier)
path: { if (res.error)
identifier: ext.identifier
}
})
if (error)
return toast.error("Fail to get latest extension", { return toast.error("Fail to get latest extension", {
description: error.error description: res.error.message
}) })
const installExtras = await getInstallExtras(data?.metadata) const tarballUrl = res.data.tarball_path.startsWith("http")
? res.data.tarball_path
: supabaseAPI.translateExtensionFilePathToUrl(res.data.tarball_path)
const installExtras = await getInstallExtras(
res.data as Tables<"ext_publish"> & { metadata: ExtPublishMetadata }
)
const installDir = await getExtensionsFolder() const installDir = await getExtensionsFolder()
return extensions return extensions
.installFromTarballUrl(data.tarball_path, installDir, installExtras) .installFromTarballUrl(tarballUrl, installDir, installExtras)
.then(() => toast.success(`Plugin ${ext.name} Installed`)) .then(() => toast.success(`Plugin ${ext.name} Installed`))
.then(() => .then(() =>
postExtensionsIncrementDownloads({ supabaseAPI.incrementDownloads({
body: {
identifier: ext.identifier, identifier: ext.identifier,
version: ext.version version: ext.version
}
}) })
.then(({ error }) => {
if (error) {
console.error(error)
}
})
.catch(console.error)
) )
} }
@ -164,7 +159,7 @@
}) })
</script> </script>
<svelte:window {onkeydown} /> <svelte:window on:keydown={onkeydown} />
{#snippet leftSlot()} {#snippet leftSlot()}
<Button <Button
variant="outline" variant="outline"

View File

@ -1,39 +1,43 @@
import { appConfig, appState, extensions, installedStoreExts } from "@/stores" import { appConfig, appState, extensions, installedStoreExts } from "@/stores"
import { goHome } from "@/utils/route" import { supabaseAPI } from "@/supabase"
// import { supabaseAPI } from "@/supabase" import type { ExtPackageJsonExtra } from "@kksh/api/models"
import type { ExtensionStoreListItem, ExtPackageJsonExtra } from "@kksh/api/models"
import { isExtPathInDev, isUpgradable } from "@kksh/extension" import { isExtPathInDev, isUpgradable } from "@kksh/extension"
import { getExtensionsStoreList } from "@kksh/sdk" import { SBExt } from "@kksh/supabase/models"
import { toast } from "svelte-sonner" import { sleep } from "@kksh/utils"
import { error } from "@sveltejs/kit"
import { derived, get, type Readable } from "svelte/store" import { derived, get, type Readable } from "svelte/store"
import type { PageLoad } from "./$types" import type { PageLoad } from "./$types"
export const load: PageLoad = (): Promise<{ export const load: PageLoad = (): Promise<{
storeExtList: ExtensionStoreListItem[] storeExtList: SBExt[]
installedStoreExts: Readable<ExtPackageJsonExtra[]> installedStoreExts: Readable<ExtPackageJsonExtra[]>
installedExtsMap: Readable<Record<string, string>> installedExtsMap: Readable<Record<string, string>>
upgradableExpsMap: Readable<Record<string, boolean>> upgradableExpsMap: Readable<Record<string, boolean>>
}> => { }> => {
appState.setFullScreenLoading(true) appState.setFullScreenLoading(true)
return getExtensionsStoreList() return supabaseAPI
.then(({ data: storeExtList, error, response }) => { .getExtList()
storeExtList = storeExtList ?? [] .then(async (storeExtList) => {
if (error) { // map identifier to extItem
toast.error(`Failed to load extension store: ${error} (${response.status})`)
goHome()
}
const storeExtsMap = Object.fromEntries(storeExtList.map((ext) => [ext.identifier, ext])) const storeExtsMap = Object.fromEntries(storeExtList.map((ext) => [ext.identifier, ext]))
// const _appConfig = get(appConfig)
// const installedStoreExts = derived(extensions, ($extensions) => {
// if (!_appConfig.extensionPath) return []
// return $extensions.filter((ext) => !isExtPathInDev(_appConfig.extensionPath!, ext.extPath))
// })
// map installed extension identifier to version
const installedExtsMap = derived(installedStoreExts, ($exts) => const installedExtsMap = derived(installedStoreExts, ($exts) =>
Object.fromEntries($exts.map((ext) => [ext.kunkun.identifier, ext.version])) Object.fromEntries($exts.map((ext) => [ext.kunkun.identifier, ext.version]))
) )
const upgradableExpsMap = derived(installedStoreExts, ($exts) => const upgradableExpsMap = derived(installedStoreExts, ($exts) =>
Object.fromEntries( Object.fromEntries(
$exts.map((ext) => { $exts.map((ext) => {
const dbExt: ExtensionStoreListItem | undefined = storeExtsMap[ext.kunkun.identifier] const dbExt: SBExt | undefined = storeExtsMap[ext.kunkun.identifier]
return [ext.kunkun.identifier, dbExt ? isUpgradable(dbExt, ext.version) : false] return [ext.kunkun.identifier, dbExt ? isUpgradable(dbExt, ext.version) : false]
}) })
) )
) )
return { return {
storeExtList, storeExtList,
installedStoreExts, installedStoreExts,

View File

@ -2,8 +2,11 @@
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 { DBExtension, ExtensionStoreListItem, ExtPackageJson, ExtPublish } from "@kksh/api/models" import { supabaseAPI } from "@/supabase"
import { postExtensionsIncrementDownloads } from "@kksh/sdk" import { goBack } from "@/utils/route.js"
import { ExtPackageJson } from "@kksh/api/models"
import { ExtPublishMetadata } from "@kksh/supabase/models"
import type { Tables } from "@kksh/supabase/types"
import { Button } from "@kksh/svelte5" import { Button } from "@kksh/svelte5"
import { cn } from "@kksh/svelte5/utils" import { cn } from "@kksh/svelte5/utils"
import { Constants } from "@kksh/ui" import { Constants } from "@kksh/ui"
@ -19,8 +22,10 @@
import { getInstallExtras } from "./helper" import { getInstallExtras } from "./helper"
const { data } = $props() const { data } = $props()
const extPublish = $derived(data.extPublish) const extPublish: Tables<"ext_publish"> & { metadata: ExtPublishMetadata } = $derived(
const ext = $derived(data.ext) data.extPublish
)
const ext: Tables<"extensions"> = $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)
@ -72,29 +77,28 @@
}, 500) }, 500)
}) })
const demoImages = $derived(extPublish.demo_images) const demoImages = $derived(
extPublish.demo_images.map((src) =>
src.startsWith("http") ? src : supabaseAPI.translateExtensionFilePathToUrl(src)
)
)
async function onInstallSelected() { async function onInstallSelected() {
loading.install = true loading.install = true
const installExtras = await getInstallExtras(extPublish.metadata) const tarballUrl = extPublish.tarball_path.startsWith("http")
? extPublish.tarball_path
: supabaseAPI.translateExtensionFilePathToUrl(extPublish.tarball_path)
const installExtras = await getInstallExtras(extPublish)
const installDir = await getExtensionsFolder() const installDir = await getExtensionsFolder()
return extensions return extensions
.installFromTarballUrl(extPublish.tarball_path, installDir, installExtras) .installFromTarballUrl(tarballUrl, installDir, installExtras)
.then(() => toast.success(`Plugin ${extPublish.name} Installed`)) .then(() => toast.success(`Plugin ${extPublish.name} Installed`))
.then((loadedExt) => { .then((loadedExt) => {
info(`Successfully installed ${extPublish.name}`) info(`Successfully installed ${extPublish.name}`)
postExtensionsIncrementDownloads({ supabaseAPI.incrementDownloads({
body: {
identifier: extPublish.identifier, identifier: extPublish.identifier,
version: extPublish.version version: extPublish.version
}
}) })
.then(({ error }) => {
if (error) {
console.error(error)
}
})
.catch(console.error)
showBtn.install = false showBtn.install = false
showBtn.uninstall = true showBtn.uninstall = true
}) })
@ -109,8 +113,9 @@
function onUpgradeSelected() { function onUpgradeSelected() {
loading.upgrade = true loading.upgrade = true
const tarballUrl = supabaseAPI.translateExtensionFilePathToUrl(extPublish.tarball_path)
return extensions return extensions
.upgradeStoreExtension(extPublish.identifier, extPublish.tarball_path) .upgradeStoreExtension(extPublish.identifier, tarballUrl)
.then((newExt) => { .then((newExt) => {
toast.success( toast.success(
`${extPublish.name} Upgraded from ${$installedExt?.version} to ${newExt.version}` `${extPublish.name} Upgraded from ${$installedExt?.version} to ${newExt.version}`

View File

@ -1,52 +1,54 @@
import { appState } from "@/stores" import { appState, extensions } from "@/stores"
import { DBExtension, ExtPublish, KunkunExtManifest } from "@kksh/api/models" import { supabaseAPI } from "@/supabase"
import { getExtensionsByIdentifier, getExtensionsLatestPublishByIdentifier } from "@kksh/sdk" import { KunkunExtManifest, type ExtPackageJsonExtra } from "@kksh/api/models"
import { ExtPublishMetadata } from "@kksh/supabase/models"
import type { Tables } from "@kksh/supabase/types"
import { sleep } from "@kksh/utils"
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: ExtPublish extPublish: Tables<"ext_publish"> & { metadata: ExtPublishMetadata }
ext: DBExtension ext: Tables<"extensions">
manifest: KunkunExtManifest manifest: KunkunExtManifest
params: { params: {
identifier: string identifier: string
} }
}> => { }> => {
appState.setFullScreenLoading(true) appState.setFullScreenLoading(true)
return getExtensionsLatestPublishByIdentifier({ return supabaseAPI
path: { .getLatestExtPublish(params.identifier)
identifier: params.identifier .then(async ({ error: dbError, data: extPublish }) => {
} const metadataParse = v.safeParse(ExtPublishMetadata, extPublish?.metadata ?? {})
}) if (dbError) {
.then(async ({ data: extPublish, error: err, response }) => { return error(400, {
if (err || !extPublish) { message: dbError.message
return error(response.status, {
message: "Failed to get extension publish"
}) })
} }
const { const metadata = metadataParse.success ? metadataParse.output : {}
data: ext, const parseManifest = v.safeParse(KunkunExtManifest, extPublish.manifest)
error: extError, if (!parseManifest.success) {
response: extRes const errMsg = "Invalid extension manifest, you may need to upgrade your app."
} = await getExtensionsByIdentifier({ toast.error(errMsg)
path: { throw error(400, errMsg)
identifier: params.identifier
} }
})
if (extError || !ext) { const { data: ext, error: extError } = await supabaseAPI.getExtension(params.identifier)
console.error(extError) if (extError) {
return error(extRes.status, { return error(400, {
message: extError.error || "Failed to get extension" message: extError.message
}) })
} }
return { return {
extPublish: v.parse(ExtPublish, extPublish), extPublish: { ...extPublish, metadata },
ext, ext,
manifest: v.parse(KunkunExtManifest, extPublish.manifest), params,
params manifest: parseManifest.output
} }
}) })
.finally(() => { .finally(() => {

View File

@ -1,15 +1,15 @@
import type { ExtPublishMetadata } from "@kunkunapi/src/models" import type { ExtPublishMetadata } from "@kksh/supabase/models"
import type { Tables } from "@kksh/supabase/types"
export async function getInstallExtras(extMetadata?: { export async function getInstallExtras(
sourceType?: string ext: Tables<"ext_publish"> & { metadata?: ExtPublishMetadata }
source?: string ): Promise<{ overwritePackageJson?: string }> {
}): Promise<{ overwritePackageJson?: string }> {
const extras: { overwritePackageJson?: string } = {} const extras: { overwritePackageJson?: string } = {}
if (extMetadata?.sourceType) { if (ext.metadata?.sourceType) {
if (extMetadata?.sourceType === "jsr") { if (ext.metadata?.sourceType === "jsr") {
if (extMetadata?.source) { if (ext.metadata?.source) {
try { try {
const res = await fetch(`${extMetadata.source}/package.json`) const res = await fetch(`${ext.metadata.source}/package.json`)
const pkgJsonContent = await res.text() const pkgJsonContent = await res.text()
extras.overwritePackageJson = pkgJsonContent extras.overwritePackageJson = pkgJsonContent
} catch (error) { } catch (error) {

View File

@ -1,125 +0,0 @@
<script lang="ts">
import {
getAllCmds,
getAllExtensions,
getExtensionDataById,
getUniqueExtensionByIdentifier,
getUniqueExtensionByPath,
searchExtensionData,
updateCmdByID
} from "@/orm/cmds"
import * as schema from "@kksh/drizzle/schema"
import { Button, Input } from "@kksh/svelte5"
import { CmdTypeEnum, Ext } from "@kunkunapi/src/models/extension"
import { SearchModeEnum, SQLSortOrderEnum } from "@kunkunapi/src/models/sql"
import { db } from "$lib/orm/database"
import * as orm from "drizzle-orm"
import { Inspect } from "svelte-inspect-value"
import { toast } from "svelte-sonner"
import * as v from "valibot"
let searchText = $state("")
/* eslint-disable */
let data: any = $state(null)
let inspectTitle = $state("")
</script>
<main class="container space-y-2">
<Button
onclick={async () => {
getAllCmds()
.then((cmds) => {
console.log(cmds)
data = cmds
inspectTitle = "All Commands"
})
.catch((e) => {
console.error(e)
toast.error("Failed to get all commands", {
description: "See console for more details"
})
})
}}
>
Get All Commands
</Button>
<Button
onclick={() => {
getAllExtensions()
.then((exts) => {
data = exts
inspectTitle = "All Extensions"
})
.catch((e) => {
console.error(e)
toast.error("Failed to get all extensions", {
description: "See console for more details"
})
})
}}
>
Get All Extensions
</Button>
<Button
onclick={async () => {
// get all extensions with path not null
const exts = await getAllExtensions()
for (const ext of exts) {
if (ext.path === null) continue
const _ext = await getUniqueExtensionByIdentifier(ext.identifier)
console.log(_ext)
if (ext.path) {
const __ext = await getUniqueExtensionByPath(ext.path)
console.log(__ext)
}
}
// data = exts
}}
>
Get Unique Extension By Identifier and Path
</Button>
<!-- <Button
onclick={async () => {
updateCmdByID({
cmdId: 1,
name: "google",
cmdType: CmdTypeEnum.QuickLink,
data: `{"link":"https://google.com/search?query={argument}","icon":{"type":"remote-url","value":"https://google.com/favicon.ico","invert":false}}`,
enabled: true
})
}}
>
Update Command By ID
</Button> -->
<Button
onclick={async () => {
const _data = await getExtensionDataById(1, ["search_text", "data"])
data = _data
inspectTitle = "Extension Data"
}}
>
Get Extension Data By ID
</Button>
<form
class="flex gap-1"
onsubmit={async (e) => {
e.preventDefault()
const _data = await searchExtensionData({
extId: 1,
searchMode: SearchModeEnum.FTS,
searchText: searchText,
orderByCreatedAt: SQLSortOrderEnum.Desc,
limit: 10,
fields: ["search_text", "data"]
})
console.log(_data)
data = _data
inspectTitle = "Search Results"
}}
>
<Input class="" bind:value={searchText} placeholder="Search Text" />
<Button class="" type="submit">Search Extension Data</Button>
</form>
<Inspect name={inspectTitle} value={data} expandLevel={2} />
</main>

View File

@ -6,7 +6,6 @@
import { Constants } from "@kksh/ui" import { Constants } from "@kksh/ui"
import { ArrowLeftIcon } from "lucide-svelte" import { ArrowLeftIcon } from "lucide-svelte"
import AppWindow from "lucide-svelte/icons/app-window" import AppWindow from "lucide-svelte/icons/app-window"
import DB from "lucide-svelte/icons/database"
import Loader from "lucide-svelte/icons/loader" import Loader from "lucide-svelte/icons/loader"
import Network from "lucide-svelte/icons/network" import Network from "lucide-svelte/icons/network"
@ -26,11 +25,6 @@
title: m.troubleshooters_sidebar_mdns_debugger_title(), title: m.troubleshooters_sidebar_mdns_debugger_title(),
url: i18n.resolveRoute("/app/troubleshooters/mdns-debugger"), url: i18n.resolveRoute("/app/troubleshooters/mdns-debugger"),
icon: Network icon: Network
},
{
title: "ORM",
url: i18n.resolveRoute("/app/troubleshooters/orm"),
icon: DB
} }
] ]
let currentItem = $state(items.find((item) => window.location.pathname === item.url)) let currentItem = $state(items.find((item) => window.location.pathname === item.url))

View File

@ -9,8 +9,7 @@
"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,9 +28,7 @@
}, },
"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.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",
@ -50,7 +48,7 @@
"tauri-plugin-keyring-api": "workspace:*", "tauri-plugin-keyring-api": "workspace:*",
"tauri-plugin-network-api": "workspace:*", "tauri-plugin-network-api": "workspace:*",
"tauri-plugin-system-info-api": "workspace:*", "tauri-plugin-system-info-api": "workspace:*",
"valibot": "^1.0.0", "valibot": "^1.0.0-rc.4",
"zod": "^3.24.2" "zod": "^3.24.2"
}, },
"workspaces": [ "workspaces": [

View File

@ -75,7 +75,7 @@
"tauri-plugin-network-api": "2.0.5", "tauri-plugin-network-api": "2.0.5",
"tauri-plugin-shellx-api": "^2.0.16", "tauri-plugin-shellx-api": "^2.0.16",
"tauri-plugin-system-info-api": "2.0.8", "tauri-plugin-system-info-api": "2.0.8",
"valibot": "^1.0.0" "valibot": "^1.0.0-rc.4"
}, },
"files": [ "files": [
"src", "src",

View File

@ -1,84 +1,91 @@
import * as v from "valibot" import {
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 = v.record( export const ExtensionLabelMap = record(
v.string("Window label"), string("Window label"),
v.object({ object({
path: v.string("Path to the extension"), path: string("Path to the extension"),
processes: v.array(v.number()), processes: array(number()),
dist: v.optional(v.nullable(v.string())) dist: optional(nullable(string()))
}) })
) )
export type ExtensionLabelMap = v.InferOutput<typeof ExtensionLabelMap> export type ExtensionLabelMap = InferOutput<typeof ExtensionLabelMap>
export const Ext = v.object({ export const Ext = object({
extId: v.number(), extId: number(),
identifier: v.string(), identifier: string(),
version: v.string(), version: string(),
enabled: v.pipe( enabled: boolean(),
v.number(), installed_at: string(),
v.transform((input) => Boolean(input)) path: nullable(string()),
), data: nullable(any())
installedAt: v.string(),
path: v.optional(v.nullable(v.string())),
data: v.optional(v.any())
}) })
export type Ext = v.InferOutput<typeof Ext> export type Ext = InferOutput<typeof Ext>
export const CmdTypeEnum = { export enum 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 = v.picklist(Object.values(CmdTypeEnum)) export const CmdType = enum_(CmdTypeEnum)
export type CmdType = InferOutput<typeof CmdType>
export type CmdType = v.InferOutput<typeof CmdType> export const ExtCmd = object({
export const ExtCmd = v.object({ cmdId: number(),
cmdId: v.number(), extId: number(),
extId: v.number(), name: string(),
name: v.string(),
type: CmdType, type: CmdType,
data: v.string(), data: string(),
alias: v.optional(v.nullable(v.string())), alias: nullable(optional(string())),
hotkey: v.optional(v.nullable(v.string())), hotkey: nullable(optional(string())),
enabled: v.pipe( enabled: boolean()
v.number(),
v.transform((input) => Boolean(input))
)
}) })
export type ExtCmd = v.InferOutput<typeof ExtCmd> export type ExtCmd = InferOutput<typeof ExtCmd>
export const QuickLinkCmd = v.object({ export const QuickLinkCmd = object({
...ExtCmd.entries, ...ExtCmd.entries,
data: v.object({ link: v.string(), icon: Icon }) data: object({ link: string(), icon: Icon })
}) })
export type QuickLinkCmd = v.InferOutput<typeof QuickLinkCmd> export type QuickLinkCmd = InferOutput<typeof QuickLinkCmd>
export const ExtData = v.object({ export const ExtData = object({
dataId: v.number(), dataId: number(),
extId: v.number(), extId: number(),
dataType: v.string(), dataType: string(),
data: v.optional(v.string()), data: optional(string()),
searchText: v.optional(v.string()), searchText: optional(string()),
createdAt: v.date(), createdAt: date(),
updatedAt: v.date() updatedAt: date()
}) })
export type ExtData = v.InferOutput<typeof ExtData> export type ExtData = InferOutput<typeof ExtData>
export const SysCommand = v.object({ export const SysCommand = object({
name: v.string(), name: string(),
value: v.string(), value: string(),
icon: v.optional(v.nullable(Icon)), icon: nullable(Icon),
keywords: v.optional(v.nullable(v.array(v.string()))), keywords: nullable(array(string())),
function: v.function_(), function: function_(),
confirmRequired: v.boolean() confirmRequired: boolean()
}) })
export type SysCommand = v.InferOutput<typeof SysCommand> export type SysCommand = InferOutput<typeof SysCommand>

View File

@ -4,21 +4,14 @@ 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.picklist(Object.values(IconEnum)) export const IconType = v.enum_(IconEnum)
export type IconType = v.InferOutput<typeof IconType> export type IconType = v.InferOutput<typeof IconType>
export type Icon = { export type Icon = {

View File

@ -13,4 +13,3 @@ export { Markdown as MarkdownSchema } from "../ui/template/schema/markdown"
export * as ListSchema from "../ui/template/schema/list" export * as ListSchema from "../ui/template/schema/list"
export * as FormSchema from "../ui/template/schema/form" export * as FormSchema from "../ui/template/schema/form"
export * from "./file-transfer" export * from "./file-transfer"
export * from "./server"

View File

@ -1,3 +1,4 @@
import { FsPermissionSchema } from "tauri-api-adapter/permissions"
import * as v from "valibot" import * as v from "valibot"
import { import {
AllKunkunPermission, AllKunkunPermission,
@ -7,29 +8,29 @@ import {
OpenPermissionScopedSchema, OpenPermissionScopedSchema,
ShellPermissionScopedSchema ShellPermissionScopedSchema
} from "../permissions" } from "../permissions"
import { CmdType, CmdTypeEnum } from "./extension" import { CmdType } from "./extension"
import { BaseIcon as Icon } from "./icon" import { BaseIcon as Icon } from "./icon"
export const OSPlatformEnum = { export enum OSPlatformEnum {
linux: "linux", linux = "linux",
macos: "macos", macos = "macos",
windows: "windows" windows = "windows"
} }
export const OSPlatform = v.picklist(Object.values(OSPlatformEnum)) export const OSPlatform = v.enum_(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 const TitleBarStyleEnum = { export enum TitleBarStyleEnum {
visible: "visible", "visible" = "visible",
transparent: "transparent", "transparent" = "transparent",
overlay: "overlay" "overlay" = "overlay"
} }
export type TitleBarStyle = v.InferOutput<typeof TitleBarStyle> export const TitleBarStyle = v.enum_(TitleBarStyleEnum)
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"]);
@ -70,33 +71,37 @@ 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.array(OSPlatform, "Platforms available on. Leave empty for all platforms.") v.nullable(
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, CmdTypeEnum.UiWorker), type: v.optional(CmdType, CmdType.enum.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, CmdTypeEnum.HeadlessWorker) type: v.optional(CmdType, CmdType.enum.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

@ -1,91 +0,0 @@
import * as v from "valibot"
import { BaseIcon } from "./icon"
import { ExtPackageJson, KunkunExtManifest } from "./manifest"
export const ExtPublishSourceTypeEnum = {
jsr: "jsr",
npm: "npm"
} as const
export const ExtPublishMetadata = v.object({
source: v.optional(v.string("Source of the extension (e.g. url to package)")),
sourceType: v.optional(v.picklist(Object.values(ExtPublishSourceTypeEnum))),
rekorLogIndex: v.optional(v.string("Rekor log index of the extension")),
git: v.optional(
v.object({
githubActionInvocationId: v.string("GitHub action invocation ID"),
repo: v.string("GitHub repo of the extension"),
owner: v.string("GitHub owner of the extension"),
commit: v.string("Commit hash of the extension"),
workflowPath: v.string("Workflow path of the extension"),
repoNodeId: v.optional(
v.string("GitHub repo node ID of the extension (a string, not the number id)")
)
})
)
})
export type ExtPublishMetadata = v.InferOutput<typeof ExtPublishMetadata>
/***
* Correspond to `extensions` table in supabase, missing a few fields
*/
export const ExtensionStoreListItem = v.object({
identifier: v.string(),
name: v.string(),
created_at: v.string(),
downloads: v.number(),
author_id: v.string(),
short_description: v.string(),
long_description: v.string(),
version: v.string(),
api_version: v.optional(v.string()),
icon: BaseIcon
})
export type ExtensionStoreListItem = v.InferOutput<typeof ExtensionStoreListItem>
export const PublishStateEnum = {
public: "public",
pending: "pending",
under_review: "under_review",
private: "private"
}
export const ExtensionPublishState = v.picklist(Object.values(PublishStateEnum))
export const ExtPublish = v.object({
id: v.number(),
name: v.string(),
tarball_path: v.string(),
created_at: v.string(),
version: v.string(),
manifest: KunkunExtManifest,
shasum: v.string(),
tarball_size: v.number(),
unpacked_size: v.nullable(v.number()),
cmd_count: v.number(),
identifier: v.string(),
downloads: v.number(),
demo_images: v.array(v.string()),
api_version: v.nullable(v.string()),
extension_state: ExtensionPublishState,
package_json: ExtPackageJson,
metadata: ExtPublishMetadata,
readme: v.nullable(v.string())
})
export type ExtPublish = v.InferOutput<typeof ExtPublish>
export const DBExtension = v.object({
api_version: v.string(),
author_id: v.string(),
created_at: v.string(),
downloads: v.number(),
icon: BaseIcon,
identifier: v.string(),
long_description: v.nullable(v.string()),
name: v.string(),
readme: v.nullable(v.string()),
short_description: v.string(),
tarball_size: v.nullable(v.number()),
version: v.string()
})
export type DBExtension = v.InferOutput<typeof DBExtension>

View File

@ -11,25 +11,3 @@ bunx drizzle-kit pull
We are using sqlite with fts5, which drizzle doesn't support yet, so pushing the schema will destroy the existing schema. We are using sqlite with fts5, which drizzle doesn't support yet, so pushing the schema will destroy the existing schema.
We only use pulled schema to generate sql queries. We only use pulled schema to generate sql queries.
## Update Schema
After `drizzle-kit pull` the schema may have problem with JSON type and boolean type.
Will need to manually update the following
### JSON
```diff lang="ts"
+ data: text({ mode: "json" }).notNull(),
+ metadata: text({ mode: "json" }),
- data: numeric().notNull(),
- metadata: numeric(),
```
### Boolean
```diff lang="ts"
+ enabled: integer({ mode: "boolean" }),
- enabled: numeric().default(sql`(TRUE)`),
```

View File

@ -1,21 +1,21 @@
import { relations } from "drizzle-orm/relations" import { relations } from "drizzle-orm/relations";
import { commands, extensionData, extensions } from "./schema" import { extensions, commands, extensionData } from "./schema";
export const commandsRelations = relations(commands, ({ one }) => ({ export const commandsRelations = relations(commands, ({one}) => ({
extension: one(extensions, { extension: one(extensions, {
fields: [commands.extId], fields: [commands.extId],
references: [extensions.extId] references: [extensions.extId]
}) }),
})) }));
export const extensionsRelations = relations(extensions, ({ many }) => ({ export const extensionsRelations = relations(extensions, ({many}) => ({
commands: many(commands), commands: many(commands),
extensionData: many(extensionData) extensionData: many(extensionData),
})) }));
export const extensionDataRelations = relations(extensionData, ({ one }) => ({ export const extensionDataRelations = relations(extensionData, ({one}) => ({
extension: one(extensions, { extension: one(extensions, {
fields: [extensionData.extId], fields: [extensionData.extId],
references: [extensions.extId] references: [extensions.extId]
}) }),
})) }));

View File

@ -29,8 +29,7 @@ export const commands = sqliteTable("commands", {
.notNull() .notNull()
.references(() => extensions.extId, { onDelete: "cascade" }), .references(() => extensions.extId, { onDelete: "cascade" }),
name: text().notNull(), name: text().notNull(),
enabled: integer({ mode: "boolean" }), enabled: numeric().default(sql`(TRUE)`),
// enabled: numeric().default(sql`(TRUE)`),
alias: text(), alias: text(),
hotkey: text(), hotkey: text(),
type: text().notNull(), type: text().notNull(),
@ -43,10 +42,8 @@ export const extensionData = sqliteTable("extension_data", {
.notNull() .notNull()
.references(() => extensions.extId, { onDelete: "cascade" }), .references(() => extensions.extId, { onDelete: "cascade" }),
dataType: text("data_type").notNull(), dataType: text("data_type").notNull(),
// data: text({ mode: "json" }).notNull(), data: numeric().notNull(),
// metadata: text({ mode: "json" }), metadata: numeric(),
data: text("data").notNull(),
metadata: text("metadata"),
searchText: text("search_text"), searchText: text("search_text"),
createdAt: numeric("created_at").default(sql`(CURRENT_TIMESTAMP)`), createdAt: numeric("created_at").default(sql`(CURRENT_TIMESTAMP)`),
updatedAt: numeric("updated_at").default(sql`(CURRENT_TIMESTAMP)`) updatedAt: numeric("updated_at").default(sql`(CURRENT_TIMESTAMP)`)

View File

@ -11,15 +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.4", "@kksh/supabase": "workspace:*",
"@std/semver": "npm:@jsr/std__semver@^1.0.3",
"@tauri-apps/plugin-upload": "^2.2.1", "@tauri-apps/plugin-upload": "^2.2.1",
"semver": "^7.7.1", "semver": "^7.7.1",
"uuid": "^11.1.0" "uuid": "^11.0.3"
}, },
"peerDependencies": { "peerDependencies": {
"typescript": "^5.0.0" "typescript": "^5.0.0"

View File

@ -4,7 +4,8 @@
*/ */
import { isCompatible } from "@kksh/api" import { isCompatible } from "@kksh/api"
import { copy_dir_all, db, decompressTarball } from "@kksh/api/commands" import { copy_dir_all, db, decompressTarball } from "@kksh/api/commands"
import type { ExtensionStoreListItem, ExtPackageJsonExtra } from "@kksh/api/models" import type { ExtPackageJsonExtra } from "@kksh/api/models"
import { SBExt } from "@kksh/supabase/models"
import { greaterThan, parse as parseSemver } from "@std/semver" import { greaterThan, parse as parseSemver } from "@std/semver"
import * as path from "@tauri-apps/api/path" import * as path from "@tauri-apps/api/path"
import * as dialog from "@tauri-apps/plugin-dialog" import * as dialog from "@tauri-apps/plugin-dialog"
@ -192,7 +193,7 @@ export async function uninstallExtensionByPath(extPath: string) {
return fs.remove(extPath, { recursive: true }).then(() => db.deleteExtensionByPath(extPath)) return fs.remove(extPath, { recursive: true }).then(() => db.deleteExtensionByPath(extPath))
} }
export function isUpgradable(dbExt: ExtensionStoreListItem, installedExtVersion: string) { export function isUpgradable(dbExt: SBExt, installedExtVersion: string) {
const upgradable = const upgradable =
greaterThan(parseSemver(dbExt.version), parseSemver(installedExtVersion)) && dbExt.api_version greaterThan(parseSemver(dbExt.version), parseSemver(installedExtVersion)) && dbExt.api_version
? isCompatible(dbExt.api_version) ? isCompatible(dbExt.api_version)

View File

@ -1,5 +1,4 @@
import type { TitleBarStyle, WindowConfig } from "@kksh/api/models" import type { 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) {
@ -27,8 +26,7 @@ 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: titleBarStyle: windowConfig?.titleBarStyle ?? undefined,
(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,15 +1,9 @@
import { expect, test } from "bun:test" import { expect, test } from "bun:test"
import { getGitHubRepoMetadata, parseGitHubRepoFromUri } from "../github" import { parseGitHubRepoFromUri } from "../github"
test("parse github repo from uri", () => { test("parse github repo from uri", () => {
expect(parseGitHubRepoFromUri("https://github.com/kunkunsh/kunkun-ext-ossinsight")).toEqual({ expect(parseGitHubRepoFromUri("https://github.com/huakunshen/kunkun-ext-ossinsight")).toEqual({
owner: "kunkunsh", owner: "huakunshen",
repo: "kunkun-ext-ossinsight" repo: "kunkun-ext-ossinsight"
}) })
expect(() => parseGitHubRepoFromUri("invalid-uri")).toThrow("Invalid GitHub repository URI")
})
test("get github repo metadata", async () => {
const metadata = await getGitHubRepoMetadata("kunkunsh", "kunkun-ext-ossinsight")
expect(metadata).toBeDefined()
}) })

View File

@ -33,12 +33,6 @@ export function authenticatedUserIsMemberOfGitHubOrg(
}) })
} }
/**
* Parse a GitHub repository URI into owner and repo
* If not a valid GitHub repository URI, throw an error
* @param uri
* @returns owner and repo
*/
export function parseGitHubRepoFromUri(uri: string): { export function parseGitHubRepoFromUri(uri: string): {
owner: string owner: string
repo: string repo: string
@ -52,15 +46,3 @@ export function parseGitHubRepoFromUri(uri: string): {
const [, owner, repo] = match const [, owner, repo] = match
return { owner, repo } return { owner, repo }
} }
/**
* Get GitHub repository metadata
* @param owner
* @param repo
* @param githubToken - Optional GitHub token to prevent rate limiting
* @returns repository metadata
*/
export function getGitHubRepoMetadata(owner: string, repo: string, githubToken?: string) {
const octokit = new Octokit({ auth: githubToken })
return octokit.rest.repos.get({ owner, repo }).then((res) => res.data)
}

View File

@ -7,11 +7,7 @@ import {
} from "@huakunshen/jsr-client/hey-api-client" } from "@huakunshen/jsr-client/hey-api-client"
import { ExtPackageJson, License } from "@kksh/api/models" import { ExtPackageJson, License } from "@kksh/api/models"
import * as v from "valibot" import * as v from "valibot"
import { import { authenticatedUserIsMemberOfGitHubOrg, userIsPublicMemberOfGitHubOrg } from "../github"
authenticatedUserIsMemberOfGitHubOrg,
getGitHubRepoMetadata,
userIsPublicMemberOfGitHubOrg
} from "../github"
import type { ExtensionPublishValidationData } from "../models" import type { ExtensionPublishValidationData } from "../models"
import type { NpmPkgMetadata } from "../npm/models" import type { NpmPkgMetadata } from "../npm/models"
import { getInfoFromRekorLog } from "../sigstore" import { getInfoFromRekorLog } from "../sigstore"
@ -123,11 +119,7 @@ export function getJsrPackageSrcFile(
file: string file: string
): Promise<string | undefined> { ): Promise<string | undefined> {
const url = `https://jsr.io/@${scope}/${name}/${version}/${file}` const url = `https://jsr.io/@${scope}/${name}/${version}/${file}`
return fetch(url, { return fetch(url).then((res) => res.text())
headers: {
Accept: "application/json"
}
}).then((res) => res.text())
} }
/** /**
@ -209,7 +201,6 @@ export function jsrPackageExists(scope: string, name: string, version?: string):
/** /**
* Validate a Jsr package as a Kunkun extension * Validate a Jsr package as a Kunkun extension
* !This function will also run in frontend, so if there is any verification logic that must be run in backend, do not add it here
* - check if jsr pkg is linked to a github repo * - check if jsr pkg is linked to a github repo
* - check if jsr pkg is signed with github action * - check if jsr pkg is signed with github action
* - check if user's github username is the same as repo's owner name * - check if user's github username is the same as repo's owner name
@ -373,7 +364,6 @@ export async function validateJsrPackageAsKunkunExtension(payload: {
} }
} }
const rekorInfo = await getInfoFromRekorLog(rekorLogId) const rekorInfo = await getInfoFromRekorLog(rekorLogId)
return { return {
data: { data: {
pkgJson: parseResult.output, pkgJson: parseResult.output,

View File

@ -2,7 +2,6 @@ import { ExtPackageJson, License } from "@kksh/api/models"
import * as v from "valibot" import * as v from "valibot"
import { import {
authenticatedUserIsMemberOfGitHubOrg, authenticatedUserIsMemberOfGitHubOrg,
getGitHubRepoMetadata,
parseGitHubRepoFromUri, parseGitHubRepoFromUri,
userIsPublicMemberOfGitHubOrg userIsPublicMemberOfGitHubOrg
} from "../github" } from "../github"
@ -238,7 +237,6 @@ export async function validateNpmPackageAsKunkunExtension(payload: {
provenance.summary.sourceRepositoryDigest, provenance.summary.sourceRepositoryDigest,
parseResult.output.readme ?? "README.md" parseResult.output.readme ?? "README.md"
) )
return { return {
data: { data: {
pkgJson: parseResult.output, pkgJson: parseResult.output,

View File

@ -15,15 +15,17 @@
}, },
"devDependencies": { "devDependencies": {
"@types/bun": "latest", "@types/bun": "latest",
"@kksh/supabase": "workspace:*",
"@supabase/supabase-js": "^2.48.0", "@supabase/supabase-js": "^2.48.0",
"@valibot/to-json-schema": "1.0.0" "@valibot/to-json-schema": "1.0.0-beta.4"
}, },
"peerDependencies": { "peerDependencies": {
"@kksh/supabase": "workspace:*",
"typescript": "^5.0.0" "typescript": "^5.0.0"
}, },
"dependencies": { "dependencies": {
"@aws-sdk/client-s3": "^3.583.0", "@aws-sdk/client-s3": "^3.583.0",
"@kksh/api": "workspace:*", "@kksh/api": "workspace:*",
"valibot": "^1.0.0" "valibot": "^1.0.0-rc.4"
} }
} }

View File

@ -1,10 +1,11 @@
import { ExtPackageJson } from "@kksh/api/models" import { ExtPackageJson } from "@kksh/api/models"
import { type Database } from "@kksh/supabase/types"
import { createClient } from "@supabase/supabase-js" import { createClient } from "@supabase/supabase-js"
import { parse, string } from "valibot" import { parse, string } from "valibot"
import * as v from "valibot" import * as v from "valibot"
import { getJsonSchema } from "../src" import { getJsonSchema } from "../src"
const supabase = createClient( const supabase = createClient<Database>(
parse(string(), process.env.SUPABASE_URL), parse(string(), process.env.SUPABASE_URL),
parse(string(), process.env.SUPABASE_SERVICE_ROLE_KEY) parse(string(), process.env.SUPABASE_SERVICE_ROLE_KEY)
) )

175
packages/supabase/.gitignore vendored Normal file
View File

@ -0,0 +1,175 @@
# Based on https://raw.githubusercontent.com/github/gitignore/main/Node.gitignore
# Logs
logs
_.log
npm-debug.log_
yarn-debug.log*
yarn-error.log*
lerna-debug.log*
.pnpm-debug.log*
# Caches
.cache
# Diagnostic reports (https://nodejs.org/api/report.html)
report.[0-9]_.[0-9]_.[0-9]_.[0-9]_.json
# Runtime data
pids
_.pid
_.seed
*.pid.lock
# Directory for instrumented libs generated by jscoverage/JSCover
lib-cov
# Coverage directory used by tools like istanbul
coverage
*.lcov
# nyc test coverage
.nyc_output
# Grunt intermediate storage (https://gruntjs.com/creating-plugins#storing-task-files)
.grunt
# Bower dependency directory (https://bower.io/)
bower_components
# node-waf configuration
.lock-wscript
# Compiled binary addons (https://nodejs.org/api/addons.html)
build/Release
# Dependency directories
node_modules/
jspm_packages/
# Snowpack dependency directory (https://snowpack.dev/)
web_modules/
# TypeScript cache
*.tsbuildinfo
# Optional npm cache directory
.npm
# Optional eslint cache
.eslintcache
# Optional stylelint cache
.stylelintcache
# Microbundle cache
.rpt2_cache/
.rts2_cache_cjs/
.rts2_cache_es/
.rts2_cache_umd/
# Optional REPL history
.node_repl_history
# Output of 'npm pack'
*.tgz
# Yarn Integrity file
.yarn-integrity
# dotenv environment variable files
.env
.env.development.local
.env.test.local
.env.production.local
.env.local
# parcel-bundler cache (https://parceljs.org/)
.parcel-cache
# Next.js build output
.next
out
# Nuxt.js build / generate output
.nuxt
dist
# Gatsby files
# Comment in the public line in if your project uses Gatsby and not Next.js
# https://nextjs.org/blog/next-9-1#public-directory-support
# public
# vuepress build output
.vuepress/dist
# vuepress v2.x temp and cache directory
.temp
# Docusaurus cache and generated files
.docusaurus
# Serverless directories
.serverless/
# FuseBox cache
.fusebox/
# DynamoDB Local files
.dynamodb/
# TernJS port file
.tern-port
# Stores VSCode versions used for testing VSCode extensions
.vscode-test
# yarn v2
.yarn/cache
.yarn/unplugged
.yarn/build-state.yml
.yarn/install-state.gz
.pnp.*
# IntelliJ based IDEs
.idea
# Finder (MacOS) folder config
.DS_Store

View File

@ -0,0 +1,4 @@
```bash
export PROJECT_REF=qzehioyfmxlgkeuujwlh
npx supabase gen types --lang=typescript --project-id $PROJECT_REF --schema public > ./src/database.types.ts
```

View File

@ -0,0 +1,24 @@
{
"name": "@kksh/supabase",
"type": "module",
"scripts": {
"prepare": "bun setup.ts"
},
"exports": {
".": "./src/index.ts",
"./api": "./src/api.ts",
"./models": "./src/models.ts",
"./types": "./src/database.types.ts"
},
"dependencies": {
"@kksh/api": "workspace:*",
"@supabase/ssr": "^0.5.2",
"@supabase/supabase-js": "^2.48.0"
},
"devDependencies": {
"@types/bun": "latest"
},
"peerDependencies": {
"typescript": "^5.0.0"
}
}

View File

View File

@ -0,0 +1,107 @@
import type { PostgrestSingleResponse, SupabaseClient } from "@supabase/supabase-js"
import * as v from "valibot"
import type { Database, Tables } from "./database.types"
import { SBExt } from "./models"
export class SupabaseAPI {
constructor(private supabase: SupabaseClient<Database>) {}
async getExtList(): Promise<SBExt[]> {
const res = await this.supabase
.from("extensions")
.select(
"identifier, version, api_version, name, downloads, short_description, long_description, icon, created_at"
)
.order("downloads", { ascending: false })
.select()
const dbExts: Tables<"extensions">[] = res.data ?? []
return dbExts
.map((x) => {
const parsedNode = v.safeParse(SBExt, x)
if (!parsedNode.success) {
console.error(`Fail to parse extension`, x)
console.warn(parsedNode.issues)
console.error(v.flatten(parsedNode.issues))
}
return parsedNode.success ? v.parse(SBExt, parsedNode.output) : null
})
.filter((x) => x !== null)
}
async getLatestExtPublish(
identifier: string
): Promise<PostgrestSingleResponse<Tables<"ext_publish">>> {
return this.supabase
.from("ext_publish")
.select(
"created_at, name, version, manifest, shasum, size, tarball_path, cmd_count, identifier, downloads, demo_images, api_version, metadata"
)
.order("created_at", { ascending: false })
.eq("identifier", identifier)
.select()
.limit(1)
.single()
}
getExtension(identifier: string) {
return this.supabase
.from("extensions")
.select("*")
.eq("identifier", identifier)
.limit(1)
.single()
}
async incrementDownloads({
identifier,
version
}: {
identifier: string
version: string
}): Promise<{ downloads: number }> {
return this.supabase.functions
.invoke("increment-downloads", {
body: { identifier, version }
})
.then(({ data, error }) => {
if (error) {
throw error
}
const parsed = v.safeParse(
v.object({
downloads: v.number()
}),
data
)
if (!parsed.success) {
throw new Error("Fail to parse increment downloads response")
}
return parsed.output
})
}
async publishExtFromJSR(payload: {
scope: string
version: string
name: string
}): Promise<void> {
return this.supabase.functions
.invoke("publish-jsr-ext", {
body: payload
})
.then(async ({ data, error }) => {
if (data && data.isValid) {
return
}
if (error?.name === "FunctionsHttpError") {
const errorMessage = await error.context.json()
throw new Error(errorMessage.error)
} else {
throw new Error(`Unknown error: ${error?.message}`)
}
})
}
translateExtensionFilePathToUrl(tarballPath: string): string {
return this.supabase.storage.from("extensions").getPublicUrl(tarballPath).data.publicUrl
}
}

View File

@ -0,0 +1,335 @@
export type Json = string | number | boolean | null | { [key: string]: Json | undefined } | Json[]
export type Database = {
public: {
Tables: {
cache: {
Row: {
created_at: string
data: Json | null
expiry_date: string | null
id: number
key: string
}
Insert: {
created_at?: string
data?: Json | null
expiry_date?: string | null
id?: number
key: string
}
Update: {
created_at?: string
data?: Json | null
expiry_date?: string | null
id?: number
key?: string
}
Relationships: []
}
events: {
Row: {
created_at: string
data: Json | null
event_type: Database["public"]["Enums"]["event_type"]
id: number
ip: string
}
Insert: {
created_at?: string
data?: Json | null
event_type: Database["public"]["Enums"]["event_type"]
id?: number
ip: string
}
Update: {
created_at?: string
data?: Json | null
event_type?: Database["public"]["Enums"]["event_type"]
id?: number
ip?: string
}
Relationships: []
}
ext_images: {
Row: {
created_at: string
image_path: string
sha512: string
}
Insert: {
created_at?: string
image_path: string
sha512: string
}
Update: {
created_at?: string
image_path?: string
sha512?: string
}
Relationships: []
}
ext_publish: {
Row: {
api_version: string | null
cmd_count: number
created_at: string
demo_images: string[]
downloads: number
extension_state: Database["public"]["Enums"]["extension_state"]
id: number
identifier: string
manifest: Json
metadata: Json | null
name: string
package_json: Json | null
readme: string | null
shasum: string
tarball_path: string
tarball_size: number
unpacked_size: number | null
version: string
}
Insert: {
api_version?: string | null
cmd_count: number
created_at?: string
demo_images: string[]
downloads: number
extension_state?: Database["public"]["Enums"]["extension_state"]
id?: number
identifier: string
manifest: Json
metadata?: Json | null
name: string
package_json?: Json | null
readme?: string | null
shasum: string
tarball_path: string
tarball_size: number
unpacked_size?: number | null
version: string
}
Update: {
api_version?: string | null
cmd_count?: number
created_at?: string
demo_images?: string[]
downloads?: number
extension_state?: Database["public"]["Enums"]["extension_state"]
id?: number
identifier?: string
manifest?: Json
metadata?: Json | null
name?: string
package_json?: Json | null
readme?: string | null
shasum?: string
tarball_path?: string
tarball_size?: number
unpacked_size?: number | null
version?: string
}
Relationships: [
{
foreignKeyName: "ext_publish_identifier_fkey"
columns: ["identifier"]
isOneToOne: false
referencedRelation: "extensions"
referencedColumns: ["identifier"]
}
]
}
extensions: {
Row: {
api_version: string
author_id: string | null
created_at: string
downloads: number
icon: Json | null
identifier: string
long_description: string | null
name: string
readme: string | null
short_description: string
tarball_size: number | null
version: string
}
Insert: {
api_version: string
author_id?: string | null
created_at?: string
downloads: number
icon?: Json | null
identifier: string
long_description?: string | null
name: string
readme?: string | null
short_description: string
tarball_size?: number | null
version: string
}
Update: {
api_version?: string
author_id?: string | null
created_at?: string
downloads?: number
icon?: Json | null
identifier?: string
long_description?: string | null
name?: string
readme?: string | null
short_description?: string
tarball_size?: number | null
version?: string
}
Relationships: []
}
stargazers: {
Row: {
created_at: string
id: number
star_date: string
username: string
}
Insert: {
created_at?: string
id?: number
star_date: string
username: string
}
Update: {
created_at?: string
id?: number
star_date?: string
username?: string
}
Relationships: []
}
}
Views: {
[_ in never]: never
}
Functions: {
get_aggregated_downloads: {
Args: Record<PropertyKey, never>
Returns: {
identifier: string
total_downloads: number
}[]
}
get_aggregated_downloads_with_details: {
Args: Record<PropertyKey, never>
Returns: {
identifier: string
total_downloads: number
name: string
short_description: string
}[]
}
increment_downloads: {
Args: {
t_identifier: string
t_version: string
}
Returns: number
}
}
Enums: {
event_type: "download" | "updater" | "schema" | "nightly_schema"
extension_state: "public" | "pending" | "under_review" | "private"
}
CompositeTypes: {
[_ in never]: never
}
}
}
type PublicSchema = Database[Extract<keyof Database, "public">]
export type Tables<
PublicTableNameOrOptions extends
| keyof (PublicSchema["Tables"] & PublicSchema["Views"])
| { schema: keyof Database },
TableName extends PublicTableNameOrOptions extends { schema: keyof Database }
? keyof (Database[PublicTableNameOrOptions["schema"]]["Tables"] &
Database[PublicTableNameOrOptions["schema"]]["Views"])
: never = never
> = PublicTableNameOrOptions extends { schema: keyof Database }
? (Database[PublicTableNameOrOptions["schema"]]["Tables"] &
Database[PublicTableNameOrOptions["schema"]]["Views"])[TableName] extends {
Row: infer R
}
? R
: never
: PublicTableNameOrOptions extends keyof (PublicSchema["Tables"] & PublicSchema["Views"])
? (PublicSchema["Tables"] & PublicSchema["Views"])[PublicTableNameOrOptions] extends {
Row: infer R
}
? R
: never
: never
export type TablesInsert<
PublicTableNameOrOptions extends keyof PublicSchema["Tables"] | { schema: keyof Database },
TableName extends PublicTableNameOrOptions extends { schema: keyof Database }
? keyof Database[PublicTableNameOrOptions["schema"]]["Tables"]
: never = never
> = PublicTableNameOrOptions extends { schema: keyof Database }
? Database[PublicTableNameOrOptions["schema"]]["Tables"][TableName] extends {
Insert: infer I
}
? I
: never
: PublicTableNameOrOptions extends keyof PublicSchema["Tables"]
? PublicSchema["Tables"][PublicTableNameOrOptions] extends {
Insert: infer I
}
? I
: never
: never
export type TablesUpdate<
PublicTableNameOrOptions extends keyof PublicSchema["Tables"] | { schema: keyof Database },
TableName extends PublicTableNameOrOptions extends { schema: keyof Database }
? keyof Database[PublicTableNameOrOptions["schema"]]["Tables"]
: never = never
> = PublicTableNameOrOptions extends { schema: keyof Database }
? Database[PublicTableNameOrOptions["schema"]]["Tables"][TableName] extends {
Update: infer U
}
? U
: never
: PublicTableNameOrOptions extends keyof PublicSchema["Tables"]
? PublicSchema["Tables"][PublicTableNameOrOptions] extends {
Update: infer U
}
? U
: never
: never
export type Enums<
PublicEnumNameOrOptions extends keyof PublicSchema["Enums"] | { schema: keyof Database },
EnumName extends PublicEnumNameOrOptions extends { schema: keyof Database }
? keyof Database[PublicEnumNameOrOptions["schema"]]["Enums"]
: never = never
> = PublicEnumNameOrOptions extends { schema: keyof Database }
? Database[PublicEnumNameOrOptions["schema"]]["Enums"][EnumName]
: PublicEnumNameOrOptions extends keyof PublicSchema["Enums"]
? PublicSchema["Enums"][PublicEnumNameOrOptions]
: never
export type CompositeTypes<
PublicCompositeTypeNameOrOptions extends
| keyof PublicSchema["CompositeTypes"]
| { schema: keyof Database },
CompositeTypeName extends PublicCompositeTypeNameOrOptions extends {
schema: keyof Database
}
? keyof Database[PublicCompositeTypeNameOrOptions["schema"]]["CompositeTypes"]
: never = never
> = PublicCompositeTypeNameOrOptions extends { schema: keyof Database }
? Database[PublicCompositeTypeNameOrOptions["schema"]]["CompositeTypes"][CompositeTypeName]
: PublicCompositeTypeNameOrOptions extends keyof PublicSchema["CompositeTypes"]
? PublicSchema["CompositeTypes"][PublicCompositeTypeNameOrOptions]
: never

View File

@ -0,0 +1,10 @@
import { createClient } from "@supabase/supabase-js"
import type { Database } from "./database.types"
// export function createSB(supabaseUrl: string, supabaseAnonKey: string) {
// return createClient<Database>(supabaseUrl, supabaseAnonKey, {
// auth: {
// flowType: "pkce"
// }
// })
// }

View File

@ -0,0 +1,44 @@
/**
* @module @kksh/supabase/models
* This module contains some models for supabase database that cannot be code generated, such as JSON fields.
*/
import { Icon } from "@kksh/api/models"
import * as v from "valibot"
export enum ExtPublishSourceTypeEnum {
jsr = "jsr",
npm = "npm"
}
export const ExtPublishMetadata = v.object({
source: v.optional(v.string("Source of the extension (e.g. url to package)")),
sourceType: v.optional(v.enum(ExtPublishSourceTypeEnum)),
rekorLogIndex: v.optional(v.string("Rekor log index of the extension")),
git: v.optional(
v.object({
githubActionInvocationId: v.string("GitHub action invocation ID"),
repo: v.string("GitHub repo of the extension"),
owner: v.string("GitHub owner of the extension"),
commit: v.string("Commit hash of the extension"),
workflowPath: v.string("Workflow path of the extension")
})
)
})
export type ExtPublishMetadata = v.InferOutput<typeof ExtPublishMetadata>
/***
* Correspond to `extensions` table in supabase
*/
export const SBExt = v.object({
identifier: v.string(),
name: v.string(),
created_at: v.string(),
downloads: v.number(),
short_description: v.string(),
long_description: v.string(),
version: v.string(),
api_version: v.optional(v.string()),
icon: Icon
})
export type SBExt = v.InferOutput<typeof SBExt>

View File

@ -0,0 +1,27 @@
{
"compilerOptions": {
// Enable latest features
"lib": ["ESNext", "DOM"],
"target": "ESNext",
"module": "ESNext",
"moduleDetection": "force",
"jsx": "react-jsx",
"allowJs": true,
// Bundler mode
"moduleResolution": "bundler",
"allowImportingTsExtensions": true,
"verbatimModuleSyntax": true,
"noEmit": true,
// Best practices
"strict": true,
"skipLibCheck": true,
"noFallthroughCasesInSwitch": true,
// Some stricter flags (disabled by default)
"noUnusedLocals": false,
"noUnusedParameters": false,
"noPropertyAccessFromIndexSignature": false
}
}

View File

@ -6,6 +6,7 @@
"prepare": "bun setup.ts" "prepare": "bun setup.ts"
}, },
"devDependencies": { "devDependencies": {
"@kksh/supabase": "workspace:*",
"@supabase/supabase-js": "^2.48.0", "@supabase/supabase-js": "^2.48.0",
"@kksh/ci": "workspace:*", "@kksh/ci": "workspace:*",
"@types/bun": "latest" "@types/bun": "latest"

View File

@ -1,3 +1,4 @@
## Permission Table ## Permission Table
<table> <table>
@ -6,6 +7,7 @@
<th>Description</th> <th>Description</th>
</tr> </tr>
<tr> <tr>
<td> <td>

View File

@ -1,11 +1,12 @@
import { writeFileSync } from "fs" import { writeFileSync } from "fs"
import { type Database } from "@kksh/supabase/types"
import { createClient } from "@supabase/supabase-js" import { createClient } from "@supabase/supabase-js"
if (!process.env.SUPABASE_URL || !process.env.SUPABASE_ANON_KEY) { if (!process.env.SUPABASE_URL || !process.env.SUPABASE_ANON_KEY) {
throw new Error("SUPABASE_URL and SUPABASE_ANON_KEY must be set") throw new Error("SUPABASE_URL and SUPABASE_ANON_KEY must be set")
} }
const supabase = createClient(process.env.SUPABASE_URL, process.env.SUPABASE_ANON_KEY) const supabase = createClient<Database>(process.env.SUPABASE_URL, process.env.SUPABASE_ANON_KEY)
const { data, error } = await supabase.storage.from("pub").download("server_public_key.pem") const { data, error } = await supabase.storage.from("pub").download("server_public_key.pem")
if (error) { if (error) {

View File

@ -11,6 +11,8 @@
"@kksh/desktop": ["./apps/desktop"], "@kksh/desktop": ["./apps/desktop"],
"@kksh/ci/*": ["./packages/ci/*"], "@kksh/ci/*": ["./packages/ci/*"],
"@kksh/ci": ["./packages/ci"], "@kksh/ci": ["./packages/ci"],
"@kksh/supabase/*": ["./packages/supabase/*"],
"@kksh/supabase": ["./packages/supabase"],
"@kksh/schema/*": ["./packages/schema/*"], "@kksh/schema/*": ["./packages/schema/*"],
"@kksh/schema": ["./packages/schema"] "@kksh/schema": ["./packages/schema"]
} }

View File

@ -78,6 +78,7 @@
"@formkit/auto-animate": "^0.8.2", "@formkit/auto-animate": "^0.8.2",
"@inlang/paraglide-sveltekit": "^0.15.5", "@inlang/paraglide-sveltekit": "^0.15.5",
"@internationalized/date": "^3.7.0", "@internationalized/date": "^3.7.0",
"@kksh/supabase": "workspace:*",
"@shikijs/langs": "^2.3.2", "@shikijs/langs": "^2.3.2",
"@shikijs/rehype": "^3.2.1", "@shikijs/rehype": "^3.2.1",
"@shikijs/themes": "^2.3.2", "@shikijs/themes": "^2.3.2",
@ -96,8 +97,8 @@
"remark-math": "^6.0.0", "remark-math": "^6.0.0",
"shiki-magic-move": "^0.5.2", "shiki-magic-move": "^0.5.2",
"svelte-exmarkdown": "^4.0.3", "svelte-exmarkdown": "^4.0.3",
"svelte-inspect-value": "^0.5.0", "svelte-inspect-value": "^0.3.0",
"svelte-motion": "^0.12.2", "svelte-motion": "^0.12.2",
"valibot": "^1.0.0" "valibot": "^1.0.0-rc.4"
} }
} }

View File

@ -12,7 +12,8 @@
// let className = "" // let className = ""
// export { className as class } // export { className as class }
let { locations, class: className }: { class?: string; locations?: [number, number][] } = $props() let { locations = [], class: className }: { class?: string; locations?: [number, number][] } =
$props()
let pointerInteracting: number | null = null let pointerInteracting: number | null = null
let pointerInteractionMovement = 0 let pointerInteractionMovement = 0
let canvas: HTMLCanvasElement let canvas: HTMLCanvasElement
@ -53,25 +54,24 @@
baseColor: [0.3, 0.3, 0.3], baseColor: [0.3, 0.3, 0.3],
markerColor: [251 / 255, 100 / 255, 21 / 255], markerColor: [251 / 255, 100 / 255, 21 / 255],
glowColor: [1, 1, 1], glowColor: [1, 1, 1],
markers: locations markers: locations.map((location) => {
? locations.map((location) => {
return { return {
location: location, location: location,
size: 0.03 size: 0.03
} }
}) }),
: [ // [
{ location: [14.5995, 120.9842], size: 0.03 }, // { location: [14.5995, 120.9842], size: 0.03 },
{ location: [19.076, 72.8777], size: 0.03 }, // { location: [19.076, 72.8777], size: 0.03 },
{ location: [23.8103, 90.4125], size: 0.05 }, // { location: [23.8103, 90.4125], size: 0.05 },
{ location: [30.0444, 31.2357], size: 0.07 }, // { location: [30.0444, 31.2357], size: 0.07 },
{ location: [39.9042, 116.4074], size: 0.08 }, // { location: [39.9042, 116.4074], size: 0.08 },
{ location: [-23.5505, -46.6333], size: 0.05 }, // { location: [-23.5505, -46.6333], size: 0.05 },
{ location: [19.4326, -99.1332], size: 0.04 }, // { location: [19.4326, -99.1332], size: 0.04 },
{ location: [40.7128, -74.006], size: 0.1 }, // { location: [40.7128, -74.006], size: 0.1 },
{ location: [34.6937, 135.5022], size: 0.05 }, // { location: [34.6937, 135.5022], size: 0.05 },
{ location: [41.0082, 28.9784], size: 0.06 } // { location: [41.0082, 28.9784], size: 0.06 }
], // ],
// onRender: (state) => { // onRender: (state) => {
// if (!pointerInteracting) { // if (!pointerInteracting) {
// // Called on every animation frame. // // Called on every animation frame.

View File

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

View File

@ -16,7 +16,7 @@
style?: HTMLAttributes<HTMLAnchorElement>["style"] style?: HTMLAttributes<HTMLAnchorElement>["style"]
class?: HTMLAttributes<HTMLAnchorElement>["class"] class?: HTMLAttributes<HTMLAnchorElement>["class"]
children: Snippet children: Snippet
ref?: HTMLAnchorElement | HTMLButtonElement | null ref: HTMLAnchorElement | HTMLButtonElement | null
} = $props() } = $props()
// @ts-expect-error window.__TAURI_INTERNALS__ is not defined in the browser // @ts-expect-error window.__TAURI_INTERNALS__ is not defined in the browser

View File

@ -1,6 +1,7 @@
<script lang="ts"> <script lang="ts">
import Icon from "@iconify/svelte" import Icon from "@iconify/svelte"
import { ExtData, ExtensionStoreListItem, Icon as TIcon } from "@kksh/api/models" import { ExtData, Icon as TIcon } from "@kksh/api/models"
import { SBExt } from "@kksh/supabase/models"
import { Button, Command } from "@kksh/svelte5" import { Button, Command } from "@kksh/svelte5"
import { Constants, IconMultiplexer } from "@kksh/ui" import { Constants, IconMultiplexer } from "@kksh/ui"
import { cn, humanReadableNumber } from "@kksh/ui/utils" import { cn, humanReadableNumber } from "@kksh/ui/utils"
@ -18,7 +19,7 @@
class: className class: className
}: { }: {
class?: string class?: string
ext: ExtensionStoreListItem ext: SBExt
installedVersion?: string installedVersion?: string
onSelect: () => void onSelect: () => void
onUpgrade: () => void onUpgrade: () => void

View File

@ -19,7 +19,6 @@
} = $props() } = $props()
const workflowRunId = githubActionInvocationId.split("/").at(-3) const workflowRunId = githubActionInvocationId.split("/").at(-3)
const workflowRunUrl = `https://github.com/${repoOwner}/${repoName}/actions/runs/${workflowRunId}/workflow` const workflowRunUrl = `https://github.com/${repoOwner}/${repoName}/actions/runs/${workflowRunId}/workflow`
const giteaMirrorUrl = `https://gitea.kunkun.sh/kunkun-extensions-mirror/${repoOwner}-${repoName}`
</script> </script>
<Card.Root> <Card.Root>
@ -61,12 +60,6 @@
class="underline">Transparentcy log entry</a class="underline">Transparentcy log entry</a
> >
</p> </p>
<p class="flex flex-col text-sm sm:flex-row">
<strong class="mt-2 inline-block w-28 md:mt-0">Mirror</strong>
<a href={giteaMirrorUrl} target="_blank" rel="noreferrer" class="underline">
Mirror Repo
</a>
</p>
</div> </div>
</Card.Content> </Card.Content>
</Card.Root> </Card.Root>

View File

@ -1,20 +1,20 @@
<script lang="ts"> <script lang="ts">
import { IconEnum, PermissionUnion, type KunkunExtManifest } from "@kksh/api/models" import { IconEnum, 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 {
permissions, manifest,
class: className class: className
}: { }: {
permissions?: PermissionUnion[] manifest: KunkunExtManifest
class?: string class?: string
} = $props() } = $props()
</script> </script>
<ul class={className}> <ul class={className}>
{#each permissions || [] as perm} {#each manifest?.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

@ -1,15 +1,10 @@
<script lang="ts"> <script lang="ts">
import autoAnimate from "@formkit/auto-animate" import autoAnimate from "@formkit/auto-animate"
import Icon from "@iconify/svelte" import Icon from "@iconify/svelte"
import { import { ExtPackageJson, IconEnum, KunkunExtManifest } from "@kksh/api/models"
ExtPackageJson, import { ExtPublishMetadata, ExtPublishSourceTypeEnum } from "@kksh/supabase/models"
ExtPublish, import { type Tables } from "@kksh/supabase/types"
ExtPublishMetadata, import { Badge, Button, ScrollArea, Separator } from "@kksh/svelte5"
ExtPublishSourceTypeEnum,
IconEnum,
KunkunExtManifest
} from "@kksh/api/models"
import { Badge, Button, ScrollArea, Separator, Tooltip } from "@kksh/svelte5"
import { Constants, IconMultiplexer } from "@kksh/ui" import { Constants, IconMultiplexer } from "@kksh/ui"
import { cn } from "@kksh/ui/utils" import { cn } from "@kksh/ui/utils"
import { CircleCheckBigIcon, MoveRightIcon, Trash2Icon } from "lucide-svelte" import { CircleCheckBigIcon, MoveRightIcon, Trash2Icon } from "lucide-svelte"
@ -41,12 +36,8 @@
loading, loading,
imageDialogOpen = $bindable(false) imageDialogOpen = $bindable(false)
}: { }: {
extPublish: ExtPublish extPublish: Tables<"ext_publish">
// extPublish: GetExtensionsLatestPublishByIdentifierResponse ext: Tables<"extensions">
ext: {
author_id: string
downloads: number
}
author?: { author?: {
id: string id: string
name: string name: string
@ -195,7 +186,7 @@
<Button onclick={onInstallSelected}>Install</Button> <Button onclick={onInstallSelected}>Install</Button>
{/if} {/if}
</div> </div>
<div class="mt-2 flex flex-col gap-2 md:flex-row"> <div class="mt-2 flex gap-2">
{#if metadata && metadata.sourceType === ExtPublishSourceTypeEnum.jsr} {#if metadata && metadata.sourceType === ExtPublishSourceTypeEnum.jsr}
<a href={metadata.source} target="_blank"> <a href={metadata.source} target="_blank">
<Icon class="h-10 w-10" icon="vscode-icons:file-type-jsr" /> <Icon class="h-10 w-10" icon="vscode-icons:file-type-jsr" />
@ -210,7 +201,7 @@
href={`https://github.com/${metadata.git.owner}/${metadata.git.repo}/tree/${metadata.git.commit}`} href={`https://github.com/${metadata.git.owner}/${metadata.git.repo}/tree/${metadata.git.commit}`}
target="_blank" target="_blank"
> >
<Badge class="min-h-8 space-x-2" variant="secondary"> <Badge class="h-8 space-x-2" variant="secondary">
<Icon class="h-6 w-6" icon="mdi:github" /> <Icon class="h-6 w-6" icon="mdi:github" />
<span>{metadata.git.owner}/{metadata.git.repo}</span> <span>{metadata.git.owner}/{metadata.git.repo}</span>
</Badge> </Badge>
@ -257,7 +248,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 permissions={manifest.permissions} /> <PermissionInspector {manifest} />
<Separator class="my-3" /> <Separator class="my-3" />
<h2 class="text-lg font-bold">Description</h2> <h2 class="text-lg font-bold">Description</h2>
@ -279,7 +270,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>

251
pnpm-lock.yaml generated
View File

@ -11,15 +11,9 @@ 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':
specifier: ^0.0.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
@ -78,8 +72,8 @@ importers:
specifier: workspace:* specifier: workspace:*
version: link:vendors/tauri-plugin-system-info version: link:vendors/tauri-plugin-system-info
valibot: valibot:
specifier: ^1.0.0 specifier: ^1.0.0-rc.4
version: 1.0.0(typescript@5.7.3) version: 1.0.0-rc.4(typescript@5.7.3)
zod: zod:
specifier: ^3.24.2 specifier: ^3.24.2
version: 3.24.2 version: 3.24.2
@ -145,12 +139,12 @@ importers:
specifier: ^5.7.2 specifier: ^5.7.2
version: 5.7.3 version: 5.7.3
valibot: valibot:
specifier: ^1.0.0 specifier: ^1.0.0-rc.4
version: 1.0.0(typescript@5.7.3) version: 1.0.0-rc.4(typescript@5.7.3)
devDependencies: devDependencies:
'@types/bun': '@types/bun':
specifier: latest specifier: latest
version: 1.2.6 version: 1.2.5
'@types/debug': '@types/debug':
specifier: ^4.1.12 specifier: ^4.1.12
version: 4.1.12 version: 4.1.12
@ -185,12 +179,12 @@ importers:
specifier: ^5.0.0 specifier: ^5.0.0
version: 5.7.3 version: 5.7.3
valibot: valibot:
specifier: ^1.0.0 specifier: ^1.0.0-rc.4
version: 1.0.0(typescript@5.7.3) version: 1.0.0-rc.4(typescript@5.7.3)
devDependencies: devDependencies:
'@types/bun': '@types/bun':
specifier: latest specifier: latest
version: 1.2.6 version: 1.2.5
'@types/fs-extra': '@types/fs-extra':
specifier: ^11.0.4 specifier: ^11.0.4
version: 11.0.4 version: 11.0.4
@ -218,6 +212,9 @@ importers:
'@kksh/extension': '@kksh/extension':
specifier: workspace:* specifier: workspace:*
version: link:../../packages/extension version: link:../../packages/extension
'@kksh/supabase':
specifier: workspace:*
version: link:../../packages/supabase
'@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)(tsx@4.19.3)(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)(tsx@4.19.3)(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)(tsx@4.19.3)(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)(tsx@4.19.3)(yaml@2.6.1)))(@types/json-schema@7.0.15)(svelte@5.20.5)(typescript@5.6.3))(typescript@5.6.3)
@ -256,7 +253,7 @@ importers:
version: 3.2.4 version: 3.2.4
drizzle-orm: drizzle-orm:
specifier: ^0.40.1 specifier: ^0.40.1
version: 0.40.1(@libsql/client@0.15.0)(bun-types@1.2.6)(gel@2.0.1) version: 0.40.1(@libsql/client@0.15.0)(bun-types@1.2.5)(gel@2.0.1)
eslint: eslint:
specifier: ^9.21.0 specifier: ^9.21.0
version: 9.21.0(jiti@2.4.0) version: 9.21.0(jiti@2.4.0)
@ -279,8 +276,8 @@ importers:
specifier: ^7.7.1 specifier: ^7.7.1
version: 7.7.1 version: 7.7.1
svelte-inspect-value: svelte-inspect-value:
specifier: ^0.5.0 specifier: ^0.3.0
version: 0.5.0(svelte@5.20.5) version: 0.3.0(svelte@5.20.5)
svelte-sonner: svelte-sonner:
specifier: ^0.3.28 specifier: ^0.3.28
version: 0.3.28(svelte@5.20.5) version: 0.3.28(svelte@5.20.5)
@ -338,7 +335,7 @@ importers:
version: 2.3.1 version: 2.3.1
'@types/bun': '@types/bun':
specifier: latest specifier: latest
version: 1.2.6 version: 1.2.5
'@types/semver': '@types/semver':
specifier: ^7.5.8 specifier: ^7.5.8
version: 7.5.8 version: 7.5.8
@ -484,12 +481,12 @@ importers:
specifier: 2.0.8 specifier: 2.0.8
version: 2.0.8(typescript@5.7.2) version: 2.0.8(typescript@5.7.2)
valibot: valibot:
specifier: ^1.0.0 specifier: ^1.0.0-rc.4
version: 1.0.0(typescript@5.7.2) version: 1.0.0-rc.4(typescript@5.7.2)
devDependencies: devDependencies:
'@types/bun': '@types/bun':
specifier: latest specifier: latest
version: 1.2.6 version: 1.2.5
'@types/lodash': '@types/lodash':
specifier: ^4.17.14 specifier: ^4.17.14
version: 4.17.14 version: 4.17.14
@ -529,7 +526,7 @@ importers:
version: link:../typescript-config version: link:../typescript-config
'@types/bun': '@types/bun':
specifier: latest specifier: latest
version: 1.2.6 version: 1.2.5
packages/config-eslint: packages/config-eslint:
dependencies: dependencies:
@ -559,14 +556,14 @@ importers:
version: 16.4.7 version: 16.4.7
drizzle-orm: drizzle-orm:
specifier: ^0.40.1 specifier: ^0.40.1
version: 0.40.1(@libsql/client@0.15.0)(bun-types@1.2.6)(gel@2.0.1) version: 0.40.1(@libsql/client@0.15.0)(bun-types@1.2.5)(gel@2.0.1)
typescript: typescript:
specifier: ^5 specifier: ^5
version: 5.7.3 version: 5.7.3
devDependencies: devDependencies:
'@types/bun': '@types/bun':
specifier: latest specifier: latest
version: 1.2.6 version: 1.2.5
drizzle-kit: drizzle-kit:
specifier: ^0.30.5 specifier: ^0.30.5
version: 0.30.5 version: 0.30.5
@ -579,8 +576,11 @@ importers:
'@kksh/api': '@kksh/api':
specifier: workspace:* specifier: workspace:*
version: link:../api version: link:../api
'@kksh/supabase':
specifier: workspace:*
version: link:../supabase
'@std/semver': '@std/semver':
specifier: npm:@jsr/std__semver@^1.0.4 specifier: npm:@jsr/std__semver@^1.0.3
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
@ -592,15 +592,12 @@ importers:
specifier: ^5.0.0 specifier: ^5.0.0
version: 5.5.4 version: 5.5.4
uuid: uuid:
specifier: ^11.1.0 specifier: ^11.0.3
version: 11.1.0 version: 11.0.3
devDependencies: devDependencies:
'@types/bun': '@types/bun':
specifier: latest specifier: latest
version: 1.2.6 version: 1.2.5
'@types/semver':
specifier: ^7.5.8
version: 7.5.8
packages/extensions/demo-worker-template-ext: packages/extensions/demo-worker-template-ext:
dependencies: dependencies:
@ -628,7 +625,7 @@ importers:
version: 11.1.6(rollup@4.34.2)(tslib@2.8.1)(typescript@5.7.3) version: 11.1.6(rollup@4.34.2)(tslib@2.8.1)(typescript@5.7.3)
'@types/bun': '@types/bun':
specifier: latest specifier: latest
version: 1.2.6 version: 1.2.5
rollup-plugin-visualizer: rollup-plugin-visualizer:
specifier: ^5.12.0 specifier: ^5.12.0
version: 5.12.0(rollup@4.34.2) version: 5.12.0(rollup@4.34.2)
@ -735,7 +732,7 @@ importers:
devDependencies: devDependencies:
'@types/bun': '@types/bun':
specifier: latest specifier: latest
version: 1.2.6 version: 1.2.5
packages/grpc: packages/grpc:
dependencies: dependencies:
@ -754,7 +751,7 @@ importers:
version: 0.7.13 version: 0.7.13
'@types/bun': '@types/bun':
specifier: latest specifier: latest
version: 1.2.6 version: 1.2.5
'@types/google-protobuf': '@types/google-protobuf':
specifier: ^3.15.12 specifier: ^3.15.12
version: 3.15.12 version: 3.15.12
@ -782,7 +779,7 @@ importers:
devDependencies: devDependencies:
'@types/bun': '@types/bun':
specifier: latest specifier: latest
version: 1.2.6 version: 1.2.5
verify-package-export: verify-package-export:
specifier: ^0.0.3 specifier: ^0.0.3
version: 0.0.3(typescript@5.7.3) version: 0.0.3(typescript@5.7.3)
@ -799,18 +796,40 @@ importers:
specifier: ^5.0.0 specifier: ^5.0.0
version: 5.7.3 version: 5.7.3
valibot: valibot:
specifier: ^1.0.0 specifier: ^1.0.0-rc.4
version: 1.0.0(typescript@5.7.3) version: 1.0.0-rc.4(typescript@5.7.3)
devDependencies: devDependencies:
'@kksh/supabase':
specifier: workspace:*
version: link:../supabase
'@supabase/supabase-js': '@supabase/supabase-js':
specifier: ^2.48.0 specifier: ^2.48.0
version: 2.48.0 version: 2.48.0
'@types/bun': '@types/bun':
specifier: latest specifier: latest
version: 1.2.6 version: 1.2.5
'@valibot/to-json-schema': '@valibot/to-json-schema':
specifier: 1.0.0 specifier: 1.0.0-beta.4
version: 1.0.0(valibot@1.0.0(typescript@5.7.3)) version: 1.0.0-beta.4(valibot@1.0.0-rc.4(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.5
packages/svelte-animation: packages/svelte-animation:
dependencies: dependencies:
@ -820,7 +839,7 @@ importers:
devDependencies: devDependencies:
'@types/bun': '@types/bun':
specifier: latest specifier: latest
version: 1.2.6 version: 1.2.5
packages/tauri-plugins/jarvis: packages/tauri-plugins/jarvis:
dependencies: dependencies:
@ -831,12 +850,15 @@ importers:
'@kksh/ci': '@kksh/ci':
specifier: workspace:* specifier: workspace:*
version: link:../../ci version: link:../../ci
'@kksh/supabase':
specifier: workspace:*
version: link:../../supabase
'@supabase/supabase-js': '@supabase/supabase-js':
specifier: ^2.48.0 specifier: ^2.48.0
version: 2.48.0 version: 2.48.0
'@types/bun': '@types/bun':
specifier: latest specifier: latest
version: 1.2.6 version: 1.2.5
packages/templates/template-ext-headless: packages/templates/template-ext-headless:
dependencies: dependencies:
@ -855,7 +877,7 @@ importers:
devDependencies: devDependencies:
'@types/bun': '@types/bun':
specifier: latest specifier: latest
version: 1.2.6 version: 1.2.5
packages/templates/template-ext-next: packages/templates/template-ext-next:
dependencies: dependencies:
@ -919,7 +941,7 @@ importers:
version: 6.12.1(magicast@0.3.5)(rollup@4.34.2) version: 6.12.1(magicast@0.3.5)(rollup@4.34.2)
nuxt: nuxt:
specifier: ^3.12.4 specifier: ^3.12.4
version: 3.14.159(@libsql/client@0.15.0)(@parcel/watcher@2.5.0)(@types/node@22.13.1)(drizzle-orm@0.40.1(@libsql/client@0.15.0)(bun-types@1.2.6)(gel@2.0.1))(eslint@9.21.0(jiti@2.4.0))(ioredis@5.4.1)(magicast@0.3.5)(optionator@0.9.4)(rollup@4.34.2)(terser@5.36.0)(typescript@5.6.3)(vite@5.4.11(@types/node@22.13.1)(terser@5.36.0))(vue-tsc@2.1.10(typescript@5.6.3)) version: 3.14.159(@libsql/client@0.15.0)(@parcel/watcher@2.5.0)(@types/node@22.13.1)(drizzle-orm@0.40.1(@libsql/client@0.15.0)(bun-types@1.2.5)(gel@2.0.1))(eslint@9.21.0(jiti@2.4.0))(ioredis@5.4.1)(magicast@0.3.5)(optionator@0.9.4)(rollup@4.34.2)(terser@5.36.0)(typescript@5.6.3)(vite@5.4.11(@types/node@22.13.1)(terser@5.36.0))(vue-tsc@2.1.10(typescript@5.6.3))
tailwindcss: tailwindcss:
specifier: ^3.4.7 specifier: ^3.4.7
version: 3.4.15 version: 3.4.15
@ -1207,7 +1229,7 @@ importers:
devDependencies: devDependencies:
'@types/bun': '@types/bun':
specifier: latest specifier: latest
version: 1.2.6 version: 1.2.5
packages/types: packages/types:
dependencies: dependencies:
@ -1217,7 +1239,7 @@ importers:
devDependencies: devDependencies:
'@types/bun': '@types/bun':
specifier: latest specifier: latest
version: 1.2.6 version: 1.2.5
packages/typescript-config: {} packages/typescript-config: {}
@ -1232,6 +1254,9 @@ importers:
'@internationalized/date': '@internationalized/date':
specifier: ^3.7.0 specifier: ^3.7.0
version: 3.7.0 version: 3.7.0
'@kksh/supabase':
specifier: workspace:*
version: link:../supabase
'@shikijs/langs': '@shikijs/langs':
specifier: ^2.3.2 specifier: ^2.3.2
version: 2.3.2 version: 2.3.2
@ -1290,14 +1315,14 @@ importers:
specifier: ^4.0.3 specifier: ^4.0.3
version: 4.0.3(svelte@5.20.5) version: 4.0.3(svelte@5.20.5)
svelte-inspect-value: svelte-inspect-value:
specifier: ^0.5.0 specifier: ^0.3.0
version: 0.5.0(svelte@5.20.5) version: 0.3.0(svelte@5.20.5)
svelte-motion: svelte-motion:
specifier: ^0.12.2 specifier: ^0.12.2
version: 0.12.2(svelte@5.20.5) version: 0.12.2(svelte@5.20.5)
valibot: valibot:
specifier: ^1.0.0 specifier: ^1.0.0-rc.4
version: 1.0.0(typescript@5.7.3) version: 1.0.0-rc.4(typescript@5.7.3)
devDependencies: devDependencies:
'@eslint/js': '@eslint/js':
specifier: ^9.18.0 specifier: ^9.18.0
@ -1313,7 +1338,7 @@ importers:
version: 0.1.15(lucide-svelte@0.471.0(svelte@5.20.5))(svelte-sonner@0.3.28(svelte@5.20.5))(svelte@5.20.5)(sveltekit-superforms@2.22.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)(tsx@4.19.3)(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)(tsx@4.19.3)(yaml@2.6.1)))(@types/json-schema@7.0.15)(svelte@5.20.5)(typescript@5.7.3))(typescript@5.7.3) version: 0.1.15(lucide-svelte@0.471.0(svelte@5.20.5))(svelte-sonner@0.3.28(svelte@5.20.5))(svelte@5.20.5)(sveltekit-superforms@2.22.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)(tsx@4.19.3)(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)(tsx@4.19.3)(yaml@2.6.1)))(@types/json-schema@7.0.15)(svelte@5.20.5)(typescript@5.7.3))(typescript@5.7.3)
'@types/bun': '@types/bun':
specifier: latest specifier: latest
version: 1.2.6 version: 1.2.5
'@typescript-eslint/eslint-plugin': '@typescript-eslint/eslint-plugin':
specifier: ^8.20.0 specifier: ^8.20.0
version: 8.20.0(@typescript-eslint/parser@8.20.0(eslint@9.21.0(jiti@2.4.0))(typescript@5.7.3))(eslint@9.21.0(jiti@2.4.0))(typescript@5.7.3) version: 8.20.0(@typescript-eslint/parser@8.20.0(eslint@9.21.0(jiti@2.4.0))(typescript@5.7.3))(eslint@9.21.0(jiti@2.4.0))(typescript@5.7.3)
@ -1395,7 +1420,7 @@ importers:
devDependencies: devDependencies:
'@types/bun': '@types/bun':
specifier: latest specifier: latest
version: 1.2.6 version: 1.2.5
vendors/tauri-plugin-keyring: vendors/tauri-plugin-keyring:
dependencies: dependencies:
@ -1426,7 +1451,7 @@ importers:
version: 2.1.1 version: 2.1.1
valibot: valibot:
specifier: ^1.0.0-beta.10 specifier: ^1.0.0-beta.10
version: 1.0.0(typescript@5.6.3) version: 1.0.0-beta.10(typescript@5.6.3)
devDependencies: devDependencies:
'@rollup/plugin-typescript': '@rollup/plugin-typescript':
specifier: ^12.1.2 specifier: ^12.1.2
@ -1451,7 +1476,7 @@ importers:
version: 2.2.0 version: 2.2.0
valibot: valibot:
specifier: ^1.0.0-beta.10 specifier: ^1.0.0-beta.10
version: 1.0.0(typescript@5.7.2) version: 1.0.0-beta.10(typescript@5.7.2)
devDependencies: devDependencies:
'@rollup/plugin-typescript': '@rollup/plugin-typescript':
specifier: ^12.1.2 specifier: ^12.1.2
@ -2949,9 +2974,6 @@ 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:
@ -3311,12 +3333,6 @@ packages:
react: ^18.2.0 react: ^18.2.0
react-dom: ^18.2.0 react-dom: ^18.2.0
'@kksh/sdk@0.0.3':
resolution: {integrity: sha512-he5/VSiIfEuXQlGWGxoIurrq/wbddbvZiHbKIGAFTS1DljCHjnAjEajueCkz9M3sbn+WGylS8VSVAFSCWdCfPg==}
peerDependencies:
'@hey-api/client-fetch': ^0.8.3
typescript: ^5
'@kksh/svelte5@0.1.15': '@kksh/svelte5@0.1.15':
resolution: {integrity: sha512-Cr/gSWsnRtQIQLpQAkGBODujWn5g4LlhDp865skRV95tkrOuAwbbWGjG5+oWx1fK+fiDu+rhe2UCqw61SW2B/Q==} resolution: {integrity: sha512-Cr/gSWsnRtQIQLpQAkGBODujWn5g4LlhDp865skRV95tkrOuAwbbWGjG5+oWx1fK+fiDu+rhe2UCqw61SW2B/Q==}
peerDependencies: peerDependencies:
@ -5337,6 +5353,11 @@ 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==}
@ -5717,8 +5738,8 @@ packages:
'@types/btoa-lite@1.0.2': '@types/btoa-lite@1.0.2':
resolution: {integrity: sha512-ZYbcE2x7yrvNFJiU7xJGrpF/ihpkM7zKgw8bha3LNJSesvTtUNxbpzaT7WXBIryf6jovisrxTBvymxMeLLj1Mg==} resolution: {integrity: sha512-ZYbcE2x7yrvNFJiU7xJGrpF/ihpkM7zKgw8bha3LNJSesvTtUNxbpzaT7WXBIryf6jovisrxTBvymxMeLLj1Mg==}
'@types/bun@1.2.6': '@types/bun@1.2.5':
resolution: {integrity: sha512-fY9CAmTdJH1Llx7rugB0FpgWK2RKuHCs3g2cFDYXUutIy1QGiPQxKkGY8owhfZ4MXWNfxwIbQLChgH5gDsY7vw==} resolution: {integrity: sha512-w2OZTzrZTVtbnJew1pdFmgV99H0/L+Pvw+z1P67HaR18MHOzYnTYOi6qzErhK8HyT+DB782ADVPPE92Xu2/Opg==}
'@types/cookie@0.6.0': '@types/cookie@0.6.0':
resolution: {integrity: sha512-4Kh9a6B2bQciAhf7FSuMRRkUWecJgJu9nPnx3yzpsfXX/c50REIqpHY4C82bXP90qrLtXtkDxTZosYO3UpOwlA==} resolution: {integrity: sha512-4Kh9a6B2bQciAhf7FSuMRRkUWecJgJu9nPnx3yzpsfXX/c50REIqpHY4C82bXP90qrLtXtkDxTZosYO3UpOwlA==}
@ -6234,10 +6255,10 @@ packages:
'@unovis/ts': 1.4.4 '@unovis/ts': 1.4.4
vue: ^3 vue: ^3
'@valibot/to-json-schema@1.0.0': '@valibot/to-json-schema@1.0.0-beta.4':
resolution: {integrity: sha512-/9crJgPptVsGCL6X+JPDQyaJwkalSZ/52WuF8DiRUxJgcmpNdzYRfZ+gqMEP8W3CTVfuMWPqqvIgfwJ97f9Etw==} resolution: {integrity: sha512-wXBdCyoqec+NLCl5ihitXzZXD4JAjPK3+HfskSXzfhiNFvKje0A/v1LygqKidUgIbaJtREmq/poJGbaS/0MKuQ==}
peerDependencies: peerDependencies:
valibot: ^1.0.0 valibot: ^1.0.0 || ^1.0.0-beta.5 || ^1.0.0-rc
'@vee-validate/zod@4.14.7': '@vee-validate/zod@4.14.7':
resolution: {integrity: sha512-UD0Tfyz1cKKd7BinnUztqKL+oeMjg/T4ZEguN/uZV4DsR9z7gdrD0lOuOU7aVl9UpVK6NM7MhDka35Lj7b/DTw==} resolution: {integrity: sha512-UD0Tfyz1cKKd7BinnUztqKL+oeMjg/T4ZEguN/uZV4DsR9z7gdrD0lOuOU7aVl9UpVK6NM7MhDka35Lj7b/DTw==}
@ -6784,8 +6805,8 @@ packages:
buffer@6.0.3: buffer@6.0.3:
resolution: {integrity: sha512-FTiCpNxtwiZZHEZbcbTIcZjERVICn9yq/pDFkTl95/AxzD1naBctN7YO68riM/gLSDY7sdrMby8hofADYuuqOA==} resolution: {integrity: sha512-FTiCpNxtwiZZHEZbcbTIcZjERVICn9yq/pDFkTl95/AxzD1naBctN7YO68riM/gLSDY7sdrMby8hofADYuuqOA==}
bun-types@1.2.6: bun-types@1.2.5:
resolution: {integrity: sha512-FbCKyr5KDiPULUzN/nm5oqQs9nXCHD8dVc64BArxJadCvbNzAI6lUWGh9fSJZWeDIRD38ikceBU8Kj/Uh+53oQ==} resolution: {integrity: sha512-3oO6LVGGRRKI4kHINx5PIdIgnLRb7l/SprhzqXapmoYkFl5m4j6EvALvbDVuuBFaamB46Ap6HCUxIXNLCGy+tg==}
bundle-name@4.1.0: bundle-name@4.1.0:
resolution: {integrity: sha512-tjwM5exMg6BGRI+kNmTntNsvdZS1X8BFYS6tnJ2hdH0kVxM6/eVZ2xy+FqStSWvYmtfFMDLIxurorHwDKfDz5Q==} resolution: {integrity: sha512-tjwM5exMg6BGRI+kNmTntNsvdZS1X8BFYS6tnJ2hdH0kVxM6/eVZ2xy+FqStSWvYmtfFMDLIxurorHwDKfDz5Q==}
@ -7094,6 +7115,10 @@ 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'}
@ -9351,6 +9376,7 @@ packages:
libsql@0.5.1: libsql@0.5.1:
resolution: {integrity: sha512-ePnm5zj6T//GKiTY/v5b0a272NX73hqdRORmD8gzz1nUui9051dtTt6t0XCrIqxwJAHSmQiZcfAx3YSASn9Y+A==} resolution: {integrity: sha512-ePnm5zj6T//GKiTY/v5b0a272NX73hqdRORmD8gzz1nUui9051dtTt6t0XCrIqxwJAHSmQiZcfAx3YSASn9Y+A==}
cpu: [x64, arm64, wasm32]
os: [darwin, linux, win32] os: [darwin, linux, win32]
lilconfig@2.1.0: lilconfig@2.1.0:
@ -11715,8 +11741,8 @@ packages:
peerDependencies: peerDependencies:
svelte: ^5.1.3 svelte: ^5.1.3
svelte-inspect-value@0.5.0: svelte-inspect-value@0.3.0:
resolution: {integrity: sha512-ZWbu/TZl/gGAPe8Xjmg0YvERSpEC+q07HV8m0xhp51auTNh8mjaf07bcmcl0coBb0wnJqcAB4uWJ1GDdtGQrQw==} resolution: {integrity: sha512-nHv+7+FRePs86sgL2I8jlbSrs8/uJmHJ2uxnMk9tVipWdZYYcmGhsmU+7U8lm/1RAZFS63/xSKdceMDyE09y0A==}
peerDependencies: peerDependencies:
svelte: ^5.19.0 svelte: ^5.19.0
@ -12433,8 +12459,8 @@ packages:
typescript: typescript:
optional: true optional: true
valibot@1.0.0: valibot@1.0.0-beta.10:
resolution: {integrity: sha512-1Hc0ihzWxBar6NGeZv7fPLY0QuxFMyxwYR2sF1Blu7Wq7EnremwY2W02tit2ij2VJT8HcSkHAQqmFfl77f73Yw==} resolution: {integrity: sha512-nmo3nxvXRrxwDYZznK3aTgYv7ZA/SUZJ/s+pLY4Tqsex/fgwZ9XrrQ14jjozjUaeduQ9PhXHE2Xx1uMb0HePYw==}
peerDependencies: peerDependencies:
typescript: '>=5' typescript: '>=5'
peerDependenciesMeta: peerDependenciesMeta:
@ -12457,6 +12483,14 @@ packages:
typescript: typescript:
optional: true optional: true
valibot@1.0.0-rc.4:
resolution: {integrity: sha512-VRaChgFv7Ab0P54AMLu7+GqoexdTPQ54Plj59X9qV0AFozI3j9CGH43skg+TqgMpXnrW8jxlJ2TTHAtAD3t4qA==}
peerDependencies:
typescript: '>=5'
peerDependenciesMeta:
typescript:
optional: true
validate-npm-package-name@5.0.1: validate-npm-package-name@5.0.1:
resolution: {integrity: sha512-OljLrQ9SQdOUqTaQxqL5dEfZWrXExyyWsozYlAWFawPVNuD83igl7uJD2RTkNMbniIYgt8l81eCJGIdQF7avLQ==} resolution: {integrity: sha512-OljLrQ9SQdOUqTaQxqL5dEfZWrXExyyWsozYlAWFawPVNuD83igl7uJD2RTkNMbniIYgt8l81eCJGIdQF7avLQ==}
engines: {node: ^14.17.0 || ^16.13.0 || >=18.0.0} engines: {node: ^14.17.0 || ^16.13.0 || >=18.0.0}
@ -14610,8 +14644,6 @@ 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)
@ -15279,11 +15311,6 @@ snapshots:
- '@types/react-dom' - '@types/react-dom'
- tailwindcss - tailwindcss
'@kksh/sdk@0.0.3(@hey-api/client-fetch@0.8.3)(typescript@5.7.3)':
dependencies:
'@hey-api/client-fetch': 0.8.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)(tsx@4.19.3)(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)(tsx@4.19.3)(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)(tsx@4.19.3)(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)(tsx@4.19.3)(yaml@2.6.1)))(@types/json-schema@7.0.15)(svelte@5.16.6)(typescript@5.7.2))(typescript@5.7.2)':
dependencies: dependencies:
'@tanstack/table-core': 8.21.2 '@tanstack/table-core': 8.21.2
@ -17743,6 +17770,12 @@ 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
@ -18192,9 +18225,9 @@ snapshots:
'@types/btoa-lite@1.0.2': {} '@types/btoa-lite@1.0.2': {}
'@types/bun@1.2.6': '@types/bun@1.2.5':
dependencies: dependencies:
bun-types: 1.2.6 bun-types: 1.2.5
'@types/cookie@0.6.0': {} '@types/cookie@0.6.0': {}
@ -18972,9 +19005,9 @@ snapshots:
'@unovis/ts': 1.4.4 '@unovis/ts': 1.4.4
vue: 3.5.13(typescript@5.6.3) vue: 3.5.13(typescript@5.6.3)
'@valibot/to-json-schema@1.0.0(valibot@1.0.0(typescript@5.7.3))': '@valibot/to-json-schema@1.0.0-beta.4(valibot@1.0.0-rc.4(typescript@5.7.3))':
dependencies: dependencies:
valibot: 1.0.0(typescript@5.7.3) valibot: 1.0.0-rc.4(typescript@5.7.3)
'@vee-validate/zod@4.14.7(vue@3.5.13(typescript@5.6.3))': '@vee-validate/zod@4.14.7(vue@3.5.13(typescript@5.6.3))':
dependencies: dependencies:
@ -19736,7 +19769,7 @@ snapshots:
base64-js: 1.5.1 base64-js: 1.5.1
ieee754: 1.2.1 ieee754: 1.2.1
bun-types@1.2.6: bun-types@1.2.5:
dependencies: dependencies:
'@types/node': 22.13.1 '@types/node': 22.13.1
'@types/ws': 8.5.14 '@types/ws': 8.5.14
@ -20015,6 +20048,8 @@ 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
@ -20371,10 +20406,10 @@ snapshots:
dayjs@1.11.13: dayjs@1.11.13:
optional: true optional: true
db0@0.2.1(@libsql/client@0.15.0)(drizzle-orm@0.40.1(@libsql/client@0.15.0)(bun-types@1.2.6)(gel@2.0.1)): db0@0.2.1(@libsql/client@0.15.0)(drizzle-orm@0.40.1(@libsql/client@0.15.0)(bun-types@1.2.5)(gel@2.0.1)):
optionalDependencies: optionalDependencies:
'@libsql/client': 0.15.0 '@libsql/client': 0.15.0
drizzle-orm: 0.40.1(@libsql/client@0.15.0)(bun-types@1.2.6)(gel@2.0.1) drizzle-orm: 0.40.1(@libsql/client@0.15.0)(bun-types@1.2.5)(gel@2.0.1)
de-indent@1.0.2: {} de-indent@1.0.2: {}
@ -20631,10 +20666,10 @@ snapshots:
transitivePeerDependencies: transitivePeerDependencies:
- supports-color - supports-color
drizzle-orm@0.40.1(@libsql/client@0.15.0)(bun-types@1.2.6)(gel@2.0.1): drizzle-orm@0.40.1(@libsql/client@0.15.0)(bun-types@1.2.5)(gel@2.0.1):
optionalDependencies: optionalDependencies:
'@libsql/client': 0.15.0 '@libsql/client': 0.15.0
bun-types: 1.2.6 bun-types: 1.2.5
gel: 2.0.1 gel: 2.0.1
duplexer@0.1.2: {} duplexer@0.1.2: {}
@ -23466,7 +23501,7 @@ snapshots:
- '@babel/core' - '@babel/core'
- babel-plugin-macros - babel-plugin-macros
nitropack@2.10.4(@libsql/client@0.15.0)(drizzle-orm@0.40.1(@libsql/client@0.15.0)(bun-types@1.2.6)(gel@2.0.1))(typescript@5.6.3): nitropack@2.10.4(@libsql/client@0.15.0)(drizzle-orm@0.40.1(@libsql/client@0.15.0)(bun-types@1.2.5)(gel@2.0.1))(typescript@5.6.3):
dependencies: dependencies:
'@cloudflare/kv-asset-handler': 0.3.4 '@cloudflare/kv-asset-handler': 0.3.4
'@netlify/functions': 2.8.2 '@netlify/functions': 2.8.2
@ -23490,7 +23525,7 @@ snapshots:
cookie-es: 1.2.2 cookie-es: 1.2.2
croner: 9.0.0 croner: 9.0.0
crossws: 0.3.1 crossws: 0.3.1
db0: 0.2.1(@libsql/client@0.15.0)(drizzle-orm@0.40.1(@libsql/client@0.15.0)(bun-types@1.2.6)(gel@2.0.1)) db0: 0.2.1(@libsql/client@0.15.0)(drizzle-orm@0.40.1(@libsql/client@0.15.0)(bun-types@1.2.5)(gel@2.0.1))
defu: 6.1.4 defu: 6.1.4
destr: 2.0.3 destr: 2.0.3
dot-prop: 9.0.0 dot-prop: 9.0.0
@ -23627,7 +23662,7 @@ snapshots:
nuxi@3.15.0: {} nuxi@3.15.0: {}
nuxt@3.14.159(@libsql/client@0.15.0)(@parcel/watcher@2.5.0)(@types/node@22.13.1)(drizzle-orm@0.40.1(@libsql/client@0.15.0)(bun-types@1.2.6)(gel@2.0.1))(eslint@9.21.0(jiti@2.4.0))(ioredis@5.4.1)(magicast@0.3.5)(optionator@0.9.4)(rollup@4.34.2)(terser@5.36.0)(typescript@5.6.3)(vite@5.4.11(@types/node@22.13.1)(terser@5.36.0))(vue-tsc@2.1.10(typescript@5.6.3)): nuxt@3.14.159(@libsql/client@0.15.0)(@parcel/watcher@2.5.0)(@types/node@22.13.1)(drizzle-orm@0.40.1(@libsql/client@0.15.0)(bun-types@1.2.5)(gel@2.0.1))(eslint@9.21.0(jiti@2.4.0))(ioredis@5.4.1)(magicast@0.3.5)(optionator@0.9.4)(rollup@4.34.2)(terser@5.36.0)(typescript@5.6.3)(vite@5.4.11(@types/node@22.13.1)(terser@5.36.0))(vue-tsc@2.1.10(typescript@5.6.3)):
dependencies: dependencies:
'@nuxt/devalue': 2.0.2 '@nuxt/devalue': 2.0.2
'@nuxt/devtools': 1.6.0(rollup@4.34.2)(vite@5.4.11(@types/node@22.13.1)(terser@5.36.0))(vue@3.5.13(typescript@5.6.3)) '@nuxt/devtools': 1.6.0(rollup@4.34.2)(vite@5.4.11(@types/node@22.13.1)(terser@5.36.0))(vue@3.5.13(typescript@5.6.3))
@ -23664,7 +23699,7 @@ snapshots:
magic-string: 0.30.12 magic-string: 0.30.12
mlly: 1.7.3 mlly: 1.7.3
nanotar: 0.1.1 nanotar: 0.1.1
nitropack: 2.10.4(@libsql/client@0.15.0)(drizzle-orm@0.40.1(@libsql/client@0.15.0)(bun-types@1.2.6)(gel@2.0.1))(typescript@5.6.3) nitropack: 2.10.4(@libsql/client@0.15.0)(drizzle-orm@0.40.1(@libsql/client@0.15.0)(bun-types@1.2.5)(gel@2.0.1))(typescript@5.6.3)
nuxi: 3.15.0 nuxi: 3.15.0
nypm: 0.3.12 nypm: 0.3.12
ofetch: 1.4.1 ofetch: 1.4.1
@ -25530,7 +25565,7 @@ snapshots:
transitivePeerDependencies: transitivePeerDependencies:
- supports-color - supports-color
svelte-inspect-value@0.5.0(svelte@5.20.5): svelte-inspect-value@0.3.0(svelte@5.20.5):
dependencies: dependencies:
esm-env: 1.2.2 esm-env: 1.2.2
fast-deep-equal: 3.1.3 fast-deep-equal: 3.1.3
@ -25663,7 +25698,7 @@ snapshots:
joi: 17.13.3 joi: 17.13.3
json-schema-to-ts: 3.1.1 json-schema-to-ts: 3.1.1
superstruct: 2.0.2 superstruct: 2.0.2
valibot: 1.0.0(typescript@5.7.3) valibot: 1.0.0-rc.4(typescript@5.7.3)
yup: 1.6.1 yup: 1.6.1
zod: 3.24.1 zod: 3.24.1
zod-to-json-schema: 3.24.1(zod@3.24.1) zod-to-json-schema: 3.24.1(zod@3.24.1)
@ -25907,7 +25942,7 @@ snapshots:
tauri-plugin-system-info-api: 2.0.10(typescript@5.7.2) tauri-plugin-system-info-api: 2.0.10(typescript@5.7.2)
tsc-alias: 1.8.10 tsc-alias: 1.8.10
typescript: 5.7.2 typescript: 5.7.2
valibot: 1.0.0(typescript@5.7.2) valibot: 1.0.0-rc.4(typescript@5.7.2)
transitivePeerDependencies: transitivePeerDependencies:
- bufferutil - bufferutil
- utf-8-validate - utf-8-validate
@ -25963,14 +25998,14 @@ snapshots:
tauri-plugin-network-api@2.0.5(typescript@5.7.2): tauri-plugin-network-api@2.0.5(typescript@5.7.2):
dependencies: dependencies:
'@tauri-apps/api': 2.3.0 '@tauri-apps/api': 2.3.0
valibot: 1.0.0(typescript@5.7.2) valibot: 1.0.0-rc.4(typescript@5.7.2)
transitivePeerDependencies: transitivePeerDependencies:
- typescript - typescript
tauri-plugin-network-api@2.0.5(typescript@5.7.3): tauri-plugin-network-api@2.0.5(typescript@5.7.3):
dependencies: dependencies:
'@tauri-apps/api': 2.3.0 '@tauri-apps/api': 2.3.0
valibot: 1.0.0(typescript@5.7.3) valibot: 1.0.0-rc.4(typescript@5.7.3)
transitivePeerDependencies: transitivePeerDependencies:
- typescript - typescript
@ -25987,7 +26022,7 @@ snapshots:
tauri-plugin-system-info-api@2.0.10(typescript@5.7.2): tauri-plugin-system-info-api@2.0.10(typescript@5.7.2):
dependencies: dependencies:
'@tauri-apps/api': 2.3.0 '@tauri-apps/api': 2.3.0
valibot: 1.0.0(typescript@5.7.2) valibot: 1.0.0-rc.4(typescript@5.7.2)
transitivePeerDependencies: transitivePeerDependencies:
- typescript - typescript
@ -26584,18 +26619,14 @@ snapshots:
optionalDependencies: optionalDependencies:
typescript: 5.7.3 typescript: 5.7.3
valibot@1.0.0(typescript@5.6.3): valibot@1.0.0-beta.10(typescript@5.6.3):
optionalDependencies: optionalDependencies:
typescript: 5.6.3 typescript: 5.6.3
valibot@1.0.0(typescript@5.7.2): valibot@1.0.0-beta.10(typescript@5.7.2):
optionalDependencies: optionalDependencies:
typescript: 5.7.2 typescript: 5.7.2
valibot@1.0.0(typescript@5.7.3):
optionalDependencies:
typescript: 5.7.3
valibot@1.0.0-beta.11(typescript@5.6.3): valibot@1.0.0-beta.11(typescript@5.6.3):
optionalDependencies: optionalDependencies:
typescript: 5.6.3 typescript: 5.6.3
@ -26613,6 +26644,14 @@ snapshots:
optionalDependencies: optionalDependencies:
typescript: 5.6.3 typescript: 5.6.3
valibot@1.0.0-rc.4(typescript@5.7.2):
optionalDependencies:
typescript: 5.7.2
valibot@1.0.0-rc.4(typescript@5.7.3):
optionalDependencies:
typescript: 5.7.3
validate-npm-package-name@5.0.1: {} validate-npm-package-name@5.0.1: {}
validator@13.12.0: validator@13.12.0: