diff --git a/Cargo.lock b/Cargo.lock index 036c449a6..2454cb4f2 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -3687,6 +3687,7 @@ dependencies = [ "tauri-plugin-membership", "tauri-plugin-misc", "tauri-plugin-notification", + "tauri-plugin-obsidian", "tauri-plugin-opener", "tauri-plugin-os", "tauri-plugin-prevent-default", @@ -14262,6 +14263,24 @@ dependencies = [ "url", ] +[[package]] +name = "tauri-plugin-obsidian" +version = "0.1.0" +dependencies = [ + "serde", + "specta", + "specta-typescript", + "strum 0.26.3", + "tauri", + "tauri-plugin", + "tauri-plugin-store", + "tauri-plugin-store2", + "tauri-specta", + "thiserror 2.0.12", + "tokio", + "tracing", +] + [[package]] name = "tauri-plugin-opener" version = "2.4.0" diff --git a/Cargo.toml b/Cargo.toml index bbe12831d..349147978 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -95,6 +95,7 @@ tauri-plugin-local-stt = { path = "plugins/local-stt" } tauri-plugin-membership = { path = "plugins/membership" } tauri-plugin-misc = { path = "plugins/misc" } tauri-plugin-notification = { path = "plugins/notification" } +tauri-plugin-obsidian = { path = "plugins/obsidian" } tauri-plugin-sfx = { path = "plugins/sfx" } tauri-plugin-sse = { path = "plugins/sse" } tauri-plugin-store2 = { path = "plugins/store2" } diff --git a/apps/desktop/package.json b/apps/desktop/package.json index 2e2155793..4aabd0919 100644 --- a/apps/desktop/package.json +++ b/apps/desktop/package.json @@ -31,6 +31,7 @@ "@hypr/plugin-membership": "workspace:^", "@hypr/plugin-misc": "workspace:^", "@hypr/plugin-notification": "workspace:^", + "@hypr/plugin-obsidian": "workspace:^", "@hypr/plugin-sfx": "workspace:^", "@hypr/plugin-task": "workspace:^", "@hypr/plugin-template": "workspace:^", @@ -60,6 +61,7 @@ "@tauri-apps/plugin-clipboard-manager": "^2.3.0", "@tauri-apps/plugin-dialog": "^2.3.0", "@tauri-apps/plugin-fs": "^2.4.0", + "@tauri-apps/plugin-http": "^2.4.4", "@tauri-apps/plugin-opener": "^2.4.0", "@tauri-apps/plugin-os": "^2.3.0", "@tauri-apps/plugin-process": "^2.3.0", diff --git a/apps/desktop/src-tauri/Cargo.toml b/apps/desktop/src-tauri/Cargo.toml index 054c25f12..a6defa32c 100644 --- a/apps/desktop/src-tauri/Cargo.toml +++ b/apps/desktop/src-tauri/Cargo.toml @@ -40,6 +40,7 @@ tauri-plugin-machine-uid = { workspace = true } tauri-plugin-membership = { workspace = true } tauri-plugin-misc = { workspace = true } tauri-plugin-notification = { workspace = true } +tauri-plugin-obsidian = { workspace = true } tauri-plugin-opener = { workspace = true } tauri-plugin-sfx = { workspace = true } tauri-plugin-sse = { workspace = true } diff --git a/apps/desktop/src-tauri/capabilities/default.json b/apps/desktop/src-tauri/capabilities/default.json index 82bc66262..4c1a00bb0 100644 --- a/apps/desktop/src-tauri/capabilities/default.json +++ b/apps/desktop/src-tauri/capabilities/default.json @@ -49,9 +49,10 @@ "fs:default", "task:default", "membership:default", + "obsidian:default", { "identifier": "opener:allow-open-url", - "allow": [{ "url": "https://**" }] + "allow": [{ "url": "https://**" }, { "url": "mailto:*" }, { "url": "obsidian://**" }] }, { "identifier": "opener:allow-open-path", @@ -81,9 +82,10 @@ { "identifier": "http:default", "allow": [ - { "url": "http://localhost:*" }, - { "url": "http://127.0.0.1:*" }, - { "url": "https://**" } + { "url": "http://localhost:*/**" }, + { "url": "http://127.0.0.1:*/**" }, + { "url": "https://**" }, + { "url": "http://**" } ] }, "dialog:allow-save" diff --git a/apps/desktop/src-tauri/src/lib.rs b/apps/desktop/src-tauri/src/lib.rs index 3c4c2635d..d191dfb2d 100644 --- a/apps/desktop/src-tauri/src/lib.rs +++ b/apps/desktop/src-tauri/src/lib.rs @@ -80,6 +80,7 @@ pub async fn main() { .plugin(tauri_plugin_os::init()) .plugin(tauri_plugin_fs::init()) .plugin(tauri_plugin_opener::init()) + .plugin(tauri_plugin_obsidian::init()) .plugin(tauri_plugin_sfx::init()) .plugin(tauri_plugin_updater::Builder::new().build()) .plugin(tauri_plugin_window_state::Builder::default().build()) diff --git a/apps/desktop/src/components/settings/components/tab-icon.tsx b/apps/desktop/src/components/settings/components/tab-icon.tsx index 680d02e5c..6ab5ef941 100644 --- a/apps/desktop/src/components/settings/components/tab-icon.tsx +++ b/apps/desktop/src/components/settings/components/tab-icon.tsx @@ -1,6 +1,7 @@ import { AudioLinesIcon, BellIcon, + BlocksIcon, CalendarIcon, FlaskConicalIcon, LayoutTemplateIcon, @@ -29,6 +30,8 @@ export function TabIcon({ tab }: { tab: Tab }) { return ; case "templates": return ; + case "integrations": + return ; default: return null; } diff --git a/apps/desktop/src/components/settings/components/types.ts b/apps/desktop/src/components/settings/components/types.ts index 4237bdd04..a3bab1fa6 100644 --- a/apps/desktop/src/components/settings/components/types.ts +++ b/apps/desktop/src/components/settings/components/types.ts @@ -1,7 +1,16 @@ import type { LucideIcon } from "lucide-react"; import { Bell, Calendar, LayoutTemplate, MessageSquare, Settings, Sparkles, Volume2 } from "lucide-react"; -export type Tab = "general" | "calendar" | "ai" | "notifications" | "sound" | "templates" | "lab" | "feedback"; +export type Tab = + | "general" + | "calendar" + | "ai" + | "notifications" + | "sound" + | "templates" + | "lab" + | "feedback" + | "integrations"; export const TABS: { name: Tab; icon: LucideIcon }[] = [ { name: "general", icon: Settings }, @@ -12,4 +21,5 @@ export const TABS: { name: Tab; icon: LucideIcon }[] = [ { name: "templates", icon: LayoutTemplate }, // { name: "lab", icon: FlaskConical }, { name: "feedback", icon: MessageSquare }, + { name: "integrations", icon: MessageSquare }, ]; diff --git a/apps/desktop/src/components/settings/views/index.ts b/apps/desktop/src/components/settings/views/index.ts index 50746bc9a..6a2d37855 100644 --- a/apps/desktop/src/components/settings/views/index.ts +++ b/apps/desktop/src/components/settings/views/index.ts @@ -3,6 +3,7 @@ export { default as Billing } from "./billing"; export { default as Calendar } from "./calendar"; export { default as Feedback } from "./feedback"; export { default as General } from "./general"; +export { default as Integrations } from "./integrations"; export { default as Lab } from "./lab"; export { default as Notifications } from "./notifications"; export { default as Profile } from "./profile"; diff --git a/apps/desktop/src/components/settings/views/integrations.tsx b/apps/desktop/src/components/settings/views/integrations.tsx new file mode 100644 index 000000000..b3e1a8021 --- /dev/null +++ b/apps/desktop/src/components/settings/views/integrations.tsx @@ -0,0 +1,282 @@ +import { zodResolver } from "@hookform/resolvers/zod"; +import { Trans } from "@lingui/react/macro"; +import { useQuery } from "@tanstack/react-query"; +import { useEffect } from "react"; +import { useForm } from "react-hook-form"; +import { z } from "zod"; + +import { commands as obsidianCommands } from "@hypr/plugin-obsidian"; +import { + Form, + FormControl, + FormDescription, + FormField, + FormItem, + FormLabel, + FormMessage, +} from "@hypr/ui/components/ui/form"; +import { Input } from "@hypr/ui/components/ui/input"; +import { Switch } from "@hypr/ui/components/ui/switch"; + +const schema = z.object({ + enabled: z.boolean(), + baseUrl: z.string().url().refine((url) => url.startsWith("http://") && !url.startsWith("https://"), { + message: "URL must start with http://, not https://", + }), + apiKey: z.string().min(1, "API key is required"), + vaultName: z.string().min(1, "Vault name is required"), + baseFolder: z.string().optional(), +}); + +type FormValues = z.infer; + +export default function IntegrationsComponent() { + const getEnabled = useQuery({ + queryKey: ["obsidian-enabled"], + queryFn: () => obsidianCommands.getEnabled(), + }); + + const getApiKey = useQuery({ + queryKey: ["obsidian-api-key"], + queryFn: () => obsidianCommands.getApiKey(), + }); + + const getBaseUrl = useQuery({ + queryKey: ["obsidian-base-url"], + queryFn: () => obsidianCommands.getBaseUrl(), + }); + + const getBaseFolder = useQuery({ + queryKey: ["obsidian-base-folder"], + queryFn: () => obsidianCommands.getBaseFolder?.() || Promise.resolve(""), + }); + + const getVaultName = useQuery({ + queryKey: ["obsidian-vault-name"], + queryFn: () => obsidianCommands.getVaultName(), + }); + + const form = useForm({ + resolver: zodResolver(schema), + mode: "onChange", + defaultValues: { + enabled: false, + baseUrl: "", + apiKey: "", + vaultName: "", + baseFolder: "", + }, + }); + + useEffect(() => { + form.reset({ + enabled: getEnabled.data || false, + baseUrl: getBaseUrl.data || "http://127.0.0.1:27123", + apiKey: getApiKey.data || "", + vaultName: getVaultName.data || "", + baseFolder: getBaseFolder.data || "", + }); + }, [ + form, + getEnabled.data, + getBaseUrl.data, + getApiKey.data, + getVaultName.data, + getBaseFolder.data, + ]); + + useEffect(() => { + const subscription = form.watch((value, { name }) => { + if (name === "enabled") { + obsidianCommands.setEnabled(value.enabled ?? false); + } + + if (name === "baseUrl") { + obsidianCommands.setBaseUrl(value.baseUrl ?? ""); + } + + if (name === "apiKey") { + obsidianCommands.setApiKey(value.apiKey ?? ""); + } + + if (name === "vaultName") { + obsidianCommands.setVaultName(value.vaultName ?? ""); + } + + if (name === "baseFolder") { + obsidianCommands.setBaseFolder(value.baseFolder ?? ""); + } + }); + + return () => subscription.unsubscribe(); + }, [form]); + + return ( +
+
+

+ Integrations +

+

+ Connect with external tools and services to enhance your workflow +

+
+ +
+
+
+
+

+ Obsidian +

+

+ Connect your Obsidian vault to export notes +

+
+
+ +
+ + ( + +
+ + Enable Integration + + + + Turn on Obsidian integration to export notes to Obsidian vault. + + +
+ + + +
+ )} + /> + + {form.watch("enabled") && ( +
+ ( + + + Base URL + + + + + + + The base URL of your Obsidian server. This is typically http://127.0.0.1:27123. + + + + + )} + /> + + ( + + + API Key + + + + + + + Your API key for Obsidian local-rest-api plugin. + + + + + )} + /> + + ( + + + Vault Name + + + + + + + The name of your Obsidian vault. + + + + + )} + /> + + ( + + + Base Folder + + + + + + + Optional base folder path within your Obsidian vault. + + + + + )} + /> +
+ )} + + +
+ +
+
+

+ More integrations coming soon... +

+

+ We're working on adding more tools and services to connect with your workflow +

+
+
+
+
+ ); +} diff --git a/apps/desktop/src/components/toolbar/buttons/share-button.tsx b/apps/desktop/src/components/toolbar/buttons/share-button.tsx index 27d4889dc..1aa4190e1 100644 --- a/apps/desktop/src/components/toolbar/buttons/share-button.tsx +++ b/apps/desktop/src/components/toolbar/buttons/share-button.tsx @@ -1,16 +1,20 @@ +import { useMutation, useQuery } from "@tanstack/react-query"; import { useParams } from "@tanstack/react-router"; +import { join } from "@tauri-apps/api/path"; import { message } from "@tauri-apps/plugin-dialog"; -import { openPath } from "@tauri-apps/plugin-opener"; -import { FileText, Share2Icon } from "lucide-react"; +import { fetch as tauriFetch } from "@tauri-apps/plugin-http"; +import { openPath, openUrl } from "@tauri-apps/plugin-opener"; +import { BookText, ChevronDown, ChevronUp, FileText, HelpCircle, Mail, Share2Icon } from "lucide-react"; import { useState } from "react"; import { useHypr } from "@/contexts"; import { commands as analyticsCommands } from "@hypr/plugin-analytics"; import { Session } from "@hypr/plugin-db"; +import { client, commands as obsidianCommands, patchVaultByFilename, putVaultByFilename } from "@hypr/plugin-obsidian"; +import { html2md } from "@hypr/tiptap/shared"; import { Button } from "@hypr/ui/components/ui/button"; import { Popover, PopoverContent, PopoverTrigger } from "@hypr/ui/components/ui/popover"; import { useSession } from "@hypr/utils/contexts"; -import { useMutation } from "@tanstack/react-query"; import { exportToPDF } from "../utils/pdf-export"; export function ShareButton() { @@ -18,16 +22,69 @@ export function ShareButton() { return param ? : null; } +interface ExportCard { + id: "pdf" | "email" | "obsidian"; + title: string; + icon: React.ReactNode; + description: string; + docsUrl: string; +} + function ShareButtonInNote() { const { userId } = useHypr(); const param = useParams({ from: "/app/note/$id", shouldThrow: true }); const session = useSession(param.id, (s) => s.session); const [open, setOpen] = useState(false); + const [expandedId, setExpandedId] = useState(null); const hasEnhancedNote = !!session?.enhanced_memo_html; + const isObsidianConfigured = useQuery({ + queryKey: ["integration", "obsidian", "enabled"], + queryFn: async () => { + const [enabled, apiKey, baseUrl] = await Promise.all([ + obsidianCommands.getEnabled(), + obsidianCommands.getApiKey(), + obsidianCommands.getBaseUrl(), + ]); + return enabled && apiKey && baseUrl; + }, + }); + + const exportOptions: ExportCard[] = [ + { + id: "pdf", + title: "PDF", + icon: , + description: "Save as PDF document", + docsUrl: "https://docs.hyprnote.com/sharing#pdf", + }, + { + id: "email", + title: "Email", + icon: , + description: "Share via email", + docsUrl: "https://docs.hyprnote.com/sharing#email", + }, + isObsidianConfigured.data + ? { + id: "obsidian", + title: "Obsidian", + icon: , + description: "Export to Obsidian", + docsUrl: "https://docs.hyprnote.com/sharing#obsidian", + } + : null, + ].filter(Boolean) as ExportCard[]; + + const toggleExpanded = (id: string) => { + setExpandedId(expandedId === id ? null : id); + }; + const handleOpenChange = (newOpen: boolean) => { setOpen(newOpen); + setExpandedId(null); + if (newOpen) { analyticsCommands.event({ event: "share_option_expanded", @@ -36,10 +93,72 @@ function ShareButtonInNote() { } }; - const exportAction = useMutation({ - mutationFn: async (session: Session) => { + const exportMutation = useMutation({ + mutationFn: async ({ session, optionId }: { session: Session; optionId: string }) => { const start = performance.now(); - const result = await exportToPDF(session); + let result: { + type: "pdf"; + path: string; + } | { + type: "email"; + url: string; + } | { + type: "obsidian"; + url: string; + } | null = null; + + if (optionId === "pdf") { + const path = await exportToPDF(session); + result = { type: "pdf", path }; + } else if (optionId === "email") { + result = { type: "email", url: `mailto:?subject=${encodeURIComponent(session.title)}` }; + } else if (optionId === "obsidian") { + const [baseFolder, apiKey, baseUrl] = await Promise.all([ + obsidianCommands.getBaseFolder(), + obsidianCommands.getApiKey(), + obsidianCommands.getBaseUrl(), + ]); + client.setConfig({ + fetch: tauriFetch, + auth: apiKey!, + baseUrl: baseUrl!, + }); + + const filename = `${session.title.replace(/[^a-zA-Z0-9 ]/g, "").replace(/\s+/g, "-")}.md`; + const filePath = baseFolder ? await join(baseFolder!, filename) : filename; + const convertedMarkdown = session.enhanced_memo_html ? html2md(session.enhanced_memo_html) : ""; + + await putVaultByFilename({ + client, + path: { filename: filePath }, + body: convertedMarkdown, + bodySerializer: null, + headers: { + "Content-Type": "text/markdown", + }, + }); + + const targets = [ + { target: "date", value: new Date().toISOString() }, + ]; + for (const { target, value } of targets) { + await patchVaultByFilename({ + client, + path: { filename: filePath }, + headers: { + "Operation": "replace", + "Target-Type": "frontmatter", + "Target": target, + "Create-Target-If-Missing": "true", + }, + body: value, + }); + } + + const url = await obsidianCommands.getDeepLinkUrl(filePath); + result = { type: "obsidian", url }; + } + const elapsed = performance.now() - start; if (elapsed < 800) { await new Promise((resolve) => setTimeout(resolve, 800 - elapsed)); @@ -47,22 +166,35 @@ function ShareButtonInNote() { return result; }, - onMutate: () => { + onMutate: ({ optionId }) => { analyticsCommands.event({ event: "share_triggered", distinct_id: userId, - type: "pdf", + type: optionId, }); }, - onSuccess: (filePath) => { + onSuccess: (result) => { + if (result?.type === "pdf") { + openPath(result.path); + } else if (result?.type === "email") { + openUrl(result.url); + } else if (result?.type === "obsidian") { + openUrl(result.url); + } + }, + onSettled: () => { setOpen(false); - openPath(filePath); }, onError: (error) => { - message(error.message, { title: "Error", kind: "error" }); + console.error(error); + message(JSON.stringify(error), { title: "Error", kind: "error" }); }, }); + const handleExport = (optionId: string) => { + exportMutation.mutate({ session, optionId }); + }; + return ( @@ -77,24 +209,69 @@ function ShareButtonInNote() {

Share Enhanced Note

-

Share your AI-enhanced meeting notes

+

+ +

-
- +
+ {exportOptions.map((option) => { + const expanded = expandedId === option.id; + + return ( +
+
toggleExpanded(option.id)} + > +
+
{option.icon}
+ {option.title} +
+ { + + } +
+ {expanded && ( +
+
+

{option.description}

+ +
+ +
+ )} +
+ ); + })}
diff --git a/apps/desktop/src/routes/app.settings.tsx b/apps/desktop/src/routes/app.settings.tsx index fa1d97474..2c3a42b45 100644 --- a/apps/desktop/src/routes/app.settings.tsx +++ b/apps/desktop/src/routes/app.settings.tsx @@ -5,7 +5,16 @@ import { z } from "zod"; import { TabIcon } from "@/components/settings/components/tab-icon"; import { type Tab, TABS } from "@/components/settings/components/types"; -import { Calendar, Feedback, General, LocalAI, Notifications, Sound, TemplatesView } from "@/components/settings/views"; +import { + Calendar, + Feedback, + General, + Integrations, + LocalAI, + Notifications, + Sound, + TemplatesView, +} from "@/components/settings/views"; import { cn } from "@hypr/ui/lib/utils"; const schema = z.object({ @@ -47,6 +56,8 @@ function Component() { return t`Team`; case "billing": return t`Billing`; + case "integrations": + return t`Integrations`; default: return tab; } @@ -93,6 +104,8 @@ function Component() { ? Feedback : tab.name === "templates" ? Templates + : tab.name === "integrations" + ? Integrations : null} @@ -125,6 +138,7 @@ function Component() { {/* {search.tab === "lab" && } */} {search.tab === "feedback" && } {search.tab === "templates" && } + {search.tab === "integrations" && }
diff --git a/packages/obsidian/generated/@tanstack/react-query.gen.ts b/packages/obsidian/generated/@tanstack/react-query.gen.ts index 05e212a1d..a3d2e5d65 100644 --- a/packages/obsidian/generated/@tanstack/react-query.gen.ts +++ b/packages/obsidian/generated/@tanstack/react-query.gen.ts @@ -1,18 +1,20 @@ // This file is auto-generated by @hey-api/openapi-ts -import { type Options, get, deleteActive, getActive, patchActive, postActive, putActive, getCommands, postCommandsByCommandId, postOpenByFilename, deletePeriodicByPeriod, getPeriodicByPeriod, patchPeriodicByPeriod, postPeriodicByPeriod, putPeriodicByPeriod, postSearch, postSearchSimple, getVault, deleteVaultByFilename, getVaultByFilename, patchVaultByFilename, postVaultByFilename, putVaultByFilename, getVaultByPathToDirectory } from '../sdk.gen'; +import { type Options, get, deleteActive, getActive, patchActive, postActive, putActive, getCommands, postCommandsByCommandId, getObsidianLocalRestApiCrt, postOpenByFilename, getOpenapiYaml, deletePeriodicByPeriod, getPeriodicByPeriod, patchPeriodicByPeriod, postPeriodicByPeriod, putPeriodicByPeriod, deletePeriodicByPeriodByYearByMonthByDay, getPeriodicByPeriodByYearByMonthByDay, patchPeriodicByPeriodByYearByMonthByDay, postPeriodicByPeriodByYearByMonthByDay, putPeriodicByPeriodByYearByMonthByDay, postSearch, postSearchSimple, getVault, deleteVaultByFilename, getVaultByFilename, patchVaultByFilename, postVaultByFilename, putVaultByFilename, getVaultByPathToDirectory } from '../sdk.gen'; import { queryOptions, type UseMutationOptions, type DefaultError } from '@tanstack/react-query'; -import type { GetData, DeleteActiveData, DeleteActiveError, DeleteActiveResponse, GetActiveData, PatchActiveData, PatchActiveError, PostActiveData, PostActiveError, PostActiveResponse, PutActiveData, PutActiveError, PutActiveResponse, GetCommandsData, PostCommandsByCommandIdData, PostCommandsByCommandIdError, PostCommandsByCommandIdResponse, PostOpenByFilenameData, DeletePeriodicByPeriodData, DeletePeriodicByPeriodError, DeletePeriodicByPeriodResponse, GetPeriodicByPeriodData, PatchPeriodicByPeriodData, PatchPeriodicByPeriodError, PostPeriodicByPeriodData, PostPeriodicByPeriodError, PostPeriodicByPeriodResponse, PutPeriodicByPeriodData, PutPeriodicByPeriodError, PutPeriodicByPeriodResponse, PostSearchData, PostSearchError, PostSearchResponse, PostSearchSimpleData, PostSearchSimpleResponse, GetVaultData, DeleteVaultByFilenameData, DeleteVaultByFilenameError, DeleteVaultByFilenameResponse, GetVaultByFilenameData, PatchVaultByFilenameData, PatchVaultByFilenameError, PostVaultByFilenameData, PostVaultByFilenameError, PostVaultByFilenameResponse, PutVaultByFilenameData, PutVaultByFilenameError, PutVaultByFilenameResponse, GetVaultByPathToDirectoryData } from '../types.gen'; +import type { GetData, DeleteActiveData, DeleteActiveError, DeleteActiveResponse, GetActiveData, PatchActiveData, PatchActiveError, PostActiveData, PostActiveError, PostActiveResponse, PutActiveData, PutActiveError, PutActiveResponse, GetCommandsData, PostCommandsByCommandIdData, PostCommandsByCommandIdError, PostCommandsByCommandIdResponse, GetObsidianLocalRestApiCrtData, PostOpenByFilenameData, GetOpenapiYamlData, DeletePeriodicByPeriodData, DeletePeriodicByPeriodError, DeletePeriodicByPeriodResponse, GetPeriodicByPeriodData, PatchPeriodicByPeriodData, PatchPeriodicByPeriodError, PostPeriodicByPeriodData, PostPeriodicByPeriodError, PostPeriodicByPeriodResponse, PutPeriodicByPeriodData, PutPeriodicByPeriodError, PutPeriodicByPeriodResponse, DeletePeriodicByPeriodByYearByMonthByDayData, DeletePeriodicByPeriodByYearByMonthByDayError, DeletePeriodicByPeriodByYearByMonthByDayResponse, GetPeriodicByPeriodByYearByMonthByDayData, PatchPeriodicByPeriodByYearByMonthByDayData, PatchPeriodicByPeriodByYearByMonthByDayError, PostPeriodicByPeriodByYearByMonthByDayData, PostPeriodicByPeriodByYearByMonthByDayError, PostPeriodicByPeriodByYearByMonthByDayResponse, PutPeriodicByPeriodByYearByMonthByDayData, PutPeriodicByPeriodByYearByMonthByDayError, PutPeriodicByPeriodByYearByMonthByDayResponse, PostSearchData, PostSearchError, PostSearchResponse, PostSearchSimpleData, PostSearchSimpleResponse, GetVaultData, DeleteVaultByFilenameData, DeleteVaultByFilenameError, DeleteVaultByFilenameResponse, GetVaultByFilenameData, PatchVaultByFilenameData, PatchVaultByFilenameError, PostVaultByFilenameData, PostVaultByFilenameError, PostVaultByFilenameResponse, PutVaultByFilenameData, PutVaultByFilenameError, PutVaultByFilenameResponse, GetVaultByPathToDirectoryData } from '../types.gen'; import { client as _heyApiClient } from '../client.gen'; -type QueryKey = [ +export type QueryKey = [ Pick & { _id: string; _infinite?: boolean; } ]; -const createQueryKey = (id: string, options?: TOptions, infinite?: boolean): QueryKey[0] => { +const createQueryKey = (id: string, options?: TOptions, infinite?: boolean): [ + QueryKey[0] +] => { const params: QueryKey[0] = { _id: id, baseUrl: (options?.client ?? _heyApiClient).getConfig().baseUrl } as QueryKey[0]; if (infinite) { params._infinite = infinite; @@ -29,12 +31,12 @@ const createQueryKey = (id: string, options?: TOptions if (options?.query) { params.query = options.query; } - return params; + return [ + params + ]; }; -export const getQueryKey = (options?: Options) => [ - createQueryKey('get', options) -]; +export const getQueryKey = (options?: Options) => createQueryKey('get', options); export const getOptions = (options?: Options) => { return queryOptions({ @@ -65,9 +67,7 @@ export const deleteActiveMutation = (options?: Partial return mutationOptions; }; -export const getActiveQueryKey = (options?: Options) => [ - createQueryKey('getActive', options) -]; +export const getActiveQueryKey = (options?: Options) => createQueryKey('getActive', options); export const getActiveOptions = (options?: Options) => { return queryOptions({ @@ -98,9 +98,7 @@ export const patchActiveMutation = (options?: Partial>) return mutationOptions; }; -export const postActiveQueryKey = (options: Options) => [ - createQueryKey('postActive', options) -]; +export const postActiveQueryKey = (options: Options) => createQueryKey('postActive', options); export const postActiveOptions = (options: Options) => { return queryOptions({ @@ -145,9 +143,7 @@ export const putActiveMutation = (options?: Partial>) => return mutationOptions; }; -export const getCommandsQueryKey = (options?: Options) => [ - createQueryKey('getCommands', options) -]; +export const getCommandsQueryKey = (options?: Options) => createQueryKey('getCommands', options); export const getCommandsOptions = (options?: Options) => { return queryOptions({ @@ -164,9 +160,7 @@ export const getCommandsOptions = (options?: Options) => { }); }; -export const postCommandsByCommandIdQueryKey = (options: Options) => [ - createQueryKey('postCommandsByCommandId', options) -]; +export const postCommandsByCommandIdQueryKey = (options: Options) => createQueryKey('postCommandsByCommandId', options); export const postCommandsByCommandIdOptions = (options: Options) => { return queryOptions({ @@ -197,9 +191,24 @@ export const postCommandsByCommandIdMutation = (options?: Partial) => [ - createQueryKey('postOpenByFilename', options) -]; +export const getObsidianLocalRestApiCrtQueryKey = (options?: Options) => createQueryKey('getObsidianLocalRestApiCrt', options); + +export const getObsidianLocalRestApiCrtOptions = (options?: Options) => { + return queryOptions({ + queryFn: async ({ queryKey, signal }) => { + const { data } = await getObsidianLocalRestApiCrt({ + ...options, + ...queryKey[0], + signal, + throwOnError: true + }); + return data; + }, + queryKey: getObsidianLocalRestApiCrtQueryKey(options) + }); +}; + +export const postOpenByFilenameQueryKey = (options: Options) => createQueryKey('postOpenByFilename', options); export const postOpenByFilenameOptions = (options: Options) => { return queryOptions({ @@ -230,6 +239,23 @@ export const postOpenByFilenameMutation = (options?: Partial) => createQueryKey('getOpenapiYaml', options); + +export const getOpenapiYamlOptions = (options?: Options) => { + return queryOptions({ + queryFn: async ({ queryKey, signal }) => { + const { data } = await getOpenapiYaml({ + ...options, + ...queryKey[0], + signal, + throwOnError: true + }); + return data; + }, + queryKey: getOpenapiYamlQueryKey(options) + }); +}; + export const deletePeriodicByPeriodMutation = (options?: Partial>) => { const mutationOptions: UseMutationOptions> = { mutationFn: async (localOptions) => { @@ -244,9 +270,7 @@ export const deletePeriodicByPeriodMutation = (options?: Partial) => [ - createQueryKey('getPeriodicByPeriod', options) -]; +export const getPeriodicByPeriodQueryKey = (options: Options) => createQueryKey('getPeriodicByPeriod', options); export const getPeriodicByPeriodOptions = (options: Options) => { return queryOptions({ @@ -277,9 +301,7 @@ export const patchPeriodicByPeriodMutation = (options?: Partial) => [ - createQueryKey('postPeriodicByPeriod', options) -]; +export const postPeriodicByPeriodQueryKey = (options: Options) => createQueryKey('postPeriodicByPeriod', options); export const postPeriodicByPeriodOptions = (options: Options) => { return queryOptions({ @@ -324,9 +346,97 @@ export const putPeriodicByPeriodMutation = (options?: Partial) => [ - createQueryKey('postSearch', options) -]; +export const deletePeriodicByPeriodByYearByMonthByDayMutation = (options?: Partial>) => { + const mutationOptions: UseMutationOptions> = { + mutationFn: async (localOptions) => { + const { data } = await deletePeriodicByPeriodByYearByMonthByDay({ + ...options, + ...localOptions, + throwOnError: true + }); + return data; + } + }; + return mutationOptions; +}; + +export const getPeriodicByPeriodByYearByMonthByDayQueryKey = (options: Options) => createQueryKey('getPeriodicByPeriodByYearByMonthByDay', options); + +export const getPeriodicByPeriodByYearByMonthByDayOptions = (options: Options) => { + return queryOptions({ + queryFn: async ({ queryKey, signal }) => { + const { data } = await getPeriodicByPeriodByYearByMonthByDay({ + ...options, + ...queryKey[0], + signal, + throwOnError: true + }); + return data; + }, + queryKey: getPeriodicByPeriodByYearByMonthByDayQueryKey(options) + }); +}; + +export const patchPeriodicByPeriodByYearByMonthByDayMutation = (options?: Partial>) => { + const mutationOptions: UseMutationOptions> = { + mutationFn: async (localOptions) => { + const { data } = await patchPeriodicByPeriodByYearByMonthByDay({ + ...options, + ...localOptions, + throwOnError: true + }); + return data; + } + }; + return mutationOptions; +}; + +export const postPeriodicByPeriodByYearByMonthByDayQueryKey = (options: Options) => createQueryKey('postPeriodicByPeriodByYearByMonthByDay', options); + +export const postPeriodicByPeriodByYearByMonthByDayOptions = (options: Options) => { + return queryOptions({ + queryFn: async ({ queryKey, signal }) => { + const { data } = await postPeriodicByPeriodByYearByMonthByDay({ + ...options, + ...queryKey[0], + signal, + throwOnError: true + }); + return data; + }, + queryKey: postPeriodicByPeriodByYearByMonthByDayQueryKey(options) + }); +}; + +export const postPeriodicByPeriodByYearByMonthByDayMutation = (options?: Partial>) => { + const mutationOptions: UseMutationOptions> = { + mutationFn: async (localOptions) => { + const { data } = await postPeriodicByPeriodByYearByMonthByDay({ + ...options, + ...localOptions, + throwOnError: true + }); + return data; + } + }; + return mutationOptions; +}; + +export const putPeriodicByPeriodByYearByMonthByDayMutation = (options?: Partial>) => { + const mutationOptions: UseMutationOptions> = { + mutationFn: async (localOptions) => { + const { data } = await putPeriodicByPeriodByYearByMonthByDay({ + ...options, + ...localOptions, + throwOnError: true + }); + return data; + } + }; + return mutationOptions; +}; + +export const postSearchQueryKey = (options: Options) => createQueryKey('postSearch', options); export const postSearchOptions = (options: Options) => { return queryOptions({ @@ -357,9 +467,7 @@ export const postSearchMutation = (options?: Partial>) = return mutationOptions; }; -export const postSearchSimpleQueryKey = (options: Options) => [ - createQueryKey('postSearchSimple', options) -]; +export const postSearchSimpleQueryKey = (options: Options) => createQueryKey('postSearchSimple', options); export const postSearchSimpleOptions = (options: Options) => { return queryOptions({ @@ -390,9 +498,7 @@ export const postSearchSimpleMutation = (options?: Partial) => [ - createQueryKey('getVault', options) -]; +export const getVaultQueryKey = (options?: Options) => createQueryKey('getVault', options); export const getVaultOptions = (options?: Options) => { return queryOptions({ @@ -423,9 +529,7 @@ export const deleteVaultByFilenameMutation = (options?: Partial) => [ - createQueryKey('getVaultByFilename', options) -]; +export const getVaultByFilenameQueryKey = (options: Options) => createQueryKey('getVaultByFilename', options); export const getVaultByFilenameOptions = (options: Options) => { return queryOptions({ @@ -456,9 +560,7 @@ export const patchVaultByFilenameMutation = (options?: Partial) => [ - createQueryKey('postVaultByFilename', options) -]; +export const postVaultByFilenameQueryKey = (options: Options) => createQueryKey('postVaultByFilename', options); export const postVaultByFilenameOptions = (options: Options) => { return queryOptions({ @@ -503,9 +605,7 @@ export const putVaultByFilenameMutation = (options?: Partial) => [ - createQueryKey('getVaultByPathToDirectory', options) -]; +export const getVaultByPathToDirectoryQueryKey = (options: Options) => createQueryKey('getVaultByPathToDirectory', options); export const getVaultByPathToDirectoryOptions = (options: Options) => { return queryOptions({ diff --git a/packages/obsidian/generated/sdk.gen.ts b/packages/obsidian/generated/sdk.gen.ts index 0f8575503..d087facbe 100644 --- a/packages/obsidian/generated/sdk.gen.ts +++ b/packages/obsidian/generated/sdk.gen.ts @@ -1,7 +1,7 @@ // This file is auto-generated by @hey-api/openapi-ts import type { Options as ClientOptions, TDataShape, Client } from '@hey-api/client-fetch'; -import type { GetData, GetResponse, DeleteActiveData, DeleteActiveResponse, DeleteActiveError, GetActiveData, GetActiveResponse, PatchActiveData, PatchActiveError, PostActiveData, PostActiveResponse, PostActiveError, PutActiveData, PutActiveResponse, PutActiveError, GetCommandsData, GetCommandsResponse, PostCommandsByCommandIdData, PostCommandsByCommandIdResponse, PostCommandsByCommandIdError, PostOpenByFilenameData, DeletePeriodicByPeriodData, DeletePeriodicByPeriodResponse, DeletePeriodicByPeriodError, GetPeriodicByPeriodData, GetPeriodicByPeriodResponse, PatchPeriodicByPeriodData, PatchPeriodicByPeriodError, PostPeriodicByPeriodData, PostPeriodicByPeriodResponse, PostPeriodicByPeriodError, PutPeriodicByPeriodData, PutPeriodicByPeriodResponse, PutPeriodicByPeriodError, PostSearchData, PostSearchResponse, PostSearchError, PostSearchSimpleData, PostSearchSimpleResponse, GetVaultData, GetVaultResponse, GetVaultError, DeleteVaultByFilenameData, DeleteVaultByFilenameResponse, DeleteVaultByFilenameError, GetVaultByFilenameData, GetVaultByFilenameResponse, PatchVaultByFilenameData, PatchVaultByFilenameError, PostVaultByFilenameData, PostVaultByFilenameResponse, PostVaultByFilenameError, PutVaultByFilenameData, PutVaultByFilenameResponse, PutVaultByFilenameError, GetVaultByPathToDirectoryData, GetVaultByPathToDirectoryResponse, GetVaultByPathToDirectoryError } from './types.gen'; +import type { GetData, GetResponse, DeleteActiveData, DeleteActiveResponse, DeleteActiveError, GetActiveData, GetActiveResponse, PatchActiveData, PatchActiveError, PostActiveData, PostActiveResponse, PostActiveError, PutActiveData, PutActiveResponse, PutActiveError, GetCommandsData, GetCommandsResponse, PostCommandsByCommandIdData, PostCommandsByCommandIdResponse, PostCommandsByCommandIdError, GetObsidianLocalRestApiCrtData, PostOpenByFilenameData, GetOpenapiYamlData, DeletePeriodicByPeriodData, DeletePeriodicByPeriodResponse, DeletePeriodicByPeriodError, GetPeriodicByPeriodData, GetPeriodicByPeriodResponse, PatchPeriodicByPeriodData, PatchPeriodicByPeriodError, PostPeriodicByPeriodData, PostPeriodicByPeriodResponse, PostPeriodicByPeriodError, PutPeriodicByPeriodData, PutPeriodicByPeriodResponse, PutPeriodicByPeriodError, DeletePeriodicByPeriodByYearByMonthByDayData, DeletePeriodicByPeriodByYearByMonthByDayResponse, DeletePeriodicByPeriodByYearByMonthByDayError, GetPeriodicByPeriodByYearByMonthByDayData, GetPeriodicByPeriodByYearByMonthByDayResponse, PatchPeriodicByPeriodByYearByMonthByDayData, PatchPeriodicByPeriodByYearByMonthByDayError, PostPeriodicByPeriodByYearByMonthByDayData, PostPeriodicByPeriodByYearByMonthByDayResponse, PostPeriodicByPeriodByYearByMonthByDayError, PutPeriodicByPeriodByYearByMonthByDayData, PutPeriodicByPeriodByYearByMonthByDayResponse, PutPeriodicByPeriodByYearByMonthByDayError, PostSearchData, PostSearchResponse, PostSearchError, PostSearchSimpleData, PostSearchSimpleResponse, GetVaultData, GetVaultResponse, GetVaultError, DeleteVaultByFilenameData, DeleteVaultByFilenameResponse, DeleteVaultByFilenameError, GetVaultByFilenameData, GetVaultByFilenameResponse, PatchVaultByFilenameData, PatchVaultByFilenameError, PostVaultByFilenameData, PostVaultByFilenameResponse, PostVaultByFilenameError, PutVaultByFilenameData, PutVaultByFilenameResponse, PutVaultByFilenameError, GetVaultByPathToDirectoryData, GetVaultByPathToDirectoryResponse, GetVaultByPathToDirectoryError } from './types.gen'; import { client as _heyApiClient } from './client.gen'; export type Options = ClientOptions & { @@ -78,9 +78,9 @@ export const getActive = (options?: Option }; /** - * Insert content into the currently open note in Obsidian relative to a heading within that document. + * Partially update content in the currently open note. * - * Inserts content into the currently-open note relative to a heading within that note. + * Inserts content into the currently-open note relative to a heading, block refeerence, or frontmatter field within that document. * * Allows you to modify the content relative to a heading, block reference, or frontmatter field in your document. * @@ -310,9 +310,24 @@ export const postCommandsByCommandId = (op }; /** - * Open the specified document in Obsidian + * Returns the certificate in use by this API. * - * Opens the specified document in Obsidian. + */ +export const getObsidianLocalRestApiCrt = (options?: Options) => { + return (options?.client ?? _heyApiClient).get({ + security: [ + { + scheme: 'bearer', + type: 'http' + } + ], + url: '/obsidian-local-rest-api.crt', + ...options + }); +}; + +/** + * Open the specified document in the Obsidian user interface. * * Note: Obsidian will create a new document at the path you have * specified if such a document did not already exist. @@ -332,9 +347,24 @@ export const postOpenByFilename = (options }; /** - * Delete a periodic note. + * Returns OpenAPI YAML document describing the capabilities of this API. * - * Deletes the periodic note for the specified period. + */ +export const getOpenapiYaml = (options?: Options) => { + return (options?.client ?? _heyApiClient).get({ + security: [ + { + scheme: 'bearer', + type: 'http' + } + ], + url: '/openapi.yaml', + ...options + }); +}; + +/** + * Delete the current periodic note for the specified period. * */ export const deletePeriodicByPeriod = (options: Options) => { @@ -368,9 +398,9 @@ export const getPeriodicByPeriod = (option }; /** - * Insert content into a periodic note relative to a heading within that document. + * Partially update content in the current periodic note for the specified period. * - * Inserts content into an existing note relative to a heading within your note. + * Inserts content into the current periodic note for the specified period relative to a heading, block refeerence, or frontmatter field within that document. * * Allows you to modify the content relative to a heading, block reference, or frontmatter field in your document. * @@ -519,9 +549,9 @@ export const patchPeriodicByPeriod = (opti }; /** - * Append content to a periodic note. + * Append content to the current periodic note for the specified period. * - * Appends content to the periodic note for the specified period. This will create the relevant periodic note if necessary. + * Note that this will create the relevant periodic note if necessary. * */ export const postPeriodicByPeriod = (options: Options) => { @@ -543,7 +573,7 @@ export const postPeriodicByPeriod = (optio }; /** - * Update the content of a periodic note. + * Update the content of the current periodic note for the specified period. * */ export const putPeriodicByPeriod = (options: Options) => { @@ -563,6 +593,238 @@ export const putPeriodicByPeriod = (option }); }; +/** + * Delete the periodic note for the specified period and date. + * + * Deletes the periodic note for the specified period. + * + */ +export const deletePeriodicByPeriodByYearByMonthByDay = (options: Options) => { + return (options.client ?? _heyApiClient).delete({ + security: [ + { + scheme: 'bearer', + type: 'http' + } + ], + url: '/periodic/{period}/{year}/{month}/{day}/', + ...options + }); +}; + +/** + * Get the periodic note for the specified period and date. + * + */ +export const getPeriodicByPeriodByYearByMonthByDay = (options: Options) => { + return (options.client ?? _heyApiClient).get({ + security: [ + { + scheme: 'bearer', + type: 'http' + } + ], + url: '/periodic/{period}/{year}/{month}/{day}/', + ...options + }); +}; + +/** + * Partially update content in the periodic note for the specified period and date. + * + * Inserts content into a periodic note relative to a heading, block refeerence, or frontmatter field within that document. + * + * Allows you to modify the content relative to a heading, block reference, or frontmatter field in your document. + * + * Note that this API was changed in Version 3.0 of this extension and the earlier PATCH API is now deprecated. Requests made using the previous version of this API will continue to work until Version 4.0 is released. See https://github.com/coddingtonbear/obsidian-local-rest-api/wiki/Changes-to-PATCH-requests-between-versions-2.0-and-3.0 for more details and migration instructions. + * + * # Examples + * + * All of the below examples assume you have a document that looks like + * this: + * + * ```markdown + * --- + * alpha: 1 + * beta: test + * delta: + * zeta: 1 + * yotta: 1 + * gamma: + * - one + * - two + * --- + * + * # Heading 1 + * + * This is the content for heading one + * + * Also references some [[#^484ef2]] + * + * ## Subheading 1:1 + * Content for Subheading 1:1 + * + * ### Subsubheading 1:1:1 + * + * ### Subsubheading 1:1:2 + * + * Testing how block references work for a table.[[#^2c7cfa]] + * Some content for Subsubheading 1:1:2 + * + * More random text. + * + * ^2d9b4a + * + * ## Subheading 1:2 + * + * Content for Subheading 1:2. + * + * some content with a block reference ^484ef2 + * + * ## Subheading 1:3 + * | City | Population | + * | ------------ | ---------- | + * | Seattle, WA | 8 | + * | Portland, OR | 4 | + * + * ^2c7cfa + * ``` + * + * ## Append Content Below a Heading + * + * If you wanted to append the content "Hello" below "Subheading 1:1:1" under "Heading 1", + * you could send a request with the following headers: + * + * - `Operation`: `append` + * - `Target-Type`: `heading` + * - `Target`: `Heading 1::Subheading 1:1:1` + * - with the request body: `Hello` + * + * The above would work just fine for `prepend` or `replace`, too, of course, + * but with different results. + * + * ## Append Content to a Block Reference + * + * If you wanted to append the content "Hello" below the block referenced by + * "2d9b4a" above ("More random text."), you could send the following headers: + * + * - `Operation`: `append` + * - `Target-Type`: `block` + * - `Target`: `2d9b4a` + * - with the request body: `Hello` + * + * The above would work just fine for `prepend` or `replace`, too, of course, + * but with different results. + * + * ## Add a Row to a Table Referenced by a Block Reference + * + * If you wanted to add a new city ("Chicago, IL") and population ("16") pair to the table above + * referenced by the block reference `2c7cfa`, you could send the following + * headers: + * + * - `Operation`: `append` + * - `TargetType`: `block` + * - `Target`: `2c7cfa` + * - `Content-Type`: `application/json` + * - with the request body: `[["Chicago, IL", "16"]]` + * + * The use of a `Content-Type` of `application/json` allows the API + * to infer that member of your array represents rows and columns of your + * to append to the referenced table. You can of course just use a + * `Content-Type` of `text/markdown`, but in such a case you'll have to + * format your table row manually instead of letting the library figure + * it out for you. + * + * You also have the option of using `prepend` (in which case, your new + * row would be the first -- right below the table heading) or `replace` (in which + * case all rows except the table heading would be replaced by the new row(s) + * you supplied). + * + * ## Setting a Frontmatter Field + * + * If you wanted to set the frontmatter field `alpha` to `2`, you could + * send the following headers: + * + * - `Operation`: `replace` + * - `TargetType`: `frontmatter` + * - `Target`: `beep` + * - with the request body `2` + * + * If you're setting a frontmatter field that might not already exist + * you may want to use the `Create-Target-If-Missing` header so the + * new frontmatter field is created and set to your specified value + * if it doesn't already exist. + * + * You may find using a `Content-Type` of `application/json` to be + * particularly useful in the case of frontmatter since frontmatter + * fields' values are JSON data, and the API can be smarter about + * interpreting yoru `prepend` or `append` requests if you specify + * your data as JSON (particularly when appending, for example, + * list items). + * + */ +export const patchPeriodicByPeriodByYearByMonthByDay = (options: Options) => { + return (options.client ?? _heyApiClient).patch({ + security: [ + { + scheme: 'bearer', + type: 'http' + } + ], + url: '/periodic/{period}/{year}/{month}/{day}/', + ...options, + headers: { + 'Content-Type': 'application/json', + ...options?.headers + } + }); +}; + +/** + * Append content to the periodic note for the specified period and date. + * + * This will create the relevant periodic note if necessary. + * + */ +export const postPeriodicByPeriodByYearByMonthByDay = (options: Options) => { + return (options.client ?? _heyApiClient).post({ + bodySerializer: null, + security: [ + { + scheme: 'bearer', + type: 'http' + } + ], + url: '/periodic/{period}/{year}/{month}/{day}/', + ...options, + headers: { + 'Content-Type': 'text/markdown', + ...options?.headers + } + }); +}; + +/** + * Update the content of the periodic note for the specified period and date. + * + */ +export const putPeriodicByPeriodByYearByMonthByDay = (options: Options) => { + return (options.client ?? _heyApiClient).put({ + security: [ + { + scheme: 'bearer', + type: 'http' + } + ], + url: '/periodic/{period}/{year}/{month}/{day}/', + ...options, + headers: { + 'Content-Type': '*/*', + ...options?.headers + } + }); +}; + /** * Search for documents matching a specified search query * @@ -694,9 +956,9 @@ export const getVaultByFilename = (options }; /** - * Insert content into an existing note relative to a heading within that document. + * Partially update content in an existing note. * - * Inserts content into an existing note relative to a heading within your note. + * Inserts content into an existing note relative to a heading, block refeerence, or frontmatter field within that document. * * Allows you to modify the content relative to a heading, block reference, or frontmatter field in your document. * @@ -849,7 +1111,7 @@ export const patchVaultByFilename = (optio * * Appends content to the end of an existing note. If the specified file does not yet exist, it will be created as an empty file. * - * If you would like to insert text relative to a particular heading instead of appending to the end of the file, see 'patch'. + * If you would like to insert text relative to a particular heading, block reference, or frontmatter field instead of appending to the end of the file, see 'patch'. * */ export const postVaultByFilename = (options: Options) => { diff --git a/packages/obsidian/generated/types.gen.ts b/packages/obsidian/generated/types.gen.ts index e1fd6bcc0..7367f5f92 100644 --- a/packages/obsidian/generated/types.gen.ts +++ b/packages/obsidian/generated/types.gen.ts @@ -295,6 +295,20 @@ export type PostCommandsByCommandIdResponses = { export type PostCommandsByCommandIdResponse = PostCommandsByCommandIdResponses[keyof PostCommandsByCommandIdResponses]; +export type GetObsidianLocalRestApiCrtData = { + body?: never; + path?: never; + query?: never; + url: '/obsidian-local-rest-api.crt'; +}; + +export type GetObsidianLocalRestApiCrtResponses = { + /** + * Success + */ + 200: unknown; +}; + export type PostOpenByFilenameData = { body?: never; path: { @@ -320,11 +334,25 @@ export type PostOpenByFilenameResponses = { 200: unknown; }; +export type GetOpenapiYamlData = { + body?: never; + path?: never; + query?: never; + url: '/openapi.yaml'; +}; + +export type GetOpenapiYamlResponses = { + /** + * Success + */ + 200: unknown; +}; + export type DeletePeriodicByPeriodData = { body?: never; path: { /** - * The name of the period for which you would like to grab the current note. + * The name of the period for which you would like to grab a periodic note. */ period: 'daily' | 'weekly' | 'monthly' | 'quarterly' | 'yearly'; }; @@ -359,7 +387,7 @@ export type GetPeriodicByPeriodData = { body?: never; path: { /** - * The name of the period for which you would like to grab the current note. + * The name of the period for which you would like to grab a periodic note. */ period: 'daily' | 'weekly' | 'monthly' | 'quarterly' | 'yearly'; }; @@ -414,7 +442,7 @@ export type PatchPeriodicByPeriodData = { }; path: { /** - * The name of the period for which you would like to grab the current note. + * The name of the period for which you would like to grab a periodic note. */ period: 'daily' | 'weekly' | 'monthly' | 'quarterly' | 'yearly'; }; @@ -454,7 +482,7 @@ export type PostPeriodicByPeriodData = { body: string; path: { /** - * The name of the period for which you would like to grab the current note. + * The name of the period for which you would like to grab a periodic note. */ period: 'daily' | 'weekly' | 'monthly' | 'quarterly' | 'yearly'; }; @@ -492,7 +520,7 @@ export type PutPeriodicByPeriodData = { body: string; path: { /** - * The name of the period for which you would like to grab the current note. + * The name of the period for which you would like to grab a periodic note. */ period: 'daily' | 'weekly' | 'monthly' | 'quarterly' | 'yearly'; }; @@ -524,6 +552,270 @@ export type PutPeriodicByPeriodResponses = { export type PutPeriodicByPeriodResponse = PutPeriodicByPeriodResponses[keyof PutPeriodicByPeriodResponses]; +export type DeletePeriodicByPeriodByYearByMonthByDayData = { + body?: never; + path: { + /** + * The year of the date for which you would like to grab a periodic note. + */ + year: number; + /** + * The month (1-12) of the date for which you would like to grab a periodic note. + */ + month: number; + /** + * The day (1-31) of the date for which you would like to grab a periodic note. + */ + day: number; + /** + * The name of the period for which you would like to grab a periodic note. + */ + period: 'daily' | 'weekly' | 'monthly' | 'quarterly' | 'yearly'; + }; + query?: never; + url: '/periodic/{period}/{year}/{month}/{day}/'; +}; + +export type DeletePeriodicByPeriodByYearByMonthByDayErrors = { + /** + * File does not exist. + */ + 404: _Error; + /** + * Your path references a directory instead of a file; this request method is valid only for updating files. + * + */ + 405: _Error; +}; + +export type DeletePeriodicByPeriodByYearByMonthByDayError = DeletePeriodicByPeriodByYearByMonthByDayErrors[keyof DeletePeriodicByPeriodByYearByMonthByDayErrors]; + +export type DeletePeriodicByPeriodByYearByMonthByDayResponses = { + /** + * Success + */ + 204: void; +}; + +export type DeletePeriodicByPeriodByYearByMonthByDayResponse = DeletePeriodicByPeriodByYearByMonthByDayResponses[keyof DeletePeriodicByPeriodByYearByMonthByDayResponses]; + +export type GetPeriodicByPeriodByYearByMonthByDayData = { + body?: never; + path: { + /** + * The year of the date for which you would like to grab a periodic note. + */ + year: number; + /** + * The month (1-12) of the date for which you would like to grab a periodic note. + */ + month: number; + /** + * The day (1-31) of the date for which you would like to grab a periodic note. + */ + day: number; + /** + * The name of the period for which you would like to grab a periodic note. + */ + period: 'daily' | 'weekly' | 'monthly' | 'quarterly' | 'yearly'; + }; + query?: never; + url: '/periodic/{period}/{year}/{month}/{day}/'; +}; + +export type GetPeriodicByPeriodByYearByMonthByDayErrors = { + /** + * File does not exist + */ + 404: unknown; +}; + +export type GetPeriodicByPeriodByYearByMonthByDayResponses = { + /** + * Success + */ + 200: NoteJson; +}; + +export type GetPeriodicByPeriodByYearByMonthByDayResponse = GetPeriodicByPeriodByYearByMonthByDayResponses[keyof GetPeriodicByPeriodByYearByMonthByDayResponses]; + +export type PatchPeriodicByPeriodByYearByMonthByDayData = { + /** + * Content you would like to insert. + */ + body: string; + headers: { + /** + * Patch operation to perform + */ + Operation: 'append' | 'prepend' | 'replace'; + /** + * Type of target to patch + */ + 'Target-Type': 'heading' | 'block' | 'frontmatter'; + /** + * Delimiter to use for nested targets (i.e. Headings) + */ + 'Target-Delimiter'?: string; + /** + * Target to patch; this value can be URL-Encoded and *must* + * be URL-Encoded if it includes non-ASCII characters. + * + */ + Target: string; + /** + * Trim whitespace from Target before applying patch? + */ + 'Trim-Target-Whitespace'?: 'true' | 'false'; + }; + path: { + /** + * The year of the date for which you would like to grab a periodic note. + */ + year: number; + /** + * The month (1-12) of the date for which you would like to grab a periodic note. + */ + month: number; + /** + * The day (1-31) of the date for which you would like to grab a periodic note. + */ + day: number; + /** + * The name of the period for which you would like to grab a periodic note. + */ + period: 'daily' | 'weekly' | 'monthly' | 'quarterly' | 'yearly'; + }; + query?: never; + url: '/periodic/{period}/{year}/{month}/{day}/'; +}; + +export type PatchPeriodicByPeriodByYearByMonthByDayErrors = { + /** + * Bad Request; see response message for details. + */ + 400: _Error; + /** + * Does not exist + */ + 404: _Error; + /** + * Your path references a directory instead of a file; this request method is valid only for updating files. + * + */ + 405: _Error; +}; + +export type PatchPeriodicByPeriodByYearByMonthByDayError = PatchPeriodicByPeriodByYearByMonthByDayErrors[keyof PatchPeriodicByPeriodByYearByMonthByDayErrors]; + +export type PatchPeriodicByPeriodByYearByMonthByDayResponses = { + /** + * Success + */ + 200: unknown; +}; + +export type PostPeriodicByPeriodByYearByMonthByDayData = { + /** + * Content you would like to append. + */ + body: string; + path: { + /** + * The year of the date for which you would like to grab a periodic note. + */ + year: number; + /** + * The month (1-12) of the date for which you would like to grab a periodic note. + */ + month: number; + /** + * The day (1-31) of the date for which you would like to grab a periodic note. + */ + day: number; + /** + * The name of the period for which you would like to grab a periodic note. + */ + period: 'daily' | 'weekly' | 'monthly' | 'quarterly' | 'yearly'; + }; + query?: never; + url: '/periodic/{period}/{year}/{month}/{day}/'; +}; + +export type PostPeriodicByPeriodByYearByMonthByDayErrors = { + /** + * Bad Request + */ + 400: _Error; + /** + * Your path references a directory instead of a file; this request method is valid only for updating files. + * + */ + 405: _Error; +}; + +export type PostPeriodicByPeriodByYearByMonthByDayError = PostPeriodicByPeriodByYearByMonthByDayErrors[keyof PostPeriodicByPeriodByYearByMonthByDayErrors]; + +export type PostPeriodicByPeriodByYearByMonthByDayResponses = { + /** + * Success + */ + 204: void; +}; + +export type PostPeriodicByPeriodByYearByMonthByDayResponse = PostPeriodicByPeriodByYearByMonthByDayResponses[keyof PostPeriodicByPeriodByYearByMonthByDayResponses]; + +export type PutPeriodicByPeriodByYearByMonthByDayData = { + /** + * Content of the file you would like to upload. + */ + body: string; + path: { + /** + * The year of the date for which you would like to grab a periodic note. + */ + year: number; + /** + * The month (1-12) of the date for which you would like to grab a periodic note. + */ + month: number; + /** + * The day (1-31) of the date for which you would like to grab a periodic note. + */ + day: number; + /** + * The name of the period for which you would like to grab a periodic note. + */ + period: 'daily' | 'weekly' | 'monthly' | 'quarterly' | 'yearly'; + }; + query?: never; + url: '/periodic/{period}/{year}/{month}/{day}/'; +}; + +export type PutPeriodicByPeriodByYearByMonthByDayErrors = { + /** + * Incoming file could not be processed. Make sure you have specified a reasonable file name, and make sure you have set a reasonable 'Content-Type' header; if you are uploading a note, 'text/markdown' is likely the right choice. + * + */ + 400: _Error; + /** + * Your path references a directory instead of a file; this request method is valid only for updating files. + * + */ + 405: _Error; +}; + +export type PutPeriodicByPeriodByYearByMonthByDayError = PutPeriodicByPeriodByYearByMonthByDayErrors[keyof PutPeriodicByPeriodByYearByMonthByDayErrors]; + +export type PutPeriodicByPeriodByYearByMonthByDayResponses = { + /** + * Success + */ + 204: void; +}; + +export type PutPeriodicByPeriodByYearByMonthByDayResponse = PutPeriodicByPeriodByYearByMonthByDayResponses[keyof PutPeriodicByPeriodByYearByMonthByDayResponses]; + export type PostSearchData = { body: { [key: string]: unknown; diff --git a/packages/obsidian/index.ts b/packages/obsidian/index.ts index d9e6cc28c..15dc9228a 100644 --- a/packages/obsidian/index.ts +++ b/packages/obsidian/index.ts @@ -1 +1,2 @@ -export * from "@hey-api/client-fetch"; +export * from "./generated"; +export * from "./generated/client.gen"; diff --git a/packages/obsidian/openapi.yaml b/packages/obsidian/openapi.yaml index ba0a5c7ae..d8b74b2cb 100644 --- a/packages/obsidian/openapi.yaml +++ b/packages/obsidian/openapi.yaml @@ -97,7 +97,7 @@ paths: summary: | Returns basic details about the server. tags: - - "Status" + - "System" /active/: delete: parameters: [] @@ -149,7 +149,7 @@ paths: - "Active File" patch: description: | - Inserts content into the currently-open note relative to a heading within that note. + Inserts content into the currently-open note relative to a heading, block refeerence, or frontmatter field within that document. Allows you to modify the content relative to a heading, block reference, or frontmatter field in your document. @@ -362,7 +362,7 @@ paths: description: | Your path references a directory instead of a file; this request method is valid only for updating files. summary: | - Insert content into the currently open note in Obsidian relative to a heading within that document. + Partially update content in the currently open note. tags: - "Active File" post: @@ -403,6 +403,7 @@ paths: tags: - "Active File" put: + parameters: [] requestBody: content: "*/*": @@ -489,11 +490,18 @@ paths: Execute a command. tags: - "Commands" + /obsidian-local-rest-api.crt: + get: + responses: + "200": + description: "Success" + summary: | + Returns the certificate in use by this API. + tags: + - "System" "/open/{filename}": post: description: | - Opens the specified document in Obsidian. - Note: Obsidian will create a new document at the path you have specified if such a document did not already exist. parameters: @@ -515,15 +523,442 @@ paths: "200": description: "Success" summary: | - Open the specified document in Obsidian + Open the specified document in the Obsidian user interface. tags: - "Open" + /openapi.yaml: + get: + responses: + "200": + description: "Success" + summary: | + Returns OpenAPI YAML document describing the capabilities of this API. + tags: + - "System" "/periodic/{period}/": + delete: + parameters: + - description: "The name of the period for which you would like to grab a periodic note." + in: "path" + name: "period" + required: true + schema: + default: "daily" + enum: + - "daily" + - "weekly" + - "monthly" + - "quarterly" + - "yearly" + type: "string" + responses: + "204": + description: "Success" + "404": + content: + application/json: + schema: + "$ref": "#/components/schemas/Error" + description: "File does not exist." + "405": + content: + application/json: + schema: + "$ref": "#/components/schemas/Error" + description: | + Your path references a directory instead of a file; this request method is valid only for updating files. + summary: | + Delete the current periodic note for the specified period. + tags: + - "Periodic Notes" + get: + parameters: + - description: "The name of the period for which you would like to grab a periodic note." + in: "path" + name: "period" + required: true + schema: + default: "daily" + enum: + - "daily" + - "weekly" + - "monthly" + - "quarterly" + - "yearly" + type: "string" + responses: + "200": + content: + "application/vnd.olrapi.note+json": + schema: + "$ref": "#/components/schemas/NoteJson" + text/markdown: + schema: + example: | + # This is my document + + something else here + type: "string" + description: "Success" + "404": + description: "File does not exist" + summary: | + Get current periodic note for the specified period. + tags: + - "Periodic Notes" + patch: + description: | + Inserts content into the current periodic note for the specified period relative to a heading, block refeerence, or frontmatter field within that document. + + Allows you to modify the content relative to a heading, block reference, or frontmatter field in your document. + + Note that this API was changed in Version 3.0 of this extension and the earlier PATCH API is now deprecated. Requests made using the previous version of this API will continue to work until Version 4.0 is released. See https://github.com/coddingtonbear/obsidian-local-rest-api/wiki/Changes-to-PATCH-requests-between-versions-2.0-and-3.0 for more details and migration instructions. + + # Examples + + All of the below examples assume you have a document that looks like + this: + + ```markdown + --- + alpha: 1 + beta: test + delta: + zeta: 1 + yotta: 1 + gamma: + - one + - two + --- + + # Heading 1 + + This is the content for heading one + + Also references some [[#^484ef2]] + + ## Subheading 1:1 + Content for Subheading 1:1 + + ### Subsubheading 1:1:1 + + ### Subsubheading 1:1:2 + + Testing how block references work for a table.[[#^2c7cfa]] + Some content for Subsubheading 1:1:2 + + More random text. + + ^2d9b4a + + ## Subheading 1:2 + + Content for Subheading 1:2. + + some content with a block reference ^484ef2 + + ## Subheading 1:3 + | City | Population | + | ------------ | ---------- | + | Seattle, WA | 8 | + | Portland, OR | 4 | + + ^2c7cfa + ``` + + ## Append Content Below a Heading + + If you wanted to append the content "Hello" below "Subheading 1:1:1" under "Heading 1", + you could send a request with the following headers: + + - `Operation`: `append` + - `Target-Type`: `heading` + - `Target`: `Heading 1::Subheading 1:1:1` + - with the request body: `Hello` + + The above would work just fine for `prepend` or `replace`, too, of course, + but with different results. + + ## Append Content to a Block Reference + + If you wanted to append the content "Hello" below the block referenced by + "2d9b4a" above ("More random text."), you could send the following headers: + + - `Operation`: `append` + - `Target-Type`: `block` + - `Target`: `2d9b4a` + - with the request body: `Hello` + + The above would work just fine for `prepend` or `replace`, too, of course, + but with different results. + + ## Add a Row to a Table Referenced by a Block Reference + + If you wanted to add a new city ("Chicago, IL") and population ("16") pair to the table above + referenced by the block reference `2c7cfa`, you could send the following + headers: + + - `Operation`: `append` + - `TargetType`: `block` + - `Target`: `2c7cfa` + - `Content-Type`: `application/json` + - with the request body: `[["Chicago, IL", "16"]]` + + The use of a `Content-Type` of `application/json` allows the API + to infer that member of your array represents rows and columns of your + to append to the referenced table. You can of course just use a + `Content-Type` of `text/markdown`, but in such a case you'll have to + format your table row manually instead of letting the library figure + it out for you. + + You also have the option of using `prepend` (in which case, your new + row would be the first -- right below the table heading) or `replace` (in which + case all rows except the table heading would be replaced by the new row(s) + you supplied). + + ## Setting a Frontmatter Field + + If you wanted to set the frontmatter field `alpha` to `2`, you could + send the following headers: + + - `Operation`: `replace` + - `TargetType`: `frontmatter` + - `Target`: `beep` + - with the request body `2` + + If you're setting a frontmatter field that might not already exist + you may want to use the `Create-Target-If-Missing` header so the + new frontmatter field is created and set to your specified value + if it doesn't already exist. + + You may find using a `Content-Type` of `application/json` to be + particularly useful in the case of frontmatter since frontmatter + fields' values are JSON data, and the API can be smarter about + interpreting yoru `prepend` or `append` requests if you specify + your data as JSON (particularly when appending, for example, + list items). + parameters: + - description: "Patch operation to perform" + in: "header" + name: "Operation" + required: true + schema: + enum: + - "append" + - "prepend" + - "replace" + type: "string" + - description: "Type of target to patch" + in: "header" + name: "Target-Type" + required: true + schema: + enum: + - "heading" + - "block" + - "frontmatter" + type: "string" + - description: "Delimiter to use for nested targets (i.e. Headings)" + in: "header" + name: "Target-Delimiter" + required: false + schema: + default: "::" + type: "string" + - description: | + Target to patch; this value can be URL-Encoded and *must* + be URL-Encoded if it includes non-ASCII characters. + in: "header" + name: "Target" + required: true + schema: + type: "string" + - description: "Trim whitespace from Target before applying patch?" + in: "header" + name: "Trim-Target-Whitespace" + required: false + schema: + default: "false" + enum: + - "true" + - "false" + type: "string" + - description: "The name of the period for which you would like to grab a periodic note." + in: "path" + name: "period" + required: true + schema: + default: "daily" + enum: + - "daily" + - "weekly" + - "monthly" + - "quarterly" + - "yearly" + type: "string" + requestBody: + content: + application/json: + schema: + example: "['one', 'two']" + type: "string" + text/markdown: + schema: + example: | + # This is my document + + something else here + type: "string" + description: "Content you would like to insert." + required: true + responses: + "200": + description: "Success" + "400": + content: + application/json: + schema: + "$ref": "#/components/schemas/Error" + description: "Bad Request; see response message for details." + "404": + content: + application/json: + schema: + "$ref": "#/components/schemas/Error" + description: "Does not exist" + "405": + content: + application/json: + schema: + "$ref": "#/components/schemas/Error" + description: | + Your path references a directory instead of a file; this request method is valid only for updating files. + summary: | + Partially update content in the current periodic note for the specified period. + tags: + - "Periodic Notes" + post: + description: | + Note that this will create the relevant periodic note if necessary. + parameters: + - description: "The name of the period for which you would like to grab a periodic note." + in: "path" + name: "period" + required: true + schema: + default: "daily" + enum: + - "daily" + - "weekly" + - "monthly" + - "quarterly" + - "yearly" + type: "string" + requestBody: + content: + text/markdown: + schema: + example: | + # This is my document + + something else here + type: "string" + description: "Content you would like to append." + required: true + responses: + "204": + description: "Success" + "400": + content: + application/json: + schema: + "$ref": "#/components/schemas/Error" + description: "Bad Request" + "405": + content: + application/json: + schema: + "$ref": "#/components/schemas/Error" + description: | + Your path references a directory instead of a file; this request method is valid only for updating files. + summary: | + Append content to the current periodic note for the specified period. + tags: + - "Periodic Notes" + put: + parameters: + - description: "The name of the period for which you would like to grab a periodic note." + in: "path" + name: "period" + required: true + schema: + default: "daily" + enum: + - "daily" + - "weekly" + - "monthly" + - "quarterly" + - "yearly" + type: "string" + requestBody: + content: + "*/*": + schema: + type: "string" + text/markdown: + schema: + example: | + # This is my document + + something else here + type: "string" + description: "Content of the file you would like to upload." + required: true + responses: + "204": + description: "Success" + "400": + content: + application/json: + schema: + "$ref": "#/components/schemas/Error" + description: | + Incoming file could not be processed. Make sure you have specified a reasonable file name, and make sure you have set a reasonable 'Content-Type' header; if you are uploading a note, 'text/markdown' is likely the right choice. + "405": + content: + application/json: + schema: + "$ref": "#/components/schemas/Error" + description: | + Your path references a directory instead of a file; this request method is valid only for updating files. + summary: | + Update the content of the current periodic note for the specified period. + tags: + - "Periodic Notes" + "/periodic/{period}/{year}/{month}/{day}/": delete: description: | Deletes the periodic note for the specified period. parameters: - - description: "The name of the period for which you would like to grab the current note." + - description: "The year of the date for which you would like to grab a periodic note." + in: "path" + name: "year" + required: true + schema: + type: "number" + - description: "The month (1-12) of the date for which you would like to grab a periodic note." + in: "path" + name: "month" + required: true + schema: + type: "number" + - description: "The day (1-31) of the date for which you would like to grab a periodic note." + in: "path" + name: "day" + required: true + schema: + type: "number" + - description: "The name of the period for which you would like to grab a periodic note." in: "path" name: "period" required: true @@ -553,12 +988,30 @@ paths: description: | Your path references a directory instead of a file; this request method is valid only for updating files. summary: | - Delete a periodic note. + Delete the periodic note for the specified period and date. tags: - "Periodic Notes" get: parameters: - - description: "The name of the period for which you would like to grab the current note." + - description: "The year of the date for which you would like to grab a periodic note." + in: "path" + name: "year" + required: true + schema: + type: "number" + - description: "The month (1-12) of the date for which you would like to grab a periodic note." + in: "path" + name: "month" + required: true + schema: + type: "number" + - description: "The day (1-31) of the date for which you would like to grab a periodic note." + in: "path" + name: "day" + required: true + schema: + type: "number" + - description: "The name of the period for which you would like to grab a periodic note." in: "path" name: "period" required: true @@ -588,12 +1041,12 @@ paths: "404": description: "File does not exist" summary: | - Get current periodic note for the specified period. + Get the periodic note for the specified period and date. tags: - "Periodic Notes" patch: description: | - Inserts content into an existing note relative to a heading within your note. + Inserts content into a periodic note relative to a heading, block refeerence, or frontmatter field within that document. Allows you to modify the content relative to a heading, block reference, or frontmatter field in your document. @@ -768,7 +1221,25 @@ paths: - "true" - "false" type: "string" - - description: "The name of the period for which you would like to grab the current note." + - description: "The year of the date for which you would like to grab a periodic note." + in: "path" + name: "year" + required: true + schema: + type: "number" + - description: "The month (1-12) of the date for which you would like to grab a periodic note." + in: "path" + name: "month" + required: true + schema: + type: "number" + - description: "The day (1-31) of the date for which you would like to grab a periodic note." + in: "path" + name: "day" + required: true + schema: + type: "number" + - description: "The name of the period for which you would like to grab a periodic note." in: "path" name: "period" required: true @@ -819,14 +1290,32 @@ paths: description: | Your path references a directory instead of a file; this request method is valid only for updating files. summary: | - Insert content into a periodic note relative to a heading within that document. + Partially update content in the periodic note for the specified period and date. tags: - "Periodic Notes" post: description: | - Appends content to the periodic note for the specified period. This will create the relevant periodic note if necessary. + This will create the relevant periodic note if necessary. parameters: - - description: "The name of the period for which you would like to grab the current note." + - description: "The year of the date for which you would like to grab a periodic note." + in: "path" + name: "year" + required: true + schema: + type: "number" + - description: "The month (1-12) of the date for which you would like to grab a periodic note." + in: "path" + name: "month" + required: true + schema: + type: "number" + - description: "The day (1-31) of the date for which you would like to grab a periodic note." + in: "path" + name: "day" + required: true + schema: + type: "number" + - description: "The name of the period for which you would like to grab a periodic note." in: "path" name: "period" required: true @@ -867,12 +1356,30 @@ paths: description: | Your path references a directory instead of a file; this request method is valid only for updating files. summary: | - Append content to a periodic note. + Append content to the periodic note for the specified period and date. tags: - "Periodic Notes" put: parameters: - - description: "The name of the period for which you would like to grab the current note." + - description: "The year of the date for which you would like to grab a periodic note." + in: "path" + name: "year" + required: true + schema: + type: "number" + - description: "The month (1-12) of the date for which you would like to grab a periodic note." + in: "path" + name: "month" + required: true + schema: + type: "number" + - description: "The day (1-31) of the date for which you would like to grab a periodic note." + in: "path" + name: "day" + required: true + schema: + type: "number" + - description: "The name of the period for which you would like to grab a periodic note." in: "path" name: "period" required: true @@ -917,7 +1424,7 @@ paths: description: | Your path references a directory instead of a file; this request method is valid only for updating files. summary: | - Update the content of a periodic note. + Update the content of the periodic note for the specified period and date. tags: - "Periodic Notes" /search/: @@ -1195,7 +1702,7 @@ paths: - "Vault Files" patch: description: | - Inserts content into an existing note relative to a heading within your note. + Inserts content into an existing note relative to a heading, block refeerence, or frontmatter field within that document. Allows you to modify the content relative to a heading, block reference, or frontmatter field in your document. @@ -1416,14 +1923,14 @@ paths: description: | Your path references a directory instead of a file; this request method is valid only for updating files. summary: | - Insert content into an existing note relative to a heading within that document. + Partially update content in an existing note. tags: - "Vault Files" post: description: | Appends content to the end of an existing note. If the specified file does not yet exist, it will be created as an empty file. - If you would like to insert text relative to a particular heading instead of appending to the end of the file, see 'patch'. + If you would like to insert text relative to a particular heading, block reference, or frontmatter field instead of appending to the end of the file, see 'patch'. parameters: - description: | Path to the relevant file (relative to your vault root). diff --git a/packages/obsidian/package.json b/packages/obsidian/package.json index b06efac50..b39f5e4c2 100644 --- a/packages/obsidian/package.json +++ b/packages/obsidian/package.json @@ -13,10 +13,10 @@ "generate": "openapi-ts && [ \"$GITHUB_WORKFLOW\" != \"\" ] && git diff --exit-code generated/ || true" }, "devDependencies": { - "@hey-api/openapi-ts": "^0.64.15" + "@hey-api/openapi-ts": "^0.78.3" }, "dependencies": { "@hey-api/client-fetch": "^0.8.4", - "@tanstack/react-query": "^5.79.0" + "@tanstack/react-query": "^5.83.0" } } diff --git a/packages/tiptap/src/shared/index.ts b/packages/tiptap/src/shared/index.ts index 55e635e1e..8ee41f039 100644 --- a/packages/tiptap/src/shared/index.ts +++ b/packages/tiptap/src/shared/index.ts @@ -1,3 +1,4 @@ export * from "./animation"; export * from "./extensions"; export * from "./hashtag"; +export * from "./utils"; diff --git a/plugins/membership/permissions/autogenerated/commands/ping.toml b/plugins/membership/permissions/autogenerated/commands/ping.toml deleted file mode 100644 index 1d1358807..000000000 --- a/plugins/membership/permissions/autogenerated/commands/ping.toml +++ /dev/null @@ -1,13 +0,0 @@ -# Automatically generated - DO NOT EDIT! - -"$schema" = "../../schemas/schema.json" - -[[permission]] -identifier = "allow-ping" -description = "Enables the ping command without any pre-configured scope." -commands.allow = ["ping"] - -[[permission]] -identifier = "deny-ping" -description = "Denies the ping command without any pre-configured scope." -commands.deny = ["ping"] diff --git a/plugins/membership/permissions/autogenerated/reference.md b/plugins/membership/permissions/autogenerated/reference.md index 817ec0385..7ef6f2a1d 100644 --- a/plugins/membership/permissions/autogenerated/reference.md +++ b/plugins/membership/permissions/autogenerated/reference.md @@ -4,7 +4,7 @@ Default permissions for the plugin #### This default permission set includes the following: -- `allow-ping` +- `allow-check` ## Permission Table @@ -38,32 +38,6 @@ Enables the check command without any pre-configured scope. Denies the check command without any pre-configured scope. - - - - - - -`membership:allow-ping` - - - - -Enables the ping command without any pre-configured scope. - - - - - - - -`membership:deny-ping` - - - - -Denies the ping command without any pre-configured scope. - diff --git a/plugins/membership/permissions/default.toml b/plugins/membership/permissions/default.toml index cc5a76f22..6ba65bb59 100644 --- a/plugins/membership/permissions/default.toml +++ b/plugins/membership/permissions/default.toml @@ -1,3 +1,3 @@ [default] description = "Default permissions for the plugin" -permissions = ["allow-ping"] +permissions = ["allow-check"] diff --git a/plugins/membership/permissions/schemas/schema.json b/plugins/membership/permissions/schemas/schema.json index a04fcbc72..aa982ca4e 100644 --- a/plugins/membership/permissions/schemas/schema.json +++ b/plugins/membership/permissions/schemas/schema.json @@ -307,22 +307,10 @@ "markdownDescription": "Denies the check command without any pre-configured scope." }, { - "description": "Enables the ping command without any pre-configured scope.", - "type": "string", - "const": "allow-ping", - "markdownDescription": "Enables the ping command without any pre-configured scope." - }, - { - "description": "Denies the ping command without any pre-configured scope.", - "type": "string", - "const": "deny-ping", - "markdownDescription": "Denies the ping command without any pre-configured scope." - }, - { - "description": "Default permissions for the plugin\n#### This default permission set includes:\n\n- `allow-ping`", + "description": "Default permissions for the plugin\n#### This default permission set includes:\n\n- `allow-check`", "type": "string", "const": "default", - "markdownDescription": "Default permissions for the plugin\n#### This default permission set includes:\n\n- `allow-ping`" + "markdownDescription": "Default permissions for the plugin\n#### This default permission set includes:\n\n- `allow-check`" } ] } diff --git a/plugins/obsidian/.gitignore b/plugins/obsidian/.gitignore new file mode 100644 index 000000000..50d8e32e8 --- /dev/null +++ b/plugins/obsidian/.gitignore @@ -0,0 +1,17 @@ +/.vs +.DS_Store +.Thumbs.db +*.sublime* +.idea/ +debug.log +package-lock.json +.vscode/settings.json +yarn.lock + +/.tauri +/target +Cargo.lock +node_modules/ + +dist-js +dist diff --git a/plugins/obsidian/Cargo.toml b/plugins/obsidian/Cargo.toml new file mode 100644 index 000000000..d099e15f8 --- /dev/null +++ b/plugins/obsidian/Cargo.toml @@ -0,0 +1,29 @@ +[package] +name = "tauri-plugin-obsidian" +version = "0.1.0" +authors = ["You"] +edition = "2021" +exclude = ["/js", "/node_modules"] +links = "tauri-plugin-obsidian" +description = "" + +[build-dependencies] +tauri-plugin = { workspace = true, features = ["build"] } + +[dev-dependencies] +specta-typescript = { workspace = true } +tauri-plugin-store = { workspace = true } + +[dependencies] +tauri-plugin-store2 = { workspace = true } + +serde = { workspace = true } +specta = { workspace = true } +strum = { workspace = true, features = ["derive"] } +thiserror = { workspace = true } + +tokio = { workspace = true, features = ["time"] } +tracing = { workspace = true } + +tauri = { workspace = true, features = ["test"] } +tauri-specta = { workspace = true, features = ["derive", "typescript"] } diff --git a/plugins/obsidian/build.rs b/plugins/obsidian/build.rs new file mode 100644 index 000000000..d3e2540c3 --- /dev/null +++ b/plugins/obsidian/build.rs @@ -0,0 +1,17 @@ +const COMMANDS: &[&str] = &[ + "set_api_key", + "set_base_url", + "get_api_key", + "get_base_url", + "get_vault_name", + "set_vault_name", + "get_enabled", + "set_enabled", + "get_deep_link_url", + "get_base_folder", + "set_base_folder", +]; + +fn main() { + tauri_plugin::Builder::new(COMMANDS).build(); +} diff --git a/plugins/obsidian/js/bindings.gen.ts b/plugins/obsidian/js/bindings.gen.ts new file mode 100644 index 000000000..941f8f35d --- /dev/null +++ b/plugins/obsidian/js/bindings.gen.ts @@ -0,0 +1,115 @@ +// @ts-nocheck + + +// This file was generated by [tauri-specta](https://github.com/oscartbeaumont/tauri-specta). Do not edit this file manually. + +/** user-defined commands **/ + + +export const commands = { +async setApiKey(apiKey: string) : Promise { + return await TAURI_INVOKE("plugin:obsidian|set_api_key", { apiKey }); +}, +async setBaseUrl(baseUrl: string) : Promise { + return await TAURI_INVOKE("plugin:obsidian|set_base_url", { baseUrl }); +}, +async getApiKey() : Promise { + return await TAURI_INVOKE("plugin:obsidian|get_api_key"); +}, +async getBaseUrl() : Promise { + return await TAURI_INVOKE("plugin:obsidian|get_base_url"); +}, +async getVaultName() : Promise { + return await TAURI_INVOKE("plugin:obsidian|get_vault_name"); +}, +async setVaultName(vaultName: string) : Promise { + return await TAURI_INVOKE("plugin:obsidian|set_vault_name", { vaultName }); +}, +async getEnabled() : Promise { + return await TAURI_INVOKE("plugin:obsidian|get_enabled"); +}, +async setEnabled(enabled: boolean) : Promise { + return await TAURI_INVOKE("plugin:obsidian|set_enabled", { enabled }); +}, +async getDeepLinkUrl(noteName: string) : Promise { + return await TAURI_INVOKE("plugin:obsidian|get_deep_link_url", { noteName }); +}, +async getBaseFolder() : Promise { + return await TAURI_INVOKE("plugin:obsidian|get_base_folder"); +}, +async setBaseFolder(baseFolder: string) : Promise { + return await TAURI_INVOKE("plugin:obsidian|set_base_folder", { baseFolder }); +} +} + +/** user-defined events **/ + + + +/** user-defined constants **/ + + + +/** user-defined types **/ + + + +/** tauri-specta globals **/ + +import { + invoke as TAURI_INVOKE, + Channel as TAURI_CHANNEL, +} from "@tauri-apps/api/core"; +import * as TAURI_API_EVENT from "@tauri-apps/api/event"; +import { type WebviewWindow as __WebviewWindow__ } from "@tauri-apps/api/webviewWindow"; + +type __EventObj__ = { + listen: ( + cb: TAURI_API_EVENT.EventCallback, + ) => ReturnType>; + once: ( + cb: TAURI_API_EVENT.EventCallback, + ) => ReturnType>; + emit: null extends T + ? (payload?: T) => ReturnType + : (payload: T) => ReturnType; +}; + +export type Result = + | { status: "ok"; data: T } + | { status: "error"; error: E }; + +function __makeEvents__>( + mappings: Record, +) { + return new Proxy( + {} as unknown as { + [K in keyof T]: __EventObj__ & { + (handle: __WebviewWindow__): __EventObj__; + }; + }, + { + get: (_, event) => { + const name = mappings[event as keyof T]; + + return new Proxy((() => {}) as any, { + apply: (_, __, [window]: [__WebviewWindow__]) => ({ + listen: (arg: any) => window.listen(name, arg), + once: (arg: any) => window.once(name, arg), + emit: (arg: any) => window.emit(name, arg), + }), + get: (_, command: keyof __EventObj__) => { + switch (command) { + case "listen": + return (arg: any) => TAURI_API_EVENT.listen(name, arg); + case "once": + return (arg: any) => TAURI_API_EVENT.once(name, arg); + case "emit": + return (arg: any) => TAURI_API_EVENT.emit(name, arg); + } + }, + }); + }, + }, + ); +} diff --git a/plugins/obsidian/js/index.ts b/plugins/obsidian/js/index.ts new file mode 100644 index 000000000..86f5a993f --- /dev/null +++ b/plugins/obsidian/js/index.ts @@ -0,0 +1,2 @@ +export * from "@hypr/obsidian"; +export * from "./bindings.gen"; diff --git a/plugins/obsidian/package.json b/plugins/obsidian/package.json new file mode 100644 index 000000000..d4c24d003 --- /dev/null +++ b/plugins/obsidian/package.json @@ -0,0 +1,12 @@ +{ + "name": "@hypr/plugin-obsidian", + "private": true, + "main": "./js/index.ts", + "scripts": { + "codegen": "cargo test -p tauri-plugin-obsidian" + }, + "dependencies": { + "@tauri-apps/api": "^2.6.0", + "@hypr/obsidian": "workspace:^" + } +} diff --git a/plugins/obsidian/permissions/autogenerated/commands/get_api_key.toml b/plugins/obsidian/permissions/autogenerated/commands/get_api_key.toml new file mode 100644 index 000000000..f893bf85e --- /dev/null +++ b/plugins/obsidian/permissions/autogenerated/commands/get_api_key.toml @@ -0,0 +1,13 @@ +# Automatically generated - DO NOT EDIT! + +"$schema" = "../../schemas/schema.json" + +[[permission]] +identifier = "allow-get-api-key" +description = "Enables the get_api_key command without any pre-configured scope." +commands.allow = ["get_api_key"] + +[[permission]] +identifier = "deny-get-api-key" +description = "Denies the get_api_key command without any pre-configured scope." +commands.deny = ["get_api_key"] diff --git a/plugins/obsidian/permissions/autogenerated/commands/get_base_folder.toml b/plugins/obsidian/permissions/autogenerated/commands/get_base_folder.toml new file mode 100644 index 000000000..baa579daf --- /dev/null +++ b/plugins/obsidian/permissions/autogenerated/commands/get_base_folder.toml @@ -0,0 +1,13 @@ +# Automatically generated - DO NOT EDIT! + +"$schema" = "../../schemas/schema.json" + +[[permission]] +identifier = "allow-get-base-folder" +description = "Enables the get_base_folder command without any pre-configured scope." +commands.allow = ["get_base_folder"] + +[[permission]] +identifier = "deny-get-base-folder" +description = "Denies the get_base_folder command without any pre-configured scope." +commands.deny = ["get_base_folder"] diff --git a/plugins/obsidian/permissions/autogenerated/commands/get_base_url.toml b/plugins/obsidian/permissions/autogenerated/commands/get_base_url.toml new file mode 100644 index 000000000..ae0a0baf0 --- /dev/null +++ b/plugins/obsidian/permissions/autogenerated/commands/get_base_url.toml @@ -0,0 +1,13 @@ +# Automatically generated - DO NOT EDIT! + +"$schema" = "../../schemas/schema.json" + +[[permission]] +identifier = "allow-get-base-url" +description = "Enables the get_base_url command without any pre-configured scope." +commands.allow = ["get_base_url"] + +[[permission]] +identifier = "deny-get-base-url" +description = "Denies the get_base_url command without any pre-configured scope." +commands.deny = ["get_base_url"] diff --git a/plugins/obsidian/permissions/autogenerated/commands/get_deep_link_url.toml b/plugins/obsidian/permissions/autogenerated/commands/get_deep_link_url.toml new file mode 100644 index 000000000..13842e92f --- /dev/null +++ b/plugins/obsidian/permissions/autogenerated/commands/get_deep_link_url.toml @@ -0,0 +1,13 @@ +# Automatically generated - DO NOT EDIT! + +"$schema" = "../../schemas/schema.json" + +[[permission]] +identifier = "allow-get-deep-link-url" +description = "Enables the get_deep_link_url command without any pre-configured scope." +commands.allow = ["get_deep_link_url"] + +[[permission]] +identifier = "deny-get-deep-link-url" +description = "Denies the get_deep_link_url command without any pre-configured scope." +commands.deny = ["get_deep_link_url"] diff --git a/plugins/obsidian/permissions/autogenerated/commands/get_enabled.toml b/plugins/obsidian/permissions/autogenerated/commands/get_enabled.toml new file mode 100644 index 000000000..d2991b1f3 --- /dev/null +++ b/plugins/obsidian/permissions/autogenerated/commands/get_enabled.toml @@ -0,0 +1,13 @@ +# Automatically generated - DO NOT EDIT! + +"$schema" = "../../schemas/schema.json" + +[[permission]] +identifier = "allow-get-enabled" +description = "Enables the get_enabled command without any pre-configured scope." +commands.allow = ["get_enabled"] + +[[permission]] +identifier = "deny-get-enabled" +description = "Denies the get_enabled command without any pre-configured scope." +commands.deny = ["get_enabled"] diff --git a/plugins/obsidian/permissions/autogenerated/commands/get_vault_name.toml b/plugins/obsidian/permissions/autogenerated/commands/get_vault_name.toml new file mode 100644 index 000000000..5058a96f7 --- /dev/null +++ b/plugins/obsidian/permissions/autogenerated/commands/get_vault_name.toml @@ -0,0 +1,13 @@ +# Automatically generated - DO NOT EDIT! + +"$schema" = "../../schemas/schema.json" + +[[permission]] +identifier = "allow-get-vault-name" +description = "Enables the get_vault_name command without any pre-configured scope." +commands.allow = ["get_vault_name"] + +[[permission]] +identifier = "deny-get-vault-name" +description = "Denies the get_vault_name command without any pre-configured scope." +commands.deny = ["get_vault_name"] diff --git a/plugins/obsidian/permissions/autogenerated/commands/set_api_key.toml b/plugins/obsidian/permissions/autogenerated/commands/set_api_key.toml new file mode 100644 index 000000000..7de43a95e --- /dev/null +++ b/plugins/obsidian/permissions/autogenerated/commands/set_api_key.toml @@ -0,0 +1,13 @@ +# Automatically generated - DO NOT EDIT! + +"$schema" = "../../schemas/schema.json" + +[[permission]] +identifier = "allow-set-api-key" +description = "Enables the set_api_key command without any pre-configured scope." +commands.allow = ["set_api_key"] + +[[permission]] +identifier = "deny-set-api-key" +description = "Denies the set_api_key command without any pre-configured scope." +commands.deny = ["set_api_key"] diff --git a/plugins/obsidian/permissions/autogenerated/commands/set_base_folder.toml b/plugins/obsidian/permissions/autogenerated/commands/set_base_folder.toml new file mode 100644 index 000000000..063301656 --- /dev/null +++ b/plugins/obsidian/permissions/autogenerated/commands/set_base_folder.toml @@ -0,0 +1,13 @@ +# Automatically generated - DO NOT EDIT! + +"$schema" = "../../schemas/schema.json" + +[[permission]] +identifier = "allow-set-base-folder" +description = "Enables the set_base_folder command without any pre-configured scope." +commands.allow = ["set_base_folder"] + +[[permission]] +identifier = "deny-set-base-folder" +description = "Denies the set_base_folder command without any pre-configured scope." +commands.deny = ["set_base_folder"] diff --git a/plugins/obsidian/permissions/autogenerated/commands/set_base_url.toml b/plugins/obsidian/permissions/autogenerated/commands/set_base_url.toml new file mode 100644 index 000000000..e7e7f1a32 --- /dev/null +++ b/plugins/obsidian/permissions/autogenerated/commands/set_base_url.toml @@ -0,0 +1,13 @@ +# Automatically generated - DO NOT EDIT! + +"$schema" = "../../schemas/schema.json" + +[[permission]] +identifier = "allow-set-base-url" +description = "Enables the set_base_url command without any pre-configured scope." +commands.allow = ["set_base_url"] + +[[permission]] +identifier = "deny-set-base-url" +description = "Denies the set_base_url command without any pre-configured scope." +commands.deny = ["set_base_url"] diff --git a/plugins/obsidian/permissions/autogenerated/commands/set_enabled.toml b/plugins/obsidian/permissions/autogenerated/commands/set_enabled.toml new file mode 100644 index 000000000..4be739a7a --- /dev/null +++ b/plugins/obsidian/permissions/autogenerated/commands/set_enabled.toml @@ -0,0 +1,13 @@ +# Automatically generated - DO NOT EDIT! + +"$schema" = "../../schemas/schema.json" + +[[permission]] +identifier = "allow-set-enabled" +description = "Enables the set_enabled command without any pre-configured scope." +commands.allow = ["set_enabled"] + +[[permission]] +identifier = "deny-set-enabled" +description = "Denies the set_enabled command without any pre-configured scope." +commands.deny = ["set_enabled"] diff --git a/plugins/obsidian/permissions/autogenerated/commands/set_vault_name.toml b/plugins/obsidian/permissions/autogenerated/commands/set_vault_name.toml new file mode 100644 index 000000000..ff132a1ce --- /dev/null +++ b/plugins/obsidian/permissions/autogenerated/commands/set_vault_name.toml @@ -0,0 +1,13 @@ +# Automatically generated - DO NOT EDIT! + +"$schema" = "../../schemas/schema.json" + +[[permission]] +identifier = "allow-set-vault-name" +description = "Enables the set_vault_name command without any pre-configured scope." +commands.allow = ["set_vault_name"] + +[[permission]] +identifier = "deny-set-vault-name" +description = "Denies the set_vault_name command without any pre-configured scope." +commands.deny = ["set_vault_name"] diff --git a/plugins/obsidian/permissions/autogenerated/reference.md b/plugins/obsidian/permissions/autogenerated/reference.md new file mode 100644 index 000000000..964c7f0b1 --- /dev/null +++ b/plugins/obsidian/permissions/autogenerated/reference.md @@ -0,0 +1,313 @@ +## Default Permission + +Default permissions for the plugin + +#### This default permission set includes the following: + +- `allow-get-api-key` +- `allow-get-base-url` +- `allow-get-vault-name` +- `allow-set-api-key` +- `allow-set-base-url` +- `allow-set-vault-name` +- `allow-get-enabled` +- `allow-set-enabled` +- `allow-get-deep-link-url` +- `allow-get-base-folder` +- `allow-set-base-folder` + +## Permission Table + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
IdentifierDescription
+ +`obsidian:allow-get-api-key` + + + +Enables the get_api_key command without any pre-configured scope. + +
+ +`obsidian:deny-get-api-key` + + + +Denies the get_api_key command without any pre-configured scope. + +
+ +`obsidian:allow-get-base-folder` + + + +Enables the get_base_folder command without any pre-configured scope. + +
+ +`obsidian:deny-get-base-folder` + + + +Denies the get_base_folder command without any pre-configured scope. + +
+ +`obsidian:allow-get-base-url` + + + +Enables the get_base_url command without any pre-configured scope. + +
+ +`obsidian:deny-get-base-url` + + + +Denies the get_base_url command without any pre-configured scope. + +
+ +`obsidian:allow-get-deep-link-url` + + + +Enables the get_deep_link_url command without any pre-configured scope. + +
+ +`obsidian:deny-get-deep-link-url` + + + +Denies the get_deep_link_url command without any pre-configured scope. + +
+ +`obsidian:allow-get-enabled` + + + +Enables the get_enabled command without any pre-configured scope. + +
+ +`obsidian:deny-get-enabled` + + + +Denies the get_enabled command without any pre-configured scope. + +
+ +`obsidian:allow-get-vault-name` + + + +Enables the get_vault_name command without any pre-configured scope. + +
+ +`obsidian:deny-get-vault-name` + + + +Denies the get_vault_name command without any pre-configured scope. + +
+ +`obsidian:allow-set-api-key` + + + +Enables the set_api_key command without any pre-configured scope. + +
+ +`obsidian:deny-set-api-key` + + + +Denies the set_api_key command without any pre-configured scope. + +
+ +`obsidian:allow-set-base-folder` + + + +Enables the set_base_folder command without any pre-configured scope. + +
+ +`obsidian:deny-set-base-folder` + + + +Denies the set_base_folder command without any pre-configured scope. + +
+ +`obsidian:allow-set-base-url` + + + +Enables the set_base_url command without any pre-configured scope. + +
+ +`obsidian:deny-set-base-url` + + + +Denies the set_base_url command without any pre-configured scope. + +
+ +`obsidian:allow-set-enabled` + + + +Enables the set_enabled command without any pre-configured scope. + +
+ +`obsidian:deny-set-enabled` + + + +Denies the set_enabled command without any pre-configured scope. + +
+ +`obsidian:allow-set-vault-name` + + + +Enables the set_vault_name command without any pre-configured scope. + +
+ +`obsidian:deny-set-vault-name` + + + +Denies the set_vault_name command without any pre-configured scope. + +
diff --git a/plugins/obsidian/permissions/default.toml b/plugins/obsidian/permissions/default.toml new file mode 100644 index 000000000..1f1a813fa --- /dev/null +++ b/plugins/obsidian/permissions/default.toml @@ -0,0 +1,15 @@ +[default] +description = "Default permissions for the plugin" +permissions = [ + "allow-get-api-key", + "allow-get-base-url", + "allow-get-vault-name", + "allow-set-api-key", + "allow-set-base-url", + "allow-set-vault-name", + "allow-get-enabled", + "allow-set-enabled", + "allow-get-deep-link-url", + "allow-get-base-folder", + "allow-set-base-folder", +] diff --git a/plugins/obsidian/permissions/schemas/schema.json b/plugins/obsidian/permissions/schemas/schema.json new file mode 100644 index 000000000..dab478c37 --- /dev/null +++ b/plugins/obsidian/permissions/schemas/schema.json @@ -0,0 +1,438 @@ +{ + "$schema": "http://json-schema.org/draft-07/schema#", + "title": "PermissionFile", + "description": "Permission file that can define a default permission, a set of permissions or a list of inlined permissions.", + "type": "object", + "properties": { + "default": { + "description": "The default permission set for the plugin", + "anyOf": [ + { + "$ref": "#/definitions/DefaultPermission" + }, + { + "type": "null" + } + ] + }, + "set": { + "description": "A list of permissions sets defined", + "type": "array", + "items": { + "$ref": "#/definitions/PermissionSet" + } + }, + "permission": { + "description": "A list of inlined permissions", + "default": [], + "type": "array", + "items": { + "$ref": "#/definitions/Permission" + } + } + }, + "definitions": { + "DefaultPermission": { + "description": "The default permission set of the plugin.\n\nWorks similarly to a permission with the \"default\" identifier.", + "type": "object", + "required": [ + "permissions" + ], + "properties": { + "version": { + "description": "The version of the permission.", + "type": [ + "integer", + "null" + ], + "format": "uint64", + "minimum": 1.0 + }, + "description": { + "description": "Human-readable description of what the permission does. Tauri convention is to use `

` headings in markdown content for Tauri documentation generation purposes.", + "type": [ + "string", + "null" + ] + }, + "permissions": { + "description": "All permissions this set contains.", + "type": "array", + "items": { + "type": "string" + } + } + } + }, + "PermissionSet": { + "description": "A set of direct permissions grouped together under a new name.", + "type": "object", + "required": [ + "description", + "identifier", + "permissions" + ], + "properties": { + "identifier": { + "description": "A unique identifier for the permission.", + "type": "string" + }, + "description": { + "description": "Human-readable description of what the permission does.", + "type": "string" + }, + "permissions": { + "description": "All permissions this set contains.", + "type": "array", + "items": { + "$ref": "#/definitions/PermissionKind" + } + } + } + }, + "Permission": { + "description": "Descriptions of explicit privileges of commands.\n\nIt can enable commands to be accessible in the frontend of the application.\n\nIf the scope is defined it can be used to fine grain control the access of individual or multiple commands.", + "type": "object", + "required": [ + "identifier" + ], + "properties": { + "version": { + "description": "The version of the permission.", + "type": [ + "integer", + "null" + ], + "format": "uint64", + "minimum": 1.0 + }, + "identifier": { + "description": "A unique identifier for the permission.", + "type": "string" + }, + "description": { + "description": "Human-readable description of what the permission does. Tauri internal convention is to use `

` headings in markdown content for Tauri documentation generation purposes.", + "type": [ + "string", + "null" + ] + }, + "commands": { + "description": "Allowed or denied commands when using this permission.", + "default": { + "allow": [], + "deny": [] + }, + "allOf": [ + { + "$ref": "#/definitions/Commands" + } + ] + }, + "scope": { + "description": "Allowed or denied scoped when using this permission.", + "allOf": [ + { + "$ref": "#/definitions/Scopes" + } + ] + }, + "platforms": { + "description": "Target platforms this permission applies. By default all platforms are affected by this permission.", + "type": [ + "array", + "null" + ], + "items": { + "$ref": "#/definitions/Target" + } + } + } + }, + "Commands": { + "description": "Allowed and denied commands inside a permission.\n\nIf two commands clash inside of `allow` and `deny`, it should be denied by default.", + "type": "object", + "properties": { + "allow": { + "description": "Allowed command.", + "default": [], + "type": "array", + "items": { + "type": "string" + } + }, + "deny": { + "description": "Denied command, which takes priority.", + "default": [], + "type": "array", + "items": { + "type": "string" + } + } + } + }, + "Scopes": { + "description": "An argument for fine grained behavior control of Tauri commands.\n\nIt can be of any serde serializable type and is used to allow or prevent certain actions inside a Tauri command. The configured scope is passed to the command and will be enforced by the command implementation.\n\n## Example\n\n```json { \"allow\": [{ \"path\": \"$HOME/**\" }], \"deny\": [{ \"path\": \"$HOME/secret.txt\" }] } ```", + "type": "object", + "properties": { + "allow": { + "description": "Data that defines what is allowed by the scope.", + "type": [ + "array", + "null" + ], + "items": { + "$ref": "#/definitions/Value" + } + }, + "deny": { + "description": "Data that defines what is denied by the scope. This should be prioritized by validation logic.", + "type": [ + "array", + "null" + ], + "items": { + "$ref": "#/definitions/Value" + } + } + } + }, + "Value": { + "description": "All supported ACL values.", + "anyOf": [ + { + "description": "Represents a null JSON value.", + "type": "null" + }, + { + "description": "Represents a [`bool`].", + "type": "boolean" + }, + { + "description": "Represents a valid ACL [`Number`].", + "allOf": [ + { + "$ref": "#/definitions/Number" + } + ] + }, + { + "description": "Represents a [`String`].", + "type": "string" + }, + { + "description": "Represents a list of other [`Value`]s.", + "type": "array", + "items": { + "$ref": "#/definitions/Value" + } + }, + { + "description": "Represents a map of [`String`] keys to [`Value`]s.", + "type": "object", + "additionalProperties": { + "$ref": "#/definitions/Value" + } + } + ] + }, + "Number": { + "description": "A valid ACL number.", + "anyOf": [ + { + "description": "Represents an [`i64`].", + "type": "integer", + "format": "int64" + }, + { + "description": "Represents a [`f64`].", + "type": "number", + "format": "double" + } + ] + }, + "Target": { + "description": "Platform target.", + "oneOf": [ + { + "description": "MacOS.", + "type": "string", + "enum": [ + "macOS" + ] + }, + { + "description": "Windows.", + "type": "string", + "enum": [ + "windows" + ] + }, + { + "description": "Linux.", + "type": "string", + "enum": [ + "linux" + ] + }, + { + "description": "Android.", + "type": "string", + "enum": [ + "android" + ] + }, + { + "description": "iOS.", + "type": "string", + "enum": [ + "iOS" + ] + } + ] + }, + "PermissionKind": { + "type": "string", + "oneOf": [ + { + "description": "Enables the get_api_key command without any pre-configured scope.", + "type": "string", + "const": "allow-get-api-key", + "markdownDescription": "Enables the get_api_key command without any pre-configured scope." + }, + { + "description": "Denies the get_api_key command without any pre-configured scope.", + "type": "string", + "const": "deny-get-api-key", + "markdownDescription": "Denies the get_api_key command without any pre-configured scope." + }, + { + "description": "Enables the get_base_folder command without any pre-configured scope.", + "type": "string", + "const": "allow-get-base-folder", + "markdownDescription": "Enables the get_base_folder command without any pre-configured scope." + }, + { + "description": "Denies the get_base_folder command without any pre-configured scope.", + "type": "string", + "const": "deny-get-base-folder", + "markdownDescription": "Denies the get_base_folder command without any pre-configured scope." + }, + { + "description": "Enables the get_base_url command without any pre-configured scope.", + "type": "string", + "const": "allow-get-base-url", + "markdownDescription": "Enables the get_base_url command without any pre-configured scope." + }, + { + "description": "Denies the get_base_url command without any pre-configured scope.", + "type": "string", + "const": "deny-get-base-url", + "markdownDescription": "Denies the get_base_url command without any pre-configured scope." + }, + { + "description": "Enables the get_deep_link_url command without any pre-configured scope.", + "type": "string", + "const": "allow-get-deep-link-url", + "markdownDescription": "Enables the get_deep_link_url command without any pre-configured scope." + }, + { + "description": "Denies the get_deep_link_url command without any pre-configured scope.", + "type": "string", + "const": "deny-get-deep-link-url", + "markdownDescription": "Denies the get_deep_link_url command without any pre-configured scope." + }, + { + "description": "Enables the get_enabled command without any pre-configured scope.", + "type": "string", + "const": "allow-get-enabled", + "markdownDescription": "Enables the get_enabled command without any pre-configured scope." + }, + { + "description": "Denies the get_enabled command without any pre-configured scope.", + "type": "string", + "const": "deny-get-enabled", + "markdownDescription": "Denies the get_enabled command without any pre-configured scope." + }, + { + "description": "Enables the get_vault_name command without any pre-configured scope.", + "type": "string", + "const": "allow-get-vault-name", + "markdownDescription": "Enables the get_vault_name command without any pre-configured scope." + }, + { + "description": "Denies the get_vault_name command without any pre-configured scope.", + "type": "string", + "const": "deny-get-vault-name", + "markdownDescription": "Denies the get_vault_name command without any pre-configured scope." + }, + { + "description": "Enables the set_api_key command without any pre-configured scope.", + "type": "string", + "const": "allow-set-api-key", + "markdownDescription": "Enables the set_api_key command without any pre-configured scope." + }, + { + "description": "Denies the set_api_key command without any pre-configured scope.", + "type": "string", + "const": "deny-set-api-key", + "markdownDescription": "Denies the set_api_key command without any pre-configured scope." + }, + { + "description": "Enables the set_base_folder command without any pre-configured scope.", + "type": "string", + "const": "allow-set-base-folder", + "markdownDescription": "Enables the set_base_folder command without any pre-configured scope." + }, + { + "description": "Denies the set_base_folder command without any pre-configured scope.", + "type": "string", + "const": "deny-set-base-folder", + "markdownDescription": "Denies the set_base_folder command without any pre-configured scope." + }, + { + "description": "Enables the set_base_url command without any pre-configured scope.", + "type": "string", + "const": "allow-set-base-url", + "markdownDescription": "Enables the set_base_url command without any pre-configured scope." + }, + { + "description": "Denies the set_base_url command without any pre-configured scope.", + "type": "string", + "const": "deny-set-base-url", + "markdownDescription": "Denies the set_base_url command without any pre-configured scope." + }, + { + "description": "Enables the set_enabled command without any pre-configured scope.", + "type": "string", + "const": "allow-set-enabled", + "markdownDescription": "Enables the set_enabled command without any pre-configured scope." + }, + { + "description": "Denies the set_enabled command without any pre-configured scope.", + "type": "string", + "const": "deny-set-enabled", + "markdownDescription": "Denies the set_enabled command without any pre-configured scope." + }, + { + "description": "Enables the set_vault_name command without any pre-configured scope.", + "type": "string", + "const": "allow-set-vault-name", + "markdownDescription": "Enables the set_vault_name command without any pre-configured scope." + }, + { + "description": "Denies the set_vault_name command without any pre-configured scope.", + "type": "string", + "const": "deny-set-vault-name", + "markdownDescription": "Denies the set_vault_name command without any pre-configured scope." + }, + { + "description": "Default permissions for the plugin\n#### This default permission set includes:\n\n- `allow-get-api-key`\n- `allow-get-base-url`\n- `allow-get-vault-name`\n- `allow-set-api-key`\n- `allow-set-base-url`\n- `allow-set-vault-name`\n- `allow-get-enabled`\n- `allow-set-enabled`\n- `allow-get-deep-link-url`\n- `allow-get-base-folder`\n- `allow-set-base-folder`", + "type": "string", + "const": "default", + "markdownDescription": "Default permissions for the plugin\n#### This default permission set includes:\n\n- `allow-get-api-key`\n- `allow-get-base-url`\n- `allow-get-vault-name`\n- `allow-set-api-key`\n- `allow-set-base-url`\n- `allow-set-vault-name`\n- `allow-get-enabled`\n- `allow-set-enabled`\n- `allow-get-deep-link-url`\n- `allow-get-base-folder`\n- `allow-set-base-folder`" + } + ] + } + } +} \ No newline at end of file diff --git a/plugins/obsidian/src/commands.rs b/plugins/obsidian/src/commands.rs new file mode 100644 index 000000000..cb450b3c3 --- /dev/null +++ b/plugins/obsidian/src/commands.rs @@ -0,0 +1,95 @@ +use crate::ObsidianPluginExt; + +#[tauri::command] +#[specta::specta] +pub(crate) async fn get_api_key( + app: tauri::AppHandle, +) -> Result, String> { + app.get_api_key().map_err(|e| e.to_string()) +} + +#[tauri::command] +#[specta::specta] +pub(crate) async fn set_api_key( + app: tauri::AppHandle, + api_key: String, +) -> Result<(), String> { + app.set_api_key(api_key).map_err(|e| e.to_string()) +} + +#[tauri::command] +#[specta::specta] +pub(crate) async fn get_base_url( + app: tauri::AppHandle, +) -> Result, String> { + app.get_base_url().map_err(|e| e.to_string()) +} + +#[tauri::command] +#[specta::specta] +pub(crate) async fn set_base_url( + app: tauri::AppHandle, + base_url: String, +) -> Result<(), String> { + app.set_base_url(base_url).map_err(|e| e.to_string()) +} + +#[tauri::command] +#[specta::specta] +pub(crate) async fn get_vault_name( + app: tauri::AppHandle, +) -> Result, String> { + app.get_vault_name().map_err(|e| e.to_string()) +} + +#[tauri::command] +#[specta::specta] +pub(crate) async fn set_vault_name( + app: tauri::AppHandle, + vault_name: String, +) -> Result<(), String> { + app.set_vault_name(vault_name).map_err(|e| e.to_string()) +} + +#[tauri::command] +#[specta::specta] +pub(crate) async fn get_base_folder( + app: tauri::AppHandle, +) -> Result, String> { + app.get_base_folder().map_err(|e| e.to_string()) +} + +#[tauri::command] +#[specta::specta] +pub(crate) async fn set_base_folder( + app: tauri::AppHandle, + base_folder: String, +) -> Result<(), String> { + app.set_base_folder(base_folder).map_err(|e| e.to_string()) +} + +#[tauri::command] +#[specta::specta] +pub(crate) async fn get_enabled( + app: tauri::AppHandle, +) -> Result { + app.get_enabled().map_err(|e| e.to_string()) +} + +#[tauri::command] +#[specta::specta] +pub(crate) async fn set_enabled( + app: tauri::AppHandle, + enabled: bool, +) -> Result<(), String> { + app.set_enabled(enabled).map_err(|e| e.to_string()) +} + +#[tauri::command] +#[specta::specta] +pub(crate) async fn get_deep_link_url( + app: tauri::AppHandle, + note_name: String, +) -> Result { + app.get_deep_link_url(note_name).map_err(|e| e.to_string()) +} diff --git a/plugins/obsidian/src/error.rs b/plugins/obsidian/src/error.rs new file mode 100644 index 000000000..93a819419 --- /dev/null +++ b/plugins/obsidian/src/error.rs @@ -0,0 +1,20 @@ +use serde::{ser::Serializer, Serialize}; + +pub type Result = std::result::Result; + +#[derive(Debug, thiserror::Error)] +pub enum Error { + #[error(transparent)] + StoreError(#[from] tauri_plugin_store2::Error), + #[error("Vault name is not configured")] + VaultNameNotConfigured, +} + +impl Serialize for Error { + fn serialize(&self, serializer: S) -> std::result::Result + where + S: Serializer, + { + serializer.serialize_str(self.to_string().as_ref()) + } +} diff --git a/plugins/obsidian/src/ext.rs b/plugins/obsidian/src/ext.rs new file mode 100644 index 000000000..8c3604ea4 --- /dev/null +++ b/plugins/obsidian/src/ext.rs @@ -0,0 +1,113 @@ +use tauri_plugin_store2::StorePluginExt; + +pub trait ObsidianPluginExt { + fn obsidian_store(&self) -> tauri_plugin_store2::ScopedStore; + fn is_configured(&self) -> Result; + + fn get_api_key(&self) -> Result, crate::Error>; + fn set_api_key(&self, api_key: String) -> Result<(), crate::Error>; + + fn get_base_url(&self) -> Result, crate::Error>; + fn set_base_url(&self, base_url: String) -> Result<(), crate::Error>; + + fn get_vault_name(&self) -> Result, crate::Error>; + fn set_vault_name(&self, vault_name: String) -> Result<(), crate::Error>; + + fn get_base_folder(&self) -> Result, crate::Error>; + fn set_base_folder(&self, base_folder: String) -> Result<(), crate::Error>; + + fn get_enabled(&self) -> Result; + fn set_enabled(&self, enabled: bool) -> Result<(), crate::Error>; + + fn get_deep_link_url(&self, note_name: String) -> Result; +} + +impl> ObsidianPluginExt for T { + fn obsidian_store(&self) -> tauri_plugin_store2::ScopedStore { + self.scoped_store(crate::PLUGIN_NAME).unwrap() + } + + fn is_configured(&self) -> Result { + let api_key = self.get_api_key()?; + let base_url = self.get_base_url()?; + + Ok(api_key.is_some() && base_url.is_some()) + } + + fn get_api_key(&self) -> Result, crate::Error> { + let store = self.obsidian_store(); + let v = store.get::(crate::StoreKey::ApiKey)?; + Ok(v) + } + + fn set_api_key(&self, api_key: String) -> Result<(), crate::Error> { + let store = self.obsidian_store(); + store.set(crate::StoreKey::ApiKey, Some(api_key))?; + store.save()?; + Ok(()) + } + + fn get_base_url(&self) -> Result, crate::Error> { + let store = self.obsidian_store(); + let v = store.get::(crate::StoreKey::BaseUrl)?; + Ok(v) + } + + fn set_base_url(&self, base_url: String) -> Result<(), crate::Error> { + let store = self.obsidian_store(); + store.set(crate::StoreKey::BaseUrl, base_url)?; + store.save()?; + Ok(()) + } + + fn get_vault_name(&self) -> Result, crate::Error> { + let store = self.obsidian_store(); + let v = store.get::(crate::StoreKey::VaultName)?; + Ok(v) + } + + fn set_vault_name(&self, vault_name: String) -> Result<(), crate::Error> { + let store = self.obsidian_store(); + store.set(crate::StoreKey::VaultName, vault_name)?; + store.save()?; + Ok(()) + } + + fn get_base_folder(&self) -> Result, crate::Error> { + let store = self.obsidian_store(); + let v = store.get::(crate::StoreKey::BaseFolder)?; + Ok(v) + } + + fn set_base_folder(&self, base_folder: String) -> Result<(), crate::Error> { + let store = self.obsidian_store(); + store.set(crate::StoreKey::BaseFolder, base_folder)?; + store.save()?; + Ok(()) + } + + fn get_enabled(&self) -> Result { + let store = self.obsidian_store(); + let v = store.get::(crate::StoreKey::Enabled)?; + Ok(v.unwrap_or(false)) + } + + fn set_enabled(&self, enabled: bool) -> Result<(), crate::Error> { + let store = self.obsidian_store(); + store.set(crate::StoreKey::Enabled, enabled)?; + store.save()?; + Ok(()) + } + + fn get_deep_link_url(&self, note_name: String) -> Result { + let store = self.obsidian_store(); + let vault_name = store + .get::(crate::StoreKey::VaultName)? + .ok_or(crate::Error::VaultNameNotConfigured)?; + + Ok(format!( + "obsidian://open?vault={}&file={}", + vault_name, note_name + )) + } +} diff --git a/plugins/obsidian/src/lib.rs b/plugins/obsidian/src/lib.rs new file mode 100644 index 000000000..8b7b8f9fc --- /dev/null +++ b/plugins/obsidian/src/lib.rs @@ -0,0 +1,82 @@ +use std::sync::Mutex; +use tauri::Manager; + +mod commands; +mod error; +mod ext; +mod store; + +pub use error::*; +pub use ext::*; +use store::*; + +const PLUGIN_NAME: &str = "obsidian"; + +pub type SharedState = Mutex; + +#[derive(Default)] +pub struct State {} + +fn make_specta_builder() -> tauri_specta::Builder { + tauri_specta::Builder::::new() + .plugin_name(PLUGIN_NAME) + .commands(tauri_specta::collect_commands![ + commands::set_api_key::, + commands::set_base_url::, + commands::get_api_key::, + commands::get_base_url::, + commands::get_vault_name::, + commands::set_vault_name::, + commands::get_enabled::, + commands::set_enabled::, + commands::get_deep_link_url::, + commands::get_base_folder::, + commands::set_base_folder::, + ]) + .error_handling(tauri_specta::ErrorHandlingMode::Throw) +} + +pub fn init() -> tauri::plugin::TauriPlugin { + let specta_builder = make_specta_builder(); + + tauri::plugin::Builder::new(PLUGIN_NAME) + .invoke_handler(specta_builder.invoke_handler()) + .setup(|app, _api| { + let state = SharedState::default(); + app.manage(state); + + Ok(()) + }) + .build() +} + +#[cfg(test)] +mod test { + use super::*; + + #[test] + fn export_types() { + make_specta_builder::() + .export( + specta_typescript::Typescript::default() + .header("// @ts-nocheck\n\n") + .formatter(specta_typescript::formatter::prettier) + .bigint(specta_typescript::BigIntExportBehavior::Number), + "./js/bindings.gen.ts", + ) + .unwrap() + } + + fn create_app(builder: tauri::Builder) -> tauri::App { + builder + .plugin(tauri_plugin_store::Builder::default().build()) + .plugin(init()) + .build(tauri::test::mock_context(tauri::test::noop_assets())) + .unwrap() + } + + #[tokio::test] + async fn test_obsidian() { + let _app = create_app(tauri::test::mock_builder()); + } +} diff --git a/plugins/obsidian/src/store.rs b/plugins/obsidian/src/store.rs new file mode 100644 index 000000000..89146bec0 --- /dev/null +++ b/plugins/obsidian/src/store.rs @@ -0,0 +1,12 @@ +use tauri_plugin_store2::ScopedStoreKey; + +#[derive(serde::Deserialize, specta::Type, PartialEq, Eq, Hash, strum::Display)] +pub enum StoreKey { + Enabled, + VaultName, + BaseFolder, + BaseUrl, + ApiKey, +} + +impl ScopedStoreKey for StoreKey {} diff --git a/plugins/obsidian/tsconfig.json b/plugins/obsidian/tsconfig.json new file mode 100644 index 000000000..13b985325 --- /dev/null +++ b/plugins/obsidian/tsconfig.json @@ -0,0 +1,5 @@ +{ + "extends": "../tsconfig.base.json", + "include": ["./js/*.ts"], + "exclude": ["node_modules"] +} diff --git a/plugins/store2/permissions/autogenerated/commands/ping.toml b/plugins/store2/permissions/autogenerated/commands/ping.toml deleted file mode 100644 index 1d1358807..000000000 --- a/plugins/store2/permissions/autogenerated/commands/ping.toml +++ /dev/null @@ -1,13 +0,0 @@ -# Automatically generated - DO NOT EDIT! - -"$schema" = "../../schemas/schema.json" - -[[permission]] -identifier = "allow-ping" -description = "Enables the ping command without any pre-configured scope." -commands.allow = ["ping"] - -[[permission]] -identifier = "deny-ping" -description = "Denies the ping command without any pre-configured scope." -commands.deny = ["ping"] diff --git a/plugins/store2/permissions/autogenerated/reference.md b/plugins/store2/permissions/autogenerated/reference.md index fc1c01fff..a2093aae3 100644 --- a/plugins/store2/permissions/autogenerated/reference.md +++ b/plugins/store2/permissions/autogenerated/reference.md @@ -4,7 +4,12 @@ Default permissions for the plugin #### This default permission set includes the following: -- `allow-ping` +- `allow-get-bool` +- `allow-get-number` +- `allow-get-str` +- `allow-set-bool` +- `allow-set-number` +- `allow-set-str` ## Permission Table @@ -96,32 +101,6 @@ Denies the get_str command without any pre-configured scope. -`store2:allow-ping` - - - - -Enables the ping command without any pre-configured scope. - - - - - - - -`store2:deny-ping` - - - - -Denies the ping command without any pre-configured scope. - - - - - - - `store2:allow-set-bool` diff --git a/plugins/store2/permissions/default.toml b/plugins/store2/permissions/default.toml index cc5a76f22..5b4178388 100644 --- a/plugins/store2/permissions/default.toml +++ b/plugins/store2/permissions/default.toml @@ -1,3 +1,3 @@ [default] description = "Default permissions for the plugin" -permissions = ["allow-ping"] +permissions = ["allow-get-bool", "allow-get-number", "allow-get-str", "allow-set-bool", "allow-set-number", "allow-set-str"] diff --git a/plugins/store2/permissions/schemas/schema.json b/plugins/store2/permissions/schemas/schema.json index 8ebfaf46a..ea03d7af9 100644 --- a/plugins/store2/permissions/schemas/schema.json +++ b/plugins/store2/permissions/schemas/schema.json @@ -330,18 +330,6 @@ "const": "deny-get-str", "markdownDescription": "Denies the get_str command without any pre-configured scope." }, - { - "description": "Enables the ping command without any pre-configured scope.", - "type": "string", - "const": "allow-ping", - "markdownDescription": "Enables the ping command without any pre-configured scope." - }, - { - "description": "Denies the ping command without any pre-configured scope.", - "type": "string", - "const": "deny-ping", - "markdownDescription": "Denies the ping command without any pre-configured scope." - }, { "description": "Enables the set_bool command without any pre-configured scope.", "type": "string", @@ -379,10 +367,10 @@ "markdownDescription": "Denies the set_str command without any pre-configured scope." }, { - "description": "Default permissions for the plugin\n#### This default permission set includes:\n\n- `allow-ping`", + "description": "Default permissions for the plugin\n#### This default permission set includes:\n\n- `allow-get-bool`\n- `allow-get-number`\n- `allow-get-str`\n- `allow-set-bool`\n- `allow-set-number`\n- `allow-set-str`", "type": "string", "const": "default", - "markdownDescription": "Default permissions for the plugin\n#### This default permission set includes:\n\n- `allow-ping`" + "markdownDescription": "Default permissions for the plugin\n#### This default permission set includes:\n\n- `allow-get-bool`\n- `allow-get-number`\n- `allow-get-str`\n- `allow-set-bool`\n- `allow-set-number`\n- `allow-set-str`" } ] } diff --git a/plugins/task/build.rs b/plugins/task/build.rs index 029861396..a220cd4b2 100644 --- a/plugins/task/build.rs +++ b/plugins/task/build.rs @@ -1,4 +1,4 @@ -const COMMANDS: &[&str] = &["ping"]; +const COMMANDS: &[&str] = &[]; fn main() { tauri_plugin::Builder::new(COMMANDS).build(); diff --git a/plugins/task/permissions/autogenerated/commands/ping.toml b/plugins/task/permissions/autogenerated/commands/ping.toml deleted file mode 100644 index 1d1358807..000000000 --- a/plugins/task/permissions/autogenerated/commands/ping.toml +++ /dev/null @@ -1,13 +0,0 @@ -# Automatically generated - DO NOT EDIT! - -"$schema" = "../../schemas/schema.json" - -[[permission]] -identifier = "allow-ping" -description = "Enables the ping command without any pre-configured scope." -commands.allow = ["ping"] - -[[permission]] -identifier = "deny-ping" -description = "Denies the ping command without any pre-configured scope." -commands.deny = ["ping"] diff --git a/plugins/task/permissions/autogenerated/reference.md b/plugins/task/permissions/autogenerated/reference.md index eabff584f..50c0f4023 100644 --- a/plugins/task/permissions/autogenerated/reference.md +++ b/plugins/task/permissions/autogenerated/reference.md @@ -2,10 +2,6 @@ Default permissions for the plugin -#### This default permission set includes the following: - -- `allow-ping` - ## Permission Table @@ -14,30 +10,4 @@ Default permissions for the plugin - - - - - - - - - -
Description
- -`task:allow-ping` - - - -Enables the ping command without any pre-configured scope. - -
- -`task:deny-ping` - - - -Denies the ping command without any pre-configured scope. - -
diff --git a/plugins/task/permissions/default.toml b/plugins/task/permissions/default.toml index cc5a76f22..8ea0a5f96 100644 --- a/plugins/task/permissions/default.toml +++ b/plugins/task/permissions/default.toml @@ -1,3 +1,3 @@ [default] description = "Default permissions for the plugin" -permissions = ["allow-ping"] +permissions = [] diff --git a/plugins/task/permissions/schemas/schema.json b/plugins/task/permissions/schemas/schema.json index ac68e129e..c801ea4cb 100644 --- a/plugins/task/permissions/schemas/schema.json +++ b/plugins/task/permissions/schemas/schema.json @@ -295,22 +295,10 @@ "type": "string", "oneOf": [ { - "description": "Enables the ping command without any pre-configured scope.", - "type": "string", - "const": "allow-ping", - "markdownDescription": "Enables the ping command without any pre-configured scope." - }, - { - "description": "Denies the ping command without any pre-configured scope.", - "type": "string", - "const": "deny-ping", - "markdownDescription": "Denies the ping command without any pre-configured scope." - }, - { - "description": "Default permissions for the plugin\n#### This default permission set includes:\n\n- `allow-ping`", + "description": "Default permissions for the plugin", "type": "string", "const": "default", - "markdownDescription": "Default permissions for the plugin\n#### This default permission set includes:\n\n- `allow-ping`" + "markdownDescription": "Default permissions for the plugin" } ] } diff --git a/pnpm-lock.yaml b/pnpm-lock.yaml index aad6536c8..8a0caccad 100644 --- a/pnpm-lock.yaml +++ b/pnpm-lock.yaml @@ -277,6 +277,9 @@ importers: '@hypr/plugin-notification': specifier: workspace:^ version: link:../../plugins/notification + '@hypr/plugin-obsidian': + specifier: workspace:^ + version: link:../../plugins/obsidian '@hypr/plugin-sfx': specifier: workspace:^ version: link:../../plugins/sfx @@ -364,6 +367,9 @@ importers: '@tauri-apps/plugin-fs': specifier: ^2.4.0 version: 2.4.0 + '@tauri-apps/plugin-http': + specifier: ^2.4.4 + version: 2.4.4 '@tauri-apps/plugin-opener': specifier: ^2.4.0 version: 2.4.0 @@ -589,12 +595,12 @@ importers: specifier: ^0.8.4 version: 0.8.4 '@tanstack/react-query': - specifier: ^5.79.0 + specifier: ^5.83.0 version: 5.83.0(react@19.1.0) devDependencies: '@hey-api/openapi-ts': - specifier: ^0.64.15 - version: 0.64.15(magicast@0.3.5)(typescript@5.8.3) + specifier: ^0.78.3 + version: 0.78.3(magicast@0.3.5)(typescript@5.8.3) packages/tiptap: dependencies: @@ -989,6 +995,15 @@ importers: specifier: ^2.6.0 version: 2.6.0 + plugins/obsidian: + dependencies: + '@hypr/obsidian': + specifier: workspace:^ + version: link:../../packages/obsidian + '@tauri-apps/api': + specifier: ^2.6.0 + version: 2.6.0 + plugins/sfx: dependencies: '@tauri-apps/api': @@ -2021,6 +2036,10 @@ packages: resolution: {integrity: sha512-jgyNFPUReGpdB0ihWv6m+Q3dcawtXx4t6cvi0NS4xxblulcCfEjThP5xVwShFiTRScckIQ/GsuZv20arRTIDkg==} engines: {node: '>= 16'} + '@hey-api/json-schema-ref-parser@1.0.6': + resolution: {integrity: sha512-yktiFZoWPtEW8QKS65eqKwA5MTKp88CyiL8q72WynrBs/73SAaxlSWlA2zW/DZlywZ5hX1OYzrCC0wFdvO9c2w==} + engines: {node: '>= 16'} + '@hey-api/openapi-ts@0.64.15': resolution: {integrity: sha512-bXpi9z3YEPVt9bVqlFA3hHmgDzfM8ID5kjnXR7t6PFxlmqo8CH8Y8aCNP7rMk1q7MXk42y2CXC2ehbU9cthCyw==} engines: {node: ^18.18.0 || ^20.9.0 || >=22.10.0} @@ -2028,6 +2047,13 @@ packages: peerDependencies: typescript: ^5.5.3 + '@hey-api/openapi-ts@0.78.3': + resolution: {integrity: sha512-uTP/EGA/mM4MsFN0xGcQ4fkFxeaAUGT2T1VKnNBv6WUwRY7J59Wg8kVuRXn3dLeI/IWUDwNNdHU0SfnEbXEmYw==} + engines: {node: ^18.18.0 || ^20.9.0 || >=22.10.0} + hasBin: true + peerDependencies: + typescript: ^5.5.3 + '@hookform/resolvers@3.10.0': resolution: {integrity: sha512-79Dv+3mDF7i+2ajj7SkypSKHhl1cbln1OGavqrsF7p6mbUv11xpqpacPsGDCTRvCSjEEIez2ef1NveSVL3b0Ag==} peerDependencies: @@ -4952,6 +4978,10 @@ packages: resolution: {integrity: sha512-zhaCDicdLuWN5UbN5IMnFqNMhNfo919sH85y2/ea+5Yg9TsTkeZxpL+JLbp6cgYFS4sRLp3YV4S6yDuqVWHYOw==} engines: {node: '>=6'} + bundle-name@4.1.0: + resolution: {integrity: sha512-tjwM5exMg6BGRI+kNmTntNsvdZS1X8BFYS6tnJ2hdH0kVxM6/eVZ2xy+FqStSWvYmtfFMDLIxurorHwDKfDz5Q==} + engines: {node: '>=18'} + c12@2.0.1: resolution: {integrity: sha512-Z4JgsKXHG37C6PYUtIxCfLJZvo6FyhHJoClwwb9ftUkLpPSkuYqn6Tr+vnaN8hymm0kIbcg6Ey3kv/Q71k5w/A==} peerDependencies: @@ -5162,6 +5192,10 @@ packages: color-string@1.9.1: resolution: {integrity: sha512-shrVawQFojnZv6xM40anx4CkoDP+fZsw/ZerEMsW/pyzsRbElpsL/DBVW7q3ExxwusdNXI3lXpuhEZkzs8p5Eg==} + color-support@1.1.3: + resolution: {integrity: sha512-qiBjkpbMLO/HL68y+lh4q0/O1MZFj2RX6X/KmMa3+gJD3z+WwI1ZzDHysvqHGS3mP6mznPckpXmw1nI9cJjyRg==} + hasBin: true + color@3.2.1: resolution: {integrity: sha512-aBl7dZI9ENN6fUGC7mWpMTPNHmWUSNan9tuWN6ahh5ZLNk9baLJOnSMlrQkHcrfFgz2/RigjUVAjdx36VcemKA==} @@ -5455,6 +5489,14 @@ packages: resolution: {integrity: sha512-3sUqbMEc77XqpdNO7FRyRog+eW3ph+GYCbj+rK+uYyRMuwsVy0rMiVtPn+QJlKFvWP/1PYpapqYn0Me2knFn+A==} engines: {node: '>=0.10.0'} + default-browser-id@5.0.0: + resolution: {integrity: sha512-A6p/pu/6fyBcA1TRz/GqWYPViplrftcW2gZC9q79ngNCKAeR/X3gcEdXQHl4KNXV+3wgIJ1CPkJQ3IHM6lcsyA==} + engines: {node: '>=18'} + + default-browser@5.2.1: + resolution: {integrity: sha512-WY/3TUME0x3KPYdRRxEJJvXRHV4PyPoUsxtZa78lwItwRQRHhd2U9xOscaT/YTf8uCXIAjeJOFBVEh/7FtD8Xg==} + engines: {node: '>=18'} + defaults@1.0.4: resolution: {integrity: sha512-eFuaLoy/Rxalv2kr+lqMlUnrDWV+3j4pljOIJgLIhI058IQfWJ7vXhyEIHu+HtC738klGALYxOKDO0bQP3tg8A==} @@ -5470,6 +5512,10 @@ packages: resolution: {integrity: sha512-Ds09qNh8yw3khSjiJjiUInaGX9xlqZDY7JVryGxdxV7NPeuqQfplOpQ66yJFZut3jLa5zOwkXw1g9EI2uKh4Og==} engines: {node: '>=8'} + define-lazy-prop@3.0.0: + resolution: {integrity: sha512-N+MeXYoqr3pOgn8xfyRPREN7gHakLYjhsHhWGT3fWAiL4IkAt0iDw14QiiEm2bE30c5XX5q0FtAA3CK5f9/BUg==} + engines: {node: '>=12'} + define-properties@1.2.1: resolution: {integrity: sha512-8QmQKqEASLd5nx0U1B1okLElbUuuttJ/AnYmRXbbbGDWh6uS208EjD4Xqq/I9wK7u0v6O08XhTWnt5XtEbR6Dg==} engines: {node: '>= 0.4'} @@ -7732,6 +7778,10 @@ packages: resolution: {integrity: sha512-1FlR+gjXK7X+AsAHso35MnyN5KqGwJRi/31ft6x0M194ht7S+rWAvd7PHss9xSKMzE0asv1pyIHaJYq+BbacAQ==} engines: {node: '>=12'} + open@10.1.2: + resolution: {integrity: sha512-cxN6aIDPz6rm8hbebcP7vrQNhvRcveZoJU72Y7vskh4oIm+BZwBECnx5nTmrlres1Qapvx27Qo1Auukpf8PKXw==} + engines: {node: '>=18'} + open@8.4.2: resolution: {integrity: sha512-7x81NCL719oNbsq/3mh+hVrAWmFuEYUqrq/Iw3kUzH8ReypT9QQ0BLoJS7/G9k6N81XjW4qHWtjWwe/9eLy1EQ==} engines: {node: '>=12'} @@ -8618,6 +8668,10 @@ packages: rrweb-snapshot@2.0.0-alpha.18: resolution: {integrity: sha512-hBHZL/NfgQX6wO1D9mpwqFu1NJPpim+moIcKhFEjVTZVRUfCln+LOugRc4teVTCISYHN8Cw5e2iNTWCSm+SkoA==} + run-applescript@7.0.0: + resolution: {integrity: sha512-9by4Ij99JUr/MCFBUkDKLWK3G9HVXmabKz9U5MlIAIuvuzkiOicRYs8XJLxX+xahD+mLiiCYDqF9dKAgtzKP1A==} + engines: {node: '>=18'} + run-async@2.4.1: resolution: {integrity: sha512-tvVnVv01b8c1RrA6Ep7JkStj85Guv/YrMcwqYQnwjsAS2cTmmPGBBjAjpCW7RrSodNSoE2/qg9O4bceNvUuDgQ==} engines: {node: '>=0.12.0'} @@ -10780,6 +10834,13 @@ snapshots: '@types/json-schema': 7.0.15 js-yaml: 4.1.0 + '@hey-api/json-schema-ref-parser@1.0.6': + dependencies: + '@jsdevtools/ono': 7.1.3 + '@types/json-schema': 7.0.15 + js-yaml: 4.1.0 + lodash: 4.17.21 + '@hey-api/openapi-ts@0.64.15(magicast@0.3.5)(typescript@5.8.3)': dependencies: '@hey-api/json-schema-ref-parser': 1.0.3 @@ -10790,6 +10851,19 @@ snapshots: transitivePeerDependencies: - magicast + '@hey-api/openapi-ts@0.78.3(magicast@0.3.5)(typescript@5.8.3)': + dependencies: + '@hey-api/json-schema-ref-parser': 1.0.6 + ansi-colors: 4.1.3 + c12: 2.0.1(magicast@0.3.5) + color-support: 1.1.3 + commander: 13.0.0 + handlebars: 4.7.8 + open: 10.1.2 + typescript: 5.8.3 + transitivePeerDependencies: + - magicast + '@hookform/resolvers@3.10.0(react-hook-form@7.57.0(react@18.3.1))': dependencies: react-hook-form: 7.57.0(react@18.3.1) @@ -14258,6 +14332,10 @@ snapshots: builtin-modules@3.3.0: {} + bundle-name@4.1.0: + dependencies: + run-applescript: 7.0.0 + c12@2.0.1(magicast@0.3.5): dependencies: chokidar: 4.0.3 @@ -14521,6 +14599,8 @@ snapshots: color-name: 1.1.4 simple-swizzle: 0.2.2 + color-support@1.1.3: {} + color@3.2.1: dependencies: color-convert: 1.9.3 @@ -14764,6 +14844,13 @@ snapshots: deepmerge@4.3.1: {} + default-browser-id@5.0.0: {} + + default-browser@5.2.1: + dependencies: + bundle-name: 4.1.0 + default-browser-id: 5.0.0 + defaults@1.0.4: dependencies: clone: 1.0.4 @@ -14778,6 +14865,8 @@ snapshots: define-lazy-prop@2.0.0: {} + define-lazy-prop@3.0.0: {} + define-properties@1.2.1: dependencies: define-data-property: 1.1.4 @@ -17339,6 +17428,13 @@ snapshots: dependencies: mimic-fn: 4.0.0 + open@10.1.2: + dependencies: + default-browser: 5.2.1 + define-lazy-prop: 3.0.0 + is-inside-container: 1.0.0 + is-wsl: 3.1.0 + open@8.4.2: dependencies: define-lazy-prop: 2.0.0 @@ -18395,6 +18491,8 @@ snapshots: postcss: 8.5.6 optional: true + run-applescript@7.0.0: {} + run-async@2.4.1: {} run-async@3.0.0: {}