mirror of
https://github.com/toeverything/AFFiNE.git
synced 2026-09-21 03:03:15 +08:00
fix #15574 #### PR Dependency Tree * **PR #15575** 👈 This tree was auto-generated by [Charcoal](https://github.com/danerwilliams/charcoal) <!-- This is an auto-generated comment: release notes by coderabbit.ai --> ## Summary by CodeRabbit ## New Features * Added source-aware blob handling for current documents and page history. * Added document lifecycle support for trashing, restoring, and permanently deleting documents. * Copilot attachments now upload directly to session attachment endpoints. ## Bug Fixes * Document actions now complete before confirmations, notifications, and navigation proceed. * Improved cancellation, upload fallback, size-limit handling, and cloud synchronization reliability. * Invite-link expiration now remains reliable for long durations. * Improved synchronization for document permissions and reserved documents. ## Changes * Blob management now displays attachment icons instead of image previews. * Cloud synchronization now uses a unified batch protocol. <!-- end of auto-generated comment: release notes by coderabbit.ai -->
@blocksuite/affine-ext-loader
Blocksuite extension loader system for AFFiNE, providing a structured way to manage and load extensions in different contexts.
Usage
Basic Extension Provider
import { BaseExtensionProvider } from '@blocksuite/affine-ext-loader';
import { z } from 'zod';
// Create a custom provider with options
class MyProvider extends BaseExtensionProvider<
'my-scope',
{ enabled: boolean }
> {
name = 'MyProvider';
schema = z.object({
enabled: z.boolean(),
});
setup(context: Context<'my-scope'>, options?: { enabled: boolean }) {
super.setup(context, options);
// Custom setup logic
}
}
Store Extensions
import {
StoreExtensionProvider,
StoreExtensionManager,
} from '@blocksuite/affine-ext-loader';
import { z } from 'zod';
// Create a store provider with custom options
class MyStoreProvider extends StoreExtensionProvider<{ cacheSize: number }> {
override name = 'MyStoreProvider';
override schema = z.object({
cacheSize: z.number().min(0),
});
override setup(
context: StoreExtensionContext,
options?: { cacheSize: number }
) {
super.setup(context, options);
context.register([Ext1, Ext2, Ext3]);
}
}
// Create and use the store extension manager
const manager = new StoreExtensionManager([MyStoreProvider]);
manager.configure(MyStoreProvider, { cacheSize: 100 });
const extensions = manager.get('store');
View Extensions
import {
ViewExtensionProvider,
ViewExtensionManager,
} from '@blocksuite/affine-ext-loader';
import { z } from 'zod';
// Create a view provider with custom options
class MyViewProvider extends ViewExtensionProvider<{ theme: string }> {
override name = 'MyViewProvider';
override schema = z.object({
theme: z.enum(['light', 'dark']),
});
override setup(context: ViewExtensionContext, options?: { theme: string }) {
super.setup(context, options);
context.register([CommonExt]);
if (context.scope === 'page') {
context.register([PageExt]);
} else if (context.scope === 'edgeless') {
context.register([EdgelessExt]);
}
if (options?.theme === 'dark') {
context.register([DarkModeExt]);
}
}
// Override effect to run one-time initialization logic
override effect() {
// This will only run once per provider class
console.log('Initializing MyViewProvider');
// Register lit elements
this.registerLitElements();
}
}
// Create and use the view extension manager
const manager = new ViewExtensionManager([MyViewProvider]);
manager.configure(MyViewProvider, { theme: 'dark' });
// Get extensions for different view scopes
const pageExtensions = manager.get('page');
const edgelessExtensions = manager.get('edgeless');
One-time Initialization with Effect
View extensions support one-time initialization through the effect method. This method is called automatically during setup, but only once per provider class. It's useful for:
- Initializing global state
- Registering lit elements
- Setting up shared resources
class MyViewProvider extends ViewExtensionProvider {
override effect() {
// This will only run once, even if multiple instances are created
initializeGlobalState();
registerLitElements();
setupGlobalEventListeners();
}
}
Available View Scopes
The view extension system supports the following scopes:
page- Standard page viewedgeless- Edgeless (whiteboard) viewpreview-page- Page preview viewpreview-edgeless- Edgeless preview viewmobile-page- Mobile page viewmobile-edgeless- Mobile edgeless view
Extension Configuration
Extensions can be configured using the configure method:
// Set configuration directly
manager.configure(MyProvider, { enabled: true });
// Update configuration using a function
manager.configure(MyProvider, prev => {
if (!prev) return prev;
return {
...prev,
enabled: !prev.enabled,
};
});
// Remove configuration
manager.configure(MyProvider, undefined);
Dependency Injection
Both store and view extension managers support dependency injection:
// Access the manager through the di container
const viewManager = std.get(ViewExtensionManagerIdentifier);
const pagePreviewExtension = viewManager.get('preview-page');