@lapis-notes/api 0.1.3 → 0.2.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.
Files changed (199) hide show
  1. package/CHANGELOG.md +304 -13
  2. package/README.md +19 -0
  3. package/dist/__tests__/fixtures/indexed-mutations.json +6862 -0
  4. package/dist/__tests__/fixtures/memory-storage.json +309 -0
  5. package/dist/__tests__/fixtures/native-facade-contract.json +3224 -0
  6. package/dist/__tests__/fixtures/projection-query.json +195 -0
  7. package/dist/__tests__/fixtures/projection-values.json +60 -0
  8. package/dist/__tests__/fixtures/search-preparation.json +1513 -0
  9. package/dist/__tests__/fixtures/search-retrieval.json +15409 -0
  10. package/dist/__tests__/fixtures/search-semantic-model.json +3691 -0
  11. package/dist/__tests__/fixtures/search-semantic-retrieval.json +6603 -0
  12. package/dist/__tests__/fixtures/search-storage.json +409 -0
  13. package/dist/__tests__/fixtures/task-projection.json +428 -0
  14. package/dist/__tests__/indexed-mutation-support.js +262 -0
  15. package/dist/__tests__/projection-query-support.js +40 -0
  16. package/dist/__tests__/search-retrieval-support.js +47 -0
  17. package/dist/app-database-host.d.ts +1 -0
  18. package/dist/app-shell-plugin-persistence.d.ts +3 -2
  19. package/dist/app-shell-plugin-persistence.js +37 -3
  20. package/dist/cache.svelte.d.ts +8 -1
  21. package/dist/cache.svelte.js +103 -5
  22. package/dist/command.svelte.js +29 -2
  23. package/dist/components/editor/editor.css +4 -0
  24. package/dist/components/editor/editor.svelte +24 -11
  25. package/dist/components/editor/embedded-editor-surface.js +3 -1
  26. package/dist/components/editor/inline-title-alignment.d.ts +3 -0
  27. package/dist/components/editor/inline-title-alignment.js +57 -0
  28. package/dist/configuration.svelte.d.ts +270 -206
  29. package/dist/configuration.svelte.js +161 -86
  30. package/dist/context.svelte.d.ts +23 -3
  31. package/dist/context.svelte.js +68 -30
  32. package/dist/diagnostics.d.ts +8 -0
  33. package/dist/diagnostics.js +6 -0
  34. package/dist/editor-save-context.d.ts +35 -0
  35. package/dist/editor-save-context.js +132 -0
  36. package/dist/editor-view-registry.d.ts +10 -0
  37. package/dist/editor-view-registry.js +44 -4
  38. package/dist/editor.svelte.d.ts +19 -1
  39. package/dist/editor.svelte.js +528 -55
  40. package/dist/embed-registry.d.ts +10 -0
  41. package/dist/embed-registry.js +15 -0
  42. package/dist/file-editing-failures.d.ts +2 -0
  43. package/dist/file-editing-failures.js +29 -0
  44. package/dist/file-editing-native-issues.d.ts +19 -0
  45. package/dist/file-editing-native-issues.js +65 -0
  46. package/dist/file-editing-sessions.d.ts +76 -0
  47. package/dist/file-editing-sessions.js +367 -0
  48. package/dist/file-manager.d.ts +9 -1
  49. package/dist/file-manager.js +45 -3
  50. package/dist/file-state-store.d.ts +5 -0
  51. package/dist/file-state-store.js +34 -0
  52. package/dist/file-text-conflicts.d.ts +25 -0
  53. package/dist/file-text-conflicts.js +35 -0
  54. package/dist/file-text-mutation.d.ts +13 -0
  55. package/dist/file-text-mutation.js +100 -0
  56. package/dist/file-text-persistence.d.ts +36 -0
  57. package/dist/file-text-persistence.js +234 -0
  58. package/dist/file-text-state-writer.d.ts +34 -0
  59. package/dist/file-text-state-writer.js +183 -0
  60. package/dist/files-configuration.d.ts +20 -0
  61. package/dist/files-configuration.js +47 -0
  62. package/dist/generated/plugin-host-modules.schema.generated.d.ts +114 -34
  63. package/dist/generated/plugin-host-modules.schema.generated.js +132 -34
  64. package/dist/glob.d.ts +3 -0
  65. package/dist/glob.js +2 -1
  66. package/dist/icons/changes.d.ts +3 -0
  67. package/dist/icons/changes.js +16 -0
  68. package/dist/icons/index.d.ts +5 -1
  69. package/dist/icons/index.js +44 -3
  70. package/dist/icons/registry.d.ts +35 -0
  71. package/dist/icons/registry.js +154 -0
  72. package/dist/icons/safe-svg.d.ts +2 -0
  73. package/dist/icons/safe-svg.js +44 -0
  74. package/dist/index.d.ts +6 -1
  75. package/dist/index.js +4 -1
  76. package/dist/lapis-extension.d.ts +6 -2
  77. package/dist/lapis-extension.js +2 -0
  78. package/dist/metadata-store.d.ts +23 -0
  79. package/dist/metadata-store.js +1 -0
  80. package/dist/metadata.svelte.js +45 -2
  81. package/dist/native-background-indexing.d.ts +48 -0
  82. package/dist/native-background-indexing.js +208 -0
  83. package/dist/native-database-protocol.d.ts +29 -0
  84. package/dist/native-database-protocol.js +1 -0
  85. package/dist/native-editing-intent-lease.d.ts +17 -0
  86. package/dist/native-editing-intent-lease.js +188 -0
  87. package/dist/native-editing-intents-protocol.d.ts +70 -0
  88. package/dist/native-editing-intents-protocol.js +1 -0
  89. package/dist/native-editing-intents.d.ts +8 -0
  90. package/dist/native-editing-intents.js +1 -0
  91. package/dist/native-editing-problems.d.ts +3 -0
  92. package/dist/native-editing-problems.js +180 -0
  93. package/dist/native-editing-recovery.d.ts +24 -0
  94. package/dist/native-editing-recovery.js +198 -0
  95. package/dist/native-editing-session.d.ts +51 -0
  96. package/dist/native-editing-session.js +251 -0
  97. package/dist/native-history-index-protocol.d.ts +80 -0
  98. package/dist/native-history-index-protocol.js +1 -0
  99. package/dist/native-history-index.d.ts +6 -0
  100. package/dist/native-history-index.js +1 -0
  101. package/dist/native-indexing-protocol.d.ts +63 -0
  102. package/dist/native-indexing-protocol.js +1 -0
  103. package/dist/native-participant-protocol.d.ts +67 -0
  104. package/dist/native-participant-protocol.js +3 -0
  105. package/dist/native-queue-protocol.d.ts +73 -0
  106. package/dist/native-queue-protocol.js +3 -0
  107. package/dist/native-tasks-protocol.d.ts +264 -0
  108. package/dist/native-tasks-protocol.js +1 -0
  109. package/dist/native-tasks.d.ts +35 -0
  110. package/dist/native-tasks.js +79 -0
  111. package/dist/native-turn-protocol.d.ts +81 -0
  112. package/dist/native-turn-protocol.js +1 -0
  113. package/dist/native-turns.d.ts +29 -0
  114. package/dist/native-turns.js +2 -0
  115. package/dist/plugin-asset-server.js +3 -2
  116. package/dist/plugin-dependency-resolver.d.ts +1 -1
  117. package/dist/plugin-distribution/compatibility.d.ts +1 -1
  118. package/dist/plugin-distribution/compatibility.js +10 -5
  119. package/dist/plugin-distribution/installed-plugin-state.js +2 -1
  120. package/dist/plugin-distribution/installer.d.ts +6 -0
  121. package/dist/plugin-distribution/installer.js +90 -37
  122. package/dist/plugin-distribution/manager.d.ts +4 -1
  123. package/dist/plugin-distribution/manager.js +12 -5
  124. package/dist/plugin-distribution/registry-cache.js +2 -1
  125. package/dist/plugin-distribution/registry-source-state.js +2 -1
  126. package/dist/plugin-distribution/schemas.d.ts +26 -8
  127. package/dist/plugin-distribution/schemas.js +2 -1
  128. package/dist/plugin-distribution/types.d.ts +4 -0
  129. package/dist/plugin-manager.d.ts +21 -5
  130. package/dist/plugin-manager.js +228 -64
  131. package/dist/plugin-runtime-entry.d.ts +1 -1
  132. package/dist/plugin-runtime-entry.js +16 -0
  133. package/dist/plugin.d.ts +19 -3
  134. package/dist/plugin.js +110 -44
  135. package/dist/registry-schema/catalog-v1.d.ts +60 -9
  136. package/dist/registry-schema/catalog-v1.js +2 -1
  137. package/dist/registry-schema/catalog-v2.d.ts +60 -9
  138. package/dist/registry-schema/catalog-v2.js +1 -1
  139. package/dist/search-result-provider.d.ts +95 -0
  140. package/dist/search-result-provider.js +42 -0
  141. package/dist/status-bar.svelte.d.ts +26 -20
  142. package/dist/status-bar.svelte.js +1 -0
  143. package/dist/storage/app-database.d.ts +9 -23
  144. package/dist/storage/app-database.js +41 -34
  145. package/dist/storage/desktop-native.d.ts +5 -3
  146. package/dist/storage/desktop-native.js +59 -6
  147. package/dist/storage/directory-watcher.d.ts +27 -0
  148. package/dist/storage/directory-watcher.js +201 -0
  149. package/dist/storage/fs.d.ts +14 -27
  150. package/dist/storage/fs.js +2 -168
  151. package/dist/storage/index-projection.js +33 -15
  152. package/dist/storage/memory-vault-adapter.d.ts +2 -0
  153. package/dist/storage/memory-vault-adapter.js +14 -1
  154. package/dist/storage/path.d.ts +6 -2
  155. package/dist/storage/path.js +8 -2
  156. package/dist/storage/projection-query-candidates.d.ts +3 -0
  157. package/dist/storage/projection-query-candidates.js +69 -0
  158. package/dist/storage/remote-app-database.d.ts +2 -2
  159. package/dist/storage/remote-app-database.js +1 -1
  160. package/dist/storage/runtime.d.ts +3 -0
  161. package/dist/storage/runtime.js +3 -0
  162. package/dist/storage/search-embedding-record.d.ts +3 -0
  163. package/dist/storage/search-embedding-record.js +18 -0
  164. package/dist/storage/turso-app-database.d.ts +2 -0
  165. package/dist/storage/turso-app-database.js +67 -30
  166. package/dist/storage/vault-listing.d.ts +3 -0
  167. package/dist/storage/vault-listing.js +36 -0
  168. package/dist/storage/vault-reconciliation.d.ts +19 -0
  169. package/dist/storage/vault-reconciliation.js +137 -0
  170. package/dist/storage/vault-session.d.ts +8 -0
  171. package/dist/storage/vault-session.js +10 -2
  172. package/dist/storage/vault.svelte.d.ts +53 -4
  173. package/dist/storage/vault.svelte.js +223 -87
  174. package/dist/sync-editor-flush.d.ts +6 -0
  175. package/dist/sync-editor-flush.js +22 -0
  176. package/dist/sync-host-local.d.ts +15 -0
  177. package/dist/sync-host-local.js +228 -0
  178. package/dist/sync-host-security.d.ts +24 -9
  179. package/dist/sync-host-security.js +47 -14
  180. package/dist/sync-host.d.ts +33 -4
  181. package/dist/sync-host.js +160 -10
  182. package/dist/sync-repository.d.ts +106 -0
  183. package/dist/sync-repository.js +18 -0
  184. package/dist/vault-change-views.d.ts +4 -0
  185. package/dist/vault-change-views.js +43 -0
  186. package/dist/vault-changes.d.ts +37 -0
  187. package/dist/vault-changes.js +228 -0
  188. package/dist/view.svelte.d.ts +182 -149
  189. package/dist/view.svelte.js +39 -21
  190. package/dist/workspace-close-guard.d.ts +3 -0
  191. package/dist/workspace-close-guard.js +35 -0
  192. package/dist/workspace-host-internal.js +10 -2
  193. package/dist/workspace-layout-normalizer.d.ts +4 -2
  194. package/dist/workspace-layout-normalizer.js +5 -5
  195. package/dist/workspace-view-document.d.ts +3 -0
  196. package/dist/workspace-view-document.js +12 -0
  197. package/dist/workspace.svelte.d.ts +13 -2
  198. package/dist/workspace.svelte.js +371 -82
  199. package/package.json +61 -8
package/dist/plugin.d.ts CHANGED
@@ -1,3 +1,6 @@
1
+ import type { IconLoader } from "./icons";
2
+ import type { ExtensionRegistrationOptions } from "./editor-view-registry";
3
+ import type { SearchResultProvider, SearchResultProviderRegistration } from "./search-result-provider";
1
4
  import type { MetadataProcessor } from "./cache.svelte";
2
5
  import type { IndexProjectionRegistration, RegisteredIndexProjectionHandle } from "./storage/index-projection";
3
6
  import type { SearchDocumentProvider, SearchDocumentProviderRegistration } from "./search-document-provider";
@@ -5,6 +8,7 @@ import type { Command, KeymapEventHandler } from "./command.svelte";
5
8
  import type { ContextKeyValue, ScopedContextKey } from "./context-keys.svelte";
6
9
  import type { App, ExtType } from "./context.svelte";
7
10
  import type { LapisExtensionContributions, LapisExtensionKind, LapisExtensionManifest, LapisExtensionPermission, LapisExtensionRuntimeHost, LapisPluginClassification, LapisServiceProviderRegistration, LapisSystemExtensionRegistration } from "./lapis-extension";
11
+ import type { MarkdownEmbedder } from "./embed-registry";
8
12
  import type { EditorViewContribution } from "./editor-view-registry";
9
13
  import type { ConfigurationOptionSourceProvider, ConfigurationOptionSourceRegistration } from "./configuration-option-source-registry";
10
14
  import type { HostedPluginCapability } from "./plugin-capability-facade";
@@ -125,6 +129,8 @@ export interface PluginManifest {
125
129
  * @public
126
130
  */
127
131
  requiredCapabilities?: HostedPluginCapability[];
132
+ /** Native host services that must be available before module evaluation. */
133
+ requiredNativeServices?: string[];
128
134
  /**
129
135
  * Optional host-specific execution hints for future sidecar scheduling.
130
136
  *
@@ -150,7 +156,7 @@ export type PluginSource = "core" | "community" | "official" | "system";
150
156
  * Resolve the compatibility data path used by `loadData()` and `saveData()`.
151
157
  *
152
158
  * Community plugins store data beside their manifest folder, while bundled and
153
- * system plugins use the shared `/.obsidian/<id>.json` location.
159
+ * system plugins use the shared `/.lapis/<id>.json` location.
154
160
  *
155
161
  * @public
156
162
  */
@@ -171,7 +177,7 @@ export interface PluginRuntimeOptions {
171
177
  requestedCapabilities?: HostedPluginCapability[];
172
178
  grantedCapabilities?: HostedPluginCapability[];
173
179
  createSyncHostCapabilities?: () => SyncHostCapabilities;
174
- revokeSyncHostCapabilities?: () => void;
180
+ revokeSyncHostCapabilities?: () => void | Promise<void>;
175
181
  }
176
182
  /**
177
183
  * Base class for Lapis plugins.
@@ -247,6 +253,8 @@ export declare abstract class Plugin extends Component {
247
253
  * @see {@link https://docs.obsidian.md/Plugins/User+interface/Settings}
248
254
  */
249
255
  loadData(): Promise<any>;
256
+ private runDataOperation;
257
+ private loadDataNow;
250
258
  /**
251
259
  * Write settings data to disk. Data is stored in `data.json` in the plugin
252
260
  * folder.
@@ -255,6 +263,7 @@ export declare abstract class Plugin extends Component {
255
263
  * @see {@link https://docs.obsidian.md/Plugins/User+interface/Settings}
256
264
  */
257
265
  saveData(data: any): Promise<void>;
266
+ private saveDataNow;
258
267
  loadGeneratedState<T>(key: string): Promise<T | null>;
259
268
  saveGeneratedState(key: string, value: unknown): Promise<void>;
260
269
  deleteGeneratedState(key: string): Promise<void>;
@@ -280,6 +289,10 @@ export declare abstract class Plugin extends Component {
280
289
  icon?: string;
281
290
  hidden?: boolean;
282
291
  }, access?: ViewAccess): void;
292
+ /** Register an App-owned SVG and dispose it automatically on plugin unload. */
293
+ registerIcon(localId: string, svg: string): string;
294
+ /** Register an owned icon pack; use the returned prefix in `prefix:icon` IDs. */
295
+ registerIconPack(input: IconLoader): string;
283
296
  registerEditorView(contribution: EditorViewContribution): void;
284
297
  registerConfigurationOptionSource(id: string, provider: Omit<ConfigurationOptionSourceProvider, "pluginId">): ConfigurationOptionSourceRegistration;
285
298
  registerHoverLinkSource(id: string, info: any): void;
@@ -291,7 +304,7 @@ export declare abstract class Plugin extends Component {
291
304
  createDiagnosticCollection(id: string, options?: DiagnosticCollectionOptions): DiagnosticCollection;
292
305
  onUserEnable(): Promise<void> | void;
293
306
  onExternalSettingsChange(): Promise<void> | void;
294
- registerExtensions(extensions: string[], viewType?: string): void;
307
+ registerExtensions(extensions: string[], viewType?: string, options?: ExtensionRegistrationOptions): void;
295
308
  registerTypeWidget(widget: TypeWidget): void;
296
309
  /**
297
310
  * Register an EditorSuggest which can provide live suggestions while the user
@@ -326,6 +339,7 @@ export declare abstract class Plugin extends Component {
326
339
  registerMarkdownCodeBlockProcessor(language: string, handler: (source: string, el: HTMLElement, ctx: MarkdownPostProcessorContext) => Promise<any> | void, sortOrder?: number): MarkdownPostProcessor;
327
340
  registerMarkdownDirectiveRenderer(directive: string, renderer: MarkdownDirectiveRenderer): void;
328
341
  registerMarkdownViewMenuItem(provider: MarkdownViewMenuItemProvider): void;
342
+ registerMarkdownEmbedder(embedder: MarkdownEmbedder): void;
329
343
  registerMetadataProcessor(processor: MetadataProcessor, ext?: string): void;
330
344
  registerIndexProjection<T = Record<string, unknown>>(registration: IndexProjectionRegistration): RegisteredIndexProjectionHandle<T>;
331
345
  private backfillIndexProjection;
@@ -334,6 +348,8 @@ export declare abstract class Plugin extends Component {
334
348
  * The local id is namespaced by this plugin's runtime id.
335
349
  */
336
350
  registerSearchDocumentProvider(localId: string, provider: Omit<SearchDocumentProvider, "id">): SearchDocumentProviderRegistration;
351
+ /** Contribute query results whose navigation remains provider-owned. */
352
+ registerSearchResultProvider(localId: string, provider: Omit<SearchResultProvider, "id">): SearchResultProviderRegistration;
337
353
  /** Register an application tool under this plugin's lifecycle and identity. */
338
354
  registerAgentTool<TInput>(tool: AppTool<TInput>): AppToolRegistration;
339
355
  /** Register a directory that contains one skill. */
package/dist/plugin.js CHANGED
@@ -1,3 +1,5 @@
1
+ import { saveFileState } from "./file-state-store";
2
+ import { appStatePath } from "./storage/path";
1
3
  import { matchesProjectionSource } from "./storage/index-projection";
2
4
  import { resolveWorkspaceHostBinding } from "./workspace-host-internal";
3
5
  import { dirname, joinPath } from "./storage";
@@ -9,13 +11,13 @@ function isPromiseLike(value) {
9
11
  * Resolve the compatibility data path used by `loadData()` and `saveData()`.
10
12
  *
11
13
  * Community plugins store data beside their manifest folder, while bundled and
12
- * system plugins use the shared `/.obsidian/<id>.json` location.
14
+ * system plugins use the shared `/.lapis/<id>.json` location.
13
15
  *
14
16
  * @public
15
17
  */
16
18
  export function resolvePluginDataPath(pluginId, source, basePath) {
17
19
  if (source === "core" || source === "system") {
18
- return joinPath("/.obsidian", `${pluginId}.json`);
20
+ return joinPath("/", appStatePath(`${pluginId}.json`));
19
21
  }
20
22
  if (!basePath) {
21
23
  return null;
@@ -122,10 +124,19 @@ export class Plugin extends Component {
122
124
  this.register(() => lease.release());
123
125
  }
124
126
  await this.loadAsync();
127
+ await this.app.metadataCache?.finishNativeContributions?.(this.id);
125
128
  this.#runtimeState = "enabled";
126
129
  this.emit("enable");
127
130
  }
128
131
  catch (error) {
132
+ if (this.app.session?.backgroundIndexing && this.loaded) {
133
+ try {
134
+ await this.unloadAsync();
135
+ }
136
+ catch (cleanupError) {
137
+ console.error("Failed to rollback native plugin activation", cleanupError);
138
+ }
139
+ }
129
140
  this.#runtimeState = "failed";
130
141
  this.#failureMessage = formatPluginError(error);
131
142
  this.#lastFailureMessage = this.#failureMessage;
@@ -200,6 +211,10 @@ export class Plugin extends Component {
200
211
  return;
201
212
  }
202
213
  const payload = JSON.stringify(data, null, 2);
214
+ if (this.app.vault.supportsConditionalTextWrites) {
215
+ await saveFileState(this.app, path, payload);
216
+ return;
217
+ }
203
218
  const file = this.app.vault.getFileByPath(path);
204
219
  if (file) {
205
220
  await this.app.vault.modify(file, payload);
@@ -236,17 +251,31 @@ export class Plugin extends Component {
236
251
  }
237
252
  async disable() {
238
253
  if (!this.loaded) {
239
- this.#revokeSyncHostCapabilities?.();
240
- this.#syncHostCapabilities = null;
254
+ try {
255
+ await this.app.metadataCache?.disableNativeContributions?.(this.id);
256
+ await this.#revokeSyncHostCapabilities?.();
257
+ }
258
+ finally {
259
+ this.#syncHostCapabilities = null;
260
+ }
241
261
  this.#runtimeState = "disabled";
242
262
  this.#failureMessage = null;
243
263
  return;
244
264
  }
245
265
  this.#runtimeState = "disabling";
246
266
  try {
247
- await this.unloadAsync();
248
- this.#revokeSyncHostCapabilities?.();
249
- this.#syncHostCapabilities = null;
267
+ await this.app.metadataCache?.disableNativeContributions?.(this.id);
268
+ try {
269
+ await this.unloadAsync();
270
+ }
271
+ finally {
272
+ try {
273
+ await this.#revokeSyncHostCapabilities?.();
274
+ }
275
+ finally {
276
+ this.#syncHostCapabilities = null;
277
+ }
278
+ }
250
279
  this.#runtimeState = "disabled";
251
280
  this.#failureMessage = null;
252
281
  this.emit("disable");
@@ -260,27 +289,17 @@ export class Plugin extends Component {
260
289
  }
261
290
  }
262
291
  addStatusBarItem() {
263
- let parent = this.app.workspace.statusCompatEl ??
264
- document.querySelector("#status-bar");
265
- if (!parent) {
266
- parent = document.querySelector("#lapis-status-bar-compat-fallback");
267
- }
268
- if (!parent) {
269
- parent = document.body.createDiv({
270
- attr: {
271
- id: "lapis-status-bar-compat-fallback",
272
- hidden: "true",
273
- "aria-hidden": "true",
274
- },
275
- });
276
- }
277
- this.app.workspace.statusCompatEl = parent;
278
- const statusEl = parent.createDiv({
279
- cls: "status-bar-item plugin-" + this.manifest.id,
280
- });
281
- this.register(() => {
282
- statusEl.detach();
292
+ const statusEl = document.createElement("div");
293
+ statusEl.className = "status-bar-item plugin-" + this.manifest.id;
294
+ const dispose = this.app.statusBar.registerItem({
295
+ id: `${this.manifest.id}:compat-status:${crypto.randomUUID()}`,
296
+ sourcePlugin: this.manifest.id,
297
+ mount: (host) => {
298
+ host.append(statusEl);
299
+ return () => statusEl.remove();
300
+ },
283
301
  });
302
+ this.register(dispose);
284
303
  return statusEl;
285
304
  }
286
305
  /**
@@ -291,6 +310,14 @@ export class Plugin extends Component {
291
310
  * @see {@link https://docs.obsidian.md/Plugins/User+interface/Settings}
292
311
  */
293
312
  loadData() {
313
+ return this.runDataOperation(() => this.loadDataNow());
314
+ }
315
+ runDataOperation(run) {
316
+ return this.app.vault.supportsConditionalTextWrites
317
+ ? this.app.fileEditingSessions.track(run)
318
+ : run();
319
+ }
320
+ loadDataNow() {
294
321
  return this.measureTelemetryAsync("plugin.load_data", async () => {
295
322
  if (this.app.configuration.hasPluginData(this.id)) {
296
323
  const data = this.app.configuration.getPluginData(this.id);
@@ -312,6 +339,9 @@ export class Plugin extends Component {
312
339
  * @see {@link https://docs.obsidian.md/Plugins/User+interface/Settings}
313
340
  */
314
341
  saveData(data) {
342
+ return this.runDataOperation(() => this.saveDataNow(data));
343
+ }
344
+ saveDataNow(data) {
315
345
  return this.measureTelemetryAsync("plugin.save_data", async () => {
316
346
  await this.app.configuration.updatePluginData(this.id, data, {
317
347
  origin: "plugin-save",
@@ -437,6 +467,18 @@ export class Plugin extends Component {
437
467
  this.app.workspace.unregisterSidebarView(type);
438
468
  });
439
469
  }
470
+ /** Register an App-owned SVG and dispose it automatically on plugin unload. */
471
+ registerIcon(localId, svg) {
472
+ const registration = this.app.icons.registerIcon(this.manifest.id, localId, svg);
473
+ this.register(registration.dispose);
474
+ return registration.id;
475
+ }
476
+ /** Register an owned icon pack; use the returned prefix in `prefix:icon` IDs. */
477
+ registerIconPack(input) {
478
+ const registration = this.app.icons.registerIconPack(this.manifest.id, input);
479
+ this.register(registration.dispose);
480
+ return registration.prefix;
481
+ }
440
482
  registerEditorView(contribution) {
441
483
  const dispose = this.app.workspace.registerEditorView({
442
484
  ...contribution,
@@ -491,7 +533,11 @@ export class Plugin extends Component {
491
533
  }
492
534
  onUserEnable() { }
493
535
  onExternalSettingsChange() { }
494
- registerExtensions(extensions, viewType = "markdown") {
536
+ registerExtensions(extensions, viewType = "markdown", options) {
537
+ if (options) {
538
+ this.register(this.app.workspace.registerExtensions(extensions, viewType, options));
539
+ return;
540
+ }
495
541
  this.app.workspace.registerExtensions(extensions, viewType);
496
542
  this.register(() => {
497
543
  this.app.workspace.unregisterExtensions(extensions, viewType);
@@ -607,29 +653,38 @@ export class Plugin extends Component {
607
653
  this.app.unregisterMarkdownViewMenuItem(provider);
608
654
  });
609
655
  }
656
+ registerMarkdownEmbedder(embedder) {
657
+ this.register(this.app.embedRegistry.registerMarkdownEmbedder(embedder));
658
+ }
610
659
  registerMetadataProcessor(processor, ext = "md") {
611
- this.app.metadataCache.addProcessor(ext, processor);
660
+ this.app.metadataCache.addProcessor(ext, processor, this.id);
612
661
  this.register(() => {
613
662
  this.app.metadataCache.removeProcessor(ext, processor);
614
663
  });
615
664
  }
616
665
  registerIndexProjection(registration) {
617
666
  const recorded = this.app.indexProjections.register(this.id, registration);
618
- void this.app.appDatabase.registerProjectionDefinition({
619
- projectionId: recorded.projectionId,
620
- ownerPluginId: this.id,
621
- schemaVersion: registration.version,
622
- configHash: registration.configurationHash ?? "",
623
- visibility: registration.visibility ?? "public",
624
- fields: registration.fields,
625
- active: true,
626
- updatedAt: Date.now(),
627
- });
628
- this.register(() => {
629
- this.app.indexProjections.unregister(recorded.projectionId);
630
- void this.app.appDatabase.unregisterProjectionDefinition(recorded.projectionId);
631
- });
632
- void this.backfillIndexProjection(recorded.projectionId);
667
+ if (this.app.session?.backgroundIndexing) {
668
+ this.app.metadataCache.registerNativeProjection(this.id, recorded.projectionId, registration);
669
+ this.register(() => this.app.indexProjections.unregister(recorded.projectionId));
670
+ }
671
+ else {
672
+ void this.app.appDatabase.registerProjectionDefinition({
673
+ projectionId: recorded.projectionId,
674
+ ownerPluginId: this.id,
675
+ schemaVersion: registration.version,
676
+ configHash: registration.configurationHash ?? "",
677
+ visibility: registration.visibility ?? "public",
678
+ fields: registration.fields,
679
+ active: true,
680
+ updatedAt: Date.now(),
681
+ });
682
+ this.register(() => {
683
+ this.app.indexProjections.unregister(recorded.projectionId);
684
+ void this.app.appDatabase.unregisterProjectionDefinition(recorded.projectionId);
685
+ });
686
+ void this.backfillIndexProjection(recorded.projectionId);
687
+ }
633
688
  return {
634
689
  id: recorded.projectionId,
635
690
  query: (query) => this.app.appDatabase.queryProjection(recorded.projectionId, query, this.id),
@@ -698,6 +753,17 @@ export class Plugin extends Component {
698
753
  this.register(() => registration.dispose());
699
754
  return registration;
700
755
  }
756
+ /** Contribute query results whose navigation remains provider-owned. */
757
+ registerSearchResultProvider(localId, provider) {
758
+ if (!localId.trim())
759
+ throw new Error("Search result provider local id must not be empty.");
760
+ const registration = this.app.searchResultProviders.register({
761
+ ...provider,
762
+ id: `${this.id}:${localId.trim()}`,
763
+ });
764
+ this.register(() => registration.dispose());
765
+ return registration;
766
+ }
701
767
  /** Register an application tool under this plugin's lifecycle and identity. */
702
768
  registerAgentTool(tool) {
703
769
  const registration = this.app.agentTools.register({