obsidian-e2e 0.4.0 → 0.6.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +166 -14
- package/dist/document-DunL2Moz.mjs +69 -0
- package/dist/document-DunL2Moz.mjs.map +1 -0
- package/dist/index.d.mts +16 -2
- package/dist/index.mjs +3 -2
- package/dist/matchers.d.mts +6 -0
- package/dist/matchers.mjs +34 -2
- package/dist/matchers.mjs.map +1 -1
- package/dist/{sandbox--mUbNsh7.mjs → test-context-Bl-e-83H.mjs} +647 -212
- package/dist/test-context-Bl-e-83H.mjs.map +1 -0
- package/dist/{vault-lock-LmqAsLDT.d.mts → types-BUXaueDI.d.mts} +84 -112
- package/dist/vault-lock-XcBHtwm9.d.mts +136 -0
- package/dist/vitest.d.mts +1 -1
- package/dist/vitest.mjs +11 -88
- package/dist/vitest.mjs.map +1 -1
- package/package.json +4 -1
- package/dist/sandbox--mUbNsh7.mjs.map +0 -1
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"test-context-Bl-e-83H.mjs","names":["DEFAULT_TIMEOUT_MS","DEFAULT_TIMEOUT_MS","sleep","sleep","pathPosix","pathPosix"],"sources":["../src/core/args.ts","../src/core/exec-options.ts","../src/core/internals.ts","../src/core/errors.ts","../src/dev/eval-json.ts","../src/metadata/metadata.ts","../src/vault/json-file.ts","../src/plugin/plugin.ts","../src/core/transport.ts","../src/dev/diagnostics.ts","../src/core/wait.ts","../src/core/client.ts","../src/core/path-slug.ts","../src/vault/paths.ts","../src/vault/vault.ts","../src/artifacts/failure-artifacts.ts","../src/vault/sandbox.ts","../src/fixtures/vault-lock.ts","../src/fixtures/base-fixtures.ts","../src/fixtures/test-context.ts"],"sourcesContent":["import type { ObsidianArg } from \"./types\";\n\nexport function buildCommandArgv(\n vaultName: string,\n command: string,\n args: Record<string, ObsidianArg> = {},\n): string[] {\n const argv = [`vault=${vaultName}`, command];\n\n for (const [key, value] of Object.entries(args)) {\n if (value === false || value === null || value === undefined) {\n continue;\n }\n\n if (value === true) {\n argv.push(key);\n continue;\n }\n\n argv.push(`${key}=${String(value)}`);\n }\n\n return argv;\n}\n","import type { ExecOptions } from \"./types\";\n\nexport function mergeExecOptions(\n defaults: ExecOptions | undefined,\n overrides: ExecOptions | undefined,\n): ExecOptions {\n if (!defaults) {\n return overrides ? { ...overrides } : {};\n }\n\n if (!overrides) {\n return { ...defaults };\n }\n\n return {\n ...defaults,\n ...overrides,\n env: mergeEnvironments(defaults.env, overrides.env),\n };\n}\n\nfunction mergeEnvironments(\n defaults: NodeJS.ProcessEnv | undefined,\n overrides: NodeJS.ProcessEnv | undefined,\n): NodeJS.ProcessEnv | undefined {\n if (!defaults) {\n return overrides ? { ...overrides } : undefined;\n }\n\n if (!overrides) {\n return { ...defaults };\n }\n\n return {\n ...defaults,\n ...overrides,\n };\n}\n","import { rm, writeFile } from \"node:fs/promises\";\n\nimport type { ObsidianClient } from \"./types\";\n\ninterface SnapshotEntry {\n exists: boolean;\n value: string;\n}\n\ninterface ClientInternals {\n restoreAll(): Promise<void>;\n restoreFile(filePath: string): Promise<void>;\n snapshotFileOnce(filePath: string): Promise<void>;\n}\n\nconst clientInternals = new WeakMap<ObsidianClient, ClientInternals>();\n\nexport function attachClientInternals(client: ObsidianClient, internals: ClientInternals): void {\n clientInternals.set(client, internals);\n}\n\nexport function getClientInternals(client: ObsidianClient): ClientInternals {\n const internals = clientInternals.get(client);\n\n if (!internals) {\n throw new Error(\"Missing obsidian client internals.\");\n }\n\n return internals;\n}\n\nexport function createRestoreManager(readFile: (filePath: string) => Promise<string>) {\n const snapshots = new Map<string, SnapshotEntry>();\n\n return {\n async restoreAll() {\n const entries = [...snapshots.entries()].reverse();\n\n for (const [filePath, snapshot] of entries) {\n await restoreSnapshot(filePath, snapshot);\n }\n\n snapshots.clear();\n },\n async restoreFile(filePath: string) {\n const snapshot = snapshots.get(filePath);\n\n if (!snapshot) {\n return;\n }\n\n await restoreSnapshot(filePath, snapshot);\n snapshots.delete(filePath);\n },\n async snapshotFileOnce(filePath: string) {\n if (snapshots.has(filePath)) {\n return;\n }\n\n try {\n snapshots.set(filePath, {\n exists: true,\n value: await readFile(filePath),\n });\n } catch (error) {\n if (isMissingFileError(error)) {\n snapshots.set(filePath, {\n exists: false,\n value: \"\",\n });\n return;\n }\n\n throw error;\n }\n },\n };\n}\n\nasync function restoreSnapshot(filePath: string, snapshot: SnapshotEntry): Promise<void> {\n if (snapshot.exists) {\n await writeFile(filePath, snapshot.value, \"utf8\");\n return;\n }\n\n await rm(filePath, { force: true, recursive: true });\n}\n\nfunction isMissingFileError(error: unknown): error is NodeJS.ErrnoException {\n return Boolean(error && typeof error === \"object\" && \"code\" in error && error.code === \"ENOENT\");\n}\n","import type { ExecResult } from \"./types\";\nimport type { DevEvalErrorPayload } from \"./types\";\n\nexport class ObsidianCommandError extends Error {\n readonly result: ExecResult;\n\n constructor(message: string, result: ExecResult) {\n super(message);\n this.name = \"ObsidianCommandError\";\n this.result = result;\n }\n}\n\nexport class WaitForTimeoutError extends Error {\n readonly causeError?: unknown;\n\n constructor(message: string, causeError?: unknown) {\n super(message);\n this.name = \"WaitForTimeoutError\";\n this.causeError = causeError;\n }\n}\n\nexport class DevEvalError extends Error {\n readonly remote: DevEvalErrorPayload;\n\n constructor(message: string, remote: DevEvalErrorPayload) {\n super(message);\n this.name = \"DevEvalError\";\n this.remote = remote;\n\n if (remote.stack) {\n this.stack = `${this.name}: ${message}\\nRemote stack:\\n${remote.stack}`;\n }\n }\n}\n","import { DevEvalError } from \"../core/errors\";\nimport type { DevEvalErrorPayload, ExecOptions, ObsidianDevHandle } from \"../core/types\";\n\ninterface EvalJsonSuccess {\n ok: true;\n value: unknown;\n}\n\ninterface EvalJsonFailure {\n error: DevEvalErrorPayload;\n ok: false;\n}\n\ntype EvalJsonEnvelope = EvalJsonFailure | EvalJsonSuccess;\n\ninterface UndefinedSentinel {\n __obsidianE2EType: \"undefined\";\n}\n\nexport async function runEvalJson<T>(\n dev: Pick<ObsidianDevHandle, \"evalRaw\">,\n code: string,\n execOptions: ExecOptions = {},\n): Promise<T> {\n return parseEvalJsonEnvelope<T>(await dev.evalRaw(buildEvalJsonCode(code), execOptions));\n}\n\nexport function buildEvalJsonCode(code: string): string {\n return [\n \"(()=>{\",\n `const __obsidianE2ECode=${JSON.stringify(code)};`,\n \"const __obsidianE2ESerialize=(value,path='$')=>{\",\n \"if(value===null){return null;}\",\n \"if(value===undefined){return {__obsidianE2EType:'undefined'};}\",\n \"const valueType=typeof value;\",\n \"if(valueType==='string'||valueType==='boolean'){return value;}\",\n \"if(valueType==='number'){if(!Number.isFinite(value)){throw new Error(`Cannot serialize non-finite number at ${path}.`);}return value;}\",\n \"if(valueType==='bigint'||valueType==='function'||valueType==='symbol'){throw new Error(`Cannot serialize ${valueType} at ${path}.`);}\",\n \"if(Array.isArray(value)){return value.map((item,index)=>__obsidianE2ESerialize(item,`${path}[${index}]`));}\",\n \"const prototype=Object.getPrototypeOf(value);\",\n \"if(prototype!==Object.prototype&&prototype!==null){throw new Error(`Cannot serialize non-plain object at ${path}.`);}\",\n \"const next={};\",\n \"for(const [key,entry] of Object.entries(value)){next[key]=__obsidianE2ESerialize(entry,`${path}.${key}`);}\",\n \"return next;\",\n \"};\",\n \"try{\",\n \"return JSON.stringify({ok:true,value:__obsidianE2ESerialize((0,eval)(__obsidianE2ECode))});\",\n \"}catch(error){\",\n \"return JSON.stringify({ok:false,error:{message:error instanceof Error?error.message:String(error),name:error instanceof Error?error.name:'Error',stack:error instanceof Error?error.stack:undefined}});\",\n \"}\",\n \"})()\",\n ].join(\"\");\n}\n\nexport function parseDevEvalOutput<T>(raw: string): T {\n const normalized = normalizeEvalOutput(raw);\n\n try {\n return JSON.parse(normalized) as T;\n } catch {\n return normalized as T;\n }\n}\n\nexport function parseEvalJsonEnvelope<T>(raw: string): T {\n const envelope = JSON.parse(normalizeEvalOutput(raw)) as EvalJsonEnvelope;\n\n if (!envelope.ok) {\n throw new DevEvalError(`Failed to evaluate Obsidian code: ${envelope.error.message}`, {\n ...envelope.error,\n });\n }\n\n return decodeEvalJsonValue(envelope.value) as T;\n}\n\nfunction normalizeEvalOutput(raw: string): string {\n return raw.startsWith(\"=> \") ? raw.slice(3) : raw;\n}\n\nfunction decodeEvalJsonValue(value: unknown): unknown {\n if (Array.isArray(value)) {\n return value.map((entry) => decodeEvalJsonValue(entry));\n }\n\n if (!value || typeof value !== \"object\") {\n return value;\n }\n\n if (isUndefinedSentinel(value)) {\n return undefined;\n }\n\n return Object.fromEntries(\n Object.entries(value).map(([key, entry]) => [key, decodeEvalJsonValue(entry)]),\n );\n}\n\nfunction isUndefinedSentinel(value: object): value is UndefinedSentinel {\n return \"__obsidianE2EType\" in value && value.__obsidianE2EType === \"undefined\";\n}\n","import type {\n ExecOptions,\n MetadataFileCache,\n MetadataPredicate,\n MetadataWaitOptions,\n NoteFrontmatter,\n ObsidianClient,\n ObsidianMetadataHandle,\n} from \"../core/types\";\nimport { runEvalJson } from \"../dev/eval-json\";\n\nexport function createObsidianMetadataHandle(client: ObsidianClient): ObsidianMetadataHandle {\n return {\n async fileCache<T = MetadataFileCache>(path: string, execOptions?: ExecOptions) {\n return readMetadata<T | null>(client, \"metadata\", path, execOptions);\n },\n async frontmatter<T extends NoteFrontmatter = NoteFrontmatter>(\n path: string,\n execOptions?: ExecOptions,\n ) {\n return readMetadata<T | null>(client, \"frontmatter\", path, execOptions);\n },\n async waitForFileCache<T = MetadataFileCache>(\n path: string,\n predicate?: MetadataPredicate<T>,\n options?: MetadataWaitOptions,\n ) {\n return waitForPresentValue(\n client,\n path,\n () => client.metadata.fileCache<T>(path),\n predicate,\n \"metadata cache\",\n options,\n );\n },\n async waitForFrontmatter<T extends NoteFrontmatter = NoteFrontmatter>(\n path: string,\n predicate?: MetadataPredicate<T>,\n options?: MetadataWaitOptions,\n ) {\n return waitForPresentValue(\n client,\n path,\n () => client.metadata.frontmatter<T>(path),\n predicate,\n \"frontmatter\",\n options,\n );\n },\n async waitForMetadata<T = MetadataFileCache>(\n path: string,\n predicate?: MetadataPredicate<T>,\n options?: MetadataWaitOptions,\n ) {\n return waitForPresentValue(\n client,\n path,\n () => client.metadata.fileCache<T>(path),\n predicate,\n \"metadata\",\n options,\n );\n },\n };\n}\n\nasync function readMetadata<T>(\n client: ObsidianClient,\n method: \"frontmatter\" | \"metadata\",\n path: string,\n execOptions?: ExecOptions,\n): Promise<T> {\n return runEvalJson<T>(client.dev, buildMetadataReadCode(method, path), execOptions);\n}\n\nfunction buildMetadataReadCode(method: \"frontmatter\" | \"metadata\", path: string): string {\n return [\n \"(()=>{\",\n `const __obsidianE2EPath=${JSON.stringify(path)};`,\n \"const __obsidianE2EFile=app?.vault?.getAbstractFileByPath?.(__obsidianE2EPath);\",\n \"if(!__obsidianE2EFile){return null;}\",\n method === \"frontmatter\"\n ? \"return app?.metadataCache?.getFileCache?.(__obsidianE2EFile)?.frontmatter ?? null;\"\n : \"return app?.metadataCache?.getFileCache?.(__obsidianE2EFile) ?? null;\",\n \"})()\",\n ].join(\"\");\n}\n\nasync function waitForPresentValue<T>(\n client: ObsidianClient,\n path: string,\n readValue: () => Promise<T | null>,\n predicate: MetadataPredicate<T> | undefined,\n label: string,\n options: MetadataWaitOptions = {},\n): Promise<T> {\n return client.waitFor(\n async () => {\n const value = await readValue();\n\n if (value === null) {\n return false;\n }\n\n return (await (predicate?.(value) ?? true)) ? value : false;\n },\n {\n ...options,\n message: options.message ?? `vault path \"${path}\" to expose ${label}`,\n },\n );\n}\n","import { mkdir, readFile, writeFile } from \"node:fs/promises\";\nimport path from \"node:path\";\n\nimport type { JsonFile, JsonFileUpdater } from \"../core/types\";\n\nexport function createJsonFile<T = unknown>(\n filePath: string,\n beforeMutate?: () => Promise<void>,\n): JsonFile<T> {\n return {\n async patch(updater: JsonFileUpdater<T>) {\n await beforeMutate?.();\n\n const currentValue = await this.read();\n const draft = structuredClone(currentValue);\n const result = await updater(draft);\n const nextValue = result ?? draft;\n\n await this.write(nextValue);\n\n return nextValue;\n },\n async read() {\n const value = await readFile(filePath, \"utf8\");\n return JSON.parse(value) as T;\n },\n async write(value: T) {\n await beforeMutate?.();\n await mkdir(path.dirname(filePath), { recursive: true });\n await writeFile(filePath, `${JSON.stringify(value, null, 2)}\\n`, \"utf8\");\n },\n };\n}\n","import path from \"node:path\";\n\nimport { getClientInternals } from \"../core/internals\";\nimport type {\n JsonFile,\n JsonFileUpdater,\n ObsidianClient,\n PluginDataPredicate,\n PluginHandle,\n PluginReloadOptions,\n PluginToggleOptions,\n PluginUpdateDataOptions,\n PluginWithPatchedDataOptions,\n PluginWaitForDataOptions,\n PluginWaitUntilReadyOptions,\n} from \"../core/types\";\nimport { runEvalJson } from \"../dev/eval-json\";\nimport { createJsonFile } from \"../vault/json-file\";\n\nexport function createPluginHandle(client: ObsidianClient, id: string): PluginHandle {\n async function resolveDataPath() {\n const vaultPath = await client.vaultPath();\n return path.join(vaultPath, \".obsidian\", \"plugins\", id, \"data.json\");\n }\n\n async function isLoadedInApp(): Promise<boolean> {\n try {\n return await runEvalJson<boolean>(client.dev, buildPluginLoadedCode(id));\n } catch {\n return false;\n }\n }\n\n function withDefaultReadyReloadOptions(options: PluginReloadOptions = {}): PluginReloadOptions {\n return {\n ...options,\n waitUntilReady: options.waitUntilReady ?? true,\n };\n }\n\n return {\n data<T = unknown>(): JsonFile<T> {\n return {\n async patch(updater) {\n const dataPath = await resolveDataPath();\n return createJsonFile<T>(dataPath, () =>\n getClientInternals(client).snapshotFileOnce(dataPath),\n ).patch(updater);\n },\n async read() {\n const dataPath = await resolveDataPath();\n return createJsonFile<T>(dataPath).read();\n },\n async write(value) {\n const dataPath = await resolveDataPath();\n await createJsonFile<T>(dataPath, () =>\n getClientInternals(client).snapshotFileOnce(dataPath),\n ).write(value);\n },\n };\n },\n async dataPath() {\n return resolveDataPath();\n },\n async disable(options: PluginToggleOptions = {}) {\n await client.exec(\"plugin:disable\", {\n filter: options.filter,\n id,\n });\n },\n async enable(options: PluginToggleOptions = {}) {\n await client.exec(\"plugin:enable\", {\n filter: options.filter,\n id,\n });\n },\n id,\n async isEnabled() {\n const output = await client.execText(\"plugin\", { id }, { allowNonZeroExit: true });\n return /enabled\\s+true/i.test(output);\n },\n async reload(options: PluginReloadOptions = {}) {\n const { readyOptions, waitUntilReady, ...execOptions } = options;\n\n await client.exec(\"plugin:reload\", { id }, execOptions);\n\n if (waitUntilReady) {\n await this.waitUntilReady(readyOptions);\n }\n },\n async restoreData() {\n await getClientInternals(client).restoreFile(await resolveDataPath());\n },\n async updateDataAndReload<T = unknown>(\n updater: JsonFileUpdater<T>,\n options: PluginUpdateDataOptions<T> = {},\n ): Promise<T> {\n const nextData = await this.data<T>().patch(updater);\n\n if (await this.isEnabled()) {\n await this.reload(withDefaultReadyReloadOptions(options));\n }\n\n return nextData;\n },\n async withPatchedData<T = unknown, TResult = void>(\n updater: JsonFileUpdater<T>,\n run: (plugin: PluginHandle) => Promise<TResult> | TResult,\n options: PluginWithPatchedDataOptions<T> = {},\n ): Promise<TResult> {\n const pluginWasEnabled = await this.isEnabled();\n const reloadOptions = withDefaultReadyReloadOptions(options);\n let hasPatchedData = false;\n let runResult: TResult | undefined;\n let runError: unknown;\n let restoreError: unknown;\n\n try {\n await this.data<T>().patch(updater);\n hasPatchedData = true;\n\n if (pluginWasEnabled) {\n await this.reload(reloadOptions);\n }\n\n runResult = await run(this);\n } catch (error) {\n runError = error;\n }\n\n if (hasPatchedData) {\n try {\n await this.restoreData();\n\n if (pluginWasEnabled) {\n await this.reload(reloadOptions);\n }\n } catch (error) {\n restoreError = error;\n }\n }\n\n if (runError && restoreError) {\n throw new AggregateError(\n [runError, restoreError],\n `Plugin \"${id}\" patch execution and restore both failed.`,\n );\n }\n\n if (runError) {\n throw runError;\n }\n\n if (restoreError) {\n throw restoreError;\n }\n\n return runResult as TResult;\n },\n async waitForData<T = unknown>(\n predicate: PluginDataPredicate<T>,\n options: PluginWaitForDataOptions = {},\n ) {\n return client.waitFor(async () => {\n try {\n const data = await this.data<T>().read();\n return (await predicate(data)) ? data : false;\n } catch {\n return false;\n }\n }, options);\n },\n async waitUntilReady(options: PluginWaitUntilReadyOptions = {}) {\n await client.waitFor(\n async () => {\n if (!(await isLoadedInApp())) {\n return false;\n }\n\n if (options.commandId) {\n return await client.command(options.commandId).exists();\n }\n\n return true;\n },\n {\n ...options,\n message:\n options.message ??\n (options.commandId\n ? `plugin \"${id}\" to be ready with command \"${options.commandId}\"`\n : `plugin \"${id}\" to be ready`),\n },\n );\n },\n };\n}\n\nfunction buildPluginLoadedCode(id: string): string {\n return [\n \"(()=>{\",\n \"const __obsidianE2EPlugins=app?.plugins;\",\n `return Boolean(__obsidianE2EPlugins?.enabledPlugins?.has?.(${JSON.stringify(id)})&&__obsidianE2EPlugins?.plugins?.[${JSON.stringify(id)}]);`,\n \"})()\",\n ].join(\"\");\n}\n","import { spawn } from \"node:child_process\";\n\nimport { ObsidianCommandError } from \"./errors\";\nimport type { CommandTransport, ExecuteRequest, ExecResult } from \"./types\";\n\nconst DEFAULT_TIMEOUT_MS = 30_000;\n\nexport const executeCommand: CommandTransport = async ({\n allowNonZeroExit = false,\n argv,\n bin,\n cwd,\n env,\n timeoutMs = DEFAULT_TIMEOUT_MS,\n}: ExecuteRequest): Promise<ExecResult> => {\n const child = spawn(bin, argv, {\n cwd,\n env,\n stdio: [\"ignore\", \"pipe\", \"pipe\"],\n });\n\n const stdoutChunks: Buffer[] = [];\n const stderrChunks: Buffer[] = [];\n\n child.stdout.on(\"data\", (chunk) => {\n stdoutChunks.push(Buffer.from(chunk));\n });\n\n child.stderr.on(\"data\", (chunk) => {\n stderrChunks.push(Buffer.from(chunk));\n });\n\n const exitCode = await new Promise<number>((resolve, reject) => {\n const timer = setTimeout(() => {\n child.kill(\"SIGTERM\");\n reject(new Error(`Command timed out after ${timeoutMs}ms: ${bin} ${argv.join(\" \")}`));\n }, timeoutMs);\n\n child.on(\"error\", (error) => {\n clearTimeout(timer);\n reject(error);\n });\n\n child.on(\"close\", (code) => {\n clearTimeout(timer);\n resolve(code ?? 0);\n });\n });\n\n const result: ExecResult = {\n argv,\n command: bin,\n exitCode,\n stderr: Buffer.concat(stderrChunks).toString(\"utf8\"),\n stdout: Buffer.concat(stdoutChunks).toString(\"utf8\"),\n };\n\n if (exitCode !== 0 && !allowNonZeroExit) {\n throw new ObsidianCommandError(\n `Obsidian command failed with exit code ${exitCode}: ${bin} ${argv.join(\" \")}`,\n result,\n );\n }\n\n return result;\n};\n","import type {\n DevConsoleMessage,\n DevDiagnostics,\n DevNoticeEvent,\n DevRuntimeError,\n} from \"../core/types\";\n\nconst DIAGNOSTICS_NAMESPACE = \"__obsidianE2EDiagnostics\";\n\nexport type DiagnosticsMethod =\n | \"consoleMessages\"\n | \"diagnostics\"\n | \"notices\"\n | \"reset\"\n | \"runtimeErrors\";\n\nexport function buildDiagnosticsCode(method: DiagnosticsMethod): string {\n return [\n \"(()=>{\",\n `const __obsidianE2EMethod=${JSON.stringify(method)};`,\n `const __obsidianE2ENamespace=${JSON.stringify(DIAGNOSTICS_NAMESPACE)};`,\n \"const __obsidianE2EMaxEntries=100;\",\n \"const __obsidianE2EPush=(entries,value)=>{if(entries.length>=__obsidianE2EMaxEntries){entries.shift();}entries.push(value);};\",\n \"const __obsidianE2EFormat=(value)=>{if(typeof value==='string'){return value;}try{return JSON.stringify(value);}catch{return String(value);}};\",\n \"const __obsidianE2EClone=(value)=>{try{return JSON.parse(JSON.stringify(value));}catch{return __obsidianE2EFormat(value);}};\",\n \"const __obsidianE2EPushRuntimeError=(source,errorLike,state)=>{const message=errorLike&&typeof errorLike==='object'&&'message' in errorLike?String(errorLike.message):String(errorLike);const stack=errorLike&&typeof errorLike==='object'&&'stack' in errorLike?String(errorLike.stack):undefined;__obsidianE2EPush(state.runtimeErrors,{at:Date.now(),message,source,stack});};\",\n \"const root=globalThis;\",\n \"const state=root[__obsidianE2ENamespace]??(root[__obsidianE2ENamespace]={consoleMessages:[],notices:[],runtimeErrors:[],consolePatched:false,noticePatched:false,runtimePatched:false});\",\n \"if(!state.consolePatched&&root.console){for(const level of ['debug','error','info','log','warn']){const original=root.console?.[level];if(typeof original!=='function'){continue;}root.console[level]=(...args)=>{__obsidianE2EPush(state.consoleMessages,{args:args.map(__obsidianE2EClone),at:Date.now(),level,text:args.map(__obsidianE2EFormat).join(' ')});return original.apply(root.console,args);};}state.consolePatched=true;}\",\n \"if(!state.runtimePatched&&typeof root.addEventListener==='function'){root.addEventListener('error',(event)=>{__obsidianE2EPushRuntimeError('error',event?.error??event?.message??'Unknown error',state);});root.addEventListener('unhandledrejection',(event)=>{__obsidianE2EPushRuntimeError('unhandledrejection',event?.reason??'Unhandled rejection',state);});state.runtimePatched=true;}\",\n \"if(!state.noticePatched&&typeof root.Notice==='function'){const OriginalNotice=root.Notice;root.Notice=new Proxy(OriginalNotice,{construct(target,ctorArgs,newTarget){__obsidianE2EPush(state.notices,{at:Date.now(),message:__obsidianE2EFormat(ctorArgs[0]??''),timeout:typeof ctorArgs[1]==='number'&&Number.isFinite(ctorArgs[1])?ctorArgs[1]:undefined});return Reflect.construct(target,ctorArgs,newTarget);}});state.noticePatched=true;}\",\n \"if(__obsidianE2EMethod==='reset'){state.consoleMessages.splice(0);state.notices.splice(0);state.runtimeErrors.splice(0);return true;}\",\n \"if(__obsidianE2EMethod==='consoleMessages'){return state.consoleMessages;}\",\n \"if(__obsidianE2EMethod==='notices'){return state.notices;}\",\n \"if(__obsidianE2EMethod==='runtimeErrors'){return state.runtimeErrors;}\",\n \"return {consoleMessages:state.consoleMessages,notices:state.notices,runtimeErrors:state.runtimeErrors};\",\n \"})()\",\n ].join(\"\");\n}\n\nexport function createDevDiagnostics(value: DevDiagnostics | null | undefined): DevDiagnostics {\n return {\n consoleMessages: (value?.consoleMessages ?? []) as DevConsoleMessage[],\n notices: (value?.notices ?? []) as DevNoticeEvent[],\n runtimeErrors: (value?.runtimeErrors ?? []) as DevRuntimeError[],\n };\n}\n","import { WaitForTimeoutError } from \"./errors\";\nimport type { WaitForOptions } from \"./types\";\n\nconst DEFAULT_INTERVAL_MS = 100;\nconst DEFAULT_TIMEOUT_MS = 5_000;\n\nexport async function sleep(ms: number): Promise<void> {\n await new Promise((resolve) => setTimeout(resolve, ms));\n}\n\nexport async function waitForValue<T>(\n fn: () => Promise<T | false | null | undefined> | T | false | null | undefined,\n options: WaitForOptions = {},\n): Promise<T> {\n const intervalMs = options.intervalMs ?? DEFAULT_INTERVAL_MS;\n const timeoutMs = options.timeoutMs ?? DEFAULT_TIMEOUT_MS;\n const startTime = Date.now();\n\n let lastError: unknown;\n\n while (Date.now() - startTime <= timeoutMs) {\n try {\n const result = await fn();\n if (result !== false && result !== null && result !== undefined) {\n return result;\n }\n } catch (error) {\n lastError = error;\n }\n\n await sleep(intervalMs);\n }\n\n const label = options.message ?? \"condition\";\n throw new WaitForTimeoutError(`Timed out waiting for ${label} after ${timeoutMs}ms.`, lastError);\n}\n","import { buildCommandArgv } from \"./args\";\nimport { mergeExecOptions } from \"./exec-options\";\nimport { attachClientInternals, createRestoreManager } from \"./internals\";\nimport { createObsidianMetadataHandle } from \"../metadata/metadata\";\nimport { createPluginHandle } from \"../plugin/plugin\";\nimport { executeCommand } from \"./transport\";\nimport { buildDiagnosticsCode, createDevDiagnostics } from \"../dev/diagnostics\";\nimport { parseDevEvalOutput, runEvalJson } from \"../dev/eval-json\";\nimport type {\n CommandListOptions,\n CreateObsidianClientOptions,\n DevConsoleMessage,\n DevDiagnostics,\n DevNoticeEvent,\n DevDomQueryOptions,\n DevDomResult,\n DevRuntimeError,\n ExecOptions,\n ObsidianArg,\n ObsidianAppHandle,\n ObsidianCommandHandle,\n ObsidianClient,\n ObsidianDevHandle,\n OpenFileOptions,\n OpenTabOptions,\n RestartAppOptions,\n TabsOptions,\n WaitForOptions,\n WorkspaceNode,\n WorkspaceOptions,\n WorkspaceTab,\n} from \"./types\";\nimport { sleep, waitForValue } from \"./wait\";\n\nexport function createObsidianClient(options: CreateObsidianClientOptions): ObsidianClient {\n const transport = options.transport ?? executeCommand;\n const defaultExecOptions = options.defaultExecOptions;\n const waitDefaults = {\n intervalMs: options.intervalMs,\n timeoutMs: options.timeoutMs,\n };\n\n const restoreManager = createRestoreManager(async (filePath) => {\n const { readFile } = await import(\"node:fs/promises\");\n return readFile(filePath, \"utf8\");\n });\n\n let cachedVaultPath: string | undefined;\n\n const client = {} as ObsidianClient;\n const metadata = createObsidianMetadataHandle(client);\n\n const app: ObsidianAppHandle = {\n async reload(execOptions: ExecOptions = {}) {\n await client.exec(\"reload\", {}, execOptions);\n },\n async restart({\n readyOptions,\n waitUntilReady = true,\n ...execOptions\n }: RestartAppOptions & ExecOptions = {}) {\n await client.exec(\"restart\", {}, execOptions);\n\n if (waitUntilReady) {\n await app.waitUntilReady(readyOptions);\n }\n },\n version(execOptions: ExecOptions = {}) {\n return client.execText(\"version\", {}, execOptions);\n },\n async waitUntilReady(waitOptions?: WaitForOptions) {\n await client.waitFor(async () => {\n try {\n await client.vaultPath();\n await client.commands();\n return true;\n } catch {\n return false;\n }\n }, waitOptions);\n },\n };\n\n const dev: ObsidianDevHandle = {\n async activeFilePath(execOptions: ExecOptions = {}) {\n return this.eval<string | null>(\"app.workspace.getActiveFile()?.path ?? null\", execOptions);\n },\n async consoleMessages(execOptions: ExecOptions = {}) {\n return readDiagnosticsValue<DevConsoleMessage[]>(this, \"consoleMessages\", execOptions);\n },\n async diagnostics(execOptions: ExecOptions = {}): Promise<DevDiagnostics> {\n return createDevDiagnostics(\n await readDiagnosticsValue<DevDiagnostics>(this, \"diagnostics\", execOptions),\n );\n },\n async dom(options: DevDomQueryOptions, execOptions: ExecOptions = {}): Promise<DevDomResult> {\n const output = await client.execText(\n \"dev:dom\",\n {\n all: options.all,\n attr: options.attr,\n css: options.css,\n inner: options.inner,\n selector: options.selector,\n text: options.text,\n total: options.total,\n },\n execOptions,\n );\n\n if (options.total) {\n return Number.parseInt(output, 10);\n }\n\n if (options.all) {\n return output ? output.split(/\\r?\\n/u).filter(Boolean) : [];\n }\n\n return output;\n },\n async eval<T = unknown>(code: string, execOptions: ExecOptions = {}) {\n return parseDevEvalOutput<T>(await this.evalRaw(code, execOptions));\n },\n async evalJson<T = unknown>(code: string, execOptions: ExecOptions = {}) {\n return runEvalJson<T>(this, code, execOptions);\n },\n async evalRaw(code: string, execOptions: ExecOptions = {}) {\n return client.execText(\n \"eval\",\n {\n code,\n },\n execOptions,\n );\n },\n async editorText(execOptions: ExecOptions = {}) {\n return this.eval<string | null>(\n \"app.workspace.activeLeaf?.view?.editor?.getValue?.() ?? null\",\n execOptions,\n );\n },\n async notices(execOptions: ExecOptions = {}) {\n return readDiagnosticsValue<DevNoticeEvent[]>(this, \"notices\", execOptions);\n },\n async resetDiagnostics(execOptions: ExecOptions = {}) {\n await readDiagnosticsValue<boolean>(this, \"reset\", execOptions);\n },\n async runtimeErrors(execOptions: ExecOptions = {}) {\n return readDiagnosticsValue<DevRuntimeError[]>(this, \"runtimeErrors\", execOptions);\n },\n async screenshot(targetPath: string, execOptions: ExecOptions = {}) {\n await client.exec(\n \"dev:screenshot\",\n {\n path: targetPath,\n },\n execOptions,\n );\n\n return targetPath;\n },\n };\n\n Object.assign(client, {\n app,\n bin: options.bin ?? \"obsidian\",\n dev,\n metadata,\n command(id: string): ObsidianCommandHandle {\n return {\n async exists(commandOptions: CommandListOptions = {}) {\n const commands = await client.commands({\n ...commandOptions,\n filter: commandOptions.filter ?? id,\n });\n\n return commands.includes(id);\n },\n id,\n async run(execOptions: ExecOptions = {}) {\n await client.exec(\"command\", { id }, execOptions);\n },\n };\n },\n async commands(\n commandOptions: CommandListOptions = {},\n execOptions: ExecOptions = {},\n ): Promise<string[]> {\n const output = await client.execText(\n \"commands\",\n {\n filter: commandOptions.filter,\n },\n execOptions,\n );\n return parseCommandIds(output);\n },\n exec(command: string, args: Record<string, ObsidianArg> = {}, execOptions: ExecOptions = {}) {\n return transport({\n ...mergeExecOptions(defaultExecOptions, execOptions),\n argv: buildCommandArgv(options.vault, command, args),\n bin: this.bin,\n });\n },\n async execJson<T = unknown>(\n command: string,\n args: Record<string, ObsidianArg> = {},\n execOptions: ExecOptions = {},\n ) {\n const output = await this.execText(command, args, execOptions);\n return JSON.parse(output) as T;\n },\n async execText(\n command: string,\n args: Record<string, ObsidianArg> = {},\n execOptions: ExecOptions = {},\n ) {\n const result = await this.exec(command, args, execOptions);\n return result.stdout.trimEnd();\n },\n async open(openOptions: OpenFileOptions, execOptions: ExecOptions = {}) {\n await client.exec(\n \"open\",\n {\n file: openOptions.file,\n newtab: openOptions.newTab,\n path: openOptions.path,\n },\n execOptions,\n );\n },\n async openTab(tabOptions: OpenTabOptions = {}, execOptions: ExecOptions = {}) {\n await client.exec(\n \"tab:open\",\n {\n file: tabOptions.file,\n group: tabOptions.group,\n view: tabOptions.view,\n },\n execOptions,\n );\n },\n plugin(id: string) {\n return createPluginHandle(this, id);\n },\n sleep(ms: number) {\n return sleep(ms);\n },\n async tabs(\n tabOptions: TabsOptions = {},\n execOptions: ExecOptions = {},\n ): Promise<WorkspaceTab[]> {\n const output = await client.execText(\n \"tabs\",\n {\n ids: tabOptions.ids ?? true,\n },\n execOptions,\n );\n return parseTabs(output);\n },\n async vaultPath() {\n if (!cachedVaultPath) {\n cachedVaultPath = await this.execText(\"vault\", { info: \"path\" });\n }\n\n return cachedVaultPath;\n },\n async verify() {\n await transport({\n ...mergeExecOptions(defaultExecOptions, undefined),\n argv: [\"--help\"],\n bin: this.bin,\n });\n\n await this.vaultPath();\n },\n vaultName: options.vault,\n async waitForActiveFile(path: string, options?: WaitForOptions) {\n return client.waitFor(\n async () => {\n const activePath = await dev.activeFilePath();\n\n return activePath === path ? activePath : false;\n },\n {\n ...options,\n message: options?.message ?? `active file \"${path}\"`,\n },\n );\n },\n async waitForConsoleMessage(\n predicate: (message: DevConsoleMessage) => boolean | Promise<boolean>,\n options?: WaitForOptions,\n ) {\n return waitForDiagnosticEntry(\n client,\n () => client.dev.consoleMessages(),\n predicate,\n options?.message ?? \"console message\",\n options,\n );\n },\n async waitForNotice(\n predicate: string | ((notice: DevNoticeEvent) => boolean | Promise<boolean>),\n options?: WaitForOptions,\n ) {\n return waitForDiagnosticEntry(\n client,\n () => client.dev.notices(),\n typeof predicate === \"string\" ? (notice) => notice.message.includes(predicate) : predicate,\n options?.message ?? \"notice\",\n options,\n );\n },\n async waitForRuntimeError(\n predicate: string | ((error: DevRuntimeError) => boolean | Promise<boolean>),\n options?: WaitForOptions,\n ) {\n return waitForDiagnosticEntry(\n client,\n () => client.dev.runtimeErrors(),\n typeof predicate === \"string\" ? (error) => error.message.includes(predicate) : predicate,\n options?.message ?? \"runtime error\",\n options,\n );\n },\n waitFor<T>(\n fn: () => Promise<T | false | null | undefined> | T | false | null | undefined,\n waitOptions?: WaitForOptions,\n ) {\n return waitForValue(fn, {\n ...waitDefaults,\n ...waitOptions,\n });\n },\n async workspace(\n workspaceOptions: WorkspaceOptions = {},\n execOptions: ExecOptions = {},\n ): Promise<WorkspaceNode[]> {\n const output = await client.execText(\n \"workspace\",\n {\n ids: workspaceOptions.ids ?? true,\n },\n execOptions,\n );\n return parseWorkspace(output);\n },\n });\n\n attachClientInternals(client, restoreManager);\n\n return client;\n}\n\nfunction parseCommandIds(output: string): string[] {\n return output\n .split(/\\r?\\n/u)\n .map((line) => line.trim())\n .filter(Boolean)\n .map((line) => line.split(\"\\t\", 1)[0]?.trim() ?? \"\")\n .filter(Boolean);\n}\n\nfunction parseTabs(output: string): WorkspaceTab[] {\n return output\n .split(/\\r?\\n/u)\n .map((line) => line.trim())\n .filter(Boolean)\n .map(parseTabLine);\n}\n\nfunction parseTabLine(line: string): WorkspaceTab {\n const [descriptor, id] = line.split(\"\\t\");\n const match = descriptor?.match(/^\\[(.+?)\\]\\s+(.*)$/u);\n\n if (!match) {\n return {\n id: id?.trim() || undefined,\n title: descriptor?.trim() ?? \"\",\n viewType: \"unknown\",\n };\n }\n\n return {\n id: id?.trim() || undefined,\n title: match[2]!,\n viewType: match[1]!,\n };\n}\n\nfunction parseWorkspace(output: string): WorkspaceNode[] {\n const roots: WorkspaceNode[] = [];\n const stack: Array<{ depth: number; node: WorkspaceNode }> = [];\n\n for (const rawLine of output.split(/\\r?\\n/u)) {\n if (!rawLine.trim()) {\n continue;\n }\n\n const depth = getWorkspaceDepth(rawLine);\n const node = parseWorkspaceNode(rawLine);\n\n while (stack.length > 0 && stack.at(-1)!.depth >= depth) {\n stack.pop();\n }\n\n const parent = stack.at(-1)?.node;\n\n if (parent) {\n parent.children.push(node);\n } else {\n roots.push(node);\n }\n\n stack.push({ depth, node });\n }\n\n return roots;\n}\n\nasync function waitForDiagnosticEntry<T>(\n client: ObsidianClient,\n readEntries: () => Promise<T[]>,\n predicate: (entry: T) => boolean | Promise<boolean>,\n label: string,\n options?: WaitForOptions,\n): Promise<T> {\n return client.waitFor(\n async () => {\n const entries = await readEntries();\n\n for (const entry of entries) {\n if (await predicate(entry)) {\n return entry;\n }\n }\n\n return false;\n },\n {\n ...options,\n message: options?.message ?? label,\n },\n );\n}\n\nasync function readDiagnosticsValue<T>(\n dev: Pick<ObsidianDevHandle, \"evalRaw\">,\n method: \"consoleMessages\" | \"diagnostics\" | \"notices\" | \"reset\" | \"runtimeErrors\",\n execOptions?: ExecOptions,\n): Promise<T> {\n return runEvalJson<T>(dev, buildDiagnosticsCode(method), execOptions);\n}\n\nfunction getWorkspaceDepth(line: string): number {\n let depth = 0;\n let remainder = line;\n\n while (true) {\n if (\n remainder.startsWith(\"│ \") ||\n remainder.startsWith(\" \") ||\n remainder.startsWith(\"├── \") ||\n remainder.startsWith(\"└── \")\n ) {\n depth += 1;\n remainder = remainder.slice(4);\n continue;\n }\n\n return depth;\n }\n}\n\nfunction parseWorkspaceNode(line: string): WorkspaceNode {\n let withoutTree = line;\n\n while (true) {\n if (\n withoutTree.startsWith(\"│ \") ||\n withoutTree.startsWith(\" \") ||\n withoutTree.startsWith(\"├── \") ||\n withoutTree.startsWith(\"└── \")\n ) {\n withoutTree = withoutTree.slice(4);\n continue;\n }\n\n break;\n }\n\n withoutTree = withoutTree.trim();\n const idMatch = withoutTree.match(/^(.*?)(?: \\(([a-z0-9]+)\\))?$/iu);\n const content = idMatch?.[1]?.trim() ?? withoutTree;\n const id = idMatch?.[2];\n const leafMatch = content.match(/^\\[(.+?)\\]\\s+(.*)$/u);\n\n if (leafMatch) {\n return {\n children: [],\n id,\n label: leafMatch[2]!,\n title: leafMatch[2]!,\n viewType: leafMatch[1]!,\n };\n }\n\n return {\n children: [],\n id,\n label: content,\n };\n}\n","export interface SanitizePathSegmentOptions {\n fallback?: string;\n maxLength?: number;\n}\n\nexport function sanitizePathSegment(\n value: string,\n options: SanitizePathSegmentOptions = {},\n): string {\n const fallback = options.fallback ?? \"test\";\n const maxLength = options.maxLength ?? 80;\n\n return (\n value\n .trim()\n .toLowerCase()\n .replace(/[^a-z0-9]+/g, \"-\")\n .replace(/^-+|-+$/g, \"\")\n .slice(0, maxLength) || fallback\n );\n}\n","import path from \"node:path\";\nimport { posix as pathPosix } from \"node:path\";\n\nimport type { ObsidianClient } from \"../core/types\";\n\nexport function normalizeScope(scope?: string): string {\n if (!scope || scope === \".\") {\n return \"\";\n }\n\n return scope.replace(/^\\/+|\\/+$/g, \"\");\n}\n\nexport function resolveVaultPath(scopeRoot: string, targetPath: string): string {\n if (!targetPath || targetPath === \".\") {\n return scopeRoot;\n }\n\n return scopeRoot ? pathPosix.join(scopeRoot, targetPath) : pathPosix.normalize(targetPath);\n}\n\nexport async function resolveFilesystemPath(\n obsidian: ObsidianClient,\n scopeRoot: string,\n targetPath: string,\n): Promise<string> {\n const vaultPath = await obsidian.vaultPath();\n const scopedPath = resolveVaultPath(scopeRoot, targetPath);\n const relativePath = scopedPath.split(\"/\").filter(Boolean);\n const resolvedPath = path.resolve(vaultPath, ...relativePath);\n const normalizedVaultPath = path.resolve(vaultPath);\n\n if (\n resolvedPath !== normalizedVaultPath &&\n !resolvedPath.startsWith(`${normalizedVaultPath}${path.sep}`)\n ) {\n throw new Error(`Resolved path escapes the vault root: ${targetPath}`);\n }\n\n return resolvedPath;\n}\n","import { access, mkdir, readFile, rm, writeFile } from \"node:fs/promises\";\nimport path from \"node:path\";\n\nimport type {\n DeleteOptions,\n JsonFile,\n ObsidianClient,\n VaultApi,\n VaultWaitForContentOptions,\n VaultWriteOptions,\n} from \"../core/types\";\nimport { normalizeScope, resolveFilesystemPath, resolveVaultPath } from \"./paths\";\n\ninterface CreateVaultApiOptions {\n obsidian: ObsidianClient;\n root?: string;\n}\n\nexport function createVaultApi(options: CreateVaultApiOptions): VaultApi {\n const scopeRoot = normalizeScope(options.root);\n\n return {\n async delete(targetPath, deleteOptions: DeleteOptions = {}) {\n const resolvedPath = await resolveFilesystemPath(options.obsidian, scopeRoot, targetPath);\n await rm(resolvedPath, {\n force: true,\n recursive: true,\n });\n\n if (deleteOptions.permanent === false) {\n return;\n }\n },\n async exists(targetPath) {\n try {\n const resolvedPath = await resolveFilesystemPath(options.obsidian, scopeRoot, targetPath);\n await access(resolvedPath);\n return true;\n } catch {\n return false;\n }\n },\n json<T = unknown>(targetPath: string) {\n const jsonFile: JsonFile<T> = {\n async patch(updater) {\n const currentValue = await jsonFile.read();\n const draft = structuredClone(currentValue);\n const result = await updater(draft);\n const nextValue = result ?? draft;\n\n await jsonFile.write(nextValue);\n\n return nextValue;\n },\n async read() {\n const resolvedPath = await resolveFilesystemPath(options.obsidian, scopeRoot, targetPath);\n const rawValue = await readFile(resolvedPath, \"utf8\");\n return JSON.parse(rawValue) as T;\n },\n async write(value) {\n const resolvedPath = await resolveFilesystemPath(options.obsidian, scopeRoot, targetPath);\n await mkdir(path.dirname(resolvedPath), { recursive: true });\n await writeFile(resolvedPath, `${JSON.stringify(value, null, 2)}\\n`, \"utf8\");\n },\n };\n\n return jsonFile;\n },\n async mkdir(targetPath) {\n const resolvedPath = await resolveFilesystemPath(options.obsidian, scopeRoot, targetPath);\n await mkdir(resolvedPath, { recursive: true });\n },\n async read(targetPath) {\n const resolvedPath = await resolveFilesystemPath(options.obsidian, scopeRoot, targetPath);\n return readFile(resolvedPath, \"utf8\");\n },\n async waitForContent(targetPath, predicate, waitOptions: VaultWaitForContentOptions = {}) {\n const resolvedPath = await resolveFilesystemPath(options.obsidian, scopeRoot, targetPath);\n\n return options.obsidian.waitFor(\n async () => {\n try {\n const content = await readFile(resolvedPath, \"utf8\");\n return (await predicate(content)) ? content : false;\n } catch {\n return false;\n }\n },\n {\n message: `vault path \"${resolveVaultPath(scopeRoot, targetPath)}\" to match content`,\n ...waitOptions,\n },\n );\n },\n async waitForExists(targetPath, waitOptions) {\n const resolvedPath = await resolveFilesystemPath(options.obsidian, scopeRoot, targetPath);\n\n await options.obsidian.waitFor(\n async () => {\n try {\n await access(resolvedPath);\n return true;\n } catch {\n return false;\n }\n },\n {\n message: `vault path \"${resolveVaultPath(scopeRoot, targetPath)}\" to exist`,\n ...waitOptions,\n },\n );\n },\n async waitForMissing(targetPath, waitOptions) {\n const resolvedPath = await resolveFilesystemPath(options.obsidian, scopeRoot, targetPath);\n\n await options.obsidian.waitFor(\n async () => {\n try {\n await access(resolvedPath);\n return false;\n } catch {\n return true;\n }\n },\n {\n message: `vault path \"${resolveVaultPath(scopeRoot, targetPath)}\" to be removed`,\n ...waitOptions,\n },\n );\n },\n async write(targetPath, content, writeOptions: VaultWriteOptions = {}) {\n const resolvedPath = await resolveFilesystemPath(options.obsidian, scopeRoot, targetPath);\n await mkdir(path.dirname(resolvedPath), { recursive: true });\n await writeFile(resolvedPath, content, \"utf8\");\n\n if (!writeOptions.waitForContent) {\n return;\n }\n\n const predicate =\n typeof writeOptions.waitForContent === \"function\"\n ? writeOptions.waitForContent\n : (value: string) => value === content;\n\n await this.waitForContent(targetPath, predicate, writeOptions.waitOptions);\n },\n };\n}\n","import { mkdir, writeFile } from \"node:fs/promises\";\nimport path from \"node:path\";\n\nimport type { ObsidianClient, PluginHandle } from \"../core/types\";\nimport { sanitizePathSegment } from \"../core/path-slug\";\nimport { parseNoteDocument } from \"../note/document\";\nimport { createVaultApi } from \"../vault/vault\";\n\nexport const DEFAULT_FAILURE_ARTIFACTS_DIR = \".obsidian-e2e-artifacts\";\n\nexport interface FailureArtifactOptions {\n activeFile?: boolean;\n activeNote?: boolean;\n consoleMessages?: boolean;\n dom?: boolean;\n editorText?: boolean;\n notices?: boolean;\n parsedFrontmatter?: boolean;\n runtimeErrors?: boolean;\n screenshot?: boolean;\n tabs?: boolean;\n workspace?: boolean;\n}\n\nexport interface FailureArtifactTask {\n id: string;\n name: string;\n}\n\nexport interface FailureArtifactConfig {\n artifactsDir: string;\n capture: Required<FailureArtifactOptions>;\n enabled: boolean;\n}\n\nexport interface FailureArtifactRegistrationOptions {\n artifactsDir?: string;\n captureOnFailure?: boolean | FailureArtifactOptions;\n}\n\nexport interface CaptureFailureArtifactsOptions extends FailureArtifactRegistrationOptions {\n plugin?: PluginHandle;\n}\n\nconst DEFAULT_FAILURE_ARTIFACT_CAPTURE: Required<FailureArtifactOptions> = {\n activeFile: true,\n activeNote: true,\n consoleMessages: true,\n dom: true,\n editorText: true,\n notices: true,\n parsedFrontmatter: true,\n runtimeErrors: true,\n screenshot: true,\n tabs: true,\n workspace: true,\n};\n\nexport function getFailureArtifactConfig(\n options: FailureArtifactRegistrationOptions,\n): FailureArtifactConfig {\n if (!options.captureOnFailure) {\n return {\n artifactsDir: path.resolve(options.artifactsDir ?? DEFAULT_FAILURE_ARTIFACTS_DIR),\n capture: { ...DEFAULT_FAILURE_ARTIFACT_CAPTURE },\n enabled: false,\n };\n }\n\n const overrides = options.captureOnFailure === true ? {} : options.captureOnFailure;\n\n return {\n artifactsDir: path.resolve(options.artifactsDir ?? DEFAULT_FAILURE_ARTIFACTS_DIR),\n capture: { ...DEFAULT_FAILURE_ARTIFACT_CAPTURE, ...overrides },\n enabled: true,\n };\n}\n\nexport function getFailureArtifactDirectory(\n artifactsDir: string,\n task: FailureArtifactTask,\n): string {\n const suffix = task.id.split(\"_\").at(-1) ?? \"test\";\n return path.join(artifactsDir, `${sanitizePathSegment(task.name, { maxLength: 60 })}-${suffix}`);\n}\n\nexport async function captureFailureArtifacts(\n task: FailureArtifactTask,\n obsidian: ObsidianClient,\n options: CaptureFailureArtifactsOptions,\n): Promise<string | undefined> {\n const config = getFailureArtifactConfig(options);\n\n if (!config.enabled) {\n return undefined;\n }\n\n const artifactDirectory = getFailureArtifactDirectory(config.artifactsDir, task);\n await mkdir(artifactDirectory, { recursive: true });\n const activeFile = readArtifactInput(() => readActiveFilePath(obsidian));\n const activeNote = readArtifactInput(async () => {\n const activeFilePath = await unwrapArtifactInput(activeFile);\n\n return activeFilePath ? readActiveNoteSnapshot(obsidian, activeFilePath) : null;\n });\n const diagnostics = await obsidian.dev.diagnostics().catch(() => null);\n\n await Promise.all([\n captureJsonArtifact(\n artifactDirectory,\n \"active-file.json\",\n config.capture.activeFile,\n async () => ({\n activeFile: await unwrapArtifactInput(activeFile),\n }),\n ),\n captureTextArtifact(\n artifactDirectory,\n \"active-note.md\",\n config.capture.activeNote,\n async () => (await unwrapArtifactInput(activeNote))?.raw ?? \"\",\n ),\n captureJsonArtifact(\n artifactDirectory,\n \"active-note-frontmatter.json\",\n config.capture.parsedFrontmatter,\n async () => ({\n frontmatter: (await unwrapArtifactInput(activeNote))?.frontmatter ?? null,\n }),\n ),\n captureTextArtifact(artifactDirectory, \"dom.txt\", config.capture.dom, async () =>\n String(\n await obsidian.dev.dom({\n inner: true,\n selector: \".workspace\",\n }),\n ),\n ),\n captureJsonArtifact(artifactDirectory, \"editor.json\", config.capture.editorText, async () => ({\n text: await obsidian.dev.editorText(),\n })),\n captureJsonArtifact(\n artifactDirectory,\n \"console-messages.json\",\n config.capture.consoleMessages,\n async () => diagnostics?.consoleMessages ?? [],\n ),\n captureJsonArtifact(\n artifactDirectory,\n \"runtime-errors.json\",\n config.capture.runtimeErrors,\n async () => diagnostics?.runtimeErrors ?? [],\n ),\n captureJsonArtifact(\n artifactDirectory,\n \"notices.json\",\n config.capture.notices,\n async () => diagnostics?.notices ?? [],\n ),\n captureScreenshotArtifact(artifactDirectory, config.capture.screenshot, obsidian),\n captureJsonArtifact(artifactDirectory, \"tabs.json\", config.capture.tabs, () => obsidian.tabs()),\n captureJsonArtifact(artifactDirectory, \"workspace.json\", config.capture.workspace, () =>\n obsidian.workspace(),\n ),\n options.plugin\n ? captureJsonArtifact(artifactDirectory, `${options.plugin.id}-data.json`, true, () =>\n options.plugin!.data().read(),\n )\n : Promise.resolve(),\n ]);\n\n return artifactDirectory;\n}\n\nexport async function capturePluginFailureArtifacts(\n task: FailureArtifactTask,\n plugin: PluginHandle,\n options: FailureArtifactRegistrationOptions,\n): Promise<string | undefined> {\n const config = getFailureArtifactConfig(options);\n\n if (!config.enabled) {\n return undefined;\n }\n\n const artifactDirectory = getFailureArtifactDirectory(config.artifactsDir, task);\n await mkdir(artifactDirectory, { recursive: true });\n await captureJsonArtifact(artifactDirectory, `${plugin.id}-data.json`, true, () =>\n plugin.data().read(),\n );\n\n return artifactDirectory;\n}\n\nasync function captureJsonArtifact(\n artifactDirectory: string,\n filename: string,\n enabled: boolean,\n readValue: () => Promise<unknown>,\n): Promise<void> {\n if (!enabled) {\n return;\n }\n\n try {\n const value = await readValue();\n await writeFile(\n path.join(artifactDirectory, filename),\n `${JSON.stringify(value, null, 2)}\\n`,\n \"utf8\",\n );\n } catch (error) {\n await writeFile(\n path.join(artifactDirectory, `${filename}.error.txt`),\n formatArtifactError(error),\n \"utf8\",\n );\n }\n}\n\nasync function captureScreenshotArtifact(\n artifactDirectory: string,\n enabled: boolean,\n obsidian: ObsidianClient,\n): Promise<void> {\n if (!enabled) {\n return;\n }\n\n const screenshotPath = path.join(artifactDirectory, \"screenshot.png\");\n\n try {\n await obsidian.dev.screenshot(screenshotPath);\n } catch (error) {\n await writeFile(\n path.join(artifactDirectory, \"screenshot.error.txt\"),\n formatArtifactError(error),\n \"utf8\",\n );\n }\n}\n\nasync function captureTextArtifact(\n artifactDirectory: string,\n filename: string,\n enabled: boolean,\n readValue: () => Promise<string>,\n): Promise<void> {\n if (!enabled) {\n return;\n }\n\n try {\n await writeFile(path.join(artifactDirectory, filename), await readValue(), \"utf8\");\n } catch (error) {\n await writeFile(\n path.join(artifactDirectory, `${filename}.error.txt`),\n formatArtifactError(error),\n \"utf8\",\n );\n }\n}\n\nfunction formatArtifactError(error: unknown): string {\n return error instanceof Error ? `${error.name}: ${error.message}\\n` : `${String(error)}\\n`;\n}\n\nasync function readActiveFilePath(obsidian: ObsidianClient): Promise<string | null> {\n return obsidian.dev.activeFilePath();\n}\n\nasync function readActiveNoteSnapshot(obsidian: ObsidianClient, activeFile: string) {\n const vault = createVaultApi({ obsidian });\n const raw = await vault.read(activeFile);\n\n return parseNoteDocument(raw);\n}\n\ninterface ArtifactInputResult<T> {\n promise: Promise<{ error: unknown; ok: false } | { ok: true; value: T }>;\n}\n\nfunction readArtifactInput<T>(readValue: () => Promise<T>): ArtifactInputResult<T> {\n return {\n promise: readValue().then(\n (value) => ({ ok: true, value }) as const,\n (error) => ({ error, ok: false }) as const,\n ),\n };\n}\n\nasync function unwrapArtifactInput<T>(result: ArtifactInputResult<T>): Promise<T> {\n const value = await result.promise;\n\n if (!value.ok) {\n throw value.error;\n }\n\n return value.value;\n}\n","import { posix as pathPosix } from \"node:path\";\nimport { randomUUID } from \"node:crypto\";\n\nimport type {\n NoteDocument,\n NoteFrontmatter,\n ObsidianClient,\n SandboxApi,\n SandboxWriteNoteOptions,\n} from \"../core/types\";\nimport { sanitizePathSegment } from \"../core/path-slug\";\nimport { createNoteDocument, parseNoteDocument } from \"../note/document\";\nimport { createVaultApi } from \"./vault\";\n\ninterface CreateSandboxApiOptions {\n obsidian: ObsidianClient;\n sandboxRoot: string;\n testName: string;\n}\n\nexport async function createSandboxApi(options: CreateSandboxApiOptions): Promise<SandboxApi> {\n const root = pathPosix.join(\n options.sandboxRoot,\n `${sanitizePathSegment(options.testName)}-${randomUUID().slice(0, 8)}`,\n );\n const sandboxPath = (...segments: string[]) => pathPosix.join(root, ...segments);\n const vault = createVaultApi({\n obsidian: options.obsidian,\n root,\n });\n\n await vault.mkdir(\".\");\n\n return {\n ...vault,\n async cleanup() {\n await vault.delete(\".\", { permanent: true });\n },\n path(...segments: string[]) {\n return sandboxPath(...segments);\n },\n async readNote<TFrontmatter extends NoteFrontmatter | null = NoteFrontmatter | null>(\n targetPath: string,\n ): Promise<NoteDocument<TFrontmatter>> {\n return parseNoteDocument(await vault.read(targetPath)) as NoteDocument<TFrontmatter>;\n },\n root,\n async writeNote<TFrontmatter extends NoteFrontmatter | null = NoteFrontmatter | null>(\n writeOptions: SandboxWriteNoteOptions<TFrontmatter>,\n ): Promise<NoteDocument<TFrontmatter>> {\n const { path, waitForMetadata = true, waitOptions, ...noteInput } = writeOptions;\n const document = createNoteDocument(noteInput) as NoteDocument<TFrontmatter>;\n\n await vault.write(path, document.raw);\n\n if (waitForMetadata) {\n const predicate = typeof waitForMetadata === \"function\" ? waitForMetadata : undefined;\n await options.obsidian.metadata.waitForMetadata(sandboxPath(path), predicate, waitOptions);\n }\n\n return document;\n },\n };\n}\n","import { mkdir, readFile, rm, stat, writeFile } from \"node:fs/promises\";\nimport os from \"node:os\";\nimport path from \"node:path\";\nimport { createHash, randomUUID } from \"node:crypto\";\n\nimport type { ObsidianClient } from \"../core/types\";\nimport type { SharedVaultLockOptions } from \"./types\";\n\nconst DEFAULT_HEARTBEAT_MS = 2_000;\nconst DEFAULT_STALE_MS = 15_000;\nconst DEFAULT_TIMEOUT_MS = 60_000;\nconst DEFAULT_WAIT_INTERVAL_MS = 500;\nconst DEFAULT_LOCK_ROOT = path.join(os.tmpdir(), \"obsidian-e2e-locks\");\nconst LOCK_METADATA_FILE = \"lock.json\";\nconst APP_LOCK_KEY = \"__obsidianE2ELock\";\nconst heldLocks = new Map<string, HeldVaultRunLock>();\n\nexport interface VaultRunLockMetadata {\n acquiredAt: number;\n cwd: string;\n heartbeatAt: number;\n hostname: string;\n ownerId: string;\n pid: number;\n staleMs: number;\n vaultName: string;\n vaultPath: string;\n}\n\nexport interface VaultRunLock {\n readonly lockDir: string;\n readonly metadata: VaultRunLockMetadata;\n\n publishMarker(obsidian: ObsidianClient): Promise<void>;\n release(): Promise<void>;\n}\n\nexport interface VaultRunLockState {\n heartbeatAgeMs: number;\n isStale: boolean;\n lockDir: string;\n metadata: VaultRunLockMetadata;\n}\n\nexport interface AcquireVaultRunLockOptions extends SharedVaultLockOptions {\n vaultName: string;\n vaultPath: string;\n}\n\ninterface HeldVaultRunLock {\n heartbeat: NodeJS.Timeout;\n lockDir: string;\n metadata: VaultRunLockMetadata;\n metadataPath: string;\n refs: number;\n}\n\nexport async function acquireVaultRunLock({\n heartbeatMs = DEFAULT_HEARTBEAT_MS,\n lockRoot = DEFAULT_LOCK_ROOT,\n onBusy = \"wait\",\n staleMs = DEFAULT_STALE_MS,\n timeoutMs = DEFAULT_TIMEOUT_MS,\n vaultName,\n vaultPath,\n}: AcquireVaultRunLockOptions): Promise<VaultRunLock> {\n const lockDir = path.join(lockRoot, createVaultLockKey(vaultPath));\n const heldLock = heldLocks.get(lockDir);\n\n if (heldLock) {\n heldLock.refs += 1;\n return createVaultRunLockHandle(heldLock);\n }\n\n const ownerId = randomUUID();\n const metadataPath = path.join(lockDir, LOCK_METADATA_FILE);\n const metadata: VaultRunLockMetadata = {\n acquiredAt: Date.now(),\n cwd: process.cwd(),\n heartbeatAt: Date.now(),\n hostname: os.hostname(),\n ownerId,\n pid: process.pid,\n staleMs,\n vaultName,\n vaultPath,\n };\n\n await mkdir(lockRoot, { recursive: true });\n\n const startedAt = Date.now();\n\n while (true) {\n try {\n await mkdir(lockDir);\n await writeMetadata(metadataPath, metadata);\n break;\n } catch (error) {\n if (!isAlreadyExistsError(error)) {\n throw error;\n }\n\n const currentLock = await inspectVaultRunLock({\n lockRoot,\n staleMs,\n vaultPath,\n });\n\n if (currentLock && !currentLock.isStale) {\n if (onBusy === \"fail\") {\n throw new Error(formatBusyLockMessage(vaultPath, currentLock));\n }\n } else {\n await rm(lockDir, { force: true, recursive: true });\n continue;\n }\n\n if (Date.now() - startedAt >= timeoutMs) {\n throw new Error(\n currentLock\n ? `Timed out waiting for shared vault lock: ${formatBusyLockMessage(vaultPath, currentLock)}`\n : `Timed out waiting for shared vault lock on ${vaultPath}`,\n );\n }\n\n await sleep(Math.min(DEFAULT_WAIT_INTERVAL_MS, heartbeatMs));\n }\n }\n\n const heartbeat = setInterval(() => {\n metadata.heartbeatAt = Date.now();\n void writeMetadata(metadataPath, metadata).catch(() => {});\n }, heartbeatMs);\n heartbeat.unref();\n\n const nextHeldLock: HeldVaultRunLock = {\n heartbeat,\n lockDir,\n metadata,\n metadataPath,\n refs: 1,\n };\n\n heldLocks.set(lockDir, nextHeldLock);\n return createVaultRunLockHandle(nextHeldLock);\n}\n\nexport async function clearVaultRunLockMarker(obsidian: ObsidianClient): Promise<void> {\n await obsidian.dev.eval(`delete window.${APP_LOCK_KEY}; delete app.${APP_LOCK_KEY}; \"cleared\"`, {\n allowNonZeroExit: true,\n });\n}\n\nexport async function inspectVaultRunLock({\n lockRoot = DEFAULT_LOCK_ROOT,\n staleMs = DEFAULT_STALE_MS,\n vaultPath,\n}: Pick<\n AcquireVaultRunLockOptions,\n \"lockRoot\" | \"staleMs\" | \"vaultPath\"\n>): Promise<VaultRunLockState | null> {\n const lockDir = path.join(lockRoot, createVaultLockKey(vaultPath));\n const metadata = await readLockState(lockDir);\n\n if (!metadata) {\n return null;\n }\n\n return {\n heartbeatAgeMs: Date.now() - metadata.heartbeatAt,\n isStale: isLockStale(metadata, staleMs),\n lockDir,\n metadata,\n };\n}\n\nexport async function readVaultRunLockMarker(\n obsidian: ObsidianClient,\n): Promise<VaultRunLockMetadata | null> {\n return obsidian.dev.eval<VaultRunLockMetadata | null>(\n `window.${APP_LOCK_KEY} ?? app.${APP_LOCK_KEY} ?? null`,\n { allowNonZeroExit: true },\n );\n}\n\nfunction createVaultLockKey(vaultPath: string): string {\n return createHash(\"sha256\").update(path.resolve(vaultPath)).digest(\"hex\");\n}\n\nfunction buildSetMarkerCode(metadata: VaultRunLockMetadata): string {\n const encodedMetadata = JSON.stringify(metadata);\n return `(() => {\n const lock = ${encodedMetadata};\n window.${APP_LOCK_KEY} = lock;\n app.${APP_LOCK_KEY} = lock;\n return lock;\n })()`;\n}\n\nfunction createVaultRunLockHandle(heldLock: HeldVaultRunLock): VaultRunLock {\n return {\n get lockDir() {\n return heldLock.lockDir;\n },\n get metadata() {\n return heldLock.metadata;\n },\n async publishMarker(obsidian: ObsidianClient) {\n await obsidian.dev.eval(buildSetMarkerCode(heldLock.metadata));\n },\n async release() {\n if (heldLock.refs > 1) {\n heldLock.refs -= 1;\n return;\n }\n\n heldLocks.delete(heldLock.lockDir);\n clearInterval(heldLock.heartbeat);\n\n const currentLock = await readLockState(heldLock.lockDir);\n\n if (currentLock?.ownerId !== heldLock.metadata.ownerId) {\n return;\n }\n\n await rm(heldLock.lockDir, { force: true, recursive: true });\n },\n };\n}\n\nasync function readLockState(lockDir: string): Promise<VaultRunLockMetadata | null> {\n const metadataPath = path.join(lockDir, LOCK_METADATA_FILE);\n\n try {\n return JSON.parse(await readFile(metadataPath, \"utf8\")) as VaultRunLockMetadata;\n } catch {\n try {\n const directoryStat = await stat(lockDir);\n return {\n acquiredAt: directoryStat.mtimeMs,\n cwd: \"\",\n heartbeatAt: directoryStat.mtimeMs,\n hostname: \"\",\n ownerId: \"\",\n pid: 0,\n staleMs: DEFAULT_STALE_MS,\n vaultName: \"\",\n vaultPath: \"\",\n };\n } catch {\n return null;\n }\n }\n}\n\nfunction formatBusyLockMessage(vaultPath: string, state: VaultRunLockState): string {\n const ownerDetails = state.metadata.ownerId\n ? `owner=${state.metadata.ownerId} pid=${state.metadata.pid} cwd=${state.metadata.cwd || \"<unknown>\"}`\n : \"owner=<unknown>\";\n const ageDetails = `heartbeatAgeMs=${state.heartbeatAgeMs} stale=${state.isStale}`;\n\n return `vault ${vaultPath} is locked by ${ownerDetails} ${ageDetails}`;\n}\n\nfunction isAlreadyExistsError(error: unknown): boolean {\n return error instanceof Error && \"code\" in error && error.code === \"EEXIST\";\n}\n\nfunction isLockStale(metadata: VaultRunLockMetadata, staleMs: number): boolean {\n return Date.now() - metadata.heartbeatAt > staleMs;\n}\n\nasync function sleep(durationMs: number): Promise<void> {\n await new Promise((resolve) => setTimeout(resolve, durationMs));\n}\n\nasync function writeMetadata(metadataPath: string, metadata: VaultRunLockMetadata): Promise<void> {\n await writeFile(metadataPath, `${JSON.stringify(metadata, null, 2)}\\n`, \"utf8\");\n}\n","import type { TestContext } from \"vite-plus/test\";\n\nimport { createObsidianClient } from \"../core/client\";\nimport type { ObsidianClient, VaultApi } from \"../core/types\";\nimport { createVaultApi } from \"../vault/vault\";\nimport { createInternalTestContext } from \"./test-context\";\nimport type { CreateObsidianTestOptions, TestContext as ObsidianTestContext } from \"./types\";\nimport { acquireVaultRunLock, clearVaultRunLockMarker, type VaultRunLock } from \"./vault-lock\";\n\nexport const DEFAULT_SANDBOX_ROOT = \"__obsidian_e2e__\";\n\nexport interface BaseFixtureState {\n _testContext: ObsidianTestContext;\n _vaultLock: VaultRunLock | null;\n}\n\ninterface BaseFixtureOptions {\n createVault?: (obsidian: ObsidianClient) => Promise<VaultApi> | VaultApi;\n}\n\nexport function createBaseFixtures(\n options: CreateObsidianTestOptions,\n fixtureOptions: BaseFixtureOptions = {},\n) {\n const createVault =\n fixtureOptions.createVault ?? ((obsidian: ObsidianClient) => createVaultApi({ obsidian }));\n\n return {\n _vaultLock: [\n // eslint-disable-next-line no-empty-pattern\n async ({}, use: (vaultLock: VaultRunLock | null) => Promise<void>) => {\n if (!options.sharedVaultLock) {\n await use(null);\n return;\n }\n\n const lockClient = createObsidianClient(options);\n await lockClient.verify();\n\n const lockOptions = options.sharedVaultLock === true ? {} : options.sharedVaultLock;\n const vaultLock = await acquireVaultRunLock({\n ...lockOptions,\n vaultName: options.vault,\n vaultPath: await lockClient.vaultPath(),\n });\n\n await vaultLock.publishMarker(lockClient);\n try {\n await use(vaultLock);\n } finally {\n try {\n await clearVaultRunLockMarker(lockClient);\n } catch {}\n\n await vaultLock.release();\n }\n },\n { scope: \"worker\" },\n ],\n _testContext: async (\n {\n _vaultLock,\n onTestFailed,\n task,\n }: Pick<BaseFixtureState & TestContext, \"_vaultLock\" | \"onTestFailed\" | \"task\">,\n use: (context: ObsidianTestContext) => Promise<void>,\n ) => {\n let failedTask = false;\n onTestFailed(() => {\n failedTask = true;\n });\n\n const context = await createInternalTestContext({\n ...options,\n createVault,\n testName: task.name,\n vaultLock: _vaultLock,\n });\n\n try {\n await use(context);\n } finally {\n await context.cleanup({\n failedTask: failedTask ? task : undefined,\n });\n }\n },\n // oxlint-disable-next-line no-empty-pattern\n obsidian: async (\n { _testContext }: Pick<BaseFixtureState, \"_testContext\">,\n use: (obsidian: ObsidianClient) => Promise<void>,\n ) => {\n await use(_testContext.obsidian);\n },\n sandbox: async (\n { _testContext }: Pick<BaseFixtureState, \"_testContext\">,\n use: (sandbox: ObsidianTestContext[\"sandbox\"]) => Promise<void>,\n ) => {\n await use(_testContext.sandbox);\n },\n vault: async (\n { _testContext }: Pick<BaseFixtureState, \"_testContext\">,\n use: (vault: VaultApi) => Promise<void>,\n ) => {\n await use(_testContext.vault);\n },\n };\n}\n","import { createObsidianClient } from \"../core/client\";\nimport { getClientInternals } from \"../core/internals\";\nimport type { FailureArtifactTask } from \"../artifacts/failure-artifacts\";\nimport { captureFailureArtifacts } from \"../artifacts/failure-artifacts\";\nimport type { ObsidianClient, PluginHandle, VaultApi } from \"../core/types\";\nimport { createSandboxApi } from \"../vault/sandbox\";\nimport { createVaultApi } from \"../vault/vault\";\nimport { DEFAULT_SANDBOX_ROOT } from \"./base-fixtures\";\nimport { acquireVaultRunLock, clearVaultRunLockMarker, type VaultRunLock } from \"./vault-lock\";\nimport type { CreateObsidianTestOptions, PluginSessionOptions, TestContext } from \"./types\";\n\ninterface CreateInternalTestContextOptions extends CreateObsidianTestOptions {\n createVault?: (obsidian: ObsidianClient) => Promise<VaultApi> | VaultApi;\n testName?: string;\n vaultLock?: VaultRunLock | null;\n}\n\ninterface TrackedPluginSession {\n filter?: PluginSessionOptions[\"filter\"];\n plugin: PluginHandle;\n wasEnabled: boolean;\n}\n\nexport async function createTestContext(\n options: CreateObsidianTestOptions & { testName?: string },\n): Promise<TestContext> {\n return createInternalTestContext(options);\n}\n\nexport async function withVaultSandbox<TResult>(\n options: CreateObsidianTestOptions & { testName?: string },\n run: (context: TestContext) => Promise<TResult> | TResult,\n): Promise<TResult> {\n const context = await createInternalTestContext(options);\n\n try {\n return await run(context);\n } finally {\n await context.cleanup();\n }\n}\n\nexport async function createInternalTestContext(\n options: CreateInternalTestContextOptions,\n): Promise<TestContext> {\n const obsidian = createObsidianClient(options);\n const trackedPlugins = new Map<string, TrackedPluginSession>();\n let sandbox: Awaited<ReturnType<typeof createSandboxApi>> | null = null;\n const vaultLock = options.vaultLock ?? (await maybeAcquireVaultLock(options, obsidian));\n const ownsVaultLock = options.vaultLock === undefined && vaultLock !== null;\n const vaultFactory =\n options.createVault ?? ((client: ObsidianClient) => createVaultApi({ obsidian: client }));\n let disposed = false;\n\n try {\n await obsidian.verify();\n\n if (vaultLock) {\n await vaultLock.publishMarker(obsidian);\n }\n\n await obsidian.dev.resetDiagnostics().catch(() => {});\n\n const vault = await vaultFactory(obsidian);\n sandbox = await createSandboxApi({\n obsidian,\n sandboxRoot: options.sandboxRoot ?? DEFAULT_SANDBOX_ROOT,\n testName: options.testName ?? \"test\",\n });\n\n const captureArtifacts = async (task: FailureArtifactTask) =>\n captureFailureArtifacts(task, obsidian, {\n ...options,\n plugin: trackedPlugins.size === 1 ? [...trackedPlugins.values()][0]!.plugin : undefined,\n });\n\n const cleanup: TestContext[\"cleanup\"] = async (cleanupOptions = {}) => {\n if (disposed) {\n return;\n }\n\n disposed = true;\n const cleanupErrors: unknown[] = [];\n\n try {\n if (cleanupOptions.failedTask && options.captureOnFailure) {\n await captureArtifacts(cleanupOptions.failedTask);\n }\n } finally {\n try {\n await getClientInternals(obsidian).restoreAll();\n } finally {\n for (const session of [...trackedPlugins.values()].reverse()) {\n if (!session.wasEnabled) {\n await recordCleanupError(cleanupErrors, async () =>\n session.plugin.disable({ filter: session.filter }),\n );\n }\n }\n\n try {\n await clearVaultRunLockMarker(obsidian);\n } catch {}\n\n if (ownsVaultLock) {\n await recordCleanupError(cleanupErrors, async () => vaultLock.release());\n }\n\n await recordCleanupError(cleanupErrors, async () => sandbox!.cleanup());\n }\n }\n\n if (cleanupErrors.length === 1) {\n throw cleanupErrors[0];\n }\n\n if (cleanupErrors.length > 1) {\n throw new AggregateError(cleanupErrors, \"One or more test cleanup steps failed.\");\n }\n };\n\n return {\n obsidian,\n sandbox: sandbox!,\n vault,\n captureFailureArtifacts: captureArtifacts,\n cleanup,\n async plugin(id: string, sessionOptions: PluginSessionOptions = {}) {\n const existing = trackedPlugins.get(id);\n\n if (existing) {\n return existing.plugin;\n }\n\n const plugin = obsidian.plugin(id);\n const wasEnabled = await plugin.isEnabled();\n\n if (!wasEnabled) {\n await plugin.enable({ filter: sessionOptions.filter });\n }\n\n if (sessionOptions.seedData !== undefined) {\n await plugin.data().write(sessionOptions.seedData);\n }\n\n trackedPlugins.set(id, {\n filter: sessionOptions.filter,\n plugin,\n wasEnabled,\n });\n\n return plugin;\n },\n async resetDiagnostics() {\n await obsidian.dev.resetDiagnostics().catch(() => {});\n },\n };\n } catch (error) {\n try {\n if (sandbox) {\n await sandbox.cleanup();\n }\n } finally {\n try {\n await clearVaultRunLockMarker(obsidian);\n } catch {}\n\n if (ownsVaultLock) {\n await vaultLock.release();\n }\n }\n\n throw error;\n }\n}\n\nasync function recordCleanupError(\n cleanupErrors: unknown[],\n run: () => Promise<void>,\n): Promise<void> {\n try {\n await run();\n } catch (error) {\n cleanupErrors.push(error);\n }\n}\n\nasync function maybeAcquireVaultLock(\n options: CreateObsidianTestOptions,\n obsidian: ObsidianClient,\n): Promise<VaultRunLock | null> {\n if (!options.sharedVaultLock) {\n return null;\n }\n\n const lockOptions = options.sharedVaultLock === true ? {} : options.sharedVaultLock;\n\n return acquireVaultRunLock({\n ...lockOptions,\n vaultName: options.vault,\n vaultPath: await obsidian.vaultPath(),\n });\n}\n"],"mappings":"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"}
|
|
@@ -1,7 +1,50 @@
|
|
|
1
|
-
import { TestAPI } from "vite-plus/test";
|
|
2
|
-
|
|
3
1
|
//#region src/core/types.d.ts
|
|
4
2
|
type ObsidianArg = boolean | number | string | null | undefined;
|
|
3
|
+
type FrontmatterValue = boolean | number | string | null | FrontmatterValue[] | {
|
|
4
|
+
[key: string]: FrontmatterValue;
|
|
5
|
+
};
|
|
6
|
+
interface NoteFrontmatter {
|
|
7
|
+
[key: string]: FrontmatterValue;
|
|
8
|
+
}
|
|
9
|
+
interface NoteDocument<TFrontmatter extends NoteFrontmatter | null = NoteFrontmatter | null> {
|
|
10
|
+
body: string;
|
|
11
|
+
frontmatter: TFrontmatter;
|
|
12
|
+
raw: string;
|
|
13
|
+
}
|
|
14
|
+
interface NoteInput<TFrontmatter extends NoteFrontmatter | null = NoteFrontmatter | null> {
|
|
15
|
+
body?: string;
|
|
16
|
+
frontmatter?: TFrontmatter;
|
|
17
|
+
}
|
|
18
|
+
interface NoteMatcherOptions<TFrontmatter extends NoteFrontmatter | null = NoteFrontmatter | null> {
|
|
19
|
+
body?: string;
|
|
20
|
+
bodyIncludes?: string;
|
|
21
|
+
frontmatter?: TFrontmatter;
|
|
22
|
+
}
|
|
23
|
+
interface MetadataFileCache<TFrontmatter extends NoteFrontmatter | null = NoteFrontmatter | null> extends Record<string, unknown> {
|
|
24
|
+
frontmatter?: TFrontmatter;
|
|
25
|
+
}
|
|
26
|
+
interface DevConsoleMessage {
|
|
27
|
+
args: unknown[];
|
|
28
|
+
at: number;
|
|
29
|
+
level: string;
|
|
30
|
+
text: string;
|
|
31
|
+
}
|
|
32
|
+
interface DevRuntimeError {
|
|
33
|
+
at: number;
|
|
34
|
+
message: string;
|
|
35
|
+
source: "error" | "unhandledrejection";
|
|
36
|
+
stack?: string;
|
|
37
|
+
}
|
|
38
|
+
interface DevNoticeEvent {
|
|
39
|
+
at: number;
|
|
40
|
+
message: string;
|
|
41
|
+
timeout?: number;
|
|
42
|
+
}
|
|
43
|
+
interface DevDiagnostics {
|
|
44
|
+
consoleMessages: DevConsoleMessage[];
|
|
45
|
+
notices: DevNoticeEvent[];
|
|
46
|
+
runtimeErrors: DevRuntimeError[];
|
|
47
|
+
}
|
|
5
48
|
interface ExecOptions {
|
|
6
49
|
allowNonZeroExit?: boolean;
|
|
7
50
|
cwd?: string;
|
|
@@ -14,6 +57,13 @@ interface VaultWriteOptions {
|
|
|
14
57
|
waitForContent?: boolean | VaultContentPredicate;
|
|
15
58
|
waitOptions?: VaultWaitForContentOptions;
|
|
16
59
|
}
|
|
60
|
+
type MetadataPredicate<T = MetadataFileCache> = (metadata: T) => boolean | Promise<boolean>;
|
|
61
|
+
type MetadataWaitOptions = WaitForOptions;
|
|
62
|
+
interface SandboxWriteNoteOptions<TFrontmatter extends NoteFrontmatter | null = NoteFrontmatter | null> extends NoteInput<TFrontmatter> {
|
|
63
|
+
path: string;
|
|
64
|
+
waitForMetadata?: boolean | MetadataPredicate<MetadataFileCache<Extract<TFrontmatter, NoteFrontmatter> | null>>;
|
|
65
|
+
waitOptions?: MetadataWaitOptions;
|
|
66
|
+
}
|
|
17
67
|
type PluginDataPredicate<T = unknown> = (data: T) => boolean | Promise<boolean>;
|
|
18
68
|
type PluginWaitForDataOptions = WaitForOptions;
|
|
19
69
|
interface PluginWaitUntilReadyOptions extends WaitForOptions {
|
|
@@ -23,6 +73,11 @@ interface PluginReloadOptions extends ExecOptions {
|
|
|
23
73
|
readyOptions?: PluginWaitUntilReadyOptions;
|
|
24
74
|
waitUntilReady?: boolean;
|
|
25
75
|
}
|
|
76
|
+
interface PluginPatchDataOptions<T> extends PluginReloadOptions {
|
|
77
|
+
patch?: JsonFileUpdater<T>;
|
|
78
|
+
}
|
|
79
|
+
type PluginUpdateDataOptions<T> = PluginPatchDataOptions<T>;
|
|
80
|
+
type PluginWithPatchedDataOptions<T> = PluginPatchDataOptions<T>;
|
|
26
81
|
interface ExecResult {
|
|
27
82
|
argv: string[];
|
|
28
83
|
command: string;
|
|
@@ -81,6 +136,8 @@ interface PluginHandle {
|
|
|
81
136
|
isEnabled(): Promise<boolean>;
|
|
82
137
|
reload(options?: PluginReloadOptions): Promise<void>;
|
|
83
138
|
restoreData(): Promise<void>;
|
|
139
|
+
updateDataAndReload<T = unknown>(updater: JsonFileUpdater<T>, options?: PluginUpdateDataOptions<T>): Promise<T>;
|
|
140
|
+
withPatchedData<T = unknown, TResult = void>(updater: JsonFileUpdater<T>, run: (plugin: PluginHandle) => Promise<TResult> | TResult, options?: PluginWithPatchedDataOptions<T>): Promise<TResult>;
|
|
84
141
|
waitForData<T = unknown>(predicate: PluginDataPredicate<T>, options?: PluginWaitForDataOptions): Promise<T>;
|
|
85
142
|
waitUntilReady(options?: PluginWaitUntilReadyOptions): Promise<void>;
|
|
86
143
|
}
|
|
@@ -96,10 +153,26 @@ interface ObsidianCommandHandle {
|
|
|
96
153
|
run(options?: ExecOptions): Promise<void>;
|
|
97
154
|
}
|
|
98
155
|
interface ObsidianDevHandle {
|
|
156
|
+
activeFilePath(execOptions?: ExecOptions): Promise<string | null>;
|
|
157
|
+
consoleMessages(execOptions?: ExecOptions): Promise<DevConsoleMessage[]>;
|
|
158
|
+
diagnostics(execOptions?: ExecOptions): Promise<DevDiagnostics>;
|
|
99
159
|
dom(options: DevDomQueryOptions, execOptions?: ExecOptions): Promise<DevDomResult>;
|
|
160
|
+
editorText(execOptions?: ExecOptions): Promise<string | null>;
|
|
100
161
|
eval<T = unknown>(code: string, options?: ExecOptions): Promise<T>;
|
|
162
|
+
evalJson<T = unknown>(code: string, options?: ExecOptions): Promise<T>;
|
|
163
|
+
evalRaw(code: string, options?: ExecOptions): Promise<string>;
|
|
164
|
+
notices(execOptions?: ExecOptions): Promise<DevNoticeEvent[]>;
|
|
165
|
+
resetDiagnostics(execOptions?: ExecOptions): Promise<void>;
|
|
166
|
+
runtimeErrors(execOptions?: ExecOptions): Promise<DevRuntimeError[]>;
|
|
101
167
|
screenshot(path: string, options?: ExecOptions): Promise<string>;
|
|
102
168
|
}
|
|
169
|
+
interface ObsidianMetadataHandle {
|
|
170
|
+
fileCache<T = MetadataFileCache>(path: string, execOptions?: ExecOptions): Promise<T | null>;
|
|
171
|
+
frontmatter<T extends NoteFrontmatter = NoteFrontmatter>(path: string, execOptions?: ExecOptions): Promise<T | null>;
|
|
172
|
+
waitForFileCache<T = MetadataFileCache>(path: string, predicate?: MetadataPredicate<T>, options?: MetadataWaitOptions): Promise<T>;
|
|
173
|
+
waitForFrontmatter<T extends NoteFrontmatter = NoteFrontmatter>(path: string, predicate?: MetadataPredicate<T>, options?: MetadataWaitOptions): Promise<T>;
|
|
174
|
+
waitForMetadata<T = MetadataFileCache>(path: string, predicate?: MetadataPredicate<T>, options?: MetadataWaitOptions): Promise<T>;
|
|
175
|
+
}
|
|
103
176
|
type DevDomResult = number | string | string[];
|
|
104
177
|
interface DevDomQueryOptions {
|
|
105
178
|
all?: boolean;
|
|
@@ -126,6 +199,7 @@ interface ObsidianClient {
|
|
|
126
199
|
readonly app: ObsidianAppHandle;
|
|
127
200
|
readonly bin: string;
|
|
128
201
|
readonly dev: ObsidianDevHandle;
|
|
202
|
+
readonly metadata: ObsidianMetadataHandle;
|
|
129
203
|
readonly vaultName: string;
|
|
130
204
|
command(id: string): ObsidianCommandHandle;
|
|
131
205
|
commands(options?: CommandListOptions, execOptions?: ExecOptions): Promise<string[]>;
|
|
@@ -139,6 +213,10 @@ interface ObsidianClient {
|
|
|
139
213
|
tabs(options?: TabsOptions, execOptions?: ExecOptions): Promise<WorkspaceTab[]>;
|
|
140
214
|
vaultPath(): Promise<string>;
|
|
141
215
|
verify(): Promise<void>;
|
|
216
|
+
waitForActiveFile(path: string, options?: WaitForOptions): Promise<string>;
|
|
217
|
+
waitForConsoleMessage(predicate: (message: DevConsoleMessage) => boolean | Promise<boolean>, options?: WaitForOptions): Promise<DevConsoleMessage>;
|
|
218
|
+
waitForNotice(predicate: string | ((notice: DevNoticeEvent) => boolean | Promise<boolean>), options?: WaitForOptions): Promise<DevNoticeEvent>;
|
|
219
|
+
waitForRuntimeError(predicate: string | ((error: DevRuntimeError) => boolean | Promise<boolean>), options?: WaitForOptions): Promise<DevRuntimeError>;
|
|
142
220
|
waitFor<T>(fn: () => Promise<T | false | null | undefined> | T | false | null | undefined, options?: WaitForOptions): Promise<T>;
|
|
143
221
|
workspace(options?: WorkspaceOptions, execOptions?: ExecOptions): Promise<WorkspaceNode[]>;
|
|
144
222
|
}
|
|
@@ -168,115 +246,9 @@ interface SandboxApi extends VaultApi {
|
|
|
168
246
|
readonly root: string;
|
|
169
247
|
cleanup(): Promise<void>;
|
|
170
248
|
path(...segments: string[]): string;
|
|
249
|
+
readNote<TFrontmatter extends NoteFrontmatter | null = NoteFrontmatter | null>(path: string): Promise<NoteDocument<TFrontmatter>>;
|
|
250
|
+
writeNote<TFrontmatter extends NoteFrontmatter | null = NoteFrontmatter | null>(options: SandboxWriteNoteOptions<TFrontmatter>): Promise<NoteDocument<TFrontmatter>>;
|
|
171
251
|
}
|
|
172
252
|
//#endregion
|
|
173
|
-
|
|
174
|
-
|
|
175
|
-
interface FailureArtifactOptions {
|
|
176
|
-
activeFile?: boolean;
|
|
177
|
-
dom?: boolean;
|
|
178
|
-
editorText?: boolean;
|
|
179
|
-
screenshot?: boolean;
|
|
180
|
-
tabs?: boolean;
|
|
181
|
-
workspace?: boolean;
|
|
182
|
-
}
|
|
183
|
-
interface FailureArtifactTask {
|
|
184
|
-
id: string;
|
|
185
|
-
name: string;
|
|
186
|
-
}
|
|
187
|
-
interface FailureArtifactConfig {
|
|
188
|
-
artifactsDir: string;
|
|
189
|
-
capture: Required<FailureArtifactOptions>;
|
|
190
|
-
enabled: boolean;
|
|
191
|
-
}
|
|
192
|
-
interface FailureArtifactRegistrationOptions {
|
|
193
|
-
artifactsDir?: string;
|
|
194
|
-
captureOnFailure?: boolean | FailureArtifactOptions;
|
|
195
|
-
}
|
|
196
|
-
interface CaptureFailureArtifactsOptions extends FailureArtifactRegistrationOptions {
|
|
197
|
-
plugin?: PluginHandle;
|
|
198
|
-
}
|
|
199
|
-
declare function captureFailureArtifacts(task: FailureArtifactTask, obsidian: ObsidianClient, options: CaptureFailureArtifactsOptions): Promise<string | undefined>;
|
|
200
|
-
//#endregion
|
|
201
|
-
//#region src/fixtures/types.d.ts
|
|
202
|
-
interface SharedVaultLockOptions {
|
|
203
|
-
heartbeatMs?: number;
|
|
204
|
-
lockRoot?: string;
|
|
205
|
-
onBusy?: "fail" | "wait";
|
|
206
|
-
staleMs?: number;
|
|
207
|
-
timeoutMs?: number;
|
|
208
|
-
}
|
|
209
|
-
interface CreateObsidianTestOptions extends CreateObsidianClientOptions {
|
|
210
|
-
artifactsDir?: string;
|
|
211
|
-
captureOnFailure?: boolean | FailureArtifactOptions;
|
|
212
|
-
sharedVaultLock?: boolean | SharedVaultLockOptions;
|
|
213
|
-
sandboxRoot?: string;
|
|
214
|
-
}
|
|
215
|
-
type VaultSeedEntry = string | {
|
|
216
|
-
json: unknown;
|
|
217
|
-
};
|
|
218
|
-
type VaultSeed = Record<string, VaultSeedEntry>;
|
|
219
|
-
interface CreatePluginTestOptions extends CreateObsidianTestOptions {
|
|
220
|
-
pluginFilter?: PluginToggleOptions["filter"];
|
|
221
|
-
pluginId: string;
|
|
222
|
-
seedPluginData?: unknown;
|
|
223
|
-
seedVault?: VaultSeed;
|
|
224
|
-
}
|
|
225
|
-
interface ObsidianFixtures {
|
|
226
|
-
obsidian: ObsidianClient;
|
|
227
|
-
sandbox: SandboxApi;
|
|
228
|
-
vault: VaultApi;
|
|
229
|
-
}
|
|
230
|
-
interface PluginFixtures extends ObsidianFixtures {
|
|
231
|
-
plugin: PluginHandle;
|
|
232
|
-
}
|
|
233
|
-
type ObsidianTest = TestAPI<ObsidianFixtures>;
|
|
234
|
-
type PluginTest = TestAPI<PluginFixtures>;
|
|
235
|
-
//#endregion
|
|
236
|
-
//#region src/fixtures/vault-lock.d.ts
|
|
237
|
-
interface VaultRunLockMetadata {
|
|
238
|
-
acquiredAt: number;
|
|
239
|
-
cwd: string;
|
|
240
|
-
heartbeatAt: number;
|
|
241
|
-
hostname: string;
|
|
242
|
-
ownerId: string;
|
|
243
|
-
pid: number;
|
|
244
|
-
staleMs: number;
|
|
245
|
-
vaultName: string;
|
|
246
|
-
vaultPath: string;
|
|
247
|
-
}
|
|
248
|
-
interface VaultRunLock {
|
|
249
|
-
readonly lockDir: string;
|
|
250
|
-
readonly metadata: VaultRunLockMetadata;
|
|
251
|
-
publishMarker(obsidian: ObsidianClient): Promise<void>;
|
|
252
|
-
release(): Promise<void>;
|
|
253
|
-
}
|
|
254
|
-
interface VaultRunLockState {
|
|
255
|
-
heartbeatAgeMs: number;
|
|
256
|
-
isStale: boolean;
|
|
257
|
-
lockDir: string;
|
|
258
|
-
metadata: VaultRunLockMetadata;
|
|
259
|
-
}
|
|
260
|
-
interface AcquireVaultRunLockOptions extends SharedVaultLockOptions {
|
|
261
|
-
vaultName: string;
|
|
262
|
-
vaultPath: string;
|
|
263
|
-
}
|
|
264
|
-
declare function acquireVaultRunLock({
|
|
265
|
-
heartbeatMs,
|
|
266
|
-
lockRoot,
|
|
267
|
-
onBusy,
|
|
268
|
-
staleMs,
|
|
269
|
-
timeoutMs,
|
|
270
|
-
vaultName,
|
|
271
|
-
vaultPath
|
|
272
|
-
}: AcquireVaultRunLockOptions): Promise<VaultRunLock>;
|
|
273
|
-
declare function clearVaultRunLockMarker(obsidian: ObsidianClient): Promise<void>;
|
|
274
|
-
declare function inspectVaultRunLock({
|
|
275
|
-
lockRoot,
|
|
276
|
-
staleMs,
|
|
277
|
-
vaultPath
|
|
278
|
-
}: Pick<AcquireVaultRunLockOptions, "lockRoot" | "staleMs" | "vaultPath">): Promise<VaultRunLockState | null>;
|
|
279
|
-
declare function readVaultRunLockMarker(obsidian: ObsidianClient): Promise<VaultRunLockMetadata | null>;
|
|
280
|
-
//#endregion
|
|
281
|
-
export { WaitForOptions as $, ExecOptions as A, OpenTabOptions as B, FailureArtifactTask as C, CreateObsidianClientOptions as D, CommandTransport as E, ObsidianArg as F, PluginWaitUntilReadyOptions as G, PluginHandle as H, ObsidianClient as I, TabsOptions as J, RestartAppOptions as K, ObsidianCommandHandle as L, JsonFile as M, JsonFileUpdater as N, DevDomQueryOptions as O, ObsidianAppHandle as P, VaultWriteOptions as Q, ObsidianDevHandle as R, FailureArtifactRegistrationOptions as S, CommandListOptions as T, PluginReloadOptions as U, PluginDataPredicate as V, PluginWaitForDataOptions as W, VaultContentPredicate as X, VaultApi as Y, VaultWaitForContentOptions as Z, VaultSeedEntry as _, acquireVaultRunLock as a, FailureArtifactConfig as b, readVaultRunLockMarker as c, ObsidianFixtures as d, WorkspaceNode as et, ObsidianTest as f, VaultSeed as g, SharedVaultLockOptions as h, VaultRunLockState as i, ExecResult as j, DevDomResult as k, CreateObsidianTestOptions as l, PluginTest as m, VaultRunLock as n, WorkspaceTab as nt, clearVaultRunLockMarker as o, PluginFixtures as p, SandboxApi as q, VaultRunLockMetadata as r, inspectVaultRunLock as s, AcquireVaultRunLockOptions as t, WorkspaceOptions as tt, CreatePluginTestOptions as u, CaptureFailureArtifactsOptions as v, captureFailureArtifacts as w, FailureArtifactOptions as x, DEFAULT_FAILURE_ARTIFACTS_DIR as y, OpenFileOptions as z };
|
|
282
|
-
//# sourceMappingURL=vault-lock-LmqAsLDT.d.mts.map
|
|
253
|
+
export { PluginHandle as A, VaultApi as B, ObsidianClient as C, OpenFileOptions as D, ObsidianMetadataHandle as E, PluginWaitUntilReadyOptions as F, WorkspaceNode as G, VaultWaitForContentOptions as H, PluginWithPatchedDataOptions as I, WorkspaceOptions as K, RestartAppOptions as L, PluginToggleOptions as M, PluginUpdateDataOptions as N, OpenTabOptions as O, PluginWaitForDataOptions as P, SandboxApi as R, ObsidianArg as S, ObsidianDevHandle as T, VaultWriteOptions as U, VaultContentPredicate as V, WaitForOptions as W, NoteDocument as _, DevDiagnostics as a, NoteMatcherOptions as b, DevNoticeEvent as c, ExecResult as d, JsonFile as f, MetadataWaitOptions as g, MetadataPredicate as h, DevConsoleMessage as i, PluginReloadOptions as j, PluginDataPredicate as k, DevRuntimeError as l, MetadataFileCache as m, CommandTransport as n, DevDomQueryOptions as o, JsonFileUpdater as p, WorkspaceTab as q, CreateObsidianClientOptions as r, DevDomResult as s, CommandListOptions as t, ExecOptions as u, NoteFrontmatter as v, ObsidianCommandHandle as w, ObsidianAppHandle as x, NoteInput as y, TabsOptions as z };
|
|
254
|
+
//# sourceMappingURL=types-BUXaueDI.d.mts.map
|
|
@@ -0,0 +1,136 @@
|
|
|
1
|
+
import { A as PluginHandle, B as VaultApi, C as ObsidianClient, M as PluginToggleOptions, R as SandboxApi, r as CreateObsidianClientOptions, y as NoteInput } from "./types-BUXaueDI.mjs";
|
|
2
|
+
import { TestAPI } from "vite-plus/test";
|
|
3
|
+
|
|
4
|
+
//#region src/artifacts/failure-artifacts.d.ts
|
|
5
|
+
declare const DEFAULT_FAILURE_ARTIFACTS_DIR = ".obsidian-e2e-artifacts";
|
|
6
|
+
interface FailureArtifactOptions {
|
|
7
|
+
activeFile?: boolean;
|
|
8
|
+
activeNote?: boolean;
|
|
9
|
+
consoleMessages?: boolean;
|
|
10
|
+
dom?: boolean;
|
|
11
|
+
editorText?: boolean;
|
|
12
|
+
notices?: boolean;
|
|
13
|
+
parsedFrontmatter?: boolean;
|
|
14
|
+
runtimeErrors?: boolean;
|
|
15
|
+
screenshot?: boolean;
|
|
16
|
+
tabs?: boolean;
|
|
17
|
+
workspace?: boolean;
|
|
18
|
+
}
|
|
19
|
+
interface FailureArtifactTask {
|
|
20
|
+
id: string;
|
|
21
|
+
name: string;
|
|
22
|
+
}
|
|
23
|
+
interface FailureArtifactConfig {
|
|
24
|
+
artifactsDir: string;
|
|
25
|
+
capture: Required<FailureArtifactOptions>;
|
|
26
|
+
enabled: boolean;
|
|
27
|
+
}
|
|
28
|
+
interface FailureArtifactRegistrationOptions {
|
|
29
|
+
artifactsDir?: string;
|
|
30
|
+
captureOnFailure?: boolean | FailureArtifactOptions;
|
|
31
|
+
}
|
|
32
|
+
interface CaptureFailureArtifactsOptions extends FailureArtifactRegistrationOptions {
|
|
33
|
+
plugin?: PluginHandle;
|
|
34
|
+
}
|
|
35
|
+
declare function captureFailureArtifacts(task: FailureArtifactTask, obsidian: ObsidianClient, options: CaptureFailureArtifactsOptions): Promise<string | undefined>;
|
|
36
|
+
//#endregion
|
|
37
|
+
//#region src/fixtures/types.d.ts
|
|
38
|
+
interface SharedVaultLockOptions {
|
|
39
|
+
heartbeatMs?: number;
|
|
40
|
+
lockRoot?: string;
|
|
41
|
+
onBusy?: "fail" | "wait";
|
|
42
|
+
staleMs?: number;
|
|
43
|
+
timeoutMs?: number;
|
|
44
|
+
}
|
|
45
|
+
interface CreateObsidianTestOptions extends CreateObsidianClientOptions {
|
|
46
|
+
artifactsDir?: string;
|
|
47
|
+
captureOnFailure?: boolean | FailureArtifactOptions;
|
|
48
|
+
sharedVaultLock?: boolean | SharedVaultLockOptions;
|
|
49
|
+
sandboxRoot?: string;
|
|
50
|
+
}
|
|
51
|
+
type VaultSeedEntry = string | {
|
|
52
|
+
json: unknown;
|
|
53
|
+
} | {
|
|
54
|
+
note: NoteInput;
|
|
55
|
+
};
|
|
56
|
+
type VaultSeed = Record<string, VaultSeedEntry>;
|
|
57
|
+
interface PluginSessionOptions {
|
|
58
|
+
filter?: PluginToggleOptions["filter"];
|
|
59
|
+
seedData?: unknown;
|
|
60
|
+
}
|
|
61
|
+
interface TestContextCleanupOptions {
|
|
62
|
+
failedTask?: FailureArtifactTask;
|
|
63
|
+
}
|
|
64
|
+
interface TestContext {
|
|
65
|
+
obsidian: ObsidianClient;
|
|
66
|
+
sandbox: SandboxApi;
|
|
67
|
+
vault: VaultApi;
|
|
68
|
+
captureFailureArtifacts(task: FailureArtifactTask): Promise<string | undefined>;
|
|
69
|
+
cleanup(options?: TestContextCleanupOptions): Promise<void>;
|
|
70
|
+
plugin(id: string, options?: PluginSessionOptions): Promise<PluginHandle>;
|
|
71
|
+
resetDiagnostics(): Promise<void>;
|
|
72
|
+
}
|
|
73
|
+
interface CreatePluginTestOptions extends CreateObsidianTestOptions {
|
|
74
|
+
pluginFilter?: PluginToggleOptions["filter"];
|
|
75
|
+
pluginId: string;
|
|
76
|
+
seedPluginData?: unknown;
|
|
77
|
+
seedVault?: VaultSeed;
|
|
78
|
+
}
|
|
79
|
+
interface ObsidianFixtures {
|
|
80
|
+
obsidian: ObsidianClient;
|
|
81
|
+
sandbox: SandboxApi;
|
|
82
|
+
vault: VaultApi;
|
|
83
|
+
}
|
|
84
|
+
interface PluginFixtures extends ObsidianFixtures {
|
|
85
|
+
plugin: PluginHandle;
|
|
86
|
+
}
|
|
87
|
+
type ObsidianTest = TestAPI<ObsidianFixtures>;
|
|
88
|
+
type PluginTest = TestAPI<PluginFixtures>;
|
|
89
|
+
//#endregion
|
|
90
|
+
//#region src/fixtures/vault-lock.d.ts
|
|
91
|
+
interface VaultRunLockMetadata {
|
|
92
|
+
acquiredAt: number;
|
|
93
|
+
cwd: string;
|
|
94
|
+
heartbeatAt: number;
|
|
95
|
+
hostname: string;
|
|
96
|
+
ownerId: string;
|
|
97
|
+
pid: number;
|
|
98
|
+
staleMs: number;
|
|
99
|
+
vaultName: string;
|
|
100
|
+
vaultPath: string;
|
|
101
|
+
}
|
|
102
|
+
interface VaultRunLock {
|
|
103
|
+
readonly lockDir: string;
|
|
104
|
+
readonly metadata: VaultRunLockMetadata;
|
|
105
|
+
publishMarker(obsidian: ObsidianClient): Promise<void>;
|
|
106
|
+
release(): Promise<void>;
|
|
107
|
+
}
|
|
108
|
+
interface VaultRunLockState {
|
|
109
|
+
heartbeatAgeMs: number;
|
|
110
|
+
isStale: boolean;
|
|
111
|
+
lockDir: string;
|
|
112
|
+
metadata: VaultRunLockMetadata;
|
|
113
|
+
}
|
|
114
|
+
interface AcquireVaultRunLockOptions extends SharedVaultLockOptions {
|
|
115
|
+
vaultName: string;
|
|
116
|
+
vaultPath: string;
|
|
117
|
+
}
|
|
118
|
+
declare function acquireVaultRunLock({
|
|
119
|
+
heartbeatMs,
|
|
120
|
+
lockRoot,
|
|
121
|
+
onBusy,
|
|
122
|
+
staleMs,
|
|
123
|
+
timeoutMs,
|
|
124
|
+
vaultName,
|
|
125
|
+
vaultPath
|
|
126
|
+
}: AcquireVaultRunLockOptions): Promise<VaultRunLock>;
|
|
127
|
+
declare function clearVaultRunLockMarker(obsidian: ObsidianClient): Promise<void>;
|
|
128
|
+
declare function inspectVaultRunLock({
|
|
129
|
+
lockRoot,
|
|
130
|
+
staleMs,
|
|
131
|
+
vaultPath
|
|
132
|
+
}: Pick<AcquireVaultRunLockOptions, "lockRoot" | "staleMs" | "vaultPath">): Promise<VaultRunLockState | null>;
|
|
133
|
+
declare function readVaultRunLockMarker(obsidian: ObsidianClient): Promise<VaultRunLockMetadata | null>;
|
|
134
|
+
//#endregion
|
|
135
|
+
export { FailureArtifactConfig as C, captureFailureArtifacts as D, FailureArtifactTask as E, DEFAULT_FAILURE_ARTIFACTS_DIR as S, FailureArtifactRegistrationOptions as T, TestContext as _, acquireVaultRunLock as a, VaultSeedEntry as b, readVaultRunLockMarker as c, ObsidianFixtures as d, ObsidianTest as f, SharedVaultLockOptions as g, PluginTest as h, VaultRunLockState as i, CreateObsidianTestOptions as l, PluginSessionOptions as m, VaultRunLock as n, clearVaultRunLockMarker as o, PluginFixtures as p, VaultRunLockMetadata as r, inspectVaultRunLock as s, AcquireVaultRunLockOptions as t, CreatePluginTestOptions as u, TestContextCleanupOptions as v, FailureArtifactOptions as w, CaptureFailureArtifactsOptions as x, VaultSeed as y };
|
|
136
|
+
//# sourceMappingURL=vault-lock-XcBHtwm9.d.mts.map
|