Compare commits

...

11 Commits

Author SHA1 Message Date
Huakun Shen
5d5cbcdeb7
Refactor ORM commands and searchExtensionData function for improved readability and consistency
- Reformatted import statements for better organization.
- Cleaned up whitespace and indentation in searchExtensionData function.
- Enhanced readability of SQL conditions and query building logic.
- Disabled eslint for explicit any usage in the troubleshooters page.
2025-03-26 12:10:35 -04:00
Huakun Shen
288c9b554a
fixed searchExtensionData orm function 2025-03-26 11:48:24 -04:00
Huakun Shen
9c89395d5e
Merge remote-tracking branch 'origin/feature/drizzle' into feature/drizzle 2025-03-26 11:26:57 -04:00
Huakun Shen
9757b6975c
reimplemented most db command functions with ORM (migrate from tauri command invoke 2025-03-26 11:26:35 -04:00
Huakun Shen
c86778bf3a
Update enum definition for type safety
- Changed enum to use 'as const' for better type inference
- Ensured more robust handling of extension publish sources
2025-03-26 09:05:57 -04:00
Huakun Shen
dda783b9f6
pnpm lock update 2025-03-26 08:57:35 -04:00
Huakun Shen
993e750c11
Merge branch 'develop' into feature/drizzle 2025-03-26 08:57:07 -04:00
Huakun
48e2e47f96
Remove supabase (#263)
* remove supabase package

* upgrade valibot

* removed supabase package

Migration not complete yet

* update submodule

* fixed some supabase errors

* Add new fields to extension models

- Added `id` field to `ExtPublish`
- Expanded `DBExtension` with multiple new properties:
  - `api_version`, `author_id`, `created_at`,
  - `downloads`, `icon`, `identifier`,
  - `long_description`, `name`,
  - `readme`, `short_description`,
  - and `tarball_size`

* Refactor: clean up unused Supabase imports

- Removed commented-out Supabase imports from various files to streamline the codebase.
- Updated `created_at` type in `ExtPublish` model from `date` to `string` for consistency.

* update icon enum to union

* fix type errors after removing supabase

* format

* more types fixed

* feat: enhance command handling and update SDK version
2025-03-26 08:50:55 -04:00
Huakun
9fe51f6260
Feat: gitea mirror (#262)
* Update component props and add GitLab link

- Made `ref` prop optional in TauriLink component
- Added GitLab mirror URL to GitHubProvenanceCard
- Included a link to the GitLab mirror in the card layout
- Adjusted layout for StoreExtDetail component for better responsiveness
- Imported Tooltip component for potential future use

* chore: add parse-github-url dependency and update GitHub parsing logic

- Added `parse-github-url` package as a dependency in `package.json`.
- Updated `parseGitHubRepoFromUri` function to utilize `parse-github-url` for improved URI parsing.
- Introduced `getGitHubRepoMetadata` function to fetch repository metadata using Octokit.
- Updated validation data structure to include optional `repoId`.
- Enhanced tests to cover new functionality and error handling for invalid URIs.

* fix typo

* refactor: update validation data structure and improve function documentation

- Removed optional `repoId` from `ExtensionPublishValidationData` and adjusted related function to reflect this change.
- Added a note in the `validateJsrPackageAsKunkunExtension` function documentation to clarify frontend/backend verification logic.
- Updated `ExtPublishMetadata` to rename `repoId` to `repoNodeId` for clarity.

* refactor: remove GitLab mirror link from GitHubProvenanceCard

- Removed the GitLab mirror URL and its associated link from the GitHubProvenanceCard component.
- Commented out the layout for the GitLab mirror instead of deleting it, preserving the structure for potential future use.

* refactor: simplify GitHub repository URI parsing

- Removed dependency on `parse-github-url` and implemented a regex-based approach for parsing GitHub repository URIs in the `parseGitHubRepoFromUri` function.
- Enhanced error handling for invalid URIs while maintaining the function's output structure.

* feat: add Gitea mirror link to GitHubProvenanceCard

- Introduced a new link to the Gitea mirror repository in the GitHubProvenanceCard component.
- Updated the layout to reflect the new mirror link while removing the commented-out GitLab mirror section.

* refactor: enhance Globe component's location handling

- Updated the Globe component to conditionally render markers based on the provided locations prop.
- Simplified the destructuring of props for better readability.
- Retained default marker locations for cases where no locations are provided.

* pnpm lock
2025-03-26 01:08:16 -04:00
Huakun Shen
7759e615dd
Merge remote-tracking branch 'origin/develop' into develop 2025-03-23 10:26:22 -04:00
Huakun Shen
11226ee2ef
fix: jsr API for cloudflare worker env
Without this header will get html format instead of json in cf worker
2025-03-23 10:26:18 -04:00
65 changed files with 1121 additions and 1216 deletions

View File

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

View File

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

View File

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

13
apps/desktop/dev.ts Normal file
View File

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

View File

@ -242,6 +242,23 @@ export const rawBuiltinCmds: BuiltinCmd[] = [
},
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",
icon: {

View File

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

View File

@ -3,16 +3,16 @@
* 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.
*/
import type { AppConfig } from "@/types/appConfig"
import type { AppConfigState } from "@kksh/types"
import { getContext, setContext } from "svelte"
import type { Writable } from "svelte/store"
export const APP_CONFIG_CONTEXT_KEY = Symbol("appConfig")
export function getAppConfigContext(): Writable<AppConfig> {
export function getAppConfigContext(): Writable<AppConfigState> {
return getContext(APP_CONFIG_CONTEXT_KEY)
}
export function setAppConfigContext(appConfig: Writable<AppConfig>) {
export function setAppConfigContext(appConfig: Writable<AppConfigState>) {
setContext(APP_CONFIG_CONTEXT_KEY, appConfig)
}

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

@ -9,7 +9,8 @@
"skipLibCheck": true,
"sourceMap": true,
"strict": true,
"moduleResolution": "bundler"
"moduleResolution": "bundler",
"allowImportingTsExtensions": true
},
// 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

View File

@ -28,7 +28,9 @@
},
"dependencies": {
"@changesets/cli": "^2.28.1",
"@hey-api/client-fetch": "^0.8.3",
"@iconify/svelte": "^4.2.0",
"@kksh/sdk": "^0.0.3",
"@supabase/supabase-js": "^2.49.1",
"@tauri-apps/api": "^2.3.0",
"@tauri-apps/cli": "^2.3.1",
@ -48,7 +50,7 @@
"tauri-plugin-keyring-api": "workspace:*",
"tauri-plugin-network-api": "workspace:*",
"tauri-plugin-system-info-api": "workspace:*",
"valibot": "^1.0.0-rc.4",
"valibot": "^1.0.0",
"zod": "^3.24.2"
},
"workspaces": [

View File

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

View File

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

View File

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

View File

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

View File

@ -1,4 +1,3 @@
import { FsPermissionSchema } from "tauri-api-adapter/permissions"
import * as v from "valibot"
import {
AllKunkunPermission,
@ -8,29 +7,29 @@ import {
OpenPermissionScopedSchema,
ShellPermissionScopedSchema
} from "../permissions"
import { CmdType } from "./extension"
import { CmdType, CmdTypeEnum } from "./extension"
import { BaseIcon as Icon } from "./icon"
export enum OSPlatformEnum {
linux = "linux",
macos = "macos",
windows = "windows"
export const OSPlatformEnum = {
linux: "linux",
macos: "macos",
windows: "windows"
}
export const OSPlatform = v.enum_(OSPlatformEnum)
export const OSPlatform = v.picklist(Object.values(OSPlatformEnum))
export type OSPlatform = v.InferOutput<typeof OSPlatform>
const allPlatforms = Object.values(OSPlatformEnum)
export const TriggerCmd = v.object({
type: v.union([v.literal("text"), v.literal("regex")]),
value: v.string()
})
export type TriggerCmd = v.InferOutput<typeof TriggerCmd>
export enum TitleBarStyleEnum {
"visible" = "visible",
"transparent" = "transparent",
"overlay" = "overlay"
export const TitleBarStyleEnum = {
visible: "visible",
transparent: "transparent",
overlay: "overlay"
}
export const TitleBarStyle = v.enum_(TitleBarStyleEnum)
export type TitleBarStyle = v.InferOutput<typeof TitleBarStyle>
export const TitleBarStyle = v.picklist(Object.values(TitleBarStyleEnum))
// JS new WebViewWindow only accepts lowercase, while manifest loaded from Rust is capitalized. I run toLowerCase() on the value before passing it to the WebViewWindow.
// 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"]);
@ -71,37 +70,33 @@ export const WindowConfig = v.object({
export type WindowConfig = v.InferOutput<typeof WindowConfig>
export const BaseCmd = v.object({
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"),
cmds: v.array(TriggerCmd, "Commands to trigger the UI"),
icon: v.optional(Icon),
platforms: v.optional(
v.nullable(
v.array(OSPlatform, "Platforms available on. Leave empty for all platforms."),
allPlatforms
),
allPlatforms
v.array(OSPlatform, "Platforms available on. Leave empty for all platforms.")
)
})
export const CustomUiCmd = v.object({
...BaseCmd.entries,
type: v.optional(CmdType, CmdType.enum.UiIframe),
dist: v.string("Dist folder to load, e.g. dist, build, out"),
devMain: v.string(
"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 const TemplateUiCmd = v.object({
...BaseCmd.entries,
type: v.optional(CmdType, CmdType.enum.UiWorker),
type: v.optional(CmdType, CmdTypeEnum.UiWorker),
window: v.optional(v.nullable(WindowConfig))
})
export const HeadlessCmd = v.object({
...BaseCmd.entries,
type: v.optional(CmdType, CmdType.enum.HeadlessWorker)
type: v.optional(CmdType, CmdTypeEnum.HeadlessWorker)
})
export type HeadlessCmd = v.InferOutput<typeof HeadlessCmd>
export type TemplateUiCmd = v.InferOutput<typeof TemplateUiCmd>

View File

@ -0,0 +1,91 @@
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,3 +11,25 @@ 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 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 { extensions, commands, extensionData } from "./schema";
import { relations } from "drizzle-orm/relations"
import { commands, extensionData, extensions } from "./schema"
export const commandsRelations = relations(commands, ({one}) => ({
export const commandsRelations = relations(commands, ({ one }) => ({
extension: one(extensions, {
fields: [commands.extId],
references: [extensions.extId]
}),
}));
})
}))
export const extensionsRelations = relations(extensions, ({many}) => ({
export const extensionsRelations = relations(extensions, ({ many }) => ({
commands: many(commands),
extensionData: many(extensionData),
}));
extensionData: many(extensionData)
}))
export const extensionDataRelations = relations(extensionData, ({one}) => ({
export const extensionDataRelations = relations(extensionData, ({ one }) => ({
extension: one(extensions, {
fields: [extensionData.extId],
references: [extensions.extId]
}),
}));
})
}))

View File

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

View File

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

View File

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

View File

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

View File

@ -1,9 +1,15 @@
import { expect, test } from "bun:test"
import { parseGitHubRepoFromUri } from "../github"
import { getGitHubRepoMetadata, parseGitHubRepoFromUri } from "../github"
test("parse github repo from uri", () => {
expect(parseGitHubRepoFromUri("https://github.com/huakunshen/kunkun-ext-ossinsight")).toEqual({
owner: "huakunshen",
expect(parseGitHubRepoFromUri("https://github.com/kunkunsh/kunkun-ext-ossinsight")).toEqual({
owner: "kunkunsh",
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,6 +33,12 @@ 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): {
owner: string
repo: string
@ -46,3 +52,15 @@ export function parseGitHubRepoFromUri(uri: string): {
const [, owner, repo] = match
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,7 +7,11 @@ import {
} from "@huakunshen/jsr-client/hey-api-client"
import { ExtPackageJson, License } from "@kksh/api/models"
import * as v from "valibot"
import { authenticatedUserIsMemberOfGitHubOrg, userIsPublicMemberOfGitHubOrg } from "../github"
import {
authenticatedUserIsMemberOfGitHubOrg,
getGitHubRepoMetadata,
userIsPublicMemberOfGitHubOrg
} from "../github"
import type { ExtensionPublishValidationData } from "../models"
import type { NpmPkgMetadata } from "../npm/models"
import { getInfoFromRekorLog } from "../sigstore"
@ -119,7 +123,11 @@ export function getJsrPackageSrcFile(
file: string
): Promise<string | undefined> {
const url = `https://jsr.io/@${scope}/${name}/${version}/${file}`
return fetch(url).then((res) => res.text())
return fetch(url, {
headers: {
Accept: "application/json"
}
}).then((res) => res.text())
}
/**
@ -201,6 +209,7 @@ export function jsrPackageExists(scope: string, name: string, version?: string):
/**
* 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 signed with github action
* - check if user's github username is the same as repo's owner name
@ -364,6 +373,7 @@ export async function validateJsrPackageAsKunkunExtension(payload: {
}
}
const rekorInfo = await getInfoFromRekorLog(rekorLogId)
return {
data: {
pkgJson: parseResult.output,

View File

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

View File

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

View File

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

View File

@ -1,175 +0,0 @@
# 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

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

View File

@ -1,24 +0,0 @@
{
"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

@ -1,107 +0,0 @@
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

@ -1,335 +0,0 @@
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

@ -1,10 +0,0 @@
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

@ -1,44 +0,0 @@
/**
* @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

@ -1,27 +0,0 @@
{
"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,7 +6,6 @@
"prepare": "bun setup.ts"
},
"devDependencies": {
"@kksh/supabase": "workspace:*",
"@supabase/supabase-js": "^2.48.0",
"@kksh/ci": "workspace:*",
"@types/bun": "latest"

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

@ -19,6 +19,7 @@
} = $props()
const workflowRunId = githubActionInvocationId.split("/").at(-3)
const workflowRunUrl = `https://github.com/${repoOwner}/${repoName}/actions/runs/${workflowRunId}/workflow`
const giteaMirrorUrl = `https://gitea.kunkun.sh/kunkun-extensions-mirror/${repoOwner}-${repoName}`
</script>
<Card.Root>
@ -60,6 +61,12 @@
class="underline">Transparentcy log entry</a
>
</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>
</Card.Content>
</Card.Root>

View File

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

View File

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

251
pnpm-lock.yaml generated
View File

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