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", "jarvis",
"form-view", "form-view",
"@kksh/desktop", "@kksh/desktop",
"@kksh/supabase",
"@kksh/utils", "@kksh/utils",
"@kksh/extension", "@kksh/extension",
"@kksh/schema", "@kksh/schema",
"@kksh/supabase",
"@kksh/ui" "@kksh/ui"
] ]
} }

View File

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

View File

@ -27,7 +27,7 @@
"commander": "^12.1.0", "commander": "^12.1.0",
"fs-extra": "^11.2.0", "fs-extra": "^11.2.0",
"handlebars": "^4.7.8", "handlebars": "^4.7.8",
"valibot": "^1.0.0-rc.4" "valibot": "^1.0.0"
}, },
"files": [ "files": [
"dist" "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", "@inlang/paraglide-sveltekit": "0.16.0",
"@kksh/drizzle": "workspace:*", "@kksh/drizzle": "workspace:*",
"@kksh/extension": "workspace:*", "@kksh/extension": "workspace:*",
"@kksh/supabase": "workspace:*",
"@kksh/svelte5": "^0.1.15", "@kksh/svelte5": "^0.1.15",
"@kksh/ui": "workspace:*", "@kksh/ui": "workspace:*",
"@kksh/utils": "workspace:*", "@kksh/utils": "workspace:*",
@ -40,7 +39,7 @@
"lz-string": "^1.5.0", "lz-string": "^1.5.0",
"pretty-bytes": "^6.1.1", "pretty-bytes": "^6.1.1",
"semver": "^7.7.1", "semver": "^7.7.1",
"svelte-inspect-value": "^0.3.0", "svelte-inspect-value": "^0.5.0",
"svelte-sonner": "^0.3.28", "svelte-sonner": "^0.3.28",
"sveltekit-superforms": "^2.23.1", "sveltekit-superforms": "^2.23.1",
"tauri-plugin-clipboard-api": "^2.1.11", "tauri-plugin-clipboard-api": "^2.1.11",

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

@ -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 * as sb from "@supabase/supabase-js"
import { SUPABASE_ANON_KEY, SUPABASE_URL } from "./constants" import { SUPABASE_ANON_KEY, SUPABASE_URL } from "./constants"
// export const supabase = createSB(SUPABASE_URL, SUPABASE_ANON_KEY) // export const supabase = createSB(SUPABASE_URL, SUPABASE_ANON_KEY)
export const supabase: sb.SupabaseClient<Database> = sb.createClient<Database>( export const supabase: sb.SupabaseClient = sb.createClient(SUPABASE_URL, SUPABASE_ANON_KEY, {
SUPABASE_URL, auth: {
SUPABASE_ANON_KEY, flowType: "pkce"
{
auth: {
flowType: "pkce"
}
} }
) })
export const storage = supabase.storage export const storage = supabase.storage
export const supabaseExtensionsStorage = supabase.storage.from("extensions") export const supabaseExtensionsStorage = supabase.storage.from("extensions")
export const supabaseAPI = new SupabaseAPI(supabase) // export const supabaseAPI = new SupabaseAPI(supabase)

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

@ -4,14 +4,21 @@ import { NodeName, NodeNameEnum } from "./constants"
/* -------------------------------------------------------------------------- */ /* -------------------------------------------------------------------------- */
/* Icon */ /* Icon */
/* -------------------------------------------------------------------------- */ /* -------------------------------------------------------------------------- */
export enum IconEnum { // export enum IconEnum {
Iconify = "iconify", // Iconify = "iconify",
RemoteUrl = "remote-url", // RemoteUrl = "remote-url",
Svg = "svg", // Svg = "svg",
Base64PNG = "base64-png", // Base64PNG = "base64-png",
Text = "text" // Text = "text"
// }
export const IconEnum = {
Iconify: "iconify",
RemoteUrl: "remote-url",
Svg: "svg",
Base64PNG: "base64-png",
Text: "text"
} }
export const IconType = v.enum_(IconEnum) export const IconType = v.picklist(Object.values(IconEnum))
export type IconType = v.InferOutput<typeof IconType> export type IconType = v.InferOutput<typeof IconType>
export type Icon = { 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 ListSchema from "../ui/template/schema/list"
export * as FormSchema from "../ui/template/schema/form" export * as FormSchema from "../ui/template/schema/form"
export * from "./file-transfer" export * from "./file-transfer"
export * from "./server"

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

@ -1,9 +1,15 @@
import { expect, test } from "bun:test" import { expect, test } from "bun:test"
import { parseGitHubRepoFromUri } from "../github" import { getGitHubRepoMetadata, parseGitHubRepoFromUri } from "../github"
test("parse github repo from uri", () => { test("parse github repo from uri", () => {
expect(parseGitHubRepoFromUri("https://github.com/huakunshen/kunkun-ext-ossinsight")).toEqual({ expect(parseGitHubRepoFromUri("https://github.com/kunkunsh/kunkun-ext-ossinsight")).toEqual({
owner: "huakunshen", owner: "kunkunsh",
repo: "kunkun-ext-ossinsight" repo: "kunkun-ext-ossinsight"
}) })
expect(() => parseGitHubRepoFromUri("invalid-uri")).toThrow("Invalid GitHub repository URI")
})
test("get github repo metadata", async () => {
const metadata = await getGitHubRepoMetadata("kunkunsh", "kunkun-ext-ossinsight")
expect(metadata).toBeDefined()
}) })

View File

@ -33,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): { export function parseGitHubRepoFromUri(uri: string): {
owner: string owner: string
repo: string repo: string
@ -46,3 +52,15 @@ export function parseGitHubRepoFromUri(uri: string): {
const [, owner, repo] = match const [, owner, repo] = match
return { owner, repo } return { owner, repo }
} }
/**
* Get GitHub repository metadata
* @param owner
* @param repo
* @param githubToken - Optional GitHub token to prevent rate limiting
* @returns repository metadata
*/
export function getGitHubRepoMetadata(owner: string, repo: string, githubToken?: string) {
const octokit = new Octokit({ auth: githubToken })
return octokit.rest.repos.get({ owner, repo }).then((res) => res.data)
}

View File

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

View File

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

View File

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

View File

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

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

251
pnpm-lock.yaml generated
View File

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