Commit Graph

378 Commits

Author SHA1 Message Date
Michael Cordell d45b7a7bf6 fix(dispatcher): skip undefined components in collectComponents (#2404)
layout.footer (and other optional layout slots) can be undefined
when disabled. Adding undefined to the seen Set caused a crash in
componentResources.ts when destructuring component properties.
2026-05-24 17:51:42 +02:00
saberzero1 caa55037f7 fix: harden core build system against silent failures
- Wrap rebuild() in try/finally to guarantee mutex release (prevents deadlock)
- Surface rebuild errors via .catch() instead of discarding with void
- Add null checks for vfile.data.relativePath (prevents crash on virtual files)
- Add try-finally for worker pool cleanup in parse.ts (prevents thread leaks)
- Remove process.exit(1) from parse error handler (let errors propagate)
- Add per-emitter error handling in emit phase with degraded-build warning
- Replace unsafe Map.get()! assertions with null-checked access in config-loader
2026-05-24 17:09:46 +02:00
saberzero1 dfde22acfd feat: emit plugin scripts individually instead of bundling into postscript 2026-05-23 19:51:55 +02:00
saberzero1 0593c8cd6a fix: allow arbitrary transclusion 2026-05-23 01:18:30 +02:00
saberzero1 cfcd9c18ac feat: split and hash inlined assets 2026-05-22 23:03:39 +02:00
saberzero1 cfba672f51 feat: split and hash static css 2026-05-22 22:42:06 +02:00
saberzero1 7fd0590a46 fix: improved plugin type resolution 2026-05-21 17:59:26 +02:00
saberzero1 21ea5895cb fix: improved plugin validation on install 2026-05-20 23:23:39 +02:00
saberzero1 c8f6e6dc14 feat(css): make styles layered by default 2026-04-28 17:25:37 +02:00
saberzero1 9fcc3f260c fix: handle EEXIST race in peer dependency symlink creation 2026-04-27 22:34:31 +02:00
saberzero1 efd9e8e095 feat(loader): prefer pre-built plugins 2026-04-27 22:03:23 +02:00
saberzero1 b3082c32dc fix(path): improper redirects in subpath domain sites 2026-04-22 18:25:05 +02:00
saberzero1 f370898c56 fix(config): properly pass ts-based options to plugins 2026-04-17 22:14:36 +02:00
saberzero1 0c50cca1f6 refactor: move vfile DataMap augmentation to @quartz-community/types 2026-04-03 15:41:11 +02:00
saberzero1 f881d5e332 fix(schema): added missing position option to plugin schema 2026-03-23 12:28:28 +01:00
saberzero1 d9bfbf876f refactor: move defaultDateType to CreatedModifiedDate plugin 2026-03-20 21:13:45 +01:00
saberzero1 db11f757c2 fix(pagetypes): prevent duplicate content 2026-03-18 17:45:56 +01:00
saberzero1 f2c2a31292 fix(cli): resolve subdir plugins during build installs 2026-03-18 02:39:45 +01:00
saberzero1 166b9c87d8 fix(cli): properly resolve subdir plugin installs 2026-03-18 01:56:48 +01:00
saberzero1 219bed15bf chore: updated plugin schema definition 2026-03-18 01:17:10 +01:00
saberzero1 51b05e79e2 feat: centralize native dep installation across plugins
Replace per-plugin npm install with a single aggregated npm install
in the quartz root. Plugins declaring requiresInstall in their quartz
manifest now have their peerDependencies collected and installed
together, letting npm resolve compatible versions across plugins.
2026-03-17 22:32:47 +01:00
saberzero1 d792d8ebf9 feat: add runtime plugin externals validation and native dep install
- validatePluginExternals() scans plugin dist/ for unbundled imports
  and warns when non-allowlisted externals are detected
- installPluginDepsIfNeeded() runs npm install for plugins with
  quartz.requiresInstall flag (for native deps like sharp)
- Added requiresInstall field to PluginManifest type
2026-03-17 19:46:42 +01:00
saberzero1 4bb075cc64 fix(plugin): forward component options from plugin bases views 2026-03-16 14:20:14 +01:00
saberzero1 b11bad1326 fix(plugin): default to HEAD instead of main 2026-03-16 11:55:47 +01:00
saberzero1 a7d91f05f9 fix: resolve frontmatter type declaration conflict between plugins and index.ts
- Removed frontmatter from description plugin's vfile augmentation to avoid
  conflicting DataMap declarations (TS2717/TS2687)
- Aligned frontmatter type in index.ts with note-properties plugin declaration
- Updated quartz.lock.json for description plugin
2026-03-14 23:04:10 +01:00
Emile Bangma ab346fa66a feat(v5): add plugin system (#2295)
* feat(plugins): v5 plugin system

* feat(plugins): explorer as community plugin

* feat(plugins): graph as community plugin

* chore: update package-lock.json

* chore: update package-lock.json

* docs: updated plugin-specific docs

* chore: update package-lock.json

* chore: update package-lock.json

* chore: update package-lock.json

* Implement Git-based plugin system with dogfooding for community plugins

- Remove npm dependencies for @quartz-community/* plugins

- Add gitLoader.ts for installing plugins from GitHub

- Update quartz.layout.ts to import from .quartz/plugins/

- Add install-plugins.ts script for prebuild hook

- Add .quartz/ to .gitignore

* Add comprehensive Git-based plugin CLI with lockfile support

- Create quartz.lock.json format for tracking exact plugin commits

- Add 'npx quartz plugin' commands: install, add, remove, update, list, restore

- Plugin state is fully reproducible via lockfile

- No npm dependencies required for community plugins

* Fix TypeScript errors in git-installed plugins

- Install @quartz-community/types as devDependency

- Fix plugin imports to define types locally

- Fix search inline script fetchData bug

- Format code with prettier

* fix(types): install types from github

* docs: updated plugin-specific docs

* Update Dockerfile and add CI/CD documentation

- Add plugin install step to Dockerfile

- Create docs/ci-cd.md with pipeline configuration guide

* Update GitHub Actions workflows for v5 branch and Git-based plugins

- Change branch references from v4 to v5

- Add plugin caching to speed up builds

- Use 'npx quartz plugin install' instead of 'restore'

- Update Docker workflow branch trigger

* Update quartz.lock.json with fixed plugin versions

* fix(docker): install command

* docs: add plugin migration analysis document

Comprehensive analysis of which Quartz v4 components and plugins
can be migrated to separate repositories, including:
- Component analysis (25 components)
- Plugin analysis (transformers, emitters, filters)
- Migration strategies for different plugin types
- Lessons learned from Explorer/Graph/Search migrations
- Recommended migration order

* chore: updated plugins

* chore: updated plugins

* chore: updated dependencies

* chore: updated plugins

* chore: updated plugins

* chore: updated plugins

* chore: updated plugins

* chore: updated plugins

* chore: updated plugins

* chore: updated plugins

* chore: updated plugins

* chore: updated plugins

* chore: tsconfig

* feat: build installed plugins

* chore: updated plugins

* chore: updated plugins

* chore: update explorer plugin with duplication fix

* docs: Quartz v5

* chore: update graph plugin with navigation fix

* fix: update explorer plugin with toggle fix

* fix: update explorer plugin - ensure toggle buttons always work

* fix: create plugin components once to prevent duplicate script registration

* chore: updated plugins

* chore: updated plugins

* feat: migrate 7 feature components to community plugins (Phase B)

Migrate ArticleTitle, TagList, PageTitle, Darkmode, ReaderMode,
ContentMeta, and Footer from internal components to community
plugins. Update layout to use Plugin.X() pattern, remove internal
component files and their styles/scripts.

Add MIGRATION_TASKS.md documenting the full migration roadmap.

* chore: updated plugins

* refactor: delete 6 internal component duplicates (Phase A)

Remove Backlinks, Breadcrumbs, RecentNotes, Search, TableOfContents,
Comments, and OverflowList — all replaced by community plugins.
Delete associated styles (6) and scripts (3). Switch layout to use
Plugin.Breadcrumbs() instead of Component.Breadcrumbs().

* refactor: unify QuartzComponent type to structural interface (Phase C)

- Changed QuartzComponent from ComponentType<QuartzComponentProps> to callable type ((props: QuartzComponentProps) => any)
- Added optional displayName property for better debugging
- Removed ComponentType import from preact
- Removed all 13 'as QuartzComponent' type casts from quartz.layout.ts
- Community plugin components now directly assignable without casts

* feat: add PageType plugin infrastructure (Phase D Step 4)

* feat: add PageTypePluginEntry for cross-boundary type compatibility

Introduce PageTypePluginEntry with never[] parameter types to accept
both internal and community PageType plugins in config arrays without
casts, working around branded FullSlug contravariance mismatch.

* refactor: update dispatcher to cast PageTypePluginEntry at boundary

Add getPageTypes() helper that casts config's PageTypePluginEntry[]
to QuartzPageTypePluginInstance[] in one place. Cast VirtualPage.slug
to FullSlug at emitPage/defaultProcessedContent call sites.

* feat: integrate community PageType plugins (Phase D Step 6)

Replace old page-rendering emitters with PageTypeDispatcher emitter
and pageTypes array. Restructure quartz.layout.ts from three separate
exports to unified layout object with defaults and byPageType record.
Install content-page, folder-page, tag-page community plugins.

* refactor: delete old page-rendering emitters

Remove ContentPage, FolderPage, TagPage, and NotFoundPage emitters
now replaced by community PageType plugins and the PageTypeDispatcher.

* refactor: remove migrated page body components

Delete Content, FolderContent, TagContent page components now provided
by community PageType plugins. Update components barrel export.

* fix: update lockfile to fixed folder-page and tag-page commits

Points to commits that remove duplicate PageList/SortFn re-exports,
fixing TS2300 duplicate identifier errors in generated plugin index.

* chore: updated plugins

* fix: populate ctx.trie in PageTypeDispatcher before rendering

Components like FolderContent depend on ctx.trie for folder hierarchy.
The dispatcher now lazily initializes it via trieFromAllFiles in emit
and force-rebuilds it in partialEmit to reflect file changes.

* chore: update lockfile to fixed folder-page commit

* chore: updated plugins

* chore: update explorer plugin to fix SPA folder navigation

* feat: extract transformers to community plugins and fix type compatibility

- Delete 12 internal transformer files (keep FrontMatter as internal)
- Switch quartz.config.ts to use ExternalPlugin.* for all transformers
- Align branded types with @quartz-community/types (_brand, FullSlug etc.)
- Add vfile DataMap augmentations for fields from extracted transformers
- Update all 29 plugins to @quartz-community/types v0.2.1

* Migrate filters to external plugins (remove-draft, explicit-publish)

Delete internal RemoveDrafts and ExplicitPublish filter implementations,
install them as community plugins, and update quartz.config.ts to use
ExternalPlugin.RemoveDrafts().

* Migrate emitters to external plugins (alias-redirects, cname, favicon, content-index, og-image)

* refactor: remove inline scripts/styles migrated to plugins

Delete dead code: callout, checkbox, mermaid inline scripts and styles
are now bundled by the obsidian-flavored-markdown plugin. Clipboard
script and styles moved to the syntax-highlighting plugin. listPage.scss
was unreferenced. Body.tsx simplified to a pure layout wrapper.

* refactor: consolidate utils to re-export from @quartz-community/utils

* fix: use dangerouslySetInnerHTML for inline CSS to prevent HTML-escaping

Preact was escaping & characters in SCSS-compiled CSS (e.g. & nesting)
into &amp;, breaking CSS rules. Using dangerouslySetInnerHTML bypasses
the escaping, matching how browsers expect style element content.

* chore: update plugins with inline script transpilation fix

* chore: updated plugins

* docs: update plugin API sections for v5 community plugins

* docs: rewrite documentation for v5 plugin system

Update feature docs, hosting, CI/CD, getting started, configuration,
layout, architecture, creating components, making plugins, and
migration guide to reflect the v5 community plugin architecture.

* docs: fix outdated v4 references in documentation

* chore: remove completed migration planning docs

* chore: updated plugins

* chore: cleanup

* chore: cleanup

* chore: bump version to 5.0.0

* chore: updated dependencies

* feat: integrate CanvasPage plugin with types, assets, config, layout, and documentation

* chore: updated dependencies

* chore: updated dependencies

* chore: updated linter

* chore: update canvas-page plugin to c942fcb

* chore: updated plugins

* chore: update canvas-page plugin to f88f1b9

* chore: updated plugins

* chore: update canvas-page plugin to 079304c

* chore: updated plugins

* chore: canvas layout

* chore: update canvas-page plugin to 38d49e1

* chore: updated plugins

* chore: update canvas-page plugin to 505c099

* chore: updated plugins

* chore: updated plugins

* fix: Obsidian flavored markdown

* fix: Obsidian flavored markdown

* fix: Obsidian flavored markdown

* chore: cleanup

* chore: updated plugins

* feat: configuration files

* feat: Quartz TUI

* feat(tui): YAML configuration

* chore: tsup

* chore: tsup

* feat: support array categories in plugin manifests

Plugins like note-properties export both transformer and component
functionality. Allow PluginManifest.category to be a single value
or an array, with config-loader resolving to the first processing
category (transformer/filter/emitter/pageType) for dispatch.

* refactor: remove built-in FrontMatter transformer

Frontmatter processing is now handled by the note-properties plugin,
which provides the same YAML/TOML parsing plus link extraction and
a visual properties panel. The built-in transformer is no longer needed.

* feat: add note-properties plugin to default configuration

Register note-properties as the first plugin (order 5) in both
the user config and the default config. Placed in beforeBody layout
zone with priority 15 (between article-title at 10 and content-meta at 20).

* docs: add plugin management strategy and syncer v5 notes

Document the plugin management system design decisions and provide
implementation guidance for the Quartz Syncer v5 integration.

* feat: add bases-page plugin to default configuration

Enable Obsidian Bases (.base) file support with bases page type
and layout entry in both user and default config.

* docs: update syncer notes with bases-page, note-properties, and spacer

Add all three new plugins to the quick reference table (40 total).
Add content, canvas, and bases page types to byPageType documentation.

* chore: updated plugins

* fix: update CI to Node 24 and regenerate lockfiles for clean install

* fix: resolve type errors for CI checks

* chore: updated plugins

* chore: updated plugins

* fix: plugin mapping from configuration

* fix: CI

* fix: CI

* docs: rewrite Frontmatter documentation for note-properties plugin

* chore: updated plugins

* docs: Quartz v5

* chore: updated plugins

* chore: updated plugins

* refactor: extract TUI to standalone plugin repository

* chore: linting

* docs: Quartz v5

* feat: update and upgrade commands

* chore: updated plugins

* chore: updated plugins

* chore: cleanup

* chore: cleanup

* chore: cleanup

* chore: cleanup

* chore: cleanup

* fix: layout group priority

* fix: view classes

* fix: include virtual pages in content index for explorer visibility

* docs: add board, gallery, and cards view examples to navigation page

* chore: updated plugins

* fix: include virtualPages in worker serializable build context

* fix: set relativePath on virtual pages to prevent explorer crash

* fix: exclude 404

* fix(links): virtual page links

* fix(links): virtual page transclusion

* docs: architecture overview

* fix: only call scripts one per page

* fix: type error in component registry instantiate method

* fix: left layout order

* fix(layout): remove tag-list by default

* docs(plugins): updated plugin list defaults

* fix(layout): priorities

* feat: add PageFrame system for custom page layouts

* feat: integrate PageFrame into rendering pipeline

* feat: add frame resolution to page type dispatcher and config loader

* style: add CSS grid overrides for full-width and minimal page frames

* feat: set minimal frame for 404 and update canvas-page plugin

* docs: add PageFrame system to architecture overview

* fix: wrap frame.render() in array to satisfy Body children type

* chore: format

* fix: use absolute asset paths for 404 page so it works in subdirectories

* fix(layout): priorities

* docs: page frames

* feat: add FrameRegistry for plugin-provided page frames

Plugins can now register custom page frames via their manifest's
'frames' field. Frames are loaded alongside components during plugin
initialization and resolved by name at render time with fallback
to built-in frames.

* feat(layout): page frames

* fix(layout): linting

* fix: inject frame CSS into page so plugin-provided frames render correctly

* chore: updated plugins

* chore: updated plugins

* chore: updated plugins

* chore: updated plugins

* docs: canvas

* chore: updated plugins

* chore: updated plugins

* chore: updated plugins

* feat: add TreeTransform hook, fix multi-category plugins, and resolve cross-plugin dependencies

- Add TreeTransform type and treeTransforms hook to pageType plugins, enabling
  render-time HAST tree mutations (e.g. bases-page inline codeblock resolution)
- Fix config-loader to push multi-category plugins into ALL matching processing
  buckets instead of only the first match
- Add side-effect import for component-only plugins so view registrations
  (e.g. leaflet-map via globalThis ViewRegistry) execute at load time
- Add npm prune --omit=dev and cross-plugin peer dependency symlinking to
  buildPlugin() to prevent duplicate-singleton issues from nested node_modules

* chore: format

* chore: test docs

* chore: updated plugins

* fix: prevent HTML-escaping of inline style and script content in htmlToJsx

Add dangerouslySetInnerHTML overrides for <style> and <script> elements
so that CSS/JS injected by tree transforms is not HTML-escaped during
preact-render-to-string serialization.

* chore: update plugin lockfile for htmlToJsx migration

* chore: update leaflet-map plugin (fix deferred L.Control)

* chore: updated plugins

* chore: updated plugins

* chore: updated plugins

* chore: updated plugins

* chore: updated plugins

* chore: updated plugins

* chore: updated plugins

* chore: test npx quartz upgrade

* feat(templates): add obsidian, ttrpg, blog templates

* docs: move bases

* docs: removed leaflet demo

* feat(cli): configure baseUrl during create

* docs: updated cli commands

* docs: updated documentation for v5

* feat(cli): prune and resolve

* chore: rebuild lockfile

* docs: cli documentation

* docs: plugin development and setup guide

* chore: deleted redundant files

* fix(build): fallback config

* chore: updated lockfile

* docs: removed outdated v3 setup

* feat(cli): allow non-default branch plugins

* docs: install branch commands

* feat(cli): allow local plugins

* docs: install local commands

* feat: add render event type and listener for in-place DOM re-initialization

* docs: add EncryptedPages plugin documentation

* docs: add encrypted pages live demo page

- New password-protected demo page (password: quartz) showing the plugin in action
- Link to demo from EncryptedPages plugin page with password hint callout

* feat: add encrypted-pages plugin to all templates

- Enabled by default in default, obsidian, and ttrpg templates
- Disabled by default in blog template

* chore: updated plugins

* chore: updated layouts

* chore: updated plugins

* feat: stacked pages

* feat: added stacked page panes

* docs: touch-ups
2026-03-14 18:10:02 +01:00
derfalx c2bea8a4c4 fix(citation): Language parameter for non en-US settings (#2075)
* Fix language parameter of the citation plugin for non en-US settings

Per default the rehype-citation project only supports en-US, as
explained here: https://github.com/timlrx/rehype-citation/issues/12
For other languages one can provide a locale-file either by passing
its path or providing an URL. The following repository contains locale
files for multiple languages. So, these are used, in case a non en-US
language is used in quarzt. But this optimistically assumes there is
indeed an according locale file.

In summary this solves the problem only partially, since there are
still some languages which will not work properly.

* Fixing code style by running prettier with --write

* Excluding `en-US` locales from the new behaviour.

* Removing unnecessary `null` und `undefined` check.

* Update quartz/plugins/transformers/citations.ts

* Update quartz/plugins/transformers/citations.ts

* Update quartz/plugins/transformers/citations.ts

---------

Co-authored-by: Jacky Zhao <j.zhao2k19@gmail.com>
2026-01-08 09:30:42 +08:00
Rithsagea e6cc9ba368 fix: pass mathjax macros to rehype correctly (#2218) 2025-12-06 22:51:37 -05:00
Lunyaa ef29c69828 add rybbit analytics (#2197) 2025-11-07 16:48:28 +01:00
Jiangnan Li af5773f0e4 fix(api): adapt to updated API parameter format from (#2185)
is-absolute-url v5.0.0
2025-10-31 16:59:46 -07:00
FishCat233 52460f376f fix: modified time data of frontmatter didnt loaded. (#2165) 2025-10-16 09:10:25 -07:00
martyone f14260b2ba fix(oxhugo): Do not discard embedded HTML (#2151)
In 'processors/parse.ts' the 'remarkRehype' plugin is used with
'allowDangerousHtml' enabled, but that needs to be combined with (e.g.)
'rehypeRaw' to have any effect on the output.
2025-10-02 10:51:40 -07:00
Emile Bangma 4923affa77 fix(callouts)!: match callout DOM to Obsidian (#2104)
* fix(callouts): match callout DOM to Obsidian

* use new transition curve for all callout transitions

* chore!: bump version to 4.5.2
2025-09-21 19:14:03 +02:00
Eritque arcus 8df8d5c6ef fix: fix CNAME path error (#2096)
* fix: fix CNAME path error

* chore: Update quartz/plugins/emitters/cname.ts

Co-authored-by: Jacky Zhao <j.zhao2k19@gmail.com>

* chore: remove unused import

---------

Co-authored-by: Jacky Zhao <j.zhao2k19@gmail.com>
2025-09-17 14:50:12 -07:00
siaikin e77a051144 feat(analytics): add support for Vercel Web Analytics provider (#2119)
* feat(analytics): add support for Vercel Web Analytics provider

* fix: correct indentation for Vercel analytics provider condition
2025-09-08 20:06:28 -07:00
John Barker e918f11652 feat: add support for matomo analytics (#2051)
* feat: Support Matomo as analytics provider (self-hosted)

* SPA support

* Don't use var

* inline

* Revert fixing issues outside of this change
2025-08-12 23:56:04 -04:00
Abhi 059848f8b0 fix(rss): add cdata to escape html content for rss feed (#2046)
* add cdata to escape html content

* fix: remove redundant CDATA
2025-07-14 10:00:38 +02:00
Wen Taichi 7253557d2c fix(goatcounter): properly count SPA page hits (#2035)
1. Should not create new instance after count.js, as it already setup an
instance.
2. Script block would be removed when navigating with SPA, and it cause
count.js can not find endpoint by query. The solution is to set
endpoint manually.
2025-07-07 22:52:49 -04:00
Jacky Zhao 1cfc87652c fix: tz-less date parse in local tz instead of utc (closes #1615) 2025-06-01 22:42:37 -07:00
fl0werpowers 951d1dec24 chore(deps): replace chalk and rimraf with builtin functions (#1879)
Co-authored-by: Copilot <175728472+Copilot@users.noreply.github.com>
2025-05-28 10:40:51 +02:00
Keisuke ANDO 51b43a2115 feat(links): added ofm option to style unresolved or broken links differently (#1992)
* feat: add option to disable broken wikilinks

* fix(style): update hover color for broken links and introduce new class

* feat: add "disableBrokenWikilinks" option to ObsidianFlavoredMarkdown
2025-05-27 21:26:17 +02:00
Aswanth 6d49d97559 fix(analytics): streamline posthog script loading and event capturing (#1974) 2025-05-24 00:55:07 -04:00
Emile Bangma fec0a62b74 fix(ofm): allow wikilink alias to be empty (#1984)
This is in line with Obsidian's behavior.
2025-05-19 07:58:05 +02:00
Dan 59d4b4eddd fix(analytics): Umami tracking pageviews properly
Update componentResources.ts to fix umami SPA tracking (#1967)

Update componentResources.ts to fix umami analytics when SPA is enabled in Quartz
2025-05-07 21:44:30 +02:00
dralagen 6ba9c7c02a doc(favicon): add documentation of favicon plugin (#1948)
* doc(favicon): add documentation of favicon plugin

* doc(favicon): add missing link to configuration page

* fix(favicon): build on public folder don't created
2025-04-28 22:00:28 -07:00
dralagen 9e58857746 feat(favicon): add plugin to expose favicon from icon.png (#1942)
* feat(favicon): add plugin to expose favicon from icon.png

* chore(favicon): clean up formatting and remove unnecessary line breaks
2025-04-26 11:06:59 -07:00
Stephen Tse 4bd714b7be fix(callout): Grid-based callout collapsible animation (#1944)
* Fixed broken nested callout maxHeight calculation

* Implemented grid-based callout collapsible
2025-04-26 11:05:51 -07:00
Jacky Zhao cdebd05dc9 fix(wikilinks): dont default empty alias 2025-04-23 09:30:25 -07:00
Jacky Zhao 2a9290b3df fix(transclude): blockref detection 2025-04-22 11:18:50 -07:00
Emile Bangma d61fb266c7 fix(popover): automatically position anchored links properly (#1897)
* fix(popover): automatically position heading links at heading

* Impement linking of blockreferences

* Popover fixes

* id mapping

* Remove excess regexes

* Updated blockref

* Remove linker element

* Restore the docs to their former glory

* Move the hash out of the loop

* Redundant

* Redundant

* Restore docs

* Remove log

* Let it const
2025-04-05 10:31:17 -07:00