lemon_js_extensions 0.2.1 copy "lemon_js_extensions: ^0.2.1" to clipboard
lemon_js_extensions: ^0.2.1 copied to clipboard

Unified extension package and manifest model for lemon_js and lemon_js_ui.

lemon_js_extensions #

lemon_js_extensionslemon_jslemon_js_ui 之上的统一插件管理层。一个安装包可以 只包含 Core 数据服务、只包含 JSUI 页面,或同时包含两者。Manager 负责安装、恢复、更新、 启停、卸载、按 ID 调用和插件级 KV 隔离;插件管理页面由宿主业务层实现。

安装 #

dependencies:
  lemon_js_extensions: ^0.2.1
import 'package:lemon_js_extensions/lemon_js_extensions.dart';

插件目录 #

site_plugin/
├── manifest.json
├── service/
│   └── main.mjs
└── ui/
    └── login.mjs

统一 Extension 必须包含 manifest;旧 Core 或 JSUI 裸入口需要通过对应 adapter 显式安装。

最小 manifest #

{
  "schemaVersion": 2,
  "id": "site.example",
  "name": "示例站点",
  "description": "提供数据和登录页面",
  "version": "1.0.0",
  "versionCode": 10000,
  "compatibilityCode": "content-source-v1",
  "service": {
    "entry": "service/main.mjs",
    "contract": "content-source/v1",
    "publicExports": ["getHome"],
    "uiExports": ["submitLogin"]
  },
  "ui": {
    "routes": {
      "login": {
        "entry": "ui/login.mjs",
        "title": "登录"
      }
    }
  },
  "flows": {
    "authentication": {"route": "login"}
  },
  "capabilities": {
    "required": {"network": 1},
    "optional": {"crypto": 1}
  },
  "permissions": ["network", "storage"]
}

插件可以只实现 contract 的部分可选方法,但必须实现宿主兼容策略声明的必需方法。插件的 内部辅助函数不影响校验。

Core 模块 #

export function getHome() {
  return { items: [] };
}

export async function submitLogin(account, password) {
  return { ok: true, account };
}

JSUI 调用同插件 Core #

import { ElevatedButton, Page, Text } from 'quickjs_ui';
import pluginService from 'lemon_js_extensions/plugin_service';
import storage from 'lemon_js_extensions/storage';

export default Page({
  name: 'LoginPage',
  createState() { return { status: '未登录' }; },
  build(state, props, page) {
    return ElevatedButton({
      child: Text(state.status),
      onPressed: page.login()
    });
  },
  async login() {
    const result = await pluginService.call('submitLogin', 'demo', 'password');
    await storage.set('session', result);
    return { status: result.ok ? '已登录' : '登录失败' };
  }
});

JSUI 只能调用同一 Session 中 manifest 声明的 uiExports,不接收任意插件 ID。Core 不能直接控制 UI;需要交互时应返回业务状态,由 Flutter 决定是否打开 flow。

创建 Manager #

final manager = JsExtensionManager(
  constraints: <JsExtensionConstraint>[
    JsExtensionConstraint(
      compatibilityCode: 'content-source-v1',
      requiredPublicExports: const <String>{'getHome'},
      optionalPublicExports: const <String>{'search', 'getDetail'},
    ),
  ],
);

await manager.restore();

store 可以省略:原生平台默认保存到应用支持目录,Web 默认使用 SharedPreferences Web 后端。宿主可传入自定义 JsExtensionStore。插件 KV 默认使用 JsSharedPreferencesKvStore,并按插件 ID 隔离。

加载、安装和调用 #

final package = await JsExtensionPackage.asset(
  manifestAsset: 'assets/extensions/site_plugin/manifest.json',
);

await manager.install(
  package,
  grantedPermissions: const <String>{'network', 'storage'},
);

final home = await manager.call('site.example', 'getHome');

还支持 filenetworkassetZipfileZipnetworkZipzipBytes。裸 Core/JSUI 模块统一使用 moduleAssetmoduleFilemoduleNetwork,并通过 adapter 指定模块类型。不同来源最终 都会归一化为 JsExtensionPackage

打开插件页面:

final installed = manager.find('site.example')!.installed!;

JsExtensionView.route(
  session: installed.session,
  route: 'login',
  initialProps: const <String, Object?>{},
)

第三方 JsUiPlugin 不能序列化,应通过 Manager 的 uiPluginsResolver 在恢复时按 插件 ID 重新注入。

更新与数据迁移 #

Manager 会校验插件 ID、compatibilityCode 和数字 versionCode,默认拒绝同版本和 降级,也不会在尚未调用 restore() 时覆盖 Store 中的同 ID 插件。

插件升级需要修改 KV 结构时,提高 storageVersion 并声明:

{
  "storageVersion": 2,
  "service": {
    "storageMigrationExport": "migrateStorage"
  }
}
export async function migrateStorage(fromVersion, toVersion) {
  // 使用 lemon_js_extensions/storage 迁移当前插件命名空间。
}

迁移或新版本激活失败时,Manager 会恢复旧 KV 和旧安装记录。

资源和能力 #

目录、asset 和网络插件通过 manifest 的 resources 列出需要持久化的非 JS 文件;ZIP 中的非 JS 文件会自动收集。必需宿主能力缺失时安装会抛出包含完整检查结果的 JsExtensionCapabilityException;可选能力缺失只报告,不阻止安装。

Manager 默认提供隔离 KV、网络/Axios 和 Web Crypto。宿主可通过 JsExtensionFeatures 替换或关闭。

管理 API #

final installed = manager.extensions;
await manager.disable('site.example');
await manager.enable('site.example');
await manager.uninstall('site.example', clearStorage: false);

Manager 只提供无 UI 的状态和管理 API,安装列表、权限确认和更新页面由宿主业务层负责。

示例与设计 #

完整可运行工程位于 GitHub;pub 包中保留最小 Dart 示例。

0
likes
150
points
168
downloads

Documentation

API reference

Publisher

unverified uploader

Weekly Downloads

Unified extension package and manifest model for lemon_js and lemon_js_ui.

Repository (GitHub)
View/report issues

License

unknown (license)

Dependencies

archive, flutter, http, lemon_js, lemon_js_ui, path_provider, shared_preferences

More

Packages that depend on lemon_js_extensions