├── .github
└── workflows
│ └── release.yml
├── .gitignore
├── LICENSE
├── README.md
├── bmc_qr.png
├── brain.svg
├── currentNote-demo.gif
├── esbuild.config.mjs
├── fabric-logo-gif.gif
├── main.ts
├── manifest.json
├── package-lock.json
├── package.json
├── styles.css
└── tsconfig.json
/.github/workflows/release.yml:
--------------------------------------------------------------------------------
1 | name: Release Obsidian plugin
2 |
3 | on:
4 | push:
5 | tags:
6 | - "*"
7 |
8 | jobs:
9 | build:
10 | runs-on: ubuntu-latest
11 |
12 | steps:
13 | - uses: actions/checkout@v3
14 |
15 | - name: Use Node.js
16 | uses: actions/setup-node@v3
17 | with:
18 | node-version: "18.x"
19 |
20 | - name: Build plugin
21 | run: |
22 | npm install
23 | npm run build
24 |
25 | - name: Create release
26 | env:
27 | GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}
28 | run: |
29 | tag="${GITHUB_REF#refs/tags/}"
30 |
31 | gh release create "$tag" \
32 | --title="$tag" \
33 | --draft \
34 | main.js manifest.json styles.css fabric-logo-gif.gif
35 |
--------------------------------------------------------------------------------
/.gitignore:
--------------------------------------------------------------------------------
1 | # Ignore built files
2 | main.js
3 | *.js.map
4 |
5 | # Ignore node_modules
6 | node_modules/
7 |
8 | # Ignore macOS system files
9 | .DS_Store
10 | data.json
--------------------------------------------------------------------------------
/LICENSE:
--------------------------------------------------------------------------------
1 | MIT License
2 |
3 | Copyright (c) [2024] [Chase Elder]
4 |
5 | Permission is hereby granted, free of charge, to any person obtaining a copy
6 | of this software and associated documentation files (the "Software"), to deal
7 | in the Software without restriction, including without limitation the rights
8 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
9 | copies of the Software, and to permit persons to whom the Software is
10 | furnished to do so, subject to the following conditions:
11 |
12 | The above copyright notice and this permission notice shall be included in all
13 | copies or substantial portions of the Software.
14 |
15 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
16 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
17 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
18 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
19 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
20 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
21 | SOFTWARE.
--------------------------------------------------------------------------------
/README.md:
--------------------------------------------------------------------------------
1 | # Fabric Plugin for Obsidian
2 |
3 | **Try out my new plugin, it accomplishes the same thing as this one without having to have fabric or fabric-connector installed. Install it from the community plugins repo in Obsidian. https://github.com/chasebank87/mesh-ai**
4 |
5 | ## Updated to work with Fabric 2.0 (Enable fabric 2.0 compatability in the plugin settings)
6 | If you like this plugin, feel free to support the development by buying a coffee:
7 |
8 |
9 |
10 |
11 |
12 | ## Overview
13 |
14 | The Fabric Plugin is an advanced integration tool for Obsidian, designed to enhance content creation and management within the Obsidian ecosystem. It connects to external APIs to fetch and manipulate data based on user-defined patterns and models. The plugin also supports custom pattern management and YouTube link detection.
15 |
16 | ## Features
17 |
18 | - **Custom Pattern Management**: Watch for changes in a designated folder and sync patterns.
19 | - **Community Custom Patterns**: Download and share custom patterns with other fabric users.
20 | - [Fork repo to submit your patterns](https://github.com/chasebank87/fabric-patterns)
21 | - **YouTube Link Detection**: Automatically detect YouTube links in notes.
22 | - **External API Integration**: Connect to Fabric Connector API and Tavily API for enhanced content manipulation.
23 | - **Dynamic Content Rendering**: Render content dynamically based on user interactions and API responses.
24 | - **Debugging Support**: Toggle debug mode for additional logging.
25 |
26 | ## Prerequisites
27 |
28 | 1. **Fabric**: Install Fabric from [danielmiessler/fabric](https://github.com/danielmiessler/fabric).
29 | 2. **Fabric Connector**: Install Fabric Connector from [chasebank87/fabric-connector](https://github.com/chasebank87/fabric-connector).
30 |
31 | ## Installation
32 |
33 | To install the Fabric Plugin, follow these steps:
34 |
35 | 1. Download the plugin from the official repository.
36 | 2. Place the plugin in your Obsidian's plugins folder.
37 | 3. Enable the plugin from Obsidian's settings under "Community Plugins".
38 |
39 | ## Configuration
40 |
41 | Configure the plugin by setting up the necessary API URLs and keys through the plugin settings tab in Obsidian.
42 |
43 | ### Settings
44 |
45 | - `Fabric Connector API URL`: URL to the Fabric Connector API.
46 | - `Fabric Connector API Key`: Authentication key for the Fabric Connector API.
47 | - `Output Folder`: Default folder path where output files will be saved.
48 | - `Custom Patterns Folder`: Folder path for storing and managing custom patterns.
49 | - `YouTube Autodetect Enabled`: Toggle to enable or disable automatic YouTube link detection.
50 | - `Default Model`: Default model used for data processing.
51 | - `Debug`: Enable or disable debug mode for logging.
52 |
53 | ### Usage
54 |
55 | 1. **Pattern Management**: Add or remove markdown files in the custom patterns folder to manage patterns.
56 | 2. **YouTube Transcription**: Autodetect youtube links in current note or clipboard and transcribe them using whisper and then running a pattern against.
57 | 3. **Tavily Search**: Use the Tavily API to search for relevant content, and process through results through the selected pattern.
58 | 4. **Input Sources**:
59 | 1. ***Current Note***: Uses the current active note as the source to be sent to fabric.
60 | 2. ***Clipboard***: Uses the clipboard as the source to be sent to fabric.
61 | 3. ***Tavily***: Uses Tavily Search results as the source to be sent to fabric.
62 | 5. **Pattern Selection**: Choose a pattern from the available custom or built in patterns to process the input data.
63 | 6. **Models**: Select a model from the available options to process the input data and pattern.
64 | 7. **Upload Patterns**: One way sync to fabric, will create if the custom pattern does not exist, and update if it does
65 | 8. **Update Patterns and Models**: Refreshes the models and patterns displayed in the dropdowns.
66 |
67 | ### Demonstration
68 |
69 | 
70 | ### Debugging
71 |
72 | Toggle the debug mode in settings to view detailed logs in the console. This can help in tracing issues and understanding the flow of data.
73 |
74 | Contributions are welcome. Please fork the repository, make changes, and submit a pull request for review.
75 |
76 | ## License
77 |
78 | This project is licensed under the MIT License - see the LICENSE file for details.
79 |
80 | ---
81 |
82 | For more information on usage and configuration, refer to the detailed comments within the codebase or visit the [Fabric Plugin Documentation](#).
83 |
--------------------------------------------------------------------------------
/bmc_qr.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/chasebank87/unofficial-fabric-plugin/1a44bb6ab12a234ec23c6f56ebafed069073ffb6/bmc_qr.png
--------------------------------------------------------------------------------
/brain.svg:
--------------------------------------------------------------------------------
1 |
--------------------------------------------------------------------------------
/currentNote-demo.gif:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/chasebank87/unofficial-fabric-plugin/1a44bb6ab12a234ec23c6f56ebafed069073ffb6/currentNote-demo.gif
--------------------------------------------------------------------------------
/esbuild.config.mjs:
--------------------------------------------------------------------------------
1 | import esbuild from "esbuild";
2 | import process from "process";
3 | import builtins from "builtin-modules";
4 |
5 | const banner =
6 | `/*
7 | THIS IS A GENERATED/BUNDLED FILE BY ESBUILD
8 | if you want to view the source, please visit the github repository of this plugin
9 | */
10 | `;
11 |
12 | const prod = (process.argv[2] === "production");
13 |
14 | esbuild.build({
15 | banner: {
16 | js: banner,
17 | },
18 | entryPoints: ["main.ts"],
19 | bundle: true,
20 | external: [
21 | "obsidian",
22 | "electron",
23 | "@codemirror/autocomplete",
24 | "@codemirror/collab",
25 | "@codemirror/commands",
26 | "@codemirror/language",
27 | "@codemirror/lint",
28 | "@codemirror/search",
29 | "@codemirror/state",
30 | "@codemirror/view",
31 | "@lezer/common",
32 | "@lezer/highlight",
33 | "@lezer/lr",
34 | ...builtins],
35 | format: "cjs",
36 | target: "es2018",
37 | logLevel: "info",
38 | sourcemap: prod ? false : "inline",
39 | treeShaking: true,
40 | outfile: "main.js",
41 | }).catch(() => process.exit(1));
--------------------------------------------------------------------------------
/fabric-logo-gif.gif:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/chasebank87/unofficial-fabric-plugin/1a44bb6ab12a234ec23c6f56ebafed069073ffb6/fabric-logo-gif.gif
--------------------------------------------------------------------------------
/main.ts:
--------------------------------------------------------------------------------
1 | import { App, Platform, Plugin, PluginSettingTab, Setting, WorkspaceLeaf, TFile, TFolder, TAbstractFile, Notice, ItemView, MarkdownRenderer, setIcon, Modal, ViewState, ButtonComponent} from 'obsidian';
2 | import { exec } from 'child_process';
3 | import { promisify } from 'util';
4 | import * as path from 'path';
5 | import * as os from 'os';
6 | import * as fuzzaldrin from 'fuzzaldrin-plus';
7 |
8 | const shellEscape = require('shell-escape');
9 | const execAsync = promisify(exec);
10 |
11 | interface FabricPluginSettings {
12 | fabricConnectorApiUrl: string;
13 | fabricConnectorApiKey: string;
14 | outputFolder: string;
15 | customPatternsFolder: string;
16 | youtubeAutodetectEnabled: boolean;
17 | audioFileAutodetectEnabled: boolean;
18 | defaultModel: string;
19 | defaultPostProcessingPattern: string;
20 | debug: boolean;
21 | fabric2: boolean;
22 | tavilyApiKey: string;
23 | }
24 |
25 | const DEFAULT_SETTINGS: FabricPluginSettings = {
26 | fabricConnectorApiUrl: '',
27 | fabricConnectorApiKey: '',
28 | outputFolder: '',
29 | customPatternsFolder: '',
30 | youtubeAutodetectEnabled: true,
31 | audioFileAutodetectEnabled: true,
32 | defaultModel: 'gpt-4o',
33 | defaultPostProcessingPattern: '',
34 | debug: false,
35 | fabric2: false,
36 | tavilyApiKey: ''
37 | };
38 |
39 | export default class FabricPlugin extends Plugin {
40 | settings: FabricPluginSettings;
41 | customPatternsFolder: TFolder | null = null;
42 | patterns: string[] = [];
43 | debug: boolean;
44 |
45 | async onload() {
46 | await this.loadSettings();
47 | this.updateLogging();
48 | await this.checkAndDownloadLogo();
49 | await this.loadSettings();
50 | this.registerCustomPatternsFolderWatcher();
51 |
52 | this.app.workspace.onLayoutReady(() => {
53 | this.registerCustomPatternsFolderWatcher();
54 | });
55 |
56 | this.addCommand({
57 | id: 'open-community-patterns',
58 | name: 'Open Community Patterns',
59 | callback: () => {
60 | new CommunityPatternsModal(this.app, this).open();
61 | }
62 | });
63 |
64 | this.addSettingTab(new FabricSettingTab(this.app, this));
65 |
66 | this.registerView(
67 | 'fabric-view',
68 | (leaf) => new FabricView(
69 | leaf,
70 | this,
71 | this.settings.fabricConnectorApiUrl,
72 | this.settings.fabricConnectorApiKey
73 | )
74 | );
75 |
76 | if (this.app.workspace.layoutReady) {
77 | this.initLeaf();
78 | } else {
79 | this.app.workspace.onLayoutReady(this.initLeaf.bind(this));
80 | }
81 |
82 | this.addRibbonIcon('brain', 'Fabric', () => {
83 | this.activateView();
84 | });
85 | }
86 |
87 | private isLogging = false;
88 |
89 | log(message: string, ...args: any[]) {
90 | if (this.settings.debug && !this.isLogging) {
91 | this.isLogging = true;
92 | console.log(`[Fabric Debug] ${message}`, ...args);
93 | this.isLogging = false;
94 | }
95 | }
96 |
97 | initLeaf(): void {
98 | if (this.app.workspace.getLeavesOfType('fabric-view').length) {
99 | return;
100 | }
101 | const rightLeaf = this.app.workspace.getRightLeaf(false);
102 | if (rightLeaf) {
103 | rightLeaf.setViewState({
104 | type: 'fabric-view',
105 | active: true,
106 | });
107 | }
108 | }
109 |
110 |
111 | updateLogging() {
112 | if (this.settings.debug) {
113 | console.log('[Fabric] Debug mode enabled');
114 | } else {
115 | console.log('[Fabric] Debug mode disabled');
116 | }
117 | }
118 |
119 | async loadSettings() {
120 | this.settings = Object.assign({}, DEFAULT_SETTINGS, await this.loadData());
121 | }
122 |
123 | async saveSettings() {
124 | await this.saveData(this.settings);
125 | }
126 |
127 | registerCustomPatternsFolderWatcher() {
128 | this.log("Registering custom patterns folder watcher");
129 | // Unregister previous watcher if exists
130 | this.app.vault.off('delete', this.handleFileDeletion);
131 |
132 | if (this.settings.customPatternsFolder) {
133 | const folderPath = this.settings.customPatternsFolder.endsWith('/')
134 | ? this.settings.customPatternsFolder
135 | : this.settings.customPatternsFolder + '/';
136 |
137 | this.log(`Watching for deletions in: ${folderPath}`);
138 |
139 | this.registerEvent(
140 | this.app.vault.on('delete', this.handleFileDeletion)
141 | );
142 | } else {
143 | console.warn('Custom patterns folder path not set in settings');
144 | }
145 | }
146 |
147 |
148 | handleFileDeletion = (file: TAbstractFile) => {
149 | this.log(`File deletion detected: ${file.path}`);
150 | this.log(`Custom patterns folder: ${this.settings.customPatternsFolder}`);
151 |
152 | if (!(file instanceof TFile)) {
153 | this.log("Deleted item is not a file");
154 | return;
155 | }
156 |
157 | // Check if the file is directly in the custom patterns folder
158 | const customPatternsPath = this.settings.customPatternsFolder.endsWith('/')
159 | ? this.settings.customPatternsFolder
160 | : this.settings.customPatternsFolder + '/';
161 |
162 | if (!file.path.startsWith(customPatternsPath)) {
163 | this.log("File is not in the custom patterns folder");
164 | return;
165 | }
166 |
167 | if (file.extension !== 'md') {
168 | this.log("File is not a markdown file");
169 | return;
170 | }
171 |
172 | this.log(`Markdown file deleted in custom patterns folder: ${file.path}`);
173 | this.handleCustomPatternDeletion(file.name);
174 | };
175 |
176 | async handleCustomPatternDeletion(fileName: string) {
177 | this.log(`Handling custom pattern deletion for: ${fileName}`);
178 | const patternName = fileName.replace('.md', '');
179 | const confirmDelete = await this.confirmPatternDeletion(patternName);
180 | if (confirmDelete) {
181 | await this.deletePatternFromFabric(patternName);
182 | }
183 | }
184 |
185 | async checkAndDownloadLogo() {
186 | if (!this.manifest.dir) {
187 | console.error('Plugin directory is undefined');
188 | return;
189 | }
190 |
191 | const logoPath = path.join(this.manifest.dir, 'fabric-logo-gif.gif');
192 | const logoExists = await this.app.vault.adapter.exists(logoPath);
193 |
194 | if (!logoExists) {
195 | try {
196 | const logoUrl = 'https://raw.githubusercontent.com/chasebank87/unofficial-fabric-plugin/main/fabric-logo-gif.gif';
197 | const response = await fetch(logoUrl);
198 | if (!response.ok) throw new Error('Failed to fetch logo');
199 | const arrayBuffer = await response.arrayBuffer();
200 | const buffer = new Uint8Array(arrayBuffer);
201 | await this.app.vault.adapter.writeBinary(logoPath, buffer);
202 | this.log('Fabric logo downloaded successfully');
203 | } catch (error) {
204 | console.error('Error downloading Fabric logo:', error);
205 | }
206 | }
207 | }
208 |
209 | async confirmPatternDeletion(patternName: string): Promise {
210 | return new Promise((resolve) => {
211 | const notice = new Notice('', 0);
212 | const container = notice.noticeEl.createDiv('fabric-confirm-deletion');
213 |
214 | container.createEl('h3', { text: 'Confirm Pattern Deletion' });
215 | container.createEl('p', { text: `Do you want to delete the pattern "${patternName}" and its folder from Fabric as well?` });
216 |
217 | const buttonContainer = container.createDiv('fabric-confirm-buttons');
218 |
219 | const yesButton = buttonContainer.createEl('button', { text: 'Yes' });
220 | yesButton.onclick = () => {
221 | notice.hide();
222 | resolve(true);
223 | };
224 |
225 | const noButton = buttonContainer.createEl('button', { text: 'No' });
226 | noButton.onclick = () => {
227 | notice.hide();
228 | resolve(false);
229 | };
230 | });
231 | }
232 |
233 | async deletePatternFromFabric(patternName: string) {
234 | try {
235 | const response = await fetch(this.settings.fabricConnectorApiUrl + '/delete_pattern', {
236 | method: 'POST',
237 | headers: {
238 | 'Content-Type': 'application/json',
239 | 'X-API-Key': this.settings.fabricConnectorApiKey // Add the Fabric Connector API Key here
240 | },
241 | body: JSON.stringify({ pattern: patternName })
242 | });
243 |
244 | if (!response.ok) {
245 | throw new Error(`HTTP error! status: ${response.status}`);
246 | }
247 |
248 | const result = await response.json();
249 | new Notice(result.message);
250 | // Reload patterns after successful deletion
251 | await this.updateFabricView();
252 | } catch (error) {
253 | console.error('Error deleting pattern from Fabric:', error);
254 | new Notice(`Failed to delete pattern "${patternName}" from Fabric.`);
255 | }
256 | }
257 |
258 |
259 | updateFabricView() {
260 | // Find and update the FabricView if it exists
261 | this.app.workspace.iterateAllLeaves((leaf) => {
262 | if (leaf.view instanceof FabricView) {
263 | (leaf.view as FabricView).loadPatterns();
264 | }
265 | });
266 | }
267 |
268 | async getDefaultShell(): Promise {
269 | // Use Platform.isWin instead of os.platform() to detect Windows
270 | if (Platform.isWin) {
271 | return 'cmd.exe';
272 | }
273 | try {
274 | const { stdout } = await execAsync('echo $SHELL');
275 | return stdout.trim();
276 | } catch (error) {
277 | console.error('Failed to detect default shell:', error);
278 | return '/bin/sh'; // Fallback to /bin/sh
279 | }
280 | }
281 |
282 | async activateView() {
283 | this.app.workspace.detachLeavesOfType('fabric-view');
284 |
285 | const rightLeaf = this.app.workspace.getRightLeaf(false);
286 | if (rightLeaf) {
287 | rightLeaf.setViewState({
288 | type: 'fabric-view',
289 | active: true,
290 | });
291 | }
292 |
293 | this.app.workspace.revealLeaf(
294 | this.app.workspace.getLeavesOfType('fabric-view')[0]
295 | );
296 | }
297 | }
298 |
299 |
300 | class FabricView extends ItemView {
301 | plugin: FabricPlugin;
302 | patterns: string[] = [];
303 | patternDropdown: HTMLElement;
304 | searchInput: HTMLInputElement;
305 | outputNoteInput: HTMLInputElement;
306 | selectedOptionIndex: number = -1;
307 | buttonsContainer: HTMLElement;
308 | progressSpinner: HTMLElement;
309 | patternsSyncContainer: HTMLElement;
310 | patternsSyncButton: HTMLElement;
311 | containerEl: HTMLElement;
312 | refreshButton: HTMLElement;
313 | communityPatternsBtn: HTMLElement;
314 | logoContainer: HTMLElement;
315 | loadingText: HTMLElement;
316 | ytSwitch: HTMLInputElement;
317 | ytToggle: HTMLElement;
318 | tsToggle: HTMLElement;
319 | modelSearchInput: HTMLInputElement;
320 | modelDropdown: HTMLElement;
321 | models: string[] = [];
322 | selectedModelIndex: number = -1;
323 | defaultModelDisplay: HTMLElement;
324 | modelNameSpan: HTMLSpanElement;
325 | syncButton: HTMLElement;
326 | fabricConnectorApiUrl: string;
327 | fabricConnectorApiKey: string;
328 | selectedPatterns: string[] = [];
329 |
330 | loadingMessages: string[] = [
331 | "reticulating splines...",
332 | "engaging warp drive...",
333 | "calibrating flux capacitor...",
334 | "compiling techno-babble...",
335 | "reversing the polarity...",
336 | "bypassing the mainframe...",
337 | "initializing neural network...",
338 | "decrypting alien transmissions...",
339 | "charging photon torpedoes...",
340 | "hacking the gibson...",
341 | "Warming flux capacitor...",
342 | "Downloading more RAM...",
343 | "Reversing neutron flow...",
344 | "Initializing sass protocol...",
345 | "Calibrating sarcasm sensors...",
346 | "Bypassing laws of physics...",
347 | "Generating witty message...",
348 | "Spinning hamster wheels...",
349 | "Charging sonic screwdriver...",
350 | "Aligning the stars...",
351 | "Dividing by zero...",
352 | "Upgrading to Windows 9...",
353 | "Searching for life's meaning...",
354 | "Awaiting the Singularity...",
355 | "Tuning alien frequencies...",
356 | "Bending space-time continuum...",
357 | "Compiling crash excuses...",
358 | "Calculating success probability...",
359 | "Rolling for initiative...",
360 | "Initiating self-destruct sequence...",
361 | "Summoning IT gods...",
362 | "Applying warp core tape...",
363 | "Translating binary to dance...",
364 | "Charging Arc Reactor..."
365 | ];
366 |
367 | constructor(leaf: WorkspaceLeaf, plugin: FabricPlugin, fabricConnectorApiUrl: string, fabricConnectorApiKey: string) {
368 | super(leaf);
369 | this.plugin = plugin;
370 | this.fabricConnectorApiUrl = fabricConnectorApiUrl;
371 | this.fabricConnectorApiKey = fabricConnectorApiKey;
372 | }
373 |
374 | getViewType(): string {
375 | return 'fabric-view';
376 | }
377 |
378 | getDisplayText(): string {
379 | return 'Fabric';
380 | }
381 |
382 | showCommunityPatternsModal() {
383 | new CommunityPatternsModal(this.app, this.plugin).open();
384 | }
385 |
386 | async onOpen() {
387 | this.containerEl = this.contentEl;
388 | this.containerEl.empty();
389 | this.containerEl.addClass('fabric-view');
390 |
391 |
392 | this.logoContainer = this.containerEl.createEl('div', { cls: 'fabric-logo-container' });
393 | let logoPath: string;
394 | if (this.plugin.manifest && this.plugin.manifest.dir) {
395 | logoPath = path.join(this.plugin.manifest.dir, 'fabric-logo-gif.gif');
396 | const logoSrc = this.app.vault.adapter.getResourcePath(logoPath);
397 | } else {
398 | // Fallback to the GitHub URL if the plugin directory is undefined
399 | logoPath = 'https://raw.githubusercontent.com/chasebank87/unofficial-fabric-plugin/main/fabric-logo-gif.gif';
400 | }
401 |
402 | const logoSrc = this.app.vault.adapter.getResourcePath(logoPath);
403 | const logo = this.logoContainer.createEl('img', {
404 | cls: 'fabric-logo',
405 | attr: { src: logoSrc }
406 | });
407 | this.loadingText = this.logoContainer.createEl('h6', { cls: 'fabric-loading-text' });
408 |
409 | const contentContainer = this.containerEl.createEl('div', { cls: 'fabric-content' });
410 |
411 | // Add YouTube toggle and icon
412 | const ytToggleContainer = contentContainer.createEl('div', { cls: 'fabric-yt-toggle-container' });
413 |
414 | // Add YouTube toggle and icon
415 | const tsToggleContainer = contentContainer.createEl('div', { cls: 'fabric-ts-toggle-container' });
416 |
417 | // Create toggle for yt
418 | this.ytToggle = ytToggleContainer.createEl('div', {
419 | cls: `fabric-yt-toggle ${this.plugin.settings.youtubeAutodetectEnabled ? 'active' : ''}`
420 | });
421 | const toggleSlider = this.ytToggle.createEl('span', { cls: 'fabric-yt-toggle-slider' });
422 |
423 | // Create text label
424 | const ytLabel = ytToggleContainer.createEl('span', {
425 | cls: 'fabric-yt-label',
426 | text: 'YouTube Links'
427 | });
428 |
429 | // Create toggle for ts
430 | this.tsToggle = tsToggleContainer.createEl('div', {
431 | cls: `fabric-ts-toggle ${this.plugin.settings.audioFileAutodetectEnabled ? 'active' : ''}`
432 | });
433 | const toggleSliderTS = this.tsToggle.createEl('span', { cls: 'fabric-ts-toggle-slider' });
434 |
435 | // Create text label
436 | const tsLabel = tsToggleContainer.createEl('span', {
437 | cls: 'fabric-ts-label',
438 | text: 'Audio Files'
439 | });
440 |
441 |
442 | contentContainer.createEl('h3', { text: 'fabric', cls: 'fabric-title' });
443 |
444 | this.buttonsContainer = contentContainer.createEl('div', { cls: 'fabric-buttons' });
445 | const currentNoteBtn = this.buttonsContainer.createEl('button', { text: 'Current note', cls: 'fabric-button current-note' });
446 | const clipboardBtn = this.buttonsContainer.createEl('button', { text: 'Clipboard', cls: 'fabric-button clipboard' });
447 |
448 | const tavilyBtn = this.buttonsContainer.createEl('button', { text: 'Tavily', cls: 'fabric-button tavily' });
449 |
450 | tavilyBtn.onclick = () => this.showTavilySearchModal();
451 | currentNoteBtn.onclick = () => this.runFabric('current');
452 | clipboardBtn.onclick = () => this.runFabric('clipboard');
453 |
454 |
455 | const inputsContainer = contentContainer.createEl('div', { cls: 'fabric-inputs-container' });
456 |
457 | this.outputNoteInput = inputsContainer.createEl('input', {
458 | cls: 'fabric-input',
459 | attr: { type: 'text', placeholder: 'Output note name' }
460 | });
461 |
462 | this.searchInput = inputsContainer.createEl('input', {
463 | cls: 'fabric-input',
464 | attr: { type: 'text', placeholder: 'Search patterns...' }
465 | });
466 |
467 | this.modelSearchInput = inputsContainer.createEl('input', {
468 | cls: 'fabric-input',
469 | attr: {
470 | type: 'text',
471 | placeholder: 'Search models...',
472 | }
473 |
474 | });
475 |
476 | this.patternDropdown = contentContainer.createEl('div', { cls: 'fabric-dropdown' , attr: { id: 'pattern-dropdown', multiple: 'true' }} );
477 | this.modelDropdown = contentContainer.createEl('div', { cls: 'fabric-dropdown', attr: { id: 'model-dropdown' }});
478 |
479 | this.searchInput.addEventListener('blur', () => {
480 | // Use setTimeout to allow click events on dropdown options to fire first
481 | setTimeout(() => {
482 | this.patternDropdown.empty();
483 | this.selectedOptionIndex = -1;
484 | }, 200);
485 | });
486 |
487 | this.searchInput.addEventListener('input', () => {
488 | const inputValue = this.searchInput.value;
489 | const patterns = inputValue.split(',').map(p => p.trim()).filter(p => p !== '');
490 |
491 | // The last item might be a partial search term, so we exclude it from selected patterns
492 | const selectedPatterns = patterns.slice(0, -1);
493 | const searchTerm = patterns[patterns.length - 1] || '';
494 |
495 | // Update selectedPatterns, ensuring no more than 5 are selected
496 | this.selectedPatterns = selectedPatterns.slice(0, 5);
497 |
498 | // Update the dropdown options based on the search term
499 | this.updatePatternOptions(searchTerm.toLowerCase());
500 | });
501 |
502 | this.modelSearchInput.addEventListener('input', () => {
503 | this.updateModelOptions(this.modelSearchInput.value.toLowerCase());
504 | this.updatePoweredByText(this.modelSearchInput.value);
505 | });
506 |
507 | this.searchInput.addEventListener('keydown', (event) => {
508 | this.handlePatternDropdownNavigation(event, this.patternDropdown, this.searchInput);
509 | });
510 |
511 | this.modelSearchInput.addEventListener('keydown', (event) => {
512 | this.handleDropdownNavigation(event, this.modelDropdown, this.modelSearchInput);
513 | });
514 |
515 | // Create the default model display
516 | this.defaultModelDisplay = contentContainer.createEl('div', { cls: 'fabric-default-model' });
517 | this.defaultModelDisplay.createSpan({ text: 'Powered by ' });
518 | this.modelNameSpan = this.defaultModelDisplay.createSpan({ cls: 'model-name' });
519 | this.updatePoweredByText(this.plugin.settings.defaultModel || 'No default model set');
520 |
521 | this.searchInput.addEventListener('focus', () => {
522 | this.searchInput.classList.add('active');
523 | });
524 |
525 | this.searchInput.addEventListener('blur', () => {
526 | this.searchInput.classList.remove('active');
527 | });
528 |
529 | this.outputNoteInput.addEventListener('focus', () => {
530 | this.outputNoteInput.classList.add('active');
531 | });
532 |
533 | this.outputNoteInput.addEventListener('blur', () => {
534 | this.outputNoteInput.classList.remove('active');
535 | });
536 |
537 | this.ytToggle.addEventListener('click', () => {
538 | this.ytToggle.classList.toggle('active');
539 | this.plugin.settings.youtubeAutodetectEnabled = this.ytToggle.classList.contains('active');
540 | this.plugin.saveSettings();
541 | if (this.plugin.settings.youtubeAutodetectEnabled) {
542 | new Notice('YouTube link detection enabled');
543 | } else {
544 | new Notice('YouTube link detection disabled');
545 | }
546 | });
547 |
548 | this.tsToggle.addEventListener('click', () => {
549 | this.tsToggle.classList.toggle('active');
550 | this.plugin.settings.audioFileAutodetectEnabled = this.tsToggle.classList.contains('active');
551 | this.plugin.saveSettings();
552 | if (this.plugin.settings.audioFileAutodetectEnabled) {
553 | new Notice('Audio file detection enabled');
554 | } else {
555 | new Notice('Audio file link detection disabled');
556 | }
557 | });
558 |
559 | // Modify the click handlers for currentNoteBtn and clipboardBtn
560 | currentNoteBtn.onclick = () => this.handleFabricRun('current');
561 | clipboardBtn.onclick = () => this.handleFabricRun('clipboard');
562 |
563 |
564 | const buttonContainer = contentContainer.createEl('div', { cls: 'fabric-button-container' });
565 |
566 | this.refreshButton = buttonContainer.createEl('button', {
567 | cls: 'fabric-icon-button fabric-refresh-button',
568 | attr: {
569 | 'aria-label': 'Refresh patterns and models'
570 | }
571 | });
572 | setIcon(this.refreshButton, 'refresh-cw');
573 | this.refreshButton.onclick = async () => {
574 | await this.loadPatterns();
575 | await this.loadModels();
576 | new Notice('Patterns and models refreshed');
577 | };
578 |
579 | this.syncButton = buttonContainer.createEl('button', {
580 | cls: 'fabric-icon-button fabric-sync-button',
581 | attr: {
582 | 'aria-label': 'Sync custom patterns'
583 | }
584 | });
585 | setIcon(this.syncButton, 'upload-cloud');
586 | this.syncButton.onclick = async () => {
587 | await this.syncCustomPatterns();
588 | };
589 |
590 | this.communityPatternsBtn = contentContainer.createEl('button', {
591 | cls: 'fabric-icon-button community-patterns',
592 | attr: {
593 | 'aria-label': 'Download community patterns'
594 | }
595 | });
596 | setIcon(this.communityPatternsBtn, 'download');
597 |
598 | this.communityPatternsBtn.onclick = () => this.showCommunityPatternsModal();
599 |
600 |
601 |
602 | this.progressSpinner = contentContainer.createEl('div', { cls: 'fabric-progress-spinner' });
603 |
604 |
605 | await this.loadPatterns();
606 | await this.loadModels();
607 | this.updatePatternOptions('');
608 | this.updateModelOptions('');
609 | this.searchInput.focus();
610 | }
611 |
612 | showTavilySearchModal() {
613 | const pattern = this.searchInput.value.trim();
614 | const model = this.getCurrentModel();
615 |
616 | if (!model) {
617 | new Notice('Please select a model or set a default model in settings before running.');
618 | return;
619 | }
620 |
621 | if (!pattern) {
622 | new Notice('Please select a pattern first');
623 | return;
624 | }
625 |
626 | const modal = new Modal(this.app);
627 | modal.titleEl.setText('Tavily Search');
628 | const { contentEl } = modal;
629 | contentEl.addClass('fabric-tavily-modal');
630 | const searchInput = contentEl.createEl('input', {
631 | type: 'text',
632 | placeholder: 'Enter your search query'
633 | });
634 | searchInput.addClass('fabric-tavily-input');
635 |
636 | const searchButton = contentEl.createEl('button', {
637 | text: 'Search',
638 | cls: 'mod-cta'
639 | });
640 |
641 | searchButton.addClass('fabric-tavily-search-button');
642 |
643 | searchButton.onclick = async () => {
644 | const query = searchInput.value.trim();
645 | if (query) {
646 | modal.close();
647 | await this.performTavilySearch(query);
648 | } else {
649 | new Notice('Please enter a search query');
650 | }
651 | };
652 |
653 | modal.open();
654 | }
655 |
656 | async performTavilySearch(query: string) {
657 | this.logoContainer.addClass('loading');
658 | this.loadingText.setText('');
659 | this.animateLoadingText('Searching Tavily...');
660 |
661 | try {
662 | const response = await fetch('https://api.tavily.com/search', {
663 | method: 'POST',
664 | headers: {
665 | 'Content-Type': 'application/json'
666 | },
667 | body: JSON.stringify({
668 | query: query,
669 | include_answer: true,
670 | max_results: 5,
671 | include_images: true,
672 | search_depth: "basic",
673 | api_key: this.plugin.settings.tavilyApiKey
674 | })
675 | });
676 |
677 | if (!response.ok) {
678 | throw new Error(`HTTP error! status: ${response.status}`);
679 | }
680 |
681 | const data = await response.json();
682 | const searchResult = JSON.stringify(data) + '\n';
683 | await this.runFabricWithTavilyResult(searchResult);
684 | } catch (error) {
685 | console.error('Failed to perform Tavily search:', error);
686 | new Notice('Failed to perform Tavily search. Please check your API key and try again.');
687 | } finally {
688 | this.logoContainer.removeClass('loading');
689 | this.loadingText.setText('');
690 | }
691 | }
692 |
693 | async runFabricWithTavilyResult(searchResult: string) {
694 | if (this.plugin.settings.defaultPostProcessingPattern) {
695 | this.selectedPatterns.push(this.plugin.settings.defaultPostProcessingPattern);
696 | }
697 | const pattern = this.selectedPatterns;
698 | const model = this.getCurrentModel();
699 | let outputNoteName = this.outputNoteInput.value.trim();
700 |
701 | if (!model) {
702 | new Notice('Please select a model or set a default model in settings before running.');
703 | return;
704 | }
705 |
706 | if (!pattern) {
707 | new Notice('Please select a pattern first');
708 | return;
709 | }
710 |
711 | try {
712 | const response = await fetch(this.plugin.settings.fabricConnectorApiUrl + '/fabric', {
713 | method: 'POST',
714 | headers: {
715 | 'Content-Type': 'application/json',
716 | 'Accept': 'application/json',
717 | 'X-API-Key': this.plugin.settings.fabricConnectorApiKey
718 | },
719 | body: JSON.stringify({
720 | pattern: pattern,
721 | model: model,
722 | data: searchResult,
723 | stream: true,
724 | goCompatibility: this.plugin.settings.fabric2
725 | })
726 | });
727 |
728 | if (!response.ok) {
729 | throw new Error(`HTTP error! status: ${response.status}`);
730 | }
731 |
732 | const responseData = await response.json();
733 | const output = responseData.output;
734 |
735 | const newFile = await this.createOutputNote(output, outputNoteName);
736 | new Notice('Fabric output generated successfully with Tavily search result');
737 | } catch (error) {
738 | console.error('Failed to run fabric with Tavily result:', error);
739 | new Notice('Failed to run fabric with Tavily result. Please check your settings and try again.');
740 | }
741 | }
742 |
743 | async runFabric(source: 'current' | 'clipboard' | 'pattern') {
744 | let data = '';
745 | let pattern = this.selectedPatterns;
746 | let outputNoteName = this.outputNoteInput.value.trim();
747 | const model = this.getCurrentModel();
748 |
749 | if (!model) {
750 | new Notice('Please select a model or set a default model in settings before running.');
751 | return;
752 | }
753 |
754 | if (source === 'current') {
755 | const activeFile = this.app.workspace.getActiveFile();
756 | if (activeFile) {
757 | data = await this.app.vault.read(activeFile) + '\n';
758 | }
759 | } else if (source === 'clipboard') {
760 | data = await navigator.clipboard.readText() + '\n';
761 | } else if (source === 'pattern') {
762 | if (!pattern) {
763 | new Notice('Please select a pattern first');
764 | return;
765 | }
766 | }
767 |
768 | this.logoContainer.addClass('loading');
769 | this.loadingText.setText('');
770 | this.animateLoadingText(this.getRandomLoadingMessage());
771 | try {
772 | const response = await fetch(this.plugin.settings.fabricConnectorApiUrl + '/fabric', {
773 | method: 'POST',
774 | headers: {
775 | 'Content-Type': 'application/json',
776 | 'Accept': 'application/json',
777 | 'X-API-Key': this.plugin.settings.fabricConnectorApiKey
778 | },
779 | body: JSON.stringify({
780 | pattern: pattern,
781 | model: model,
782 | data: data,
783 | stream: true,
784 | goCompatibility: this.plugin.settings.fabric2
785 | })
786 | });
787 |
788 | if (!response.ok) {
789 | throw new Error(`HTTP error! status: ${response.status}`);
790 | }
791 |
792 | const responseData = await response.json();
793 | const output = responseData.output;
794 |
795 | const newFile = await this.createOutputNote(output, outputNoteName);
796 | this.logoContainer.removeClass('loading');
797 | this.loadingText.setText('');
798 | new Notice('Fabric output generated successfully');
799 | } catch (error) {
800 | console.error('Failed to run fabric:', error);
801 | this.logoContainer.removeClass('loading');
802 | this.loadingText.setText('');
803 | new Notice('Failed to run fabric. Please check your settings and try again.');
804 | }
805 | }
806 |
807 | getRandomLoadingMessage(): string {
808 | return this.loadingMessages[Math.floor(Math.random() * this.loadingMessages.length)];
809 | }
810 |
811 | animateLoadingText(text: string) {
812 | let i = 0;
813 | const intervalId = setInterval(() => {
814 | if (!this.logoContainer.hasClass('loading')) {
815 | clearInterval(intervalId);
816 | return;
817 | }
818 | if (i < text.length) {
819 | this.loadingText.setText(this.loadingText.getText() + text[i]);
820 | i++;
821 | } else {
822 | setTimeout(() => {
823 | this.loadingText.setText('');
824 | i = 0;
825 | }, 1000); // Pause for a second before restarting
826 | }
827 | }, 100); // Adjust this value to change the typing speed
828 | }
829 |
830 | async createOutputNote(content: string, noteName: string): Promise {
831 | let fileName = `${noteName}.md`;
832 | let filePath = path.join(this.plugin.settings.outputFolder, fileName);
833 | let fileExists = await this.app.vault.adapter.exists(filePath);
834 | let counter = 1;
835 |
836 | while (fileExists) {
837 | fileName = `${noteName} (${counter}).md`;
838 | filePath = path.join(this.plugin.settings.outputFolder, fileName);
839 | fileExists = await this.app.vault.adapter.exists(filePath);
840 | counter++;
841 | }
842 |
843 | const newFile = await this.app.vault.create(filePath, content);
844 |
845 | // Get the most recently focused leaf in the main workspace
846 | const activeLeaf = this.app.workspace.getMostRecentLeaf();
847 |
848 | if (activeLeaf && !activeLeaf.getViewState().pinned) {
849 | // If there's an active leaf and it's not pinned, create a new leaf in split
850 | const newLeaf = this.app.workspace.createLeafBySplit(activeLeaf, 'vertical');
851 | await newLeaf.openFile(newFile);
852 | } else {
853 | // If there's no active leaf or it's pinned, create a new leaf
854 | const newLeaf = this.app.workspace.getLeaf('tab');
855 | await newLeaf.openFile(newFile);
856 | }
857 |
858 | return newFile;
859 | }
860 |
861 |
862 |
863 |
864 | updatePatternOptions(query: string) {
865 | this.patternDropdown.empty();
866 | this.selectedOptionIndex = -1;
867 |
868 | const filteredPatterns = query
869 | ? fuzzaldrin.filter(this.patterns, query)
870 | : this.patterns;
871 |
872 | if (filteredPatterns.length === 0) {
873 | this.patternDropdown.createEl('div', {
874 | cls: 'fabric-dropdown-option',
875 | text: 'No patterns found'
876 | });
877 | } else {
878 | filteredPatterns.forEach((pattern, index) => {
879 | this.addPatternOption(pattern, index);
880 | });
881 | }
882 |
883 | if (this.patternDropdown.children.length > 0) {
884 | this.selectedOptionIndex = 0;
885 | this.updateSelectedOption(this.patternDropdown.querySelectorAll('.fabric-dropdown-option'));
886 | }
887 | }
888 |
889 |
890 | private addPatternOption(pattern: string, index: number) {
891 | const option = this.patternDropdown.createEl('div', {
892 | cls: `fabric-dropdown-option ${index === 0 ? 'selected' : ''}`,
893 | text: pattern
894 | });
895 |
896 | option.addEventListener('mousedown', (event) => {
897 | // Prevent the default behavior which would trigger the blur event
898 | event.preventDefault();
899 | });
900 |
901 | option.addEventListener('click', (event) => {
902 | event.preventDefault();
903 | this.selectPattern(pattern);
904 | // Refocus on the input after selection
905 | this.searchInput.focus();
906 | });
907 | }
908 |
909 | private selectPattern(pattern: string) {
910 | if (this.selectedPatterns.length >= 5 && !this.selectedPatterns.includes(pattern)) {
911 | new Notice('You can only select up to 5 patterns.');
912 | return;
913 | }
914 |
915 | if (!this.selectedPatterns.includes(pattern)) {
916 | this.selectedPatterns.push(pattern);
917 | }
918 |
919 | this.searchInput.value = this.selectedPatterns.join(', ') + (this.selectedPatterns.length > 0 ? ', ' : '');
920 | this.updatePatternOptions('');
921 | this.searchInput.focus();
922 |
923 | // Set cursor position to the end
924 | const len = this.searchInput.value.length;
925 | this.searchInput.setSelectionRange(len, len);
926 | }
927 |
928 | private updateSelectedOption(options: NodeListOf) {
929 | options.forEach((option, index) => {
930 | if (index === this.selectedOptionIndex) {
931 | option.classList.add('selected');
932 | option.scrollIntoView({ block: 'nearest' });
933 | } else {
934 | option.classList.remove('selected');
935 | }
936 | });
937 | }
938 |
939 | updateModelOptions(query: string) {
940 | this.modelDropdown.empty();
941 | this.selectedModelIndex = -1;
942 |
943 | if (query === '') return;
944 |
945 | const filteredModels = fuzzaldrin.filter(this.models, query);
946 |
947 | if (filteredModels.length === 0 && query !== '') {
948 | this.modelDropdown.createEl('div', {
949 | cls: 'fabric-dropdown-option',
950 | text: 'No models found'
951 | });
952 | } else {
953 | filteredModels.forEach((model, index) => {
954 | const option = this.modelDropdown.createEl('div', {
955 | cls: `fabric-dropdown-option ${index === 0 ? 'selected' : ''}`,
956 | text: model
957 | });
958 | option.addEventListener('click', () => {
959 | this.selectModel(model);
960 | });
961 | });
962 | this.selectedModelIndex = 0;
963 | }
964 | }
965 |
966 | selectModel(model: string) {
967 | this.modelSearchInput.value = model;
968 | this.modelDropdown.empty();
969 | this.updatePoweredByText(model);
970 | }
971 |
972 | updatePoweredByText(model: string) {
973 | const displayModel = model || this.plugin.settings.defaultModel || 'No model selected';
974 |
975 | if (this.modelNameSpan.textContent !== displayModel) {
976 | this.modelNameSpan.setText(displayModel);
977 | this.modelNameSpan.addClass('updating');
978 |
979 | setTimeout(() => {
980 | this.modelNameSpan.removeClass('updating');
981 | }, 500); // This should match the animation duration
982 | }
983 | }
984 |
985 | updateDefaultModelDisplay() {
986 | this.updatePoweredByText(this.modelSearchInput.value);
987 | }
988 |
989 | getCurrentModel(): string {
990 | return this.modelSearchInput.value || this.plugin.settings.defaultModel;
991 | }
992 |
993 | async loadModels() {
994 | try {
995 | const url = new URL(this.plugin.settings.fabricConnectorApiUrl + '/models');
996 | url.searchParams.append('goCompatibility', this.plugin.settings.fabric2.toString());
997 | const response = await fetch(url, {
998 | method: 'GET',
999 | headers: {
1000 | 'Content-Type': 'application/json',
1001 | 'X-API-Key': this.plugin.settings.fabricConnectorApiKey
1002 | }
1003 | });
1004 | if (!response.ok) {
1005 | throw new Error(`HTTP error! status: ${response.status}`);
1006 | }
1007 | const data = await response.json();
1008 | this.models = data.data.models.map((model: { name: any; }) => model.name);
1009 | this.plugin.log('Models loaded:', this.models);
1010 | this.updateDefaultModelDisplay();
1011 | } catch (error) {
1012 | this.plugin.log('Failed to load models from API:', error);
1013 | new Notice('Failed to load models. Please check the API server.');
1014 | }
1015 | }
1016 |
1017 | handleDropdownNavigation(event: KeyboardEvent, dropdown: HTMLElement, input: HTMLInputElement) {
1018 | switch (event.key) {
1019 | case 'ArrowDown':
1020 | event.preventDefault();
1021 | this.navigateDropdownOptions(1, dropdown);
1022 | break;
1023 | case 'ArrowUp':
1024 | event.preventDefault();
1025 | this.navigateDropdownOptions(-1, dropdown);
1026 | break;
1027 | case 'Enter':
1028 | event.preventDefault();
1029 | this.selectCurrentOption(dropdown, input);
1030 | break;
1031 | }
1032 | }
1033 |
1034 | handlePatternDropdownNavigation(event: KeyboardEvent, dropdown: HTMLElement, input: HTMLInputElement) {
1035 | const options = dropdown.querySelectorAll('.fabric-dropdown-option');
1036 |
1037 | switch (event.key) {
1038 | case 'ArrowDown':
1039 | event.preventDefault();
1040 | this.selectedOptionIndex = Math.min(this.selectedOptionIndex + 1, options.length - 1);
1041 | this.updateSelectedOption(options);
1042 | break;
1043 | case 'ArrowUp':
1044 | event.preventDefault();
1045 | this.selectedOptionIndex = Math.max(this.selectedOptionIndex - 1, 0);
1046 | this.updateSelectedOption(options);
1047 | break;
1048 | case 'Enter':
1049 | event.preventDefault();
1050 | if (this.selectedOptionIndex >= 0 && this.selectedOptionIndex < options.length) {
1051 | const selectedPattern = options[this.selectedOptionIndex].textContent;
1052 | if (selectedPattern) {
1053 | this.selectPattern(selectedPattern);
1054 | // Keep the dropdown open
1055 | this.updatePatternOptions('');
1056 | }
1057 | }
1058 | break;
1059 | case 'Escape':
1060 | event.preventDefault();
1061 | dropdown.empty();
1062 | this.selectedOptionIndex = -1;
1063 | break;
1064 | }
1065 | }
1066 |
1067 |
1068 | navigateDropdownOptions(direction: number, dropdown: HTMLElement) {
1069 | const options = Array.from(dropdown.children) as HTMLElement[];
1070 | const optionsCount = options.length;
1071 |
1072 | if (optionsCount === 0) return;
1073 |
1074 | const currentIndex = dropdown === this.patternDropdown ? this.selectedOptionIndex : this.selectedModelIndex;
1075 | const newIndex = (currentIndex + direction + optionsCount) % optionsCount;
1076 |
1077 | options.forEach((option, index) => {
1078 | if (index === newIndex) {
1079 | option.classList.add('selected');
1080 | } else {
1081 | option.classList.remove('selected');
1082 | }
1083 | });
1084 |
1085 | if (dropdown === this.patternDropdown) {
1086 | this.selectedOptionIndex = newIndex;
1087 | } else {
1088 | this.selectedModelIndex = newIndex;
1089 | }
1090 | }
1091 |
1092 | selectCurrentOption(dropdown: HTMLElement, input: HTMLInputElement) {
1093 | const index = dropdown === this.modelDropdown ? this.selectedModelIndex : this.selectedOptionIndex;
1094 | const selectedOption = dropdown.children[index] as HTMLElement;
1095 | if (selectedOption) {
1096 | const value = selectedOption.textContent!;
1097 | if (dropdown === this.modelDropdown) {
1098 | this.selectModel(value);
1099 | } else {
1100 | input.value = value;
1101 | dropdown.empty();
1102 | }
1103 | }
1104 | }
1105 |
1106 | async loadPatterns() {
1107 | try {
1108 | const url = new URL(this.plugin.settings.fabricConnectorApiUrl + '/patterns');
1109 | url.searchParams.append('goCompatibility', this.plugin.settings.fabric2.toString());
1110 | const response = await fetch(url, {
1111 | method: 'GET',
1112 | headers: {
1113 | 'Content-Type': 'application/json',
1114 | 'X-API-Key': this.plugin.settings.fabricConnectorApiKey
1115 | },
1116 | });
1117 | if (!response.ok) {
1118 | throw new Error(`HTTP error! status: ${response.status}`);
1119 | }
1120 | const data = await response.json();
1121 | // Extract pattern names from the JSON structure
1122 | this.patterns = data.data.patterns.map((pattern: { name: any; }) => pattern.name);
1123 | this.plugin.log('Patterns loaded:', this.patterns);
1124 | } catch (error) {
1125 | this.plugin.log('Failed to load patterns from API:', error);
1126 | new Notice('Failed to load patterns. Please check the API server.');
1127 | }
1128 | }
1129 |
1130 | async handleFabricRun(source: 'current' | 'clipboard') {
1131 | if (this.plugin.settings.defaultPostProcessingPattern) {
1132 | this.selectedPatterns.push(this.plugin.settings.defaultPostProcessingPattern);
1133 | }
1134 | if (this.ytToggle.classList.contains('active') && this.tsToggle.classList.contains('active')) {
1135 | const links = await this.extractYouTubeLinks(source);
1136 | const paths = await this.extractAudioFiles(source);
1137 | if (links.length > 0 && paths.length > 0) {
1138 | new Notice('Both YouTube links and audio files found. This is not supported yet. Try using clipboard.');
1139 | this.runFabric(source);
1140 | return;
1141 | }
1142 | if (links.length > 0) {
1143 | this.showYouTubeModal(links, source);
1144 | } else if (paths.length > 0) {
1145 | this.showAudioModal(paths, source);
1146 | } else {
1147 | new Notice('No YouTube links or audio files found. Running Fabric normally.');
1148 | this.runFabric(source);
1149 | }
1150 | } else if (this.tsToggle.classList.contains('active')) {
1151 | const links = await this.extractAudioFiles(source);
1152 | if (links.length > 0) {
1153 | this.showAudioModal(links, source);
1154 | } else {
1155 | new Notice('No audio files found. Running Fabric normally.');
1156 | this.runFabric(source);
1157 | }
1158 | } else if (this.ytToggle.classList.contains('active')) {
1159 | const links = await this.extractYouTubeLinks(source);
1160 | if (links.length > 0) {
1161 | this.showYouTubeModal(links, source);
1162 | } else {
1163 | new Notice('No YouTube links found. Running Fabric normally.');
1164 | this.runFabric(source);
1165 | }
1166 | } else {
1167 | this.runFabric(source);
1168 | }
1169 | }
1170 |
1171 | async extractYouTubeLinks(source: 'current' | 'clipboard'): Promise {
1172 | let text = '';
1173 | if (source === 'current') {
1174 | const activeFile = this.app.workspace.getActiveFile();
1175 | if (activeFile) {
1176 | text = await this.app.vault.read(activeFile);
1177 | }
1178 | } else {
1179 | text = await navigator.clipboard.readText();
1180 | }
1181 | const youtubeRegex = /(?:https?:\/\/)?(?:www\.)?(?:youtube\.com|youtu\.be)\/(?:watch\?v=)?(?:embed\/)?(?:v\/)?(?:shorts\/)?(?:\S+)/g;
1182 | return text.match(youtubeRegex) || [];
1183 | }
1184 |
1185 | async extractAudioFiles(source: 'current' | 'clipboard'): Promise {
1186 | let text = '';
1187 | if (source === 'current') {
1188 | const activeFile = this.app.workspace.getActiveFile();
1189 | if (activeFile) {
1190 | text = await this.app.vault.read(activeFile);
1191 | }
1192 | } else {
1193 | text = await navigator.clipboard.readText();
1194 | }
1195 | const audioRegex = /(?:^|[\s(])?(?:")?(?:\/|[a-zA-Z]:[\\/])(?:[^"\n\r]*[\\/])*[^"\n\r]*\.(?:mp3|wav|ogg|aac|flac|mp4|mkv|webm|avi|mov|flv)(?:")?(?:\s|$)/gi;
1196 | return text.match(audioRegex) || [];
1197 | }
1198 |
1199 | showYouTubeModal(links: string[], source: 'current' | 'clipboard') {
1200 | const modal = new Modal(this.app);
1201 | modal.titleEl.setText('Select YouTube Link');
1202 | const { contentEl } = modal;
1203 |
1204 | let selectedIndex = 0;
1205 |
1206 | const linkList = contentEl.createEl('div', { cls: 'fabric-yt-link-list' });
1207 |
1208 | const updateSelection = () => {
1209 | linkList.querySelectorAll('.fabric-yt-link').forEach((el, index) => {
1210 | el.classList.toggle('is-selected', index === selectedIndex);
1211 | });
1212 | };
1213 |
1214 | links.forEach((link, index) => {
1215 | const linkEl = linkList.createEl('div', { cls: 'fabric-yt-link', text: link });
1216 | linkEl.addEventListener('click', () => {
1217 | selectedIndex = index;
1218 | updateSelection();
1219 | });
1220 | });
1221 |
1222 | const buttonContainer = contentEl.createEl('div', { cls: 'fabric-yt-modal-buttons' });
1223 | const skipButton = buttonContainer.createEl('button', { text: 'Skip' });
1224 | skipButton.addClass('skip-button');
1225 | const runYTButton = buttonContainer.createEl('button', { text: 'Run' });
1226 | runYTButton.addClass('run-button');
1227 |
1228 | skipButton.addEventListener('click', () => {
1229 | modal.close();
1230 | this.runFabric(source);
1231 | });
1232 |
1233 | runYTButton.addEventListener('click', () => {
1234 | modal.close();
1235 | if (links.length > 0) {
1236 | this.runYT(links[selectedIndex]);
1237 | } else {
1238 | new Notice('No YouTube links found');
1239 | }
1240 | });
1241 |
1242 | modal.onOpen = () => {
1243 | updateSelection();
1244 |
1245 | const handleKeyDown = (event: KeyboardEvent) => {
1246 | switch (event.key) {
1247 | case 'ArrowUp':
1248 | selectedIndex = (selectedIndex - 1 + links.length) % links.length;
1249 | updateSelection();
1250 | event.preventDefault();
1251 | break;
1252 | case 'ArrowDown':
1253 | selectedIndex = (selectedIndex + 1) % links.length;
1254 | updateSelection();
1255 | event.preventDefault();
1256 | break;
1257 | case 'Enter':
1258 | modal.close();
1259 | this.runYT(links[selectedIndex]);
1260 | event.preventDefault();
1261 | break;
1262 | }
1263 | };
1264 |
1265 | document.addEventListener('keydown', handleKeyDown);
1266 | modal.onClose = () => {
1267 | document.removeEventListener('keydown', handleKeyDown);
1268 | };
1269 | };
1270 |
1271 | modal.open();
1272 | }
1273 |
1274 | showAudioModal(files: string[], source: 'current' | 'clipboard') {
1275 | const modal = new Modal(this.app);
1276 | modal.titleEl.setText('Select Audio File Path');
1277 | const { contentEl } = modal;
1278 |
1279 | let selectedIndex = 0;
1280 |
1281 | const fileList = contentEl.createEl('div', { cls: 'fabric-ts-link-list' });
1282 |
1283 | const updateSelection = () => {
1284 | fileList.querySelectorAll('.fabric-ts-link').forEach((el, index) => {
1285 | el.classList.toggle('is-selected', index === selectedIndex);
1286 | });
1287 | };
1288 |
1289 | files.forEach((file, index) => {
1290 | const linkEl = fileList.createEl('div', { cls: 'fabric-ts-link', text: file });
1291 | linkEl.addEventListener('click', () => {
1292 | selectedIndex = index;
1293 | updateSelection();
1294 | });
1295 | });
1296 |
1297 | const buttonContainer = contentEl.createEl('div', { cls: 'fabric-ts-modal-buttons' });
1298 | const skipButton = buttonContainer.createEl('button', { text: 'Skip' });
1299 | skipButton.addClass('skip-button');
1300 | const runTSButton = buttonContainer.createEl('button', { text: 'Run' });
1301 | runTSButton.addClass('run-button');
1302 |
1303 | skipButton.addEventListener('click', () => {
1304 | modal.close();
1305 | this.runTS(source);
1306 | });
1307 |
1308 | runTSButton.addEventListener('click', () => {
1309 | modal.close();
1310 | if (files.length > 0) {
1311 | this.runTS(files[selectedIndex]);
1312 | } else {
1313 | new Notice('No audio files found');
1314 | }
1315 | });
1316 |
1317 | modal.onOpen = () => {
1318 | updateSelection();
1319 |
1320 | const handleKeyDown = (event: KeyboardEvent) => {
1321 | switch (event.key) {
1322 | case 'ArrowUp':
1323 | selectedIndex = (selectedIndex - 1 + files.length) % files.length;
1324 | updateSelection();
1325 | event.preventDefault();
1326 | break;
1327 | case 'ArrowDown':
1328 | selectedIndex = (selectedIndex + 1) % files.length;
1329 | updateSelection();
1330 | event.preventDefault();
1331 | break;
1332 | case 'Enter':
1333 | modal.close();
1334 | this.runTS(files[selectedIndex]);
1335 | event.preventDefault();
1336 | break;
1337 | }
1338 | };
1339 |
1340 | document.addEventListener('keydown', handleKeyDown);
1341 | modal.onClose = () => {
1342 | document.removeEventListener('keydown', handleKeyDown);
1343 | };
1344 | };
1345 |
1346 | modal.open();
1347 | }
1348 |
1349 |
1350 | async runYT(url: string) {
1351 | let outputNoteName = this.outputNoteInput.value.trim();
1352 | const pattern = this.selectedPatterns
1353 | const model = this.getCurrentModel();
1354 |
1355 | if (!model) {
1356 | new Notice('Please select a model or set a default model in settings before running.');
1357 | return;
1358 | }
1359 |
1360 | if (!pattern) {
1361 | new Notice('Please select a pattern first');
1362 | return;
1363 | }
1364 |
1365 | this.logoContainer.addClass('loading');
1366 | this.loadingText.setText('');
1367 | this.animateLoadingText(this.getRandomLoadingMessage());
1368 |
1369 |
1370 | try {
1371 | const response = await fetch(this.plugin.settings.fabricConnectorApiUrl + '/yt', {
1372 | method: 'POST',
1373 | headers: {
1374 | 'Content-Type': 'application/json',
1375 | 'X-API-Key': this.plugin.settings.fabricConnectorApiKey
1376 | },
1377 | body: JSON.stringify({
1378 | pattern: pattern,
1379 | model: model,
1380 | url: url,
1381 | stream: true,
1382 | goCompatibility: this.plugin.settings.fabric2
1383 | }),
1384 | });
1385 |
1386 | if (!response.ok) {
1387 | throw new Error(`HTTP error! status: ${response.status}`);
1388 | }
1389 |
1390 | const data = await response.json();
1391 | const output = data.output;
1392 |
1393 | const newFile = await this.createOutputNote(output, outputNoteName);
1394 | this.logoContainer.removeClass('loading');
1395 | this.loadingText.setText('');
1396 | new Notice('YouTube Fabric output generated successfully');
1397 | } catch (error) {
1398 | console.error('Failed to run YouTube Fabric:', error);
1399 | new Notice('Failed to run YouTube Fabric. Please check your settings and try again.');
1400 | }
1401 | }
1402 |
1403 | async runTS(path: string) {
1404 | let outputNoteName = this.outputNoteInput.value.trim();
1405 | const pattern = this.selectedPatterns
1406 | const model = this.getCurrentModel();
1407 |
1408 | if (!model) {
1409 | new Notice('Please select a model or set a default model in settings before running.');
1410 | return;
1411 | }
1412 |
1413 | if (!pattern) {
1414 | new Notice('Please select a pattern first');
1415 | return;
1416 | }
1417 |
1418 | this.logoContainer.addClass('loading');
1419 | this.loadingText.setText('');
1420 | this.animateLoadingText(this.getRandomLoadingMessage());
1421 |
1422 | try {
1423 | const response = await fetch(this.plugin.settings.fabricConnectorApiUrl + '/ts', {
1424 | method: 'POST',
1425 | headers: {
1426 | 'Content-Type': 'application/json',
1427 | 'X-API-Key': this.plugin.settings.fabricConnectorApiKey
1428 | },
1429 | body: JSON.stringify({
1430 | pattern: pattern,
1431 | model: model,
1432 | path: path,
1433 | stream: true,
1434 | goCompatibility: this.plugin.settings.fabric2
1435 | }),
1436 | });
1437 |
1438 | if (!response.ok) {
1439 | throw new Error(`HTTP error! status: ${response.status}`);
1440 | }
1441 |
1442 | const data = await response.json();
1443 | const output = data.output;
1444 |
1445 | const newFile = await this.createOutputNote(output, outputNoteName);
1446 | this.logoContainer.removeClass('loading');
1447 | this.loadingText.setText('');
1448 | new Notice('TS Fabric output generated successfully');
1449 | } catch (error) {
1450 | console.error('Failed to run TS Fabric:', error);
1451 | new Notice('Failed to run TS Fabric. Please check your settings and try again.');
1452 | }
1453 | }
1454 |
1455 | async syncCustomPatterns() {
1456 | const customPatternsFolder = this.plugin.settings.customPatternsFolder;
1457 | if (!customPatternsFolder) {
1458 | new Notice('Custom patterns folder not set. Please set it in the plugin settings.');
1459 | return;
1460 | }
1461 |
1462 | const folderPath = this.app.vault.getAbstractFileByPath(customPatternsFolder);
1463 | if (!folderPath || !(folderPath instanceof TFolder)) {
1464 | new Notice('Custom patterns folder not found in the vault.');
1465 | return;
1466 | }
1467 |
1468 | for (const file of folderPath.children) {
1469 | if (file instanceof TFile && file.extension === 'md') {
1470 | const content = await this.app.vault.read(file);
1471 | const patternName = file.basename;
1472 |
1473 | try {
1474 | await this.updatePattern(patternName, content);
1475 | new Notice(`Pattern "${patternName}" synced successfully.`);
1476 | } catch (error) {
1477 | new Notice(`Failed to sync pattern "${patternName}": ${error.message}`);
1478 | }
1479 | }
1480 | }
1481 | await this.loadPatterns()
1482 | }
1483 |
1484 | async updatePattern(name: string, content: string) {
1485 | const response = await fetch(this.plugin.settings.fabricConnectorApiUrl + '/update_pattern', {
1486 | method: 'POST',
1487 | headers: {
1488 | 'Content-Type': 'application/json',
1489 | 'X-API-Key': this.plugin.settings.fabricConnectorApiKey
1490 | },
1491 | body: JSON.stringify({
1492 | pattern: name,
1493 | content: content
1494 | })
1495 | });
1496 |
1497 | if (!response.ok) {
1498 | throw new Error(`HTTP error! status: ${response.status}`);
1499 | }
1500 |
1501 |
1502 |
1503 |
1504 | return await response.json();
1505 | }
1506 |
1507 | }
1508 |
1509 | class FabricSettingTab extends PluginSettingTab {
1510 | plugin: FabricPlugin;
1511 |
1512 | constructor(app: App, plugin: FabricPlugin) {
1513 | super(app, plugin);
1514 | this.plugin = plugin;
1515 | }
1516 |
1517 | display(): void {
1518 | const { containerEl } = this;
1519 |
1520 | containerEl.empty();
1521 |
1522 | // Instructions for Fabric Connector API URL and Key
1523 | containerEl.createEl('p', {
1524 | text: 'To set up the Fabric Connector:',
1525 | cls: 'fabric-settings-instruction'
1526 | });
1527 | containerEl.createEl('ol', {cls: 'fabric-settings-list'}, (ol) => {
1528 | ol.createEl('li', {text: 'Click the Fabric Connector icon (brain icon) in your system tray'});
1529 | ol.createEl('li', {text: 'For the API URL: Click "Open API Docs" and copy the URL from your browser, removing "/docs" from the end'});
1530 | ol.createEl('li', {text: 'For the API Key: Click "Copy API Key"'});
1531 | });
1532 |
1533 | // Fabric Connector API URL input
1534 | new Setting(containerEl)
1535 | .setName('Fabric Connector API URL')
1536 | .setDesc('Enter the URL for the Fabric Connector API')
1537 | .addDropdown(dropdown => {
1538 | dropdown
1539 | .addOption('http://', 'http://')
1540 | .addOption('https://', 'https://')
1541 | .setValue(this.plugin.settings.fabricConnectorApiUrl.startsWith('https://') ? 'https://' : 'http://')
1542 | .onChange(async (value) => {
1543 | const domain = this.plugin.settings.fabricConnectorApiUrl.replace(/^https?:\/\//, '');
1544 | this.plugin.settings.fabricConnectorApiUrl = value + domain;
1545 | await this.plugin.saveSettings();
1546 | });
1547 | })
1548 | .addText(text => {
1549 | const domain = this.plugin.settings.fabricConnectorApiUrl.replace(/^https?:\/\//, '');
1550 | text
1551 | .setPlaceholder('Enter domain')
1552 | .setValue(domain)
1553 | .onChange(async (value) => {
1554 | // Remove any slashes from the input
1555 | const cleanValue = value.replace(/\//g, '');
1556 | const protocol = this.plugin.settings.fabricConnectorApiUrl.startsWith('https://') ? 'https://' : 'http://';
1557 | this.plugin.settings.fabricConnectorApiUrl = protocol + cleanValue;
1558 | await this.plugin.saveSettings();
1559 | // Update the text field to show the cleaned value
1560 | text.setValue(cleanValue);
1561 | });
1562 | });
1563 |
1564 | // Fabric Connector API Key input
1565 | new Setting(containerEl)
1566 | .setName('Fabric Connector API Key')
1567 | .setDesc('Enter your API key for the Fabric Connector')
1568 | .addText(text => text
1569 | .setPlaceholder('Enter API Key')
1570 | .setValue(this.plugin.settings.fabricConnectorApiKey || '')
1571 | .onChange(async (value) => {
1572 | this.plugin.settings.fabricConnectorApiKey = value;
1573 | await this.plugin.saveSettings();
1574 | }))
1575 | .addButton(button => button
1576 | .setButtonText('Test API Key')
1577 | .onClick(async () => {
1578 | await this.testFabricConnectorApiKey();
1579 | }));
1580 |
1581 |
1582 | new Setting(containerEl)
1583 | .setName('Tavily API Key')
1584 | .setDesc('Enter your Tavily API key')
1585 | .addText(text => text
1586 | .setPlaceholder('Enter API Key')
1587 | .setValue(this.plugin.settings.tavilyApiKey || '')
1588 | .onChange(async (value) => {
1589 | this.plugin.settings.tavilyApiKey = value;
1590 | await this.plugin.saveSettings();
1591 | }))
1592 | .addButton(button => button
1593 | .setButtonText('Test API Key')
1594 | .onClick(async () => {
1595 | await this.testTavilyApiKey();
1596 | }));
1597 |
1598 | new Setting(containerEl)
1599 | .setName('Output Folder')
1600 | .setDesc('Folder to save output files')
1601 | .addText(text => text
1602 | .setPlaceholder('Enter folder path')
1603 | .setValue(this.plugin.settings.outputFolder)
1604 | .onChange(async (value) => {
1605 | this.plugin.settings.outputFolder = value;
1606 | await this.plugin.saveSettings();
1607 | }));
1608 |
1609 | new Setting(containerEl)
1610 | .setName('Custom Patterns Folder')
1611 | .setDesc('Folder to store custom patterns')
1612 | .addText(text => text
1613 | .setPlaceholder('Enter folder path')
1614 | .setValue(this.plugin.settings.customPatternsFolder)
1615 | .onChange(async (value) => {
1616 | this.plugin.settings.customPatternsFolder = value;
1617 | await this.plugin.saveSettings();
1618 | this.plugin.registerCustomPatternsFolderWatcher();
1619 | }));
1620 |
1621 | new Setting(containerEl)
1622 | .setName('Default Model')
1623 | .setDesc('The default model to use when running Fabric')
1624 | .addText(text => text
1625 | .setPlaceholder('Enter default model')
1626 | .setValue(this.plugin.settings.defaultModel)
1627 | .onChange(async (value) => {
1628 | this.plugin.settings.defaultModel = value;
1629 | await this.plugin.saveSettings();
1630 | }));
1631 |
1632 | new Setting(containerEl)
1633 | .setName('Default Post Processing Pattern')
1634 | .setDesc('This pattern will be appended to selected patterns when running Fabric')
1635 | .addText(text => text
1636 | .setPlaceholder('Enter pattern name')
1637 | .setValue(this.plugin.settings.defaultPostProcessingPattern)
1638 | .onChange(async (value) => {
1639 | this.plugin.settings.defaultPostProcessingPattern = value;
1640 | await this.plugin.saveSettings();
1641 | }));
1642 |
1643 | new Setting(containerEl)
1644 | .setName('Fabric 2.0 Compatibility Mode')
1645 | .setDesc('Enable comptaibility mode for Fabric 2.0')
1646 | .addToggle(toggle => toggle
1647 | .setValue(this.plugin.settings.fabric2)
1648 | .onChange(async (value) => {
1649 | this.plugin.settings.fabric2 = value;
1650 | await this.plugin.saveSettings();
1651 | this.plugin.updateLogging();
1652 | }));
1653 |
1654 | new Setting(containerEl)
1655 | .setName('Debug Mode')
1656 | .setDesc('Enable debug logging')
1657 | .addToggle(toggle => toggle
1658 | .setValue(this.plugin.settings.debug)
1659 | .onChange(async (value) => {
1660 | this.plugin.settings.debug = value;
1661 | await this.plugin.saveSettings();
1662 | this.plugin.updateLogging();
1663 | }));
1664 | }
1665 |
1666 | async testFabricConnectorApiKey() {
1667 | const fabricConnectorApiUrl = this.plugin.settings.fabricConnectorApiUrl;
1668 | const url = new URL(this.plugin.settings.fabricConnectorApiUrl + '/models');
1669 | url.searchParams.append('goCompatibility', this.plugin.settings.fabric2.toString());
1670 | const apiKey = this.plugin.settings.fabricConnectorApiKey;
1671 |
1672 | if (!fabricConnectorApiUrl || !apiKey) {
1673 | new Notice('Please enter both Fabric Connector API URL and API Key');
1674 | return;
1675 | }
1676 |
1677 | try {
1678 | const response = await fetch(url, {
1679 | method: 'GET',
1680 | headers: {
1681 | 'Content-Type': 'application/json',
1682 | 'X-API-Key': apiKey
1683 | }
1684 | });
1685 |
1686 | if (response.ok) {
1687 | new Notice('Fabric Connector API Key is valid');
1688 | } else {
1689 | new Notice('Invalid Fabric Connector API Key');
1690 | }
1691 | } catch (error) {
1692 | console.error('Error testing Fabric Connector API Key:', error);
1693 | new Notice('Error testing Fabric Connector API Key. Check console for details.');
1694 | }
1695 |
1696 | }
1697 |
1698 | async testTavilyApiKey() {
1699 | const apiKey = this.plugin.settings.tavilyApiKey;
1700 |
1701 | if (!this.plugin.settings.tavilyApiKey) {
1702 | new Notice('Please enter a Tavily API Key');
1703 | return;
1704 | }
1705 |
1706 | try {
1707 | const response = await fetch('https://api.tavily.com/search', {
1708 | method: 'POST',
1709 | headers: {
1710 | 'Content-Type': 'application/json'
1711 | },
1712 | body: JSON.stringify({
1713 | query: 'Test Query',
1714 | max_results: 1,
1715 | api_key: apiKey
1716 | })
1717 | });
1718 |
1719 | if (response.ok) {
1720 | new Notice('Tavily API Key is valid');
1721 | } else {
1722 | new Notice('Invalid Tavily API Key');
1723 | }
1724 | } catch (error) {
1725 | console.error('Error testing Tavily API Key:', error);
1726 | new Notice('Error testing Tavily API Key. Check console for details.');
1727 | }
1728 | }
1729 | }
1730 |
1731 |
1732 | class CommunityPatternsModal extends Modal {
1733 | plugin: FabricPlugin;
1734 | patterns: any[];
1735 | searchInput: HTMLInputElement;
1736 | resultsContainer: HTMLElement;
1737 |
1738 | constructor(app: App, plugin: FabricPlugin) {
1739 | super(app);
1740 | this.plugin = plugin;
1741 | }
1742 |
1743 | async onOpen() {
1744 | const { contentEl } = this;
1745 | contentEl.empty();
1746 |
1747 | contentEl.createEl('h2', { text: 'Community Patterns', cls: 'community-patterns-title' });
1748 |
1749 | // Add Update All button
1750 |
1751 | const buttonContainer = contentEl.createDiv({ cls: 'community-patterns-button-container' });
1752 |
1753 | const updateAllButton = new ButtonComponent(buttonContainer)
1754 | .setButtonText('Update All')
1755 | .onClick(() => this.updateAllPatterns());
1756 | //setIcon(updateAllButton.buttonEl, 'refresh-cw'); // Use an appropriate icon
1757 | updateAllButton.buttonEl.className = 'fabric-button community-patterns-update-all';
1758 |
1759 | const refreshPatternsButton = new ButtonComponent(buttonContainer)
1760 | .setButtonText('Refresh Patterns')
1761 | .onClick(() => this.refreshPatterns());
1762 | //setIcon(refreshPatternsButton.buttonEl, 'refresh-cw'); // Use an appropriate icon
1763 | refreshPatternsButton.buttonEl.className = 'fabric-button community-patterns-refresh';
1764 |
1765 |
1766 | this.searchInput = contentEl.createEl('input', {
1767 | type: 'text',
1768 | placeholder: 'Search patterns...',
1769 | cls: 'community-patterns-search'
1770 | });
1771 | this.searchInput.addEventListener('input', () => this.updateResults());
1772 |
1773 | this.resultsContainer = contentEl.createEl('div', { cls: 'community-patterns-results' });
1774 |
1775 | await this.fetchPatterns();
1776 | this.updateResults();
1777 | }
1778 |
1779 | async fetchPatterns() {
1780 | try {
1781 | const response = await fetch('https://raw.githubusercontent.com/chasebank87/fabric-patterns/main/patterns.json');
1782 | if (!response.ok) {
1783 | throw new Error('Failed to fetch patterns');
1784 | }
1785 | const data = await response.json();
1786 | this.patterns = Object.keys(data.patterns).map(key => ({
1787 | name: key,
1788 | ...data.patterns[key]
1789 | }));
1790 | } catch (error) {
1791 | console.error('Error fetching patterns:', error);
1792 | new Notice('Failed to fetch patterns');
1793 | }
1794 | }
1795 |
1796 | async isPatternInstalled(patternName: string): Promise {
1797 | const file = `${this.plugin.settings.customPatternsFolder}/${patternName}.md`;
1798 | return await this.app.vault.adapter.exists(file);
1799 | }
1800 |
1801 | async doesPatternNeedUpdate(patternName: string, pattern_repo: string): Promise {
1802 | const installedPath = `${this.plugin.settings.customPatternsFolder}/${patternName}.md`;
1803 | const repoPath = 'https://raw.githubusercontent.com/'+ pattern_repo + '/main/patterns/' + patternName + '.md';
1804 |
1805 | const installedContent = await this.app.vault.adapter.read(installedPath);
1806 | const response = await fetch(repoPath);
1807 | if (!response.ok) {
1808 | throw new Error('Failed to fetch pattern content');
1809 | }
1810 | const repoContent = await response.text();
1811 |
1812 | return installedContent !== repoContent;
1813 | }
1814 |
1815 | async updateResults() {
1816 | const searchTerm = this.searchInput.value.toLowerCase();
1817 | const filteredPatterns = this.patterns.filter(pattern =>
1818 | pattern.name.toLowerCase().includes(searchTerm) ||
1819 | pattern.description.toLowerCase().includes(searchTerm) ||
1820 | pattern.author.toLowerCase().includes(searchTerm)
1821 | );
1822 |
1823 | this.resultsContainer.empty();
1824 | for (const pattern of filteredPatterns) {
1825 | try {
1826 | // Check if the pattern_repo URL is valid
1827 | let currentPatternUrl = 'https://raw.githubusercontent.com/'+ pattern.pattern_repo + '/main/patterns/' + pattern.name + '.md';
1828 | const response = await fetch(currentPatternUrl);
1829 | if (!response.ok) {
1830 | console.warn(`Pattern ${pattern.name} has an invalid URL: ${currentPatternUrl}`);
1831 | continue; // Skip this pattern and move to the next one
1832 | }
1833 |
1834 | const patternEl = this.resultsContainer.createEl('div', { cls: 'community-pattern-item' });
1835 |
1836 | const patternInfo = patternEl.createEl('div', { cls: 'community-pattern-info' });
1837 | patternInfo.createEl('div', { text: pattern.name, cls: 'community-pattern-title' });
1838 | patternInfo.createEl('div', { text: pattern.description, cls: 'community-pattern-description' });
1839 | patternInfo.createEl('em', {text: `by ${pattern.author}`, cls: 'community-fabric-author'});
1840 | patternInfo.createEl('small', { text: `For models: ${pattern.for_models}`, cls: 'community-fabric-models' });
1841 |
1842 |
1843 | const isInstalled = await this.isPatternInstalled(pattern.name);
1844 | const needsUpdate = isInstalled && await this.doesPatternNeedUpdate(pattern.name, pattern.pattern_repo);
1845 |
1846 | const buttonContainer = patternEl.createEl('div', { cls: 'community-pattern-buttons' });
1847 |
1848 | if (!isInstalled) {
1849 | const downloadBtn = new ButtonComponent(buttonContainer)
1850 | .setButtonText('')
1851 | .onClick(() => this.downloadPattern(pattern.name, pattern.pattern_repo));
1852 | downloadBtn.buttonEl.className = 'community-pattern-download';
1853 | setIcon(downloadBtn.buttonEl, 'download');
1854 | } else {
1855 | if (needsUpdate) {
1856 | const updateBtn = new ButtonComponent(buttonContainer)
1857 | .setButtonText('')
1858 | .onClick(() => this.updatePattern(pattern.name, pattern.pattern_repo));
1859 | updateBtn.buttonEl.className = 'community-pattern-update';
1860 | setIcon(updateBtn.buttonEl, 'refresh-cw');
1861 | }
1862 | const uninstallBtn = new ButtonComponent(buttonContainer)
1863 | .setButtonText('')
1864 | .onClick(() => this.uninstallPattern(pattern.name));
1865 | uninstallBtn.buttonEl.className = 'community-pattern-uninstall';
1866 | setIcon(uninstallBtn.buttonEl, 'trash');
1867 | }
1868 | } catch (error) {
1869 | console.error(`Error processing pattern ${pattern.name}:`, error);
1870 | // Skip this pattern and move to the next one
1871 | }
1872 | }
1873 | }
1874 |
1875 | async downloadPattern(patternName: string, pattern_repo: string) {
1876 | try {
1877 | let patternUrl = 'https://raw.githubusercontent.com/'+ pattern_repo + '/main/patterns/' + patternName + '.md';
1878 | console.log(patternUrl);
1879 | const response = await fetch(patternUrl);
1880 | if (!response.ok) {
1881 | throw new Error('Failed to download pattern');
1882 | }
1883 | const content = await response.text();
1884 |
1885 | const file = `${this.plugin.settings.customPatternsFolder}/${patternName}.md`;
1886 | await this.app.vault.create(file, content);
1887 |
1888 | new Notice(`Pattern ${patternName} downloaded successfully`);
1889 | this.updateResults();
1890 | } catch (error) {
1891 | console.error('Error downloading pattern:', error);
1892 | new Notice('Failed to download pattern');
1893 | }
1894 | }
1895 |
1896 | async updatePattern(patternName: string, pattern_repo: string) {
1897 | try {
1898 | let patternUrl = 'https://raw.githubusercontent.com/'+ pattern_repo + '/main/patterns/' + patternName + '.md';
1899 | const response = await fetch(patternUrl);
1900 | if (!response.ok) {
1901 | throw new Error('Failed to update pattern');
1902 | }
1903 | const content = await response.text();
1904 |
1905 | const file = `${this.plugin.settings.customPatternsFolder}/${patternName}.md`;
1906 | await this.app.vault.adapter.write(file, content);
1907 |
1908 | new Notice(`Pattern ${patternName} updated successfully`);
1909 | this.updateResults();
1910 | } catch (error) {
1911 | console.error('Error updating pattern:', error);
1912 | new Notice('Failed to update pattern');
1913 | }
1914 | }
1915 |
1916 | async refreshPatterns() {
1917 | await this.fetchPatterns();
1918 | this.updateResults();
1919 | new Notice('Patterns list refreshed');
1920 | }
1921 |
1922 |
1923 | async uninstallPattern(patternName: string) {
1924 | try {
1925 | const file = `${this.plugin.settings.customPatternsFolder}/${patternName}.md`;
1926 | await this.app.vault.adapter.remove(file);
1927 | new Notice(`Pattern ${patternName} uninstalled successfully`);
1928 | this.updateResults();
1929 | } catch (error) {
1930 | console.error('Error uninstalling pattern:', error);
1931 | new Notice('Failed to uninstall pattern');
1932 | }
1933 | }
1934 |
1935 | async updateAllPatterns() {
1936 | let updatedCount = 0;
1937 | for (const pattern of this.patterns) {
1938 | const isInstalled = await this.isPatternInstalled(pattern.name);
1939 | const needsUpdate = isInstalled && await this.doesPatternNeedUpdate(pattern.name, pattern.pattern_repo);
1940 | if (needsUpdate) {
1941 | await this.updatePattern(pattern.name, pattern.pattern_repo);
1942 | updatedCount++;
1943 | }
1944 | }
1945 | new Notice(`Updated ${updatedCount} patterns`);
1946 | this.updateResults();
1947 | }
1948 |
1949 | onClose() {
1950 | const { contentEl } = this;
1951 | contentEl.empty();
1952 | }
1953 | }
--------------------------------------------------------------------------------
/manifest.json:
--------------------------------------------------------------------------------
1 | {
2 | "id": "unofficial-fabric-integration",
3 | "name": "Unofficial Fabric Integration",
4 | "version": "1.3.3",
5 | "minAppVersion": "1.6.5",
6 | "description": "Integrates Fabric into your vault",
7 | "author": "Chasebank87",
8 | "authorUrl": "https://chaseelder.com",
9 | "fundingUrl": "https://buymeacoffee.com/chasebank87",
10 | "isDesktopOnly": true
11 | }
12 |
13 |
--------------------------------------------------------------------------------
/package-lock.json:
--------------------------------------------------------------------------------
1 | {
2 | "name": "obsidian-fabric-plugin",
3 | "version": "1.0.0",
4 | "lockfileVersion": 3,
5 | "requires": true,
6 | "packages": {
7 | "": {
8 | "name": "obsidian-fabric-plugin",
9 | "version": "1.0.0",
10 | "license": "MIT",
11 | "dependencies": {
12 | "@types/he": "^1.2.3",
13 | "he": "^1.2.0",
14 | "shell-escape": "^0.2.0"
15 | },
16 | "devDependencies": {
17 | "@types/fuzzaldrin-plus": "^0.6.5",
18 | "@types/node": "^16.11.6",
19 | "@types/semver": "^7.5.8",
20 | "@types/shell-escape": "^0.2.3",
21 | "@typescript-eslint/eslint-plugin": "5.29.0",
22 | "@typescript-eslint/parser": "5.29.0",
23 | "builtin-modules": "3.3.0",
24 | "esbuild": "0.17.3",
25 | "fuzzaldrin-plus": "^0.6.0",
26 | "obsidian": "latest",
27 | "tslib": "^2.4.0",
28 | "typescript": "4.7.4"
29 | }
30 | },
31 | "node_modules/@codemirror/state": {
32 | "version": "6.4.1",
33 | "resolved": "https://registry.npmjs.org/@codemirror/state/-/state-6.4.1.tgz",
34 | "integrity": "sha512-QkEyUiLhsJoZkbumGZlswmAhA7CBU02Wrz7zvH4SrcifbsqwlXShVXg65f3v/ts57W3dqyamEriMhij1Z3Zz4A==",
35 | "dev": true,
36 | "peer": true
37 | },
38 | "node_modules/@codemirror/view": {
39 | "version": "6.28.2",
40 | "resolved": "https://registry.npmjs.org/@codemirror/view/-/view-6.28.2.tgz",
41 | "integrity": "sha512-A3DmyVfjgPsGIjiJqM/zvODUAPQdQl3ci0ghehYNnbt5x+o76xq+dL5+mMBuysDXnI3kapgOkoeJ0sbtL/3qPw==",
42 | "dev": true,
43 | "peer": true,
44 | "dependencies": {
45 | "@codemirror/state": "^6.4.0",
46 | "style-mod": "^4.1.0",
47 | "w3c-keyname": "^2.2.4"
48 | }
49 | },
50 | "node_modules/@esbuild/android-arm": {
51 | "version": "0.17.3",
52 | "resolved": "https://registry.npmjs.org/@esbuild/android-arm/-/android-arm-0.17.3.tgz",
53 | "integrity": "sha512-1Mlz934GvbgdDmt26rTLmf03cAgLg5HyOgJN+ZGCeP3Q9ynYTNMn2/LQxIl7Uy+o4K6Rfi2OuLsr12JQQR8gNg==",
54 | "cpu": [
55 | "arm"
56 | ],
57 | "dev": true,
58 | "optional": true,
59 | "os": [
60 | "android"
61 | ],
62 | "engines": {
63 | "node": ">=12"
64 | }
65 | },
66 | "node_modules/@esbuild/android-arm64": {
67 | "version": "0.17.3",
68 | "resolved": "https://registry.npmjs.org/@esbuild/android-arm64/-/android-arm64-0.17.3.tgz",
69 | "integrity": "sha512-XvJsYo3dO3Pi4kpalkyMvfQsjxPWHYjoX4MDiB/FUM4YMfWcXa5l4VCwFWVYI1+92yxqjuqrhNg0CZg3gSouyQ==",
70 | "cpu": [
71 | "arm64"
72 | ],
73 | "dev": true,
74 | "optional": true,
75 | "os": [
76 | "android"
77 | ],
78 | "engines": {
79 | "node": ">=12"
80 | }
81 | },
82 | "node_modules/@esbuild/android-x64": {
83 | "version": "0.17.3",
84 | "resolved": "https://registry.npmjs.org/@esbuild/android-x64/-/android-x64-0.17.3.tgz",
85 | "integrity": "sha512-nuV2CmLS07Gqh5/GrZLuqkU9Bm6H6vcCspM+zjp9TdQlxJtIe+qqEXQChmfc7nWdyr/yz3h45Utk1tUn8Cz5+A==",
86 | "cpu": [
87 | "x64"
88 | ],
89 | "dev": true,
90 | "optional": true,
91 | "os": [
92 | "android"
93 | ],
94 | "engines": {
95 | "node": ">=12"
96 | }
97 | },
98 | "node_modules/@esbuild/darwin-arm64": {
99 | "version": "0.17.3",
100 | "resolved": "https://registry.npmjs.org/@esbuild/darwin-arm64/-/darwin-arm64-0.17.3.tgz",
101 | "integrity": "sha512-01Hxaaat6m0Xp9AXGM8mjFtqqwDjzlMP0eQq9zll9U85ttVALGCGDuEvra5Feu/NbP5AEP1MaopPwzsTcUq1cw==",
102 | "cpu": [
103 | "arm64"
104 | ],
105 | "dev": true,
106 | "optional": true,
107 | "os": [
108 | "darwin"
109 | ],
110 | "engines": {
111 | "node": ">=12"
112 | }
113 | },
114 | "node_modules/@esbuild/darwin-x64": {
115 | "version": "0.17.3",
116 | "resolved": "https://registry.npmjs.org/@esbuild/darwin-x64/-/darwin-x64-0.17.3.tgz",
117 | "integrity": "sha512-Eo2gq0Q/er2muf8Z83X21UFoB7EU6/m3GNKvrhACJkjVThd0uA+8RfKpfNhuMCl1bKRfBzKOk6xaYKQZ4lZqvA==",
118 | "cpu": [
119 | "x64"
120 | ],
121 | "dev": true,
122 | "optional": true,
123 | "os": [
124 | "darwin"
125 | ],
126 | "engines": {
127 | "node": ">=12"
128 | }
129 | },
130 | "node_modules/@esbuild/freebsd-arm64": {
131 | "version": "0.17.3",
132 | "resolved": "https://registry.npmjs.org/@esbuild/freebsd-arm64/-/freebsd-arm64-0.17.3.tgz",
133 | "integrity": "sha512-CN62ESxaquP61n1ZjQP/jZte8CE09M6kNn3baos2SeUfdVBkWN5n6vGp2iKyb/bm/x4JQzEvJgRHLGd5F5b81w==",
134 | "cpu": [
135 | "arm64"
136 | ],
137 | "dev": true,
138 | "optional": true,
139 | "os": [
140 | "freebsd"
141 | ],
142 | "engines": {
143 | "node": ">=12"
144 | }
145 | },
146 | "node_modules/@esbuild/freebsd-x64": {
147 | "version": "0.17.3",
148 | "resolved": "https://registry.npmjs.org/@esbuild/freebsd-x64/-/freebsd-x64-0.17.3.tgz",
149 | "integrity": "sha512-feq+K8TxIznZE+zhdVurF3WNJ/Sa35dQNYbaqM/wsCbWdzXr5lyq+AaTUSER2cUR+SXPnd/EY75EPRjf4s1SLg==",
150 | "cpu": [
151 | "x64"
152 | ],
153 | "dev": true,
154 | "optional": true,
155 | "os": [
156 | "freebsd"
157 | ],
158 | "engines": {
159 | "node": ">=12"
160 | }
161 | },
162 | "node_modules/@esbuild/linux-arm": {
163 | "version": "0.17.3",
164 | "resolved": "https://registry.npmjs.org/@esbuild/linux-arm/-/linux-arm-0.17.3.tgz",
165 | "integrity": "sha512-CLP3EgyNuPcg2cshbwkqYy5bbAgK+VhyfMU7oIYyn+x4Y67xb5C5ylxsNUjRmr8BX+MW3YhVNm6Lq6FKtRTWHQ==",
166 | "cpu": [
167 | "arm"
168 | ],
169 | "dev": true,
170 | "optional": true,
171 | "os": [
172 | "linux"
173 | ],
174 | "engines": {
175 | "node": ">=12"
176 | }
177 | },
178 | "node_modules/@esbuild/linux-arm64": {
179 | "version": "0.17.3",
180 | "resolved": "https://registry.npmjs.org/@esbuild/linux-arm64/-/linux-arm64-0.17.3.tgz",
181 | "integrity": "sha512-JHeZXD4auLYBnrKn6JYJ0o5nWJI9PhChA/Nt0G4MvLaMrvXuWnY93R3a7PiXeJQphpL1nYsaMcoV2QtuvRnF/g==",
182 | "cpu": [
183 | "arm64"
184 | ],
185 | "dev": true,
186 | "optional": true,
187 | "os": [
188 | "linux"
189 | ],
190 | "engines": {
191 | "node": ">=12"
192 | }
193 | },
194 | "node_modules/@esbuild/linux-ia32": {
195 | "version": "0.17.3",
196 | "resolved": "https://registry.npmjs.org/@esbuild/linux-ia32/-/linux-ia32-0.17.3.tgz",
197 | "integrity": "sha512-FyXlD2ZjZqTFh0sOQxFDiWG1uQUEOLbEh9gKN/7pFxck5Vw0qjWSDqbn6C10GAa1rXJpwsntHcmLqydY9ST9ZA==",
198 | "cpu": [
199 | "ia32"
200 | ],
201 | "dev": true,
202 | "optional": true,
203 | "os": [
204 | "linux"
205 | ],
206 | "engines": {
207 | "node": ">=12"
208 | }
209 | },
210 | "node_modules/@esbuild/linux-loong64": {
211 | "version": "0.17.3",
212 | "resolved": "https://registry.npmjs.org/@esbuild/linux-loong64/-/linux-loong64-0.17.3.tgz",
213 | "integrity": "sha512-OrDGMvDBI2g7s04J8dh8/I7eSO+/E7nMDT2Z5IruBfUO/RiigF1OF6xoH33Dn4W/OwAWSUf1s2nXamb28ZklTA==",
214 | "cpu": [
215 | "loong64"
216 | ],
217 | "dev": true,
218 | "optional": true,
219 | "os": [
220 | "linux"
221 | ],
222 | "engines": {
223 | "node": ">=12"
224 | }
225 | },
226 | "node_modules/@esbuild/linux-mips64el": {
227 | "version": "0.17.3",
228 | "resolved": "https://registry.npmjs.org/@esbuild/linux-mips64el/-/linux-mips64el-0.17.3.tgz",
229 | "integrity": "sha512-DcnUpXnVCJvmv0TzuLwKBC2nsQHle8EIiAJiJ+PipEVC16wHXaPEKP0EqN8WnBe0TPvMITOUlP2aiL5YMld+CQ==",
230 | "cpu": [
231 | "mips64el"
232 | ],
233 | "dev": true,
234 | "optional": true,
235 | "os": [
236 | "linux"
237 | ],
238 | "engines": {
239 | "node": ">=12"
240 | }
241 | },
242 | "node_modules/@esbuild/linux-ppc64": {
243 | "version": "0.17.3",
244 | "resolved": "https://registry.npmjs.org/@esbuild/linux-ppc64/-/linux-ppc64-0.17.3.tgz",
245 | "integrity": "sha512-BDYf/l1WVhWE+FHAW3FzZPtVlk9QsrwsxGzABmN4g8bTjmhazsId3h127pliDRRu5674k1Y2RWejbpN46N9ZhQ==",
246 | "cpu": [
247 | "ppc64"
248 | ],
249 | "dev": true,
250 | "optional": true,
251 | "os": [
252 | "linux"
253 | ],
254 | "engines": {
255 | "node": ">=12"
256 | }
257 | },
258 | "node_modules/@esbuild/linux-riscv64": {
259 | "version": "0.17.3",
260 | "resolved": "https://registry.npmjs.org/@esbuild/linux-riscv64/-/linux-riscv64-0.17.3.tgz",
261 | "integrity": "sha512-WViAxWYMRIi+prTJTyV1wnqd2mS2cPqJlN85oscVhXdb/ZTFJdrpaqm/uDsZPGKHtbg5TuRX/ymKdOSk41YZow==",
262 | "cpu": [
263 | "riscv64"
264 | ],
265 | "dev": true,
266 | "optional": true,
267 | "os": [
268 | "linux"
269 | ],
270 | "engines": {
271 | "node": ">=12"
272 | }
273 | },
274 | "node_modules/@esbuild/linux-s390x": {
275 | "version": "0.17.3",
276 | "resolved": "https://registry.npmjs.org/@esbuild/linux-s390x/-/linux-s390x-0.17.3.tgz",
277 | "integrity": "sha512-Iw8lkNHUC4oGP1O/KhumcVy77u2s6+KUjieUqzEU3XuWJqZ+AY7uVMrrCbAiwWTkpQHkr00BuXH5RpC6Sb/7Ug==",
278 | "cpu": [
279 | "s390x"
280 | ],
281 | "dev": true,
282 | "optional": true,
283 | "os": [
284 | "linux"
285 | ],
286 | "engines": {
287 | "node": ">=12"
288 | }
289 | },
290 | "node_modules/@esbuild/linux-x64": {
291 | "version": "0.17.3",
292 | "resolved": "https://registry.npmjs.org/@esbuild/linux-x64/-/linux-x64-0.17.3.tgz",
293 | "integrity": "sha512-0AGkWQMzeoeAtXQRNB3s4J1/T2XbigM2/Mn2yU1tQSmQRmHIZdkGbVq2A3aDdNslPyhb9/lH0S5GMTZ4xsjBqg==",
294 | "cpu": [
295 | "x64"
296 | ],
297 | "dev": true,
298 | "optional": true,
299 | "os": [
300 | "linux"
301 | ],
302 | "engines": {
303 | "node": ">=12"
304 | }
305 | },
306 | "node_modules/@esbuild/netbsd-x64": {
307 | "version": "0.17.3",
308 | "resolved": "https://registry.npmjs.org/@esbuild/netbsd-x64/-/netbsd-x64-0.17.3.tgz",
309 | "integrity": "sha512-4+rR/WHOxIVh53UIQIICryjdoKdHsFZFD4zLSonJ9RRw7bhKzVyXbnRPsWSfwybYqw9sB7ots/SYyufL1mBpEg==",
310 | "cpu": [
311 | "x64"
312 | ],
313 | "dev": true,
314 | "optional": true,
315 | "os": [
316 | "netbsd"
317 | ],
318 | "engines": {
319 | "node": ">=12"
320 | }
321 | },
322 | "node_modules/@esbuild/openbsd-x64": {
323 | "version": "0.17.3",
324 | "resolved": "https://registry.npmjs.org/@esbuild/openbsd-x64/-/openbsd-x64-0.17.3.tgz",
325 | "integrity": "sha512-cVpWnkx9IYg99EjGxa5Gc0XmqumtAwK3aoz7O4Dii2vko+qXbkHoujWA68cqXjhh6TsLaQelfDO4MVnyr+ODeA==",
326 | "cpu": [
327 | "x64"
328 | ],
329 | "dev": true,
330 | "optional": true,
331 | "os": [
332 | "openbsd"
333 | ],
334 | "engines": {
335 | "node": ">=12"
336 | }
337 | },
338 | "node_modules/@esbuild/sunos-x64": {
339 | "version": "0.17.3",
340 | "resolved": "https://registry.npmjs.org/@esbuild/sunos-x64/-/sunos-x64-0.17.3.tgz",
341 | "integrity": "sha512-RxmhKLbTCDAY2xOfrww6ieIZkZF+KBqG7S2Ako2SljKXRFi+0863PspK74QQ7JpmWwncChY25JTJSbVBYGQk2Q==",
342 | "cpu": [
343 | "x64"
344 | ],
345 | "dev": true,
346 | "optional": true,
347 | "os": [
348 | "sunos"
349 | ],
350 | "engines": {
351 | "node": ">=12"
352 | }
353 | },
354 | "node_modules/@esbuild/win32-arm64": {
355 | "version": "0.17.3",
356 | "resolved": "https://registry.npmjs.org/@esbuild/win32-arm64/-/win32-arm64-0.17.3.tgz",
357 | "integrity": "sha512-0r36VeEJ4efwmofxVJRXDjVRP2jTmv877zc+i+Pc7MNsIr38NfsjkQj23AfF7l0WbB+RQ7VUb+LDiqC/KY/M/A==",
358 | "cpu": [
359 | "arm64"
360 | ],
361 | "dev": true,
362 | "optional": true,
363 | "os": [
364 | "win32"
365 | ],
366 | "engines": {
367 | "node": ">=12"
368 | }
369 | },
370 | "node_modules/@esbuild/win32-ia32": {
371 | "version": "0.17.3",
372 | "resolved": "https://registry.npmjs.org/@esbuild/win32-ia32/-/win32-ia32-0.17.3.tgz",
373 | "integrity": "sha512-wgO6rc7uGStH22nur4aLFcq7Wh86bE9cOFmfTr/yxN3BXvDEdCSXyKkO+U5JIt53eTOgC47v9k/C1bITWL/Teg==",
374 | "cpu": [
375 | "ia32"
376 | ],
377 | "dev": true,
378 | "optional": true,
379 | "os": [
380 | "win32"
381 | ],
382 | "engines": {
383 | "node": ">=12"
384 | }
385 | },
386 | "node_modules/@esbuild/win32-x64": {
387 | "version": "0.17.3",
388 | "resolved": "https://registry.npmjs.org/@esbuild/win32-x64/-/win32-x64-0.17.3.tgz",
389 | "integrity": "sha512-FdVl64OIuiKjgXBjwZaJLKp0eaEckifbhn10dXWhysMJkWblg3OEEGKSIyhiD5RSgAya8WzP3DNkngtIg3Nt7g==",
390 | "cpu": [
391 | "x64"
392 | ],
393 | "dev": true,
394 | "optional": true,
395 | "os": [
396 | "win32"
397 | ],
398 | "engines": {
399 | "node": ">=12"
400 | }
401 | },
402 | "node_modules/@eslint-community/eslint-utils": {
403 | "version": "4.4.0",
404 | "resolved": "https://registry.npmjs.org/@eslint-community/eslint-utils/-/eslint-utils-4.4.0.tgz",
405 | "integrity": "sha512-1/sA4dwrzBAyeUoQ6oxahHKmrZvsnLCg4RfxW3ZFGGmQkSNQPFNLV9CUEFQP1x9EYXHTo5p6xdhZM1Ne9p/AfA==",
406 | "dev": true,
407 | "peer": true,
408 | "dependencies": {
409 | "eslint-visitor-keys": "^3.3.0"
410 | },
411 | "engines": {
412 | "node": "^12.22.0 || ^14.17.0 || >=16.0.0"
413 | },
414 | "peerDependencies": {
415 | "eslint": "^6.0.0 || ^7.0.0 || >=8.0.0"
416 | }
417 | },
418 | "node_modules/@eslint-community/regexpp": {
419 | "version": "4.10.1",
420 | "resolved": "https://registry.npmjs.org/@eslint-community/regexpp/-/regexpp-4.10.1.tgz",
421 | "integrity": "sha512-Zm2NGpWELsQAD1xsJzGQpYfvICSsFkEpU0jxBjfdC6uNEWXcHnfs9hScFWtXVDVl+rBQJGrl4g1vcKIejpH9dA==",
422 | "dev": true,
423 | "peer": true,
424 | "engines": {
425 | "node": "^12.0.0 || ^14.0.0 || >=16.0.0"
426 | }
427 | },
428 | "node_modules/@eslint/eslintrc": {
429 | "version": "2.1.4",
430 | "resolved": "https://registry.npmjs.org/@eslint/eslintrc/-/eslintrc-2.1.4.tgz",
431 | "integrity": "sha512-269Z39MS6wVJtsoUl10L60WdkhJVdPG24Q4eZTH3nnF6lpvSShEK3wQjDX9JRWAUPvPh7COouPpU9IrqaZFvtQ==",
432 | "dev": true,
433 | "peer": true,
434 | "dependencies": {
435 | "ajv": "^6.12.4",
436 | "debug": "^4.3.2",
437 | "espree": "^9.6.0",
438 | "globals": "^13.19.0",
439 | "ignore": "^5.2.0",
440 | "import-fresh": "^3.2.1",
441 | "js-yaml": "^4.1.0",
442 | "minimatch": "^3.1.2",
443 | "strip-json-comments": "^3.1.1"
444 | },
445 | "engines": {
446 | "node": "^12.22.0 || ^14.17.0 || >=16.0.0"
447 | },
448 | "funding": {
449 | "url": "https://opencollective.com/eslint"
450 | }
451 | },
452 | "node_modules/@eslint/js": {
453 | "version": "8.57.0",
454 | "resolved": "https://registry.npmjs.org/@eslint/js/-/js-8.57.0.tgz",
455 | "integrity": "sha512-Ys+3g2TaW7gADOJzPt83SJtCDhMjndcDMFVQ/Tj9iA1BfJzFKD9mAUXT3OenpuPHbI6P/myECxRJrofUsDx/5g==",
456 | "dev": true,
457 | "peer": true,
458 | "engines": {
459 | "node": "^12.22.0 || ^14.17.0 || >=16.0.0"
460 | }
461 | },
462 | "node_modules/@humanwhocodes/config-array": {
463 | "version": "0.11.14",
464 | "resolved": "https://registry.npmjs.org/@humanwhocodes/config-array/-/config-array-0.11.14.tgz",
465 | "integrity": "sha512-3T8LkOmg45BV5FICb15QQMsyUSWrQ8AygVfC7ZG32zOalnqrilm018ZVCw0eapXux8FtA33q8PSRSstjee3jSg==",
466 | "deprecated": "Use @eslint/config-array instead",
467 | "dev": true,
468 | "peer": true,
469 | "dependencies": {
470 | "@humanwhocodes/object-schema": "^2.0.2",
471 | "debug": "^4.3.1",
472 | "minimatch": "^3.0.5"
473 | },
474 | "engines": {
475 | "node": ">=10.10.0"
476 | }
477 | },
478 | "node_modules/@humanwhocodes/module-importer": {
479 | "version": "1.0.1",
480 | "resolved": "https://registry.npmjs.org/@humanwhocodes/module-importer/-/module-importer-1.0.1.tgz",
481 | "integrity": "sha512-bxveV4V8v5Yb4ncFTT3rPSgZBOpCkjfK0y4oVVVJwIuDVBRMDXrPyXRL988i5ap9m9bnyEEjWfm5WkBmtffLfA==",
482 | "dev": true,
483 | "peer": true,
484 | "engines": {
485 | "node": ">=12.22"
486 | },
487 | "funding": {
488 | "type": "github",
489 | "url": "https://github.com/sponsors/nzakas"
490 | }
491 | },
492 | "node_modules/@humanwhocodes/object-schema": {
493 | "version": "2.0.3",
494 | "resolved": "https://registry.npmjs.org/@humanwhocodes/object-schema/-/object-schema-2.0.3.tgz",
495 | "integrity": "sha512-93zYdMES/c1D69yZiKDBj0V24vqNzB/koF26KPaagAfd3P/4gUlh3Dys5ogAK+Exi9QyzlD8x/08Zt7wIKcDcA==",
496 | "deprecated": "Use @eslint/object-schema instead",
497 | "dev": true,
498 | "peer": true
499 | },
500 | "node_modules/@nodelib/fs.scandir": {
501 | "version": "2.1.5",
502 | "resolved": "https://registry.npmjs.org/@nodelib/fs.scandir/-/fs.scandir-2.1.5.tgz",
503 | "integrity": "sha512-vq24Bq3ym5HEQm2NKCr3yXDwjc7vTsEThRDnkp2DK9p1uqLR+DHurm/NOTo0KG7HYHU7eppKZj3MyqYuMBf62g==",
504 | "dev": true,
505 | "dependencies": {
506 | "@nodelib/fs.stat": "2.0.5",
507 | "run-parallel": "^1.1.9"
508 | },
509 | "engines": {
510 | "node": ">= 8"
511 | }
512 | },
513 | "node_modules/@nodelib/fs.stat": {
514 | "version": "2.0.5",
515 | "resolved": "https://registry.npmjs.org/@nodelib/fs.stat/-/fs.stat-2.0.5.tgz",
516 | "integrity": "sha512-RkhPPp2zrqDAQA/2jNhnztcPAlv64XdhIp7a7454A5ovI7Bukxgt7MX7udwAu3zg1DcpPU0rz3VV1SeaqvY4+A==",
517 | "dev": true,
518 | "engines": {
519 | "node": ">= 8"
520 | }
521 | },
522 | "node_modules/@nodelib/fs.walk": {
523 | "version": "1.2.8",
524 | "resolved": "https://registry.npmjs.org/@nodelib/fs.walk/-/fs.walk-1.2.8.tgz",
525 | "integrity": "sha512-oGB+UxlgWcgQkgwo8GcEGwemoTFt3FIO9ababBmaGwXIoBKZ+GTy0pP185beGg7Llih/NSHSV2XAs1lnznocSg==",
526 | "dev": true,
527 | "dependencies": {
528 | "@nodelib/fs.scandir": "2.1.5",
529 | "fastq": "^1.6.0"
530 | },
531 | "engines": {
532 | "node": ">= 8"
533 | }
534 | },
535 | "node_modules/@types/codemirror": {
536 | "version": "5.60.8",
537 | "resolved": "https://registry.npmjs.org/@types/codemirror/-/codemirror-5.60.8.tgz",
538 | "integrity": "sha512-VjFgDF/eB+Aklcy15TtOTLQeMjTo07k7KAjql8OK5Dirr7a6sJY4T1uVBDuTVG9VEmn1uUsohOpYnVfgC6/jyw==",
539 | "dev": true,
540 | "dependencies": {
541 | "@types/tern": "*"
542 | }
543 | },
544 | "node_modules/@types/estree": {
545 | "version": "1.0.5",
546 | "resolved": "https://registry.npmjs.org/@types/estree/-/estree-1.0.5.tgz",
547 | "integrity": "sha512-/kYRxGDLWzHOB7q+wtSUQlFrtcdUccpfy+X+9iMBpHK8QLLhx2wIPYuS5DYtR9Wa/YlZAbIovy7qVdB1Aq6Lyw==",
548 | "dev": true
549 | },
550 | "node_modules/@types/fuzzaldrin-plus": {
551 | "version": "0.6.5",
552 | "resolved": "https://registry.npmjs.org/@types/fuzzaldrin-plus/-/fuzzaldrin-plus-0.6.5.tgz",
553 | "integrity": "sha512-fUFxKXq/Qu8WVgPtSkQMK7jF5odTnBaIthuhKQb6PivpTaTTUlOTMS3WsT+UpWVZcYQH5skjHuFRTNmrUGSDfg==",
554 | "dev": true
555 | },
556 | "node_modules/@types/he": {
557 | "version": "1.2.3",
558 | "resolved": "https://registry.npmjs.org/@types/he/-/he-1.2.3.tgz",
559 | "integrity": "sha512-q67/qwlxblDzEDvzHhVkwc1gzVWxaNxeyHUBF4xElrvjL11O+Ytze+1fGpBHlr/H9myiBUaUXNnNPmBHxxfAcA=="
560 | },
561 | "node_modules/@types/json-schema": {
562 | "version": "7.0.15",
563 | "resolved": "https://registry.npmjs.org/@types/json-schema/-/json-schema-7.0.15.tgz",
564 | "integrity": "sha512-5+fP8P8MFNC+AyZCDxrB2pkZFPGzqQWUzpSeuuVLvm8VMcorNYavBqoFcxK8bQz4Qsbn4oUEEem4wDLfcysGHA==",
565 | "dev": true
566 | },
567 | "node_modules/@types/node": {
568 | "version": "16.18.101",
569 | "resolved": "https://registry.npmjs.org/@types/node/-/node-16.18.101.tgz",
570 | "integrity": "sha512-AAsx9Rgz2IzG8KJ6tXd6ndNkVcu+GYB6U/SnFAaokSPNx2N7dcIIfnighYUNumvj6YS2q39Dejz5tT0NCV7CWA==",
571 | "dev": true
572 | },
573 | "node_modules/@types/semver": {
574 | "version": "7.5.8",
575 | "resolved": "https://registry.npmjs.org/@types/semver/-/semver-7.5.8.tgz",
576 | "integrity": "sha512-I8EUhyrgfLrcTkzV3TSsGyl1tSuPrEDzr0yd5m90UgNxQkyDXULk3b6MlQqTCpZpNtWe1K0hzclnZkTcLBe2UQ==",
577 | "dev": true
578 | },
579 | "node_modules/@types/shell-escape": {
580 | "version": "0.2.3",
581 | "resolved": "https://registry.npmjs.org/@types/shell-escape/-/shell-escape-0.2.3.tgz",
582 | "integrity": "sha512-xZWkMuQkn1I20gEzhYRa4/t1pwZ8XiIkqGA1Iee1D2IgAUIRLr57nrgJgF2QmHEfkfVzOM59gi/4xp6V+Aq+4A==",
583 | "dev": true
584 | },
585 | "node_modules/@types/tern": {
586 | "version": "0.23.9",
587 | "resolved": "https://registry.npmjs.org/@types/tern/-/tern-0.23.9.tgz",
588 | "integrity": "sha512-ypzHFE/wBzh+BlH6rrBgS5I/Z7RD21pGhZ2rltb/+ZrVM1awdZwjx7hE5XfuYgHWk9uvV5HLZN3SloevCAp3Bw==",
589 | "dev": true,
590 | "dependencies": {
591 | "@types/estree": "*"
592 | }
593 | },
594 | "node_modules/@typescript-eslint/eslint-plugin": {
595 | "version": "5.29.0",
596 | "resolved": "https://registry.npmjs.org/@typescript-eslint/eslint-plugin/-/eslint-plugin-5.29.0.tgz",
597 | "integrity": "sha512-kgTsISt9pM53yRFQmLZ4npj99yGl3x3Pl7z4eA66OuTzAGC4bQB5H5fuLwPnqTKU3yyrrg4MIhjF17UYnL4c0w==",
598 | "dev": true,
599 | "dependencies": {
600 | "@typescript-eslint/scope-manager": "5.29.0",
601 | "@typescript-eslint/type-utils": "5.29.0",
602 | "@typescript-eslint/utils": "5.29.0",
603 | "debug": "^4.3.4",
604 | "functional-red-black-tree": "^1.0.1",
605 | "ignore": "^5.2.0",
606 | "regexpp": "^3.2.0",
607 | "semver": "^7.3.7",
608 | "tsutils": "^3.21.0"
609 | },
610 | "engines": {
611 | "node": "^12.22.0 || ^14.17.0 || >=16.0.0"
612 | },
613 | "funding": {
614 | "type": "opencollective",
615 | "url": "https://opencollective.com/typescript-eslint"
616 | },
617 | "peerDependencies": {
618 | "@typescript-eslint/parser": "^5.0.0",
619 | "eslint": "^6.0.0 || ^7.0.0 || ^8.0.0"
620 | },
621 | "peerDependenciesMeta": {
622 | "typescript": {
623 | "optional": true
624 | }
625 | }
626 | },
627 | "node_modules/@typescript-eslint/parser": {
628 | "version": "5.29.0",
629 | "resolved": "https://registry.npmjs.org/@typescript-eslint/parser/-/parser-5.29.0.tgz",
630 | "integrity": "sha512-ruKWTv+x0OOxbzIw9nW5oWlUopvP/IQDjB5ZqmTglLIoDTctLlAJpAQFpNPJP/ZI7hTT9sARBosEfaKbcFuECw==",
631 | "dev": true,
632 | "dependencies": {
633 | "@typescript-eslint/scope-manager": "5.29.0",
634 | "@typescript-eslint/types": "5.29.0",
635 | "@typescript-eslint/typescript-estree": "5.29.0",
636 | "debug": "^4.3.4"
637 | },
638 | "engines": {
639 | "node": "^12.22.0 || ^14.17.0 || >=16.0.0"
640 | },
641 | "funding": {
642 | "type": "opencollective",
643 | "url": "https://opencollective.com/typescript-eslint"
644 | },
645 | "peerDependencies": {
646 | "eslint": "^6.0.0 || ^7.0.0 || ^8.0.0"
647 | },
648 | "peerDependenciesMeta": {
649 | "typescript": {
650 | "optional": true
651 | }
652 | }
653 | },
654 | "node_modules/@typescript-eslint/scope-manager": {
655 | "version": "5.29.0",
656 | "resolved": "https://registry.npmjs.org/@typescript-eslint/scope-manager/-/scope-manager-5.29.0.tgz",
657 | "integrity": "sha512-etbXUT0FygFi2ihcxDZjz21LtC+Eps9V2xVx09zFoN44RRHPrkMflidGMI+2dUs821zR1tDS6Oc9IXxIjOUZwA==",
658 | "dev": true,
659 | "dependencies": {
660 | "@typescript-eslint/types": "5.29.0",
661 | "@typescript-eslint/visitor-keys": "5.29.0"
662 | },
663 | "engines": {
664 | "node": "^12.22.0 || ^14.17.0 || >=16.0.0"
665 | },
666 | "funding": {
667 | "type": "opencollective",
668 | "url": "https://opencollective.com/typescript-eslint"
669 | }
670 | },
671 | "node_modules/@typescript-eslint/type-utils": {
672 | "version": "5.29.0",
673 | "resolved": "https://registry.npmjs.org/@typescript-eslint/type-utils/-/type-utils-5.29.0.tgz",
674 | "integrity": "sha512-JK6bAaaiJozbox3K220VRfCzLa9n0ib/J+FHIwnaV3Enw/TO267qe0pM1b1QrrEuy6xun374XEAsRlA86JJnyg==",
675 | "dev": true,
676 | "dependencies": {
677 | "@typescript-eslint/utils": "5.29.0",
678 | "debug": "^4.3.4",
679 | "tsutils": "^3.21.0"
680 | },
681 | "engines": {
682 | "node": "^12.22.0 || ^14.17.0 || >=16.0.0"
683 | },
684 | "funding": {
685 | "type": "opencollective",
686 | "url": "https://opencollective.com/typescript-eslint"
687 | },
688 | "peerDependencies": {
689 | "eslint": "*"
690 | },
691 | "peerDependenciesMeta": {
692 | "typescript": {
693 | "optional": true
694 | }
695 | }
696 | },
697 | "node_modules/@typescript-eslint/types": {
698 | "version": "5.29.0",
699 | "resolved": "https://registry.npmjs.org/@typescript-eslint/types/-/types-5.29.0.tgz",
700 | "integrity": "sha512-X99VbqvAXOMdVyfFmksMy3u8p8yoRGITgU1joBJPzeYa0rhdf5ok9S56/itRoUSh99fiDoMtarSIJXo7H/SnOg==",
701 | "dev": true,
702 | "engines": {
703 | "node": "^12.22.0 || ^14.17.0 || >=16.0.0"
704 | },
705 | "funding": {
706 | "type": "opencollective",
707 | "url": "https://opencollective.com/typescript-eslint"
708 | }
709 | },
710 | "node_modules/@typescript-eslint/typescript-estree": {
711 | "version": "5.29.0",
712 | "resolved": "https://registry.npmjs.org/@typescript-eslint/typescript-estree/-/typescript-estree-5.29.0.tgz",
713 | "integrity": "sha512-mQvSUJ/JjGBdvo+1LwC+GY2XmSYjK1nAaVw2emp/E61wEVYEyibRHCqm1I1vEKbXCpUKuW4G7u9ZCaZhJbLoNQ==",
714 | "dev": true,
715 | "dependencies": {
716 | "@typescript-eslint/types": "5.29.0",
717 | "@typescript-eslint/visitor-keys": "5.29.0",
718 | "debug": "^4.3.4",
719 | "globby": "^11.1.0",
720 | "is-glob": "^4.0.3",
721 | "semver": "^7.3.7",
722 | "tsutils": "^3.21.0"
723 | },
724 | "engines": {
725 | "node": "^12.22.0 || ^14.17.0 || >=16.0.0"
726 | },
727 | "funding": {
728 | "type": "opencollective",
729 | "url": "https://opencollective.com/typescript-eslint"
730 | },
731 | "peerDependenciesMeta": {
732 | "typescript": {
733 | "optional": true
734 | }
735 | }
736 | },
737 | "node_modules/@typescript-eslint/utils": {
738 | "version": "5.29.0",
739 | "resolved": "https://registry.npmjs.org/@typescript-eslint/utils/-/utils-5.29.0.tgz",
740 | "integrity": "sha512-3Eos6uP1nyLOBayc/VUdKZikV90HahXE5Dx9L5YlSd/7ylQPXhLk1BYb29SDgnBnTp+jmSZUU0QxUiyHgW4p7A==",
741 | "dev": true,
742 | "dependencies": {
743 | "@types/json-schema": "^7.0.9",
744 | "@typescript-eslint/scope-manager": "5.29.0",
745 | "@typescript-eslint/types": "5.29.0",
746 | "@typescript-eslint/typescript-estree": "5.29.0",
747 | "eslint-scope": "^5.1.1",
748 | "eslint-utils": "^3.0.0"
749 | },
750 | "engines": {
751 | "node": "^12.22.0 || ^14.17.0 || >=16.0.0"
752 | },
753 | "funding": {
754 | "type": "opencollective",
755 | "url": "https://opencollective.com/typescript-eslint"
756 | },
757 | "peerDependencies": {
758 | "eslint": "^6.0.0 || ^7.0.0 || ^8.0.0"
759 | }
760 | },
761 | "node_modules/@typescript-eslint/visitor-keys": {
762 | "version": "5.29.0",
763 | "resolved": "https://registry.npmjs.org/@typescript-eslint/visitor-keys/-/visitor-keys-5.29.0.tgz",
764 | "integrity": "sha512-Hpb/mCWsjILvikMQoZIE3voc9wtQcS0A9FUw3h8bhr9UxBdtI/tw1ZDZUOXHXLOVMedKCH5NxyzATwnU78bWCQ==",
765 | "dev": true,
766 | "dependencies": {
767 | "@typescript-eslint/types": "5.29.0",
768 | "eslint-visitor-keys": "^3.3.0"
769 | },
770 | "engines": {
771 | "node": "^12.22.0 || ^14.17.0 || >=16.0.0"
772 | },
773 | "funding": {
774 | "type": "opencollective",
775 | "url": "https://opencollective.com/typescript-eslint"
776 | }
777 | },
778 | "node_modules/@ungap/structured-clone": {
779 | "version": "1.2.0",
780 | "resolved": "https://registry.npmjs.org/@ungap/structured-clone/-/structured-clone-1.2.0.tgz",
781 | "integrity": "sha512-zuVdFrMJiuCDQUMCzQaD6KL28MjnqqN8XnAqiEq9PNm/hCPTSGfrXCOfwj1ow4LFb/tNymJPwsNbVePc1xFqrQ==",
782 | "dev": true,
783 | "peer": true
784 | },
785 | "node_modules/acorn": {
786 | "version": "8.12.0",
787 | "resolved": "https://registry.npmjs.org/acorn/-/acorn-8.12.0.tgz",
788 | "integrity": "sha512-RTvkC4w+KNXrM39/lWCUaG0IbRkWdCv7W/IOW9oU6SawyxulvkQy5HQPVTKxEjczcUvapcrw3cFx/60VN/NRNw==",
789 | "dev": true,
790 | "peer": true,
791 | "bin": {
792 | "acorn": "bin/acorn"
793 | },
794 | "engines": {
795 | "node": ">=0.4.0"
796 | }
797 | },
798 | "node_modules/acorn-jsx": {
799 | "version": "5.3.2",
800 | "resolved": "https://registry.npmjs.org/acorn-jsx/-/acorn-jsx-5.3.2.tgz",
801 | "integrity": "sha512-rq9s+JNhf0IChjtDXxllJ7g41oZk5SlXtp0LHwyA5cejwn7vKmKp4pPri6YEePv2PU65sAsegbXtIinmDFDXgQ==",
802 | "dev": true,
803 | "peer": true,
804 | "peerDependencies": {
805 | "acorn": "^6.0.0 || ^7.0.0 || ^8.0.0"
806 | }
807 | },
808 | "node_modules/ajv": {
809 | "version": "6.12.6",
810 | "resolved": "https://registry.npmjs.org/ajv/-/ajv-6.12.6.tgz",
811 | "integrity": "sha512-j3fVLgvTo527anyYyJOGTYJbG+vnnQYvE0m5mmkc1TK+nxAppkCLMIL0aZ4dblVCNoGShhm+kzE4ZUykBoMg4g==",
812 | "dev": true,
813 | "peer": true,
814 | "dependencies": {
815 | "fast-deep-equal": "^3.1.1",
816 | "fast-json-stable-stringify": "^2.0.0",
817 | "json-schema-traverse": "^0.4.1",
818 | "uri-js": "^4.2.2"
819 | },
820 | "funding": {
821 | "type": "github",
822 | "url": "https://github.com/sponsors/epoberezkin"
823 | }
824 | },
825 | "node_modules/ansi-regex": {
826 | "version": "5.0.1",
827 | "resolved": "https://registry.npmjs.org/ansi-regex/-/ansi-regex-5.0.1.tgz",
828 | "integrity": "sha512-quJQXlTSUGL2LH9SUXo8VwsY4soanhgo6LNSm84E1LBcE8s3O0wpdiRzyR9z/ZZJMlMWv37qOOb9pdJlMUEKFQ==",
829 | "dev": true,
830 | "peer": true,
831 | "engines": {
832 | "node": ">=8"
833 | }
834 | },
835 | "node_modules/ansi-styles": {
836 | "version": "4.3.0",
837 | "resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-4.3.0.tgz",
838 | "integrity": "sha512-zbB9rCJAT1rbjiVDb2hqKFHNYLxgtk8NURxZ3IZwD3F6NtxbXZQCnnSi1Lkx+IDohdPlFp222wVALIheZJQSEg==",
839 | "dev": true,
840 | "peer": true,
841 | "dependencies": {
842 | "color-convert": "^2.0.1"
843 | },
844 | "engines": {
845 | "node": ">=8"
846 | },
847 | "funding": {
848 | "url": "https://github.com/chalk/ansi-styles?sponsor=1"
849 | }
850 | },
851 | "node_modules/argparse": {
852 | "version": "2.0.1",
853 | "resolved": "https://registry.npmjs.org/argparse/-/argparse-2.0.1.tgz",
854 | "integrity": "sha512-8+9WqebbFzpX9OR+Wa6O29asIogeRMzcGtAINdpMHHyAg10f05aSFVBbcEqGf/PXw1EjAZ+q2/bEBg3DvurK3Q==",
855 | "dev": true,
856 | "peer": true
857 | },
858 | "node_modules/array-union": {
859 | "version": "2.1.0",
860 | "resolved": "https://registry.npmjs.org/array-union/-/array-union-2.1.0.tgz",
861 | "integrity": "sha512-HGyxoOTYUyCM6stUe6EJgnd4EoewAI7zMdfqO+kGjnlZmBDz/cR5pf8r/cR4Wq60sL/p0IkcjUEEPwS3GFrIyw==",
862 | "dev": true,
863 | "engines": {
864 | "node": ">=8"
865 | }
866 | },
867 | "node_modules/balanced-match": {
868 | "version": "1.0.2",
869 | "resolved": "https://registry.npmjs.org/balanced-match/-/balanced-match-1.0.2.tgz",
870 | "integrity": "sha512-3oSeUO0TMV67hN1AmbXsK4yaqU7tjiHlbxRDZOpH0KW9+CeX4bRAaX0Anxt0tx2MrpRpWwQaPwIlISEJhYU5Pw==",
871 | "dev": true,
872 | "peer": true
873 | },
874 | "node_modules/brace-expansion": {
875 | "version": "1.1.11",
876 | "resolved": "https://registry.npmjs.org/brace-expansion/-/brace-expansion-1.1.11.tgz",
877 | "integrity": "sha512-iCuPHDFgrHX7H2vEI/5xpz07zSHB00TpugqhmYtVmMO6518mCuRMoOYFldEBl0g187ufozdaHgWKcYFb61qGiA==",
878 | "dev": true,
879 | "peer": true,
880 | "dependencies": {
881 | "balanced-match": "^1.0.0",
882 | "concat-map": "0.0.1"
883 | }
884 | },
885 | "node_modules/braces": {
886 | "version": "3.0.3",
887 | "resolved": "https://registry.npmjs.org/braces/-/braces-3.0.3.tgz",
888 | "integrity": "sha512-yQbXgO/OSZVD2IsiLlro+7Hf6Q18EJrKSEsdoMzKePKXct3gvD8oLcOQdIzGupr5Fj+EDe8gO/lxc1BzfMpxvA==",
889 | "dev": true,
890 | "dependencies": {
891 | "fill-range": "^7.1.1"
892 | },
893 | "engines": {
894 | "node": ">=8"
895 | }
896 | },
897 | "node_modules/builtin-modules": {
898 | "version": "3.3.0",
899 | "resolved": "https://registry.npmjs.org/builtin-modules/-/builtin-modules-3.3.0.tgz",
900 | "integrity": "sha512-zhaCDicdLuWN5UbN5IMnFqNMhNfo919sH85y2/ea+5Yg9TsTkeZxpL+JLbp6cgYFS4sRLp3YV4S6yDuqVWHYOw==",
901 | "dev": true,
902 | "engines": {
903 | "node": ">=6"
904 | },
905 | "funding": {
906 | "url": "https://github.com/sponsors/sindresorhus"
907 | }
908 | },
909 | "node_modules/callsites": {
910 | "version": "3.1.0",
911 | "resolved": "https://registry.npmjs.org/callsites/-/callsites-3.1.0.tgz",
912 | "integrity": "sha512-P8BjAsXvZS+VIDUI11hHCQEv74YT67YUi5JJFNWIqL235sBmjX4+qx9Muvls5ivyNENctx46xQLQ3aTuE7ssaQ==",
913 | "dev": true,
914 | "peer": true,
915 | "engines": {
916 | "node": ">=6"
917 | }
918 | },
919 | "node_modules/chalk": {
920 | "version": "4.1.2",
921 | "resolved": "https://registry.npmjs.org/chalk/-/chalk-4.1.2.tgz",
922 | "integrity": "sha512-oKnbhFyRIXpUuez8iBMmyEa4nbj4IOQyuhc/wy9kY7/WVPcwIO9VA668Pu8RkO7+0G76SLROeyw9CpQ061i4mA==",
923 | "dev": true,
924 | "peer": true,
925 | "dependencies": {
926 | "ansi-styles": "^4.1.0",
927 | "supports-color": "^7.1.0"
928 | },
929 | "engines": {
930 | "node": ">=10"
931 | },
932 | "funding": {
933 | "url": "https://github.com/chalk/chalk?sponsor=1"
934 | }
935 | },
936 | "node_modules/color-convert": {
937 | "version": "2.0.1",
938 | "resolved": "https://registry.npmjs.org/color-convert/-/color-convert-2.0.1.tgz",
939 | "integrity": "sha512-RRECPsj7iu/xb5oKYcsFHSppFNnsj/52OVTRKb4zP5onXwVF3zVmmToNcOfGC+CRDpfK/U584fMg38ZHCaElKQ==",
940 | "dev": true,
941 | "peer": true,
942 | "dependencies": {
943 | "color-name": "~1.1.4"
944 | },
945 | "engines": {
946 | "node": ">=7.0.0"
947 | }
948 | },
949 | "node_modules/color-name": {
950 | "version": "1.1.4",
951 | "resolved": "https://registry.npmjs.org/color-name/-/color-name-1.1.4.tgz",
952 | "integrity": "sha512-dOy+3AuW3a2wNbZHIuMZpTcgjGuLU/uBL/ubcZF9OXbDo8ff4O8yVp5Bf0efS8uEoYo5q4Fx7dY9OgQGXgAsQA==",
953 | "dev": true,
954 | "peer": true
955 | },
956 | "node_modules/concat-map": {
957 | "version": "0.0.1",
958 | "resolved": "https://registry.npmjs.org/concat-map/-/concat-map-0.0.1.tgz",
959 | "integrity": "sha512-/Srv4dswyQNBfohGpz9o6Yb3Gz3SrUDqBH5rTuhGR7ahtlbYKnVxw2bCFMRljaA7EXHaXZ8wsHdodFvbkhKmqg==",
960 | "dev": true,
961 | "peer": true
962 | },
963 | "node_modules/cross-spawn": {
964 | "version": "7.0.3",
965 | "resolved": "https://registry.npmjs.org/cross-spawn/-/cross-spawn-7.0.3.tgz",
966 | "integrity": "sha512-iRDPJKUPVEND7dHPO8rkbOnPpyDygcDFtWjpeWNCgy8WP2rXcxXL8TskReQl6OrB2G7+UJrags1q15Fudc7G6w==",
967 | "dev": true,
968 | "peer": true,
969 | "dependencies": {
970 | "path-key": "^3.1.0",
971 | "shebang-command": "^2.0.0",
972 | "which": "^2.0.1"
973 | },
974 | "engines": {
975 | "node": ">= 8"
976 | }
977 | },
978 | "node_modules/debug": {
979 | "version": "4.3.5",
980 | "resolved": "https://registry.npmjs.org/debug/-/debug-4.3.5.tgz",
981 | "integrity": "sha512-pt0bNEmneDIvdL1Xsd9oDQ/wrQRkXDT4AUWlNZNPKvW5x/jyO9VFXkJUP07vQ2upmw5PlaITaPKc31jK13V+jg==",
982 | "dev": true,
983 | "dependencies": {
984 | "ms": "2.1.2"
985 | },
986 | "engines": {
987 | "node": ">=6.0"
988 | },
989 | "peerDependenciesMeta": {
990 | "supports-color": {
991 | "optional": true
992 | }
993 | }
994 | },
995 | "node_modules/deep-is": {
996 | "version": "0.1.4",
997 | "resolved": "https://registry.npmjs.org/deep-is/-/deep-is-0.1.4.tgz",
998 | "integrity": "sha512-oIPzksmTg4/MriiaYGO+okXDT7ztn/w3Eptv/+gSIdMdKsJo0u4CfYNFJPy+4SKMuCqGw2wxnA+URMg3t8a/bQ==",
999 | "dev": true,
1000 | "peer": true
1001 | },
1002 | "node_modules/dir-glob": {
1003 | "version": "3.0.1",
1004 | "resolved": "https://registry.npmjs.org/dir-glob/-/dir-glob-3.0.1.tgz",
1005 | "integrity": "sha512-WkrWp9GR4KXfKGYzOLmTuGVi1UWFfws377n9cc55/tb6DuqyF6pcQ5AbiHEshaDpY9v6oaSr2XCDidGmMwdzIA==",
1006 | "dev": true,
1007 | "dependencies": {
1008 | "path-type": "^4.0.0"
1009 | },
1010 | "engines": {
1011 | "node": ">=8"
1012 | }
1013 | },
1014 | "node_modules/doctrine": {
1015 | "version": "3.0.0",
1016 | "resolved": "https://registry.npmjs.org/doctrine/-/doctrine-3.0.0.tgz",
1017 | "integrity": "sha512-yS+Q5i3hBf7GBkd4KG8a7eBNNWNGLTaEwwYWUijIYM7zrlYDM0BFXHjjPWlWZ1Rg7UaddZeIDmi9jF3HmqiQ2w==",
1018 | "dev": true,
1019 | "peer": true,
1020 | "dependencies": {
1021 | "esutils": "^2.0.2"
1022 | },
1023 | "engines": {
1024 | "node": ">=6.0.0"
1025 | }
1026 | },
1027 | "node_modules/esbuild": {
1028 | "version": "0.17.3",
1029 | "resolved": "https://registry.npmjs.org/esbuild/-/esbuild-0.17.3.tgz",
1030 | "integrity": "sha512-9n3AsBRe6sIyOc6kmoXg2ypCLgf3eZSraWFRpnkto+svt8cZNuKTkb1bhQcitBcvIqjNiK7K0J3KPmwGSfkA8g==",
1031 | "dev": true,
1032 | "hasInstallScript": true,
1033 | "bin": {
1034 | "esbuild": "bin/esbuild"
1035 | },
1036 | "engines": {
1037 | "node": ">=12"
1038 | },
1039 | "optionalDependencies": {
1040 | "@esbuild/android-arm": "0.17.3",
1041 | "@esbuild/android-arm64": "0.17.3",
1042 | "@esbuild/android-x64": "0.17.3",
1043 | "@esbuild/darwin-arm64": "0.17.3",
1044 | "@esbuild/darwin-x64": "0.17.3",
1045 | "@esbuild/freebsd-arm64": "0.17.3",
1046 | "@esbuild/freebsd-x64": "0.17.3",
1047 | "@esbuild/linux-arm": "0.17.3",
1048 | "@esbuild/linux-arm64": "0.17.3",
1049 | "@esbuild/linux-ia32": "0.17.3",
1050 | "@esbuild/linux-loong64": "0.17.3",
1051 | "@esbuild/linux-mips64el": "0.17.3",
1052 | "@esbuild/linux-ppc64": "0.17.3",
1053 | "@esbuild/linux-riscv64": "0.17.3",
1054 | "@esbuild/linux-s390x": "0.17.3",
1055 | "@esbuild/linux-x64": "0.17.3",
1056 | "@esbuild/netbsd-x64": "0.17.3",
1057 | "@esbuild/openbsd-x64": "0.17.3",
1058 | "@esbuild/sunos-x64": "0.17.3",
1059 | "@esbuild/win32-arm64": "0.17.3",
1060 | "@esbuild/win32-ia32": "0.17.3",
1061 | "@esbuild/win32-x64": "0.17.3"
1062 | }
1063 | },
1064 | "node_modules/escape-string-regexp": {
1065 | "version": "4.0.0",
1066 | "resolved": "https://registry.npmjs.org/escape-string-regexp/-/escape-string-regexp-4.0.0.tgz",
1067 | "integrity": "sha512-TtpcNJ3XAzx3Gq8sWRzJaVajRs0uVxA2YAkdb1jm2YkPz4G6egUFAyA3n5vtEIZefPk5Wa4UXbKuS5fKkJWdgA==",
1068 | "dev": true,
1069 | "peer": true,
1070 | "engines": {
1071 | "node": ">=10"
1072 | },
1073 | "funding": {
1074 | "url": "https://github.com/sponsors/sindresorhus"
1075 | }
1076 | },
1077 | "node_modules/eslint": {
1078 | "version": "8.57.0",
1079 | "resolved": "https://registry.npmjs.org/eslint/-/eslint-8.57.0.tgz",
1080 | "integrity": "sha512-dZ6+mexnaTIbSBZWgou51U6OmzIhYM2VcNdtiTtI7qPNZm35Akpr0f6vtw3w1Kmn5PYo+tZVfh13WrhpS6oLqQ==",
1081 | "dev": true,
1082 | "peer": true,
1083 | "dependencies": {
1084 | "@eslint-community/eslint-utils": "^4.2.0",
1085 | "@eslint-community/regexpp": "^4.6.1",
1086 | "@eslint/eslintrc": "^2.1.4",
1087 | "@eslint/js": "8.57.0",
1088 | "@humanwhocodes/config-array": "^0.11.14",
1089 | "@humanwhocodes/module-importer": "^1.0.1",
1090 | "@nodelib/fs.walk": "^1.2.8",
1091 | "@ungap/structured-clone": "^1.2.0",
1092 | "ajv": "^6.12.4",
1093 | "chalk": "^4.0.0",
1094 | "cross-spawn": "^7.0.2",
1095 | "debug": "^4.3.2",
1096 | "doctrine": "^3.0.0",
1097 | "escape-string-regexp": "^4.0.0",
1098 | "eslint-scope": "^7.2.2",
1099 | "eslint-visitor-keys": "^3.4.3",
1100 | "espree": "^9.6.1",
1101 | "esquery": "^1.4.2",
1102 | "esutils": "^2.0.2",
1103 | "fast-deep-equal": "^3.1.3",
1104 | "file-entry-cache": "^6.0.1",
1105 | "find-up": "^5.0.0",
1106 | "glob-parent": "^6.0.2",
1107 | "globals": "^13.19.0",
1108 | "graphemer": "^1.4.0",
1109 | "ignore": "^5.2.0",
1110 | "imurmurhash": "^0.1.4",
1111 | "is-glob": "^4.0.0",
1112 | "is-path-inside": "^3.0.3",
1113 | "js-yaml": "^4.1.0",
1114 | "json-stable-stringify-without-jsonify": "^1.0.1",
1115 | "levn": "^0.4.1",
1116 | "lodash.merge": "^4.6.2",
1117 | "minimatch": "^3.1.2",
1118 | "natural-compare": "^1.4.0",
1119 | "optionator": "^0.9.3",
1120 | "strip-ansi": "^6.0.1",
1121 | "text-table": "^0.2.0"
1122 | },
1123 | "bin": {
1124 | "eslint": "bin/eslint.js"
1125 | },
1126 | "engines": {
1127 | "node": "^12.22.0 || ^14.17.0 || >=16.0.0"
1128 | },
1129 | "funding": {
1130 | "url": "https://opencollective.com/eslint"
1131 | }
1132 | },
1133 | "node_modules/eslint-scope": {
1134 | "version": "5.1.1",
1135 | "resolved": "https://registry.npmjs.org/eslint-scope/-/eslint-scope-5.1.1.tgz",
1136 | "integrity": "sha512-2NxwbF/hZ0KpepYN0cNbo+FN6XoK7GaHlQhgx/hIZl6Va0bF45RQOOwhLIy8lQDbuCiadSLCBnH2CFYquit5bw==",
1137 | "dev": true,
1138 | "dependencies": {
1139 | "esrecurse": "^4.3.0",
1140 | "estraverse": "^4.1.1"
1141 | },
1142 | "engines": {
1143 | "node": ">=8.0.0"
1144 | }
1145 | },
1146 | "node_modules/eslint-utils": {
1147 | "version": "3.0.0",
1148 | "resolved": "https://registry.npmjs.org/eslint-utils/-/eslint-utils-3.0.0.tgz",
1149 | "integrity": "sha512-uuQC43IGctw68pJA1RgbQS8/NP7rch6Cwd4j3ZBtgo4/8Flj4eGE7ZYSZRN3iq5pVUv6GPdW5Z1RFleo84uLDA==",
1150 | "dev": true,
1151 | "dependencies": {
1152 | "eslint-visitor-keys": "^2.0.0"
1153 | },
1154 | "engines": {
1155 | "node": "^10.0.0 || ^12.0.0 || >= 14.0.0"
1156 | },
1157 | "funding": {
1158 | "url": "https://github.com/sponsors/mysticatea"
1159 | },
1160 | "peerDependencies": {
1161 | "eslint": ">=5"
1162 | }
1163 | },
1164 | "node_modules/eslint-utils/node_modules/eslint-visitor-keys": {
1165 | "version": "2.1.0",
1166 | "resolved": "https://registry.npmjs.org/eslint-visitor-keys/-/eslint-visitor-keys-2.1.0.tgz",
1167 | "integrity": "sha512-0rSmRBzXgDzIsD6mGdJgevzgezI534Cer5L/vyMX0kHzT/jiB43jRhd9YUlMGYLQy2zprNmoT8qasCGtY+QaKw==",
1168 | "dev": true,
1169 | "engines": {
1170 | "node": ">=10"
1171 | }
1172 | },
1173 | "node_modules/eslint-visitor-keys": {
1174 | "version": "3.4.3",
1175 | "resolved": "https://registry.npmjs.org/eslint-visitor-keys/-/eslint-visitor-keys-3.4.3.tgz",
1176 | "integrity": "sha512-wpc+LXeiyiisxPlEkUzU6svyS1frIO3Mgxj1fdy7Pm8Ygzguax2N3Fa/D/ag1WqbOprdI+uY6wMUl8/a2G+iag==",
1177 | "dev": true,
1178 | "engines": {
1179 | "node": "^12.22.0 || ^14.17.0 || >=16.0.0"
1180 | },
1181 | "funding": {
1182 | "url": "https://opencollective.com/eslint"
1183 | }
1184 | },
1185 | "node_modules/eslint/node_modules/eslint-scope": {
1186 | "version": "7.2.2",
1187 | "resolved": "https://registry.npmjs.org/eslint-scope/-/eslint-scope-7.2.2.tgz",
1188 | "integrity": "sha512-dOt21O7lTMhDM+X9mB4GX+DZrZtCUJPL/wlcTqxyrx5IvO0IYtILdtrQGQp+8n5S0gwSVmOf9NQrjMOgfQZlIg==",
1189 | "dev": true,
1190 | "peer": true,
1191 | "dependencies": {
1192 | "esrecurse": "^4.3.0",
1193 | "estraverse": "^5.2.0"
1194 | },
1195 | "engines": {
1196 | "node": "^12.22.0 || ^14.17.0 || >=16.0.0"
1197 | },
1198 | "funding": {
1199 | "url": "https://opencollective.com/eslint"
1200 | }
1201 | },
1202 | "node_modules/eslint/node_modules/estraverse": {
1203 | "version": "5.3.0",
1204 | "resolved": "https://registry.npmjs.org/estraverse/-/estraverse-5.3.0.tgz",
1205 | "integrity": "sha512-MMdARuVEQziNTeJD8DgMqmhwR11BRQ/cBP+pLtYdSTnf3MIO8fFeiINEbX36ZdNlfU/7A9f3gUw49B3oQsvwBA==",
1206 | "dev": true,
1207 | "peer": true,
1208 | "engines": {
1209 | "node": ">=4.0"
1210 | }
1211 | },
1212 | "node_modules/espree": {
1213 | "version": "9.6.1",
1214 | "resolved": "https://registry.npmjs.org/espree/-/espree-9.6.1.tgz",
1215 | "integrity": "sha512-oruZaFkjorTpF32kDSI5/75ViwGeZginGGy2NoOSg3Q9bnwlnmDm4HLnkl0RE3n+njDXR037aY1+x58Z/zFdwQ==",
1216 | "dev": true,
1217 | "peer": true,
1218 | "dependencies": {
1219 | "acorn": "^8.9.0",
1220 | "acorn-jsx": "^5.3.2",
1221 | "eslint-visitor-keys": "^3.4.1"
1222 | },
1223 | "engines": {
1224 | "node": "^12.22.0 || ^14.17.0 || >=16.0.0"
1225 | },
1226 | "funding": {
1227 | "url": "https://opencollective.com/eslint"
1228 | }
1229 | },
1230 | "node_modules/esquery": {
1231 | "version": "1.5.0",
1232 | "resolved": "https://registry.npmjs.org/esquery/-/esquery-1.5.0.tgz",
1233 | "integrity": "sha512-YQLXUplAwJgCydQ78IMJywZCceoqk1oH01OERdSAJc/7U2AylwjhSCLDEtqwg811idIS/9fIU5GjG73IgjKMVg==",
1234 | "dev": true,
1235 | "peer": true,
1236 | "dependencies": {
1237 | "estraverse": "^5.1.0"
1238 | },
1239 | "engines": {
1240 | "node": ">=0.10"
1241 | }
1242 | },
1243 | "node_modules/esquery/node_modules/estraverse": {
1244 | "version": "5.3.0",
1245 | "resolved": "https://registry.npmjs.org/estraverse/-/estraverse-5.3.0.tgz",
1246 | "integrity": "sha512-MMdARuVEQziNTeJD8DgMqmhwR11BRQ/cBP+pLtYdSTnf3MIO8fFeiINEbX36ZdNlfU/7A9f3gUw49B3oQsvwBA==",
1247 | "dev": true,
1248 | "peer": true,
1249 | "engines": {
1250 | "node": ">=4.0"
1251 | }
1252 | },
1253 | "node_modules/esrecurse": {
1254 | "version": "4.3.0",
1255 | "resolved": "https://registry.npmjs.org/esrecurse/-/esrecurse-4.3.0.tgz",
1256 | "integrity": "sha512-KmfKL3b6G+RXvP8N1vr3Tq1kL/oCFgn2NYXEtqP8/L3pKapUA4G8cFVaoF3SU323CD4XypR/ffioHmkti6/Tag==",
1257 | "dev": true,
1258 | "dependencies": {
1259 | "estraverse": "^5.2.0"
1260 | },
1261 | "engines": {
1262 | "node": ">=4.0"
1263 | }
1264 | },
1265 | "node_modules/esrecurse/node_modules/estraverse": {
1266 | "version": "5.3.0",
1267 | "resolved": "https://registry.npmjs.org/estraverse/-/estraverse-5.3.0.tgz",
1268 | "integrity": "sha512-MMdARuVEQziNTeJD8DgMqmhwR11BRQ/cBP+pLtYdSTnf3MIO8fFeiINEbX36ZdNlfU/7A9f3gUw49B3oQsvwBA==",
1269 | "dev": true,
1270 | "engines": {
1271 | "node": ">=4.0"
1272 | }
1273 | },
1274 | "node_modules/estraverse": {
1275 | "version": "4.3.0",
1276 | "resolved": "https://registry.npmjs.org/estraverse/-/estraverse-4.3.0.tgz",
1277 | "integrity": "sha512-39nnKffWz8xN1BU/2c79n9nB9HDzo0niYUqx6xyqUnyoAnQyyWpOTdZEeiCch8BBu515t4wp9ZmgVfVhn9EBpw==",
1278 | "dev": true,
1279 | "engines": {
1280 | "node": ">=4.0"
1281 | }
1282 | },
1283 | "node_modules/esutils": {
1284 | "version": "2.0.3",
1285 | "resolved": "https://registry.npmjs.org/esutils/-/esutils-2.0.3.tgz",
1286 | "integrity": "sha512-kVscqXk4OCp68SZ0dkgEKVi6/8ij300KBWTJq32P/dYeWTSwK41WyTxalN1eRmA5Z9UU/LX9D7FWSmV9SAYx6g==",
1287 | "dev": true,
1288 | "peer": true,
1289 | "engines": {
1290 | "node": ">=0.10.0"
1291 | }
1292 | },
1293 | "node_modules/fast-deep-equal": {
1294 | "version": "3.1.3",
1295 | "resolved": "https://registry.npmjs.org/fast-deep-equal/-/fast-deep-equal-3.1.3.tgz",
1296 | "integrity": "sha512-f3qQ9oQy9j2AhBe/H9VC91wLmKBCCU/gDOnKNAYG5hswO7BLKj09Hc5HYNz9cGI++xlpDCIgDaitVs03ATR84Q==",
1297 | "dev": true,
1298 | "peer": true
1299 | },
1300 | "node_modules/fast-glob": {
1301 | "version": "3.3.2",
1302 | "resolved": "https://registry.npmjs.org/fast-glob/-/fast-glob-3.3.2.tgz",
1303 | "integrity": "sha512-oX2ruAFQwf/Orj8m737Y5adxDQO0LAB7/S5MnxCdTNDd4p6BsyIVsv9JQsATbTSq8KHRpLwIHbVlUNatxd+1Ow==",
1304 | "dev": true,
1305 | "dependencies": {
1306 | "@nodelib/fs.stat": "^2.0.2",
1307 | "@nodelib/fs.walk": "^1.2.3",
1308 | "glob-parent": "^5.1.2",
1309 | "merge2": "^1.3.0",
1310 | "micromatch": "^4.0.4"
1311 | },
1312 | "engines": {
1313 | "node": ">=8.6.0"
1314 | }
1315 | },
1316 | "node_modules/fast-glob/node_modules/glob-parent": {
1317 | "version": "5.1.2",
1318 | "resolved": "https://registry.npmjs.org/glob-parent/-/glob-parent-5.1.2.tgz",
1319 | "integrity": "sha512-AOIgSQCepiJYwP3ARnGx+5VnTu2HBYdzbGP45eLw1vr3zB3vZLeyed1sC9hnbcOc9/SrMyM5RPQrkGz4aS9Zow==",
1320 | "dev": true,
1321 | "dependencies": {
1322 | "is-glob": "^4.0.1"
1323 | },
1324 | "engines": {
1325 | "node": ">= 6"
1326 | }
1327 | },
1328 | "node_modules/fast-json-stable-stringify": {
1329 | "version": "2.1.0",
1330 | "resolved": "https://registry.npmjs.org/fast-json-stable-stringify/-/fast-json-stable-stringify-2.1.0.tgz",
1331 | "integrity": "sha512-lhd/wF+Lk98HZoTCtlVraHtfh5XYijIjalXck7saUtuanSDyLMxnHhSXEDJqHxD7msR8D0uCmqlkwjCV8xvwHw==",
1332 | "dev": true,
1333 | "peer": true
1334 | },
1335 | "node_modules/fast-levenshtein": {
1336 | "version": "2.0.6",
1337 | "resolved": "https://registry.npmjs.org/fast-levenshtein/-/fast-levenshtein-2.0.6.tgz",
1338 | "integrity": "sha512-DCXu6Ifhqcks7TZKY3Hxp3y6qphY5SJZmrWMDrKcERSOXWQdMhU9Ig/PYrzyw/ul9jOIyh0N4M0tbC5hodg8dw==",
1339 | "dev": true,
1340 | "peer": true
1341 | },
1342 | "node_modules/fastq": {
1343 | "version": "1.17.1",
1344 | "resolved": "https://registry.npmjs.org/fastq/-/fastq-1.17.1.tgz",
1345 | "integrity": "sha512-sRVD3lWVIXWg6By68ZN7vho9a1pQcN/WBFaAAsDDFzlJjvoGx0P8z7V1t72grFJfJhu3YPZBuu25f7Kaw2jN1w==",
1346 | "dev": true,
1347 | "dependencies": {
1348 | "reusify": "^1.0.4"
1349 | }
1350 | },
1351 | "node_modules/file-entry-cache": {
1352 | "version": "6.0.1",
1353 | "resolved": "https://registry.npmjs.org/file-entry-cache/-/file-entry-cache-6.0.1.tgz",
1354 | "integrity": "sha512-7Gps/XWymbLk2QLYK4NzpMOrYjMhdIxXuIvy2QBsLE6ljuodKvdkWs/cpyJJ3CVIVpH0Oi1Hvg1ovbMzLdFBBg==",
1355 | "dev": true,
1356 | "peer": true,
1357 | "dependencies": {
1358 | "flat-cache": "^3.0.4"
1359 | },
1360 | "engines": {
1361 | "node": "^10.12.0 || >=12.0.0"
1362 | }
1363 | },
1364 | "node_modules/fill-range": {
1365 | "version": "7.1.1",
1366 | "resolved": "https://registry.npmjs.org/fill-range/-/fill-range-7.1.1.tgz",
1367 | "integrity": "sha512-YsGpe3WHLK8ZYi4tWDg2Jy3ebRz2rXowDxnld4bkQB00cc/1Zw9AWnC0i9ztDJitivtQvaI9KaLyKrc+hBW0yg==",
1368 | "dev": true,
1369 | "dependencies": {
1370 | "to-regex-range": "^5.0.1"
1371 | },
1372 | "engines": {
1373 | "node": ">=8"
1374 | }
1375 | },
1376 | "node_modules/find-up": {
1377 | "version": "5.0.0",
1378 | "resolved": "https://registry.npmjs.org/find-up/-/find-up-5.0.0.tgz",
1379 | "integrity": "sha512-78/PXT1wlLLDgTzDs7sjq9hzz0vXD+zn+7wypEe4fXQxCmdmqfGsEPQxmiCSQI3ajFV91bVSsvNtrJRiW6nGng==",
1380 | "dev": true,
1381 | "peer": true,
1382 | "dependencies": {
1383 | "locate-path": "^6.0.0",
1384 | "path-exists": "^4.0.0"
1385 | },
1386 | "engines": {
1387 | "node": ">=10"
1388 | },
1389 | "funding": {
1390 | "url": "https://github.com/sponsors/sindresorhus"
1391 | }
1392 | },
1393 | "node_modules/flat-cache": {
1394 | "version": "3.2.0",
1395 | "resolved": "https://registry.npmjs.org/flat-cache/-/flat-cache-3.2.0.tgz",
1396 | "integrity": "sha512-CYcENa+FtcUKLmhhqyctpclsq7QF38pKjZHsGNiSQF5r4FtoKDWabFDl3hzaEQMvT1LHEysw5twgLvpYYb4vbw==",
1397 | "dev": true,
1398 | "peer": true,
1399 | "dependencies": {
1400 | "flatted": "^3.2.9",
1401 | "keyv": "^4.5.3",
1402 | "rimraf": "^3.0.2"
1403 | },
1404 | "engines": {
1405 | "node": "^10.12.0 || >=12.0.0"
1406 | }
1407 | },
1408 | "node_modules/flatted": {
1409 | "version": "3.3.1",
1410 | "resolved": "https://registry.npmjs.org/flatted/-/flatted-3.3.1.tgz",
1411 | "integrity": "sha512-X8cqMLLie7KsNUDSdzeN8FYK9rEt4Dt67OsG/DNGnYTSDBG4uFAJFBnUeiV+zCVAvwFy56IjM9sH51jVaEhNxw==",
1412 | "dev": true,
1413 | "peer": true
1414 | },
1415 | "node_modules/fs.realpath": {
1416 | "version": "1.0.0",
1417 | "resolved": "https://registry.npmjs.org/fs.realpath/-/fs.realpath-1.0.0.tgz",
1418 | "integrity": "sha512-OO0pH2lK6a0hZnAdau5ItzHPI6pUlvI7jMVnxUQRtw4owF2wk8lOSabtGDCTP4Ggrg2MbGnWO9X8K1t4+fGMDw==",
1419 | "dev": true,
1420 | "peer": true
1421 | },
1422 | "node_modules/functional-red-black-tree": {
1423 | "version": "1.0.1",
1424 | "resolved": "https://registry.npmjs.org/functional-red-black-tree/-/functional-red-black-tree-1.0.1.tgz",
1425 | "integrity": "sha512-dsKNQNdj6xA3T+QlADDA7mOSlX0qiMINjn0cgr+eGHGsbSHzTabcIogz2+p/iqP1Xs6EP/sS2SbqH+brGTbq0g==",
1426 | "dev": true
1427 | },
1428 | "node_modules/fuzzaldrin-plus": {
1429 | "version": "0.6.0",
1430 | "resolved": "https://registry.npmjs.org/fuzzaldrin-plus/-/fuzzaldrin-plus-0.6.0.tgz",
1431 | "integrity": "sha512-srIDThJHkdp3aPwJpR/HNzYZCRJwm07b/igxseoHSB7qR8e/gQp4F6lMGknE3TQI1Aq14TiFf/wzrHOp9LY/EA==",
1432 | "dev": true
1433 | },
1434 | "node_modules/glob": {
1435 | "version": "7.2.3",
1436 | "resolved": "https://registry.npmjs.org/glob/-/glob-7.2.3.tgz",
1437 | "integrity": "sha512-nFR0zLpU2YCaRxwoCJvL6UvCH2JFyFVIvwTLsIf21AuHlMskA1hhTdk+LlYJtOlYt9v6dvszD2BGRqBL+iQK9Q==",
1438 | "deprecated": "Glob versions prior to v9 are no longer supported",
1439 | "dev": true,
1440 | "peer": true,
1441 | "dependencies": {
1442 | "fs.realpath": "^1.0.0",
1443 | "inflight": "^1.0.4",
1444 | "inherits": "2",
1445 | "minimatch": "^3.1.1",
1446 | "once": "^1.3.0",
1447 | "path-is-absolute": "^1.0.0"
1448 | },
1449 | "engines": {
1450 | "node": "*"
1451 | },
1452 | "funding": {
1453 | "url": "https://github.com/sponsors/isaacs"
1454 | }
1455 | },
1456 | "node_modules/glob-parent": {
1457 | "version": "6.0.2",
1458 | "resolved": "https://registry.npmjs.org/glob-parent/-/glob-parent-6.0.2.tgz",
1459 | "integrity": "sha512-XxwI8EOhVQgWp6iDL+3b0r86f4d6AX6zSU55HfB4ydCEuXLXc5FcYeOu+nnGftS4TEju/11rt4KJPTMgbfmv4A==",
1460 | "dev": true,
1461 | "peer": true,
1462 | "dependencies": {
1463 | "is-glob": "^4.0.3"
1464 | },
1465 | "engines": {
1466 | "node": ">=10.13.0"
1467 | }
1468 | },
1469 | "node_modules/globals": {
1470 | "version": "13.24.0",
1471 | "resolved": "https://registry.npmjs.org/globals/-/globals-13.24.0.tgz",
1472 | "integrity": "sha512-AhO5QUcj8llrbG09iWhPU2B204J1xnPeL8kQmVorSsy+Sjj1sk8gIyh6cUocGmH4L0UuhAJy+hJMRA4mgA4mFQ==",
1473 | "dev": true,
1474 | "peer": true,
1475 | "dependencies": {
1476 | "type-fest": "^0.20.2"
1477 | },
1478 | "engines": {
1479 | "node": ">=8"
1480 | },
1481 | "funding": {
1482 | "url": "https://github.com/sponsors/sindresorhus"
1483 | }
1484 | },
1485 | "node_modules/globby": {
1486 | "version": "11.1.0",
1487 | "resolved": "https://registry.npmjs.org/globby/-/globby-11.1.0.tgz",
1488 | "integrity": "sha512-jhIXaOzy1sb8IyocaruWSn1TjmnBVs8Ayhcy83rmxNJ8q2uWKCAj3CnJY+KpGSXCueAPc0i05kVvVKtP1t9S3g==",
1489 | "dev": true,
1490 | "dependencies": {
1491 | "array-union": "^2.1.0",
1492 | "dir-glob": "^3.0.1",
1493 | "fast-glob": "^3.2.9",
1494 | "ignore": "^5.2.0",
1495 | "merge2": "^1.4.1",
1496 | "slash": "^3.0.0"
1497 | },
1498 | "engines": {
1499 | "node": ">=10"
1500 | },
1501 | "funding": {
1502 | "url": "https://github.com/sponsors/sindresorhus"
1503 | }
1504 | },
1505 | "node_modules/graphemer": {
1506 | "version": "1.4.0",
1507 | "resolved": "https://registry.npmjs.org/graphemer/-/graphemer-1.4.0.tgz",
1508 | "integrity": "sha512-EtKwoO6kxCL9WO5xipiHTZlSzBm7WLT627TqC/uVRd0HKmq8NXyebnNYxDoBi7wt8eTWrUrKXCOVaFq9x1kgag==",
1509 | "dev": true,
1510 | "peer": true
1511 | },
1512 | "node_modules/has-flag": {
1513 | "version": "4.0.0",
1514 | "resolved": "https://registry.npmjs.org/has-flag/-/has-flag-4.0.0.tgz",
1515 | "integrity": "sha512-EykJT/Q1KjTWctppgIAgfSO0tKVuZUjhgMr17kqTumMl6Afv3EISleU7qZUzoXDFTAHTDC4NOoG/ZxU3EvlMPQ==",
1516 | "dev": true,
1517 | "peer": true,
1518 | "engines": {
1519 | "node": ">=8"
1520 | }
1521 | },
1522 | "node_modules/he": {
1523 | "version": "1.2.0",
1524 | "resolved": "https://registry.npmjs.org/he/-/he-1.2.0.tgz",
1525 | "integrity": "sha512-F/1DnUGPopORZi0ni+CvrCgHQ5FyEAHRLSApuYWMmrbSwoN2Mn/7k+Gl38gJnR7yyDZk6WLXwiGod1JOWNDKGw==",
1526 | "bin": {
1527 | "he": "bin/he"
1528 | }
1529 | },
1530 | "node_modules/ignore": {
1531 | "version": "5.3.1",
1532 | "resolved": "https://registry.npmjs.org/ignore/-/ignore-5.3.1.tgz",
1533 | "integrity": "sha512-5Fytz/IraMjqpwfd34ke28PTVMjZjJG2MPn5t7OE4eUCUNf8BAa7b5WUS9/Qvr6mwOQS7Mk6vdsMno5he+T8Xw==",
1534 | "dev": true,
1535 | "engines": {
1536 | "node": ">= 4"
1537 | }
1538 | },
1539 | "node_modules/import-fresh": {
1540 | "version": "3.3.0",
1541 | "resolved": "https://registry.npmjs.org/import-fresh/-/import-fresh-3.3.0.tgz",
1542 | "integrity": "sha512-veYYhQa+D1QBKznvhUHxb8faxlrwUnxseDAbAp457E0wLNio2bOSKnjYDhMj+YiAq61xrMGhQk9iXVk5FzgQMw==",
1543 | "dev": true,
1544 | "peer": true,
1545 | "dependencies": {
1546 | "parent-module": "^1.0.0",
1547 | "resolve-from": "^4.0.0"
1548 | },
1549 | "engines": {
1550 | "node": ">=6"
1551 | },
1552 | "funding": {
1553 | "url": "https://github.com/sponsors/sindresorhus"
1554 | }
1555 | },
1556 | "node_modules/imurmurhash": {
1557 | "version": "0.1.4",
1558 | "resolved": "https://registry.npmjs.org/imurmurhash/-/imurmurhash-0.1.4.tgz",
1559 | "integrity": "sha512-JmXMZ6wuvDmLiHEml9ykzqO6lwFbof0GG4IkcGaENdCRDDmMVnny7s5HsIgHCbaq0w2MyPhDqkhTUgS2LU2PHA==",
1560 | "dev": true,
1561 | "peer": true,
1562 | "engines": {
1563 | "node": ">=0.8.19"
1564 | }
1565 | },
1566 | "node_modules/inflight": {
1567 | "version": "1.0.6",
1568 | "resolved": "https://registry.npmjs.org/inflight/-/inflight-1.0.6.tgz",
1569 | "integrity": "sha512-k92I/b08q4wvFscXCLvqfsHCrjrF7yiXsQuIVvVE7N82W3+aqpzuUdBbfhWcy/FZR3/4IgflMgKLOsvPDrGCJA==",
1570 | "deprecated": "This module is not supported, and leaks memory. Do not use it. Check out lru-cache if you want a good and tested way to coalesce async requests by a key value, which is much more comprehensive and powerful.",
1571 | "dev": true,
1572 | "peer": true,
1573 | "dependencies": {
1574 | "once": "^1.3.0",
1575 | "wrappy": "1"
1576 | }
1577 | },
1578 | "node_modules/inherits": {
1579 | "version": "2.0.4",
1580 | "resolved": "https://registry.npmjs.org/inherits/-/inherits-2.0.4.tgz",
1581 | "integrity": "sha512-k/vGaX4/Yla3WzyMCvTQOXYeIHvqOKtnqBduzTHpzpQZzAskKMhZ2K+EnBiSM9zGSoIFeMpXKxa4dYeZIQqewQ==",
1582 | "dev": true,
1583 | "peer": true
1584 | },
1585 | "node_modules/is-extglob": {
1586 | "version": "2.1.1",
1587 | "resolved": "https://registry.npmjs.org/is-extglob/-/is-extglob-2.1.1.tgz",
1588 | "integrity": "sha512-SbKbANkN603Vi4jEZv49LeVJMn4yGwsbzZworEoyEiutsN3nJYdbO36zfhGJ6QEDpOZIFkDtnq5JRxmvl3jsoQ==",
1589 | "dev": true,
1590 | "engines": {
1591 | "node": ">=0.10.0"
1592 | }
1593 | },
1594 | "node_modules/is-glob": {
1595 | "version": "4.0.3",
1596 | "resolved": "https://registry.npmjs.org/is-glob/-/is-glob-4.0.3.tgz",
1597 | "integrity": "sha512-xelSayHH36ZgE7ZWhli7pW34hNbNl8Ojv5KVmkJD4hBdD3th8Tfk9vYasLM+mXWOZhFkgZfxhLSnrwRr4elSSg==",
1598 | "dev": true,
1599 | "dependencies": {
1600 | "is-extglob": "^2.1.1"
1601 | },
1602 | "engines": {
1603 | "node": ">=0.10.0"
1604 | }
1605 | },
1606 | "node_modules/is-number": {
1607 | "version": "7.0.0",
1608 | "resolved": "https://registry.npmjs.org/is-number/-/is-number-7.0.0.tgz",
1609 | "integrity": "sha512-41Cifkg6e8TylSpdtTpeLVMqvSBEVzTttHvERD741+pnZ8ANv0004MRL43QKPDlK9cGvNp6NZWZUBlbGXYxxng==",
1610 | "dev": true,
1611 | "engines": {
1612 | "node": ">=0.12.0"
1613 | }
1614 | },
1615 | "node_modules/is-path-inside": {
1616 | "version": "3.0.3",
1617 | "resolved": "https://registry.npmjs.org/is-path-inside/-/is-path-inside-3.0.3.tgz",
1618 | "integrity": "sha512-Fd4gABb+ycGAmKou8eMftCupSir5lRxqf4aD/vd0cD2qc4HL07OjCeuHMr8Ro4CoMaeCKDB0/ECBOVWjTwUvPQ==",
1619 | "dev": true,
1620 | "peer": true,
1621 | "engines": {
1622 | "node": ">=8"
1623 | }
1624 | },
1625 | "node_modules/isexe": {
1626 | "version": "2.0.0",
1627 | "resolved": "https://registry.npmjs.org/isexe/-/isexe-2.0.0.tgz",
1628 | "integrity": "sha512-RHxMLp9lnKHGHRng9QFhRCMbYAcVpn69smSGcq3f36xjgVVWThj4qqLbTLlq7Ssj8B+fIQ1EuCEGI2lKsyQeIw==",
1629 | "dev": true,
1630 | "peer": true
1631 | },
1632 | "node_modules/js-yaml": {
1633 | "version": "4.1.0",
1634 | "resolved": "https://registry.npmjs.org/js-yaml/-/js-yaml-4.1.0.tgz",
1635 | "integrity": "sha512-wpxZs9NoxZaJESJGIZTyDEaYpl0FKSA+FB9aJiyemKhMwkxQg63h4T1KJgUGHpTqPDNRcmmYLugrRjJlBtWvRA==",
1636 | "dev": true,
1637 | "peer": true,
1638 | "dependencies": {
1639 | "argparse": "^2.0.1"
1640 | },
1641 | "bin": {
1642 | "js-yaml": "bin/js-yaml.js"
1643 | }
1644 | },
1645 | "node_modules/json-buffer": {
1646 | "version": "3.0.1",
1647 | "resolved": "https://registry.npmjs.org/json-buffer/-/json-buffer-3.0.1.tgz",
1648 | "integrity": "sha512-4bV5BfR2mqfQTJm+V5tPPdf+ZpuhiIvTuAB5g8kcrXOZpTT/QwwVRWBywX1ozr6lEuPdbHxwaJlm9G6mI2sfSQ==",
1649 | "dev": true,
1650 | "peer": true
1651 | },
1652 | "node_modules/json-schema-traverse": {
1653 | "version": "0.4.1",
1654 | "resolved": "https://registry.npmjs.org/json-schema-traverse/-/json-schema-traverse-0.4.1.tgz",
1655 | "integrity": "sha512-xbbCH5dCYU5T8LcEhhuh7HJ88HXuW3qsI3Y0zOZFKfZEHcpWiHU/Jxzk629Brsab/mMiHQti9wMP+845RPe3Vg==",
1656 | "dev": true,
1657 | "peer": true
1658 | },
1659 | "node_modules/json-stable-stringify-without-jsonify": {
1660 | "version": "1.0.1",
1661 | "resolved": "https://registry.npmjs.org/json-stable-stringify-without-jsonify/-/json-stable-stringify-without-jsonify-1.0.1.tgz",
1662 | "integrity": "sha512-Bdboy+l7tA3OGW6FjyFHWkP5LuByj1Tk33Ljyq0axyzdk9//JSi2u3fP1QSmd1KNwq6VOKYGlAu87CisVir6Pw==",
1663 | "dev": true,
1664 | "peer": true
1665 | },
1666 | "node_modules/keyv": {
1667 | "version": "4.5.4",
1668 | "resolved": "https://registry.npmjs.org/keyv/-/keyv-4.5.4.tgz",
1669 | "integrity": "sha512-oxVHkHR/EJf2CNXnWxRLW6mg7JyCCUcG0DtEGmL2ctUo1PNTin1PUil+r/+4r5MpVgC/fn1kjsx7mjSujKqIpw==",
1670 | "dev": true,
1671 | "peer": true,
1672 | "dependencies": {
1673 | "json-buffer": "3.0.1"
1674 | }
1675 | },
1676 | "node_modules/levn": {
1677 | "version": "0.4.1",
1678 | "resolved": "https://registry.npmjs.org/levn/-/levn-0.4.1.tgz",
1679 | "integrity": "sha512-+bT2uH4E5LGE7h/n3evcS/sQlJXCpIp6ym8OWJ5eV6+67Dsql/LaaT7qJBAt2rzfoa/5QBGBhxDix1dMt2kQKQ==",
1680 | "dev": true,
1681 | "peer": true,
1682 | "dependencies": {
1683 | "prelude-ls": "^1.2.1",
1684 | "type-check": "~0.4.0"
1685 | },
1686 | "engines": {
1687 | "node": ">= 0.8.0"
1688 | }
1689 | },
1690 | "node_modules/locate-path": {
1691 | "version": "6.0.0",
1692 | "resolved": "https://registry.npmjs.org/locate-path/-/locate-path-6.0.0.tgz",
1693 | "integrity": "sha512-iPZK6eYjbxRu3uB4/WZ3EsEIMJFMqAoopl3R+zuq0UjcAm/MO6KCweDgPfP3elTztoKP3KtnVHxTn2NHBSDVUw==",
1694 | "dev": true,
1695 | "peer": true,
1696 | "dependencies": {
1697 | "p-locate": "^5.0.0"
1698 | },
1699 | "engines": {
1700 | "node": ">=10"
1701 | },
1702 | "funding": {
1703 | "url": "https://github.com/sponsors/sindresorhus"
1704 | }
1705 | },
1706 | "node_modules/lodash.merge": {
1707 | "version": "4.6.2",
1708 | "resolved": "https://registry.npmjs.org/lodash.merge/-/lodash.merge-4.6.2.tgz",
1709 | "integrity": "sha512-0KpjqXRVvrYyCsX1swR/XTK0va6VQkQM6MNo7PqW77ByjAhoARA8EfrP1N4+KlKj8YS0ZUCtRT/YUuhyYDujIQ==",
1710 | "dev": true,
1711 | "peer": true
1712 | },
1713 | "node_modules/merge2": {
1714 | "version": "1.4.1",
1715 | "resolved": "https://registry.npmjs.org/merge2/-/merge2-1.4.1.tgz",
1716 | "integrity": "sha512-8q7VEgMJW4J8tcfVPy8g09NcQwZdbwFEqhe/WZkoIzjn/3TGDwtOCYtXGxA3O8tPzpczCCDgv+P2P5y00ZJOOg==",
1717 | "dev": true,
1718 | "engines": {
1719 | "node": ">= 8"
1720 | }
1721 | },
1722 | "node_modules/micromatch": {
1723 | "version": "4.0.7",
1724 | "resolved": "https://registry.npmjs.org/micromatch/-/micromatch-4.0.7.tgz",
1725 | "integrity": "sha512-LPP/3KorzCwBxfeUuZmaR6bG2kdeHSbe0P2tY3FLRU4vYrjYz5hI4QZwV0njUx3jeuKe67YukQ1LSPZBKDqO/Q==",
1726 | "dev": true,
1727 | "dependencies": {
1728 | "braces": "^3.0.3",
1729 | "picomatch": "^2.3.1"
1730 | },
1731 | "engines": {
1732 | "node": ">=8.6"
1733 | }
1734 | },
1735 | "node_modules/minimatch": {
1736 | "version": "3.1.2",
1737 | "resolved": "https://registry.npmjs.org/minimatch/-/minimatch-3.1.2.tgz",
1738 | "integrity": "sha512-J7p63hRiAjw1NDEww1W7i37+ByIrOWO5XQQAzZ3VOcL0PNybwpfmV/N05zFAzwQ9USyEcX6t3UO+K5aqBQOIHw==",
1739 | "dev": true,
1740 | "peer": true,
1741 | "dependencies": {
1742 | "brace-expansion": "^1.1.7"
1743 | },
1744 | "engines": {
1745 | "node": "*"
1746 | }
1747 | },
1748 | "node_modules/moment": {
1749 | "version": "2.29.4",
1750 | "resolved": "https://registry.npmjs.org/moment/-/moment-2.29.4.tgz",
1751 | "integrity": "sha512-5LC9SOxjSc2HF6vO2CyuTDNivEdoz2IvyJJGj6X8DJ0eFyfszE0QiEd+iXmBvUP3WHxSjFH/vIsA0EN00cgr8w==",
1752 | "dev": true,
1753 | "engines": {
1754 | "node": "*"
1755 | }
1756 | },
1757 | "node_modules/ms": {
1758 | "version": "2.1.2",
1759 | "resolved": "https://registry.npmjs.org/ms/-/ms-2.1.2.tgz",
1760 | "integrity": "sha512-sGkPx+VjMtmA6MX27oA4FBFELFCZZ4S4XqeGOXCv68tT+jb3vk/RyaKWP0PTKyWtmLSM0b+adUTEvbs1PEaH2w==",
1761 | "dev": true
1762 | },
1763 | "node_modules/natural-compare": {
1764 | "version": "1.4.0",
1765 | "resolved": "https://registry.npmjs.org/natural-compare/-/natural-compare-1.4.0.tgz",
1766 | "integrity": "sha512-OWND8ei3VtNC9h7V60qff3SVobHr996CTwgxubgyQYEpg290h9J0buyECNNJexkFm5sOajh5G116RYA1c8ZMSw==",
1767 | "dev": true,
1768 | "peer": true
1769 | },
1770 | "node_modules/obsidian": {
1771 | "version": "1.5.7-1",
1772 | "resolved": "https://registry.npmjs.org/obsidian/-/obsidian-1.5.7-1.tgz",
1773 | "integrity": "sha512-T5ZRuQ1FnfXqEoakTTHVDYvzUEEoT8zSPnQCW31PVgYwG4D4tZCQfKHN2hTz1ifnCe8upvwa6mBTAP2WUA5Vng==",
1774 | "dev": true,
1775 | "dependencies": {
1776 | "@types/codemirror": "5.60.8",
1777 | "moment": "2.29.4"
1778 | },
1779 | "peerDependencies": {
1780 | "@codemirror/state": "^6.0.0",
1781 | "@codemirror/view": "^6.0.0"
1782 | }
1783 | },
1784 | "node_modules/once": {
1785 | "version": "1.4.0",
1786 | "resolved": "https://registry.npmjs.org/once/-/once-1.4.0.tgz",
1787 | "integrity": "sha512-lNaJgI+2Q5URQBkccEKHTQOPaXdUxnZZElQTZY0MFUAuaEqe1E+Nyvgdz/aIyNi6Z9MzO5dv1H8n58/GELp3+w==",
1788 | "dev": true,
1789 | "peer": true,
1790 | "dependencies": {
1791 | "wrappy": "1"
1792 | }
1793 | },
1794 | "node_modules/optionator": {
1795 | "version": "0.9.4",
1796 | "resolved": "https://registry.npmjs.org/optionator/-/optionator-0.9.4.tgz",
1797 | "integrity": "sha512-6IpQ7mKUxRcZNLIObR0hz7lxsapSSIYNZJwXPGeF0mTVqGKFIXj1DQcMoT22S3ROcLyY/rz0PWaWZ9ayWmad9g==",
1798 | "dev": true,
1799 | "peer": true,
1800 | "dependencies": {
1801 | "deep-is": "^0.1.3",
1802 | "fast-levenshtein": "^2.0.6",
1803 | "levn": "^0.4.1",
1804 | "prelude-ls": "^1.2.1",
1805 | "type-check": "^0.4.0",
1806 | "word-wrap": "^1.2.5"
1807 | },
1808 | "engines": {
1809 | "node": ">= 0.8.0"
1810 | }
1811 | },
1812 | "node_modules/p-limit": {
1813 | "version": "3.1.0",
1814 | "resolved": "https://registry.npmjs.org/p-limit/-/p-limit-3.1.0.tgz",
1815 | "integrity": "sha512-TYOanM3wGwNGsZN2cVTYPArw454xnXj5qmWF1bEoAc4+cU/ol7GVh7odevjp1FNHduHc3KZMcFduxU5Xc6uJRQ==",
1816 | "dev": true,
1817 | "peer": true,
1818 | "dependencies": {
1819 | "yocto-queue": "^0.1.0"
1820 | },
1821 | "engines": {
1822 | "node": ">=10"
1823 | },
1824 | "funding": {
1825 | "url": "https://github.com/sponsors/sindresorhus"
1826 | }
1827 | },
1828 | "node_modules/p-locate": {
1829 | "version": "5.0.0",
1830 | "resolved": "https://registry.npmjs.org/p-locate/-/p-locate-5.0.0.tgz",
1831 | "integrity": "sha512-LaNjtRWUBY++zB5nE/NwcaoMylSPk+S+ZHNB1TzdbMJMny6dynpAGt7X/tl/QYq3TIeE6nxHppbo2LGymrG5Pw==",
1832 | "dev": true,
1833 | "peer": true,
1834 | "dependencies": {
1835 | "p-limit": "^3.0.2"
1836 | },
1837 | "engines": {
1838 | "node": ">=10"
1839 | },
1840 | "funding": {
1841 | "url": "https://github.com/sponsors/sindresorhus"
1842 | }
1843 | },
1844 | "node_modules/parent-module": {
1845 | "version": "1.0.1",
1846 | "resolved": "https://registry.npmjs.org/parent-module/-/parent-module-1.0.1.tgz",
1847 | "integrity": "sha512-GQ2EWRpQV8/o+Aw8YqtfZZPfNRWZYkbidE9k5rpl/hC3vtHHBfGm2Ifi6qWV+coDGkrUKZAxE3Lot5kcsRlh+g==",
1848 | "dev": true,
1849 | "peer": true,
1850 | "dependencies": {
1851 | "callsites": "^3.0.0"
1852 | },
1853 | "engines": {
1854 | "node": ">=6"
1855 | }
1856 | },
1857 | "node_modules/path-exists": {
1858 | "version": "4.0.0",
1859 | "resolved": "https://registry.npmjs.org/path-exists/-/path-exists-4.0.0.tgz",
1860 | "integrity": "sha512-ak9Qy5Q7jYb2Wwcey5Fpvg2KoAc/ZIhLSLOSBmRmygPsGwkVVt0fZa0qrtMz+m6tJTAHfZQ8FnmB4MG4LWy7/w==",
1861 | "dev": true,
1862 | "peer": true,
1863 | "engines": {
1864 | "node": ">=8"
1865 | }
1866 | },
1867 | "node_modules/path-is-absolute": {
1868 | "version": "1.0.1",
1869 | "resolved": "https://registry.npmjs.org/path-is-absolute/-/path-is-absolute-1.0.1.tgz",
1870 | "integrity": "sha512-AVbw3UJ2e9bq64vSaS9Am0fje1Pa8pbGqTTsmXfaIiMpnr5DlDhfJOuLj9Sf95ZPVDAUerDfEk88MPmPe7UCQg==",
1871 | "dev": true,
1872 | "peer": true,
1873 | "engines": {
1874 | "node": ">=0.10.0"
1875 | }
1876 | },
1877 | "node_modules/path-key": {
1878 | "version": "3.1.1",
1879 | "resolved": "https://registry.npmjs.org/path-key/-/path-key-3.1.1.tgz",
1880 | "integrity": "sha512-ojmeN0qd+y0jszEtoY48r0Peq5dwMEkIlCOu6Q5f41lfkswXuKtYrhgoTpLnyIcHm24Uhqx+5Tqm2InSwLhE6Q==",
1881 | "dev": true,
1882 | "peer": true,
1883 | "engines": {
1884 | "node": ">=8"
1885 | }
1886 | },
1887 | "node_modules/path-type": {
1888 | "version": "4.0.0",
1889 | "resolved": "https://registry.npmjs.org/path-type/-/path-type-4.0.0.tgz",
1890 | "integrity": "sha512-gDKb8aZMDeD/tZWs9P6+q0J9Mwkdl6xMV8TjnGP3qJVJ06bdMgkbBlLU8IdfOsIsFz2BW1rNVT3XuNEl8zPAvw==",
1891 | "dev": true,
1892 | "engines": {
1893 | "node": ">=8"
1894 | }
1895 | },
1896 | "node_modules/picomatch": {
1897 | "version": "2.3.1",
1898 | "resolved": "https://registry.npmjs.org/picomatch/-/picomatch-2.3.1.tgz",
1899 | "integrity": "sha512-JU3teHTNjmE2VCGFzuY8EXzCDVwEqB2a8fsIvwaStHhAWJEeVd1o1QD80CU6+ZdEXXSLbSsuLwJjkCBWqRQUVA==",
1900 | "dev": true,
1901 | "engines": {
1902 | "node": ">=8.6"
1903 | },
1904 | "funding": {
1905 | "url": "https://github.com/sponsors/jonschlinkert"
1906 | }
1907 | },
1908 | "node_modules/prelude-ls": {
1909 | "version": "1.2.1",
1910 | "resolved": "https://registry.npmjs.org/prelude-ls/-/prelude-ls-1.2.1.tgz",
1911 | "integrity": "sha512-vkcDPrRZo1QZLbn5RLGPpg/WmIQ65qoWWhcGKf/b5eplkkarX0m9z8ppCat4mlOqUsWpyNuYgO3VRyrYHSzX5g==",
1912 | "dev": true,
1913 | "peer": true,
1914 | "engines": {
1915 | "node": ">= 0.8.0"
1916 | }
1917 | },
1918 | "node_modules/punycode": {
1919 | "version": "2.3.1",
1920 | "resolved": "https://registry.npmjs.org/punycode/-/punycode-2.3.1.tgz",
1921 | "integrity": "sha512-vYt7UD1U9Wg6138shLtLOvdAu+8DsC/ilFtEVHcH+wydcSpNE20AfSOduf6MkRFahL5FY7X1oU7nKVZFtfq8Fg==",
1922 | "dev": true,
1923 | "peer": true,
1924 | "engines": {
1925 | "node": ">=6"
1926 | }
1927 | },
1928 | "node_modules/queue-microtask": {
1929 | "version": "1.2.3",
1930 | "resolved": "https://registry.npmjs.org/queue-microtask/-/queue-microtask-1.2.3.tgz",
1931 | "integrity": "sha512-NuaNSa6flKT5JaSYQzJok04JzTL1CA6aGhv5rfLW3PgqA+M2ChpZQnAC8h8i4ZFkBS8X5RqkDBHA7r4hej3K9A==",
1932 | "dev": true,
1933 | "funding": [
1934 | {
1935 | "type": "github",
1936 | "url": "https://github.com/sponsors/feross"
1937 | },
1938 | {
1939 | "type": "patreon",
1940 | "url": "https://www.patreon.com/feross"
1941 | },
1942 | {
1943 | "type": "consulting",
1944 | "url": "https://feross.org/support"
1945 | }
1946 | ]
1947 | },
1948 | "node_modules/regexpp": {
1949 | "version": "3.2.0",
1950 | "resolved": "https://registry.npmjs.org/regexpp/-/regexpp-3.2.0.tgz",
1951 | "integrity": "sha512-pq2bWo9mVD43nbts2wGv17XLiNLya+GklZ8kaDLV2Z08gDCsGpnKn9BFMepvWuHCbyVvY7J5o5+BVvoQbmlJLg==",
1952 | "dev": true,
1953 | "engines": {
1954 | "node": ">=8"
1955 | },
1956 | "funding": {
1957 | "url": "https://github.com/sponsors/mysticatea"
1958 | }
1959 | },
1960 | "node_modules/resolve-from": {
1961 | "version": "4.0.0",
1962 | "resolved": "https://registry.npmjs.org/resolve-from/-/resolve-from-4.0.0.tgz",
1963 | "integrity": "sha512-pb/MYmXstAkysRFx8piNI1tGFNQIFA3vkE3Gq4EuA1dF6gHp/+vgZqsCGJapvy8N3Q+4o7FwvquPJcnZ7RYy4g==",
1964 | "dev": true,
1965 | "peer": true,
1966 | "engines": {
1967 | "node": ">=4"
1968 | }
1969 | },
1970 | "node_modules/reusify": {
1971 | "version": "1.0.4",
1972 | "resolved": "https://registry.npmjs.org/reusify/-/reusify-1.0.4.tgz",
1973 | "integrity": "sha512-U9nH88a3fc/ekCF1l0/UP1IosiuIjyTh7hBvXVMHYgVcfGvt897Xguj2UOLDeI5BG2m7/uwyaLVT6fbtCwTyzw==",
1974 | "dev": true,
1975 | "engines": {
1976 | "iojs": ">=1.0.0",
1977 | "node": ">=0.10.0"
1978 | }
1979 | },
1980 | "node_modules/rimraf": {
1981 | "version": "3.0.2",
1982 | "resolved": "https://registry.npmjs.org/rimraf/-/rimraf-3.0.2.tgz",
1983 | "integrity": "sha512-JZkJMZkAGFFPP2YqXZXPbMlMBgsxzE8ILs4lMIX/2o0L9UBw9O/Y3o6wFw/i9YLapcUJWwqbi3kdxIPdC62TIA==",
1984 | "deprecated": "Rimraf versions prior to v4 are no longer supported",
1985 | "dev": true,
1986 | "peer": true,
1987 | "dependencies": {
1988 | "glob": "^7.1.3"
1989 | },
1990 | "bin": {
1991 | "rimraf": "bin.js"
1992 | },
1993 | "funding": {
1994 | "url": "https://github.com/sponsors/isaacs"
1995 | }
1996 | },
1997 | "node_modules/run-parallel": {
1998 | "version": "1.2.0",
1999 | "resolved": "https://registry.npmjs.org/run-parallel/-/run-parallel-1.2.0.tgz",
2000 | "integrity": "sha512-5l4VyZR86LZ/lDxZTR6jqL8AFE2S0IFLMP26AbjsLVADxHdhB/c0GUsH+y39UfCi3dzz8OlQuPmnaJOMoDHQBA==",
2001 | "dev": true,
2002 | "funding": [
2003 | {
2004 | "type": "github",
2005 | "url": "https://github.com/sponsors/feross"
2006 | },
2007 | {
2008 | "type": "patreon",
2009 | "url": "https://www.patreon.com/feross"
2010 | },
2011 | {
2012 | "type": "consulting",
2013 | "url": "https://feross.org/support"
2014 | }
2015 | ],
2016 | "dependencies": {
2017 | "queue-microtask": "^1.2.2"
2018 | }
2019 | },
2020 | "node_modules/semver": {
2021 | "version": "7.6.2",
2022 | "resolved": "https://registry.npmjs.org/semver/-/semver-7.6.2.tgz",
2023 | "integrity": "sha512-FNAIBWCx9qcRhoHcgcJ0gvU7SN1lYU2ZXuSfl04bSC5OpvDHFyJCjdNHomPXxjQlCBU67YW64PzY7/VIEH7F2w==",
2024 | "dev": true,
2025 | "bin": {
2026 | "semver": "bin/semver.js"
2027 | },
2028 | "engines": {
2029 | "node": ">=10"
2030 | }
2031 | },
2032 | "node_modules/shebang-command": {
2033 | "version": "2.0.0",
2034 | "resolved": "https://registry.npmjs.org/shebang-command/-/shebang-command-2.0.0.tgz",
2035 | "integrity": "sha512-kHxr2zZpYtdmrN1qDjrrX/Z1rR1kG8Dx+gkpK1G4eXmvXswmcE1hTWBWYUzlraYw1/yZp6YuDY77YtvbN0dmDA==",
2036 | "dev": true,
2037 | "peer": true,
2038 | "dependencies": {
2039 | "shebang-regex": "^3.0.0"
2040 | },
2041 | "engines": {
2042 | "node": ">=8"
2043 | }
2044 | },
2045 | "node_modules/shebang-regex": {
2046 | "version": "3.0.0",
2047 | "resolved": "https://registry.npmjs.org/shebang-regex/-/shebang-regex-3.0.0.tgz",
2048 | "integrity": "sha512-7++dFhtcx3353uBaq8DDR4NuxBetBzC7ZQOhmTQInHEd6bSrXdiEyzCvG07Z44UYdLShWUyXt5M/yhz8ekcb1A==",
2049 | "dev": true,
2050 | "peer": true,
2051 | "engines": {
2052 | "node": ">=8"
2053 | }
2054 | },
2055 | "node_modules/shell-escape": {
2056 | "version": "0.2.0",
2057 | "resolved": "https://registry.npmjs.org/shell-escape/-/shell-escape-0.2.0.tgz",
2058 | "integrity": "sha512-uRRBT2MfEOyxuECseCZd28jC1AJ8hmqqneWQ4VWUTgCAFvb3wKU1jLqj6egC4Exrr88ogg3dp+zroH4wJuaXzw=="
2059 | },
2060 | "node_modules/slash": {
2061 | "version": "3.0.0",
2062 | "resolved": "https://registry.npmjs.org/slash/-/slash-3.0.0.tgz",
2063 | "integrity": "sha512-g9Q1haeby36OSStwb4ntCGGGaKsaVSjQ68fBxoQcutl5fS1vuY18H3wSt3jFyFtrkx+Kz0V1G85A4MyAdDMi2Q==",
2064 | "dev": true,
2065 | "engines": {
2066 | "node": ">=8"
2067 | }
2068 | },
2069 | "node_modules/strip-ansi": {
2070 | "version": "6.0.1",
2071 | "resolved": "https://registry.npmjs.org/strip-ansi/-/strip-ansi-6.0.1.tgz",
2072 | "integrity": "sha512-Y38VPSHcqkFrCpFnQ9vuSXmquuv5oXOKpGeT6aGrr3o3Gc9AlVa6JBfUSOCnbxGGZF+/0ooI7KrPuUSztUdU5A==",
2073 | "dev": true,
2074 | "peer": true,
2075 | "dependencies": {
2076 | "ansi-regex": "^5.0.1"
2077 | },
2078 | "engines": {
2079 | "node": ">=8"
2080 | }
2081 | },
2082 | "node_modules/strip-json-comments": {
2083 | "version": "3.1.1",
2084 | "resolved": "https://registry.npmjs.org/strip-json-comments/-/strip-json-comments-3.1.1.tgz",
2085 | "integrity": "sha512-6fPc+R4ihwqP6N/aIv2f1gMH8lOVtWQHoqC4yK6oSDVVocumAsfCqjkXnqiYMhmMwS/mEHLp7Vehlt3ql6lEig==",
2086 | "dev": true,
2087 | "peer": true,
2088 | "engines": {
2089 | "node": ">=8"
2090 | },
2091 | "funding": {
2092 | "url": "https://github.com/sponsors/sindresorhus"
2093 | }
2094 | },
2095 | "node_modules/style-mod": {
2096 | "version": "4.1.2",
2097 | "resolved": "https://registry.npmjs.org/style-mod/-/style-mod-4.1.2.tgz",
2098 | "integrity": "sha512-wnD1HyVqpJUI2+eKZ+eo1UwghftP6yuFheBqqe+bWCotBjC2K1YnteJILRMs3SM4V/0dLEW1SC27MWP5y+mwmw==",
2099 | "dev": true,
2100 | "peer": true
2101 | },
2102 | "node_modules/supports-color": {
2103 | "version": "7.2.0",
2104 | "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-7.2.0.tgz",
2105 | "integrity": "sha512-qpCAvRl9stuOHveKsn7HncJRvv501qIacKzQlO/+Lwxc9+0q2wLyv4Dfvt80/DPn2pqOBsJdDiogXGR9+OvwRw==",
2106 | "dev": true,
2107 | "peer": true,
2108 | "dependencies": {
2109 | "has-flag": "^4.0.0"
2110 | },
2111 | "engines": {
2112 | "node": ">=8"
2113 | }
2114 | },
2115 | "node_modules/text-table": {
2116 | "version": "0.2.0",
2117 | "resolved": "https://registry.npmjs.org/text-table/-/text-table-0.2.0.tgz",
2118 | "integrity": "sha512-N+8UisAXDGk8PFXP4HAzVR9nbfmVJ3zYLAWiTIoqC5v5isinhr+r5uaO8+7r3BMfuNIufIsA7RdpVgacC2cSpw==",
2119 | "dev": true,
2120 | "peer": true
2121 | },
2122 | "node_modules/to-regex-range": {
2123 | "version": "5.0.1",
2124 | "resolved": "https://registry.npmjs.org/to-regex-range/-/to-regex-range-5.0.1.tgz",
2125 | "integrity": "sha512-65P7iz6X5yEr1cwcgvQxbbIw7Uk3gOy5dIdtZ4rDveLqhrdJP+Li/Hx6tyK0NEb+2GCyneCMJiGqrADCSNk8sQ==",
2126 | "dev": true,
2127 | "dependencies": {
2128 | "is-number": "^7.0.0"
2129 | },
2130 | "engines": {
2131 | "node": ">=8.0"
2132 | }
2133 | },
2134 | "node_modules/tslib": {
2135 | "version": "2.4.0",
2136 | "resolved": "https://registry.npmjs.org/tslib/-/tslib-2.4.0.tgz",
2137 | "integrity": "sha512-d6xOpEDfsi2CZVlPQzGeux8XMwLT9hssAsaPYExaQMuYskwb+x1x7J371tWlbBdWHroy99KnVB6qIkUbs5X3UQ==",
2138 | "dev": true
2139 | },
2140 | "node_modules/tsutils": {
2141 | "version": "3.21.0",
2142 | "resolved": "https://registry.npmjs.org/tsutils/-/tsutils-3.21.0.tgz",
2143 | "integrity": "sha512-mHKK3iUXL+3UF6xL5k0PEhKRUBKPBCv/+RkEOpjRWxxx27KKRBmmA60A9pgOUvMi8GKhRMPEmjBRPzs2W7O1OA==",
2144 | "dev": true,
2145 | "dependencies": {
2146 | "tslib": "^1.8.1"
2147 | },
2148 | "engines": {
2149 | "node": ">= 6"
2150 | },
2151 | "peerDependencies": {
2152 | "typescript": ">=2.8.0 || >= 3.2.0-dev || >= 3.3.0-dev || >= 3.4.0-dev || >= 3.5.0-dev || >= 3.6.0-dev || >= 3.6.0-beta || >= 3.7.0-dev || >= 3.7.0-beta"
2153 | }
2154 | },
2155 | "node_modules/tsutils/node_modules/tslib": {
2156 | "version": "1.14.1",
2157 | "resolved": "https://registry.npmjs.org/tslib/-/tslib-1.14.1.tgz",
2158 | "integrity": "sha512-Xni35NKzjgMrwevysHTCArtLDpPvye8zV/0E4EyYn43P7/7qvQwPh9BGkHewbMulVntbigmcT7rdX3BNo9wRJg==",
2159 | "dev": true
2160 | },
2161 | "node_modules/type-check": {
2162 | "version": "0.4.0",
2163 | "resolved": "https://registry.npmjs.org/type-check/-/type-check-0.4.0.tgz",
2164 | "integrity": "sha512-XleUoc9uwGXqjWwXaUTZAmzMcFZ5858QA2vvx1Ur5xIcixXIP+8LnFDgRplU30us6teqdlskFfu+ae4K79Ooew==",
2165 | "dev": true,
2166 | "peer": true,
2167 | "dependencies": {
2168 | "prelude-ls": "^1.2.1"
2169 | },
2170 | "engines": {
2171 | "node": ">= 0.8.0"
2172 | }
2173 | },
2174 | "node_modules/type-fest": {
2175 | "version": "0.20.2",
2176 | "resolved": "https://registry.npmjs.org/type-fest/-/type-fest-0.20.2.tgz",
2177 | "integrity": "sha512-Ne+eE4r0/iWnpAxD852z3A+N0Bt5RN//NjJwRd2VFHEmrywxf5vsZlh4R6lixl6B+wz/8d+maTSAkN1FIkI3LQ==",
2178 | "dev": true,
2179 | "peer": true,
2180 | "engines": {
2181 | "node": ">=10"
2182 | },
2183 | "funding": {
2184 | "url": "https://github.com/sponsors/sindresorhus"
2185 | }
2186 | },
2187 | "node_modules/typescript": {
2188 | "version": "4.7.4",
2189 | "resolved": "https://registry.npmjs.org/typescript/-/typescript-4.7.4.tgz",
2190 | "integrity": "sha512-C0WQT0gezHuw6AdY1M2jxUO83Rjf0HP7Sk1DtXj6j1EwkQNZrHAg2XPWlq62oqEhYvONq5pkC2Y9oPljWToLmQ==",
2191 | "dev": true,
2192 | "bin": {
2193 | "tsc": "bin/tsc",
2194 | "tsserver": "bin/tsserver"
2195 | },
2196 | "engines": {
2197 | "node": ">=4.2.0"
2198 | }
2199 | },
2200 | "node_modules/uri-js": {
2201 | "version": "4.4.1",
2202 | "resolved": "https://registry.npmjs.org/uri-js/-/uri-js-4.4.1.tgz",
2203 | "integrity": "sha512-7rKUyy33Q1yc98pQ1DAmLtwX109F7TIfWlW1Ydo8Wl1ii1SeHieeh0HHfPeL2fMXK6z0s8ecKs9frCuLJvndBg==",
2204 | "dev": true,
2205 | "peer": true,
2206 | "dependencies": {
2207 | "punycode": "^2.1.0"
2208 | }
2209 | },
2210 | "node_modules/w3c-keyname": {
2211 | "version": "2.2.8",
2212 | "resolved": "https://registry.npmjs.org/w3c-keyname/-/w3c-keyname-2.2.8.tgz",
2213 | "integrity": "sha512-dpojBhNsCNN7T82Tm7k26A6G9ML3NkhDsnw9n/eoxSRlVBB4CEtIQ/KTCLI2Fwf3ataSXRhYFkQi3SlnFwPvPQ==",
2214 | "dev": true,
2215 | "peer": true
2216 | },
2217 | "node_modules/which": {
2218 | "version": "2.0.2",
2219 | "resolved": "https://registry.npmjs.org/which/-/which-2.0.2.tgz",
2220 | "integrity": "sha512-BLI3Tl1TW3Pvl70l3yq3Y64i+awpwXqsGBYWkkqMtnbXgrMD+yj7rhW0kuEDxzJaYXGjEW5ogapKNMEKNMjibA==",
2221 | "dev": true,
2222 | "peer": true,
2223 | "dependencies": {
2224 | "isexe": "^2.0.0"
2225 | },
2226 | "bin": {
2227 | "node-which": "bin/node-which"
2228 | },
2229 | "engines": {
2230 | "node": ">= 8"
2231 | }
2232 | },
2233 | "node_modules/word-wrap": {
2234 | "version": "1.2.5",
2235 | "resolved": "https://registry.npmjs.org/word-wrap/-/word-wrap-1.2.5.tgz",
2236 | "integrity": "sha512-BN22B5eaMMI9UMtjrGd5g5eCYPpCPDUy0FJXbYsaT5zYxjFOckS53SQDE3pWkVoWpHXVb3BrYcEN4Twa55B5cA==",
2237 | "dev": true,
2238 | "peer": true,
2239 | "engines": {
2240 | "node": ">=0.10.0"
2241 | }
2242 | },
2243 | "node_modules/wrappy": {
2244 | "version": "1.0.2",
2245 | "resolved": "https://registry.npmjs.org/wrappy/-/wrappy-1.0.2.tgz",
2246 | "integrity": "sha512-l4Sp/DRseor9wL6EvV2+TuQn63dMkPjZ/sp9XkghTEbV9KlPS1xUsZ3u7/IQO4wxtcFB4bgpQPRcR3QCvezPcQ==",
2247 | "dev": true,
2248 | "peer": true
2249 | },
2250 | "node_modules/yocto-queue": {
2251 | "version": "0.1.0",
2252 | "resolved": "https://registry.npmjs.org/yocto-queue/-/yocto-queue-0.1.0.tgz",
2253 | "integrity": "sha512-rVksvsnNCdJ/ohGc6xgPwyN8eheCxsiLM8mxuE/t/mOVqJewPuO1miLpTHQiRgTKCLexL4MeAFVagts7HmNZ2Q==",
2254 | "dev": true,
2255 | "peer": true,
2256 | "engines": {
2257 | "node": ">=10"
2258 | },
2259 | "funding": {
2260 | "url": "https://github.com/sponsors/sindresorhus"
2261 | }
2262 | }
2263 | }
2264 | }
2265 |
--------------------------------------------------------------------------------
/package.json:
--------------------------------------------------------------------------------
1 | {
2 | "name": "obsidian-fabric-plugin",
3 | "version": "1.0.0",
4 | "description": "Fabric integration for Obsidian",
5 | "main": "main.js",
6 | "scripts": {
7 | "dev": "node esbuild.config.mjs",
8 | "build": "tsc -noEmit -skipLibCheck && node esbuild.config.mjs production",
9 | "version": "node version-bump.mjs && git add manifest.json versions.json"
10 | },
11 | "keywords": [],
12 | "author": "",
13 | "license": "MIT",
14 | "devDependencies": {
15 | "@types/fuzzaldrin-plus": "^0.6.5",
16 | "@types/node": "^16.11.6",
17 | "@types/semver": "^7.5.8",
18 | "@types/shell-escape": "^0.2.3",
19 | "@typescript-eslint/eslint-plugin": "5.29.0",
20 | "@typescript-eslint/parser": "5.29.0",
21 | "builtin-modules": "3.3.0",
22 | "esbuild": "0.17.3",
23 | "fuzzaldrin-plus": "^0.6.0",
24 | "obsidian": "latest",
25 | "tslib": "^2.4.0",
26 | "typescript": "4.7.4"
27 | },
28 | "dependencies": {
29 | "@types/he": "^1.2.3",
30 | "he": "^1.2.0",
31 | "shell-escape": "^0.2.0"
32 | }
33 | }
34 |
--------------------------------------------------------------------------------
/styles.css:
--------------------------------------------------------------------------------
1 |
2 | :root {
3 | --dropdown-top-offset: 5px;
4 | --dropdown-left-offset: 0;
5 | --dropdown-width-offset: 0;
6 | }
7 |
8 | .fabric-view {
9 | padding: 2rem;
10 | background-color: var(--background-primary);
11 | border-left: 1px solid var(--border-color);
12 | }
13 |
14 | .fabric-logo-container {
15 | text-align: center;
16 | margin-bottom: 3rem;
17 | position: relative;
18 | }
19 |
20 | @keyframes pulse {
21 | 0%, 50%, 100% {
22 | transform: scale(0.95);
23 | opacity: 0.7;
24 | }
25 | 25%, 75% {
26 | transform: scale(1);
27 | opacity: 1;
28 | }
29 | }
30 |
31 | .fabric-logo-container.loading .fabric-logo {
32 | animation: pulse 4s infinite ease-in-out;
33 | }
34 |
35 | .fabric-loading-text {
36 | position: absolute;
37 | bottom: -0.625rem;
38 | left: 50%;
39 | transform: translateX(-50%);
40 | font-size: 1rem;
41 | color: var(--text-muted);
42 | opacity: 0;
43 | transition: opacity 0.3s ease;
44 | }
45 |
46 | .fabric-logo-container.loading .fabric-loading-text {
47 | opacity: 1;
48 | }
49 |
50 | @keyframes blink {
51 | 0%, 100% { opacity: 1; }
52 | 50% { opacity: 0; }
53 | }
54 |
55 | .fabric-loading-text::after {
56 | content: '|';
57 | animation: blink 1s infinite;
58 | margin-left: 0.125rem;
59 | }
60 |
61 | .fabric-logo {
62 | max-width: 100%;
63 | height: auto;
64 | max-height: 28.125rem;
65 | transition: all 0.3s ease;
66 | }
67 |
68 | .fabric-title {
69 | font-size: 1.5rem;
70 | font-weight: bold;
71 | margin-bottom: 1.25rem;
72 | color: var(--text-normal);
73 | }
74 |
75 | .fabric-content {
76 | background-color: var(--background-secondary);
77 | border-radius: 0.625rem;
78 | padding: 1.25rem 1.25rem 3.125rem 1.25rem;
79 | box-shadow: 0 0.125rem 0.25rem rgba(0, 0, 0, 0.1);
80 | display: flex;
81 | flex-direction: column;
82 | align-items: center;
83 | width: 90%;
84 | max-width: 43.75rem;
85 | margin: 0 auto;
86 | position: relative;
87 | }
88 |
89 | .fabric-refresh-button,
90 | .fabric-sync-button {
91 | position: absolute;
92 | bottom: 0.625rem;
93 | background: none;
94 | border: none;
95 | cursor: pointer;
96 | color: var(--text-muted);
97 | transition: color 0.2s ease;
98 | }
99 |
100 | .fabric-refresh-button {
101 | right: 0.625rem;
102 | }
103 |
104 | .fabric-sync-button {
105 | right: 3.125rem;
106 | }
107 |
108 | .fabric-refresh-button:hover,
109 | .fabric-sync-button:hover {
110 | color: var(--text-accent);
111 | }
112 |
113 | .fabric-buttons {
114 | display: flex;
115 | justify-content: space-between;
116 | margin-bottom: 0.625rem;
117 | width: 100%;
118 | max-width: 28.125rem;
119 | }
120 |
121 | .fabric-button {
122 | flex: 1;
123 | padding: 0.9375rem;
124 | border: none;
125 | border-radius: 0.3125rem;
126 | background-color: var(--interactive-accent);
127 | color: var(--text-on-accent);
128 | cursor: pointer;
129 | transition: background-color 0.3s ease, box-shadow 0.3s ease;
130 | margin: 0 0.625rem;
131 | position: relative;
132 | overflow: hidden;
133 | }
134 |
135 | .fabric-button::before {
136 | content: "";
137 | position: absolute;
138 | top: 0;
139 | left: 0;
140 | width: 0;
141 | height: 0;
142 | background-color: rgba(255, 255, 255, 0.3);
143 | border-radius: 50%;
144 | transform: translate(-50%, -50%);
145 | transition: width 0.5s, height 0.5s;
146 | }
147 |
148 | .fabric-button:hover::before {
149 | width: 200%;
150 | height: 200%;
151 | }
152 |
153 | .fabric-button:first-child {
154 | margin-left: 0;
155 | }
156 |
157 | .fabric-button:last-child {
158 | margin-right: 0;
159 | }
160 |
161 | .fabric-button:hover {
162 | background-color: var(--interactive-accent-hover);
163 | box-shadow: 0 0 0.625rem rgba(0, 0, 0, 0.1);
164 | }
165 |
166 | .fabric-button.clipboard {
167 | background: rgb(171, 118, 209);
168 | transition: background 0.3s ease;
169 | margin: 0;
170 | }
171 |
172 | .fabric-button.current-note {
173 | background: rgb(60, 62, 149);
174 | }
175 |
176 | .fabric-button.clipboard:hover,
177 | .fabric-button.current-note:hover {
178 | box-shadow: 0 0 0.625rem rgba(107, 63, 160, 0.5), 0 0 1.25rem rgba(76, 127, 210, 0.5);
179 | }
180 |
181 | .fabric-inputs-container {
182 | display: flex;
183 | flex-direction: column;
184 | align-items: center;
185 | gap: 0.625rem;
186 | margin-bottom: 0.625rem;
187 | width: 100%;
188 | }
189 |
190 | .fabric-input,
191 | .fabric-dropdown-input,
192 | .fabric-output-note-input {
193 | width: 100%;
194 | max-width: 28.125rem;
195 | padding: 0.75rem;
196 | border: 1px solid var(--border-color);
197 | border-radius: 0.3125rem;
198 | background-color: var(--background-primary);
199 | color: var(--text-normal);
200 | transition: box-shadow 0.3s ease;
201 | box-shadow: 0 0 0.625rem rgba(0, 0, 0, 0.1);
202 | }
203 |
204 | .fabric-input.active,
205 | .fabric-dropdown-input.active,
206 | .fabric-output-note-input.active {
207 | box-shadow: 0 0 0.625rem rgba(107, 63, 160, 0.5), 0 0 1.25rem rgba(76, 127, 210, 0.5);
208 | }
209 |
210 | .fabric-dropdown {
211 | width: 100%;
212 | max-width: 28.125rem;
213 | max-height: 12.5rem;
214 | overflow-y: auto;
215 | scrollbar-width: thin;
216 | scroll-behavior: auto;
217 | border: 1px solid var(--border-color);
218 | border-radius: 0.3125rem;
219 | background-color: var(--background-primary);
220 | color: var(--text-normal);
221 | margin-top: 11.875rem;
222 | box-shadow: 0 0.125rem 0.25rem rgba(0, 0, 0, 0.1);
223 | position: absolute;
224 | z-index: 100;
225 | }
226 |
227 | .fabric-dropdown-option {
228 | padding: 0.5rem 0.75rem;
229 | cursor: pointer;
230 | background-color: var(--background-primary);
231 | border-radius: 0.3125rem;
232 | width: 100%;
233 | }
234 |
235 | .fabric-dropdown-option.selected {
236 | background: linear-gradient(to right, #6B3FA0, #4C7FD2);
237 | color: var(--text-on-accent);
238 | }
239 |
240 | .fabric-progress-spinner {
241 | border: 0.25rem solid var(--border-color);
242 | border-top-color: var(--interactive-accent);
243 | border-radius: 50%;
244 | width: 1.875rem;
245 | height: 1.875rem;
246 | animation: spin 2s linear infinite;
247 | display: none;
248 | margin: 0 auto;
249 | }
250 |
251 | .fabric-progress-spinner.active {
252 | display: block;
253 | }
254 |
255 | @keyframes spin {
256 | 0% { transform: rotate(0deg); }
257 | 100% { transform: rotate(360deg); }
258 | }
259 |
260 | .theme-light .fabric-input,
261 | .theme-light .fabric-dropdown-input,
262 | .theme-light .fabric-output-note-input,
263 | .theme-light .fabric-dropdown {
264 | color: var(--text-normal);
265 | }
266 |
267 | .fabric-content {
268 | position: relative;
269 | padding-top: 2.5rem;
270 | }
271 |
272 | .fabric-yt-toggle-container {
273 | position: absolute;
274 | top: 0.625rem;
275 | left: 0.625rem;
276 | display: flex;
277 | align-items: center;
278 | }
279 |
280 | .fabric-yt-toggle {
281 | position: relative;
282 | width: 1.875rem;
283 | height: 1.0625rem;
284 | background-color: #ccc;
285 | border-radius: 1.0625rem;
286 | cursor: pointer;
287 | transition: background-color 0.3s;
288 | }
289 |
290 | .fabric-yt-toggle.active {
291 | background-color: #2196F3;
292 | }
293 |
294 | .fabric-yt-toggle-slider {
295 | position: absolute;
296 | height: 0.8125rem;
297 | width: 0.8125rem;
298 | left: 0.25rem;
299 | bottom: 0.125rem;
300 | background-color: white;
301 | border-radius: 50%;
302 | transition: 0.3s;
303 | }
304 |
305 | .fabric-yt-toggle.active .fabric-yt-toggle-slider {
306 | transform: translateX(0.625rem);
307 | }
308 |
309 | .fabric-yt-label {
310 | margin-left: 0.625rem;
311 | font-size: 0.875rem;
312 | color: var(--text-normal);
313 | }
314 |
315 | .fabric-yt-link-list {
316 | max-height: 18.75rem;
317 | overflow-y: auto;
318 | margin-bottom: 0.625rem;
319 | border: 1px solid var(--background-modifier-border);
320 | border-radius: 0.25rem;
321 | }
322 |
323 | .fabric-yt-link {
324 | padding: 0.5rem 0.75rem;
325 | cursor: pointer;
326 | border-bottom: 1px solid var(--background-modifier-border);
327 | }
328 |
329 | .fabric-yt-link:last-child {
330 | border-bottom: none;
331 | }
332 |
333 | .fabric-yt-link.is-selected {
334 | background: linear-gradient(to right, #6B3FA0, #4C7FD2);
335 | color: var(--text-on-accent);
336 | }
337 |
338 | .fabric-yt-link:hover:not(.is-selected) {
339 | background-color: var(--background-modifier-hover);
340 | }
341 |
342 | .fabric-yt-modal-buttons {
343 | display: flex;
344 | justify-content: flex-end;
345 | gap: 0.625rem;
346 | }
347 |
348 | .fabric-ts-toggle-container {
349 | position: absolute;
350 | top: 2.1rem;
351 | left: 0.625rem;
352 | display: flex;
353 | align-items: center;
354 | }
355 |
356 | .fabric-ts-toggle {
357 | position: relative;
358 | width: 1.875rem;
359 | height: 1.0625rem;
360 | background-color: #ccc;
361 | border-radius: 1.0625rem;
362 | cursor: pointer;
363 | transition: background-color 0.3s;
364 | }
365 |
366 | .fabric-ts-toggle.active {
367 | background-color: #2196F3;
368 | }
369 |
370 | .fabric-ts-toggle-slider {
371 | position: absolute;
372 | height: 0.8125rem;
373 | width: 0.8125rem;
374 | left: 0.25rem;
375 | bottom: 0.125rem;
376 | background-color: white;
377 | border-radius: 50%;
378 | transition: 0.3s;
379 | }
380 |
381 | .fabric-ts-toggle.active .fabric-ts-toggle-slider {
382 | transform: translateX(0.625rem);
383 | }
384 |
385 | .fabric-ts-label {
386 | margin-left: 0.625rem;
387 | font-size: 0.875rem;
388 | color: var(--text-normal);
389 | }
390 |
391 | .fabric-ts-link-list {
392 | max-height: 18.75rem;
393 | overflow-y: auto;
394 | margin-bottom: 0.625rem;
395 | border: 1px solid var(--background-modifier-border);
396 | border-radius: 0.25rem;
397 | }
398 |
399 | .fabric-ts-link {
400 | padding: 0.5rem 0.75rem;
401 | cursor: pointer;
402 | border-bottom: 1px solid var(--background-modifier-border);
403 | }
404 |
405 | .fabric-ts-link:last-child {
406 | border-bottom: none;
407 | }
408 |
409 | .fabric-ts-link.is-selected {
410 | background: linear-gradient(to right, #6B3FA0, #4C7FD2);
411 | color: var(--text-on-accent);
412 | }
413 |
414 | .fabric-ts-link:hover:not(.is-selected) {
415 | background-color: var(--background-modifier-hover);
416 | }
417 |
418 | .fabric-ts-modal-buttons {
419 | display: flex;
420 | justify-content: flex-end;
421 | gap: 0.625rem;
422 | }
423 |
424 | .skip-button,
425 | .run-button {
426 | padding: 0.5rem 1rem;
427 | border: none;
428 | border-radius: 0.25rem;
429 | cursor: pointer;
430 | color: var(--text-on-accent);
431 | position: relative;
432 | overflow: hidden;
433 | }
434 |
435 | .skip-button {
436 | background: rgb(60, 62, 149);
437 | }
438 |
439 | .run-button {
440 | background: linear-gradient(to right, #6B3FA0, #4C7FD2);
441 | }
442 |
443 | .skip-button::before,
444 | .run-button::before {
445 | content: "";
446 | position: absolute;
447 | top: 0;
448 | left: 0;
449 | width: 0;
450 | height: 0;
451 | background-color: rgba(255, 255, 255, 0.3);
452 | border-radius: 50%;
453 | transform: translate(-50%, -50%);
454 | transition: width 0.5s, height 0.5s;
455 | }
456 |
457 | .skip-button:hover::before,
458 | .run-button:hover::before {
459 | width: 200%;
460 | height: 200%;
461 | }
462 |
463 | .run-button:hover {
464 | box-shadow: 0 0 0.625rem rgba(107, 63, 160, 0.5), 0 0 1.25rem rgba(76, 127, 210, 0.5);
465 | }
466 |
467 | .skip-button:hover {
468 | box-shadow: 0 0 0.625rem rgba(63, 42, 86, 0.5), 0 0 1.25rem rgba(46, 80, 119, 0.5);
469 | }
470 |
471 | @keyframes swipeUp {
472 | 0% {
473 | transform: rotateX(45deg) translateY(0.3125rem);
474 | opacity: 0;
475 | }
476 | 100% {
477 | transform: rotateX(0deg) translateY(0);
478 | opacity: 1;
479 | }
480 | }
481 |
482 | .fabric-default-model {
483 | text-align: center;
484 | margin-top: 1.25rem;
485 | font-size: 0.9em;
486 | color: var(--text-muted);
487 | opacity: 0.8;
488 | }
489 |
490 | .fabric-default-model .model-name {
491 | transition: color 0.5s ease;
492 | display: inline-block;
493 | }
494 |
495 | .fabric-default-model .model-name.updating {
496 | animation: swipeUp 0.5s ease-out;
497 | color: var(--text-accent);
498 | }
499 |
500 | #model-dropdown {
501 | top: 22%;
502 | max-height: 9.375rem;
503 | }
504 |
505 | .fabric-button-container {
506 | display: flex;
507 | justify-content: flex-end;
508 | margin-bottom: 0.625rem;
509 | }
510 |
511 | .fabric-icon-button {
512 | background-color: transparent;
513 | border: none;
514 | cursor: pointer;
515 | padding: 0.25rem;
516 | margin-left: 0.5rem;
517 | border-radius: 0.25rem;
518 | display: flex;
519 | align-items: center;
520 | justify-content: center;
521 | }
522 |
523 | .fabric-icon-button:hover {
524 | background-color: var(--interactive-hover);
525 | color: var(--text-accent);
526 | }
527 |
528 | .fabric-icon-button svg {
529 | width: 1.5625rem;
530 | height: 1rem;
531 | color: var(--text-muted);
532 | }
533 |
534 | .fabric-icon-button:hover svg {
535 | color: var(--text-accent);
536 | }
537 |
538 | .fabric-confirm-deletion {
539 | padding: 1rem;
540 | max-width: 18.75rem;
541 | }
542 |
543 | .fabric-confirm-deletion h3 {
544 | margin-top: 0;
545 | margin-bottom: 0.75rem;
546 | }
547 |
548 | .fabric-confirm-deletion p {
549 | margin-bottom: 1rem;
550 | }
551 |
552 | .fabric-confirm-buttons {
553 | display: flex;
554 | justify-content: flex-end;
555 | gap: 0.5rem;
556 | }
557 |
558 | .fabric-confirm-buttons button {
559 | padding: 0.375rem 0.75rem;
560 | border: none;
561 | border-radius: 0.25rem;
562 | cursor: pointer;
563 | }
564 |
565 | .fabric-confirm-buttons button:first-child {
566 | background-color: var(--interactive-accent);
567 | color: var(--text-on-accent);
568 | }
569 |
570 | .fabric-confirm-buttons button:last-child {
571 | background-color: var(--interactive-normal);
572 | }
573 |
574 | .fabric-button.tavily {
575 | background: linear-gradient(to right, #6B3FA0, #4C7FD2);
576 | }
577 |
578 | .fabric-button.clipboard,
579 | .fabric-button.tavily {
580 | flex: 0.5;
581 | }
582 |
583 | .fabric-tavily-modal {
584 | background-color: var(--background-primary);
585 | border-radius: 10px;
586 | padding: 20px;
587 | max-width: 500px;
588 | width: 90%;
589 | }
590 |
591 | .fabric-tavily-modal .modal-title {
592 | font-size: 1.5rem;
593 | font-weight: bold;
594 | margin-bottom: 20px;
595 | color: var(--text-normal);
596 | text-align: center;
597 | }
598 |
599 | .fabric-tavily-modal .fabric-tavily-input {
600 | width: 100%;
601 | padding: 10px;
602 | border: 1px solid var(--border-color);
603 | border-radius: 5px;
604 | background-color: var(--background-secondary);
605 | color: var(--text-normal);
606 | font-size: 1rem;
607 | margin-bottom: 20px;
608 | transition: box-shadow 0.3s ease;
609 | }
610 |
611 | .fabric-tavily-modal .fabric-tavily-input:focus {
612 | outline: none;
613 | box-shadow: 0 0 0 2px var(--interactive-accent);
614 | }
615 |
616 | .fabric-tavily-modal .fabric-tavily-button-container {
617 | display: flex;
618 | justify-content: flex-end;
619 | }
620 |
621 | .fabric-tavily-modal .fabric-tavily-search-button {
622 | background: linear-gradient(to right, #6B3FA0, #4C7FD2);
623 | color: var(--text-on-accent);
624 | border: none;
625 | border-radius: 5px;
626 | padding: 10px 20px;
627 | font-size: 1rem;
628 | cursor: pointer;
629 | transition: all 0.3s ease;
630 | position: relative;
631 | overflow: hidden;
632 | }
633 |
634 | .fabric-tavily-modal .fabric-tavily-search-button:hover {
635 | box-shadow: 0 0 10px rgba(107, 63, 160, 0.5), 0 0 20px rgba(76, 127, 210, 0.5);
636 | }
637 |
638 | .fabric-tavily-modal .fabric-tavily-search-button::before {
639 | content: "";
640 | position: absolute;
641 | top: 0;
642 | left: 0;
643 | width: 0;
644 | height: 0;
645 | background-color: rgba(255, 255, 255, 0.3);
646 | border-radius: 50%;
647 | transform: translate(-50%, -50%);
648 | transition: width 0.5s, height 0.5s;
649 | }
650 |
651 | .fabric-tavily-modal .fabric-tavily-search-button:hover::before {
652 | width: 300%;
653 | height: 300%;
654 | }
655 | .community-patterns-title {
656 | font-size: 1.5rem;
657 | font-weight: bold;
658 | margin-bottom: 1.25rem;
659 | color: var(--text-normal);
660 | }
661 |
662 | .community-patterns-search {
663 | width: 100%;
664 | padding: 0.75rem;
665 | border: 1px solid var(--border-color);
666 | border-radius: 0.3125rem;
667 | background-color: var(--background-primary);
668 | color: var(--text-normal);
669 | transition: box-shadow 0.3s ease;
670 | box-shadow: 0 0 0.625rem rgba(0, 0, 0, 0.1);
671 | margin-bottom: 1rem;
672 | margin-top: 1rem;
673 | }
674 |
675 | .community-patterns-results {
676 | display: flex;
677 | flex-direction: column;
678 | gap: 0.25rem;
679 | width: 100%;
680 | max-height: 70vh;
681 | overflow-y: auto;
682 | margin-top: 1rem;
683 | }
684 |
685 | .community-pattern-item {
686 | background-color: var(--background-secondary);
687 | border-radius: 0.25rem;
688 | padding: 0.25rem 0.5rem;
689 | box-shadow: 0 1px 2px rgba(0, 0, 0, 0.1);
690 | display: flex;
691 | justify-content: space-between;
692 | align-items: center;
693 | gap: 0.5rem;
694 | font-size: 0.75rem;
695 | min-height: 2rem;
696 | width: 100%;
697 | }
698 |
699 | .community-pattern-info {
700 | display: flex;
701 | flex-direction: column;
702 | gap: 0.125rem;
703 | flex-grow: 1;
704 | overflow: hidden;
705 | text-align: left;
706 | }
707 |
708 | .community-pattern-title {
709 | font-size: 0.8125rem;
710 | font-weight: bold;
711 | margin: 0;
712 | white-space: nowrap;
713 | overflow: hidden;
714 | text-overflow: ellipsis;
715 | }
716 |
717 | .community-pattern-description {
718 | color: var(--text-muted);
719 | font-size: 0.6875rem;
720 | margin: 0;
721 | white-space: nowrap;
722 | overflow: hidden;
723 | text-overflow: ellipsis;
724 | }
725 |
726 | .community-pattern-buttons {
727 | display: flex;
728 | gap: 0.25rem;
729 | }
730 |
731 | .community-pattern-download,
732 | .community-pattern-update,
733 | .community-pattern-uninstall {
734 | padding: 0.125rem 0.25rem;
735 | font-size: 0.6875rem;
736 | min-width: 3rem;
737 | border: none;
738 | border-radius: 0.1875rem;
739 | cursor: pointer;
740 | transition: background-color 0.3s ease;
741 | }
742 |
743 | .community-pattern-download {
744 | background-color: var(--interactive-accent);
745 | color: var(--text-on-accent);
746 | }
747 |
748 | .community-pattern-update {
749 | background-color: var(--text-accent);
750 | color: var(--text-on-accent);
751 | }
752 |
753 | .community-pattern-uninstall {
754 | background-color: var(--text-error);
755 | color: var(--text-on-accent);
756 | }
757 |
758 | .community-pattern-download:hover,
759 | .community-pattern-update:hover,
760 | .community-pattern-uninstall:hover {
761 | opacity: 0.8;
762 | }
763 |
764 | .fabric-icon-button.community-patterns {
765 | position: absolute;
766 | bottom: 0.625rem;
767 | right: 5.6rem;
768 | background-color: var(--interactive-normal);
769 | border: none;
770 | cursor: pointer;
771 | color: var(--text-muted);
772 | transition: color 0.2s ease;
773 | }
774 |
775 | .fabric-icon-button.community-patterns:hover {
776 | color: var(--text-on-accent);
777 | }
778 |
779 | .community-patterns-button-container {
780 | display: flex;
781 | gap: 0.5rem; /* Space between buttons */
782 | margin-bottom: 1rem; /* Space below the button container */
783 | }
784 |
785 | .fabric-button.community-patterns-update-all,
786 | .fabric-button.community-patterns-refresh {
787 | background-color: var(--interactive-normal);
788 | border: none;
789 | cursor: pointer;
790 | color: var(--text-muted);
791 | transition: color 0.2s ease;
792 | }
793 |
794 | .fabric-button.community-patterns-update-all:hover,
795 | .fabric-button.community-patterns-refresh:hover {
796 | color: var(--text-accent);
797 | }
--------------------------------------------------------------------------------
/tsconfig.json:
--------------------------------------------------------------------------------
1 | {
2 | "compilerOptions": {
3 | "baseUrl": ".",
4 | "inlineSourceMap": true,
5 | "inlineSources": true,
6 | "module": "ESNext",
7 | "target": "ES6",
8 | "allowJs": true,
9 | "noImplicitAny": true,
10 | "moduleResolution": "node",
11 | "importHelpers": true,
12 | "isolatedModules": true,
13 | "strictNullChecks": true,
14 | "lib": [
15 | "DOM",
16 | "ES5",
17 | "ES6",
18 | "ES7"
19 | ]
20 | },
21 | "include": [
22 | "**/*.ts"
23 | ]
24 | }
--------------------------------------------------------------------------------