# SGS Framework Contract ## Public Core Core is exposed as both `window.SgsFramework` and `window.__SgsFramework`. Stable top-level services: ```text events event bus logger scoped logger storage Core-scoped serialized storage timers disposable timers hooks reversible method hooks dom overlay and control helpers browser URL and network helpers laya raw Laya access and stage traversal runtime battle/window/log lifecycle events plugins installation, lifecycle, configuration, and updates update Core update check and hot reload ui edge dock, settings window, dialogs, and refresh ``` Core replacement is hot reload: the new source disposes the previous instance, then recreates services and restores enabled plugins from cached source. ## Plugin Source Format Every plugin is a standalone classic JavaScript file. It must begin with a machine-readable header and call `SgsFramework.plugins.define(plugin)` when evaluated. ```javascript // ==SgsPlugin== // @id example.plugin // @name Example Plugin // @version 1.0.0 // @description Example description. // @permissions core.events,browser.dom-overlay // @updateMode default // ==/SgsPlugin== (() => { SgsFramework.plugins.define({ id: "example.plugin", manifest: { name: "Example Plugin", version: "1.0.0", description: "Example description.", permissions: ["core.events", "browser.dom-overlay"] }, defaults: {}, settings: [], install(context) {} }); })(); ``` Header fields used before execution: ```text @id stable plugin id @name display name @version comparable dotted version @description installation description @permissions comma-separated capability disclosure @updateMode default | header | api @versionHeader response header for header mode @versionApi JSON endpoint for api mode ``` ## Update Modes - `default`: GET the plugin JavaScript, parse its header, and compare `@version`. - `header`: send a HEAD request and compare the response header named by `@versionHeader` (default `x-sgs-plugin-version`). No response body is read. - `api`: GET `@versionApi`; JSON must provide `version` and may provide `url`. Each network request uses a five-second timeout unless the Core contract version changes explicitly. Cross-origin header sources must expose the selected version header with `Access-Control-Expose-Headers`; `Access-Control-Allow-Origin` alone is not sufficient for browser JavaScript to read a custom response header. ## Plugin Settings Plugin definitions may provide `defaults`, `settings`, and `actions`. ```javascript settings: [ { id: "display", name: "Display", items: [ { key: "enabled", name: "Enabled", type: "toggle", onChange: "apply" }, { key: "name", name: "Name", type: "text", patterns: ["^.{1,20}$"] }, { key: "mode", name: "Mode", type: "select", options: [{ value: "a", label: "A" }] }, { name: "Open list", type: "button", action: "openList" }, { name: "Custom", type: "custom", render: "renderCustom" } ] } ] ``` Supported types are `toggle`, `button`, `text`, `select`, and `custom`. String action names resolve against `plugin.actions`. A custom renderer receives a Core-owned host element and plugin context; the plugin controls only the contents of that host. ## Storage Core owns all LocalStorage keys. ```text sgs.framework.ui.* sgs.framework.plugins.registry sgs.framework.plugins.sources sgs.framework.plugins.catalog-cache sgs.framework.plugins..code sgs.framework.plugins..config sgs.framework.plugins..data.* ``` `context.storage` is automatically scoped to `plugins..data.`. `context.config` serializes one configuration object, merges first-run defaults, validates declared text patterns, and invokes plugin actions after successful changes. ## Catalog `plugin/index.json` is the official source. Third-party sources use the same structure: ```json { "name": "Source name", "plugins": [ { "id": "example.plugin", "url": "https://example/plugin.js" } ] } ``` The official source is fixed. Third-party sources can be added, renamed, disabled, and removed by the user.