OpenCode AI e9899d2e6d
Some checks failed
Android CI Build / check (push) Has been cancelled
Android CI Build / package-apks (push) Has been cancelled
Docs Deploy / build (push) Has been cancelled
Module Market Check / Validate modules/ (push) Has been cancelled
Module Market Publish / Generate submissions.json (push) Has been cancelled
Docs Deploy / deploy (push) Has been cancelled
Initial DruksCode V2: fresh fork of web-to-app (f3b488e) with DruksCode identity
- Package rename com.webtoapp -> br.com.drukstech.codeapp
- Product rename WebToApp/web-to-app -> DruksCode/drukscode
- Design system Wta* -> Dkc*
- applicationId br.com.drukstech.codeapp (.play for gplay flavor)
- rootProject.name DruksCode
- Fresh git history (upstream kept as remote for sync)
2026-09-12 02:42:02 +02:00

138 lines
5.2 KiB
Markdown

# JS Modules
A JS module is the most capable native extension format: a manifest, a script, optional CSS, a config UI, and an optional floating panel — all packaged together.
## File layout
```
my-module/
├── module.json # required — the manifest
├── main.js # required — runs in the WebView
├── style.css # optional — auto-injected when hasCss / cssCode present
└── icon.png # optional — ≤256KB; png/svg/webp/jpg/jpeg
```
## `module.json` schema
```json
{
"id": "my-module",
"name": "My Module",
"description": "What it does",
"icon": "star",
"category": "CONTENT_ENHANCE",
"tags": ["demo"],
"version": { "code": 1, "name": "1.0.0", "changelog": "Initial release" },
"author": { "name": "You", "url": "https://example.com" },
"runAt": "DOCUMENT_END",
"urlMatches": [
{ "pattern": "*://example.com/*", "isRegex": false, "exclude": false }
],
"permissions": ["DOM_ACCESS", "STORAGE"],
"configItems": [
{
"key": "greeting",
"name": "Greeting text",
"type": "TEXT",
"defaultValue": "Hello",
"required": true
}
]
}
```
::: warning `version` is an object
`version` has `code` (int), `name` (semver string), and `changelog`. Don't make it a plain string in `module.json`.
:::
### Field reference
| Field | Notes |
| --- | --- |
| `id` | Globally unique. |
| `icon` | A Material Icons name (e.g. `star`, `package`). |
| `category` | One of: `CONTENT_FILTER`, `CONTENT_ENHANCE`, `STYLE_MODIFIER`, `THEME`, `FUNCTION_ENHANCE`, `AUTOMATION`, `NAVIGATION`, `DATA_EXTRACT`, `DATA_SAVE`, `INTERACTION`, `ACCESSIBILITY`, `MEDIA`, `VIDEO`, `IMAGE`, `AUDIO`, `SECURITY`, `ANTI_TRACKING`, `SOCIAL`, `SHOPPING`, `READING`, `TRANSLATE`, `DEVELOPER`, `OTHER`. |
| `runAt` | `DOCUMENT_START`, `DOCUMENT_END` (default), `DOCUMENT_IDLE`, `CONTEXT_MENU`, `BEFORE_UNLOAD`. |
| `urlMatches[]` | `{pattern, isRegex=false, exclude=false}`. See [URL matching](#url-matching). |
| `permissions[]` | Display-only; the runtime does **not** sandbox based on these. Dangerous ones (e.g. `CAMERA`, `LOCATION`, `EVAL`, `FILE_ACCESS`) get extra review. |
| `configItems[]` | User-configurable fields; see [Config items](#config-items). |
## URL matching
- **`isRegex: false`** (default) — Chrome-style glob. `*` matches anything; `*://` expands to `(https?|ftp|file)://`; `*` or `<all_urls>` matches everything. Falls back to substring `contains` if the glob fails to match.
- **`isRegex: true`** — Java regex with a **200ms timeout**; a timeout counts as no match.
- **`exclude: true`** — removes matching URLs from the result set.
## The `main.js` contract
Your code is wrapped in an IIFE with a `try/catch` (errors go to `console.error` and never break the page). These globals are available:
| Global | Value |
| --- | --- |
| `__MODULE_INFO__` | `{id, name, icon, version, uiConfig, runMode}` |
| `__MODULE_CONFIG__` | The resolved config object |
| `__MODULE_UI_CONFIG__` | UI config |
| `__MODULE_RUN_MODE__` | `'INTERACTIVE'` or `'AUTO'` |
| `__MODULE_PANEL_HTML__` | Your `panelHtml`, if any |
| `getConfig(key, defaultValue)` | Convenience accessor for config values |
```js
// main.js
const greeting = getConfig('greeting', 'Hello')
const banner = document.createElement('div')
banner.textContent = greeting
banner.style.cssText = 'position:fixed;top:0;left:0;z-index:99999;padding:8px;background:#2563eb;color:#fff'
document.body.appendChild(banner)
```
::: warning No top-level `return`
Because your code is wrapped in an IIFE, a top-level `return` statement is invalid and is rejected by the market validator.
:::
## Config items
`configItems[]` build a settings UI for the user. Each item:
```json
{
"key": "speedLevel",
"name": "Speed",
"description": "Scroll speed multiplier",
"type": "NUMBER",
"defaultValue": "3",
"options": [],
"required": false,
"placeholder": "",
"validation": ""
}
```
Supported `type` values: `TEXT`, `TEXTAREA`, `NUMBER`, `BOOLEAN`, `SELECT`, `MULTI_SELECT`, `RADIO`, `CHECKBOX`, `COLOR`, `URL`, `EMAIL`, `PASSWORD`, `REGEX`, `CSS_SELECTOR`, `JAVASCRIPT`, `JSON`, `RANGE`, `DATE`, `TIME`, `DATETIME`, `FILE`, `IMAGE`.
Read values with `getConfig(key, defaultValue)`.
## Interactive panel
For a floating UI, provide `panelHtml` and register a panel button:
```js
window.__DKC_MODULE_UI__.register({
id: __MODULE_INFO__.id,
name: __MODULE_INFO__.name,
icon: __MODULE_INFO__.icon
})
```
Inside `panelHtml`, use `data-dkc-action` attributes wired to `window.__dkc_module_action_<name>` handlers, and style with the `var(--dkc-*)` theme variables so your panel matches the app theme.
## Multi-file modules
`codeFiles` is a `Map<filename, source>`. The entry point is auto-detected from `main.js`, `index.js`, `app.js`, `script.js`, or `content.js`.
## Packaging & sharing
- Module export extension: `.dkcmod`; a bundle of modules: `.dkcpkg`.
- Share code prefix: `DKC1:` (full gzip + Base64) or `DKC2:` (defaults-diff + max compression, emitted when V1 overflows one QR code), shareable via QR. Decoders accept V2, V1, and legacy bare Base64.
See the built-in `hello-world` and `auto-scroll` modules under [`modules/`](https://github.com/shiaho777/web-to-app/tree/main/modules) for complete working examples.