├── .eslintrc.json ├── .github └── workflows │ └── release.yml ├── .gitignore ├── .prettierrc ├── LICENSE ├── README.md ├── main.ts ├── manifest-beta.json ├── manifest.json ├── package.json ├── rollup.config.js ├── settings.ts ├── styles.css ├── tsconfig.json ├── types.ts ├── utils.ts ├── version-bump.mjs ├── versions.json ├── voicenotes-api.ts └── yarn.lock /.eslintrc.json: -------------------------------------------------------------------------------- 1 | { 2 | "env": { 3 | "browser": true, 4 | "es6": true 5 | }, 6 | "extends": [ 7 | "eslint:recommended", 8 | "plugin:@typescript-eslint/recommended", 9 | "plugin:prettier/recommended" 10 | ], 11 | "parserOptions": { 12 | "ecmaVersion": 2020, 13 | "sourceType": "module" 14 | }, 15 | "rules": { 16 | "prettier/prettier": "error" 17 | } 18 | } -------------------------------------------------------------------------------- /.github/workflows/release.yml: -------------------------------------------------------------------------------- 1 | name: Release Obsidian VoiceNotes Sync plugin 2 | 3 | on: 4 | push: 5 | tags: 6 | - "*" 7 | 8 | env: 9 | PLUGIN_NAME: voicenotes-sync 10 | 11 | jobs: 12 | build: 13 | runs-on: ubuntu-latest 14 | 15 | steps: 16 | - uses: actions/checkout@v2 17 | - name: Use Node.js 18 | uses: actions/setup-node@v1 19 | with: 20 | node-version: "18.x" 21 | 22 | - name: Build 23 | id: build 24 | run: | 25 | yarn install 26 | yarn run build 27 | mkdir ${{ env.PLUGIN_NAME }} 28 | cp main.js manifest.json styles.css ${{ env.PLUGIN_NAME }} 29 | zip -r ${{ env.PLUGIN_NAME }}.zip ${{ env.PLUGIN_NAME }} 30 | ls 31 | echo "::set-output name=tag_name::$(git tag --sort version:refname | tail -n 1)" 32 | 33 | - name: Create Release 34 | id: create_release 35 | uses: actions/create-release@v1 36 | env: 37 | GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }} 38 | VERSION: ${{ github.ref }} 39 | with: 40 | tag_name: ${{ github.ref }} 41 | release_name: ${{ github.ref }} 42 | draft: false 43 | prerelease: false 44 | 45 | - name: Upload zip file 46 | id: upload-zip 47 | uses: actions/upload-release-asset@v1 48 | env: 49 | GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }} 50 | with: 51 | upload_url: ${{ steps.create_release.outputs.upload_url }} 52 | asset_path: ./${{ env.PLUGIN_NAME }}.zip 53 | asset_name: ${{ env.PLUGIN_NAME }}-${{ steps.build.outputs.tag_name }}.zip 54 | asset_content_type: application/zip 55 | 56 | - name: Upload main.js 57 | id: upload-main 58 | uses: actions/upload-release-asset@v1 59 | env: 60 | GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }} 61 | with: 62 | upload_url: ${{ steps.create_release.outputs.upload_url }} 63 | asset_path: ./main.js 64 | asset_name: main.js 65 | asset_content_type: text/javascript 66 | 67 | - name: Upload manifest.json 68 | id: upload-manifest 69 | uses: actions/upload-release-asset@v1 70 | env: 71 | GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }} 72 | with: 73 | upload_url: ${{ steps.create_release.outputs.upload_url }} 74 | asset_path: ./manifest.json 75 | asset_name: manifest.json 76 | asset_content_type: application/json 77 | 78 | - name: Upload manifest-beta.json 79 | id: upload-manifest-beta 80 | uses: actions/upload-release-asset@v1 81 | env: 82 | GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }} 83 | with: 84 | upload_url: ${{ steps.create_release.outputs.upload_url }} 85 | asset_path: ./manifest-beta.json 86 | asset_name: manifest-beta.json 87 | asset_content_type: application/json 88 | 89 | - name: Upload styles.css 90 | id: upload-css 91 | uses: actions/upload-release-asset@v1 92 | env: 93 | GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }} 94 | with: 95 | upload_url: ${{ steps.create_release.outputs.upload_url }} 96 | asset_path: ./styles.css 97 | asset_name: styles.css 98 | asset_content_type: text/css -------------------------------------------------------------------------------- /.gitignore: -------------------------------------------------------------------------------- 1 | # Intellij 2 | *.iml 3 | .idea 4 | 5 | # npm 6 | node_modules 7 | package-lock.json 8 | 9 | # build 10 | main.js 11 | *.js.map 12 | 13 | # obsidian 14 | data.json 15 | -------------------------------------------------------------------------------- /.prettierrc: -------------------------------------------------------------------------------- 1 | { 2 | "tabWidth": 2, 3 | "useTabs": false, 4 | "singleQuote": true, 5 | "printWidth": 120, 6 | "semi": true, 7 | "trailingComma": "es5" 8 | } 9 | -------------------------------------------------------------------------------- /LICENSE: -------------------------------------------------------------------------------- 1 | MIT License 2 | 3 | Copyright (c) 2021 Andrew Lombardi 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. 22 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | ## Voicenotes Sync 2 | Plugin offers the ability to sync down your thoughts an ideas from the voicenotes.com online service. The service 3 | uses an API key which the plugin can grab post login (if using email and password or use the Login via Apple, Google, 4 | Twitter (X) instructions below) and we do not save anything but the username in the settings file. 5 | 6 | Through the plugin settings one can customize the sync directory and frequency, download the audio file used in the 7 | transcript and any AI generated summaries or actions become sections in the note text. 8 | 9 | ### Signup 10 | You can signup using my referral link if you'd like: [VoiceNotes.com Signup with Referral](https://voicenotes.com/?via=andrew-lombardi). 11 | 12 | ### Features 13 | - Automatically sync data based on configurable minutes from VoiceNotes.com 14 | - Includes any AI generated summaries or actions 15 | - Includes TODOs which are turned into markdown todos (can append a tag to every TODO as well) 16 | - Customize the sync directory and frequency 17 | - Downloads the audio file (default is off) 18 | - Prepend the date to the title / filename 19 | - Optional mode to delete synced notes from the voicenotes.com server 20 | - Destructive action which requires double opt-in toggles 21 | 22 | ### Login via Apple, Google, Twitter (X) 23 | Steps to login with the above services (quite manual but doable). 24 | 25 | 1. Open up voicenotes.com in a browser like Chrome 26 | 2. After logging in open up Developer Tools 27 | 3. Navigate to the "Network" tab 28 | 4. Click on Fetch/XHR to see those calls specifically 29 | 5. Hit refresh on the voicenotes.com page 30 | 6. One of the entries should say "me" click on it and navigate to the Headers section 31 | 7. Scroll down to "Request Headers" and find the line that says "Authorization" 32 | 8. The right side of this entry will say "Bearer x" where x is a longish string of text. This is your authorization / login key 33 | 9. Copy that value for the next step 34 | 35 | ## Back in Obsidian 36 | 1. Enter the token into the "Auth Token" field in settings 37 | 4. Click Login with Token 38 | 39 | 40 | ### Installation 41 | The VoiceNotes.com Sync Plugin is available in the Obsidian Community Plugins area. 42 | 43 | 1. Turn off restricted mode if it's on 44 | 2. Click 'Browse' under Community pllugins and search for "Voicenotes" 45 | 3. Install and enable the plugin 46 | 4. Click the gear icon for settings to login to voicenotes.com and sync 47 | 48 | ### Manual Installation 49 | Two methods and the first one is easier: 50 | 51 | #### Method 1 52 | - Enable community plugins and install Obsidian42 - BRAT 53 | - Go to settings and under Beta Plugin List click "Add Beta plugin" and type mysticcoders/voicenotes-sync 54 | 55 | #### Method 2 56 | - Create an `voicenotes-sync` folder under `.obsidian/plugins` in your vault. Add the 57 | `main.js`, `manifest.json`, and the `styles.css` files from the 58 | [latest release](https://github.com/kinabalu/voicenotes-sync/releases) to the folder. 59 | 60 | ## Say Thanks 🙏 61 | 62 | If you like this plugin and would like to buy me a coffee, you can! 63 | 64 | [BuyMeACoffee](https://www.buymeacoffee.com/andrewlombardi) 65 | -------------------------------------------------------------------------------- /main.ts: -------------------------------------------------------------------------------- 1 | import { App, DataAdapter, Editor, normalizePath, Notice, Plugin, PluginManifest, TFile } from 'obsidian'; 2 | import VoiceNotesApi from './voicenotes-api'; 3 | import { getFilenameFromUrl, isToday, formatDuration, formatDate, formatTags, convertHtmlToMarkdown } from './utils'; 4 | import { VoiceNotesPluginSettings } from './types'; 5 | import { sanitize } from 'sanitize-filename-ts'; 6 | import { VoiceNotesSettingTab } from './settings'; 7 | // @ts-ignore 8 | import * as jinja from 'jinja-js'; 9 | 10 | const DEFAULT_SETTINGS: VoiceNotesPluginSettings = { 11 | automaticSync: true, 12 | syncTimeout: 60, 13 | downloadAudio: false, 14 | syncDirectory: 'voicenotes', 15 | deleteSynced: false, 16 | reallyDeleteSynced: false, 17 | todoTag: '', 18 | filenameDateFormat: 'YYYY-MM-DD', 19 | frontmatterTemplate: `duration: {{duration}} 20 | created_at: {{created_at}} 21 | updated_at: {{updated_at}} 22 | {{tags}}`, 23 | noteTemplate: `# {{ title }} 24 | 25 | Date: {{ date }} 26 | 27 | {% if summary %} 28 | ## Summary 29 | 30 | {{ summary }} 31 | {% endif %} 32 | 33 | {% if points %} 34 | ## Main points 35 | 36 | {{ points }} 37 | {% endif %} 38 | 39 | {% if attachments %} 40 | ## Attachments 41 | 42 | {{ attachments }} 43 | {% endif %} 44 | 45 | {% if tidy %} 46 | ## Tidy Transcript 47 | 48 | {{ tidy }} 49 | 50 | {% else %} 51 | ## Transcript 52 | 53 | {{ transcript }} 54 | {% endif %} 55 | 56 | {% if embedded_audio_link %} 57 | {{ embedded_audio_link }} 58 | {% endif %} 59 | 60 | {% if audio_filename %} 61 | [[{{ audio_filename }}|Audio]] 62 | {% endif %} 63 | 64 | {% if todo %} 65 | ## Todos 66 | 67 | {{ todo }} 68 | {% endif %} 69 | 70 | {% if email %} 71 | ## Email 72 | 73 | {{ email }} 74 | {% endif %} 75 | 76 | {% if blog %} 77 | ## Blog 78 | 79 | {{ blog }} 80 | {% endif %} 81 | 82 | {% if tweet %} 83 | ## Tweet 84 | 85 | {{ tweet }} 86 | {% endif %} 87 | 88 | {% if custom %} 89 | ## Others 90 | 91 | {{ custom }} 92 | {% endif %} 93 | 94 | {% if tags %} 95 | ## Tags 96 | 97 | {{ tags }} 98 | {% endif %} 99 | 100 | {% if related_notes %} 101 | # Related Notes 102 | 103 | {{ related_notes }} 104 | {% endif %} 105 | 106 | {% if parent_note %} 107 | ## Parent Note 108 | 109 | - {{ parent_note }} 110 | {% endif %} 111 | 112 | {% if subnotes %} 113 | ## Subnotes 114 | 115 | {{ subnotes }} 116 | {% endif %}`, 117 | 118 | filenameTemplate: ` 119 | {{date}} {{title}} 120 | `, 121 | excludeTags: [], 122 | dateFormat: 'YYYY-MM-DD', 123 | }; 124 | 125 | export default class VoiceNotesPlugin extends Plugin { 126 | settings: VoiceNotesPluginSettings; 127 | vnApi: VoiceNotesApi; 128 | fs: DataAdapter; 129 | timeSinceSync: number = 0; 130 | syncedRecordingIds: number[]; 131 | syncIntervalId: NodeJS.Timeout | null = null; 132 | 133 | ONE_SECOND = 1000; 134 | 135 | constructor(app: App, manifest: PluginManifest) { 136 | super(app, manifest); 137 | this.fs = app.vault.adapter; 138 | } 139 | 140 | async onload() { 141 | await this.loadSettings(); 142 | this.addSettingTab(new VoiceNotesSettingTab(this.app, this)); 143 | 144 | if (this.settings.token) { 145 | this.setupAutoSync(); 146 | } 147 | 148 | this.addCommand({ 149 | id: 'manual-sync-voicenotes', 150 | name: 'Manual Sync Voicenotes', 151 | callback: async () => await this.sync(false), 152 | }); 153 | 154 | this.addCommand({ 155 | id: 'insert-voicenotes-from-today', 156 | name: "Insert Today's Voicenotes", 157 | editorCallback: async (editor: Editor) => { 158 | if (!this.settings.token) { 159 | new Notice('No access available, please login in plugin settings'); 160 | return; 161 | } 162 | 163 | const todaysRecordings = await this.getTodaysSyncedRecordings(); 164 | 165 | if (todaysRecordings.length === 0) { 166 | new Notice('No recordings from today found'); 167 | return; 168 | } 169 | 170 | const listOfToday = todaysRecordings.map((filename) => `- [[${filename}]]`).join('\n'); 171 | editor.replaceSelection(listOfToday); 172 | }, 173 | }); 174 | 175 | this.registerEvent( 176 | this.app.metadataCache.on('deleted', (deletedFile, prevCache) => { 177 | if (prevCache.frontmatter?.recording_id) { 178 | this.syncedRecordingIds.remove(prevCache.frontmatter?.recording_id); 179 | } 180 | }) 181 | ); 182 | 183 | // Timeout to give the app time to load 184 | setTimeout(async () => { 185 | this.syncedRecordingIds = await this.getSyncedRecordingIds(); 186 | await this.sync(this.syncedRecordingIds.length === 0); 187 | }, 1000); 188 | } 189 | 190 | onunload() { 191 | this.syncedRecordingIds = []; 192 | this.clearAutoSync(); 193 | } 194 | 195 | async loadSettings() { 196 | this.settings = Object.assign({}, DEFAULT_SETTINGS, await this.loadData()); 197 | } 198 | 199 | async saveSettings() { 200 | await this.saveData(this.settings); 201 | this.setupAutoSync(); 202 | } 203 | 204 | setupAutoSync() { 205 | this.clearAutoSync(); 206 | if (this.settings.automaticSync) { 207 | this.syncIntervalId = setInterval( 208 | () => { 209 | this.sync(false); 210 | }, 211 | this.settings.syncTimeout * 60 * 1000 212 | ); 213 | } 214 | } 215 | 216 | clearAutoSync() { 217 | if (this.syncIntervalId) { 218 | clearInterval(this.syncIntervalId); 219 | this.syncIntervalId = null; 220 | } 221 | } 222 | 223 | async getRecordingIdFromFile(file: TFile): Promise { 224 | return this.app.metadataCache.getFileCache(file)?.frontmatter?.['recording_id']; 225 | } 226 | 227 | async isRecordingFromToday(file: TFile): Promise { 228 | return isToday(await this.app.metadataCache.getFileCache(file)?.frontmatter?.['created_at']); 229 | } 230 | 231 | sanitizedTitle(title: string, created_at: string): string { 232 | const date = formatDate(created_at, this.settings.filenameDateFormat); 233 | const generatedTitle = this.settings.filenameTemplate.replace('{{date}}', date).replace('{{title}}', title); 234 | return sanitize(generatedTitle); 235 | } 236 | 237 | /** 238 | * Return the recording IDs that we've already synced 239 | */ 240 | async getSyncedRecordingIds(): Promise { 241 | const { vault } = this.app; 242 | 243 | const markdownFiles = vault.getMarkdownFiles().filter((file) => file.path.startsWith(this.settings.syncDirectory)); 244 | 245 | return (await Promise.all(markdownFiles.map(async (file) => this.getRecordingIdFromFile(file)))).filter( 246 | (recordingId) => recordingId !== undefined 247 | ) as number[]; 248 | } 249 | 250 | async getTodaysSyncedRecordings(): Promise { 251 | const { vault } = this.app; 252 | 253 | const markdownFiles = vault.getMarkdownFiles().filter((file) => file.path.startsWith(this.settings.syncDirectory)); 254 | 255 | return ( 256 | await Promise.all( 257 | markdownFiles.map(async (file) => ((await this.isRecordingFromToday(file)) ? file.basename : undefined)) 258 | ) 259 | ).filter((filename) => filename !== undefined) as string[]; 260 | } 261 | 262 | async processNote( 263 | recording: any, 264 | voiceNotesDir: string, 265 | isSubnote: boolean = false, 266 | parentTitle: string = '', 267 | unsyncedCount: { count: number } 268 | ): Promise { 269 | try { 270 | if (!recording.title) { 271 | new Notice(`Unable to grab voice recording with id: ${recording.id}`); 272 | return; 273 | } 274 | 275 | const title = this.sanitizedTitle(recording.title, recording.created_at); 276 | const recordingPath = normalizePath(`${voiceNotesDir}/${title}.md`); 277 | 278 | // Process sub-notes, whether the note already exists or not 279 | if (recording.subnotes && recording.subnotes.length > 0) { 280 | for (const subnote of recording.subnotes) { 281 | await this.processNote(subnote, voiceNotesDir, true, title, unsyncedCount); 282 | } 283 | } 284 | 285 | // Check if the recording contains any excluded tags 286 | if ( 287 | recording.tags && 288 | recording.tags.some((tag: { name: string }) => this.settings.excludeTags.includes(tag.name)) 289 | ) { 290 | unsyncedCount.count++; 291 | return; 292 | } 293 | 294 | // Check if the note already exists 295 | const noteExists = await this.app.vault.adapter.exists(recordingPath); 296 | 297 | // If the note doesn't exist, or if it's a sub-note, it's treated as follows 298 | if (!noteExists || isSubnote) { 299 | // Prepare data for the template 300 | const creationTypes = ['summary', 'points', 'tidy', 'todo', 'tweet', 'blog', 'email', 'custom']; 301 | const creations = Object.fromEntries( 302 | creationTypes.map((type) => [ 303 | type, 304 | recording.creations.find((creation: { type: string }) => creation.type === type), 305 | ]) 306 | ); 307 | 308 | const { transcript } = recording; 309 | 310 | // Destructure creations object to get individual variables if needed 311 | const { summary, points, tidy, todo, tweet, blog, email, custom } = creations; 312 | 313 | let embeddedAudioLink = ''; 314 | let audioFilename = ''; 315 | if (this.settings.downloadAudio) { 316 | const audioPath = normalizePath(`${voiceNotesDir}/audio`); 317 | if (!(await this.app.vault.adapter.exists(audioPath))) { 318 | await this.app.vault.createFolder(audioPath); 319 | } 320 | const outputLocationPath = normalizePath(`${audioPath}/${recording.recording_id}.mp3`); 321 | if (!(await this.app.vault.adapter.exists(outputLocationPath))) { 322 | const signedUrl = await this.vnApi.getSignedUrl(recording.recording_id); 323 | await this.vnApi.downloadFile(this.fs, signedUrl.url, outputLocationPath); 324 | } 325 | embeddedAudioLink = `![[${recording.recording_id}.mp3]]`; 326 | audioFilename = `${recording.recording_id}.mp3`; 327 | } 328 | 329 | // Handle attachments 330 | let attachments = ''; 331 | if (recording.attachments && recording.attachments.length > 0) { 332 | const attachmentsPath = normalizePath(`${voiceNotesDir}/attachments`); 333 | if (!(await this.app.vault.adapter.exists(attachmentsPath))) { 334 | await this.app.vault.createFolder(attachmentsPath); 335 | } 336 | attachments = ( 337 | await Promise.all( 338 | recording.attachments.map(async (data: any) => { 339 | if (data.type === 1) { 340 | return `- ${data.description}`; 341 | } else if (data.type === 2) { 342 | const filename = getFilenameFromUrl(data.url); 343 | const attachmentPath = normalizePath(`${attachmentsPath}/${filename}`); 344 | await this.vnApi.downloadFile(this.fs, data.url, attachmentPath); 345 | return `- ![[${filename}]]`; 346 | } 347 | }) 348 | ) 349 | ).join('\n'); 350 | } 351 | 352 | // Prepare context for Jinja template 353 | const formattedPoints = points ? points.content.data.map((data: string) => `- ${data}`).join('\n') : null; 354 | const formattedTodos = todo 355 | ? todo.content.data 356 | .map((data: string) => `- [ ] ${data}${this.settings.todoTag ? ' #' + this.settings.todoTag : ''}`) 357 | .join('\n') 358 | : null; 359 | // Format tags, replacing spaces with hyphens for multi-word tags 360 | const formattedTags = 361 | recording.tags && recording.tags.length > 0 362 | ? recording.tags.map((tag: { name: string }) => `#${tag.name.replace(/\s+/g, '-')}`).join(' ') 363 | : null; 364 | const context = { 365 | recording_id: recording.recording_id, 366 | title: title, 367 | date: formatDate(recording.created_at, this.settings.dateFormat), 368 | duration: formatDuration(recording.duration), 369 | created_at: formatDate(recording.created_at, this.settings.dateFormat), 370 | updated_at: formatDate(recording.updated_at, this.settings.dateFormat), 371 | transcript: transcript, 372 | embedded_audio_link: embeddedAudioLink, 373 | audio_filename: audioFilename, 374 | summary: summary ? summary.markdown_content : null, 375 | tidy: tidy ? tidy.markdown_content : null, 376 | points: formattedPoints, 377 | todo: formattedTodos, 378 | tweet: tweet ? tweet.markdown_content : null, 379 | blog: blog ? blog.markdown_content : null, 380 | email: email ? email.markdown_content : null, 381 | custom: custom ? custom.markdown_content : null, 382 | tags: formattedTags, 383 | related_notes: 384 | recording.related_notes && recording.related_notes.length > 0 385 | ? recording.related_notes 386 | .map( 387 | (relatedNote: { title: string; created_at: string }) => 388 | `- [[${this.sanitizedTitle(relatedNote.title, relatedNote.created_at)}]]` 389 | ) 390 | .join('\n') 391 | : null, 392 | subnotes: 393 | recording.subnotes && recording.subnotes.length > 0 394 | ? recording.subnotes 395 | .map( 396 | (subnote: { title: string; created_at: string }) => 397 | `- [[${this.sanitizedTitle(subnote.title, subnote.created_at)}]]` 398 | ) 399 | .join('\n') 400 | : null, 401 | attachments: attachments, 402 | parent_note: isSubnote ? `[[${parentTitle}]]` : null, 403 | }; 404 | 405 | // Render the template using Jinja 406 | let note = jinja.render(this.settings.noteTemplate, context).replace(/\n{3,}/g, '\n\n'); 407 | note = convertHtmlToMarkdown(note); 408 | 409 | // Recording ID is required so we force it 410 | let recordingIdTemplate = `recording_id: {{recording_id}}\n`; 411 | let renderedFrontmatter = jinja.render(recordingIdTemplate + this.settings.frontmatterTemplate, context).replace(/\n{3,}/g, '\n\n'); 412 | 413 | const metadata = `---\n${renderedFrontmatter}\n---\n` 414 | 415 | note = metadata + note; 416 | 417 | // Create or update note 418 | if (noteExists) { 419 | await this.app.vault.modify(this.app.vault.getFileByPath(recordingPath) as TFile, note); 420 | } else { 421 | await this.app.vault.create(recordingPath, note); 422 | } 423 | 424 | if (!this.syncedRecordingIds.includes(recording.recording_id)) { 425 | this.syncedRecordingIds.push(recording.recording_id); 426 | } 427 | 428 | if (this.settings.deleteSynced && this.settings.reallyDeleteSynced) { 429 | await this.vnApi.deleteRecording(recording.recording_id); 430 | } 431 | } 432 | } catch (error) { 433 | console.error(error); 434 | if (error.hasOwnProperty('status') !== 'undefined') { 435 | console.error(error.status); 436 | if (error.hasOwnProperty('text') !== 'undefined') { 437 | console.error(error.text); 438 | } 439 | if (error.hasOwnProperty('json') !== 'undefined') { 440 | console.error(error.json); 441 | } 442 | if (error.hasOwnProperty('headers') !== 'undefined') { 443 | console.error(error.headers); 444 | } 445 | 446 | this.settings.token = undefined; 447 | await this.saveSettings(); 448 | new Notice(`Login token was invalid, please try logging in again.`); 449 | } else { 450 | new Notice(`Error occurred syncing some notes to this vault.`) 451 | } 452 | } 453 | } 454 | 455 | async sync(fullSync: boolean = false) { 456 | try { 457 | console.debug(`Sync running full? ${fullSync}`); 458 | 459 | this.syncedRecordingIds = await this.getSyncedRecordingIds(); 460 | 461 | this.vnApi = new VoiceNotesApi({}); 462 | this.vnApi.token = this.settings.token; 463 | 464 | const voiceNotesDir = normalizePath(this.settings.syncDirectory); 465 | if (!(await this.app.vault.adapter.exists(voiceNotesDir))) { 466 | new Notice('Creating sync directory for Voice Notes Sync plugin'); 467 | await this.app.vault.createFolder(voiceNotesDir); 468 | } 469 | 470 | const recordings = await this.vnApi.getRecordings(); 471 | // This only happens if we aren't actually logged in, fail immediately. 472 | if (recordings === null) { 473 | this.settings.token = undefined; 474 | return; 475 | } 476 | const unsyncedCount = { count: 0 }; 477 | 478 | if (fullSync && recordings.links.next) { 479 | let nextPage = recordings.links.next; 480 | 481 | do { 482 | console.debug(`Performing a full sync ${nextPage}`); 483 | 484 | const moreRecordings = await this.vnApi.getRecordingsFromLink(nextPage); 485 | recordings.data.push(...moreRecordings.data); 486 | nextPage = moreRecordings.links.next; 487 | } while (nextPage); 488 | } 489 | 490 | if (recordings) { 491 | new Notice(`Syncing latest Voicenotes`); 492 | for (const recording of recordings.data) { 493 | await this.processNote(recording, voiceNotesDir, false, '', unsyncedCount); 494 | } 495 | } 496 | 497 | new Notice(`Sync complete. ${unsyncedCount.count} recordings were not synced due to excluded tags.`); 498 | } catch (error) { 499 | console.error(error); 500 | if (error.hasOwnProperty('status') !== 'undefined') { 501 | this.settings.token = undefined; 502 | await this.saveSettings(); 503 | new Notice(`Login token was invalid, please try logging in again.`); 504 | } else { 505 | new Notice(`Error occurred syncing some notes to this vault.`) 506 | } 507 | } 508 | } 509 | } 510 | -------------------------------------------------------------------------------- /manifest-beta.json: -------------------------------------------------------------------------------- 1 | { 2 | "id": "voicenotes-sync", 3 | "name": "Voicenotes Sync", 4 | "version": "0.0.30-beta3", 5 | "minAppVersion": "1.5.12", 6 | "description": "Synchronize your notes from Voicenotes.com", 7 | "author": "Andrew Lombardi", 8 | "authorUrl": "https://mysticcoders.com", 9 | "isDesktopOnly": false 10 | } 11 | -------------------------------------------------------------------------------- /manifest.json: -------------------------------------------------------------------------------- 1 | { 2 | "id": "voicenotes-sync", 3 | "name": "Voicenotes Sync", 4 | "version": "0.0.28", 5 | "minAppVersion": "1.5.12", 6 | "description": "Synchronize your notes from Voicenotes.com", 7 | "author": "Andrew Lombardi", 8 | "authorUrl": "https://mysticcoders.com", 9 | "isDesktopOnly": false 10 | } -------------------------------------------------------------------------------- /package.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "voicenotes-sync", 3 | "version": "0.0.30-beta3", 4 | "description": "A plugin for syncing Voicenotes.com data into notes", 5 | "main": "main.js", 6 | "scripts": { 7 | "dev": "rollup --config rollup.config.js --bundleConfigAsCjs -w", 8 | "lint": "eslint *.ts", 9 | "lint:fix": "eslint --fix *.ts", 10 | "version": "node version-bump.mjs && git add manifest.json versions.json", 11 | "build": "rollup --config rollup.config.js --bundleConfigAsCjs --environment BUILD:production" 12 | }, 13 | "keywords": [], 14 | "author": "", 15 | "license": "MIT", 16 | "devDependencies": { 17 | "@rollup/plugin-commonjs": "^26.0.1", 18 | "@rollup/plugin-node-resolve": "^15.2.3", 19 | "@rollup/plugin-typescript": "^11.1.6", 20 | "@types/moment": "2.13.0", 21 | "@types/node": "^22.1.0", 22 | "@types/numeral": "^2.0.5", 23 | "@typescript-eslint/eslint-plugin": "^8.0.1", 24 | "@typescript-eslint/parser": "^8.0.1", 25 | "eslint": "^8.57.0", 26 | "eslint-config-prettier": "^9.1.0", 27 | "eslint-plugin-prettier": "^5.2.1", 28 | "eslint-plugin-unused-imports": "^4.0.1", 29 | "obsidian": "^1.5.7-1", 30 | "rollup": "^4.20.0", 31 | "tslib": "^2.6.3", 32 | "typescript": "^5.5.4" 33 | }, 34 | "dependencies": { 35 | "jinja-js": "^0.1.8", 36 | "moment": "2.30.1", 37 | "numeral": "^2.0.6", 38 | "prettier": "^3.3.3", 39 | "sanitize-filename-ts": "^1.0.2" 40 | } 41 | } 42 | -------------------------------------------------------------------------------- /rollup.config.js: -------------------------------------------------------------------------------- 1 | import typescript from '@rollup/plugin-typescript'; 2 | import {nodeResolve} from '@rollup/plugin-node-resolve'; 3 | import commonjs from '@rollup/plugin-commonjs'; 4 | 5 | const isProd = (process.env.BUILD === 'production'); 6 | 7 | const banner = 8 | `/* 9 | THIS IS A GENERATED/BUNDLED FILE BY ROLLUP 10 | if you want to view the source visit the plugins github repository 11 | */ 12 | `; 13 | 14 | export default { 15 | input: 'main.ts', 16 | output: { 17 | dir: '.', 18 | sourcemap: 'inline', 19 | sourcemapExcludeSources: isProd, 20 | format: 'cjs', 21 | exports: 'default', 22 | banner, 23 | }, 24 | external: ['obsidian'], 25 | plugins: [ 26 | typescript(), 27 | nodeResolve({browser: true}), 28 | commonjs(), 29 | ] 30 | }; -------------------------------------------------------------------------------- /settings.ts: -------------------------------------------------------------------------------- 1 | import { App, Notice, PluginSettingTab, Setting } from 'obsidian'; 2 | import VoiceNotesApi from './voicenotes-api'; 3 | import VoiceNotesPlugin from './main'; 4 | import { autoResizeTextArea } from './utils'; 5 | 6 | export class VoiceNotesSettingTab extends PluginSettingTab { 7 | plugin: VoiceNotesPlugin; 8 | vnApi: VoiceNotesApi; 9 | password: string; 10 | 11 | constructor(app: App, plugin: VoiceNotesPlugin) { 12 | super(app, plugin); 13 | this.plugin = plugin; 14 | this.vnApi = new VoiceNotesApi({}); 15 | } 16 | 17 | async display(): Promise { 18 | const { containerEl } = this; 19 | 20 | containerEl.empty(); 21 | 22 | if (!this.plugin.settings.token) { 23 | new Setting(containerEl).setName('Username').addText((text) => 24 | text 25 | .setPlaceholder('Email address') 26 | .setValue(this.plugin.settings.username) 27 | .onChange(async (value) => { 28 | this.plugin.settings.username = value; 29 | await this.plugin.saveSettings(); 30 | }) 31 | ); 32 | 33 | new Setting(containerEl).setName('Password').addText((text) => { 34 | text 35 | .setPlaceholder('Password') 36 | .setValue(this.plugin.settings.password) 37 | .onChange(async (value) => { 38 | this.password = value; 39 | await this.plugin.saveSettings(); 40 | }); 41 | text.inputEl.type = 'password'; 42 | return text; 43 | }); 44 | 45 | new Setting(containerEl).addButton((button) => 46 | button.setButtonText('Login').onClick(async () => { 47 | this.plugin.settings.token = await this.vnApi.login({ 48 | username: this.plugin.settings.username, 49 | password: this.password, 50 | }); 51 | 52 | this.plugin.settings.password = null; 53 | if (this.plugin.settings.token) { 54 | new Notice('Login to voicenotes.com was successful'); 55 | await this.plugin.saveSettings(); 56 | this.plugin.setupAutoSync(); 57 | await this.display(); 58 | } else { 59 | new Notice('Login to voicenotes.com was unsuccessful'); 60 | } 61 | }) 62 | ); 63 | 64 | new Setting(containerEl).setName('Auth Token').addText((text) => 65 | text 66 | .setPlaceholder('12345|abcdefghijklmnopqrstuvwxyz') 67 | .setValue(this.plugin.settings.token) 68 | .onChange(async (value) => { 69 | this.plugin.settings.token = value; 70 | await this.plugin.saveSettings(); 71 | }) 72 | ); 73 | new Setting(containerEl).addButton((button) => 74 | button.setButtonText('Login with token').onClick(async () => { 75 | this.vnApi.setToken(this.plugin.settings.token); 76 | const response = await this.vnApi.getUserInfo(); 77 | this.plugin.settings.password = null; 78 | 79 | if (response) { 80 | new Notice('Login to voicenotes.com was successful'); 81 | await this.plugin.saveSettings(); 82 | this.plugin.setupAutoSync(); 83 | await this.display(); 84 | } else { 85 | new Notice('Login to voicenotes.com was unsuccessful'); 86 | } 87 | }) 88 | ); 89 | } 90 | if (this.plugin.settings.token) { 91 | this.vnApi.setToken(this.plugin.settings.token); 92 | 93 | const userInfo = await this.vnApi.getUserInfo(); 94 | 95 | new Setting(containerEl).setName('Name').addText((text) => text.setPlaceholder(userInfo.name).setDisabled(true)); 96 | new Setting(containerEl) 97 | .setName('Email') 98 | .addText((text) => text.setPlaceholder(userInfo.email).setDisabled(true)); 99 | new Setting(containerEl).addButton((button) => 100 | button.setButtonText('Logout').onClick(async () => { 101 | new Notice('Logged out of voicenotes.com'); 102 | this.plugin.settings.token = null; 103 | this.plugin.settings.password = null; 104 | this.password = null; 105 | await this.plugin.saveSettings(); 106 | await this.display(); 107 | }) 108 | ); 109 | 110 | new Setting(containerEl) 111 | .setName('Force Sync') 112 | .setDesc( 113 | "Manual synchronization -- Prefer using the quick sync option unless you're having issues with syncing. Full synchronization will sync all notes, not just the last ten but can be much slower." 114 | ) 115 | .addButton((button) => 116 | button.setButtonText('Manual sync (quick)').onClick(async () => { 117 | new Notice('Performing manual synchronization of the last ten notes.'); 118 | await this.plugin.sync(); 119 | new Notice('Manual quick synchronization has completed.'); 120 | }) 121 | ) 122 | .addButton((button) => 123 | button.setButtonText('Manual sync (full)').onClick(async () => { 124 | new Notice('Performing manual synchronization of all notes.'); 125 | this.plugin.syncedRecordingIds = []; 126 | await this.plugin.sync(true); 127 | new Notice('Manual full synchronization has completed.'); 128 | }) 129 | ); 130 | } 131 | 132 | new Setting(containerEl) 133 | .setName('Automatic sync every') 134 | .setDesc('Number of minutes between syncing with VoiceNotes.com servers (uncheck to sync manually)') 135 | .addText((text) => { 136 | text 137 | .setDisabled(!this.plugin.settings.automaticSync) 138 | .setPlaceholder('30') 139 | .setValue(`${this.plugin.settings.syncTimeout}`) 140 | .onChange(async (value) => { 141 | const numericValue = Number(value); 142 | const inputElement = text.inputEl; 143 | 144 | if (isNaN(numericValue) || numericValue < 1) { 145 | inputElement.style.backgroundColor = 'red'; 146 | new Notice('Please enter a number greater than or equal to 1'); 147 | } else { 148 | inputElement.style.backgroundColor = ''; 149 | this.plugin.settings.syncTimeout = numericValue; 150 | await this.plugin.saveSettings(); 151 | } 152 | }); 153 | text.inputEl.type = 'number'; 154 | return text; 155 | }) 156 | .addToggle((toggle) => 157 | toggle.setValue(this.plugin.settings.automaticSync).onChange(async (value) => { 158 | this.plugin.settings.automaticSync = value; 159 | // If we've turned on automatic sync again, let's re-sync right away 160 | if (value) { 161 | await this.plugin.sync(false); 162 | } 163 | await this.plugin.saveSettings(); 164 | await this.display(); 165 | }) 166 | ); 167 | 168 | new Setting(containerEl) 169 | .setName('Sync directory') 170 | .setDesc('Directory to sync voice notes') 171 | .addText((text) => 172 | text 173 | .setPlaceholder('voicenotes') 174 | .setValue(`${this.plugin.settings.syncDirectory}`) 175 | .onChange(async (value) => { 176 | this.plugin.settings.syncDirectory = value; 177 | await this.plugin.saveSettings(); 178 | }) 179 | ); 180 | 181 | new Setting(containerEl) 182 | .setName('Add a tag to todos') 183 | .setDesc('When syncing a note add an optional tag to the todo') 184 | .addText((text) => 185 | text 186 | .setPlaceholder('TODO') 187 | .setValue(this.plugin.settings.todoTag) 188 | .onChange(async (value) => { 189 | this.plugin.settings.todoTag = value; 190 | await this.plugin.saveSettings(); 191 | }) 192 | ); 193 | 194 | new Setting(containerEl) 195 | .setName('Download audio') 196 | .setDesc('Store and download the audio associated with the transcript') 197 | .addToggle((toggle) => 198 | toggle.setValue(this.plugin.settings.downloadAudio).onChange(async (value) => { 199 | this.plugin.settings.downloadAudio = Boolean(value); 200 | await this.plugin.saveSettings(); 201 | }) 202 | ); 203 | 204 | new Setting(containerEl) 205 | .setName('Date Format') 206 | .setDesc('Format of the date used in the templates below (moment.js format)') 207 | .addText((text) => 208 | text 209 | .setPlaceholder('YYYY-MM-DD') 210 | .setValue(this.plugin.settings.dateFormat) 211 | .onChange(async (value) => { 212 | this.plugin.settings.dateFormat = value; 213 | await this.plugin.saveSettings(); 214 | }) 215 | ); 216 | 217 | new Setting(containerEl) 218 | .setName('Filename Date Format') 219 | .setDesc('Format of the date used to replace {{date}} if in Filename Template below (moment.js format)') 220 | .addText((text) => 221 | text 222 | .setPlaceholder('YYYY-MM-DD') 223 | .setValue(this.plugin.settings.filenameDateFormat) 224 | .onChange(async (value) => { 225 | this.plugin.settings.filenameDateFormat = value; 226 | await this.plugin.saveSettings(); 227 | }) 228 | ); 229 | 230 | new Setting(containerEl) 231 | .setName('Filename Template') 232 | .setDesc('Template for the filename of synced notes. Available variables: {{date}}, {{title}}') 233 | .addText((text) => 234 | text 235 | .setPlaceholder('{{date}} {{title}}') 236 | .setValue(this.plugin.settings.filenameTemplate) 237 | .onChange(async (value) => { 238 | this.plugin.settings.filenameTemplate = value; 239 | await this.plugin.saveSettings(); 240 | }) 241 | ); 242 | 243 | new Setting(containerEl) 244 | .setName('Frontmatter Template') 245 | .setDesc( 246 | 'Frontmatter / properties template for notes. recording_id and the three dashes before and after properties automatically added' 247 | ) 248 | .addTextArea((text) => { 249 | text 250 | .setPlaceholder(this.plugin.settings.frontmatterTemplate) 251 | .setValue(this.plugin.settings.frontmatterTemplate) 252 | .onChange(async (value) => { 253 | this.plugin.settings.frontmatterTemplate = value; 254 | await this.plugin.saveSettings(); 255 | }); 256 | // Add autoresize to the textarea 257 | text.inputEl.classList.add('autoresize'); 258 | autoResizeTextArea(text.inputEl); 259 | text.inputEl.addEventListener('input', () => autoResizeTextArea(text.inputEl)); 260 | containerEl.appendChild(text.inputEl); 261 | }) 262 | 263 | new Setting(containerEl) 264 | .setName('Note Template') 265 | .setDesc( 266 | 'Template for synced notes. Available variables: {{recording_id}}, {{title}}, {{date}}, {{duration}}, {{created_at}}, {{updated_at}}, {{tags}}, {{transcript}}, {{embedded_audio_link}}, {{audio_filename}}, {{summary}}, {{tidy}}, {{points}}, {{todo}}, {{email}}, {{tweet}}, {{blog}}, {{custom}}, {{parent_note}} and {{related_notes}}' 267 | ) 268 | .addTextArea((text) => { 269 | text 270 | .setPlaceholder(this.plugin.settings.noteTemplate) 271 | .setValue(this.plugin.settings.noteTemplate) 272 | .onChange(async (value) => { 273 | this.plugin.settings.noteTemplate = value; 274 | await this.plugin.saveSettings(); 275 | }); 276 | // Add autoresize to the textarea 277 | text.inputEl.classList.add('autoresize'); 278 | autoResizeTextArea(text.inputEl); 279 | text.inputEl.addEventListener('input', () => autoResizeTextArea(text.inputEl)); 280 | containerEl.appendChild(text.inputEl); 281 | }) 282 | 283 | new Setting(containerEl) 284 | .setName('Exclude Tags') 285 | .setDesc('Comma-separated list of tags to exclude from syncing') 286 | .addText((text) => 287 | text 288 | .setPlaceholder('archive, trash') 289 | .setValue(this.plugin.settings.excludeTags.join(', ')) 290 | .onChange(async (value) => { 291 | this.plugin.settings.excludeTags = value.split(',').map((folder) => folder.trim()); 292 | await this.plugin.saveSettings(); 293 | }) 294 | ); 295 | } 296 | } 297 | -------------------------------------------------------------------------------- /styles.css: -------------------------------------------------------------------------------- 1 | textarea.autoresize { 2 | display: block; 3 | width: 100%; 4 | resize: none; 5 | overflow: hidden; 6 | min-height: 100px; 7 | box-sizing: border-box; 8 | } -------------------------------------------------------------------------------- /tsconfig.json: -------------------------------------------------------------------------------- 1 | { 2 | "compilerOptions": { 3 | "allowSyntheticDefaultImports": true, 4 | "baseUrl": ".", 5 | "inlineSourceMap": true, 6 | "inlineSources": true, 7 | "module": "ESNext", 8 | "target": "es6", 9 | "allowJs": true, 10 | "noImplicitAny": true, 11 | "moduleResolution": "node", 12 | "importHelpers": true, 13 | "lib": [ 14 | "dom", 15 | "es5", 16 | "scripthost", 17 | "es2015" 18 | ] 19 | }, 20 | "include": [ 21 | "**/*.ts" 22 | ] 23 | } 24 | -------------------------------------------------------------------------------- /types.ts: -------------------------------------------------------------------------------- 1 | /* -------------------------------------------------------------------------- */ 2 | /* MAIN */ 3 | /* -------------------------------------------------------------------------- */ 4 | 5 | export interface VoiceNotesPluginSettings { 6 | token?: string; 7 | username?: string; 8 | password?: string; 9 | automaticSync: boolean; 10 | syncTimeout?: number; 11 | downloadAudio?: boolean; 12 | downloadAttachment?: boolean; 13 | syncDirectory: string; 14 | deleteSynced: boolean; 15 | reallyDeleteSynced: boolean; 16 | todoTag: string; 17 | filenameDateFormat: string; 18 | frontmatterTemplate: string; 19 | noteTemplate: string; 20 | filenameTemplate: string; 21 | excludeTags: string[]; 22 | dateFormat: string; 23 | } 24 | 25 | export interface UserSettings { 26 | about: string | null; 27 | language: string | null; 28 | remember_words: string | null; 29 | fix_punctuation: boolean; 30 | theme: string; 31 | } 32 | 33 | export interface User { 34 | id: number; 35 | name: string; 36 | email: string; 37 | photo_url: string | null; 38 | is_password_set: boolean; 39 | subscription_status: boolean; 40 | can_record_more: boolean; 41 | subscription_plan: string; 42 | subscription_gateway: string; 43 | subscription_created_at: string; 44 | latest_updated_at: string; 45 | latest_attachment_updated_at: string; 46 | recordings_count: number; 47 | public_recordings_count: number; 48 | settings: UserSettings; 49 | } 50 | 51 | /* -------------------------------------------------------------------------- */ 52 | /* VOICENOTES API */ 53 | /* -------------------------------------------------------------------------- */ 54 | 55 | export interface VoiceNoteSignedUrl { 56 | url: string; 57 | } 58 | 59 | export interface VoiceNoteRecordings { 60 | data: any[]; 61 | links: { 62 | next?: string; 63 | }; 64 | json: any; 65 | } 66 | -------------------------------------------------------------------------------- /utils.ts: -------------------------------------------------------------------------------- 1 | import { moment } from 'obsidian'; 2 | import * as crypto from 'crypto'; 3 | import { promises as fs } from 'fs'; 4 | 5 | export function capitalizeFirstLetter(word: string): string { 6 | return word[0].toUpperCase() + word.slice(1); 7 | } 8 | 9 | export function getFilenameFromUrl(url: string): string { 10 | try { 11 | const parsedUrl = new URL(url); 12 | const pathname = parsedUrl.pathname; 13 | const filename = pathname.split('/').pop(); 14 | 15 | return filename || ''; 16 | } catch (error) { 17 | console.error('Invalid URL:', error); 18 | return ''; 19 | } 20 | } 21 | 22 | export function isAlphaNumeric(value: string): boolean { 23 | const regex = /^[a-z0-9_]+$/i; 24 | return regex.test(value); 25 | } 26 | 27 | export function isToday(date: string): boolean { 28 | return moment(date).isSame(moment(), 'day'); 29 | } 30 | 31 | export async function generateChecksum(filePath: string, algorithm: string = 'sha256'): Promise { 32 | const hash = crypto.createHash(algorithm); 33 | const fileHandle = await fs.open(filePath, 'r'); 34 | const buffer = Buffer.alloc(8192); 35 | 36 | let bytesRead: number; 37 | do { 38 | const { bytesRead: readBytes } = await fileHandle.read(buffer, 0, buffer.length, null); 39 | bytesRead = readBytes; 40 | if (bytesRead > 0) { 41 | hash.update(buffer.slice(0, bytesRead)); 42 | } 43 | } while (bytesRead > 0); 44 | 45 | await fileHandle.close(); 46 | return hash.digest('hex'); 47 | } 48 | 49 | export function formatDuration(durationMs: number): string { 50 | const minutes = Math.floor(durationMs / 60000); 51 | const seconds = Math.floor((durationMs % 60000) / 1000); 52 | 53 | if (minutes > 0) { 54 | return `${minutes}m${seconds.toString().padStart(2, '0')}s`; 55 | } else { 56 | return `${seconds}s`; 57 | } 58 | } 59 | 60 | export function formatDate(date: string, dateFormat: string): string { 61 | try { 62 | return moment(date).format(dateFormat); 63 | } catch (error) { 64 | console.error('Error formatting date:', error); 65 | return date; 66 | } 67 | } 68 | 69 | export function formatTags(recording: any): string { 70 | if (recording.tags && recording.tags.length > 0) { 71 | return `tags: ${recording.tags.map((tag: { name: string }) => tag.name.replace(/\s+/g, '-')).join(',')}`; 72 | } 73 | return ''; 74 | } 75 | 76 | export function autoResizeTextArea(textarea: HTMLTextAreaElement): void { 77 | requestAnimationFrame(() => { 78 | textarea.style.height = 'auto'; 79 | textarea.style.height = `${textarea.scrollHeight}px`; 80 | }); 81 | } 82 | 83 | export function convertHtmlToMarkdown(text: string): string { 84 | const htmlEntities: { [key: string]: string } = { 85 | '<': '<', 86 | '>': '>', 87 | '&': '&', 88 | '"': '"', 89 | ''': "'", 90 | ' ': ' ', 91 | }; 92 | 93 | // Convert HTML entities 94 | let markdown = text.replace(/&[a-zA-Z0-9#]+;/g, (entity) => htmlEntities[entity] || entity); 95 | 96 | // Convert
tags to newlines 97 | markdown = markdown.replace(//gi, '\n'); 98 | 99 | // Remove other HTML tags 100 | markdown = markdown.replace(/<\/?[^>]+(>|$)/g, ''); 101 | 102 | return markdown.trim(); 103 | } 104 | -------------------------------------------------------------------------------- /version-bump.mjs: -------------------------------------------------------------------------------- 1 | import { readFileSync, writeFileSync } from "fs"; 2 | 3 | const targetVersion = process.env.npm_package_version; 4 | 5 | // read minAppVersion from manifest.json and bump version to target version 6 | let manifest = JSON.parse(readFileSync("manifest.json", "utf8")); 7 | const { minAppVersion } = manifest; 8 | manifest.version = targetVersion; 9 | writeFileSync("manifest.json", JSON.stringify(manifest, null, "\t")); 10 | 11 | // update versions.json with target version and minAppVersion from manifest.json 12 | let versions = JSON.parse(readFileSync("versions.json", "utf8")); 13 | versions[targetVersion] = minAppVersion; 14 | writeFileSync("versions.json", JSON.stringify(versions, null, "\t")); -------------------------------------------------------------------------------- /versions.json: -------------------------------------------------------------------------------- 1 | { 2 | "0.0.9": "1.5.12", 3 | "0.0.10": "1.5.12", 4 | "0.0.11": "1.5.12", 5 | "0.0.12": "1.5.12", 6 | "0.0.14": "1.5.12", 7 | "0.0.15": "1.5.12", 8 | "0.0.16": "1.5.12", 9 | "0.0.17": "1.5.12", 10 | "0.0.18": "1.5.12", 11 | "0.0.19": "1.5.12", 12 | "0.0.20": "1.5.12", 13 | "0.0.21": "1.5.12", 14 | "0.0.22": "1.5.12", 15 | "0.0.23": "1.5.12", 16 | "0.0.24": "1.5.12", 17 | "0.0.25": "1.5.12", 18 | "0.0.26": "1.5.12", 19 | "0.0.27": "1.5.12", 20 | "0.0.28": "1.5.12", 21 | "0.0.30-beta": "1.5.12", 22 | "0.0.30-beta2": "1.5.12", 23 | "0.0.30-beta3": "1.5.12" 24 | } -------------------------------------------------------------------------------- /voicenotes-api.ts: -------------------------------------------------------------------------------- 1 | import { DataAdapter, requestUrl } from 'obsidian'; 2 | import { User, VoiceNoteRecordings, VoiceNoteSignedUrl } from './types'; 3 | 4 | const VOICENOTES_API_URL = 'https://api.voicenotes.com/api'; 5 | 6 | export default class VoiceNotesApi { 7 | token!: string; 8 | 9 | constructor(options: { token?: string }) { 10 | if (options.token) { 11 | this.token = options.token; 12 | } 13 | } 14 | 15 | setToken(token: string): void { 16 | this.token = token; 17 | } 18 | 19 | async login(options: { username?: string; password?: string }): Promise { 20 | if (options.username && options.password) { 21 | const loginUrl = `${VOICENOTES_API_URL}/auth/login`; 22 | console.log(`loginUrl: ${loginUrl}`); 23 | 24 | const response = await requestUrl({ 25 | url: loginUrl, 26 | method: 'POST', 27 | contentType: 'application/json', 28 | body: JSON.stringify({ 29 | email: options.username, 30 | password: options.password, 31 | }), 32 | }); 33 | 34 | if (response.status === 200) { 35 | this.token = response.json.authorisation.token; 36 | return this.token; 37 | } 38 | return null; 39 | } 40 | return null; 41 | } 42 | 43 | async getSignedUrl(recordingId: number): Promise { 44 | if (this.token) { 45 | const data = await requestUrl({ 46 | url: `${VOICENOTES_API_URL}/recordings/${recordingId}/signed-url`, 47 | headers: { 48 | Authorization: `Bearer ${this.token}`, 49 | }, 50 | }); 51 | return data.json as VoiceNoteSignedUrl; 52 | } 53 | return null; 54 | } 55 | 56 | async downloadFile(fs: DataAdapter, url: string, outputLocationPath: string) { 57 | const response = await requestUrl({ 58 | url, 59 | }); 60 | const buffer = Buffer.from(response.arrayBuffer); 61 | 62 | await fs.writeBinary(outputLocationPath, buffer); 63 | } 64 | 65 | async deleteRecording(recordingId: number): Promise { 66 | if (this.token) { 67 | const data = await requestUrl({ 68 | url: `${VOICENOTES_API_URL}/recordings/${recordingId}`, 69 | headers: { 70 | Authorization: `Bearer ${this.token}`, 71 | }, 72 | method: 'DELETE', 73 | }); 74 | 75 | return data.status === 200; 76 | } 77 | 78 | return false; 79 | } 80 | 81 | async getRecordingsFromLink(link: string): Promise { 82 | if (this.token) { 83 | const data = await requestUrl({ 84 | url: link, 85 | headers: { 86 | Authorization: `Bearer ${this.token}`, 87 | }, 88 | }); 89 | 90 | return data.json as VoiceNoteRecordings; 91 | } 92 | return null; 93 | } 94 | 95 | async getRecordings(): Promise { 96 | if (this.token) { 97 | try { 98 | const data = await requestUrl({ 99 | url: `${VOICENOTES_API_URL}/recordings`, 100 | headers: { 101 | Authorization: `Bearer ${this.token}`, 102 | }, 103 | }); 104 | return data.json as VoiceNoteRecordings; 105 | } catch (error) { 106 | if (error.status === 401) { 107 | this.token = undefined; 108 | throw error; // rethrow so we can catch in caller 109 | } 110 | } 111 | } 112 | return null; 113 | } 114 | 115 | async getUserInfo(): Promise { 116 | if (this.token) { 117 | try { 118 | const data = await requestUrl({ 119 | url: `${VOICENOTES_API_URL}/auth/me`, 120 | headers: { 121 | Authorization: `Bearer ${this.token}`, 122 | }, 123 | }); 124 | return data.json; 125 | } catch (error) { 126 | console.error(error); 127 | } 128 | } 129 | return null; 130 | } 131 | } 132 | -------------------------------------------------------------------------------- /yarn.lock: -------------------------------------------------------------------------------- 1 | # THIS IS AN AUTOGENERATED FILE. DO NOT EDIT THIS FILE DIRECTLY. 2 | # yarn lockfile v1 3 | 4 | 5 | "@eslint-community/eslint-utils@^4.2.0", "@eslint-community/eslint-utils@^4.4.0": 6 | version "4.4.0" 7 | resolved "https://registry.yarnpkg.com/@eslint-community/eslint-utils/-/eslint-utils-4.4.0.tgz#a23514e8fb9af1269d5f7788aa556798d61c6b59" 8 | integrity sha512-1/sA4dwrzBAyeUoQ6oxahHKmrZvsnLCg4RfxW3ZFGGmQkSNQPFNLV9CUEFQP1x9EYXHTo5p6xdhZM1Ne9p/AfA== 9 | dependencies: 10 | eslint-visitor-keys "^3.3.0" 11 | 12 | "@eslint-community/regexpp@^4.10.0", "@eslint-community/regexpp@^4.6.1": 13 | version "4.11.0" 14 | resolved "https://registry.yarnpkg.com/@eslint-community/regexpp/-/regexpp-4.11.0.tgz#b0ffd0312b4a3fd2d6f77237e7248a5ad3a680ae" 15 | integrity sha512-G/M/tIiMrTAxEWRfLfQJMmGNX28IxBg4PBz8XqQhqUHLFI6TL2htpIB1iQCj144V5ee/JaKyT9/WZ0MGZWfA7A== 16 | 17 | "@eslint/eslintrc@^2.1.4": 18 | version "2.1.4" 19 | resolved "https://registry.yarnpkg.com/@eslint/eslintrc/-/eslintrc-2.1.4.tgz#388a269f0f25c1b6adc317b5a2c55714894c70ad" 20 | integrity sha512-269Z39MS6wVJtsoUl10L60WdkhJVdPG24Q4eZTH3nnF6lpvSShEK3wQjDX9JRWAUPvPh7COouPpU9IrqaZFvtQ== 21 | dependencies: 22 | ajv "^6.12.4" 23 | debug "^4.3.2" 24 | espree "^9.6.0" 25 | globals "^13.19.0" 26 | ignore "^5.2.0" 27 | import-fresh "^3.2.1" 28 | js-yaml "^4.1.0" 29 | minimatch "^3.1.2" 30 | strip-json-comments "^3.1.1" 31 | 32 | "@eslint/js@8.57.0": 33 | version "8.57.0" 34 | resolved "https://registry.yarnpkg.com/@eslint/js/-/js-8.57.0.tgz#a5417ae8427873f1dd08b70b3574b453e67b5f7f" 35 | integrity sha512-Ys+3g2TaW7gADOJzPt83SJtCDhMjndcDMFVQ/Tj9iA1BfJzFKD9mAUXT3OenpuPHbI6P/myECxRJrofUsDx/5g== 36 | 37 | "@humanwhocodes/config-array@^0.11.14": 38 | version "0.11.14" 39 | resolved "https://registry.yarnpkg.com/@humanwhocodes/config-array/-/config-array-0.11.14.tgz#d78e481a039f7566ecc9660b4ea7fe6b1fec442b" 40 | integrity sha512-3T8LkOmg45BV5FICb15QQMsyUSWrQ8AygVfC7ZG32zOalnqrilm018ZVCw0eapXux8FtA33q8PSRSstjee3jSg== 41 | dependencies: 42 | "@humanwhocodes/object-schema" "^2.0.2" 43 | debug "^4.3.1" 44 | minimatch "^3.0.5" 45 | 46 | "@humanwhocodes/module-importer@^1.0.1": 47 | version "1.0.1" 48 | resolved "https://registry.yarnpkg.com/@humanwhocodes/module-importer/-/module-importer-1.0.1.tgz#af5b2691a22b44be847b0ca81641c5fb6ad0172c" 49 | integrity sha512-bxveV4V8v5Yb4ncFTT3rPSgZBOpCkjfK0y4oVVVJwIuDVBRMDXrPyXRL988i5ap9m9bnyEEjWfm5WkBmtffLfA== 50 | 51 | "@humanwhocodes/object-schema@^2.0.2": 52 | version "2.0.3" 53 | resolved "https://registry.yarnpkg.com/@humanwhocodes/object-schema/-/object-schema-2.0.3.tgz#4a2868d75d6d6963e423bcf90b7fd1be343409d3" 54 | integrity sha512-93zYdMES/c1D69yZiKDBj0V24vqNzB/koF26KPaagAfd3P/4gUlh3Dys5ogAK+Exi9QyzlD8x/08Zt7wIKcDcA== 55 | 56 | "@isaacs/cliui@^8.0.2": 57 | version "8.0.2" 58 | resolved "https://registry.yarnpkg.com/@isaacs/cliui/-/cliui-8.0.2.tgz#b37667b7bc181c168782259bab42474fbf52b550" 59 | integrity sha512-O8jcjabXaleOG9DQ0+ARXWZBTfnP4WNAqzuiJK7ll44AmxGKv/J2M4TPjxjY3znBCfvBXFzucm1twdyFybFqEA== 60 | dependencies: 61 | string-width "^5.1.2" 62 | string-width-cjs "npm:string-width@^4.2.0" 63 | strip-ansi "^7.0.1" 64 | strip-ansi-cjs "npm:strip-ansi@^6.0.1" 65 | wrap-ansi "^8.1.0" 66 | wrap-ansi-cjs "npm:wrap-ansi@^7.0.0" 67 | 68 | "@jridgewell/sourcemap-codec@^1.4.15": 69 | version "1.4.15" 70 | resolved "https://registry.yarnpkg.com/@jridgewell/sourcemap-codec/-/sourcemap-codec-1.4.15.tgz#d7c6e6755c78567a951e04ab52ef0fd26de59f32" 71 | integrity sha512-eF2rxCRulEKXHTRiDrDy6erMYWqNw4LPdQ8UQA4huuxaQsVeRPFl2oM8oDGxMFhJUWZf9McpLtJasDDZb/Bpeg== 72 | 73 | "@nodelib/fs.scandir@2.1.5": 74 | version "2.1.5" 75 | resolved "https://registry.yarnpkg.com/@nodelib/fs.scandir/-/fs.scandir-2.1.5.tgz#7619c2eb21b25483f6d167548b4cfd5a7488c3d5" 76 | integrity sha512-vq24Bq3ym5HEQm2NKCr3yXDwjc7vTsEThRDnkp2DK9p1uqLR+DHurm/NOTo0KG7HYHU7eppKZj3MyqYuMBf62g== 77 | dependencies: 78 | "@nodelib/fs.stat" "2.0.5" 79 | run-parallel "^1.1.9" 80 | 81 | "@nodelib/fs.stat@2.0.5", "@nodelib/fs.stat@^2.0.2": 82 | version "2.0.5" 83 | resolved "https://registry.yarnpkg.com/@nodelib/fs.stat/-/fs.stat-2.0.5.tgz#5bd262af94e9d25bd1e71b05deed44876a222e8b" 84 | integrity sha512-RkhPPp2zrqDAQA/2jNhnztcPAlv64XdhIp7a7454A5ovI7Bukxgt7MX7udwAu3zg1DcpPU0rz3VV1SeaqvY4+A== 85 | 86 | "@nodelib/fs.walk@^1.2.3", "@nodelib/fs.walk@^1.2.8": 87 | version "1.2.8" 88 | resolved "https://registry.yarnpkg.com/@nodelib/fs.walk/-/fs.walk-1.2.8.tgz#e95737e8bb6746ddedf69c556953494f196fe69a" 89 | integrity sha512-oGB+UxlgWcgQkgwo8GcEGwemoTFt3FIO9ababBmaGwXIoBKZ+GTy0pP185beGg7Llih/NSHSV2XAs1lnznocSg== 90 | dependencies: 91 | "@nodelib/fs.scandir" "2.1.5" 92 | fastq "^1.6.0" 93 | 94 | "@pkgjs/parseargs@^0.11.0": 95 | version "0.11.0" 96 | resolved "https://registry.yarnpkg.com/@pkgjs/parseargs/-/parseargs-0.11.0.tgz#a77ea742fab25775145434eb1d2328cf5013ac33" 97 | integrity sha512-+1VkjdD0QBLPodGrJUeqarH8VAIvQODIbwh9XpP5Syisf7YoQgsJKPNFoqqLQlu+VQ/tVSshMR6loPMn8U+dPg== 98 | 99 | "@pkgr/core@^0.1.0": 100 | version "0.1.1" 101 | resolved "https://registry.yarnpkg.com/@pkgr/core/-/core-0.1.1.tgz#1ec17e2edbec25c8306d424ecfbf13c7de1aaa31" 102 | integrity sha512-cq8o4cWH0ibXh9VGi5P20Tu9XF/0fFXl9EUinr9QfTM7a7p0oTA4iJRCQWppXR1Pg8dSM0UCItCkPwsk9qWWYA== 103 | 104 | "@rollup/plugin-commonjs@^26.0.1": 105 | version "26.0.1" 106 | resolved "https://registry.yarnpkg.com/@rollup/plugin-commonjs/-/plugin-commonjs-26.0.1.tgz#16d4d6e54fa63021249a292b50f27c0b0f1a30d8" 107 | integrity sha512-UnsKoZK6/aGIH6AdkptXhNvhaqftcjq3zZdT+LY5Ftms6JR06nADcDsYp5hTU9E2lbJUEOhdlY5J4DNTneM+jQ== 108 | dependencies: 109 | "@rollup/pluginutils" "^5.0.1" 110 | commondir "^1.0.1" 111 | estree-walker "^2.0.2" 112 | glob "^10.4.1" 113 | is-reference "1.2.1" 114 | magic-string "^0.30.3" 115 | 116 | "@rollup/plugin-node-resolve@^15.2.3": 117 | version "15.2.3" 118 | resolved "https://registry.yarnpkg.com/@rollup/plugin-node-resolve/-/plugin-node-resolve-15.2.3.tgz#e5e0b059bd85ca57489492f295ce88c2d4b0daf9" 119 | integrity sha512-j/lym8nf5E21LwBT4Df1VD6hRO2L2iwUeUmP7litikRsVp1H6NWx20NEp0Y7su+7XGc476GnXXc4kFeZNGmaSQ== 120 | dependencies: 121 | "@rollup/pluginutils" "^5.0.1" 122 | "@types/resolve" "1.20.2" 123 | deepmerge "^4.2.2" 124 | is-builtin-module "^3.2.1" 125 | is-module "^1.0.0" 126 | resolve "^1.22.1" 127 | 128 | "@rollup/plugin-typescript@^11.1.6": 129 | version "11.1.6" 130 | resolved "https://registry.yarnpkg.com/@rollup/plugin-typescript/-/plugin-typescript-11.1.6.tgz#724237d5ec12609ec01429f619d2a3e7d4d1b22b" 131 | integrity sha512-R92yOmIACgYdJ7dJ97p4K69I8gg6IEHt8M7dUBxN3W6nrO8uUxX5ixl0yU/N3aZTi8WhPuICvOHXQvF6FaykAA== 132 | dependencies: 133 | "@rollup/pluginutils" "^5.1.0" 134 | resolve "^1.22.1" 135 | 136 | "@rollup/pluginutils@^5.0.1", "@rollup/pluginutils@^5.1.0": 137 | version "5.1.0" 138 | resolved "https://registry.yarnpkg.com/@rollup/pluginutils/-/pluginutils-5.1.0.tgz#7e53eddc8c7f483a4ad0b94afb1f7f5fd3c771e0" 139 | integrity sha512-XTIWOPPcpvyKI6L1NHo0lFlCyznUEyPmPY1mc3KpPVDYulHSTvyeLNVW00QTLIAFNhR3kYnJTQHeGqU4M3n09g== 140 | dependencies: 141 | "@types/estree" "^1.0.0" 142 | estree-walker "^2.0.2" 143 | picomatch "^2.3.1" 144 | 145 | "@rollup/rollup-android-arm-eabi@4.20.0": 146 | version "4.20.0" 147 | resolved "https://registry.yarnpkg.com/@rollup/rollup-android-arm-eabi/-/rollup-android-arm-eabi-4.20.0.tgz#c3f5660f67030c493a981ac1d34ee9dfe1d8ec0f" 148 | integrity sha512-TSpWzflCc4VGAUJZlPpgAJE1+V60MePDQnBd7PPkpuEmOy8i87aL6tinFGKBFKuEDikYpig72QzdT3QPYIi+oA== 149 | 150 | "@rollup/rollup-android-arm64@4.20.0": 151 | version "4.20.0" 152 | resolved "https://registry.yarnpkg.com/@rollup/rollup-android-arm64/-/rollup-android-arm64-4.20.0.tgz#64161f0b67050023a3859e723570af54a82cff5c" 153 | integrity sha512-u00Ro/nok7oGzVuh/FMYfNoGqxU5CPWz1mxV85S2w9LxHR8OoMQBuSk+3BKVIDYgkpeOET5yXkx90OYFc+ytpQ== 154 | 155 | "@rollup/rollup-darwin-arm64@4.20.0": 156 | version "4.20.0" 157 | resolved "https://registry.yarnpkg.com/@rollup/rollup-darwin-arm64/-/rollup-darwin-arm64-4.20.0.tgz#25f3d57b1da433097cfebc89341b355901615763" 158 | integrity sha512-uFVfvzvsdGtlSLuL0ZlvPJvl6ZmrH4CBwLGEFPe7hUmf7htGAN+aXo43R/V6LATyxlKVC/m6UsLb7jbG+LG39Q== 159 | 160 | "@rollup/rollup-darwin-x64@4.20.0": 161 | version "4.20.0" 162 | resolved "https://registry.yarnpkg.com/@rollup/rollup-darwin-x64/-/rollup-darwin-x64-4.20.0.tgz#d8ddaffb636cc2f59222c50316e27771e48966df" 163 | integrity sha512-xbrMDdlev53vNXexEa6l0LffojxhqDTBeL+VUxuuIXys4x6xyvbKq5XqTXBCEUA8ty8iEJblHvFaWRJTk/icAQ== 164 | 165 | "@rollup/rollup-linux-arm-gnueabihf@4.20.0": 166 | version "4.20.0" 167 | resolved "https://registry.yarnpkg.com/@rollup/rollup-linux-arm-gnueabihf/-/rollup-linux-arm-gnueabihf-4.20.0.tgz#41bd4fcffa20fb84f3dbac6c5071638f46151885" 168 | integrity sha512-jMYvxZwGmoHFBTbr12Xc6wOdc2xA5tF5F2q6t7Rcfab68TT0n+r7dgawD4qhPEvasDsVpQi+MgDzj2faOLsZjA== 169 | 170 | "@rollup/rollup-linux-arm-musleabihf@4.20.0": 171 | version "4.20.0" 172 | resolved "https://registry.yarnpkg.com/@rollup/rollup-linux-arm-musleabihf/-/rollup-linux-arm-musleabihf-4.20.0.tgz#842077c5113a747eb5686f19f2f18c33ecc0acc8" 173 | integrity sha512-1asSTl4HKuIHIB1GcdFHNNZhxAYEdqML/MW4QmPS4G0ivbEcBr1JKlFLKsIRqjSwOBkdItn3/ZDlyvZ/N6KPlw== 174 | 175 | "@rollup/rollup-linux-arm64-gnu@4.20.0": 176 | version "4.20.0" 177 | resolved "https://registry.yarnpkg.com/@rollup/rollup-linux-arm64-gnu/-/rollup-linux-arm64-gnu-4.20.0.tgz#65d1d5b6778848f55b7823958044bf3e8737e5b7" 178 | integrity sha512-COBb8Bkx56KldOYJfMf6wKeYJrtJ9vEgBRAOkfw6Ens0tnmzPqvlpjZiLgkhg6cA3DGzCmLmmd319pmHvKWWlQ== 179 | 180 | "@rollup/rollup-linux-arm64-musl@4.20.0": 181 | version "4.20.0" 182 | resolved "https://registry.yarnpkg.com/@rollup/rollup-linux-arm64-musl/-/rollup-linux-arm64-musl-4.20.0.tgz#50eef7d6e24d0fe3332200bb666cad2be8afcf86" 183 | integrity sha512-+it+mBSyMslVQa8wSPvBx53fYuZK/oLTu5RJoXogjk6x7Q7sz1GNRsXWjn6SwyJm8E/oMjNVwPhmNdIjwP135Q== 184 | 185 | "@rollup/rollup-linux-powerpc64le-gnu@4.20.0": 186 | version "4.20.0" 187 | resolved "https://registry.yarnpkg.com/@rollup/rollup-linux-powerpc64le-gnu/-/rollup-linux-powerpc64le-gnu-4.20.0.tgz#8837e858f53c84607f05ad0602943e96d104c6b4" 188 | integrity sha512-yAMvqhPfGKsAxHN8I4+jE0CpLWD8cv4z7CK7BMmhjDuz606Q2tFKkWRY8bHR9JQXYcoLfopo5TTqzxgPUjUMfw== 189 | 190 | "@rollup/rollup-linux-riscv64-gnu@4.20.0": 191 | version "4.20.0" 192 | resolved "https://registry.yarnpkg.com/@rollup/rollup-linux-riscv64-gnu/-/rollup-linux-riscv64-gnu-4.20.0.tgz#c894ade2300caa447757ddf45787cca246e816a4" 193 | integrity sha512-qmuxFpfmi/2SUkAw95TtNq/w/I7Gpjurx609OOOV7U4vhvUhBcftcmXwl3rqAek+ADBwSjIC4IVNLiszoj3dPA== 194 | 195 | "@rollup/rollup-linux-s390x-gnu@4.20.0": 196 | version "4.20.0" 197 | resolved "https://registry.yarnpkg.com/@rollup/rollup-linux-s390x-gnu/-/rollup-linux-s390x-gnu-4.20.0.tgz#5841e5390d4c82dd5cdf7b2c95a830e3c2f47dd3" 198 | integrity sha512-I0BtGXddHSHjV1mqTNkgUZLnS3WtsqebAXv11D5BZE/gfw5KoyXSAXVqyJximQXNvNzUo4GKlCK/dIwXlz+jlg== 199 | 200 | "@rollup/rollup-linux-x64-gnu@4.20.0": 201 | version "4.20.0" 202 | resolved "https://registry.yarnpkg.com/@rollup/rollup-linux-x64-gnu/-/rollup-linux-x64-gnu-4.20.0.tgz#cc1f26398bf777807a99226dc13f47eb0f6c720d" 203 | integrity sha512-y+eoL2I3iphUg9tN9GB6ku1FA8kOfmF4oUEWhztDJ4KXJy1agk/9+pejOuZkNFhRwHAOxMsBPLbXPd6mJiCwew== 204 | 205 | "@rollup/rollup-linux-x64-musl@4.20.0": 206 | version "4.20.0" 207 | resolved "https://registry.yarnpkg.com/@rollup/rollup-linux-x64-musl/-/rollup-linux-x64-musl-4.20.0.tgz#1507465d9056e0502a590d4c1a00b4d7b1fda370" 208 | integrity sha512-hM3nhW40kBNYUkZb/r9k2FKK+/MnKglX7UYd4ZUy5DJs8/sMsIbqWK2piZtVGE3kcXVNj3B2IrUYROJMMCikNg== 209 | 210 | "@rollup/rollup-win32-arm64-msvc@4.20.0": 211 | version "4.20.0" 212 | resolved "https://registry.yarnpkg.com/@rollup/rollup-win32-arm64-msvc/-/rollup-win32-arm64-msvc-4.20.0.tgz#86a221f01a2c248104dd0defb4da119f2a73642e" 213 | integrity sha512-psegMvP+Ik/Bg7QRJbv8w8PAytPA7Uo8fpFjXyCRHWm6Nt42L+JtoqH8eDQ5hRP7/XW2UiIriy1Z46jf0Oa1kA== 214 | 215 | "@rollup/rollup-win32-ia32-msvc@4.20.0": 216 | version "4.20.0" 217 | resolved "https://registry.yarnpkg.com/@rollup/rollup-win32-ia32-msvc/-/rollup-win32-ia32-msvc-4.20.0.tgz#8bc8f77e02760aa664694b4286d6fbea7f1331c5" 218 | integrity sha512-GabekH3w4lgAJpVxkk7hUzUf2hICSQO0a/BLFA11/RMxQT92MabKAqyubzDZmMOC/hcJNlc+rrypzNzYl4Dx7A== 219 | 220 | "@rollup/rollup-win32-x64-msvc@4.20.0": 221 | version "4.20.0" 222 | resolved "https://registry.yarnpkg.com/@rollup/rollup-win32-x64-msvc/-/rollup-win32-x64-msvc-4.20.0.tgz#601fffee719a1e8447f908aca97864eec23b2784" 223 | integrity sha512-aJ1EJSuTdGnM6qbVC4B5DSmozPTqIag9fSzXRNNo+humQLG89XpPgdt16Ia56ORD7s+H8Pmyx44uczDQ0yDzpg== 224 | 225 | "@types/codemirror@5.60.8": 226 | version "5.60.8" 227 | resolved "https://registry.yarnpkg.com/@types/codemirror/-/codemirror-5.60.8.tgz#b647d04b470e8e1836dd84b2879988fc55c9de68" 228 | integrity sha512-VjFgDF/eB+Aklcy15TtOTLQeMjTo07k7KAjql8OK5Dirr7a6sJY4T1uVBDuTVG9VEmn1uUsohOpYnVfgC6/jyw== 229 | dependencies: 230 | "@types/tern" "*" 231 | 232 | "@types/estree@*": 233 | version "0.0.50" 234 | resolved "https://registry.yarnpkg.com/@types/estree/-/estree-0.0.50.tgz#1e0caa9364d3fccd2931c3ed96fdbeaa5d4cca83" 235 | integrity sha512-C6N5s2ZFtuZRj54k2/zyRhNDjJwwcViAM3Nbm8zjBpbqAdZ00mr0CFxvSKeO8Y/e03WVFLpQMdHYVfUd6SB+Hw== 236 | 237 | "@types/estree@1.0.5", "@types/estree@^1.0.0": 238 | version "1.0.5" 239 | resolved "https://registry.yarnpkg.com/@types/estree/-/estree-1.0.5.tgz#a6ce3e556e00fd9895dd872dd172ad0d4bd687f4" 240 | integrity sha512-/kYRxGDLWzHOB7q+wtSUQlFrtcdUccpfy+X+9iMBpHK8QLLhx2wIPYuS5DYtR9Wa/YlZAbIovy7qVdB1Aq6Lyw== 241 | 242 | "@types/moment@2.13.0": 243 | version "2.13.0" 244 | resolved "https://registry.yarnpkg.com/@types/moment/-/moment-2.13.0.tgz#604ebd189bc3bc34a1548689404e61a2a4aac896" 245 | integrity sha1-YE69GJvDvDShVIaJQE5hoqSqyJY= 246 | dependencies: 247 | moment "*" 248 | 249 | "@types/node@^22.1.0": 250 | version "22.1.0" 251 | resolved "https://registry.yarnpkg.com/@types/node/-/node-22.1.0.tgz#6d6adc648b5e03f0e83c78dc788c2b037d0ad94b" 252 | integrity sha512-AOmuRF0R2/5j1knA3c6G3HOk523Ga+l+ZXltX8SF1+5oqcXijjfTd8fY3XRZqSihEu9XhtQnKYLmkFaoxgsJHw== 253 | dependencies: 254 | undici-types "~6.13.0" 255 | 256 | "@types/numeral@^2.0.5": 257 | version "2.0.5" 258 | resolved "https://registry.yarnpkg.com/@types/numeral/-/numeral-2.0.5.tgz#388e5c4ff4b0e1787f130753cbbe83d3ba770858" 259 | integrity sha512-kH8I7OSSwQu9DS9JYdFWbuvhVzvFRoCPCkGxNwoGgaPeDfEPJlcxNvEOypZhQ3XXHsGbfIuYcxcJxKUfJHnRfw== 260 | 261 | "@types/resolve@1.20.2": 262 | version "1.20.2" 263 | resolved "https://registry.yarnpkg.com/@types/resolve/-/resolve-1.20.2.tgz#97d26e00cd4a0423b4af620abecf3e6f442b7975" 264 | integrity sha512-60BCwRFOZCQhDncwQdxxeOEEkbc5dIMccYLwbxsS4TUNeVECQ/pBJ0j09mrHOl/JJvpRPGwO9SvE4nR2Nb/a4Q== 265 | 266 | "@types/tern@*": 267 | version "0.23.4" 268 | resolved "https://registry.yarnpkg.com/@types/tern/-/tern-0.23.4.tgz#03926eb13dbeaf3ae0d390caf706b2643a0127fb" 269 | integrity sha512-JAUw1iXGO1qaWwEOzxTKJZ/5JxVeON9kvGZ/osgZaJImBnyjyn0cjovPsf6FNLmyGY8Vw9DoXZCMlfMkMwHRWg== 270 | dependencies: 271 | "@types/estree" "*" 272 | 273 | "@typescript-eslint/eslint-plugin@^8.0.1": 274 | version "8.0.1" 275 | resolved "https://registry.yarnpkg.com/@typescript-eslint/eslint-plugin/-/eslint-plugin-8.0.1.tgz#5dbd1b498fdea83a16d292322d27d293ce156f94" 276 | integrity sha512-5g3Y7GDFsJAnY4Yhvk8sZtFfV6YNF2caLzjrRPUBzewjPCaj0yokePB4LJSobyCzGMzjZZYFbwuzbfDHlimXbQ== 277 | dependencies: 278 | "@eslint-community/regexpp" "^4.10.0" 279 | "@typescript-eslint/scope-manager" "8.0.1" 280 | "@typescript-eslint/type-utils" "8.0.1" 281 | "@typescript-eslint/utils" "8.0.1" 282 | "@typescript-eslint/visitor-keys" "8.0.1" 283 | graphemer "^1.4.0" 284 | ignore "^5.3.1" 285 | natural-compare "^1.4.0" 286 | ts-api-utils "^1.3.0" 287 | 288 | "@typescript-eslint/parser@^8.0.1": 289 | version "8.0.1" 290 | resolved "https://registry.yarnpkg.com/@typescript-eslint/parser/-/parser-8.0.1.tgz#eb0728147a3a79edf43dde84c797f117213bbfdb" 291 | integrity sha512-5IgYJ9EO/12pOUwiBKFkpU7rS3IU21mtXzB81TNwq2xEybcmAZrE9qwDtsb5uQd9aVO9o0fdabFyAmKveXyujg== 292 | dependencies: 293 | "@typescript-eslint/scope-manager" "8.0.1" 294 | "@typescript-eslint/types" "8.0.1" 295 | "@typescript-eslint/typescript-estree" "8.0.1" 296 | "@typescript-eslint/visitor-keys" "8.0.1" 297 | debug "^4.3.4" 298 | 299 | "@typescript-eslint/scope-manager@8.0.1": 300 | version "8.0.1" 301 | resolved "https://registry.yarnpkg.com/@typescript-eslint/scope-manager/-/scope-manager-8.0.1.tgz#544259c29e1ebf65d30b6e99a9f420d98795a54e" 302 | integrity sha512-NpixInP5dm7uukMiRyiHjRKkom5RIFA4dfiHvalanD2cF0CLUuQqxfg8PtEUo9yqJI2bBhF+pcSafqnG3UBnRQ== 303 | dependencies: 304 | "@typescript-eslint/types" "8.0.1" 305 | "@typescript-eslint/visitor-keys" "8.0.1" 306 | 307 | "@typescript-eslint/type-utils@8.0.1": 308 | version "8.0.1" 309 | resolved "https://registry.yarnpkg.com/@typescript-eslint/type-utils/-/type-utils-8.0.1.tgz#a613ee2dfeed4a9781300b5d326ec7cf946eed92" 310 | integrity sha512-+/UT25MWvXeDX9YaHv1IS6KI1fiuTto43WprE7pgSMswHbn1Jm9GEM4Txp+X74ifOWV8emu2AWcbLhpJAvD5Ng== 311 | dependencies: 312 | "@typescript-eslint/typescript-estree" "8.0.1" 313 | "@typescript-eslint/utils" "8.0.1" 314 | debug "^4.3.4" 315 | ts-api-utils "^1.3.0" 316 | 317 | "@typescript-eslint/types@8.0.1": 318 | version "8.0.1" 319 | resolved "https://registry.yarnpkg.com/@typescript-eslint/types/-/types-8.0.1.tgz#333e2f4c158952dbc8181a4ddcc6e49898a28918" 320 | integrity sha512-PpqTVT3yCA/bIgJ12czBuE3iBlM3g4inRSC5J0QOdQFAn07TYrYEQBBKgXH1lQpglup+Zy6c1fxuwTk4MTNKIw== 321 | 322 | "@typescript-eslint/typescript-estree@8.0.1": 323 | version "8.0.1" 324 | resolved "https://registry.yarnpkg.com/@typescript-eslint/typescript-estree/-/typescript-estree-8.0.1.tgz#64575ec7b77aedfe497acdfb2779ec942bb8d866" 325 | integrity sha512-8V9hriRvZQXPWU3bbiUV4Epo7EvgM6RTs+sUmxp5G//dBGy402S7Fx0W0QkB2fb4obCF8SInoUzvTYtc3bkb5w== 326 | dependencies: 327 | "@typescript-eslint/types" "8.0.1" 328 | "@typescript-eslint/visitor-keys" "8.0.1" 329 | debug "^4.3.4" 330 | globby "^11.1.0" 331 | is-glob "^4.0.3" 332 | minimatch "^9.0.4" 333 | semver "^7.6.0" 334 | ts-api-utils "^1.3.0" 335 | 336 | "@typescript-eslint/utils@8.0.1": 337 | version "8.0.1" 338 | resolved "https://registry.yarnpkg.com/@typescript-eslint/utils/-/utils-8.0.1.tgz#b48e3320c4f9011f97d25e0588b8c143adc38d2a" 339 | integrity sha512-CBFR0G0sCt0+fzfnKaciu9IBsKvEKYwN9UZ+eeogK1fYHg4Qxk1yf/wLQkLXlq8wbU2dFlgAesxt8Gi76E8RTA== 340 | dependencies: 341 | "@eslint-community/eslint-utils" "^4.4.0" 342 | "@typescript-eslint/scope-manager" "8.0.1" 343 | "@typescript-eslint/types" "8.0.1" 344 | "@typescript-eslint/typescript-estree" "8.0.1" 345 | 346 | "@typescript-eslint/visitor-keys@8.0.1": 347 | version "8.0.1" 348 | resolved "https://registry.yarnpkg.com/@typescript-eslint/visitor-keys/-/visitor-keys-8.0.1.tgz#e5816803b4dad1de5e97f00df8dc15d0bcb49778" 349 | integrity sha512-W5E+o0UfUcK5EgchLZsyVWqARmsM7v54/qEq6PY3YI5arkgmCzHiuk0zKSJJbm71V0xdRna4BGomkCTXz2/LkQ== 350 | dependencies: 351 | "@typescript-eslint/types" "8.0.1" 352 | eslint-visitor-keys "^3.4.3" 353 | 354 | "@ungap/structured-clone@^1.2.0": 355 | version "1.2.0" 356 | resolved "https://registry.yarnpkg.com/@ungap/structured-clone/-/structured-clone-1.2.0.tgz#756641adb587851b5ccb3e095daf27ae581c8406" 357 | integrity sha512-zuVdFrMJiuCDQUMCzQaD6KL28MjnqqN8XnAqiEq9PNm/hCPTSGfrXCOfwj1ow4LFb/tNymJPwsNbVePc1xFqrQ== 358 | 359 | acorn-jsx@^5.3.2: 360 | version "5.3.2" 361 | resolved "https://registry.yarnpkg.com/acorn-jsx/-/acorn-jsx-5.3.2.tgz#7ed5bb55908b3b2f1bc55c6af1653bada7f07937" 362 | integrity sha512-rq9s+JNhf0IChjtDXxllJ7g41oZk5SlXtp0LHwyA5cejwn7vKmKp4pPri6YEePv2PU65sAsegbXtIinmDFDXgQ== 363 | 364 | acorn@^8.9.0: 365 | version "8.12.1" 366 | resolved "https://registry.yarnpkg.com/acorn/-/acorn-8.12.1.tgz#71616bdccbe25e27a54439e0046e89ca76df2248" 367 | integrity sha512-tcpGyI9zbizT9JbV6oYE477V6mTlXvvi0T0G3SNIYE2apm/G5huBa1+K89VGeovbg+jycCrfhl3ADxErOuO6Jg== 368 | 369 | ajv@^6.12.4: 370 | version "6.12.6" 371 | resolved "https://registry.yarnpkg.com/ajv/-/ajv-6.12.6.tgz#baf5a62e802b07d977034586f8c3baf5adf26df4" 372 | integrity sha512-j3fVLgvTo527anyYyJOGTYJbG+vnnQYvE0m5mmkc1TK+nxAppkCLMIL0aZ4dblVCNoGShhm+kzE4ZUykBoMg4g== 373 | dependencies: 374 | fast-deep-equal "^3.1.1" 375 | fast-json-stable-stringify "^2.0.0" 376 | json-schema-traverse "^0.4.1" 377 | uri-js "^4.2.2" 378 | 379 | ansi-regex@^5.0.1: 380 | version "5.0.1" 381 | resolved "https://registry.yarnpkg.com/ansi-regex/-/ansi-regex-5.0.1.tgz#082cb2c89c9fe8659a311a53bd6a4dc5301db304" 382 | integrity sha512-quJQXlTSUGL2LH9SUXo8VwsY4soanhgo6LNSm84E1LBcE8s3O0wpdiRzyR9z/ZZJMlMWv37qOOb9pdJlMUEKFQ== 383 | 384 | ansi-regex@^6.0.1: 385 | version "6.0.1" 386 | resolved "https://registry.yarnpkg.com/ansi-regex/-/ansi-regex-6.0.1.tgz#3183e38fae9a65d7cb5e53945cd5897d0260a06a" 387 | integrity sha512-n5M855fKb2SsfMIiFFoVrABHJC8QtHwVx+mHWP3QcEqBHYienj5dHSgjbxtC0WEZXYt4wcD6zrQElDPhFuZgfA== 388 | 389 | ansi-styles@^4.0.0, ansi-styles@^4.1.0: 390 | version "4.3.0" 391 | resolved "https://registry.yarnpkg.com/ansi-styles/-/ansi-styles-4.3.0.tgz#edd803628ae71c04c85ae7a0906edad34b648937" 392 | integrity sha512-zbB9rCJAT1rbjiVDb2hqKFHNYLxgtk8NURxZ3IZwD3F6NtxbXZQCnnSi1Lkx+IDohdPlFp222wVALIheZJQSEg== 393 | dependencies: 394 | color-convert "^2.0.1" 395 | 396 | ansi-styles@^6.1.0: 397 | version "6.2.1" 398 | resolved "https://registry.yarnpkg.com/ansi-styles/-/ansi-styles-6.2.1.tgz#0e62320cf99c21afff3b3012192546aacbfb05c5" 399 | integrity sha512-bN798gFfQX+viw3R7yrGWRqnrN2oRkEkUjjl4JNn4E8GxxbjtG3FbrEIIY3l8/hrwUwIeCZvi4QuOTP4MErVug== 400 | 401 | argparse@^2.0.1: 402 | version "2.0.1" 403 | resolved "https://registry.yarnpkg.com/argparse/-/argparse-2.0.1.tgz#246f50f3ca78a3240f6c997e8a9bd1eac49e4b38" 404 | integrity sha512-8+9WqebbFzpX9OR+Wa6O29asIogeRMzcGtAINdpMHHyAg10f05aSFVBbcEqGf/PXw1EjAZ+q2/bEBg3DvurK3Q== 405 | 406 | array-union@^2.1.0: 407 | version "2.1.0" 408 | resolved "https://registry.yarnpkg.com/array-union/-/array-union-2.1.0.tgz#b798420adbeb1de828d84acd8a2e23d3efe85e8d" 409 | integrity sha512-HGyxoOTYUyCM6stUe6EJgnd4EoewAI7zMdfqO+kGjnlZmBDz/cR5pf8r/cR4Wq60sL/p0IkcjUEEPwS3GFrIyw== 410 | 411 | balanced-match@^1.0.0: 412 | version "1.0.2" 413 | resolved "https://registry.yarnpkg.com/balanced-match/-/balanced-match-1.0.2.tgz#e83e3a7e3f300b34cb9d87f615fa0cbf357690ee" 414 | integrity sha512-3oSeUO0TMV67hN1AmbXsK4yaqU7tjiHlbxRDZOpH0KW9+CeX4bRAaX0Anxt0tx2MrpRpWwQaPwIlISEJhYU5Pw== 415 | 416 | brace-expansion@^1.1.7: 417 | version "1.1.11" 418 | resolved "https://registry.yarnpkg.com/brace-expansion/-/brace-expansion-1.1.11.tgz#3c7fcbf529d87226f3d2f52b966ff5271eb441dd" 419 | integrity sha512-iCuPHDFgrHX7H2vEI/5xpz07zSHB00TpugqhmYtVmMO6518mCuRMoOYFldEBl0g187ufozdaHgWKcYFb61qGiA== 420 | dependencies: 421 | balanced-match "^1.0.0" 422 | concat-map "0.0.1" 423 | 424 | brace-expansion@^2.0.1: 425 | version "2.0.1" 426 | resolved "https://registry.yarnpkg.com/brace-expansion/-/brace-expansion-2.0.1.tgz#1edc459e0f0c548486ecf9fc99f2221364b9a0ae" 427 | integrity sha512-XnAIvQ8eM+kC6aULx6wuQiwVsnzsi9d3WxzV3FpWTGA19F621kwdbsAcFKXgKUHZWsy+mY6iL1sHTxWEFCytDA== 428 | dependencies: 429 | balanced-match "^1.0.0" 430 | 431 | braces@^3.0.3: 432 | version "3.0.3" 433 | resolved "https://registry.yarnpkg.com/braces/-/braces-3.0.3.tgz#490332f40919452272d55a8480adc0c441358789" 434 | integrity sha512-yQbXgO/OSZVD2IsiLlro+7Hf6Q18EJrKSEsdoMzKePKXct3gvD8oLcOQdIzGupr5Fj+EDe8gO/lxc1BzfMpxvA== 435 | dependencies: 436 | fill-range "^7.1.1" 437 | 438 | builtin-modules@^3.3.0: 439 | version "3.3.0" 440 | resolved "https://registry.yarnpkg.com/builtin-modules/-/builtin-modules-3.3.0.tgz#cae62812b89801e9656336e46223e030386be7b6" 441 | integrity sha512-zhaCDicdLuWN5UbN5IMnFqNMhNfo919sH85y2/ea+5Yg9TsTkeZxpL+JLbp6cgYFS4sRLp3YV4S6yDuqVWHYOw== 442 | 443 | callsites@^3.0.0: 444 | version "3.1.0" 445 | resolved "https://registry.yarnpkg.com/callsites/-/callsites-3.1.0.tgz#b3630abd8943432f54b3f0519238e33cd7df2f73" 446 | integrity sha512-P8BjAsXvZS+VIDUI11hHCQEv74YT67YUi5JJFNWIqL235sBmjX4+qx9Muvls5ivyNENctx46xQLQ3aTuE7ssaQ== 447 | 448 | chalk@^4.0.0: 449 | version "4.1.2" 450 | resolved "https://registry.yarnpkg.com/chalk/-/chalk-4.1.2.tgz#aac4e2b7734a740867aeb16bf02aad556a1e7a01" 451 | integrity sha512-oKnbhFyRIXpUuez8iBMmyEa4nbj4IOQyuhc/wy9kY7/WVPcwIO9VA668Pu8RkO7+0G76SLROeyw9CpQ061i4mA== 452 | dependencies: 453 | ansi-styles "^4.1.0" 454 | supports-color "^7.1.0" 455 | 456 | color-convert@^2.0.1: 457 | version "2.0.1" 458 | resolved "https://registry.yarnpkg.com/color-convert/-/color-convert-2.0.1.tgz#72d3a68d598c9bdb3af2ad1e84f21d896abd4de3" 459 | integrity sha512-RRECPsj7iu/xb5oKYcsFHSppFNnsj/52OVTRKb4zP5onXwVF3zVmmToNcOfGC+CRDpfK/U584fMg38ZHCaElKQ== 460 | dependencies: 461 | color-name "~1.1.4" 462 | 463 | color-name@~1.1.4: 464 | version "1.1.4" 465 | resolved "https://registry.yarnpkg.com/color-name/-/color-name-1.1.4.tgz#c2a09a87acbde69543de6f63fa3995c826c536a2" 466 | integrity sha512-dOy+3AuW3a2wNbZHIuMZpTcgjGuLU/uBL/ubcZF9OXbDo8ff4O8yVp5Bf0efS8uEoYo5q4Fx7dY9OgQGXgAsQA== 467 | 468 | commondir@^1.0.1: 469 | version "1.0.1" 470 | resolved "https://registry.yarnpkg.com/commondir/-/commondir-1.0.1.tgz#ddd800da0c66127393cca5950ea968a3aaf1253b" 471 | integrity sha1-3dgA2gxmEnOTzKWVDqloo6rxJTs= 472 | 473 | concat-map@0.0.1: 474 | version "0.0.1" 475 | resolved "https://registry.yarnpkg.com/concat-map/-/concat-map-0.0.1.tgz#d8a96bd77fd68df7793a73036a3ba0d5405d477b" 476 | integrity sha512-/Srv4dswyQNBfohGpz9o6Yb3Gz3SrUDqBH5rTuhGR7ahtlbYKnVxw2bCFMRljaA7EXHaXZ8wsHdodFvbkhKmqg== 477 | 478 | cross-spawn@^7.0.0, cross-spawn@^7.0.2: 479 | version "7.0.3" 480 | resolved "https://registry.yarnpkg.com/cross-spawn/-/cross-spawn-7.0.3.tgz#f73a85b9d5d41d045551c177e2882d4ac85728a6" 481 | integrity sha512-iRDPJKUPVEND7dHPO8rkbOnPpyDygcDFtWjpeWNCgy8WP2rXcxXL8TskReQl6OrB2G7+UJrags1q15Fudc7G6w== 482 | dependencies: 483 | path-key "^3.1.0" 484 | shebang-command "^2.0.0" 485 | which "^2.0.1" 486 | 487 | debug@^4.3.1, debug@^4.3.2, debug@^4.3.4: 488 | version "4.3.6" 489 | resolved "https://registry.yarnpkg.com/debug/-/debug-4.3.6.tgz#2ab2c38fbaffebf8aa95fdfe6d88438c7a13c52b" 490 | integrity sha512-O/09Bd4Z1fBrU4VzkhFqVgpPzaGbw6Sm9FEkBT1A/YBXQFGuuSxa1dN2nxgxS34JmKXqYx8CZAwEVoJFImUXIg== 491 | dependencies: 492 | ms "2.1.2" 493 | 494 | deep-is@^0.1.3: 495 | version "0.1.4" 496 | resolved "https://registry.yarnpkg.com/deep-is/-/deep-is-0.1.4.tgz#a6f2dce612fadd2ef1f519b73551f17e85199831" 497 | integrity sha512-oIPzksmTg4/MriiaYGO+okXDT7ztn/w3Eptv/+gSIdMdKsJo0u4CfYNFJPy+4SKMuCqGw2wxnA+URMg3t8a/bQ== 498 | 499 | deepmerge@^4.2.2: 500 | version "4.2.2" 501 | resolved "https://registry.yarnpkg.com/deepmerge/-/deepmerge-4.2.2.tgz#44d2ea3679b8f4d4ffba33f03d865fc1e7bf4955" 502 | integrity sha512-FJ3UgI4gIl+PHZm53knsuSFpE+nESMr7M4v9QcgB7S63Kj/6WqMiFQJpBBYz1Pt+66bZpP3Q7Lye0Oo9MPKEdg== 503 | 504 | dir-glob@^3.0.1: 505 | version "3.0.1" 506 | resolved "https://registry.yarnpkg.com/dir-glob/-/dir-glob-3.0.1.tgz#56dbf73d992a4a93ba1584f4534063fd2e41717f" 507 | integrity sha512-WkrWp9GR4KXfKGYzOLmTuGVi1UWFfws377n9cc55/tb6DuqyF6pcQ5AbiHEshaDpY9v6oaSr2XCDidGmMwdzIA== 508 | dependencies: 509 | path-type "^4.0.0" 510 | 511 | doctrine@^3.0.0: 512 | version "3.0.0" 513 | resolved "https://registry.yarnpkg.com/doctrine/-/doctrine-3.0.0.tgz#addebead72a6574db783639dc87a121773973961" 514 | integrity sha512-yS+Q5i3hBf7GBkd4KG8a7eBNNWNGLTaEwwYWUijIYM7zrlYDM0BFXHjjPWlWZ1Rg7UaddZeIDmi9jF3HmqiQ2w== 515 | dependencies: 516 | esutils "^2.0.2" 517 | 518 | eastasianwidth@^0.2.0: 519 | version "0.2.0" 520 | resolved "https://registry.yarnpkg.com/eastasianwidth/-/eastasianwidth-0.2.0.tgz#696ce2ec0aa0e6ea93a397ffcf24aa7840c827cb" 521 | integrity sha512-I88TYZWc9XiYHRQ4/3c5rjjfgkjhLyW2luGIheGERbNQ6OY7yTybanSpDXZa8y7VUP9YmDcYa+eyq4ca7iLqWA== 522 | 523 | emoji-regex@^8.0.0: 524 | version "8.0.0" 525 | resolved "https://registry.yarnpkg.com/emoji-regex/-/emoji-regex-8.0.0.tgz#e818fd69ce5ccfcb404594f842963bf53164cc37" 526 | integrity sha512-MSjYzcWNOA0ewAHpz0MxpYFvwg6yjy1NG3xteoqz644VCo/RPgnr1/GGt+ic3iJTzQ8Eu3TdM14SawnVUmGE6A== 527 | 528 | emoji-regex@^9.2.2: 529 | version "9.2.2" 530 | resolved "https://registry.yarnpkg.com/emoji-regex/-/emoji-regex-9.2.2.tgz#840c8803b0d8047f4ff0cf963176b32d4ef3ed72" 531 | integrity sha512-L18DaJsXSUk2+42pv8mLs5jJT2hqFkFE4j21wOmgbUqsZ2hL72NsUU785g9RXgo3s0ZNgVl42TiHp3ZtOv/Vyg== 532 | 533 | escape-string-regexp@^4.0.0: 534 | version "4.0.0" 535 | resolved "https://registry.yarnpkg.com/escape-string-regexp/-/escape-string-regexp-4.0.0.tgz#14ba83a5d373e3d311e5afca29cf5bfad965bf34" 536 | integrity sha512-TtpcNJ3XAzx3Gq8sWRzJaVajRs0uVxA2YAkdb1jm2YkPz4G6egUFAyA3n5vtEIZefPk5Wa4UXbKuS5fKkJWdgA== 537 | 538 | eslint-config-prettier@^9.1.0: 539 | version "9.1.0" 540 | resolved "https://registry.yarnpkg.com/eslint-config-prettier/-/eslint-config-prettier-9.1.0.tgz#31af3d94578645966c082fcb71a5846d3c94867f" 541 | integrity sha512-NSWl5BFQWEPi1j4TjVNItzYV7dZXZ+wP6I6ZhrBGpChQhZRUaElihE9uRRkcbRnNb76UMKDF3r+WTmNcGPKsqw== 542 | 543 | eslint-plugin-prettier@^5.2.1: 544 | version "5.2.1" 545 | resolved "https://registry.yarnpkg.com/eslint-plugin-prettier/-/eslint-plugin-prettier-5.2.1.tgz#d1c8f972d8f60e414c25465c163d16f209411f95" 546 | integrity sha512-gH3iR3g4JfF+yYPaJYkN7jEl9QbweL/YfkoRlNnuIEHEz1vHVlCmWOS+eGGiRuzHQXdJFCOTxRgvju9b8VUmrw== 547 | dependencies: 548 | prettier-linter-helpers "^1.0.0" 549 | synckit "^0.9.1" 550 | 551 | eslint-plugin-unused-imports@^4.0.1: 552 | version "4.0.1" 553 | resolved "https://registry.yarnpkg.com/eslint-plugin-unused-imports/-/eslint-plugin-unused-imports-4.0.1.tgz#b78916ecb82ae6d0f54efb33879c6c7ecb52f080" 554 | integrity sha512-rax76s05z64uQgG9YXsWFmXrgjkaK79AvfeAWiSxhPP6RVGxeRaj4+2u+wxxu/mDy2pmJoOy1QTOEALMia2xGQ== 555 | dependencies: 556 | eslint-rule-composer "^0.3.0" 557 | 558 | eslint-rule-composer@^0.3.0: 559 | version "0.3.0" 560 | resolved "https://registry.yarnpkg.com/eslint-rule-composer/-/eslint-rule-composer-0.3.0.tgz#79320c927b0c5c0d3d3d2b76c8b4a488f25bbaf9" 561 | integrity sha512-bt+Sh8CtDmn2OajxvNO+BX7Wn4CIWMpTRm3MaiKPCQcnnlm0CS2mhui6QaoeQugs+3Kj2ESKEEGJUdVafwhiCg== 562 | 563 | eslint-scope@^7.2.2: 564 | version "7.2.2" 565 | resolved "https://registry.yarnpkg.com/eslint-scope/-/eslint-scope-7.2.2.tgz#deb4f92563390f32006894af62a22dba1c46423f" 566 | integrity sha512-dOt21O7lTMhDM+X9mB4GX+DZrZtCUJPL/wlcTqxyrx5IvO0IYtILdtrQGQp+8n5S0gwSVmOf9NQrjMOgfQZlIg== 567 | dependencies: 568 | esrecurse "^4.3.0" 569 | estraverse "^5.2.0" 570 | 571 | eslint-visitor-keys@^3.3.0, eslint-visitor-keys@^3.4.1, eslint-visitor-keys@^3.4.3: 572 | version "3.4.3" 573 | resolved "https://registry.yarnpkg.com/eslint-visitor-keys/-/eslint-visitor-keys-3.4.3.tgz#0cd72fe8550e3c2eae156a96a4dddcd1c8ac5800" 574 | integrity sha512-wpc+LXeiyiisxPlEkUzU6svyS1frIO3Mgxj1fdy7Pm8Ygzguax2N3Fa/D/ag1WqbOprdI+uY6wMUl8/a2G+iag== 575 | 576 | eslint@^8.57.0: 577 | version "8.57.0" 578 | resolved "https://registry.yarnpkg.com/eslint/-/eslint-8.57.0.tgz#c786a6fd0e0b68941aaf624596fb987089195668" 579 | integrity sha512-dZ6+mexnaTIbSBZWgou51U6OmzIhYM2VcNdtiTtI7qPNZm35Akpr0f6vtw3w1Kmn5PYo+tZVfh13WrhpS6oLqQ== 580 | dependencies: 581 | "@eslint-community/eslint-utils" "^4.2.0" 582 | "@eslint-community/regexpp" "^4.6.1" 583 | "@eslint/eslintrc" "^2.1.4" 584 | "@eslint/js" "8.57.0" 585 | "@humanwhocodes/config-array" "^0.11.14" 586 | "@humanwhocodes/module-importer" "^1.0.1" 587 | "@nodelib/fs.walk" "^1.2.8" 588 | "@ungap/structured-clone" "^1.2.0" 589 | ajv "^6.12.4" 590 | chalk "^4.0.0" 591 | cross-spawn "^7.0.2" 592 | debug "^4.3.2" 593 | doctrine "^3.0.0" 594 | escape-string-regexp "^4.0.0" 595 | eslint-scope "^7.2.2" 596 | eslint-visitor-keys "^3.4.3" 597 | espree "^9.6.1" 598 | esquery "^1.4.2" 599 | esutils "^2.0.2" 600 | fast-deep-equal "^3.1.3" 601 | file-entry-cache "^6.0.1" 602 | find-up "^5.0.0" 603 | glob-parent "^6.0.2" 604 | globals "^13.19.0" 605 | graphemer "^1.4.0" 606 | ignore "^5.2.0" 607 | imurmurhash "^0.1.4" 608 | is-glob "^4.0.0" 609 | is-path-inside "^3.0.3" 610 | js-yaml "^4.1.0" 611 | json-stable-stringify-without-jsonify "^1.0.1" 612 | levn "^0.4.1" 613 | lodash.merge "^4.6.2" 614 | minimatch "^3.1.2" 615 | natural-compare "^1.4.0" 616 | optionator "^0.9.3" 617 | strip-ansi "^6.0.1" 618 | text-table "^0.2.0" 619 | 620 | espree@^9.6.0, espree@^9.6.1: 621 | version "9.6.1" 622 | resolved "https://registry.yarnpkg.com/espree/-/espree-9.6.1.tgz#a2a17b8e434690a5432f2f8018ce71d331a48c6f" 623 | integrity sha512-oruZaFkjorTpF32kDSI5/75ViwGeZginGGy2NoOSg3Q9bnwlnmDm4HLnkl0RE3n+njDXR037aY1+x58Z/zFdwQ== 624 | dependencies: 625 | acorn "^8.9.0" 626 | acorn-jsx "^5.3.2" 627 | eslint-visitor-keys "^3.4.1" 628 | 629 | esquery@^1.4.2: 630 | version "1.6.0" 631 | resolved "https://registry.yarnpkg.com/esquery/-/esquery-1.6.0.tgz#91419234f804d852a82dceec3e16cdc22cf9dae7" 632 | integrity sha512-ca9pw9fomFcKPvFLXhBKUK90ZvGibiGOvRJNbjljY7s7uq/5YO4BOzcYtJqExdx99rF6aAcnRxHmcUHcz6sQsg== 633 | dependencies: 634 | estraverse "^5.1.0" 635 | 636 | esrecurse@^4.3.0: 637 | version "4.3.0" 638 | resolved "https://registry.yarnpkg.com/esrecurse/-/esrecurse-4.3.0.tgz#7ad7964d679abb28bee72cec63758b1c5d2c9921" 639 | integrity sha512-KmfKL3b6G+RXvP8N1vr3Tq1kL/oCFgn2NYXEtqP8/L3pKapUA4G8cFVaoF3SU323CD4XypR/ffioHmkti6/Tag== 640 | dependencies: 641 | estraverse "^5.2.0" 642 | 643 | estraverse@^5.1.0, estraverse@^5.2.0: 644 | version "5.3.0" 645 | resolved "https://registry.yarnpkg.com/estraverse/-/estraverse-5.3.0.tgz#2eea5290702f26ab8fe5370370ff86c965d21123" 646 | integrity sha512-MMdARuVEQziNTeJD8DgMqmhwR11BRQ/cBP+pLtYdSTnf3MIO8fFeiINEbX36ZdNlfU/7A9f3gUw49B3oQsvwBA== 647 | 648 | estree-walker@^2.0.2: 649 | version "2.0.2" 650 | resolved "https://registry.yarnpkg.com/estree-walker/-/estree-walker-2.0.2.tgz#52f010178c2a4c117a7757cfe942adb7d2da4cac" 651 | integrity sha512-Rfkk/Mp/DL7JVje3u18FxFujQlTNR2q6QfMSMB7AvCBx91NGj/ba3kCfza0f6dVDbw7YlRf/nDrn7pQrCCyQ/w== 652 | 653 | esutils@^2.0.2: 654 | version "2.0.3" 655 | resolved "https://registry.yarnpkg.com/esutils/-/esutils-2.0.3.tgz#74d2eb4de0b8da1293711910d50775b9b710ef64" 656 | integrity sha512-kVscqXk4OCp68SZ0dkgEKVi6/8ij300KBWTJq32P/dYeWTSwK41WyTxalN1eRmA5Z9UU/LX9D7FWSmV9SAYx6g== 657 | 658 | fast-deep-equal@^3.1.1, fast-deep-equal@^3.1.3: 659 | version "3.1.3" 660 | resolved "https://registry.yarnpkg.com/fast-deep-equal/-/fast-deep-equal-3.1.3.tgz#3a7d56b559d6cbc3eb512325244e619a65c6c525" 661 | integrity sha512-f3qQ9oQy9j2AhBe/H9VC91wLmKBCCU/gDOnKNAYG5hswO7BLKj09Hc5HYNz9cGI++xlpDCIgDaitVs03ATR84Q== 662 | 663 | fast-diff@^1.1.2: 664 | version "1.3.0" 665 | resolved "https://registry.yarnpkg.com/fast-diff/-/fast-diff-1.3.0.tgz#ece407fa550a64d638536cd727e129c61616e0f0" 666 | integrity sha512-VxPP4NqbUjj6MaAOafWeUn2cXWLcCtljklUtZf0Ind4XQ+QPtmA0b18zZy0jIQx+ExRVCR/ZQpBmik5lXshNsw== 667 | 668 | fast-glob@^3.2.9: 669 | version "3.3.2" 670 | resolved "https://registry.yarnpkg.com/fast-glob/-/fast-glob-3.3.2.tgz#a904501e57cfdd2ffcded45e99a54fef55e46129" 671 | integrity sha512-oX2ruAFQwf/Orj8m737Y5adxDQO0LAB7/S5MnxCdTNDd4p6BsyIVsv9JQsATbTSq8KHRpLwIHbVlUNatxd+1Ow== 672 | dependencies: 673 | "@nodelib/fs.stat" "^2.0.2" 674 | "@nodelib/fs.walk" "^1.2.3" 675 | glob-parent "^5.1.2" 676 | merge2 "^1.3.0" 677 | micromatch "^4.0.4" 678 | 679 | fast-json-stable-stringify@^2.0.0: 680 | version "2.1.0" 681 | resolved "https://registry.yarnpkg.com/fast-json-stable-stringify/-/fast-json-stable-stringify-2.1.0.tgz#874bf69c6f404c2b5d99c481341399fd55892633" 682 | integrity sha512-lhd/wF+Lk98HZoTCtlVraHtfh5XYijIjalXck7saUtuanSDyLMxnHhSXEDJqHxD7msR8D0uCmqlkwjCV8xvwHw== 683 | 684 | fast-levenshtein@^2.0.6: 685 | version "2.0.6" 686 | resolved "https://registry.yarnpkg.com/fast-levenshtein/-/fast-levenshtein-2.0.6.tgz#3d8a5c66883a16a30ca8643e851f19baa7797917" 687 | integrity sha512-DCXu6Ifhqcks7TZKY3Hxp3y6qphY5SJZmrWMDrKcERSOXWQdMhU9Ig/PYrzyw/ul9jOIyh0N4M0tbC5hodg8dw== 688 | 689 | fastq@^1.6.0: 690 | version "1.17.1" 691 | resolved "https://registry.yarnpkg.com/fastq/-/fastq-1.17.1.tgz#2a523f07a4e7b1e81a42b91b8bf2254107753b47" 692 | integrity sha512-sRVD3lWVIXWg6By68ZN7vho9a1pQcN/WBFaAAsDDFzlJjvoGx0P8z7V1t72grFJfJhu3YPZBuu25f7Kaw2jN1w== 693 | dependencies: 694 | reusify "^1.0.4" 695 | 696 | file-entry-cache@^6.0.1: 697 | version "6.0.1" 698 | resolved "https://registry.yarnpkg.com/file-entry-cache/-/file-entry-cache-6.0.1.tgz#211b2dd9659cb0394b073e7323ac3c933d522027" 699 | integrity sha512-7Gps/XWymbLk2QLYK4NzpMOrYjMhdIxXuIvy2QBsLE6ljuodKvdkWs/cpyJJ3CVIVpH0Oi1Hvg1ovbMzLdFBBg== 700 | dependencies: 701 | flat-cache "^3.0.4" 702 | 703 | fill-range@^7.1.1: 704 | version "7.1.1" 705 | resolved "https://registry.yarnpkg.com/fill-range/-/fill-range-7.1.1.tgz#44265d3cac07e3ea7dc247516380643754a05292" 706 | integrity sha512-YsGpe3WHLK8ZYi4tWDg2Jy3ebRz2rXowDxnld4bkQB00cc/1Zw9AWnC0i9ztDJitivtQvaI9KaLyKrc+hBW0yg== 707 | dependencies: 708 | to-regex-range "^5.0.1" 709 | 710 | find-up@^5.0.0: 711 | version "5.0.0" 712 | resolved "https://registry.yarnpkg.com/find-up/-/find-up-5.0.0.tgz#4c92819ecb7083561e4f4a240a86be5198f536fc" 713 | integrity sha512-78/PXT1wlLLDgTzDs7sjq9hzz0vXD+zn+7wypEe4fXQxCmdmqfGsEPQxmiCSQI3ajFV91bVSsvNtrJRiW6nGng== 714 | dependencies: 715 | locate-path "^6.0.0" 716 | path-exists "^4.0.0" 717 | 718 | flat-cache@^3.0.4: 719 | version "3.2.0" 720 | resolved "https://registry.yarnpkg.com/flat-cache/-/flat-cache-3.2.0.tgz#2c0c2d5040c99b1632771a9d105725c0115363ee" 721 | integrity sha512-CYcENa+FtcUKLmhhqyctpclsq7QF38pKjZHsGNiSQF5r4FtoKDWabFDl3hzaEQMvT1LHEysw5twgLvpYYb4vbw== 722 | dependencies: 723 | flatted "^3.2.9" 724 | keyv "^4.5.3" 725 | rimraf "^3.0.2" 726 | 727 | flatted@^3.2.9: 728 | version "3.3.1" 729 | resolved "https://registry.yarnpkg.com/flatted/-/flatted-3.3.1.tgz#21db470729a6734d4997002f439cb308987f567a" 730 | integrity sha512-X8cqMLLie7KsNUDSdzeN8FYK9rEt4Dt67OsG/DNGnYTSDBG4uFAJFBnUeiV+zCVAvwFy56IjM9sH51jVaEhNxw== 731 | 732 | foreground-child@^3.1.0: 733 | version "3.3.0" 734 | resolved "https://registry.yarnpkg.com/foreground-child/-/foreground-child-3.3.0.tgz#0ac8644c06e431439f8561db8ecf29a7b5519c77" 735 | integrity sha512-Ld2g8rrAyMYFXBhEqMz8ZAHBi4J4uS1i/CxGMDnjyFWddMXLVcDp051DZfu+t7+ab7Wv6SMqpWmyFIj5UbfFvg== 736 | dependencies: 737 | cross-spawn "^7.0.0" 738 | signal-exit "^4.0.1" 739 | 740 | fs.realpath@^1.0.0: 741 | version "1.0.0" 742 | resolved "https://registry.yarnpkg.com/fs.realpath/-/fs.realpath-1.0.0.tgz#1504ad2523158caa40db4a2787cb01411994ea4f" 743 | integrity sha512-OO0pH2lK6a0hZnAdau5ItzHPI6pUlvI7jMVnxUQRtw4owF2wk8lOSabtGDCTP4Ggrg2MbGnWO9X8K1t4+fGMDw== 744 | 745 | fsevents@~2.3.2: 746 | version "2.3.2" 747 | resolved "https://registry.yarnpkg.com/fsevents/-/fsevents-2.3.2.tgz#8a526f78b8fdf4623b709e0b975c52c24c02fd1a" 748 | integrity sha512-xiqMQR4xAeHTuB9uWm+fFRcIOgKBMiOBP+eXiyT7jsgVCq1bkVygt00oASowB7EdtpOHaaPgKt812P9ab+DDKA== 749 | 750 | function-bind@^1.1.2: 751 | version "1.1.2" 752 | resolved "https://registry.yarnpkg.com/function-bind/-/function-bind-1.1.2.tgz#2c02d864d97f3ea6c8830c464cbd11ab6eab7a1c" 753 | integrity sha512-7XHNxH7qX9xG5mIwxkhumTox/MIRNcOgDrxWsMt2pAr23WHp6MrRlN7FBSFpCpr+oVO0F744iUgR82nJMfG2SA== 754 | 755 | glob-parent@^5.1.2: 756 | version "5.1.2" 757 | resolved "https://registry.yarnpkg.com/glob-parent/-/glob-parent-5.1.2.tgz#869832c58034fe68a4093c17dc15e8340d8401c4" 758 | integrity sha512-AOIgSQCepiJYwP3ARnGx+5VnTu2HBYdzbGP45eLw1vr3zB3vZLeyed1sC9hnbcOc9/SrMyM5RPQrkGz4aS9Zow== 759 | dependencies: 760 | is-glob "^4.0.1" 761 | 762 | glob-parent@^6.0.2: 763 | version "6.0.2" 764 | resolved "https://registry.yarnpkg.com/glob-parent/-/glob-parent-6.0.2.tgz#6d237d99083950c79290f24c7642a3de9a28f9e3" 765 | integrity sha512-XxwI8EOhVQgWp6iDL+3b0r86f4d6AX6zSU55HfB4ydCEuXLXc5FcYeOu+nnGftS4TEju/11rt4KJPTMgbfmv4A== 766 | dependencies: 767 | is-glob "^4.0.3" 768 | 769 | glob@^10.4.1: 770 | version "10.4.5" 771 | resolved "https://registry.yarnpkg.com/glob/-/glob-10.4.5.tgz#f4d9f0b90ffdbab09c9d77f5f29b4262517b0956" 772 | integrity sha512-7Bv8RF0k6xjo7d4A/PxYLbUCfb6c+Vpd2/mB2yRDlew7Jb5hEXiCD9ibfO7wpk8i4sevK6DFny9h7EYbM3/sHg== 773 | dependencies: 774 | foreground-child "^3.1.0" 775 | jackspeak "^3.1.2" 776 | minimatch "^9.0.4" 777 | minipass "^7.1.2" 778 | package-json-from-dist "^1.0.0" 779 | path-scurry "^1.11.1" 780 | 781 | glob@^7.1.3: 782 | version "7.2.3" 783 | resolved "https://registry.yarnpkg.com/glob/-/glob-7.2.3.tgz#b8df0fb802bbfa8e89bd1d938b4e16578ed44f2b" 784 | integrity sha512-nFR0zLpU2YCaRxwoCJvL6UvCH2JFyFVIvwTLsIf21AuHlMskA1hhTdk+LlYJtOlYt9v6dvszD2BGRqBL+iQK9Q== 785 | dependencies: 786 | fs.realpath "^1.0.0" 787 | inflight "^1.0.4" 788 | inherits "2" 789 | minimatch "^3.1.1" 790 | once "^1.3.0" 791 | path-is-absolute "^1.0.0" 792 | 793 | globals@^13.19.0: 794 | version "13.24.0" 795 | resolved "https://registry.yarnpkg.com/globals/-/globals-13.24.0.tgz#8432a19d78ce0c1e833949c36adb345400bb1171" 796 | integrity sha512-AhO5QUcj8llrbG09iWhPU2B204J1xnPeL8kQmVorSsy+Sjj1sk8gIyh6cUocGmH4L0UuhAJy+hJMRA4mgA4mFQ== 797 | dependencies: 798 | type-fest "^0.20.2" 799 | 800 | globby@^11.1.0: 801 | version "11.1.0" 802 | resolved "https://registry.yarnpkg.com/globby/-/globby-11.1.0.tgz#bd4be98bb042f83d796f7e3811991fbe82a0d34b" 803 | integrity sha512-jhIXaOzy1sb8IyocaruWSn1TjmnBVs8Ayhcy83rmxNJ8q2uWKCAj3CnJY+KpGSXCueAPc0i05kVvVKtP1t9S3g== 804 | dependencies: 805 | array-union "^2.1.0" 806 | dir-glob "^3.0.1" 807 | fast-glob "^3.2.9" 808 | ignore "^5.2.0" 809 | merge2 "^1.4.1" 810 | slash "^3.0.0" 811 | 812 | graphemer@^1.4.0: 813 | version "1.4.0" 814 | resolved "https://registry.yarnpkg.com/graphemer/-/graphemer-1.4.0.tgz#fb2f1d55e0e3a1849aeffc90c4fa0dd53a0e66c6" 815 | integrity sha512-EtKwoO6kxCL9WO5xipiHTZlSzBm7WLT627TqC/uVRd0HKmq8NXyebnNYxDoBi7wt8eTWrUrKXCOVaFq9x1kgag== 816 | 817 | has-flag@^4.0.0: 818 | version "4.0.0" 819 | resolved "https://registry.yarnpkg.com/has-flag/-/has-flag-4.0.0.tgz#944771fd9c81c81265c4d6941860da06bb59479b" 820 | integrity sha512-EykJT/Q1KjTWctppgIAgfSO0tKVuZUjhgMr17kqTumMl6Afv3EISleU7qZUzoXDFTAHTDC4NOoG/ZxU3EvlMPQ== 821 | 822 | hasown@^2.0.0: 823 | version "2.0.2" 824 | resolved "https://registry.yarnpkg.com/hasown/-/hasown-2.0.2.tgz#003eaf91be7adc372e84ec59dc37252cedb80003" 825 | integrity sha512-0hJU9SCPvmMzIBdZFqNPXWa6dqh7WdH0cII9y+CyS8rG3nL48Bclra9HmKhVVUHyPWNH5Y7xDwAB7bfgSjkUMQ== 826 | dependencies: 827 | function-bind "^1.1.2" 828 | 829 | ignore@^5.2.0, ignore@^5.3.1: 830 | version "5.3.1" 831 | resolved "https://registry.yarnpkg.com/ignore/-/ignore-5.3.1.tgz#5073e554cd42c5b33b394375f538b8593e34d4ef" 832 | integrity sha512-5Fytz/IraMjqpwfd34ke28PTVMjZjJG2MPn5t7OE4eUCUNf8BAa7b5WUS9/Qvr6mwOQS7Mk6vdsMno5he+T8Xw== 833 | 834 | import-fresh@^3.2.1: 835 | version "3.3.0" 836 | resolved "https://registry.yarnpkg.com/import-fresh/-/import-fresh-3.3.0.tgz#37162c25fcb9ebaa2e6e53d5b4d88ce17d9e0c2b" 837 | integrity sha512-veYYhQa+D1QBKznvhUHxb8faxlrwUnxseDAbAp457E0wLNio2bOSKnjYDhMj+YiAq61xrMGhQk9iXVk5FzgQMw== 838 | dependencies: 839 | parent-module "^1.0.0" 840 | resolve-from "^4.0.0" 841 | 842 | imurmurhash@^0.1.4: 843 | version "0.1.4" 844 | resolved "https://registry.yarnpkg.com/imurmurhash/-/imurmurhash-0.1.4.tgz#9218b9b2b928a238b13dc4fb6b6d576f231453ea" 845 | integrity sha512-JmXMZ6wuvDmLiHEml9ykzqO6lwFbof0GG4IkcGaENdCRDDmMVnny7s5HsIgHCbaq0w2MyPhDqkhTUgS2LU2PHA== 846 | 847 | inflight@^1.0.4: 848 | version "1.0.6" 849 | resolved "https://registry.yarnpkg.com/inflight/-/inflight-1.0.6.tgz#49bd6331d7d02d0c09bc910a1075ba8165b56df9" 850 | integrity sha512-k92I/b08q4wvFscXCLvqfsHCrjrF7yiXsQuIVvVE7N82W3+aqpzuUdBbfhWcy/FZR3/4IgflMgKLOsvPDrGCJA== 851 | dependencies: 852 | once "^1.3.0" 853 | wrappy "1" 854 | 855 | inherits@2: 856 | version "2.0.4" 857 | resolved "https://registry.yarnpkg.com/inherits/-/inherits-2.0.4.tgz#0fa2c64f932917c3433a0ded55363aae37416b7c" 858 | integrity sha512-k/vGaX4/Yla3WzyMCvTQOXYeIHvqOKtnqBduzTHpzpQZzAskKMhZ2K+EnBiSM9zGSoIFeMpXKxa4dYeZIQqewQ== 859 | 860 | is-builtin-module@^3.2.1: 861 | version "3.2.1" 862 | resolved "https://registry.yarnpkg.com/is-builtin-module/-/is-builtin-module-3.2.1.tgz#f03271717d8654cfcaf07ab0463faa3571581169" 863 | integrity sha512-BSLE3HnV2syZ0FK0iMA/yUGplUeMmNz4AW5fnTunbCIqZi4vG3WjJT9FHMy5D69xmAYBHXQhJdALdpwVxV501A== 864 | dependencies: 865 | builtin-modules "^3.3.0" 866 | 867 | is-core-module@^2.13.0: 868 | version "2.13.1" 869 | resolved "https://registry.yarnpkg.com/is-core-module/-/is-core-module-2.13.1.tgz#ad0d7532c6fea9da1ebdc82742d74525c6273384" 870 | integrity sha512-hHrIjvZsftOsvKSn2TRYl63zvxsgE0K+0mYMoH6gD4omR5IWB2KynivBQczo3+wF1cCkjzvptnI9Q0sPU66ilw== 871 | dependencies: 872 | hasown "^2.0.0" 873 | 874 | is-extglob@^2.1.1: 875 | version "2.1.1" 876 | resolved "https://registry.yarnpkg.com/is-extglob/-/is-extglob-2.1.1.tgz#a88c02535791f02ed37c76a1b9ea9773c833f8c2" 877 | integrity sha512-SbKbANkN603Vi4jEZv49LeVJMn4yGwsbzZworEoyEiutsN3nJYdbO36zfhGJ6QEDpOZIFkDtnq5JRxmvl3jsoQ== 878 | 879 | is-fullwidth-code-point@^3.0.0: 880 | version "3.0.0" 881 | resolved "https://registry.yarnpkg.com/is-fullwidth-code-point/-/is-fullwidth-code-point-3.0.0.tgz#f116f8064fe90b3f7844a38997c0b75051269f1d" 882 | integrity sha512-zymm5+u+sCsSWyD9qNaejV3DFvhCKclKdizYaJUuHA83RLjb7nSuGnddCHGv0hk+KY7BMAlsWeK4Ueg6EV6XQg== 883 | 884 | is-glob@^4.0.0, is-glob@^4.0.1, is-glob@^4.0.3: 885 | version "4.0.3" 886 | resolved "https://registry.yarnpkg.com/is-glob/-/is-glob-4.0.3.tgz#64f61e42cbbb2eec2071a9dac0b28ba1e65d5084" 887 | integrity sha512-xelSayHH36ZgE7ZWhli7pW34hNbNl8Ojv5KVmkJD4hBdD3th8Tfk9vYasLM+mXWOZhFkgZfxhLSnrwRr4elSSg== 888 | dependencies: 889 | is-extglob "^2.1.1" 890 | 891 | is-module@^1.0.0: 892 | version "1.0.0" 893 | resolved "https://registry.yarnpkg.com/is-module/-/is-module-1.0.0.tgz#3258fb69f78c14d5b815d664336b4cffb6441591" 894 | integrity sha1-Mlj7afeMFNW4FdZkM2tM/7ZEFZE= 895 | 896 | is-number@^7.0.0: 897 | version "7.0.0" 898 | resolved "https://registry.yarnpkg.com/is-number/-/is-number-7.0.0.tgz#7535345b896734d5f80c4d06c50955527a14f12b" 899 | integrity sha512-41Cifkg6e8TylSpdtTpeLVMqvSBEVzTttHvERD741+pnZ8ANv0004MRL43QKPDlK9cGvNp6NZWZUBlbGXYxxng== 900 | 901 | is-path-inside@^3.0.3: 902 | version "3.0.3" 903 | resolved "https://registry.yarnpkg.com/is-path-inside/-/is-path-inside-3.0.3.tgz#d231362e53a07ff2b0e0ea7fed049161ffd16283" 904 | integrity sha512-Fd4gABb+ycGAmKou8eMftCupSir5lRxqf4aD/vd0cD2qc4HL07OjCeuHMr8Ro4CoMaeCKDB0/ECBOVWjTwUvPQ== 905 | 906 | is-reference@1.2.1: 907 | version "1.2.1" 908 | resolved "https://registry.yarnpkg.com/is-reference/-/is-reference-1.2.1.tgz#8b2dac0b371f4bc994fdeaba9eb542d03002d0b7" 909 | integrity sha512-U82MsXXiFIrjCK4otLT+o2NA2Cd2g5MLoOVXUZjIOhLurrRxpEXzI8O0KZHr3IjLvlAH1kTPYSuqer5T9ZVBKQ== 910 | dependencies: 911 | "@types/estree" "*" 912 | 913 | isexe@^2.0.0: 914 | version "2.0.0" 915 | resolved "https://registry.yarnpkg.com/isexe/-/isexe-2.0.0.tgz#e8fbf374dc556ff8947a10dcb0572d633f2cfa10" 916 | integrity sha512-RHxMLp9lnKHGHRng9QFhRCMbYAcVpn69smSGcq3f36xjgVVWThj4qqLbTLlq7Ssj8B+fIQ1EuCEGI2lKsyQeIw== 917 | 918 | jackspeak@^3.1.2: 919 | version "3.4.3" 920 | resolved "https://registry.yarnpkg.com/jackspeak/-/jackspeak-3.4.3.tgz#8833a9d89ab4acde6188942bd1c53b6390ed5a8a" 921 | integrity sha512-OGlZQpz2yfahA/Rd1Y8Cd9SIEsqvXkLVoSw/cgwhnhFMDbsQFeZYoJJ7bIZBS9BcamUW96asq/npPWugM+RQBw== 922 | dependencies: 923 | "@isaacs/cliui" "^8.0.2" 924 | optionalDependencies: 925 | "@pkgjs/parseargs" "^0.11.0" 926 | 927 | jinja-js@^0.1.8: 928 | version "0.1.8" 929 | resolved "https://registry.yarnpkg.com/jinja-js/-/jinja-js-0.1.8.tgz#0b13eeb96e90993f040514d7ce64f53786f58511" 930 | integrity sha512-1wJNbeZxknEckfqt5VU4oVvphC2qASn9yfAw5BNF0JhRZM5LNPcnQKC6nAiEx8nJh0NhxkjCWjQDOut/zQqUOw== 931 | 932 | js-yaml@^4.1.0: 933 | version "4.1.0" 934 | resolved "https://registry.yarnpkg.com/js-yaml/-/js-yaml-4.1.0.tgz#c1fb65f8f5017901cdd2c951864ba18458a10602" 935 | integrity sha512-wpxZs9NoxZaJESJGIZTyDEaYpl0FKSA+FB9aJiyemKhMwkxQg63h4T1KJgUGHpTqPDNRcmmYLugrRjJlBtWvRA== 936 | dependencies: 937 | argparse "^2.0.1" 938 | 939 | json-buffer@3.0.1: 940 | version "3.0.1" 941 | resolved "https://registry.yarnpkg.com/json-buffer/-/json-buffer-3.0.1.tgz#9338802a30d3b6605fbe0613e094008ca8c05a13" 942 | integrity sha512-4bV5BfR2mqfQTJm+V5tPPdf+ZpuhiIvTuAB5g8kcrXOZpTT/QwwVRWBywX1ozr6lEuPdbHxwaJlm9G6mI2sfSQ== 943 | 944 | json-schema-traverse@^0.4.1: 945 | version "0.4.1" 946 | resolved "https://registry.yarnpkg.com/json-schema-traverse/-/json-schema-traverse-0.4.1.tgz#69f6a87d9513ab8bb8fe63bdb0979c448e684660" 947 | integrity sha512-xbbCH5dCYU5T8LcEhhuh7HJ88HXuW3qsI3Y0zOZFKfZEHcpWiHU/Jxzk629Brsab/mMiHQti9wMP+845RPe3Vg== 948 | 949 | json-stable-stringify-without-jsonify@^1.0.1: 950 | version "1.0.1" 951 | resolved "https://registry.yarnpkg.com/json-stable-stringify-without-jsonify/-/json-stable-stringify-without-jsonify-1.0.1.tgz#9db7b59496ad3f3cfef30a75142d2d930ad72651" 952 | integrity sha512-Bdboy+l7tA3OGW6FjyFHWkP5LuByj1Tk33Ljyq0axyzdk9//JSi2u3fP1QSmd1KNwq6VOKYGlAu87CisVir6Pw== 953 | 954 | keyv@^4.5.3: 955 | version "4.5.4" 956 | resolved "https://registry.yarnpkg.com/keyv/-/keyv-4.5.4.tgz#a879a99e29452f942439f2a405e3af8b31d4de93" 957 | integrity sha512-oxVHkHR/EJf2CNXnWxRLW6mg7JyCCUcG0DtEGmL2ctUo1PNTin1PUil+r/+4r5MpVgC/fn1kjsx7mjSujKqIpw== 958 | dependencies: 959 | json-buffer "3.0.1" 960 | 961 | levn@^0.4.1: 962 | version "0.4.1" 963 | resolved "https://registry.yarnpkg.com/levn/-/levn-0.4.1.tgz#ae4562c007473b932a6200d403268dd2fffc6ade" 964 | integrity sha512-+bT2uH4E5LGE7h/n3evcS/sQlJXCpIp6ym8OWJ5eV6+67Dsql/LaaT7qJBAt2rzfoa/5QBGBhxDix1dMt2kQKQ== 965 | dependencies: 966 | prelude-ls "^1.2.1" 967 | type-check "~0.4.0" 968 | 969 | locate-path@^6.0.0: 970 | version "6.0.0" 971 | resolved "https://registry.yarnpkg.com/locate-path/-/locate-path-6.0.0.tgz#55321eb309febbc59c4801d931a72452a681d286" 972 | integrity sha512-iPZK6eYjbxRu3uB4/WZ3EsEIMJFMqAoopl3R+zuq0UjcAm/MO6KCweDgPfP3elTztoKP3KtnVHxTn2NHBSDVUw== 973 | dependencies: 974 | p-locate "^5.0.0" 975 | 976 | lodash.merge@^4.6.2: 977 | version "4.6.2" 978 | resolved "https://registry.yarnpkg.com/lodash.merge/-/lodash.merge-4.6.2.tgz#558aa53b43b661e1925a0afdfa36a9a1085fe57a" 979 | integrity sha512-0KpjqXRVvrYyCsX1swR/XTK0va6VQkQM6MNo7PqW77ByjAhoARA8EfrP1N4+KlKj8YS0ZUCtRT/YUuhyYDujIQ== 980 | 981 | lru-cache@^10.2.0: 982 | version "10.4.3" 983 | resolved "https://registry.yarnpkg.com/lru-cache/-/lru-cache-10.4.3.tgz#410fc8a17b70e598013df257c2446b7f3383f119" 984 | integrity sha512-JNAzZcXrCt42VGLuYz0zfAzDfAvJWW6AfYlDBQyDV5DClI2m5sAmK+OIO7s59XfsRsWHp02jAJrRadPRGTt6SQ== 985 | 986 | magic-string@^0.30.3: 987 | version "0.30.10" 988 | resolved "https://registry.yarnpkg.com/magic-string/-/magic-string-0.30.10.tgz#123d9c41a0cb5640c892b041d4cfb3bd0aa4b39e" 989 | integrity sha512-iIRwTIf0QKV3UAnYK4PU8uiEc4SRh5jX0mwpIwETPpHdhVM4f53RSwS/vXvN1JhGX+Cs7B8qIq3d6AH49O5fAQ== 990 | dependencies: 991 | "@jridgewell/sourcemap-codec" "^1.4.15" 992 | 993 | merge2@^1.3.0, merge2@^1.4.1: 994 | version "1.4.1" 995 | resolved "https://registry.yarnpkg.com/merge2/-/merge2-1.4.1.tgz#4368892f885e907455a6fd7dc55c0c9d404990ae" 996 | integrity sha512-8q7VEgMJW4J8tcfVPy8g09NcQwZdbwFEqhe/WZkoIzjn/3TGDwtOCYtXGxA3O8tPzpczCCDgv+P2P5y00ZJOOg== 997 | 998 | micromatch@^4.0.4: 999 | version "4.0.7" 1000 | resolved "https://registry.yarnpkg.com/micromatch/-/micromatch-4.0.7.tgz#33e8190d9fe474a9895525f5618eee136d46c2e5" 1001 | integrity sha512-LPP/3KorzCwBxfeUuZmaR6bG2kdeHSbe0P2tY3FLRU4vYrjYz5hI4QZwV0njUx3jeuKe67YukQ1LSPZBKDqO/Q== 1002 | dependencies: 1003 | braces "^3.0.3" 1004 | picomatch "^2.3.1" 1005 | 1006 | minimatch@^3.0.5, minimatch@^3.1.1, minimatch@^3.1.2: 1007 | version "3.1.2" 1008 | resolved "https://registry.yarnpkg.com/minimatch/-/minimatch-3.1.2.tgz#19cd194bfd3e428f049a70817c038d89ab4be35b" 1009 | integrity sha512-J7p63hRiAjw1NDEww1W7i37+ByIrOWO5XQQAzZ3VOcL0PNybwpfmV/N05zFAzwQ9USyEcX6t3UO+K5aqBQOIHw== 1010 | dependencies: 1011 | brace-expansion "^1.1.7" 1012 | 1013 | minimatch@^9.0.4: 1014 | version "9.0.5" 1015 | resolved "https://registry.yarnpkg.com/minimatch/-/minimatch-9.0.5.tgz#d74f9dd6b57d83d8e98cfb82133b03978bc929e5" 1016 | integrity sha512-G6T0ZX48xgozx7587koeX9Ys2NYy6Gmv//P89sEte9V9whIapMNF4idKxnW2QtCcLiTWlb/wfCabAtAFWhhBow== 1017 | dependencies: 1018 | brace-expansion "^2.0.1" 1019 | 1020 | "minipass@^5.0.0 || ^6.0.2 || ^7.0.0", minipass@^7.1.2: 1021 | version "7.1.2" 1022 | resolved "https://registry.yarnpkg.com/minipass/-/minipass-7.1.2.tgz#93a9626ce5e5e66bd4db86849e7515e92340a707" 1023 | integrity sha512-qOOzS1cBTWYF4BH8fVePDBOO9iptMnGUEZwNc/cMWnTV2nVLZ7VoNWEPHkYczZA0pdoA7dl6e7FL659nX9S2aw== 1024 | 1025 | moment@*: 1026 | version "2.29.1" 1027 | resolved "https://registry.yarnpkg.com/moment/-/moment-2.29.1.tgz#b2be769fa31940be9eeea6469c075e35006fa3d3" 1028 | integrity sha512-kHmoybcPV8Sqy59DwNDY3Jefr64lK/by/da0ViFcuA4DH0vQg5Q6Ze5VimxkfQNSC+Mls/Kx53s7TjP1RhFEDQ== 1029 | 1030 | moment@2.29.4: 1031 | version "2.29.4" 1032 | resolved "https://registry.yarnpkg.com/moment/-/moment-2.29.4.tgz#3dbe052889fe7c1b2ed966fcb3a77328964ef108" 1033 | integrity sha512-5LC9SOxjSc2HF6vO2CyuTDNivEdoz2IvyJJGj6X8DJ0eFyfszE0QiEd+iXmBvUP3WHxSjFH/vIsA0EN00cgr8w== 1034 | 1035 | moment@2.30.1: 1036 | version "2.30.1" 1037 | resolved "https://registry.yarnpkg.com/moment/-/moment-2.30.1.tgz#f8c91c07b7a786e30c59926df530b4eac96974ae" 1038 | integrity sha512-uEmtNhbDOrWPFS+hdjFCBfy9f2YoyzRpwcl+DqpC6taX21FzsTLQVbMV/W7PzNSX6x/bhC1zA3c2UQ5NzH6how== 1039 | 1040 | ms@2.1.2: 1041 | version "2.1.2" 1042 | resolved "https://registry.yarnpkg.com/ms/-/ms-2.1.2.tgz#d09d1f357b443f493382a8eb3ccd183872ae6009" 1043 | integrity sha512-sGkPx+VjMtmA6MX27oA4FBFELFCZZ4S4XqeGOXCv68tT+jb3vk/RyaKWP0PTKyWtmLSM0b+adUTEvbs1PEaH2w== 1044 | 1045 | natural-compare@^1.4.0: 1046 | version "1.4.0" 1047 | resolved "https://registry.yarnpkg.com/natural-compare/-/natural-compare-1.4.0.tgz#4abebfeed7541f2c27acfb29bdbbd15c8d5ba4f7" 1048 | integrity sha512-OWND8ei3VtNC9h7V60qff3SVobHr996CTwgxubgyQYEpg290h9J0buyECNNJexkFm5sOajh5G116RYA1c8ZMSw== 1049 | 1050 | numeral@^2.0.6: 1051 | version "2.0.6" 1052 | resolved "https://registry.yarnpkg.com/numeral/-/numeral-2.0.6.tgz#4ad080936d443c2561aed9f2197efffe25f4e506" 1053 | integrity sha1-StCAk21EPCVhrtnyGX7//iX05QY= 1054 | 1055 | obsidian@^1.5.7-1: 1056 | version "1.5.7-1" 1057 | resolved "https://registry.yarnpkg.com/obsidian/-/obsidian-1.5.7-1.tgz#6e367f015f6a1b6b13204135434bbe3c04d4dfc3" 1058 | integrity sha512-T5ZRuQ1FnfXqEoakTTHVDYvzUEEoT8zSPnQCW31PVgYwG4D4tZCQfKHN2hTz1ifnCe8upvwa6mBTAP2WUA5Vng== 1059 | dependencies: 1060 | "@types/codemirror" "5.60.8" 1061 | moment "2.29.4" 1062 | 1063 | once@^1.3.0: 1064 | version "1.4.0" 1065 | resolved "https://registry.yarnpkg.com/once/-/once-1.4.0.tgz#583b1aa775961d4b113ac17d9c50baef9dd76bd1" 1066 | integrity sha512-lNaJgI+2Q5URQBkccEKHTQOPaXdUxnZZElQTZY0MFUAuaEqe1E+Nyvgdz/aIyNi6Z9MzO5dv1H8n58/GELp3+w== 1067 | dependencies: 1068 | wrappy "1" 1069 | 1070 | optionator@^0.9.3: 1071 | version "0.9.4" 1072 | resolved "https://registry.yarnpkg.com/optionator/-/optionator-0.9.4.tgz#7ea1c1a5d91d764fb282139c88fe11e182a3a734" 1073 | integrity sha512-6IpQ7mKUxRcZNLIObR0hz7lxsapSSIYNZJwXPGeF0mTVqGKFIXj1DQcMoT22S3ROcLyY/rz0PWaWZ9ayWmad9g== 1074 | dependencies: 1075 | deep-is "^0.1.3" 1076 | fast-levenshtein "^2.0.6" 1077 | levn "^0.4.1" 1078 | prelude-ls "^1.2.1" 1079 | type-check "^0.4.0" 1080 | word-wrap "^1.2.5" 1081 | 1082 | p-limit@^3.0.2: 1083 | version "3.1.0" 1084 | resolved "https://registry.yarnpkg.com/p-limit/-/p-limit-3.1.0.tgz#e1daccbe78d0d1388ca18c64fea38e3e57e3706b" 1085 | integrity sha512-TYOanM3wGwNGsZN2cVTYPArw454xnXj5qmWF1bEoAc4+cU/ol7GVh7odevjp1FNHduHc3KZMcFduxU5Xc6uJRQ== 1086 | dependencies: 1087 | yocto-queue "^0.1.0" 1088 | 1089 | p-locate@^5.0.0: 1090 | version "5.0.0" 1091 | resolved "https://registry.yarnpkg.com/p-locate/-/p-locate-5.0.0.tgz#83c8315c6785005e3bd021839411c9e110e6d834" 1092 | integrity sha512-LaNjtRWUBY++zB5nE/NwcaoMylSPk+S+ZHNB1TzdbMJMny6dynpAGt7X/tl/QYq3TIeE6nxHppbo2LGymrG5Pw== 1093 | dependencies: 1094 | p-limit "^3.0.2" 1095 | 1096 | package-json-from-dist@^1.0.0: 1097 | version "1.0.0" 1098 | resolved "https://registry.yarnpkg.com/package-json-from-dist/-/package-json-from-dist-1.0.0.tgz#e501cd3094b278495eb4258d4c9f6d5ac3019f00" 1099 | integrity sha512-dATvCeZN/8wQsGywez1mzHtTlP22H8OEfPrVMLNr4/eGa+ijtLn/6M5f0dY8UKNrC2O9UCU6SSoG3qRKnt7STw== 1100 | 1101 | parent-module@^1.0.0: 1102 | version "1.0.1" 1103 | resolved "https://registry.yarnpkg.com/parent-module/-/parent-module-1.0.1.tgz#691d2709e78c79fae3a156622452d00762caaaa2" 1104 | integrity sha512-GQ2EWRpQV8/o+Aw8YqtfZZPfNRWZYkbidE9k5rpl/hC3vtHHBfGm2Ifi6qWV+coDGkrUKZAxE3Lot5kcsRlh+g== 1105 | dependencies: 1106 | callsites "^3.0.0" 1107 | 1108 | path-exists@^4.0.0: 1109 | version "4.0.0" 1110 | resolved "https://registry.yarnpkg.com/path-exists/-/path-exists-4.0.0.tgz#513bdbe2d3b95d7762e8c1137efa195c6c61b5b3" 1111 | integrity sha512-ak9Qy5Q7jYb2Wwcey5Fpvg2KoAc/ZIhLSLOSBmRmygPsGwkVVt0fZa0qrtMz+m6tJTAHfZQ8FnmB4MG4LWy7/w== 1112 | 1113 | path-is-absolute@^1.0.0: 1114 | version "1.0.1" 1115 | resolved "https://registry.yarnpkg.com/path-is-absolute/-/path-is-absolute-1.0.1.tgz#174b9268735534ffbc7ace6bf53a5a9e1b5c5f5f" 1116 | integrity sha512-AVbw3UJ2e9bq64vSaS9Am0fje1Pa8pbGqTTsmXfaIiMpnr5DlDhfJOuLj9Sf95ZPVDAUerDfEk88MPmPe7UCQg== 1117 | 1118 | path-key@^3.1.0: 1119 | version "3.1.1" 1120 | resolved "https://registry.yarnpkg.com/path-key/-/path-key-3.1.1.tgz#581f6ade658cbba65a0d3380de7753295054f375" 1121 | integrity sha512-ojmeN0qd+y0jszEtoY48r0Peq5dwMEkIlCOu6Q5f41lfkswXuKtYrhgoTpLnyIcHm24Uhqx+5Tqm2InSwLhE6Q== 1122 | 1123 | path-parse@^1.0.7: 1124 | version "1.0.7" 1125 | resolved "https://registry.yarnpkg.com/path-parse/-/path-parse-1.0.7.tgz#fbc114b60ca42b30d9daf5858e4bd68bbedb6735" 1126 | integrity sha512-LDJzPVEEEPR+y48z93A0Ed0yXb8pAByGWo/k5YYdYgpY2/2EsOsksJrq7lOHxryrVOn1ejG6oAp8ahvOIQD8sw== 1127 | 1128 | path-scurry@^1.11.1: 1129 | version "1.11.1" 1130 | resolved "https://registry.yarnpkg.com/path-scurry/-/path-scurry-1.11.1.tgz#7960a668888594a0720b12a911d1a742ab9f11d2" 1131 | integrity sha512-Xa4Nw17FS9ApQFJ9umLiJS4orGjm7ZzwUrwamcGQuHSzDyth9boKDaycYdDcZDuqYATXw4HFXgaqWTctW/v1HA== 1132 | dependencies: 1133 | lru-cache "^10.2.0" 1134 | minipass "^5.0.0 || ^6.0.2 || ^7.0.0" 1135 | 1136 | path-type@^4.0.0: 1137 | version "4.0.0" 1138 | resolved "https://registry.yarnpkg.com/path-type/-/path-type-4.0.0.tgz#84ed01c0a7ba380afe09d90a8c180dcd9d03043b" 1139 | integrity sha512-gDKb8aZMDeD/tZWs9P6+q0J9Mwkdl6xMV8TjnGP3qJVJ06bdMgkbBlLU8IdfOsIsFz2BW1rNVT3XuNEl8zPAvw== 1140 | 1141 | picomatch@^2.3.1: 1142 | version "2.3.1" 1143 | resolved "https://registry.yarnpkg.com/picomatch/-/picomatch-2.3.1.tgz#3ba3833733646d9d3e4995946c1365a67fb07a42" 1144 | integrity sha512-JU3teHTNjmE2VCGFzuY8EXzCDVwEqB2a8fsIvwaStHhAWJEeVd1o1QD80CU6+ZdEXXSLbSsuLwJjkCBWqRQUVA== 1145 | 1146 | prelude-ls@^1.2.1: 1147 | version "1.2.1" 1148 | resolved "https://registry.yarnpkg.com/prelude-ls/-/prelude-ls-1.2.1.tgz#debc6489d7a6e6b0e7611888cec880337d316396" 1149 | integrity sha512-vkcDPrRZo1QZLbn5RLGPpg/WmIQ65qoWWhcGKf/b5eplkkarX0m9z8ppCat4mlOqUsWpyNuYgO3VRyrYHSzX5g== 1150 | 1151 | prettier-linter-helpers@^1.0.0: 1152 | version "1.0.0" 1153 | resolved "https://registry.yarnpkg.com/prettier-linter-helpers/-/prettier-linter-helpers-1.0.0.tgz#d23d41fe1375646de2d0104d3454a3008802cf7b" 1154 | integrity sha512-GbK2cP9nraSSUF9N2XwUwqfzlAFlMNYYl+ShE/V+H8a9uNl/oUqB1w2EL54Jh0OlyRSd8RfWYJ3coVS4TROP2w== 1155 | dependencies: 1156 | fast-diff "^1.1.2" 1157 | 1158 | prettier@^3.3.3: 1159 | version "3.3.3" 1160 | resolved "https://registry.yarnpkg.com/prettier/-/prettier-3.3.3.tgz#30c54fe0be0d8d12e6ae61dbb10109ea00d53105" 1161 | integrity sha512-i2tDNA0O5IrMO757lfrdQZCc2jPNDVntV0m/+4whiDfWaTKfMNgR7Qz0NAeGz/nRqF4m5/6CLzbP4/liHt12Ew== 1162 | 1163 | punycode@^2.1.0: 1164 | version "2.3.1" 1165 | resolved "https://registry.yarnpkg.com/punycode/-/punycode-2.3.1.tgz#027422e2faec0b25e1549c3e1bd8309b9133b6e5" 1166 | integrity sha512-vYt7UD1U9Wg6138shLtLOvdAu+8DsC/ilFtEVHcH+wydcSpNE20AfSOduf6MkRFahL5FY7X1oU7nKVZFtfq8Fg== 1167 | 1168 | queue-microtask@^1.2.2: 1169 | version "1.2.3" 1170 | resolved "https://registry.yarnpkg.com/queue-microtask/-/queue-microtask-1.2.3.tgz#4929228bbc724dfac43e0efb058caf7b6cfb6243" 1171 | integrity sha512-NuaNSa6flKT5JaSYQzJok04JzTL1CA6aGhv5rfLW3PgqA+M2ChpZQnAC8h8i4ZFkBS8X5RqkDBHA7r4hej3K9A== 1172 | 1173 | resolve-from@^4.0.0: 1174 | version "4.0.0" 1175 | resolved "https://registry.yarnpkg.com/resolve-from/-/resolve-from-4.0.0.tgz#4abcd852ad32dd7baabfe9b40e00a36db5f392e6" 1176 | integrity sha512-pb/MYmXstAkysRFx8piNI1tGFNQIFA3vkE3Gq4EuA1dF6gHp/+vgZqsCGJapvy8N3Q+4o7FwvquPJcnZ7RYy4g== 1177 | 1178 | resolve@^1.22.1: 1179 | version "1.22.8" 1180 | resolved "https://registry.yarnpkg.com/resolve/-/resolve-1.22.8.tgz#b6c87a9f2aa06dfab52e3d70ac8cde321fa5a48d" 1181 | integrity sha512-oKWePCxqpd6FlLvGV1VU0x7bkPmmCNolxzjMf4NczoDnQcIWrAF+cPtZn5i6n+RfD2d9i0tzpKnG6Yk168yIyw== 1182 | dependencies: 1183 | is-core-module "^2.13.0" 1184 | path-parse "^1.0.7" 1185 | supports-preserve-symlinks-flag "^1.0.0" 1186 | 1187 | reusify@^1.0.4: 1188 | version "1.0.4" 1189 | resolved "https://registry.yarnpkg.com/reusify/-/reusify-1.0.4.tgz#90da382b1e126efc02146e90845a88db12925d76" 1190 | integrity sha512-U9nH88a3fc/ekCF1l0/UP1IosiuIjyTh7hBvXVMHYgVcfGvt897Xguj2UOLDeI5BG2m7/uwyaLVT6fbtCwTyzw== 1191 | 1192 | rimraf@^3.0.2: 1193 | version "3.0.2" 1194 | resolved "https://registry.yarnpkg.com/rimraf/-/rimraf-3.0.2.tgz#f1a5402ba6220ad52cc1282bac1ae3aa49fd061a" 1195 | integrity sha512-JZkJMZkAGFFPP2YqXZXPbMlMBgsxzE8ILs4lMIX/2o0L9UBw9O/Y3o6wFw/i9YLapcUJWwqbi3kdxIPdC62TIA== 1196 | dependencies: 1197 | glob "^7.1.3" 1198 | 1199 | rollup@^4.20.0: 1200 | version "4.20.0" 1201 | resolved "https://registry.yarnpkg.com/rollup/-/rollup-4.20.0.tgz#f9d602161d29e178f0bf1d9f35f0a26f83939492" 1202 | integrity sha512-6rbWBChcnSGzIlXeIdNIZTopKYad8ZG8ajhl78lGRLsI2rX8IkaotQhVas2Ma+GPxJav19wrSzvRvuiv0YKzWw== 1203 | dependencies: 1204 | "@types/estree" "1.0.5" 1205 | optionalDependencies: 1206 | "@rollup/rollup-android-arm-eabi" "4.20.0" 1207 | "@rollup/rollup-android-arm64" "4.20.0" 1208 | "@rollup/rollup-darwin-arm64" "4.20.0" 1209 | "@rollup/rollup-darwin-x64" "4.20.0" 1210 | "@rollup/rollup-linux-arm-gnueabihf" "4.20.0" 1211 | "@rollup/rollup-linux-arm-musleabihf" "4.20.0" 1212 | "@rollup/rollup-linux-arm64-gnu" "4.20.0" 1213 | "@rollup/rollup-linux-arm64-musl" "4.20.0" 1214 | "@rollup/rollup-linux-powerpc64le-gnu" "4.20.0" 1215 | "@rollup/rollup-linux-riscv64-gnu" "4.20.0" 1216 | "@rollup/rollup-linux-s390x-gnu" "4.20.0" 1217 | "@rollup/rollup-linux-x64-gnu" "4.20.0" 1218 | "@rollup/rollup-linux-x64-musl" "4.20.0" 1219 | "@rollup/rollup-win32-arm64-msvc" "4.20.0" 1220 | "@rollup/rollup-win32-ia32-msvc" "4.20.0" 1221 | "@rollup/rollup-win32-x64-msvc" "4.20.0" 1222 | fsevents "~2.3.2" 1223 | 1224 | run-parallel@^1.1.9: 1225 | version "1.2.0" 1226 | resolved "https://registry.yarnpkg.com/run-parallel/-/run-parallel-1.2.0.tgz#66d1368da7bdf921eb9d95bd1a9229e7f21a43ee" 1227 | integrity sha512-5l4VyZR86LZ/lDxZTR6jqL8AFE2S0IFLMP26AbjsLVADxHdhB/c0GUsH+y39UfCi3dzz8OlQuPmnaJOMoDHQBA== 1228 | dependencies: 1229 | queue-microtask "^1.2.2" 1230 | 1231 | sanitize-filename-ts@^1.0.2: 1232 | version "1.0.2" 1233 | resolved "https://registry.yarnpkg.com/sanitize-filename-ts/-/sanitize-filename-ts-1.0.2.tgz#831b0f727a5a8f2cadc0a2cfd65353936b1d5d99" 1234 | integrity sha512-bON2VOJoappmaBHlnxvBNk5R7HkUAsirf5m1M5Kz15uZykDGbHfGPCQNcEQKR8HrQhgh9CmQ6Xe9y71yM9ywkw== 1235 | dependencies: 1236 | truncate-utf8-bytes "^1.0.2" 1237 | 1238 | semver@^7.6.0: 1239 | version "7.6.3" 1240 | resolved "https://registry.yarnpkg.com/semver/-/semver-7.6.3.tgz#980f7b5550bc175fb4dc09403085627f9eb33143" 1241 | integrity sha512-oVekP1cKtI+CTDvHWYFUcMtsK/00wmAEfyqKfNdARm8u1wNVhSgaX7A8d4UuIlUI5e84iEwOhs7ZPYRmzU9U6A== 1242 | 1243 | shebang-command@^2.0.0: 1244 | version "2.0.0" 1245 | resolved "https://registry.yarnpkg.com/shebang-command/-/shebang-command-2.0.0.tgz#ccd0af4f8835fbdc265b82461aaf0c36663f34ea" 1246 | integrity sha512-kHxr2zZpYtdmrN1qDjrrX/Z1rR1kG8Dx+gkpK1G4eXmvXswmcE1hTWBWYUzlraYw1/yZp6YuDY77YtvbN0dmDA== 1247 | dependencies: 1248 | shebang-regex "^3.0.0" 1249 | 1250 | shebang-regex@^3.0.0: 1251 | version "3.0.0" 1252 | resolved "https://registry.yarnpkg.com/shebang-regex/-/shebang-regex-3.0.0.tgz#ae16f1644d873ecad843b0307b143362d4c42172" 1253 | integrity sha512-7++dFhtcx3353uBaq8DDR4NuxBetBzC7ZQOhmTQInHEd6bSrXdiEyzCvG07Z44UYdLShWUyXt5M/yhz8ekcb1A== 1254 | 1255 | signal-exit@^4.0.1: 1256 | version "4.1.0" 1257 | resolved "https://registry.yarnpkg.com/signal-exit/-/signal-exit-4.1.0.tgz#952188c1cbd546070e2dd20d0f41c0ae0530cb04" 1258 | integrity sha512-bzyZ1e88w9O1iNJbKnOlvYTrWPDl46O1bG0D3XInv+9tkPrxrN8jUUTiFlDkkmKWgn1M6CfIA13SuGqOa9Korw== 1259 | 1260 | slash@^3.0.0: 1261 | version "3.0.0" 1262 | resolved "https://registry.yarnpkg.com/slash/-/slash-3.0.0.tgz#6539be870c165adbd5240220dbe361f1bc4d4634" 1263 | integrity sha512-g9Q1haeby36OSStwb4ntCGGGaKsaVSjQ68fBxoQcutl5fS1vuY18H3wSt3jFyFtrkx+Kz0V1G85A4MyAdDMi2Q== 1264 | 1265 | "string-width-cjs@npm:string-width@^4.2.0": 1266 | version "4.2.3" 1267 | resolved "https://registry.yarnpkg.com/string-width/-/string-width-4.2.3.tgz#269c7117d27b05ad2e536830a8ec895ef9c6d010" 1268 | integrity sha512-wKyQRQpjJ0sIp62ErSZdGsjMJWsap5oRNihHhu6G7JVO/9jIB6UyevL+tXuOqrng8j/cxKTWyWUwvSTriiZz/g== 1269 | dependencies: 1270 | emoji-regex "^8.0.0" 1271 | is-fullwidth-code-point "^3.0.0" 1272 | strip-ansi "^6.0.1" 1273 | 1274 | string-width@^4.1.0: 1275 | version "4.2.3" 1276 | resolved "https://registry.yarnpkg.com/string-width/-/string-width-4.2.3.tgz#269c7117d27b05ad2e536830a8ec895ef9c6d010" 1277 | integrity sha512-wKyQRQpjJ0sIp62ErSZdGsjMJWsap5oRNihHhu6G7JVO/9jIB6UyevL+tXuOqrng8j/cxKTWyWUwvSTriiZz/g== 1278 | dependencies: 1279 | emoji-regex "^8.0.0" 1280 | is-fullwidth-code-point "^3.0.0" 1281 | strip-ansi "^6.0.1" 1282 | 1283 | string-width@^5.0.1, string-width@^5.1.2: 1284 | version "5.1.2" 1285 | resolved "https://registry.yarnpkg.com/string-width/-/string-width-5.1.2.tgz#14f8daec6d81e7221d2a357e668cab73bdbca794" 1286 | integrity sha512-HnLOCR3vjcY8beoNLtcjZ5/nxn2afmME6lhrDrebokqMap+XbeW8n9TXpPDOqdGK5qcI3oT0GKTW6wC7EMiVqA== 1287 | dependencies: 1288 | eastasianwidth "^0.2.0" 1289 | emoji-regex "^9.2.2" 1290 | strip-ansi "^7.0.1" 1291 | 1292 | "strip-ansi-cjs@npm:strip-ansi@^6.0.1": 1293 | version "6.0.1" 1294 | resolved "https://registry.yarnpkg.com/strip-ansi/-/strip-ansi-6.0.1.tgz#9e26c63d30f53443e9489495b2105d37b67a85d9" 1295 | integrity sha512-Y38VPSHcqkFrCpFnQ9vuSXmquuv5oXOKpGeT6aGrr3o3Gc9AlVa6JBfUSOCnbxGGZF+/0ooI7KrPuUSztUdU5A== 1296 | dependencies: 1297 | ansi-regex "^5.0.1" 1298 | 1299 | strip-ansi@^6.0.0, strip-ansi@^6.0.1: 1300 | version "6.0.1" 1301 | resolved "https://registry.yarnpkg.com/strip-ansi/-/strip-ansi-6.0.1.tgz#9e26c63d30f53443e9489495b2105d37b67a85d9" 1302 | integrity sha512-Y38VPSHcqkFrCpFnQ9vuSXmquuv5oXOKpGeT6aGrr3o3Gc9AlVa6JBfUSOCnbxGGZF+/0ooI7KrPuUSztUdU5A== 1303 | dependencies: 1304 | ansi-regex "^5.0.1" 1305 | 1306 | strip-ansi@^7.0.1: 1307 | version "7.1.0" 1308 | resolved "https://registry.yarnpkg.com/strip-ansi/-/strip-ansi-7.1.0.tgz#d5b6568ca689d8561370b0707685d22434faff45" 1309 | integrity sha512-iq6eVVI64nQQTRYq2KtEg2d2uU7LElhTJwsH4YzIHZshxlgZms/wIc4VoDQTlG/IvVIrBKG06CrZnp0qv7hkcQ== 1310 | dependencies: 1311 | ansi-regex "^6.0.1" 1312 | 1313 | strip-json-comments@^3.1.1: 1314 | version "3.1.1" 1315 | resolved "https://registry.yarnpkg.com/strip-json-comments/-/strip-json-comments-3.1.1.tgz#31f1281b3832630434831c310c01cccda8cbe006" 1316 | integrity sha512-6fPc+R4ihwqP6N/aIv2f1gMH8lOVtWQHoqC4yK6oSDVVocumAsfCqjkXnqiYMhmMwS/mEHLp7Vehlt3ql6lEig== 1317 | 1318 | supports-color@^7.1.0: 1319 | version "7.2.0" 1320 | resolved "https://registry.yarnpkg.com/supports-color/-/supports-color-7.2.0.tgz#1b7dcdcb32b8138801b3e478ba6a51caa89648da" 1321 | integrity sha512-qpCAvRl9stuOHveKsn7HncJRvv501qIacKzQlO/+Lwxc9+0q2wLyv4Dfvt80/DPn2pqOBsJdDiogXGR9+OvwRw== 1322 | dependencies: 1323 | has-flag "^4.0.0" 1324 | 1325 | supports-preserve-symlinks-flag@^1.0.0: 1326 | version "1.0.0" 1327 | resolved "https://registry.yarnpkg.com/supports-preserve-symlinks-flag/-/supports-preserve-symlinks-flag-1.0.0.tgz#6eda4bd344a3c94aea376d4cc31bc77311039e09" 1328 | integrity sha512-ot0WnXS9fgdkgIcePe6RHNk1WA8+muPa6cSjeR3V8K27q9BB1rTE3R1p7Hv0z1ZyAc8s6Vvv8DIyWf681MAt0w== 1329 | 1330 | synckit@^0.9.1: 1331 | version "0.9.1" 1332 | resolved "https://registry.yarnpkg.com/synckit/-/synckit-0.9.1.tgz#febbfbb6649979450131f64735aa3f6c14575c88" 1333 | integrity sha512-7gr8p9TQP6RAHusBOSLs46F4564ZrjV8xFmw5zCmgmhGUcw2hxsShhJ6CEiHQMgPDwAQ1fWHPM0ypc4RMAig4A== 1334 | dependencies: 1335 | "@pkgr/core" "^0.1.0" 1336 | tslib "^2.6.2" 1337 | 1338 | text-table@^0.2.0: 1339 | version "0.2.0" 1340 | resolved "https://registry.yarnpkg.com/text-table/-/text-table-0.2.0.tgz#7f5ee823ae805207c00af2df4a84ec3fcfa570b4" 1341 | integrity sha512-N+8UisAXDGk8PFXP4HAzVR9nbfmVJ3zYLAWiTIoqC5v5isinhr+r5uaO8+7r3BMfuNIufIsA7RdpVgacC2cSpw== 1342 | 1343 | to-regex-range@^5.0.1: 1344 | version "5.0.1" 1345 | resolved "https://registry.yarnpkg.com/to-regex-range/-/to-regex-range-5.0.1.tgz#1648c44aae7c8d988a326018ed72f5b4dd0392e4" 1346 | integrity sha512-65P7iz6X5yEr1cwcgvQxbbIw7Uk3gOy5dIdtZ4rDveLqhrdJP+Li/Hx6tyK0NEb+2GCyneCMJiGqrADCSNk8sQ== 1347 | dependencies: 1348 | is-number "^7.0.0" 1349 | 1350 | truncate-utf8-bytes@^1.0.2: 1351 | version "1.0.2" 1352 | resolved "https://registry.yarnpkg.com/truncate-utf8-bytes/-/truncate-utf8-bytes-1.0.2.tgz#405923909592d56f78a5818434b0b78489ca5f2b" 1353 | integrity sha512-95Pu1QXQvruGEhv62XCMO3Mm90GscOCClvrIUwCM0PYOXK3kaF3l3sIHxx71ThJfcbM2O5Au6SO3AWCSEfW4mQ== 1354 | dependencies: 1355 | utf8-byte-length "^1.0.1" 1356 | 1357 | ts-api-utils@^1.3.0: 1358 | version "1.3.0" 1359 | resolved "https://registry.yarnpkg.com/ts-api-utils/-/ts-api-utils-1.3.0.tgz#4b490e27129f1e8e686b45cc4ab63714dc60eea1" 1360 | integrity sha512-UQMIo7pb8WRomKR1/+MFVLTroIvDVtMX3K6OUir8ynLyzB8Jeriont2bTAtmNPa1ekAgN7YPDyf6V+ygrdU+eQ== 1361 | 1362 | tslib@^2.6.2: 1363 | version "2.6.2" 1364 | resolved "https://registry.yarnpkg.com/tslib/-/tslib-2.6.2.tgz#703ac29425e7b37cd6fd456e92404d46d1f3e4ae" 1365 | integrity sha512-AEYxH93jGFPn/a2iVAwW87VuUIkR1FVUKB77NwMF7nBTDkDrrT/Hpt/IrCJ0QXhW27jTBDcf5ZY7w6RiqTMw2Q== 1366 | 1367 | tslib@^2.6.3: 1368 | version "2.6.3" 1369 | resolved "https://registry.yarnpkg.com/tslib/-/tslib-2.6.3.tgz#0438f810ad7a9edcde7a241c3d80db693c8cbfe0" 1370 | integrity sha512-xNvxJEOUiWPGhUuUdQgAJPKOOJfGnIyKySOc09XkKsgdUV/3E2zvwZYdejjmRgPCgcym1juLH3226yA7sEFJKQ== 1371 | 1372 | type-check@^0.4.0, type-check@~0.4.0: 1373 | version "0.4.0" 1374 | resolved "https://registry.yarnpkg.com/type-check/-/type-check-0.4.0.tgz#07b8203bfa7056c0657050e3ccd2c37730bab8f1" 1375 | integrity sha512-XleUoc9uwGXqjWwXaUTZAmzMcFZ5858QA2vvx1Ur5xIcixXIP+8LnFDgRplU30us6teqdlskFfu+ae4K79Ooew== 1376 | dependencies: 1377 | prelude-ls "^1.2.1" 1378 | 1379 | type-fest@^0.20.2: 1380 | version "0.20.2" 1381 | resolved "https://registry.yarnpkg.com/type-fest/-/type-fest-0.20.2.tgz#1bf207f4b28f91583666cb5fbd327887301cd5f4" 1382 | integrity sha512-Ne+eE4r0/iWnpAxD852z3A+N0Bt5RN//NjJwRd2VFHEmrywxf5vsZlh4R6lixl6B+wz/8d+maTSAkN1FIkI3LQ== 1383 | 1384 | typescript@^5.5.4: 1385 | version "5.5.4" 1386 | resolved "https://registry.yarnpkg.com/typescript/-/typescript-5.5.4.tgz#d9852d6c82bad2d2eda4fd74a5762a8f5909e9ba" 1387 | integrity sha512-Mtq29sKDAEYP7aljRgtPOpTvOfbwRWlS6dPRzwjdE+C0R4brX/GUyhHSecbHMFLNBLcJIPt9nl9yG5TZ1weH+Q== 1388 | 1389 | undici-types@~6.13.0: 1390 | version "6.13.0" 1391 | resolved "https://registry.yarnpkg.com/undici-types/-/undici-types-6.13.0.tgz#e3e79220ab8c81ed1496b5812471afd7cf075ea5" 1392 | integrity sha512-xtFJHudx8S2DSoujjMd1WeWvn7KKWFRESZTMeL1RptAYERu29D6jphMjjY+vn96jvN3kVPDNxU/E13VTaXj6jg== 1393 | 1394 | uri-js@^4.2.2: 1395 | version "4.4.1" 1396 | resolved "https://registry.yarnpkg.com/uri-js/-/uri-js-4.4.1.tgz#9b1a52595225859e55f669d928f88c6c57f2a77e" 1397 | integrity sha512-7rKUyy33Q1yc98pQ1DAmLtwX109F7TIfWlW1Ydo8Wl1ii1SeHieeh0HHfPeL2fMXK6z0s8ecKs9frCuLJvndBg== 1398 | dependencies: 1399 | punycode "^2.1.0" 1400 | 1401 | utf8-byte-length@^1.0.1: 1402 | version "1.0.4" 1403 | resolved "https://registry.yarnpkg.com/utf8-byte-length/-/utf8-byte-length-1.0.4.tgz#f45f150c4c66eee968186505ab93fcbb8ad6bf61" 1404 | integrity sha512-4+wkEYLBbWxqTahEsWrhxepcoVOJ+1z5PGIjPZxRkytcdSUaNjIjBM7Xn8E+pdSuV7SzvWovBFA54FO0JSoqhA== 1405 | 1406 | which@^2.0.1: 1407 | version "2.0.2" 1408 | resolved "https://registry.yarnpkg.com/which/-/which-2.0.2.tgz#7c6a8dd0a636a0327e10b59c9286eee93f3f51b1" 1409 | integrity sha512-BLI3Tl1TW3Pvl70l3yq3Y64i+awpwXqsGBYWkkqMtnbXgrMD+yj7rhW0kuEDxzJaYXGjEW5ogapKNMEKNMjibA== 1410 | dependencies: 1411 | isexe "^2.0.0" 1412 | 1413 | word-wrap@^1.2.5: 1414 | version "1.2.5" 1415 | resolved "https://registry.yarnpkg.com/word-wrap/-/word-wrap-1.2.5.tgz#d2c45c6dd4fbce621a66f136cbe328afd0410b34" 1416 | integrity sha512-BN22B5eaMMI9UMtjrGd5g5eCYPpCPDUy0FJXbYsaT5zYxjFOckS53SQDE3pWkVoWpHXVb3BrYcEN4Twa55B5cA== 1417 | 1418 | "wrap-ansi-cjs@npm:wrap-ansi@^7.0.0": 1419 | version "7.0.0" 1420 | resolved "https://registry.yarnpkg.com/wrap-ansi/-/wrap-ansi-7.0.0.tgz#67e145cff510a6a6984bdf1152911d69d2eb9e43" 1421 | integrity sha512-YVGIj2kamLSTxw6NsZjoBxfSwsn0ycdesmc4p+Q21c5zPuZ1pl+NfxVdxPtdHvmNVOQ6XSYG4AUtyt/Fi7D16Q== 1422 | dependencies: 1423 | ansi-styles "^4.0.0" 1424 | string-width "^4.1.0" 1425 | strip-ansi "^6.0.0" 1426 | 1427 | wrap-ansi@^8.1.0: 1428 | version "8.1.0" 1429 | resolved "https://registry.yarnpkg.com/wrap-ansi/-/wrap-ansi-8.1.0.tgz#56dc22368ee570face1b49819975d9b9a5ead214" 1430 | integrity sha512-si7QWI6zUMq56bESFvagtmzMdGOtoxfR+Sez11Mobfc7tm+VkUckk9bW2UeffTGVUbOksxmSw0AA2gs8g71NCQ== 1431 | dependencies: 1432 | ansi-styles "^6.1.0" 1433 | string-width "^5.0.1" 1434 | strip-ansi "^7.0.1" 1435 | 1436 | wrappy@1: 1437 | version "1.0.2" 1438 | resolved "https://registry.yarnpkg.com/wrappy/-/wrappy-1.0.2.tgz#b5243d8f3ec1aa35f1364605bc0d1036e30ab69f" 1439 | integrity sha512-l4Sp/DRseor9wL6EvV2+TuQn63dMkPjZ/sp9XkghTEbV9KlPS1xUsZ3u7/IQO4wxtcFB4bgpQPRcR3QCvezPcQ== 1440 | 1441 | yocto-queue@^0.1.0: 1442 | version "0.1.0" 1443 | resolved "https://registry.yarnpkg.com/yocto-queue/-/yocto-queue-0.1.0.tgz#0294eb3dee05028d31ee1a5fa2c556a6aaf10a1b" 1444 | integrity sha512-rVksvsnNCdJ/ohGc6xgPwyN8eheCxsiLM8mxuE/t/mOVqJewPuO1miLpTHQiRgTKCLexL4MeAFVagts7HmNZ2Q== 1445 | --------------------------------------------------------------------------------