split: deterministic-tests, obsidian-plugin, local-cli, test-client, frontend root
New deterministic-tests workspace: scripted multi-client harness against a real server (~110 scenario tests, server-control, managed-websocket, test-runner). Updates to existing workspaces: obsidian-plugin (settings, cursors, plugin entrypoint), local-client-cli (args, cli, file-watcher, node-filesystem, path-utils + tests), test-client (mock-agent/client, cli, error tracker). Bumps frontend root package.json/lock and adds eslint config tweaks.
This commit is contained in:
parent
5a070340f1
commit
0daeaf6382
162 changed files with 10687 additions and 4051 deletions
|
|
@ -8,6 +8,7 @@ The repo depends on the latest plugin API (obsidian.d.ts) in TypeScript Definiti
|
|||
**Note:** The Obsidian API is still in early alpha and is subject to change at any time!
|
||||
|
||||
This sample plugin demonstrates some of the basic functionality the plugin API can do.
|
||||
|
||||
- Adds a ribbon icon, which shows a Notice when clicked.
|
||||
- Adds a command "Open Sample Modal" which opens a Modal.
|
||||
- Adds a plugin setting tab to the settings page.
|
||||
|
|
@ -57,31 +58,6 @@ Quick starting guide for new plugin devs:
|
|||
|
||||
- Copy over `main.js`, `styles.css`, `manifest.json` to your vault `VaultFolder/.obsidian/plugins/your-plugin-id/`.
|
||||
|
||||
|
||||
## Funding URL
|
||||
|
||||
You can include funding URLs where people who use your plugin can financially support it.
|
||||
|
||||
The simple way is to set the `fundingUrl` field to your link in your `manifest.json` file:
|
||||
|
||||
```json
|
||||
{
|
||||
"fundingUrl": "https://buymeacoffee.com"
|
||||
}
|
||||
```
|
||||
|
||||
If you have multiple URLs, you can also do:
|
||||
|
||||
```json
|
||||
{
|
||||
"fundingUrl": {
|
||||
"Buy Me a Coffee": "https://buymeacoffee.com",
|
||||
"GitHub Sponsor": "https://github.com/sponsors",
|
||||
"Patreon": "https://www.patreon.com/"
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
## API Documentation
|
||||
|
||||
See https://github.com/obsidianmd/obsidian-api
|
||||
|
|
|
|||
|
|
@ -13,25 +13,25 @@
|
|||
"author": "",
|
||||
"license": "MIT",
|
||||
"devDependencies": {
|
||||
"@types/node": "^24.8.1",
|
||||
"@types/node": "^25.0.2",
|
||||
"css-loader": "^7.1.2",
|
||||
"date-fns": "^4.1.0",
|
||||
"file-loader": "^6.2.0",
|
||||
"fs-extra": "^11.3.0",
|
||||
"mini-css-extract-plugin": "^2.9.2",
|
||||
"obsidian": "1.10.2",
|
||||
"reconcile-text": "^0.8.0",
|
||||
"fs-extra": "^11.3.2",
|
||||
"mini-css-extract-plugin": "^2.9.4",
|
||||
"obsidian": "1.11.0",
|
||||
"reconcile-text": "^0.11.0",
|
||||
"resolve-url-loader": "^5.0.0",
|
||||
"sass": "^1.91.0",
|
||||
"sass": "^1.96.0",
|
||||
"sass-loader": "^16.0.6",
|
||||
"sync-client": "file:../sync-client",
|
||||
"terser-webpack-plugin": "^5.3.14",
|
||||
"ts-loader": "^9.5.2",
|
||||
"terser-webpack-plugin": "^5.3.16",
|
||||
"ts-loader": "^9.5.4",
|
||||
"tslib": "2.8.1",
|
||||
"tsx": "^4.20.6",
|
||||
"typescript": "5.8.3",
|
||||
"tsx": "^4.21.0",
|
||||
"typescript": "5.9.3",
|
||||
"url": "^0.11.4",
|
||||
"webpack": "^5.99.9",
|
||||
"webpack": "^5.103.0",
|
||||
"webpack-cli": "^6.0.1"
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -135,14 +135,14 @@ export default class VaultLinkPlugin extends Plugin {
|
|||
nativeLineEndings: Platform.isWin ? "\r\n" : "\n",
|
||||
...(IS_DEBUG_BUILD
|
||||
? {
|
||||
fetch: debugging.slowFetchFactory(1),
|
||||
webSocket: debugging.slowWebSocketFactory(1, new Logger())
|
||||
}
|
||||
fetch: debugging.slowFetchFactory(1),
|
||||
webSocket: debugging.slowWebSocketFactory(1, new Logger())
|
||||
}
|
||||
: {})
|
||||
});
|
||||
|
||||
if (IS_DEBUG_BUILD) {
|
||||
debugging.logToConsole(client);
|
||||
debugging.logToConsole(client.logger);
|
||||
}
|
||||
|
||||
return client;
|
||||
|
|
@ -231,9 +231,9 @@ export default class VaultLinkPlugin extends Plugin {
|
|||
}
|
||||
}
|
||||
),
|
||||
this.app.vault.on("create", async (file: TAbstractFile) => {
|
||||
this.app.vault.on("create", (file: TAbstractFile) => {
|
||||
if (file instanceof TFile) {
|
||||
await client.syncLocallyCreatedFile(file.path);
|
||||
client.syncLocallyCreatedFile(file.path);
|
||||
}
|
||||
}),
|
||||
this.app.vault.on("modify", async (file: TAbstractFile) => {
|
||||
|
|
@ -241,14 +241,14 @@ export default class VaultLinkPlugin extends Plugin {
|
|||
await this.rateLimitedUpdate(file.path, client);
|
||||
}
|
||||
}),
|
||||
this.app.vault.on("delete", async (file: TAbstractFile) => {
|
||||
await client.syncLocallyDeletedFile(file.path);
|
||||
this.app.vault.on("delete", (file: TAbstractFile) => {
|
||||
client.syncLocallyDeletedFile(file.path);
|
||||
}),
|
||||
this.app.vault.on(
|
||||
"rename",
|
||||
async (file: TAbstractFile, oldPath: string) => {
|
||||
(file: TAbstractFile, oldPath: string) => {
|
||||
if (file instanceof TFile) {
|
||||
await client.syncLocallyUpdatedFile({
|
||||
client.syncLocallyUpdatedFile({
|
||||
oldPath,
|
||||
relativePath: file.path
|
||||
});
|
||||
|
|
@ -267,13 +267,11 @@ export default class VaultLinkPlugin extends Plugin {
|
|||
if (!this.rateLimitedUpdatesPerFile.has(path)) {
|
||||
this.rateLimitedUpdatesPerFile.set(
|
||||
path,
|
||||
rateLimit(
|
||||
async () =>
|
||||
client.syncLocallyUpdatedFile({
|
||||
relativePath: path
|
||||
}),
|
||||
MIN_WAIT_BETWEEN_UPDATES_IN_MS
|
||||
)
|
||||
rateLimit(async () => {
|
||||
client.syncLocallyUpdatedFile({
|
||||
relativePath: path
|
||||
});
|
||||
}, MIN_WAIT_BETWEEN_UPDATES_IN_MS)
|
||||
);
|
||||
}
|
||||
await this.rateLimitedUpdatesPerFile.get(path)?.();
|
||||
|
|
|
|||
|
|
@ -14,7 +14,9 @@ export function renderCursorsInFileExplorer(
|
|||
app: App
|
||||
): void {
|
||||
const fileExplorers = app.workspace.getLeavesOfType("file-explorer");
|
||||
if (fileExplorers.length == 0) return;
|
||||
if (fileExplorers.length == 0) {
|
||||
return;
|
||||
}
|
||||
|
||||
const [fileExplorer] = fileExplorers;
|
||||
|
||||
|
|
@ -34,7 +36,7 @@ export function renderCursorsInFileExplorer(
|
|||
(parent) => {
|
||||
cursors.forEach((cursor) => {
|
||||
cursor.documentsWithCursors.forEach((document) => {
|
||||
if (document.relative_path.startsWith(key)) {
|
||||
if (document.relativePath.startsWith(key)) {
|
||||
parent.appendChild(
|
||||
createSpan({
|
||||
text: cursor.userName,
|
||||
|
|
|
|||
|
|
@ -61,7 +61,7 @@ export class RemoteCursorsPluginValue implements PluginValue {
|
|||
return clientCursors.flatMap((cursor) =>
|
||||
cursor.cursors.map((span) => ({
|
||||
name: client.userName,
|
||||
path: cursor.relative_path,
|
||||
path: cursor.relativePath,
|
||||
deviceId: client.deviceId,
|
||||
isOutdated: client.isOutdated,
|
||||
span: { ...span }
|
||||
|
|
@ -132,7 +132,8 @@ export class RemoteCursorsPluginValue implements PluginValue {
|
|||
]
|
||||
)
|
||||
},
|
||||
edited
|
||||
edited,
|
||||
"Markdown"
|
||||
);
|
||||
|
||||
reconciled.cursors.forEach(({ id, position }) => {
|
||||
|
|
|
|||
|
|
@ -266,9 +266,8 @@ export class SyncSettingsTab extends PluginSettingTab {
|
|||
|
||||
new Notice("Checking connection to the server...");
|
||||
new Notice(
|
||||
(
|
||||
await this.syncClient.checkConnection()
|
||||
).serverMessage
|
||||
(await this.syncClient.checkConnection())
|
||||
.serverMessage
|
||||
);
|
||||
await this.statusDescription.updateConnectionState();
|
||||
} else {
|
||||
|
|
@ -351,22 +350,6 @@ export class SyncSettingsTab extends PluginSettingTab {
|
|||
})
|
||||
);
|
||||
|
||||
new Setting(containerEl)
|
||||
.setName("Sync concurrency")
|
||||
.setDesc(
|
||||
"How many concurrent sync operations to run. Setting this value higher may increase the overall performance, however, it will require more memory as well. If you notice frequent crashes, especially on mobile, set this to 1."
|
||||
)
|
||||
.addSlider((text) =>
|
||||
text
|
||||
.setLimits(1, 16, 1)
|
||||
.setDynamicTooltip()
|
||||
.setInstant(false)
|
||||
.setValue(this.syncClient.getSettings().syncConcurrency)
|
||||
.onChange(async (value) =>
|
||||
this.syncClient.setSetting("syncConcurrency", value)
|
||||
)
|
||||
);
|
||||
|
||||
new Setting(containerEl)
|
||||
.setName("Maximum file size to be uploaded (MB)")
|
||||
.setDesc(
|
||||
|
|
@ -484,40 +467,6 @@ export class SyncSettingsTab extends PluginSettingTab {
|
|||
);
|
||||
})
|
||||
);
|
||||
|
||||
new Setting(containerEl)
|
||||
.setName("Minimum save interval (ms)")
|
||||
.setDesc(
|
||||
"The minimum time between saving settings and database to disk, in milliseconds. Lower values save more frequently but may impact performance."
|
||||
)
|
||||
.addText((input) =>
|
||||
input
|
||||
.setValue(
|
||||
this.syncClient
|
||||
.getSettings()
|
||||
.minimumSaveIntervalMs.toString()
|
||||
)
|
||||
.onChange(async (value) => {
|
||||
if (value === "") {
|
||||
return;
|
||||
}
|
||||
let parsedValue = Number.parseInt(value, 10);
|
||||
if (Number.isNaN(parsedValue) || parsedValue < 0) {
|
||||
parsedValue =
|
||||
this.syncClient.getSettings()
|
||||
.minimumSaveIntervalMs;
|
||||
}
|
||||
|
||||
if (value !== parsedValue.toString()) {
|
||||
input.setValue(parsedValue.toString());
|
||||
}
|
||||
|
||||
return this.syncClient.setSetting(
|
||||
"minimumSaveIntervalMs",
|
||||
parsedValue
|
||||
);
|
||||
})
|
||||
);
|
||||
}
|
||||
|
||||
private setStatusDescriptionSubscription(
|
||||
|
|
|
|||
|
|
@ -88,7 +88,7 @@ export class StatusDescription {
|
|||
text: ` and has indexed approximately `
|
||||
});
|
||||
container.createSpan({
|
||||
text: `${this.syncClient.documentCount}`,
|
||||
text: `${this.syncClient.syncedDocumentCount}`,
|
||||
cls: "number"
|
||||
});
|
||||
container.createSpan({
|
||||
|
|
|
|||
|
|
@ -6,12 +6,7 @@
|
|||
"strict": true,
|
||||
"moduleResolution": "bundler",
|
||||
"allowSyntheticDefaultImports": true,
|
||||
"lib": [
|
||||
"DOM",
|
||||
"ES2024"
|
||||
]
|
||||
"lib": ["DOM", "ES2024"]
|
||||
},
|
||||
"exclude": [
|
||||
"./dist"
|
||||
]
|
||||
"exclude": ["./dist"]
|
||||
}
|
||||
|
|
|
|||
|
|
@ -46,7 +46,7 @@ module.exports = (env, argv) => ({
|
|||
const source = path.resolve(__dirname, "dist");
|
||||
const destinations = [
|
||||
"/volumes/syncthing/Desktop/test/test/.obsidian/plugins/vault-link",
|
||||
"/volumes/syncthing/Desktop/test/test2/.obsidian/plugins/vault-link",
|
||||
"/volumes/syncthing/Desktop/test/test2/.obsidian/plugins/vault-link"
|
||||
// "/home/andras/obsidian-test/.obsidian/plugins/vault-link"
|
||||
];
|
||||
destinations.forEach((destination) => {
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue