mirror of
https://github.com/Afilmory/afilmory
synced 2026-05-01 10:16:40 +00:00
- Introduced a comprehensive `DEVELOPMENT.md` guide for contributors and self-hosters, detailing workspace layout and common commands. - Updated `README.md` to include links to the new development guide and improved deployment instructions. - Added new documentation files covering architecture, builder pipeline, configuration, and deployment strategies. - Implemented new storage provider documentation for Backblaze B2, Eagle, GitHub, and local storage options. - Enhanced the UI components with new features, including a navigation context and improved theme handling. - Removed outdated GitHub Action deployment documentation. Signed-off-by: Innei <tukon479@gmail.com>
172 lines
5.7 KiB
Plaintext
172 lines
5.7 KiB
Plaintext
---
|
|
title: Plugins
|
|
description: Lifecycle hooks, authoring a custom plugin, and built-in plugins.
|
|
createdAt: 2025-11-23T19:00:00+08:00
|
|
lastModified: 2025-11-23T19:40:52+08:00
|
|
order: 5
|
|
---
|
|
|
|
# Plugins
|
|
|
|
Plugins extend the builder without forking its core. They are plain objects with lifecycle hooks, optional `onInit`, and can be registered inline, as factories, or via async ESM importers.
|
|
|
|
## Lifecycle surface
|
|
|
|
Hook names map directly to `packages/builder/src/plugins/types.ts`:
|
|
|
|
- `onInit` — once per process, after config is resolved.
|
|
- `beforeBuild` / `afterBuild` — whole run.
|
|
- `afterManifestLoad` — existing manifest is available.
|
|
- `afterAllFilesListed` → `afterLivePhotoDetection` → `afterImagesListed` → `afterTasksPrepared` — storage discovery.
|
|
- `beforeProcessTasks` / `afterProcessTasks` — batch level.
|
|
- `beforePhotoProcess` / `afterPhotoProcess` / `photoProcessError` — per photo.
|
|
- `beforeAddManifestItem` — right before an item is pushed.
|
|
- `beforeSaveManifest` / `afterSaveManifest` — final write.
|
|
- `afterCleanup` — after orphaned thumbnail cleanup.
|
|
- `onError` — uncaught errors.
|
|
|
|
All hooks receive `{ builder, config, logger, options, pluginName, pluginOptions, runShared, payload }`.
|
|
|
|
## Writing your first plugin
|
|
|
|
Minimal inline plugin (skips GIFs):
|
|
|
|
```typescript
|
|
// builder.config.ts
|
|
import { defineBuilderConfig } from '@afilmory/builder'
|
|
|
|
const skipGifsPlugin = {
|
|
name: 'skip-gifs',
|
|
hooks: {
|
|
afterTasksPrepared: async ({ payload }) => {
|
|
payload.tasks = payload.tasks.filter((t) => !t.key.toLowerCase().endsWith('.gif'))
|
|
},
|
|
},
|
|
}
|
|
|
|
export default defineBuilderConfig(() => ({
|
|
storage: { provider: 'local', basePath: './photos', baseUrl: '/photos' },
|
|
plugins: [skipGifsPlugin],
|
|
}))
|
|
```
|
|
|
|
Factory with options:
|
|
|
|
```typescript
|
|
function watermarkPlugin(options: { text: string }) {
|
|
return {
|
|
name: 'watermark',
|
|
hooks: {
|
|
afterPhotoProcess: async ({ payload }) => {
|
|
if (!payload.result.item) return
|
|
payload.result.item.description += ` | ${options.text}`
|
|
},
|
|
},
|
|
}
|
|
}
|
|
|
|
export default defineBuilderConfig(() => ({
|
|
storage: { provider: 's3', bucket: process.env.S3_BUCKET_NAME! },
|
|
plugins: [watermarkPlugin({ text: '© Afilmory' })],
|
|
}))
|
|
```
|
|
|
|
Async importer (keeps bundles slim):
|
|
|
|
```typescript
|
|
export default defineBuilderConfig(() => ({
|
|
storage: { provider: 's3', bucket: process.env.S3_BUCKET_NAME! },
|
|
plugins: [() => import('./plugins/geo-tag-plugin.js')],
|
|
}))
|
|
```
|
|
|
|
## Patterns
|
|
|
|
- **Shared state**: use `runShared` (a `Map`) to cache data across hooks within one run.
|
|
- **Storage extensions**: `registerStorageProvider` lets a plugin add a custom storage provider before discovery.
|
|
- **Manifest mutations**: prefer `beforeAddManifestItem` or `afterPhotoProcess` for per-item edits; `beforeSaveManifest` for global edits.
|
|
- **I/O**: keep uploads/downloads async and respect `options` flags; avoid blocking the event loop in hooks.
|
|
|
|
## Built-in plugins
|
|
|
|
### GitHub repo sync (`githubRepoSyncPlugin`)
|
|
|
|
Purpose: cache thumbnails and `photos-manifest.json` in a Git repo to speed up CI/CD and enable sharing of built assets.
|
|
|
|
What it does
|
|
- `beforeBuild`: clones or pulls the repo into `assets-git`, ensures branch exists, creates `thumbnails/` and `photos-manifest.json` if missing, then symlinks them into `apps/web/public/thumbnails` and `apps/web/src/data/photos-manifest.json`.
|
|
- `afterBuild`: if `autoPush` and there are changes, commits and pushes to the configured branch (requires token).
|
|
|
|
Config example:
|
|
|
|
```typescript
|
|
import { defineBuilderConfig, githubRepoSyncPlugin } from '@afilmory/builder'
|
|
|
|
export default defineBuilderConfig(() => ({
|
|
storage: { provider: 's3', bucket: process.env.S3_BUCKET_NAME! },
|
|
plugins: [
|
|
githubRepoSyncPlugin({
|
|
enable: true,
|
|
autoPush: true,
|
|
repo: {
|
|
url: 'https://github.com/you/gallery-cache',
|
|
token: process.env.GIT_TOKEN,
|
|
branch: 'main',
|
|
},
|
|
}),
|
|
],
|
|
}))
|
|
```
|
|
|
|
Notes
|
|
- Requires Git in PATH.
|
|
- If token is absent, sync still reads but skips push.
|
|
- Safe to run repeatedly; it reuses `assets-git` and handles re-clone on pull failure.
|
|
|
|
### Thumbnail storage (`@afilmory/builder/plugins/thumbnail-storage`)
|
|
|
|
Purpose: upload generated thumbnails to your storage (default or a secondary storage config) and rewrite `thumbnailUrl` to point to the remote location.
|
|
|
|
What it does
|
|
- `beforeBuild`: resolves the target storage manager; can reuse default storage or a dedicated one you pass in `storageConfig`.
|
|
- `afterPhotoProcess`: uploads the thumbnail buffer once per run per file, caches remote URL, and mutates `payload.result.item.thumbnailUrl` to the remote URL.
|
|
|
|
Config example (reuse default storage):
|
|
|
|
```typescript
|
|
import thumbnailStoragePlugin from '@afilmory/builder/plugins/thumbnail-storage'
|
|
|
|
export default defineBuilderConfig(() => ({
|
|
storage: { provider: 's3', bucket: process.env.S3_BUCKET_NAME! },
|
|
plugins: [thumbnailStoragePlugin()],
|
|
}))
|
|
```
|
|
|
|
Config example (separate storage for thumbnails):
|
|
|
|
```typescript
|
|
import thumbnailStoragePlugin from '@afilmory/builder/plugins/thumbnail-storage'
|
|
|
|
export default defineBuilderConfig(() => ({
|
|
storage: { provider: 's3', bucket: process.env.S3_BUCKET_NAME! },
|
|
plugins: [
|
|
thumbnailStoragePlugin({
|
|
storageConfig: {
|
|
provider: 'b2',
|
|
bucketId: process.env.B2_BUCKET_ID!,
|
|
applicationKeyId: process.env.B2_KEY_ID!,
|
|
applicationKey: process.env.B2_KEY!,
|
|
},
|
|
prefix: 'thumbnails/',
|
|
contentType: 'image/jpeg',
|
|
}),
|
|
],
|
|
}))
|
|
```
|
|
|
|
Notes
|
|
- Deduplicates uploads per run via an in-memory set; safe for concurrent workers.
|
|
- If upload fails, it logs the error and leaves the local URL intact rather than failing the whole build.
|
|
|
|
Use these built-ins as references for structure, error handling, and hook usage when authoring your own plugins.
|