@beeintel/batch-image 1.0.1 → 1.1.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (55) hide show
  1. package/README.md +186 -184
  2. package/dist/chunks/{AdjustToolPanel-BELqYSUR.js → AdjustToolPanel-DCNhkuE4.js} +29 -28
  3. package/dist/chunks/BackgroundToolPanel-D3TILm-m.js +43 -0
  4. package/dist/chunks/{BatchMaterials-niGKrga3.js → BatchMaterials-BPJeE3y9.js} +1 -1
  5. package/dist/chunks/BatchModeChoices-BuP83uOq.js +118 -0
  6. package/dist/chunks/{BatchOutputColorPicker-CCvmIF-b.js → BatchOutputColorPicker-CZoQzBII.js} +1 -1
  7. package/dist/chunks/BatchReferenceFields-B7SL__lu.js +308 -0
  8. package/dist/chunks/BeautifyToolPanel-DsTOjndh.js +220 -0
  9. package/dist/chunks/{BrandMarkToolPanel-FKxXth_3.js → BrandMarkToolPanel-Cob9bPYT.js} +319 -333
  10. package/dist/chunks/{ContentTrimControl-BQfigZPq.js → ContentTrimControl-CKNfHz_u.js} +1 -1
  11. package/dist/chunks/{CropToolPanel-BhSuHkYm.js → CropToolPanel-6MiynTP2.js} +60 -56
  12. package/dist/chunks/CutoutToolPanel-V-AUrbwz.js +78 -0
  13. package/dist/chunks/DisclosureToolPanel-DvouSIbA.js +72 -0
  14. package/dist/chunks/ExpandToolPanel-C98UZmBx.js +69 -0
  15. package/dist/chunks/{ImageEffectsToolPanel-BRLPIt4q.js → ImageEffectsToolPanel-hA0TlEix.js} +63 -52
  16. package/dist/chunks/{IpAuditToolPanel-DfY-mBSe.js → IpAuditToolPanel-BCQ8Kewh.js} +15 -13
  17. package/dist/chunks/{ListingToolPanel-B9Yh3LBK.js → ListingToolPanel-DH-xpvLp.js} +170 -184
  18. package/dist/chunks/{MaterialSelectionPlate-DhioUjdW.js → MaterialSelectionPlate-CQBIf6ZJ.js} +4 -4
  19. package/dist/chunks/MetadataToolPanel-z4RK3JCb.js +116 -0
  20. package/dist/chunks/{OrientToolPanel-BTrwaWBm.js → OrientToolPanel-BwtT0xKI.js} +2 -2
  21. package/dist/chunks/PluginActionFooter.vue_vue_type_script_setup_true_lang-DIRuJ1De.js +122 -0
  22. package/dist/chunks/ResizeToolPanel-BVeZbKJl.js +1171 -0
  23. package/dist/chunks/RetouchToolPanel-CqSzWVOK.js +358 -0
  24. package/dist/chunks/ShadowToolPanel-BgsCgLay.js +258 -0
  25. package/dist/chunks/SvgExportToolPanel-CdCXYYHF.js +208 -0
  26. package/dist/chunks/TranslationToolPanel-D4ETI6sf.js +102 -0
  27. package/dist/chunks/{UpscaleToolPanel-D0H-j2Tr.js → UpscaleToolPanel-D_hmQLEi.js} +44 -39
  28. package/dist/chunks/arrow-up-C1vBvuff.js +18 -0
  29. package/dist/chunks/{entry-DK9FjQZ_.js → entry-DVV89YMR.js} +7504 -7389
  30. package/dist/chunks/{loader-circle-UFoEem2a.js → loader-circle-GPucRX_4.js} +1 -1
  31. package/dist/chunks/{motionFeatures-D4miwXxc.js → motionFeatures-_pQ-ZW4p.js} +1 -1
  32. package/dist/chunks/{search-BjTSm1KS.js → search-CUAg5uDr.js} +1 -1
  33. package/dist/config.d.ts +6 -0
  34. package/dist/index.d.ts +1 -0
  35. package/dist/index.js +6 -5
  36. package/dist/resources.json +104 -94
  37. package/dist/slots.d.ts +2 -0
  38. package/dist/style.css +1 -1
  39. package/dist/tool-links.d.ts +10 -0
  40. package/dist/types/batch/public/config.d.ts +6 -0
  41. package/package.json +95 -95
  42. package/dist/chunks/BackgroundToolPanel-Dy_l8KFl.js +0 -41
  43. package/dist/chunks/BatchModeChoices-BRqn6zNI.js +0 -111
  44. package/dist/chunks/BatchReferenceFields-C4t7OSTw.js +0 -316
  45. package/dist/chunks/BeautifyToolPanel-Dc-ddaBC.js +0 -215
  46. package/dist/chunks/CutoutToolPanel-BfaZZSE_.js +0 -73
  47. package/dist/chunks/DisclosureToolPanel-B_oc5fld.js +0 -76
  48. package/dist/chunks/ExpandToolPanel-D_ZODTUZ.js +0 -67
  49. package/dist/chunks/MetadataToolPanel-KVrtb3K0.js +0 -104
  50. package/dist/chunks/PluginActionFooter.vue_vue_type_script_setup_true_lang-C2kJCYeA.js +0 -102
  51. package/dist/chunks/ResizeToolPanel-Ch_-WR74.js +0 -1178
  52. package/dist/chunks/RetouchToolPanel-BTS33Dsd.js +0 -350
  53. package/dist/chunks/ShadowToolPanel-DxJE4eyV.js +0 -254
  54. package/dist/chunks/SvgExportToolPanel-RHmuQARH.js +0 -219
  55. package/dist/chunks/TranslationToolPanel-B_qTA1hM.js +0 -125
package/README.md CHANGED
@@ -1,184 +1,186 @@
1
- # @beeintel/batch-image
2
-
3
- 正式包通过 `pnpm add @beeintel/batch-image@1.0.1` 安装,入口包括主模块、`style.css`、`processing`、`resources.json` 和 `node`。此前 `@batch-images/core` 的本地预发布包已更名;宿主应将所有主入口与子路径 import 一起更新。
4
-
5
- `1.0.1` 在工作台数据和保存的视图恢复完成前隐藏内容,保留布局测量;首次可见时直接呈现保存的工具分组,避免默认文件处理面板闪烁。左侧标签按 Figma 使用普通态 12px / 16px、选中态 14px / 20px,英文长标签允许换行。
6
-
7
- `1.0.0` 汇总 BeePOP 的宿主布局、语言与主题适配、任务/项目历史修复、本地工具以及远程结果采用恢复。PNG 输入可采用 JPEG 输出,声明 MIME 差异不阻塞结果,仍保留字节指纹、尺寸及任务身份校验。
8
-
9
- 2026-11-03 `0.3.0-ticket17.35`:按宿主需求移除图片声明 MIME 与真实格式一致性的拒绝条件。支持 PNG 输入、JPEG 输出及 MIME 声明未同步的结果;资产读取、版本恢复和导出按文件头识别类型,仅修正读取 Blob 的 MIME,不转码、不改变字节。仍核对资产身份、SHA-256、大小和尺寸,保留像素预算与解码校验;原任务恢复不重新生成或重复收费。
10
-
11
- 2026-11-03 `0.3.0-ticket17.34`:远程成功回执已保存但结果读取或校验失败时,任务明确标为“结果采用失败”,结束执行中状态并保留原图与回执;依赖步骤继续按失败前置阻塞。禁止通过普通失败重试重新生成,提供“重试采用原结果(不重新生成)”,沿原回执恢复并只采用一次。重开旧的处理中记录时沿原回执校验后同步收敛,不重新提交远程请求。
12
-
13
- 2026-11-03 `0.3.0-ticket17.33`:任务、版本、删除确认和导出浮层使用实例的 body overlay host,导入/任务/版本/导出使用不透明主题表面;手机工具区独立横向滚动,保留右侧任务/帮助入口。修复宿主项目清理、分组草稿恢复、全失败导出状态及处理中英文提示。状态恢复完成前暂不接受工具操作,同项目更新不重复恢复视图;任务浮层优先展示最近重试结果。库产物将内联 WASM/运行时模块还原为带摘要的独立资源,避免宿主 Vite 对超长 data URL 转换溢出;资源清单覆盖最终字节。
14
-
15
- 自定义持久化 Adapter 可实现 `persistence.removeBatch(batchId)` 配合 `loadBatch`/`list` 支持项目删除。核心先检查当前项目、未结束任务及跨页占用;内置 Adapter 只删除对应项目快照和匹配的旧快照,不批量删除可能由其它项目引用的资产。清理反馈在项目抽屉内显示;没有该能力的自定义 Adapter 显示明确错误,不静默成功。
16
-
17
- 2026-11-03 `0.3.0-ticket17.28`:宿主工作台按 BeePOP Figma 修正五类工具图标、侧栏位置、背景卡片素材和尺寸、主题色、header、footer 与空态。中文桌面概览宽 200px,英文侧栏宽 72px、按钮宽 60px,标签居中且包含在按钮背景内;英文概览宽 232px 并允许卡片随文字增高;具体工具宽 280px,宿主宽度不超过 760px 时切换上下布局。参数独立滚动、帮助、白底与元数据行为沿用 17.23。
18
-
19
- 每个实例的主题浮层容器 Teleport 到 document.body,导入遮罩覆盖宿主导航,不再被工作台容器裁切;卸载时随实例清理。宿主仍负责登录和计费。容器需有明确高度,不再要求至少 620px,短屏通过内部滚动保持操作可达。
20
-
21
- Explicit browser cutout models use `createBrowserCutoutCapability` with pinned model/runtime manifests; the resource contract, Worker hosting protocol and deferred inference boundary are documented in `docs/integration/cutout-resources.md` in the repository. Default adapters do not download model weights or select a paid fallback.
22
-
23
- The 1.0 release exposes the complete workbench UI, browser local tools, manual declaration, frozen-version format/ZIP export, and explicit per-instance external IO. Remote operations require a host Adapter. Authentication, pricing and product policy stay in the consumer. Actual model inference and backend AI acceptance are deferred separately; controlled adapters are not evidence of production AI quality.
24
-
25
- Build from repository root after `pnpm install --frozen-lockfile`:
26
-
27
- ```sh
28
- pnpm --filter @beeintel/batch-image build
29
- npm pack ./packages/batch-images --ignore-scripts --pack-destination ./artifacts
30
- ```
31
-
32
- Create the `artifacts` directory before packing. The resulting archive is `beeintel-batch-image-1.0.1.tgz`; consumers normally install `@beeintel/batch-image@1.0.1` from npm. Retain earlier published versions and their matching resource graphs for rollback. Import `BatchWorkspace`, `createBrowserBatchAdapter` from `@beeintel/batch-image` and import `@beeintel/batch-image/style.css`. Pass an explicit Adapter created with `{ namespace: 'your-opaque-context' }`. Mount the component inside a container with a defined height. Pinia is bundled privately; Vue is a peer shared with the consumer.
33
-
34
- Published candidate mapping (retain older artifacts/commits for rollback):
35
-
36
- | Candidate | Scope | Compatibility |
37
- | ------------------ | ------------------------------------------------------------------------------------------------------------------------------------------------------------ | --------------------------------------------------------------------------------------------------- |
38
- | `0.1.0-ticket02.0` | Original public metadata flow and workspace/artifact split | Original `createBatchWorkspace({adapter})` and metadata commands |
39
- | `0.2.0-ticket16.0` | Host controls/slots, instance lifecycle and integrated remote/resize/crop contracts | Original metadata calls retained; new capabilities require exact allowlist configuration |
40
- | `0.2.1-ticket12.0` | Migrated local tools, declaration, explicit source reads and format/ZIP export | Retains earlier contracts; optional external reader requires frozen hashes |
41
- | `0.3.0-ticket17.0` | Complete per-instance ports, versioned defaults/reset intent, owned previews, external Demo and container/CDN consumption | Snapshot envelope/contract remain version 1; protected original request identity is retained |
42
- | `0.3.0-ticket17.1` | Responsive Header groups across embedded widths; reversible deletion of verified local originals and results | Snapshot and task contracts unchanged; uploading, busy and unresolved local inputs remain protected |
43
- | `0.3.0-ticket17.2` | Known metadata/manual declaration/translation result localization and intrinsic mobile Header/rail track sizing | Stored reasons, image versions, parameters and task contracts unchanged |
44
- | `0.3.0-ticket17.3` | Task peek placement avoids its trigger on first render and when clamped in narrow hosts | Native touch/mouse/keyboard and hover remain available; stored tasks and image bytes unchanged |
45
- | `0.3.0-ticket17.4` | Latest-context lifecycle serialization, shared immutable values and known local no-change result localization | Snapshot/schema/params and original task identities unchanged; superseded context requests reject |
46
- | `0.3.0-ticket17.6` | Instance-owned material GPU/snapshots/overlays and readable dark import, preset, history and export surfaces; supersedes the local 17.5 validation candidate | Display-only; task identities, parameters, persistence and image bytes unchanged |
47
- | `0.3.0-ticket17.7` | Narrow hosts reserve usable canvas height when notices and tool panels are open; active local flights do not enter remote receipt polling | Existing task identities, original-ID recovery, parameters and image bytes unchanged |
48
- | `0.3.0-ticket17.8` | Lint cleanup and one source owner for existing content-trim result labels | Existing translations, saved reasons, execution parameters and image bytes unchanged |
49
-
50
- | `0.3.0-ticket17.9` | TAPD 1001027 host navigation slot, neutral selection/radio cards, unobstructed preview captions and vertical desktop filmstrip, two-step export and pending-work leave warning | Optional chrome/slot additions; parameters, modes, version/task identities and output pipeline retained |
51
-
52
- | `0.3.0-ticket17.10` | Narrow preview footer uses content height to keep wrapped captions and controls outside the picture | Desktop vertical filmstrip and all execution contracts retained |
53
-
54
- | `0.3.0-ticket17.11` | Compact native radio cards with visible labels; shared 33×16 switches with light/dark state colors; Logo actions stay on one row in narrow panels | Display-only; original modes, parameters, queues, persistence and output bytes retained |
55
-
56
- | `0.3.0-ticket17.12` | TAPD 1001032 local Logo feedback in eight locales, concise first-three cutout labels and spaced translation fields/footer without duplicated service self-check | Stored reasons, model identities, parameters and recovery retained; consumers still own the product mode allowlist and business action |
57
-
58
- | `0.3.0-ticket17.13` | Optional host visibility for service diagnostics and recheck controls | Default diagnostics remain visible; execution capability checks, tasks and image bytes are unchanged |
59
-
60
- Hosts can set `config.visibility.serviceStatus = false` to hide service availability diagnostics and the recheck action in tool footers. This only changes presentation; unavailable execution remains disabled. Omitting the option preserves existing diagnostics. Business action slots remain owned by the host.
61
-
62
- TAPD 1001032: known local Logo background failures are translated only at display; unknown host diagnostics remain verbatim. Quick, Standard and Precision Cutout labels omit model names while preserving the original mode IDs. All core modes remain available to explicit consumers; a host can expose only its approved modes through the existing capability configuration. Translation paragraphs use a 12px gap and the action footer uses 8px. Hiding that panel's service self-check does not enable unavailable execution. The host owns concise status, temporary pricing reference and any explanatory tooltip.
63
-
64
- TAPD 1001027 follow-up: generic text-field sizing excludes radio inputs. Switch geometry and state colors have one shared owner; orientation and export panels no longer redefine the same control. Logo background help and removal use fixed grid columns so English labels wrap without moving the removal action to a new row. Verify the published CSS in a real browser with `node packages/batch-images/tests/public-consumer-cdn.browser.mjs --ui-audit`; it measures card bounds and switch states in English/Chinese, light/dark and wide/narrow hosts. Evidence stays outside Git; `BATCH_CDN_EVIDENCE` selects its folder. Real model inference is not part of this check.
65
-
66
- The component receives `adapter`, `config`, `display`, and `revision`, emits `event`, and exposes `command`, `snapshot`, `subscribe`, `dispose`. Explicit mounting uses `createBatchWorkspace({ adapter, config, display }).mount(element)`, with the same handle and implementation. `updateContext` changes the opaque Adapter namespace/revision through the same persistence and lifecycle barriers. Each instance owns its Pinia, translation, theme and overlay target.
67
-
68
- For Vite development consumption, configure `optimizeDeps.exclude: ['@beeintel/batch-image']` so dependency prebundling does not relocate the emitted relative Worker URLs. Production builds consume the bundled package graph directly; no source alias is required.
69
-
70
- Commands include `importFiles`, `openTool`, `runTool`, `runMetadataCleanup`, `select`, `exportCurrent`, `newBatch`, `openBatch`, `restoreVersion`, `resetDraft`, and `updateConfig`. Tool commands return a queued operation identity; `status: completed` means the command was handled, not that image processing succeeded. Observe immutable events/snapshots until an attempt is `succeeded` and `applied`; check failures too. `exportCurrent` reads the frozen current versions, validates their bytes, returns files and invokes the optional Adapter download handler. It never exports the input in place of an adopted result.
71
-
72
- `config.capabilities` is an exact allowlist of `{ toolId, entryId?, execution: 'local' | 'remote', mode? }`. New tools, entries and modes are closed until explicitly configured. Local execution also requires an actual local implementation; remote execution requires the remote Adapter's `supports({toolId, params})`. The resolver derives the concrete entry/mode from frozen parameters and the plugin execution path. A parameter or UI label claiming to be free/local cannot bypass it. Example: `adjust/local` and `retouch/recolor/remote` are independent rules; `ai_disclosure/local/manual` and `ai_disclosure/remote/ai` are separate modes. Cutout model, SVG engine, brand mark mode and upscale mode require their exact mode values.
73
-
74
- Local manual declaration writes the existing keyword to supported PNG, JPEG and WebP containers. It records `method: 'manual'` and binds the fact to the actual file SHA-256; it does not claim an AI decision. Existing declarations are read back without creating a duplicate image version. Metadata cleanup preserves this declaration and updates its file hash. Manual declaration preserves encoded pixels, EXIF orientation, ICC profiles and unrelated business metadata; unsupported carriers fail with the original bytes retained.
75
-
76
- For compatibility with the original V1 entry, **omitting `config` retains only local `metadata_cleanup`**. Explicit `config: {}` closes every tool, including metadata cleanup. Omitting configuration never opens newly migrated algorithms such as resize/crop. The command gate, panel action, menus, shortcuts and history reconfiguration use the same resolver. Updating configuration affects new actions; it does not re-authorize, cancel or replay frozen attempts, original-ID queries or adoption of existing results. Readonly history remains available when its UI entry is shown.
77
-
78
- `config.visibility` controls `brand`, `history`, `import`, `export`, `newBatch`, `draftReset`, `theme` and `language` chrome. `config.beforeReset({action, intent?, batchId, toolId?, entryId?})` can synchronously or asynchronously confirm `draft`, `newBatch`, or `restoreVersion`; false/rejection preserves the original state. Confirmation becomes invalid when its configuration or owning batch/draft/version changes. Draft reset only changes the plugin's owned draft; it never edits queued parameters or protected task records. `config.parameterDefaults` takes bounded finite JSON entries `{schemaVersion:1, toolId, entryId?, params}` in the existing image parameter schemas. Unknown fields, non-JSON values, assets and task identities are rejected. Full `resetDraft` clears that tool and applies its configured defaults; panel reset has `intent: parameters`, preserving selected assets and mode while applying compatible appearance defaults. Neither changes frozen operations. Hot updates use the Vue `config`/`display` props or `command({type:'updateConfig', config, display})`.
79
-
80
- Vue named slots `navigation`, `header`, `toolbar`, `emptyState`, and `mainAction` receive immutable snapshots and the bounded `command` function. `mainAction` additionally receives `toolId`, `entryId`, frozen submission `params`, `count`, `disabled`, and `submit()`. Business components in slots retain their host Router, host Pinia, ancestor provides and global i18n context, including reactive changes; core components retain the private core context. `navigation` is placed before the editable project name; a host can set `visibility.brand: false` and provide its own back link there while reusing its own logo, workspace selector and account header outside the core. The default brand stays visible for existing consumers. Standalone mounting can pass equivalent render callbacks in `slots` and needs no host Vue app. Pricing, login, balance and product actions belong in these slots. Core does not infer or contain any estimated credit rates; `apps/demo/src/business-presentation.ts` is an illustrative business-owned display.
81
-
82
- ## SDK-owned local model resources
83
-
84
- Pass `resourceBaseUrl` to `createBrowserBatchAdapter({ namespace, resourceBaseUrl })` to install the original quick ISNet and full standard BiRefNet executors. SDK initialization performs no downloads. Business capability allowlists, identity, authentication and pricing remain host-owned. Omitting resources keeps existing browser edits and leaves model cutout unavailable; it never switches to a paid remote mode.
85
-
86
- Prepare the SDK-pinned model/runtime bytes outside Git, then serve or deploy that directory:
87
-
88
- ```sh
89
- pnpm exec batch-images-prepare-resources local-artifacts/batch-cutout
90
- # Check a prepopulated cache without network access:
91
- pnpm exec batch-images-prepare-resources local-artifacts/batch-cutout --offline
92
- ```
93
-
94
- ```ts
95
- // Host Vite config (Node only):
96
- import { createBatchResourcesPlugin } from '@beeintel/batch-image/node';
97
- const plugin = createBatchResourcesPlugin({ directory: '/absolute/host/local-artifacts/batch-cutout' });
98
- // Add plugin to Vite plugins. Default public path: assets/batch-cutout.
99
-
100
- // Host browser container:
101
- const adapter = createBrowserBatchAdapter({
102
- namespace: 'opaque-project-revision',
103
- resourceBaseUrl: 'https://assets.example/product/assets/batch-cutout/',
104
- });
105
- ```
106
-
107
- The Node entry also exports `prepareBatchResources({directory, offline?})` and `verifyBatchResources({directory})`. Model source revisions, runtime versions, exact manifests, chunk hashes, download/repair and verification live in this SDK. The Vite plugin verifies the cache, serves only listed GET/HEAD resources in development and copies identical content-addressed bytes for builds, including absolute CDN bases. It does not initiate downloads. A custom `publicPath` changes deployment placement only; match the browser URL accordingly. The model cache is about 643 MB and is never included in the core npm archive. Hosts without Vite can deploy the verified directory using their static/CDN pipeline. Resource versions change with the SDK; keep old hash files available while old app releases are supported.
108
-
109
- Advanced users can pass `cutoutResources` instead of `resourceBaseUrl`, or compose `createBrowserCutoutCapability(resources)` with custom asset/persistence adapters. Both options together are rejected. Model execution remains lazy, isolated per executor, and subject to the host allowlist.
110
-
111
- `createBrowserBatchAdapter` explicitly selects browser Worker execution and isolated IndexedDB bytes/snapshots. No Demo API, login or wallet is required. Custom Adapters implement the public assets, metadata execution, persistence and optional download interfaces. A version-1 snapshot envelope binds its namespace and contract version; original bare Batch snapshots remain readable. Reads of asset/external versions require their explicit ports and frozen hashes. Missing remote execution preserves pending records and reports unavailable instead of querying Demo or resubmitting. Unsupported/corrupt snapshot versions are refused without replacement writes. This also covers historical and reversibly deleted image versions.
112
-
113
- Built-in local resize, crop, color adjustment, orientation and brand mark execution can be reused through the public `createBrowserLocalCapabilities()` factory when a host supplies its own assets/persistence. Local asset uploads, including original and background-removed Logos, use `assets.write` through the workbench reference registration port. A frozen `WorkspaceAssetIdentity` contains only `{assetId, assetVersionId, sha256}`. The optional `assets.resolveReference(identity, signal)` returns the full `WorkspaceAssetReference` with MIME, bytes, width and height; `assets.readReference(reference, signal)` supplies its Blob. Existing full references can still be read without a resolver. Identity-only references require an explicit resolver and never fall back to a Demo URL or mutable draft metadata. The core independently checks the resolved identity and the actual Blob hash, container, dimensions and size before use.
114
-
115
- External versions use the optional `assets.readExternal(source: WorkspaceExternalSource, signal?)` port. The host owns URL access, authentication and cancellation. The default browser Adapter has no external reader and makes no network fallback. An existing external version must have a valid frozen `source.expectedSha256` or asset hash; a changed or unbound URL cannot replace its original bytes. Actual container, hash, size and display dimensions are checked after reading. URL/XLSX imports read through this port once, independently verify the file, and register its Blob and hash as a local original version. A mutable URL is never used later as an unbound original.
116
-
117
- The export dialog first shows settings, then replaces the body with progress/results and download actions. Returning to settings retains the chosen parameters and prepared files. The dialog freezes selected versions and settings, uses the same explicit assets interface, and reports each ZIP member or exclusion without adding image versions. PNG/JPEG/WebP retain declaration and business metadata through the existing export pipeline; GIF/TGA reject sources with XMP or a declaration. JPEG composites transparency on the chosen background (white by default). PNG offers lossless and compact modes, retaining the original PNG when conversion would increase its size. Cancelling releases the export Worker and download links; a later result cannot replace another session. Safe SVG input reuses the restricted XML parser for original copying or rasterization; external SVG references are rejected.
118
-
119
- `exportCurrent` copies frozen bytes. Original versions retain their exact filename; edited versions use their actual container suffix, preserving an existing matching `.jpg`/`.jpeg` spelling and case. A frozen historical original larger than 24MP can be copied without decoding after header/hash/MIME/size/dimension checks, while conversion and ordinary image operations retain the 24MP limit. All reads remain limited to 25MiB.
120
-
121
- For example, add a host asset catalog while retaining browser-local uploads:
122
-
123
- ```ts
124
- import { createBrowserBatchAdapter, createBatchWorkspace,
125
- type BatchWorkspaceAdapter, type WorkspaceAssetReference } from '@beeintel/batch-image';
126
-
127
- const browser = createBrowserBatchAdapter({ namespace: 'opaque-project-revision' });
128
- const catalog = new Map<string, { reference: WorkspaceAssetReference; blob: Blob }>();
129
- const assetKey = (value: Pick<WorkspaceAssetReference, 'assetId' | 'assetVersionId'>) =>
130
- JSON.stringify([value.assetId, value.assetVersionId]);
131
- // Populate catalog from the host's stable, versioned asset layer.
132
- const adapter: BatchWorkspaceAdapter = {
133
- ...browser,
134
- assets: {
135
- ...browser.assets,
136
- async resolveReference(identity, signal) {
137
- signal?.throwIfAborted();
138
- const saved = catalog.get(assetKey(identity));
139
- if (!saved) return browser.assets.resolveReference!(identity, signal);
140
- if (saved.reference.assetId !== identity.assetId ||
141
- saved.reference.sha256 !== identity.sha256) throw Error('Asset identity changed');
142
- return { ...saved.reference };
143
- },
144
- async readReference(reference, signal) {
145
- signal?.throwIfAborted();
146
- const saved = catalog.get(assetKey(reference));
147
- return saved ? saved.blob : browser.assets.readReference!(reference, signal);
148
- },
149
- },
150
- };
151
- const workspace = createBatchWorkspace({ adapter, config: { capabilities: [
152
- { toolId: 'brand_mark', execution: 'local', mode: 'single' },
153
- { toolId: 'brand_mark', execution: 'local', mode: 'tile' },
154
- ] } });
155
- await workspace.mount(document.querySelector<HTMLElement>('#workspace')!);
156
- ```
157
-
158
- Use a typed `BatchWorkspaceAdapter` for custom ports so their method parameters are checked. A Logo is a separate frozen reference in version-1 brand parameters and must be static PNG/JPEG/WebP, at most 5MiB and 4MP; its metadata cannot become the main image's declaration. Single mode accepts its original absent `mode` or explicit `mode: 'single'`. Tile mode accepts numeric `density: 0..100` and integer `angle: -90..90`, and retained legacy `density: 'sparse'|'standard'|'dense'` plus `direction: 'diagonal'|'horizontal'`. The two shapes cannot be mixed. Each mode needs its own exact capability rule. Edits generate full-size PNG versions with normalized physical orientation and retain only the main source's verified declaration. Missing asset capabilities or mismatched content produce a failed attempt rather than a synthetic image version.
159
-
160
- Published declarations are emitted from the public TypeScript sources. The build checks a separate consumer against the emitted functions, component props/events and exposed handle, and verifies that scoped styles preserve the actual workbench class selectors.
161
-
162
- The root `pnpm dev` starts core watch build and waits for this session’s first complete JS/types/CSS/Worker validation before starting `apps/demo`. Rebuilds stage privately, publish immutable hash assets and atomically replace stable entries behind the Demo readiness gate, then reload Demo. During failed or unfinished rebuilds the Demo request gate reports 503, and retains the previous complete artifact without exposing partial output. No source fallback exists. `pnpm dev -- --port 8872` changes the Demo port. Stop the entry to close only its owned child processes.
163
-
164
- Native page close/reload asks for confirmation while tasks are running/waiting, an export is active or a queue commit is pending. Saved history alone does not trigger the warning. This browser lifecycle guard does not intercept host SPA navigation; hosts still own their route policy. One active writer owns each namespace. Package styles are container-prefixed; named container queries also support a narrow embedded workbench inside a wide page. Each view releases its owned Blob URLs and aborts late reads. EXIF-correct temporary preview PNGs do not overwrite original files or create image versions. The orient preview reads the frozen original bytes. Hosted mode does not bootstrap global document preferences; system theme listeners are instance-owned.
165
-
166
- `resources.json` lists the emitted asset bytes, sizes and SHA256. Keep the complete immutable graph with each version. Cross-origin module Workers use a same-origin Blob bootstrap importing the actual package resource URL; the host must permit the module origin with CORS and its CSP must permit that Worker bootstrap (or serve Workers on the application origin). No production CSP is weakened by the package. Explicit cutout manifests separately pin model/runtime URLs, chunks, sizes and actual hashes; default adapters do not download weights. See `docs/integration/cutout-resources.md`.
167
-
168
- The optional `adapter.services` port covers retained tool/capability/upload/transport callers without global clients. Each method is optional; a missing method reports `MISSING_SERVICE`. The normal execution paths use `execution.remote`, `assets` and `persistence`; new integrations do not need to implement Demo DTOs or install legacy services. The Demo installs its optional HTTP bridge only in its explicit legacy entry. The public exports are exactly the package root, `./processing`, `./style.css` and `./resources.json`; there are no private store or source subpaths.
169
-
170
- The bundled Figtree font is distributed under the SIL Open Font License; see `FONT-LICENSE.txt` in this package.
171
-
172
- Final review followup `0.3.0-ticket17.4` serializes context lifecycles with immediate callback invalidation. During claim, save or release, the latest valid `updateContext` request wins; superseded requests return `rejected` and never emit `ready`. Old writes finish in their original namespace before its writer is released. Known local no-change reasons are localized at presentation only; saved reasons and parameters remain unchanged.
173
-
174
- # 多页签与项目编辑权
175
-
176
- 默认浏览器Adapter在同一namespace下共享项目历史,每个页签通过独立sessionStorage绑定自己的项目;新开或复制页签开始独立项目,刷新恢复本页项目。旧全局快照首次迁移保留为项目,后续新页签不再读取全局最近项目。无需BeePOP传页签ID或实现锁逻辑。
177
-
178
- 写入锁收窄到namespace和projectId。打开已被编辑的项目时,第二页完整呈现为只读,持续读取已保存内容;原页退出后用户点击申请编辑权,SDK获得锁后重读最新快照再开放编辑。只读页面可以切换项目或新建项目。首次保存、处理队列及销毁均经过原保存屏障;不自动重放未知远程请求。
179
-
180
- 可选 `pageSession` 工厂和 `persistence.load(page?)` 为SDK实例提供页签绑定与按页恢复;使用该协议需提供 `loadBatch`。不提供该协议的旧自定义Adapter继续按命名空间排他协调。新版还持有共享作用域锁,与仍运行的旧版排他锁互斥,避免升级过程中覆盖旧页数据;遇到旧版本占用应刷新原页签。挂载级失败仍显示文本alert并发出error事件,不静默空白。
181
-
182
- ## 弹窗与材质底色
183
-
184
- 任务/项目和版本抽屉、导入/删除确认、导出、快捷键、图片信息及视图菜单与工具栏始终保留实例主题的不透明底色。GPU材质仅提供装饰效果;画布清空、重建或不可用时不能暴露底层编辑内容,CSS材质降级也不使用半透明底色。宿主无需额外覆盖弹层背景。
1
+ # @beeintel/batch-image
2
+
3
+ 正式包通过 `pnpm add @beeintel/batch-image@1.1.0` 安装,入口包括主模块、`style.css`、`processing`、`resources.json` 和 `node`。此前 `@batch-images/core` 的本地预发布包已更名;宿主应将所有主入口与子路径 import 一起更新。
4
+
5
+ `1.1.0` 精简工具说明,复用面板导入框,并提供公开工具直达链接及 `navigation.onToolChange`。旧 `mainAction` 保持为按钮外业务区域;新增 `mainActionContent` 仅提供按钮内积分展示。历史项目恢复会同步最终工具位置;报价由宿主负责。保留原任务、参数、版本和取消协议。
6
+
7
+ `1.0.1` 在工作台数据和保存的视图恢复完成前隐藏内容,保留布局测量;首次可见时直接呈现保存的工具分组,避免默认文件处理面板闪烁。左侧标签按 Figma 使用普通态 12px / 16px、选中态 14px / 20px,英文长标签允许换行。
8
+
9
+ `1.0.0` 汇总 BeePOP 的宿主布局、语言与主题适配、任务/项目历史修复、本地工具以及远程结果采用恢复。PNG 输入可采用 JPEG 输出,声明 MIME 差异不阻塞结果,仍保留字节指纹、尺寸及任务身份校验。
10
+
11
+ 2026-11-03 `0.3.0-ticket17.35`:按宿主需求移除图片声明 MIME 与真实格式一致性的拒绝条件。支持 PNG 输入、JPEG 输出及 MIME 声明未同步的结果;资产读取、版本恢复和导出按文件头识别类型,仅修正读取 Blob 的 MIME,不转码、不改变字节。仍核对资产身份、SHA-256、大小和尺寸,保留像素预算与解码校验;原任务恢复不重新生成或重复收费。
12
+
13
+ 2026-11-03 `0.3.0-ticket17.34`:远程成功回执已保存但结果读取或校验失败时,任务明确标为“结果采用失败”,结束执行中状态并保留原图与回执;依赖步骤继续按失败前置阻塞。禁止通过普通失败重试重新生成,提供“重试采用原结果(不重新生成)”,沿原回执恢复并只采用一次。重开旧的处理中记录时沿原回执校验后同步收敛,不重新提交远程请求。
14
+
15
+ 2026-11-03 `0.3.0-ticket17.33`:任务、版本、删除确认和导出浮层使用实例的 body overlay host,导入/任务/版本/导出使用不透明主题表面;手机工具区独立横向滚动,保留右侧任务/帮助入口。修复宿主项目清理、分组草稿恢复、全失败导出状态及处理中英文提示。状态恢复完成前暂不接受工具操作,同项目更新不重复恢复视图;任务浮层优先展示最近重试结果。库产物将内联 WASM/运行时模块还原为带摘要的独立资源,避免宿主 Vite 对超长 data URL 转换溢出;资源清单覆盖最终字节。
16
+
17
+ 自定义持久化 Adapter 可实现 `persistence.removeBatch(batchId)` 配合 `loadBatch`/`list` 支持项目删除。核心先检查当前项目、未结束任务及跨页占用;内置 Adapter 只删除对应项目快照和匹配的旧快照,不批量删除可能由其它项目引用的资产。清理反馈在项目抽屉内显示;没有该能力的自定义 Adapter 显示明确错误,不静默成功。
18
+
19
+ 2026-11-03 `0.3.0-ticket17.28`:宿主工作台按 BeePOP Figma 修正五类工具图标、侧栏位置、背景卡片素材和尺寸、主题色、header、footer 与空态。中文桌面概览宽 200px,英文侧栏宽 72px、按钮宽 60px,标签居中且包含在按钮背景内;英文概览宽 232px 并允许卡片随文字增高;具体工具宽 280px,宿主宽度不超过 760px 时切换上下布局。参数独立滚动、帮助、白底与元数据行为沿用 17.23。
20
+
21
+ 每个实例的主题浮层容器 Teleport 到 document.body,导入遮罩覆盖宿主导航,不再被工作台容器裁切;卸载时随实例清理。宿主仍负责登录和计费。容器需有明确高度,不再要求至少 620px,短屏通过内部滚动保持操作可达。
22
+
23
+ Explicit browser cutout models use `createBrowserCutoutCapability` with pinned model/runtime manifests; the resource contract, Worker hosting protocol and deferred inference boundary are documented in `docs/integration/cutout-resources.md` in the repository. Default adapters do not download model weights or select a paid fallback.
24
+
25
+ The 1.0 release exposes the complete workbench UI, browser local tools, manual declaration, frozen-version format/ZIP export, and explicit per-instance external IO. Remote operations require a host Adapter. Authentication, pricing and product policy stay in the consumer. Actual model inference and backend AI acceptance are deferred separately; controlled adapters are not evidence of production AI quality.
26
+
27
+ Build from repository root after `pnpm install --frozen-lockfile`:
28
+
29
+ ```sh
30
+ pnpm --filter @beeintel/batch-image build
31
+ npm pack ./packages/batch-images --ignore-scripts --pack-destination ./artifacts
32
+ ```
33
+
34
+ Create the `artifacts` directory before packing. The resulting archive is `beeintel-batch-image-1.0.1.tgz`; consumers normally install `@beeintel/batch-image@1.0.1` from npm. Retain earlier published versions and their matching resource graphs for rollback. Import `BatchWorkspace`, `createBrowserBatchAdapter` from `@beeintel/batch-image` and import `@beeintel/batch-image/style.css`. Pass an explicit Adapter created with `{ namespace: 'your-opaque-context' }`. Mount the component inside a container with a defined height. Pinia is bundled privately; Vue is a peer shared with the consumer.
35
+
36
+ Published candidate mapping (retain older artifacts/commits for rollback):
37
+
38
+ | Candidate | Scope | Compatibility |
39
+ | ------------------ | ------------------------------------------------------------------------------------------------------------------------------------------------------------ | --------------------------------------------------------------------------------------------------- |
40
+ | `0.1.0-ticket02.0` | Original public metadata flow and workspace/artifact split | Original `createBatchWorkspace({adapter})` and metadata commands |
41
+ | `0.2.0-ticket16.0` | Host controls/slots, instance lifecycle and integrated remote/resize/crop contracts | Original metadata calls retained; new capabilities require exact allowlist configuration |
42
+ | `0.2.1-ticket12.0` | Migrated local tools, declaration, explicit source reads and format/ZIP export | Retains earlier contracts; optional external reader requires frozen hashes |
43
+ | `0.3.0-ticket17.0` | Complete per-instance ports, versioned defaults/reset intent, owned previews, external Demo and container/CDN consumption | Snapshot envelope/contract remain version 1; protected original request identity is retained |
44
+ | `0.3.0-ticket17.1` | Responsive Header groups across embedded widths; reversible deletion of verified local originals and results | Snapshot and task contracts unchanged; uploading, busy and unresolved local inputs remain protected |
45
+ | `0.3.0-ticket17.2` | Known metadata/manual declaration/translation result localization and intrinsic mobile Header/rail track sizing | Stored reasons, image versions, parameters and task contracts unchanged |
46
+ | `0.3.0-ticket17.3` | Task peek placement avoids its trigger on first render and when clamped in narrow hosts | Native touch/mouse/keyboard and hover remain available; stored tasks and image bytes unchanged |
47
+ | `0.3.0-ticket17.4` | Latest-context lifecycle serialization, shared immutable values and known local no-change result localization | Snapshot/schema/params and original task identities unchanged; superseded context requests reject |
48
+ | `0.3.0-ticket17.6` | Instance-owned material GPU/snapshots/overlays and readable dark import, preset, history and export surfaces; supersedes the local 17.5 validation candidate | Display-only; task identities, parameters, persistence and image bytes unchanged |
49
+ | `0.3.0-ticket17.7` | Narrow hosts reserve usable canvas height when notices and tool panels are open; active local flights do not enter remote receipt polling | Existing task identities, original-ID recovery, parameters and image bytes unchanged |
50
+ | `0.3.0-ticket17.8` | Lint cleanup and one source owner for existing content-trim result labels | Existing translations, saved reasons, execution parameters and image bytes unchanged |
51
+
52
+ | `0.3.0-ticket17.9` | TAPD 1001027 host navigation slot, neutral selection/radio cards, unobstructed preview captions and vertical desktop filmstrip, two-step export and pending-work leave warning | Optional chrome/slot additions; parameters, modes, version/task identities and output pipeline retained |
53
+
54
+ | `0.3.0-ticket17.10` | Narrow preview footer uses content height to keep wrapped captions and controls outside the picture | Desktop vertical filmstrip and all execution contracts retained |
55
+
56
+ | `0.3.0-ticket17.11` | Compact native radio cards with visible labels; shared 33×16 switches with light/dark state colors; Logo actions stay on one row in narrow panels | Display-only; original modes, parameters, queues, persistence and output bytes retained |
57
+
58
+ | `0.3.0-ticket17.12` | TAPD 1001032 local Logo feedback in eight locales, concise first-three cutout labels and spaced translation fields/footer without duplicated service self-check | Stored reasons, model identities, parameters and recovery retained; consumers still own the product mode allowlist and business action |
59
+
60
+ | `0.3.0-ticket17.13` | Optional host visibility for service diagnostics and recheck controls | Default diagnostics remain visible; execution capability checks, tasks and image bytes are unchanged |
61
+
62
+ Hosts can set `config.visibility.serviceStatus = false` to hide service availability diagnostics and the recheck action in tool footers. This only changes presentation; unavailable execution remains disabled. Omitting the option preserves existing diagnostics. Business action slots remain owned by the host.
63
+
64
+ TAPD 1001032: known local Logo background failures are translated only at display; unknown host diagnostics remain verbatim. Quick, Standard and Precision Cutout labels omit model names while preserving the original mode IDs. All core modes remain available to explicit consumers; a host can expose only its approved modes through the existing capability configuration. Translation paragraphs use a 12px gap and the action footer uses 8px. Hiding that panel's service self-check does not enable unavailable execution. The host owns concise status, temporary pricing reference and any explanatory tooltip.
65
+
66
+ TAPD 1001027 follow-up: generic text-field sizing excludes radio inputs. Switch geometry and state colors have one shared owner; orientation and export panels no longer redefine the same control. Logo background help and removal use fixed grid columns so English labels wrap without moving the removal action to a new row. Verify the published CSS in a real browser with `node packages/batch-images/tests/public-consumer-cdn.browser.mjs --ui-audit`; it measures card bounds and switch states in English/Chinese, light/dark and wide/narrow hosts. Evidence stays outside Git; `BATCH_CDN_EVIDENCE` selects its folder. Real model inference is not part of this check.
67
+
68
+ The component receives `adapter`, `config`, `display`, and `revision`, emits `event`, and exposes `command`, `snapshot`, `subscribe`, `dispose`. Explicit mounting uses `createBatchWorkspace({ adapter, config, display }).mount(element)`, with the same handle and implementation. `updateContext` changes the opaque Adapter namespace/revision through the same persistence and lifecycle barriers. Each instance owns its Pinia, translation, theme and overlay target.
69
+
70
+ For Vite development consumption, configure `optimizeDeps.exclude: ['@beeintel/batch-image']` so dependency prebundling does not relocate the emitted relative Worker URLs. Production builds consume the bundled package graph directly; no source alias is required.
71
+
72
+ Commands include `importFiles`, `openTool`, `runTool`, `runMetadataCleanup`, `select`, `exportCurrent`, `newBatch`, `openBatch`, `restoreVersion`, `resetDraft`, and `updateConfig`. Tool commands return a queued operation identity; `status: completed` means the command was handled, not that image processing succeeded. Observe immutable events/snapshots until an attempt is `succeeded` and `applied`; check failures too. `exportCurrent` reads the frozen current versions, validates their bytes, returns files and invokes the optional Adapter download handler. It never exports the input in place of an adopted result.
73
+
74
+ `config.capabilities` is an exact allowlist of `{ toolId, entryId?, execution: 'local' | 'remote', mode? }`. New tools, entries and modes are closed until explicitly configured. Local execution also requires an actual local implementation; remote execution requires the remote Adapter's `supports({toolId, params})`. The resolver derives the concrete entry/mode from frozen parameters and the plugin execution path. A parameter or UI label claiming to be free/local cannot bypass it. Example: `adjust/local` and `retouch/recolor/remote` are independent rules; `ai_disclosure/local/manual` and `ai_disclosure/remote/ai` are separate modes. Cutout model, SVG engine, brand mark mode and upscale mode require their exact mode values.
75
+
76
+ Local manual declaration writes the existing keyword to supported PNG, JPEG and WebP containers. It records `method: 'manual'` and binds the fact to the actual file SHA-256; it does not claim an AI decision. Existing declarations are read back without creating a duplicate image version. Metadata cleanup preserves this declaration and updates its file hash. Manual declaration preserves encoded pixels, EXIF orientation, ICC profiles and unrelated business metadata; unsupported carriers fail with the original bytes retained.
77
+
78
+ For compatibility with the original V1 entry, **omitting `config` retains only local `metadata_cleanup`**. Explicit `config: {}` closes every tool, including metadata cleanup. Omitting configuration never opens newly migrated algorithms such as resize/crop. The command gate, panel action, menus, shortcuts and history reconfiguration use the same resolver. Updating configuration affects new actions; it does not re-authorize, cancel or replay frozen attempts, original-ID queries or adoption of existing results. Readonly history remains available when its UI entry is shown.
79
+
80
+ `config.visibility` controls `brand`, `history`, `import`, `export`, `newBatch`, `draftReset`, `theme` and `language` chrome. `config.beforeReset({action, intent?, batchId, toolId?, entryId?})` can synchronously or asynchronously confirm `draft`, `newBatch`, or `restoreVersion`; false/rejection preserves the original state. Confirmation becomes invalid when its configuration or owning batch/draft/version changes. Draft reset only changes the plugin's owned draft; it never edits queued parameters or protected task records. `config.parameterDefaults` takes bounded finite JSON entries `{schemaVersion:1, toolId, entryId?, params}` in the existing image parameter schemas. Unknown fields, non-JSON values, assets and task identities are rejected. Full `resetDraft` clears that tool and applies its configured defaults; panel reset has `intent: parameters`, preserving selected assets and mode while applying compatible appearance defaults. Neither changes frozen operations. Hot updates use the Vue `config`/`display` props or `command({type:'updateConfig', config, display})`.
81
+
82
+ Vue named slots `navigation`, `header`, `toolbar`, `emptyState`, `mainAction`, and `mainActionContent` receive immutable snapshots and the bounded `command` function. `mainAction` and `mainActionContent` additionally receive `toolId`, `entryId`, frozen submission `params`, `count`, `disabled`, and `submit()`. Business components in slots retain their host Router, host Pinia, ancestor provides and global i18n context, including reactive changes; core components retain the private core context. `navigation` is placed before the editable project name; a host can set `visibility.brand: false` and provide its own back link there while reusing its own logo, workspace selector and account header outside the core. The default brand stays visible for existing consumers. Standalone mounting can pass equivalent render callbacks in `slots` and needs no host Vue app. Pricing, login, balance and product actions belong in these slots. `mainAction` remains outside the submit button for interactive business controls. `mainActionContent` supplies display-only credit text inside that button; it must not contain buttons or links. Core does not infer or contain any estimated credit rates; `apps/demo/src/business-presentation.ts` is an illustrative business-owned display.
83
+
84
+ ## SDK-owned local model resources
85
+
86
+ Pass `resourceBaseUrl` to `createBrowserBatchAdapter({ namespace, resourceBaseUrl })` to install the original quick ISNet and full standard BiRefNet executors. SDK initialization performs no downloads. Business capability allowlists, identity, authentication and pricing remain host-owned. Omitting resources keeps existing browser edits and leaves model cutout unavailable; it never switches to a paid remote mode.
87
+
88
+ Prepare the SDK-pinned model/runtime bytes outside Git, then serve or deploy that directory:
89
+
90
+ ```sh
91
+ pnpm exec batch-images-prepare-resources local-artifacts/batch-cutout
92
+ # Check a prepopulated cache without network access:
93
+ pnpm exec batch-images-prepare-resources local-artifacts/batch-cutout --offline
94
+ ```
95
+
96
+ ```ts
97
+ // Host Vite config (Node only):
98
+ import { createBatchResourcesPlugin } from '@beeintel/batch-image/node';
99
+ const plugin = createBatchResourcesPlugin({ directory: '/absolute/host/local-artifacts/batch-cutout' });
100
+ // Add plugin to Vite plugins. Default public path: assets/batch-cutout.
101
+
102
+ // Host browser container:
103
+ const adapter = createBrowserBatchAdapter({
104
+ namespace: 'opaque-project-revision',
105
+ resourceBaseUrl: 'https://assets.example/product/assets/batch-cutout/',
106
+ });
107
+ ```
108
+
109
+ The Node entry also exports `prepareBatchResources({directory, offline?})` and `verifyBatchResources({directory})`. Model source revisions, runtime versions, exact manifests, chunk hashes, download/repair and verification live in this SDK. The Vite plugin verifies the cache, serves only listed GET/HEAD resources in development and copies identical content-addressed bytes for builds, including absolute CDN bases. It does not initiate downloads. A custom `publicPath` changes deployment placement only; match the browser URL accordingly. The model cache is about 643 MB and is never included in the core npm archive. Hosts without Vite can deploy the verified directory using their static/CDN pipeline. Resource versions change with the SDK; keep old hash files available while old app releases are supported.
110
+
111
+ Advanced users can pass `cutoutResources` instead of `resourceBaseUrl`, or compose `createBrowserCutoutCapability(resources)` with custom asset/persistence adapters. Both options together are rejected. Model execution remains lazy, isolated per executor, and subject to the host allowlist.
112
+
113
+ `createBrowserBatchAdapter` explicitly selects browser Worker execution and isolated IndexedDB bytes/snapshots. No Demo API, login or wallet is required. Custom Adapters implement the public assets, metadata execution, persistence and optional download interfaces. A version-1 snapshot envelope binds its namespace and contract version; original bare Batch snapshots remain readable. Reads of asset/external versions require their explicit ports and frozen hashes. Missing remote execution preserves pending records and reports unavailable instead of querying Demo or resubmitting. Unsupported/corrupt snapshot versions are refused without replacement writes. This also covers historical and reversibly deleted image versions.
114
+
115
+ Built-in local resize, crop, color adjustment, orientation and brand mark execution can be reused through the public `createBrowserLocalCapabilities()` factory when a host supplies its own assets/persistence. Local asset uploads, including original and background-removed Logos, use `assets.write` through the workbench reference registration port. A frozen `WorkspaceAssetIdentity` contains only `{assetId, assetVersionId, sha256}`. The optional `assets.resolveReference(identity, signal)` returns the full `WorkspaceAssetReference` with MIME, bytes, width and height; `assets.readReference(reference, signal)` supplies its Blob. Existing full references can still be read without a resolver. Identity-only references require an explicit resolver and never fall back to a Demo URL or mutable draft metadata. The core independently checks the resolved identity and the actual Blob hash, container, dimensions and size before use.
116
+
117
+ External versions use the optional `assets.readExternal(source: WorkspaceExternalSource, signal?)` port. The host owns URL access, authentication and cancellation. The default browser Adapter has no external reader and makes no network fallback. An existing external version must have a valid frozen `source.expectedSha256` or asset hash; a changed or unbound URL cannot replace its original bytes. Actual container, hash, size and display dimensions are checked after reading. URL/XLSX imports read through this port once, independently verify the file, and register its Blob and hash as a local original version. A mutable URL is never used later as an unbound original.
118
+
119
+ The export dialog first shows settings, then replaces the body with progress/results and download actions. Returning to settings retains the chosen parameters and prepared files. The dialog freezes selected versions and settings, uses the same explicit assets interface, and reports each ZIP member or exclusion without adding image versions. PNG/JPEG/WebP retain declaration and business metadata through the existing export pipeline; GIF/TGA reject sources with XMP or a declaration. JPEG composites transparency on the chosen background (white by default). PNG offers lossless and compact modes, retaining the original PNG when conversion would increase its size. Cancelling releases the export Worker and download links; a later result cannot replace another session. Safe SVG input reuses the restricted XML parser for original copying or rasterization; external SVG references are rejected.
120
+
121
+ `exportCurrent` copies frozen bytes. Original versions retain their exact filename; edited versions use their actual container suffix, preserving an existing matching `.jpg`/`.jpeg` spelling and case. A frozen historical original larger than 24MP can be copied without decoding after header/hash/MIME/size/dimension checks, while conversion and ordinary image operations retain the 24MP limit. All reads remain limited to 25MiB.
122
+
123
+ For example, add a host asset catalog while retaining browser-local uploads:
124
+
125
+ ```ts
126
+ import { createBrowserBatchAdapter, createBatchWorkspace,
127
+ type BatchWorkspaceAdapter, type WorkspaceAssetReference } from '@beeintel/batch-image';
128
+
129
+ const browser = createBrowserBatchAdapter({ namespace: 'opaque-project-revision' });
130
+ const catalog = new Map<string, { reference: WorkspaceAssetReference; blob: Blob }>();
131
+ const assetKey = (value: Pick<WorkspaceAssetReference, 'assetId' | 'assetVersionId'>) =>
132
+ JSON.stringify([value.assetId, value.assetVersionId]);
133
+ // Populate catalog from the host's stable, versioned asset layer.
134
+ const adapter: BatchWorkspaceAdapter = {
135
+ ...browser,
136
+ assets: {
137
+ ...browser.assets,
138
+ async resolveReference(identity, signal) {
139
+ signal?.throwIfAborted();
140
+ const saved = catalog.get(assetKey(identity));
141
+ if (!saved) return browser.assets.resolveReference!(identity, signal);
142
+ if (saved.reference.assetId !== identity.assetId ||
143
+ saved.reference.sha256 !== identity.sha256) throw Error('Asset identity changed');
144
+ return { ...saved.reference };
145
+ },
146
+ async readReference(reference, signal) {
147
+ signal?.throwIfAborted();
148
+ const saved = catalog.get(assetKey(reference));
149
+ return saved ? saved.blob : browser.assets.readReference!(reference, signal);
150
+ },
151
+ },
152
+ };
153
+ const workspace = createBatchWorkspace({ adapter, config: { capabilities: [
154
+ { toolId: 'brand_mark', execution: 'local', mode: 'single' },
155
+ { toolId: 'brand_mark', execution: 'local', mode: 'tile' },
156
+ ] } });
157
+ await workspace.mount(document.querySelector<HTMLElement>('#workspace')!);
158
+ ```
159
+
160
+ Use a typed `BatchWorkspaceAdapter` for custom ports so their method parameters are checked. A Logo is a separate frozen reference in version-1 brand parameters and must be static PNG/JPEG/WebP, at most 5MiB and 4MP; its metadata cannot become the main image's declaration. Single mode accepts its original absent `mode` or explicit `mode: 'single'`. Tile mode accepts numeric `density: 0..100` and integer `angle: -90..90`, and retained legacy `density: 'sparse'|'standard'|'dense'` plus `direction: 'diagonal'|'horizontal'`. The two shapes cannot be mixed. Each mode needs its own exact capability rule. Edits generate full-size PNG versions with normalized physical orientation and retain only the main source's verified declaration. Missing asset capabilities or mismatched content produce a failed attempt rather than a synthetic image version.
161
+
162
+ Published declarations are emitted from the public TypeScript sources. The build checks a separate consumer against the emitted functions, component props/events and exposed handle, and verifies that scoped styles preserve the actual workbench class selectors.
163
+
164
+ The root `pnpm dev` starts core watch build and waits for this session’s first complete JS/types/CSS/Worker validation before starting `apps/demo`. Rebuilds stage privately, publish immutable hash assets and atomically replace stable entries behind the Demo readiness gate, then reload Demo. During failed or unfinished rebuilds the Demo request gate reports 503, and retains the previous complete artifact without exposing partial output. No source fallback exists. `pnpm dev -- --port 8872` changes the Demo port. Stop the entry to close only its owned child processes.
165
+
166
+ Native page close/reload asks for confirmation while tasks are running/waiting, an export is active or a queue commit is pending. Saved history alone does not trigger the warning. This browser lifecycle guard does not intercept host SPA navigation; hosts still own their route policy. One active writer owns each namespace. Package styles are container-prefixed; named container queries also support a narrow embedded workbench inside a wide page. Each view releases its owned Blob URLs and aborts late reads. EXIF-correct temporary preview PNGs do not overwrite original files or create image versions. The orient preview reads the frozen original bytes. Hosted mode does not bootstrap global document preferences; system theme listeners are instance-owned.
167
+
168
+ `resources.json` lists the emitted asset bytes, sizes and SHA256. Keep the complete immutable graph with each version. Cross-origin module Workers use a same-origin Blob bootstrap importing the actual package resource URL; the host must permit the module origin with CORS and its CSP must permit that Worker bootstrap (or serve Workers on the application origin). No production CSP is weakened by the package. Explicit cutout manifests separately pin model/runtime URLs, chunks, sizes and actual hashes; default adapters do not download weights. See `docs/integration/cutout-resources.md`.
169
+
170
+ The optional `adapter.services` port covers retained tool/capability/upload/transport callers without global clients. Each method is optional; a missing method reports `MISSING_SERVICE`. The normal execution paths use `execution.remote`, `assets` and `persistence`; new integrations do not need to implement Demo DTOs or install legacy services. The Demo installs its optional HTTP bridge only in its explicit legacy entry. The public exports are exactly the package root, `./processing`, `./style.css` and `./resources.json`; there are no private store or source subpaths.
171
+
172
+ The bundled Figtree font is distributed under the SIL Open Font License; see `FONT-LICENSE.txt` in this package.
173
+
174
+ Final review followup `0.3.0-ticket17.4` serializes context lifecycles with immediate callback invalidation. During claim, save or release, the latest valid `updateContext` request wins; superseded requests return `rejected` and never emit `ready`. Old writes finish in their original namespace before its writer is released. Known local no-change reasons are localized at presentation only; saved reasons and parameters remain unchanged.
175
+
176
+ # 多页签与项目编辑权
177
+
178
+ 默认浏览器Adapter在同一namespace下共享项目历史,每个页签通过独立sessionStorage绑定自己的项目;新开或复制页签开始独立项目,刷新恢复本页项目。旧全局快照首次迁移保留为项目,后续新页签不再读取全局最近项目。无需BeePOP传页签ID或实现锁逻辑。
179
+
180
+ 写入锁收窄到namespace和projectId。打开已被编辑的项目时,第二页完整呈现为只读,持续读取已保存内容;原页退出后用户点击申请编辑权,SDK获得锁后重读最新快照再开放编辑。只读页面可以切换项目或新建项目。首次保存、处理队列及销毁均经过原保存屏障;不自动重放未知远程请求。
181
+
182
+ 可选 `pageSession` 工厂和 `persistence.load(page?)` 为SDK实例提供页签绑定与按页恢复;使用该协议需提供 `loadBatch`。不提供该协议的旧自定义Adapter继续按命名空间排他协调。新版还持有共享作用域锁,与仍运行的旧版排他锁互斥,避免升级过程中覆盖旧页数据;遇到旧版本占用应刷新原页签。挂载级失败仍显示文本alert并发出error事件,不静默空白。
183
+
184
+ ## 弹窗与材质底色
185
+
186
+ 任务/项目和版本抽屉、导入/删除确认、导出、快捷键、图片信息及视图菜单与工具栏始终保留实例主题的不透明底色。GPU材质仅提供装饰效果;画布清空、重建或不可用时不能暴露底层编辑内容,CSS材质降级也不使用半透明底色。宿主无需额外覆盖弹层背景。