Huakun Shen 7a3b6f3983
fix: listview action menu (#64)
* refactor: add a valibot schema for package registry validation

* fix: list view action menu

* chore: bump version to 0.1.16 in package.json

* refactor: extract supabase package from api

* ci: remove NODE_OPTIONS from build step and improve error handling in getLatestNpmPkgVersion function
2025-01-18 02:26:23 -05:00

99 lines
2.6 KiB
TypeScript

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()
}
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
}
}