Skip to content

Refactor(collaborative-editing): 协同编辑模块依赖注入#380

Merged
kagol merged 2 commits intoopentiny:mainfrom
Yinlin124:refactor/imp
Nov 5, 2025
Merged

Refactor(collaborative-editing): 协同编辑模块依赖注入#380
kagol merged 2 commits intoopentiny:mainfrom
Yinlin124:refactor/imp

Conversation

@Yinlin124
Copy link
Copy Markdown
Contributor

@Yinlin124 Yinlin124 commented Nov 2, 2025

PR

PR Type

What kind of change does this PR introduce?

  • Refactoring (no functional changes, no api changes)
  • Build related changes
  • Documentation content changes

What is the current behavior?

  • 将协同编辑模块所有依赖改为动态导入
  • 后端初始配置密码改为 admin 与后端包保持一致

Summary by CodeRabbit

  • New Features

    • Added collaborative editing support with dynamic module loading for real-time multi-user editing.
    • Enabled WebSocket and WebRTC-based collaboration providers for flexible connectivity options.
    • Added IndexedDB persistence to maintain editing sessions offline.
    • Implemented multi-user cursor tracking to display other collaborators' positions.
  • Documentation

    • Updated guides with collaborative editing setup and configuration examples.
  • Chores

    • Added collaborative editing dependencies.
    • Updated MongoDB configuration defaults.

@coderabbitai
Copy link
Copy Markdown

coderabbitai Bot commented Nov 2, 2025

Walkthrough

Introduced dependency injection for Yjs and collaborative editing components across multiple modules. Added new runtime dependencies (yjs, y-websocket, y-webrtc, y-quill, y-protocols, y-indexeddb, quill-cursors) and created a CollaborativeEditingDeps interface to abstract these dependencies. Refactored providers, awareness utilities, and the collaborative editor core to accept and validate injected dependencies instead of direct imports.

Changes

Cohort / File(s) Summary
Demo & Documentation Updates
packages/docs/fluent-editor/demos/collaborative-editing.vue, packages/docs/fluent-editor/docs/demo/collaborative-editing.md
Added dynamic imports for Yjs dependencies during module initialization; registered collaborative editing module with deps object containing Y, Awareness, QuillBinding, QuillCursors, WebsocketProvider, and IndexeddbPersistence; updated both WebSocket and WebRTC examples to use new dynamic import and registration pattern; updated MongoDB credentials from admin!123 to admin
Package Dependencies
packages/docs/package.json
Added runtime dependencies: quill-cursors, y-indexeddb, y-protocols, y-quill, y-webrtc, y-websocket, yjs
Type Definitions
packages/fluent-editor/src/modules/collaborative-editing/types.ts
Introduced new exported interface CollaborativeEditingDeps encapsulating Y, Awareness, QuillBinding, QuillCursors, WebsocketProvider, WebrtcProvider, and IndexeddbPersistence; augmented YjsOptions with optional deps field; tightened onError callback typing from generic to (error: Error) => void
Collaborative Editor Core
packages/fluent-editor/src/modules/collaborative-editing/collaborative-editing.ts
Introduced dependency injection via deps parameter; added mandatory dependency resolution on construction; replaced eager ydoc initialization with optional provisioning; stored deps on instance and propagated through provider creation; updated bindAwarenessToCursors and IndexedDB setup calls to use injected dependencies
Provider Registry
packages/fluent-editor/src/modules/collaborative-editing/provider/providerRegistry.ts
Added optional deps?: CollaborativeEditingDeps field to ProviderConstructorProps<T>
WebSocket Provider
packages/fluent-editor/src/modules/collaborative-editing/provider/websocket.ts
Added deps parameter to constructor; updated WebsocketProviderOptions interface (narrowed awareness type to Awareness, added resyncInterval, maxBackoffTime, disableBc fields); added dependency validation for WebsocketProvider
WebRTC Provider
packages/fluent-editor/src/modules/collaborative-editing/provider/webrtc.ts
Added deps parameter to constructor; added dependency validation for WebrtcProvider; updated document and awareness initialization to use injected or default instances
Awareness Utilities
packages/fluent-editor/src/modules/collaborative-editing/awareness/awareness.ts, packages/fluent-editor/src/modules/collaborative-editing/awareness/y-indexeddb.ts
Added Yjs namespace parameter to bindAwarenessToCursors; replaced direct Yjs API calls with injected parameter; introduced dependency injection for IndexeddbPersistenceClass in setupIndexedDB with warning fallback when not provided

Sequence Diagram

sequenceDiagram
    participant App as Application
    participant CE as CollaborativeEditor
    participant Registry as Provider Registry
    participant Provider as WebsocketProvider
    participant Awareness as Awareness Module
    participant Deps as Injected Deps

    App->>App: Prepare deps object<br/>(Y, Awareness, WebsocketProvider, etc.)
    App->>CE: Initialize with options.deps
    
    CE->>Deps: Resolve Y, Awareness,<br/>QuillBinding, QuillCursors
    alt Missing dependencies
        Deps-->>CE: Error (throw)
    else All present
        CE->>CE: Store deps on instance
        CE->>Registry: Create provider<br/>with deps
        Registry->>Provider: Instantiate<br/>WebsocketProvider
        Provider->>Deps: Validate WebsocketProvider
        alt Valid
            Provider->>Provider: Initialize
        else Invalid
            Deps-->>Provider: Error (throw)
        end
        
        CE->>Awareness: bindAwarenessToCursors<br/>(awareness, cursors, quill,<br/>yText, Yjs namespace)
        Awareness->>Deps: Use injected Yjs<br/>for position utilities
    end
Loading

Estimated code review effort

🎯 3 (Moderate) | ⏱️ ~20–25 minutes

  • Dependency validation logic: Each provider class validates its required dependencies; ensure error handling is consistent and informative across WebsocketProviderWrapper and WebRTCProviderWrapper
  • Type correctness: Verify CollaborativeEditingDeps interface completeness and that all injected dependencies are properly typed throughout the codebase
  • Constructor parameter handling: Check that deps resolution follows the same pattern in collaborative-editing.ts, providers, and utility functions (awareness.ts, y-indexeddb.ts)
  • Public API changes: Constructor signatures for WebsocketProviderWrapper and WebRTCProviderWrapper now include deps parameter; confirm backward compatibility or document breaking changes
  • Module registration flow: Verify dynamic import and registration in demo files correctly supplies all required dependencies to the collaborative editing module

Poem

🐰 A hoppy refactor brings structured cheer,
Deps injected, dependencies clear,
No more hardcoded paths to chase,
Yjs components find their place,
Collaboration now takes form with grace! 🌿✨

Pre-merge checks and finishing touches

❌ Failed checks (1 warning)
Check name Status Explanation Resolution
Docstring Coverage ⚠️ Warning Docstring coverage is 0.00% which is insufficient. The required threshold is 80.00%. You can run @coderabbitai generate docstrings to improve docstring coverage.
✅ Passed checks (2 passed)
Check name Status Explanation
Description Check ✅ Passed Check skipped - CodeRabbit’s high-level summary is enabled.
Title Check ✅ Passed The pull request title "Refactor(collaborative-editing): 协同编辑模块依赖注入" directly and accurately describes the primary refactoring effort captured in the changeset. The changes across multiple files consistently implement dependency injection for the collaborative-editing module by introducing a CollaborativeEditingDeps interface and updating constructors and functions to accept injected dependencies rather than relying on global imports. The title is specific to the module and the architectural pattern being implemented, clearly conveying the main intent of the refactoring. While the secondary backend password configuration change is not explicitly mentioned in the title, this aligns with the stated instruction that titles need not cover every detail of the changeset. The title uses a standard "Refactor" prefix with the module name, making it scannable and professional, despite the inclusion of Chinese text which may affect readability for some developers.
✨ Finishing touches
  • 📝 Generate docstrings
🧪 Generate unit tests (beta)
  • Create PR with unit tests
  • Post copyable unit tests in a comment

Thanks for using CodeRabbit! It's free for OSS, and your support helps us grow. If you like it, consider giving us a shout-out.

❤️ Share

Comment @coderabbitai help to get the list of available commands and usage tips.

Copy link
Copy Markdown

@coderabbitai coderabbitai Bot left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Actionable comments posted: 2

Caution

Some comments are outside the diff and can’t be posted inline due to platform limitations.

⚠️ Outside diff range comments (1)
packages/fluent-editor/src/modules/collaborative-editing/awareness/y-indexeddb.ts (1)

12-16: Store persistence instance and use clearData() for cleanup.

The current cleanup uses indexedDB.deleteDatabase(), but the learned best practice is to use persistence.clearData() which properly closes connections and removes database metadata. The persistence instance should be stored to enable proper cleanup.

Based on learnings

Apply this diff:

 export function setupIndexedDB(doc: Y.Doc, IndexeddbPersistenceClass?: typeof IndexeddbPersistence): () => void {
   if (!IndexeddbPersistenceClass) {
     console.warn('[yjs] IndexeddbPersistence not provided, offline support disabled')
     return () => {}
   }
 
   const fullDbName = `tiny-editor-${doc.guid}`
 
-  new IndexeddbPersistenceClass(fullDbName, doc)
+  const persistence = new IndexeddbPersistenceClass(fullDbName, doc)
 
   return (): void => {
-    indexedDB.deleteDatabase(fullDbName)
+    persistence.clearData()
   }
 }
📜 Review details

Configuration used: CodeRabbit UI

Review profile: CHILL

Plan: Pro

📥 Commits

Reviewing files that changed from the base of the PR and between 57fff2a and 56e12fc.

⛔ Files ignored due to path filters (1)
  • pnpm-lock.yaml is excluded by !**/pnpm-lock.yaml
📒 Files selected for processing (10)
  • packages/docs/fluent-editor/demos/collaborative-editing.vue (2 hunks)
  • packages/docs/fluent-editor/docs/demo/collaborative-editing.md (7 hunks)
  • packages/docs/package.json (1 hunks)
  • packages/fluent-editor/src/modules/collaborative-editing/awareness/awareness.ts (4 hunks)
  • packages/fluent-editor/src/modules/collaborative-editing/awareness/y-indexeddb.ts (1 hunks)
  • packages/fluent-editor/src/modules/collaborative-editing/collaborative-editing.ts (4 hunks)
  • packages/fluent-editor/src/modules/collaborative-editing/provider/providerRegistry.ts (2 hunks)
  • packages/fluent-editor/src/modules/collaborative-editing/provider/webrtc.ts (2 hunks)
  • packages/fluent-editor/src/modules/collaborative-editing/provider/websocket.ts (2 hunks)
  • packages/fluent-editor/src/modules/collaborative-editing/types.ts (2 hunks)
🧰 Additional context used
🧠 Learnings (3)
📚 Learning: 2025-09-11T03:19:54.210Z
Learnt from: vaebe
Repo: opentiny/tiny-editor PR: 338
File: packages/fluent-editor/src/modules/collaborative-editing/awareness/y-indexeddb.ts:9-13
Timestamp: 2025-09-11T03:19:54.210Z
Learning: In y-indexeddb cleanup functions, use persistence.clearData() instead of raw indexedDB.deleteDatabase() calls. The clearData() method properly closes connections and removes database metadata, while raw deleteDatabase() can leave hanging promises and open handles.

Applied to files:

  • packages/fluent-editor/src/modules/collaborative-editing/awareness/y-indexeddb.ts
  • packages/fluent-editor/src/modules/collaborative-editing/collaborative-editing.ts
📚 Learning: 2025-10-29T06:42:59.434Z
Learnt from: vaebe
Repo: opentiny/tiny-editor PR: 365
File: packages/fluent-editor/vite.config.ts:18-26
Timestamp: 2025-10-29T06:42:59.434Z
Learning: In projects using Quill editor: `Quill.import('parchment')` dynamically loads parchment from Quill's internal registry at runtime and does not require a direct dependency on the parchment package. Only type imports like `import type { Root } from 'parchment'` may be needed, which can be satisfied by having parchment in devDependencies.

Applied to files:

  • packages/docs/fluent-editor/demos/collaborative-editing.vue
  • packages/docs/package.json
  • packages/docs/fluent-editor/docs/demo/collaborative-editing.md
  • packages/fluent-editor/src/modules/collaborative-editing/awareness/awareness.ts
  • packages/fluent-editor/src/modules/collaborative-editing/types.ts
📚 Learning: 2025-09-23T02:27:09.479Z
Learnt from: Yinlin124
Repo: opentiny/tiny-editor PR: 346
File: packages/fluent-editor/src/modules/collaborative-editing/awareness/awareness.ts:65-70
Timestamp: 2025-09-23T02:27:09.479Z
Learning: The moveCursor method from quill-cursors library has built-in negative value checking/handling, so manual normalization of negative length values is not required when calling cursorsModule.moveCursor().

Applied to files:

  • packages/fluent-editor/src/modules/collaborative-editing/awareness/awareness.ts
🧬 Code graph analysis (5)
packages/fluent-editor/src/modules/collaborative-editing/provider/providerRegistry.ts (1)
packages/fluent-editor/src/modules/collaborative-editing/types.ts (1)
  • CollaborativeEditingDeps (38-46)
packages/fluent-editor/src/modules/collaborative-editing/provider/websocket.ts (1)
packages/fluent-editor/src/modules/collaborative-editing/types.ts (2)
  • CollaborativeEditingDeps (38-46)
  • ProviderEventHandlers (11-16)
packages/fluent-editor/src/modules/collaborative-editing/provider/webrtc.ts (1)
packages/fluent-editor/src/modules/collaborative-editing/types.ts (2)
  • CollaborativeEditingDeps (38-46)
  • ProviderEventHandlers (11-16)
packages/fluent-editor/src/modules/collaborative-editing/collaborative-editing.ts (4)
packages/fluent-editor/src/modules/collaborative-editing/provider/providerRegistry.ts (1)
  • UnifiedProvider (20-29)
packages/fluent-editor/src/modules/collaborative-editing/types.ts (2)
  • CollaborativeEditingDeps (38-46)
  • YjsOptions (48-60)
packages/fluent-editor/src/modules/collaborative-editing/awareness/awareness.ts (1)
  • bindAwarenessToCursors (35-142)
packages/fluent-editor/src/modules/collaborative-editing/awareness/y-indexeddb.ts (1)
  • setupIndexedDB (4-17)
packages/fluent-editor/src/modules/collaborative-editing/types.ts (1)
packages/fluent-editor/src/modules/collaborative-editing/awareness/awareness.ts (1)
  • AwarenessOptions (17-21)
🔇 Additional comments (14)
packages/fluent-editor/src/modules/collaborative-editing/provider/providerRegistry.ts (1)

17-17: LGTM!

The addition of the optional deps field to ProviderConstructorProps correctly enables dependency injection for provider implementations, aligning with the broader refactoring goal.

packages/docs/fluent-editor/demos/collaborative-editing.vue (2)

54-69: LGTM!

The dynamic imports and destructuring correctly implement the dependency injection pattern, enabling runtime loading of Yjs-related modules.


108-115: Deps object correctly configured.

The dependency injection configuration properly wires all required Yjs components (Y, Awareness, QuillBinding, QuillCursors, WebsocketProvider, IndexeddbPersistence) for collaborative editing.

packages/fluent-editor/src/modules/collaborative-editing/awareness/y-indexeddb.ts (1)

5-8: LGTM!

The validation and graceful degradation when IndexeddbPersistence is not provided ensures offline support can be optionally disabled without breaking the application.

packages/fluent-editor/src/modules/collaborative-editing/awareness/awareness.ts (2)

35-41: LGTM!

The addition of the Yjs parameter enables dependency injection for the Y namespace, replacing the previous direct import pattern. This aligns with the broader refactoring goal.


55-56: Yjs namespace correctly used throughout.

All Y.* API calls have been properly updated to use the injected Yjs parameter, ensuring consistency with the dependency injection pattern.

Also applies to: 79-80, 84-85

packages/fluent-editor/src/modules/collaborative-editing/types.ts (2)

38-46: LGTM!

The CollaborativeEditingDeps interface correctly defines the dependency injection contract, with core dependencies (Y, Awareness, QuillBinding, QuillCursors) as required and provider-specific dependencies (WebsocketProvider, WebrtcProvider, IndexeddbPersistence) as optional.


54-54: Good type improvements.

Adding the deps field to YjsOptions and tightening the onError callback type to (error: Error) => void improve type safety.

Also applies to: 58-58

packages/fluent-editor/src/modules/collaborative-editing/collaborative-editing.ts (3)

24-32: Good validation for required dependencies.

The dependency validation ensures that core collaborative editing components (Y, Awareness, QuillBinding, QuillCursors) are available before proceeding. The fallback to window when deps is not provided maintains backward compatibility while the validation catches missing dependencies.


34-50: Correct dependency usage in initialization.

The injected dependencies are properly used to instantiate the Yjs document, cursors module, and awareness, ensuring the refactored code uses the provided implementations.


64-64: Dependencies correctly propagated.

The deps object is properly passed to provider creation (line 64), the Y namespace to awareness binding (line 78), and IndexeddbPersistence to offline storage setup (line 90).

Also applies to: 78-78, 90-90

packages/fluent-editor/src/modules/collaborative-editing/provider/websocket.ts (2)

11-11: Good type improvements.

Tightening the awareness type from any to Awareness and adding explicit optional fields (resyncInterval, maxBackoffTime, disableBc) to WebsocketProviderOptions improves type safety.

Also applies to: 15-17


78-97: Dependency injection correctly implemented.

The constructor properly accepts and validates the deps parameter, extracting required Yjs components (Y, Awareness, WebsocketProvider) and using them to instantiate the document, awareness, and provider. The validation on lines 92-94 ensures WebsocketProvider is available before proceeding.

packages/docs/package.json (1)

27-41: No security advisories found; verify quill-cursors minor patch availability.

Verification confirms that all Yjs-related dependencies are free from known security vulnerabilities. Six packages are already on their latest versions, and quill-cursors@4.0.3 has a newer patch available (4.0.4). Consider updating quill-cursors to the latest patch version if compatibility is confirmed.

Comment on lines +36 to 79
import FluentEditor from '@opentiny/fluent-editor'

let editor
const editorRef = document.querySelector('#editor')

Promise.all([
import('@opentiny/fluent-editor'),
import('yjs'),
import('y-protocols/awareness'),
import('y-quill'),
import('y-websocket'),
import('y-indexeddb'),
import('quill-cursors'),
]).then(
([
{ default: FluentEditor, CollaborationModule },
Y,
{ Awareness },
{ QuillBinding },
{ WebsocketProvider },
{ IndexeddbPersistence },
{ default: QuillCursors },
]) => {
FluentEditor.register('modules/collaborative-editing', CollaborationModule, true)

editor = new FluentEditor(editorRef, {
theme: 'snow',
modules: {
'collaborative-editing': {
deps: { Y, Awareness, QuillBinding, QuillCursors, WebsocketProvider, IndexeddbPersistence },
provider: {
type: 'websocket',
options: {
serverUrl: 'wss://demos.yjs.dev/ws',
roomName: 'Tiny-Editor-Demo',
},
},
},
},
},
})
},
).catch((error) => {
console.error('Failed to initialize FluentEditor:', error)
})
Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

⚠️ Potential issue | 🟠 Major

Remove the static import to keep the example fully dynamic.

This section is supposed to demonstrate lazy-loading all collaborative-editing dependencies, but the top-level import FluentEditor from '@opentiny/fluent-editor' keeps the module (and its transitive deps) eagerly bundled. That defeats the goal of dependency injection and duplicates the subsequent dynamic import call. Please drop the static import and rely on the FluentEditor binding returned inside Promise.all.

-import FluentEditor from '@opentiny/fluent-editor'
-
-let editor
+let editor
🤖 Prompt for AI Agents
packages/docs/fluent-editor/docs/demo/collaborative-editing.md lines 36-79:
remove the top-level static import "import FluentEditor from
'@opentiny/fluent-editor'" so the example truly lazy-loads all dependencies;
rely on the FluentEditor binding returned by the dynamic import in Promise.all
(ensure the destructured default FluentEditor is used where the static one was
referenced) and keep the rest of the Promise.all dynamic imports/usage
unchanged.

Comment on lines +257 to 300
import FluentEditor from '@opentiny/fluent-editor'

let editor
const editorRef = document.querySelector('#editor')

Promise.all([
import('@opentiny/fluent-editor'),
import('yjs'),
import('y-protocols/awareness'),
import('y-quill'),
import('y-webrtc'),
import('y-indexeddb'),
import('quill-cursors'),
]).then(
([
{ default: FluentEditor, CollaborationModule },
Y,
{ Awareness },
{ QuillBinding },
{ WebrtcProvider },
{ IndexeddbPersistence },
{ default: QuillCursors },
]) => {
FluentEditor.register('modules/collaborative-editing', CollaborationModule, true)

editor = new FluentEditor(editorRef, {
theme: 'snow',
modules: {
'collaborative-editing': {
deps: { Y, Awareness, QuillBinding, QuillCursors, WebrtcProvider, IndexeddbPersistence },
provider: {
type: 'webrtc',
options: {
roomName: 'Tiny-Editor-WebRTC',
signaling: ['wss://signaling.yjs.dev'],
},
},
},
},
},
})
},
).catch((error) => {
console.error('Failed to initialize FluentEditor:', error)
})
Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

⚠️ Potential issue | 🟠 Major

Mirror the dynamic loading pattern in the WebRTC example.

The WebRTC snippet still performs a static import FluentEditor ..., so the collaborative-editing bundle is eagerly pulled in despite the new lazy Promise.all loader. Remove that static import so the docs accurately reflect the dynamic dependency injection workflow and avoid bundling regressions for consumers.

-import FluentEditor from '@opentiny/fluent-editor'
-
-let editor
+let editor
📝 Committable suggestion

‼️ IMPORTANT
Carefully review the code before committing. Ensure that it accurately replaces the highlighted code, contains no missing lines, and has no issues with indentation. Thoroughly test & benchmark the code to ensure it meets the requirements.

Suggested change
import FluentEditor from '@opentiny/fluent-editor'
let editor
const editorRef = document.querySelector('#editor')
Promise.all([
import('@opentiny/fluent-editor'),
import('yjs'),
import('y-protocols/awareness'),
import('y-quill'),
import('y-webrtc'),
import('y-indexeddb'),
import('quill-cursors'),
]).then(
([
{ default: FluentEditor, CollaborationModule },
Y,
{ Awareness },
{ QuillBinding },
{ WebrtcProvider },
{ IndexeddbPersistence },
{ default: QuillCursors },
]) => {
FluentEditor.register('modules/collaborative-editing', CollaborationModule, true)
editor = new FluentEditor(editorRef, {
theme: 'snow',
modules: {
'collaborative-editing': {
deps: { Y, Awareness, QuillBinding, QuillCursors, WebrtcProvider, IndexeddbPersistence },
provider: {
type: 'webrtc',
options: {
roomName: 'Tiny-Editor-WebRTC',
signaling: ['wss://signaling.yjs.dev'],
},
},
},
},
},
})
},
).catch((error) => {
console.error('Failed to initialize FluentEditor:', error)
})
let editor
const editorRef = document.querySelector('#editor')
Promise.all([
import('@opentiny/fluent-editor'),
import('yjs'),
import('y-protocols/awareness'),
import('y-quill'),
import('y-webrtc'),
import('y-indexeddb'),
import('quill-cursors'),
]).then(
([
{ default: FluentEditor, CollaborationModule },
Y,
{ Awareness },
{ QuillBinding },
{ WebrtcProvider },
{ IndexeddbPersistence },
{ default: QuillCursors },
]) => {
FluentEditor.register('modules/collaborative-editing', CollaborationModule, true)
editor = new FluentEditor(editorRef, {
theme: 'snow',
modules: {
'collaborative-editing': {
deps: { Y, Awareness, QuillBinding, QuillCursors, WebrtcProvider, IndexeddbPersistence },
provider: {
type: 'webrtc',
options: {
roomName: 'Tiny-Editor-WebRTC',
signaling: ['wss://signaling.yjs.dev'],
},
},
},
},
})
},
).catch((error) => {
console.error('Failed to initialize FluentEditor:', error)
})
🤖 Prompt for AI Agents
packages/docs/fluent-editor/docs/demo/collaborative-editing.md around lines 257
to 300: the file still uses a static top-level "import FluentEditor ..." which
defeats the lazy Promise.all dynamic loader; remove that static import line so
FluentEditor is only loaded via the Promise.all import (which already returns
default: FluentEditor), and ensure there are no duplicate declarations or
unresolved references to FluentEditor elsewhere in this snippet so the dynamic
import result is used exclusively.

@kagol kagol merged commit e87aa53 into opentiny:main Nov 5, 2025
5 of 6 checks passed
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

3 participants