flare-plugin-sdk 0.0.0-stage → 0.1.0-beta.2
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.
- package/LICENSE +661 -0
- package/README.md +131 -2
- package/package.json +33 -4
- package/skill/flare-plugin/ABI.md +334 -0
- package/skill/flare-plugin/README.md +204 -0
- package/skill/flare-plugin/SKILL.md +80 -0
- package/skill/flare-plugin/assets/github-template/README.md +71 -0
- package/skill/flare-plugin/assets/github-template/assets/icon.png +0 -0
- package/skill/flare-plugin/assets/github-template/manifest.json +29 -0
- package/skill/flare-plugin/assets/github-template/plugin.js +108 -0
- package/skill/flare-plugin/examples/pixelfed/README.md +78 -0
- package/skill/flare-plugin/examples/pixelfed/assets/icon.png +0 -0
- package/skill/flare-plugin/examples/pixelfed/locales/en.json +24 -0
- package/skill/flare-plugin/examples/pixelfed/locales/zh-Hans.json +24 -0
- package/skill/flare-plugin/examples/pixelfed/manifest.json +211 -0
- package/skill/flare-plugin/examples/pixelfed/plugin.js +793 -0
- package/skill/flare-plugin/flare-plugin.d.ts +501 -0
- package/skill/flare-plugin/pack.mjs +155 -0
- package/skill/flare-plugin/references/authentication.md +239 -0
- package/skill/flare-plugin/references/capabilities.md +88 -0
- package/skill/flare-plugin/references/manifest.md +192 -0
- package/skill/flare-plugin/references/publishing.md +111 -0
- package/skill/flare-plugin/references/recipes.md +328 -0
- package/skill/flare-plugin/references/runtime-http.md +207 -0
- package/skill/flare-plugin/references/testing.md +176 -0
- package/skill/flare-plugin/references/troubleshooting.md +116 -0
- package/skill/flare-plugin/references/wire-data.md +163 -0
package/README.md
CHANGED
|
@@ -1,3 +1,132 @@
|
|
|
1
|
-
#
|
|
1
|
+
# Flare Plugin SDK
|
|
2
2
|
|
|
3
|
-
|
|
3
|
+
`flare-plugin-sdk` contains editor types, a local package command,
|
|
4
|
+
templates, examples, and a portable AI authoring skill for Social Plugin API v1.
|
|
5
|
+
Flare provides the plugin runtime. Supported targets are Android, JVM Desktop,
|
|
6
|
+
iOS, and native macOS, not Web. Use a Flare build that includes Plugins in Settings;
|
|
7
|
+
this SDK does not promise a minimum public app release.
|
|
8
|
+
|
|
9
|
+
## Install for development
|
|
10
|
+
|
|
11
|
+
Install the npm preview:
|
|
12
|
+
|
|
13
|
+
```sh
|
|
14
|
+
npm install --save-dev flare-plugin-sdk@next
|
|
15
|
+
```
|
|
16
|
+
|
|
17
|
+
To validate a Flare checkout without publication, build a local tarball instead:
|
|
18
|
+
|
|
19
|
+
```sh
|
|
20
|
+
cd feature/plugin/sdk
|
|
21
|
+
npm ci
|
|
22
|
+
npm test
|
|
23
|
+
npm pack --pack-destination /tmp
|
|
24
|
+
```
|
|
25
|
+
|
|
26
|
+
Install the resulting `.tgz` in your plugin project with
|
|
27
|
+
`npm install --save-dev /path/to/flare-plugin-sdk-VERSION.tgz`.
|
|
28
|
+
These local checks and packaging commands do not publish anything.
|
|
29
|
+
|
|
30
|
+
## Create and develop a plugin
|
|
31
|
+
|
|
32
|
+
1. Copy the contents of `node_modules/flare-plugin-sdk/skill/flare-plugin/assets/github-template/`
|
|
33
|
+
into your plugin repository. Replace its IDs, icon, and illustrative website
|
|
34
|
+
endpoints using evidence from the real API.
|
|
35
|
+
2. Read the [complete developer guide](https://github.com/DimensionDev/Flare/tree/feature/plugin/feature/plugin/sdk/skill/flare-plugin).
|
|
36
|
+
The same guide is bundled at `skill/flare-plugin/README.md` inside the npm package,
|
|
37
|
+
with all authentication, capability, runtime, data, testing, and publication references.
|
|
38
|
+
3. Keep your ready-to-run `manifest.json`, classic-script `plugin.js`, one supported
|
|
39
|
+
`assets/icon.<extension>`, and optional `locales/*.json` in a plugin output directory.
|
|
40
|
+
For a TypeScript project, configure your bundler to produce that classic script.
|
|
41
|
+
4. In Desktop or native macOS, select the output directory in Settings → Plugins →
|
|
42
|
+
Plugin development. Start development, then reload after edits or rebuilds.
|
|
43
|
+
5. For local file installation, package that directory from your plugin project:
|
|
44
|
+
|
|
45
|
+
```sh
|
|
46
|
+
npx flare-plugin-pack ./dist ./plugin.fpp
|
|
47
|
+
```
|
|
48
|
+
|
|
49
|
+
The packer accepts plugin files only, so keep source, `.git`, `package.json`,
|
|
50
|
+
`node_modules`, and the generated `.fpp` outside `dist`. It checks archive structure;
|
|
51
|
+
Flare still validates the manifest, registration, permissions, and runtime behavior.
|
|
52
|
+
For GitHub installation, commit the ready-to-run plugin files at the repository
|
|
53
|
+
root and publish a stable tag matching `manifest.version`. npm SDK versions and
|
|
54
|
+
individual plugin versions are independent; GitHub plugin installation ignores
|
|
55
|
+
prerelease tags even though the npm SDK can use them.
|
|
56
|
+
|
|
57
|
+
## Editor types
|
|
58
|
+
|
|
59
|
+
Add the package to your TypeScript project's compiler options:
|
|
60
|
+
|
|
61
|
+
```json
|
|
62
|
+
{
|
|
63
|
+
"compilerOptions": {
|
|
64
|
+
"types": ["flare-plugin-sdk"]
|
|
65
|
+
}
|
|
66
|
+
}
|
|
67
|
+
```
|
|
68
|
+
|
|
69
|
+
Append it to any existing `types` list. For JavaScript, enable `checkJs` as well.
|
|
70
|
+
The declarations provide ambient `definePlugin`, `flare`, and wire types. Do not
|
|
71
|
+
import the SDK at runtime: Flare supplies those globals, and plugin scripts must
|
|
72
|
+
bundle their own runtime dependencies without Node or browser APIs.
|
|
73
|
+
|
|
74
|
+
## Use the AI authoring skill
|
|
75
|
+
|
|
76
|
+
The self-contained skill is in `skill/flare-plugin/` in both the source and npm
|
|
77
|
+
package. Copy that **entire directory** into your agent's skill directory; copying
|
|
78
|
+
only `SKILL.md` loses its types, references, templates, and examples. Follow the
|
|
79
|
+
[skill installation guide](https://github.com/DimensionDev/Flare/blob/feature/plugin/feature/plugin/sdk/skill/flare-plugin/README.md#install-the-skill)
|
|
80
|
+
for Codex or Claude Code, including project scope, verification, and updates.
|
|
81
|
+
All documentation is in English. The complete Pixelfed adapter is bundled at
|
|
82
|
+
`skill/flare-plugin/examples/pixelfed/`.
|
|
83
|
+
|
|
84
|
+
## Validate this SDK
|
|
85
|
+
|
|
86
|
+
From `feature/plugin/sdk`, run `npm ci` and `npm test` with Node 22 or newer.
|
|
87
|
+
The tests build an npm tarball, check its complete resource set and license,
|
|
88
|
+
install it offline in an empty project, type-check an actual consumer, and run
|
|
89
|
+
the installed package command against the bundled template. They do not contact
|
|
90
|
+
a website or publish to npm. Flare's Host and platform acceptance checks are
|
|
91
|
+
documented in `skill/flare-plugin/references/testing.md`.
|
|
92
|
+
|
|
93
|
+
## Publish this SDK (maintainers)
|
|
94
|
+
|
|
95
|
+
For the first publication, use the npm account that will own this unscoped package.
|
|
96
|
+
Subsequent publication and Trusted Publisher setup require package maintainer access;
|
|
97
|
+
GitHub repository permissions do not grant npm access. The package includes the
|
|
98
|
+
repository's AGPL license; its types, templates, and skill remain the canonical source resources.
|
|
99
|
+
|
|
100
|
+
For the first publication, an authorized maintainer can use an npm account with
|
|
101
|
+
2FA, run `npm ci` and `npm test` in this directory, then explicitly run:
|
|
102
|
+
|
|
103
|
+
```sh
|
|
104
|
+
npm login
|
|
105
|
+
npm whoami
|
|
106
|
+
npm publish --access public --tag next
|
|
107
|
+
```
|
|
108
|
+
|
|
109
|
+
Only run that last command when publication is intended. The GitHub workflow does
|
|
110
|
+
not bootstrap a new npm package or configure npm account permissions.
|
|
111
|
+
|
|
112
|
+
After the package exists, configure [npm Trusted Publishing](https://docs.npmjs.com/trusted-publishers/)
|
|
113
|
+
in its npm Settings with GitHub owner `DimensionDev`, repository `Flare`, workflow
|
|
114
|
+
filename `plugin-sdk.yml`, no environment, and permission to publish directly with
|
|
115
|
+
`npm publish`. Use a GitHub-hosted runner. The workflow uses Node 24 and npm's OIDC
|
|
116
|
+
authentication; no long-lived npm token or `NPM_TOKEN` secret is required. npm
|
|
117
|
+
requires CLI 11.5.1 or newer and Node 22.14 or newer. Complete the configuration's
|
|
118
|
+
first successful CI publication within two days, or recreate the expired connection.
|
|
119
|
+
Public OIDC publications from this public repository receive provenance automatically.
|
|
120
|
+
|
|
121
|
+
For subsequent releases:
|
|
122
|
+
|
|
123
|
+
1. Update the SDK version and lockfile together, for example with
|
|
124
|
+
`npm version 0.1.0-beta.2 --no-git-tag-version`, and commit the tested changes.
|
|
125
|
+
2. Tag that commit `plugin-sdk-v0.1.0-beta.2` and push only that tag when ready to publish.
|
|
126
|
+
The workflow rejects a tag that does not exactly match `package.json`.
|
|
127
|
+
3. The workflow validates the tarball first, then publishes prereleases to `next`
|
|
128
|
+
and stable versions to `latest`. Existing app workflows exclude SDK tags.
|
|
129
|
+
|
|
130
|
+
Run the **Plugin SDK** workflow manually to validate a branch or tag; this does not
|
|
131
|
+
publish, even when a tag is selected. Publishing requires a push of a matching
|
|
132
|
+
`plugin-sdk-v*` tag. Branch pushes and pull requests do not start this workflow.
|
package/package.json
CHANGED
|
@@ -1,6 +1,35 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "flare-plugin-sdk",
|
|
3
|
-
"version": "0.
|
|
4
|
-
"
|
|
5
|
-
"
|
|
6
|
-
|
|
3
|
+
"version": "0.1.0-beta.2",
|
|
4
|
+
"description": "Types, tooling, templates and authoring references for Flare plugins",
|
|
5
|
+
"license": "SEE LICENSE IN LICENSE",
|
|
6
|
+
"homepage": "https://github.com/DimensionDev/Flare#plugins-beta",
|
|
7
|
+
"repository": {
|
|
8
|
+
"type": "git",
|
|
9
|
+
"url": "git+https://github.com/DimensionDev/Flare.git",
|
|
10
|
+
"directory": "feature/plugin/sdk"
|
|
11
|
+
},
|
|
12
|
+
"bugs": {
|
|
13
|
+
"url": "https://github.com/DimensionDev/Flare/issues"
|
|
14
|
+
},
|
|
15
|
+
"bin": {
|
|
16
|
+
"flare-plugin-pack": "skill/flare-plugin/pack.mjs"
|
|
17
|
+
},
|
|
18
|
+
"types": "skill/flare-plugin/flare-plugin.d.ts",
|
|
19
|
+
"files": [
|
|
20
|
+
"skill/flare-plugin/"
|
|
21
|
+
],
|
|
22
|
+
"engines": {
|
|
23
|
+
"node": ">=22"
|
|
24
|
+
},
|
|
25
|
+
"publishConfig": {
|
|
26
|
+
"access": "public",
|
|
27
|
+
"registry": "https://registry.npmjs.org/"
|
|
28
|
+
},
|
|
29
|
+
"scripts": {
|
|
30
|
+
"test": "node --test scripts/*.test.mjs"
|
|
31
|
+
},
|
|
32
|
+
"devDependencies": {
|
|
33
|
+
"typescript": "6.0.3"
|
|
34
|
+
}
|
|
35
|
+
}
|
|
@@ -0,0 +1,334 @@
|
|
|
1
|
+
# Flare Social Plugin API v1
|
|
2
|
+
|
|
3
|
+
This directory is the authoring contract for Social Plugin API v1. Prefer
|
|
4
|
+
[GitHub distribution](references/publishing.md); local `.fpp` installation is
|
|
5
|
+
also supported. Start with the [authoring guide](README.md) or [agent skill](SKILL.md).
|
|
6
|
+
The Host implementation remains authoritative when this document and code disagree.
|
|
7
|
+
|
|
8
|
+
## Package
|
|
9
|
+
|
|
10
|
+
An API v1 package is a ZIP with a `.fpp` extension and exactly these files:
|
|
11
|
+
|
|
12
|
+
```text
|
|
13
|
+
manifest.json
|
|
14
|
+
plugin.js
|
|
15
|
+
assets/icon.png
|
|
16
|
+
locales/<bcp47>.json # optional
|
|
17
|
+
```
|
|
18
|
+
|
|
19
|
+
The package must contain exactly one `assets/icon.<extension>`: `png`, `jpg`,
|
|
20
|
+
`jpeg`, `webp`, `gif`, or `ico`. Its extension must match its encoded contents.
|
|
21
|
+
The icon is kept unchanged, limited to 2 MiB and 1024×1024 pixels. SVG is not
|
|
22
|
+
supported. PNG remains the default in the templates.
|
|
23
|
+
|
|
24
|
+
`plugin.js` is one self-contained classic script. Static modules, dynamic
|
|
25
|
+
imports, remote code, filesystem access, and native access are unavailable.
|
|
26
|
+
Run `node pack.mjs <directory> [output.fpp]` to produce a deterministic package
|
|
27
|
+
using only Node's standard library.
|
|
28
|
+
|
|
29
|
+
## GitHub installation and updates
|
|
30
|
+
|
|
31
|
+
Flare can install from a public `https://github.com/<owner>/<repository>` URL
|
|
32
|
+
(an optional `.git` suffix is accepted). Each repository contains one plugin at
|
|
33
|
+
its root: `manifest.json`, the self-contained, already-built `plugin.js`,
|
|
34
|
+
one supported `assets/icon.<extension>`, and optional `locales/*.json`. Other development files are
|
|
35
|
+
ignored. Flare does not run package managers, build scripts, or repository code
|
|
36
|
+
outside the existing plugin sandbox.
|
|
37
|
+
|
|
38
|
+
Publish a stable SemVer tag such as `1.2.3` or `v1.2.3`; removing the optional
|
|
39
|
+
lowercase `v` must exactly match `manifest.version`. Pre-release and arbitrary
|
|
40
|
+
tags are excluded from the version picker and update checks. A GitHub Release
|
|
41
|
+
or uploaded `.fpp` asset is not required.
|
|
42
|
+
|
|
43
|
+
The Host lists tags, compares semantic versions, resolves the selected commit,
|
|
44
|
+
and downloads its source ZIP by commit SHA. It imports the plugin files into a
|
|
45
|
+
canonical `.fpp` and applies the same package, registration, compatibility, and
|
|
46
|
+
permission checks as local installation. The repository archive is limited to
|
|
47
|
+
20 MiB compressed, 50 MiB uncompressed, and 4,096 entries; existing per-file and
|
|
48
|
+
plugin package limits still apply. Traversal paths, symlinks, duplicate paths,
|
|
49
|
+
and multiple archive roots are rejected, including in ignored files.
|
|
50
|
+
|
|
51
|
+
GitHub installation records the repository ID, canonical owner/name, tag, and
|
|
52
|
+
commit SHA. Updates must retain that repository ID, plugin ID, and platform ID.
|
|
53
|
+
Checks only offer updates; downloading and confirming the existing install
|
|
54
|
+
review remain separate user actions, and changes take effect immediately.
|
|
55
|
+
New permissions, source changes, and a tag pointing to a different commit are
|
|
56
|
+
shown in the review. Cancellation or failure leaves the installed plugin intact.
|
|
57
|
+
|
|
58
|
+
Opening plugin management checks for updates using a five-minute metadata cache;
|
|
59
|
+
manual checks bypass it. Checks include all tag pages up to 1,000 tags and report
|
|
60
|
+
an error rather than claim a result from an incomplete list. GitHub requests use
|
|
61
|
+
the global proxy policy, without account credentials, and respect rate-limit retry
|
|
62
|
+
headers. Private repositories,
|
|
63
|
+
branch tracking, client-side builds, and automatic installation are unsupported.
|
|
64
|
+
|
|
65
|
+
## Registration
|
|
66
|
+
|
|
67
|
+
The script calls `definePlugin` once. It registers named services; it does not
|
|
68
|
+
implement a universal dispatcher:
|
|
69
|
+
|
|
70
|
+
```js
|
|
71
|
+
definePlugin({
|
|
72
|
+
detector: { async detect(request, context) {} },
|
|
73
|
+
login: {
|
|
74
|
+
oauth: {
|
|
75
|
+
async begin(request, context) {},
|
|
76
|
+
async resume(request, context) {},
|
|
77
|
+
},
|
|
78
|
+
},
|
|
79
|
+
capabilities: {
|
|
80
|
+
timeline: { async page(request, context) {} },
|
|
81
|
+
post: {
|
|
82
|
+
async detail(request, context) {},
|
|
83
|
+
async mutate(request, context) {},
|
|
84
|
+
},
|
|
85
|
+
},
|
|
86
|
+
});
|
|
87
|
+
```
|
|
88
|
+
|
|
89
|
+
The manifest is the static upper bound. Every declared known operation must
|
|
90
|
+
have the corresponding function, or installation fails. Login returns the
|
|
91
|
+
subset supported by that account and instance. Unknown capability IDs remain
|
|
92
|
+
visible as compatibility warnings but are ignored by this Host.
|
|
93
|
+
|
|
94
|
+
Current method paths are:
|
|
95
|
+
|
|
96
|
+
| Capability | Service operations |
|
|
97
|
+
| --- | --- |
|
|
98
|
+
| `flare.datasource.timeline/v1` | `timeline.page` |
|
|
99
|
+
| `flare.datasource.search/v1` | `search.posts`, `profiles`, `discoverPosts`, `discoverProfiles`, `discoverHashtags` |
|
|
100
|
+
| `flare.datasource.profile/v1` | `profile.byId`, `byHandle`, `timeline`, `following`, `followers` |
|
|
101
|
+
| `flare.datasource.post/v1` | `post.detail`, `context`, `delete`, `mutate` |
|
|
102
|
+
| `flare.datasource.relation/v1` | `relation.state`, `mutate` |
|
|
103
|
+
| `flare.datasource.compose/v1` | `compose.publish` |
|
|
104
|
+
| `flare.datasource.notification/v1` | `notification.page`, `badge` |
|
|
105
|
+
| `flare.datasource.list/v1` | `list.page`, `detail`, `create`, `update`, `delete`, `timeline`, `members`, `memberships`, `addMember`, `removeMember` |
|
|
106
|
+
| `flare.datasource.direct-message/v1` | `directMessage.rooms`, `room`, `messages`, `send`, `delete`, `leave`, `create`, `badge`, `canSend` |
|
|
107
|
+
| `flare.datasource.article/v1` | `article.detail`, `comments` |
|
|
108
|
+
| `flare.datasource.gallery/v1` | `gallery.detail`, `comments`, `recommendations` |
|
|
109
|
+
| `flare.datasource.tab-catalog/v1` | `tabCatalog.page` |
|
|
110
|
+
|
|
111
|
+
The [capability matrix](references/capabilities.md) distinguishes required and
|
|
112
|
+
optional operations and explains UI dependencies. `PluginAbiV1.kt` defines the
|
|
113
|
+
Host contract. Use [flare-plugin.d.ts](flare-plugin.d.ts) for the complete v1
|
|
114
|
+
JavaScript types and [recipes](references/recipes.md) for implementation guidance.
|
|
115
|
+
|
|
116
|
+
Capabilities that map to a full Host interface must declare its required
|
|
117
|
+
operation set; installation rejects partial interfaces. Notification filters
|
|
118
|
+
(`all`, `mention`, `comment`, `like`) and relation actions (`follow`, `block`,
|
|
119
|
+
`mute`) are static arrays on their capability manifest declarations. They are
|
|
120
|
+
not asynchronous JavaScript methods because Flare needs them synchronously to
|
|
121
|
+
decide which controls to show.
|
|
122
|
+
|
|
123
|
+
## Invocation and state
|
|
124
|
+
|
|
125
|
+
Native Apple targets use system JavaScriptCore, Android uses AndroidX JavaScriptEngine,
|
|
126
|
+
and Compose Desktop uses QuickJS. Await/return required asynchronous work: the Host
|
|
127
|
+
waits for started Host tasks before completing the invocation, but detached Promise
|
|
128
|
+
rejections do not automatically fail it. Returned/awaited errors retain normal typed
|
|
129
|
+
or fatal handling. Engine availability, version differences, cancellation, and resource
|
|
130
|
+
limits are described in [Runtime and HTTP](references/runtime-http.md).
|
|
131
|
+
|
|
132
|
+
Every method receives immutable request and context values. JavaScript globals
|
|
133
|
+
are disposable cache only. Plugins have no lifecycle or migration hooks.
|
|
134
|
+
|
|
135
|
+
Runtime scopes are detector attempt, login flow, account, and guest origin.
|
|
136
|
+
Calls in one Runtime serialize. A fatal JavaScript error, timeout, cancellation,
|
|
137
|
+
out-of-memory condition, or invalid Wire result retires that Runtime.
|
|
138
|
+
|
|
139
|
+
All values crossing the boundary are JSON Wire v1 DTOs. IDs use
|
|
140
|
+
`{ "id": "...", "host": "..." }`; page responses use `items`,
|
|
141
|
+
`olderCursor`, `newerCursor`, and `endReached`. Timestamps are ISO-8601 strings.
|
|
142
|
+
Rich text is `{ "format": "plain|html", "value": "..." }`; Flare sanitizes
|
|
143
|
+
HTML before rendering.
|
|
144
|
+
|
|
145
|
+
`PostV1` requires `key`, `createdAt`, and `content`. Its `author` and `visibility`
|
|
146
|
+
fields default to null and accept explicit null. A provided author must satisfy
|
|
147
|
+
the complete `ProfileV1` contract. The Host does not synthesize an author or infer
|
|
148
|
+
public visibility. These rules also apply to nested reposts and `updatedPost`
|
|
149
|
+
results; an updated post is a complete snapshot, so omitted fields do not retain
|
|
150
|
+
their previous values.
|
|
151
|
+
|
|
152
|
+
HTML resource and link URLs must use HTTPS without URL credentials. Relative
|
|
153
|
+
URLs resolve against the selected instance. Local files, `content:`, `data:`,
|
|
154
|
+
`javascript:`, and other schemes are rejected before rendering.
|
|
155
|
+
|
|
156
|
+
## Post detail navigation
|
|
157
|
+
|
|
158
|
+
Each `PostV1` may set `detailType` to `"post"`, `"article"`, `"gallery"`, or `"link"`.
|
|
159
|
+
Omitting it defaults to `"post"`.
|
|
160
|
+
For example, a timeline may return an article preview with `detailType: "article"`
|
|
161
|
+
alongside regular posts and gallery previews. The selected detail receives that
|
|
162
|
+
post's `key` and uses the same account or guest origin. Reposted content keeps
|
|
163
|
+
its own `detailType`.
|
|
164
|
+
|
|
165
|
+
For internal details, the target capability must be available for that account
|
|
166
|
+
(or declared for guest access), including its required operations: `post.detail`; `article.detail` and
|
|
167
|
+
`comments`; or `gallery.detail`, `comments`, and `recommendations`. Otherwise the
|
|
168
|
+
post click does nothing; it does not fall back to another detail type. In media
|
|
169
|
+
grids, article and gallery previews use the same detail click target.
|
|
170
|
+
|
|
171
|
+
For `"link"`, the existing `url` field is required and must contain an absolute
|
|
172
|
+
HTTPS URL without URL credentials. The Host opens it through the existing browser
|
|
173
|
+
flow, following the user's browser settings and bypassing internal detail-link
|
|
174
|
+
matching. No post/article/gallery detail capability is required. Post and grid
|
|
175
|
+
cover clicks use this target; author and action buttons keep their own behavior.
|
|
176
|
+
For example (other required post fields omitted):
|
|
177
|
+
|
|
178
|
+
```js
|
|
179
|
+
{ detailType: "link", url: "https://example.com/article/123" }
|
|
180
|
+
```
|
|
181
|
+
|
|
182
|
+
The URL remains optional for the three internal detail types. Missing or invalid
|
|
183
|
+
link URLs, and unknown or null `detailType` values, are invalid Wire results.
|
|
184
|
+
|
|
185
|
+
## Host API
|
|
186
|
+
|
|
187
|
+
The frozen `flare` object exposes:
|
|
188
|
+
|
|
189
|
+
- `flare.http.request`: JSON, text, form, and streaming multipart HTTP;
|
|
190
|
+
- `flare.credential.read/replace`: the current account credential only;
|
|
191
|
+
- `flare.crypto.randomHex/uuid/sha256`;
|
|
192
|
+
- `flare.locale.current`;
|
|
193
|
+
- `flare.error`: marks a typed error safe to cross the ABI.
|
|
194
|
+
|
|
195
|
+
Authentication is structured:
|
|
196
|
+
|
|
197
|
+
```js
|
|
198
|
+
await flare.http.request({
|
|
199
|
+
url: context.origin + "/api/v1/account",
|
|
200
|
+
authorization: { type: "bearer", token },
|
|
201
|
+
});
|
|
202
|
+
```
|
|
203
|
+
|
|
204
|
+
Do not set raw `Authorization`, `Cookie`, `Host`, or `Content-Length` headers.
|
|
205
|
+
Compose bytes never enter JavaScript. Forward the request's asset handle:
|
|
206
|
+
|
|
207
|
+
```js
|
|
208
|
+
await flare.http.request({
|
|
209
|
+
method: "POST",
|
|
210
|
+
url: context.origin + "/api/v1/media",
|
|
211
|
+
body: {
|
|
212
|
+
type: "multipart",
|
|
213
|
+
parts: [{ type: "asset", name: "file", handle: asset.handle }],
|
|
214
|
+
},
|
|
215
|
+
});
|
|
216
|
+
```
|
|
217
|
+
|
|
218
|
+
Detector calls may access only the candidate origin. Login calls may also use
|
|
219
|
+
exact HTTPS origins listed in `permissions.authOrigins`. Account and guest
|
|
220
|
+
calls use the verified account origin. Redirects stay on the current origin.
|
|
221
|
+
|
|
222
|
+
Automatic media loading is a separate permission, disabled by default. A plugin
|
|
223
|
+
that returns avatars, images, audio, video, covers, or HTML images must declare
|
|
224
|
+
`"permissions": { "mediaNetwork": true }`. Installation review explicitly grants
|
|
225
|
+
media requests to any website, including CDNs and federated servers; these URLs
|
|
226
|
+
can transmit the plugin account's data. Adding this permission during an update
|
|
227
|
+
requires confirmation. It does not expand `flare.http.request` origins or permit
|
|
228
|
+
local-file resources. Text-only plugins do not need it. Cached profiles, posts,
|
|
229
|
+
article history, and direct messages retain their plugin ownership and recheck
|
|
230
|
+
the running package's grant when restored, including translated and nested media.
|
|
231
|
+
Permission removal and uninstall take effect immediately, like the
|
|
232
|
+
package change itself; absent plugins cannot restore media.
|
|
233
|
+
Development caches predating ownership metadata are rebuilt on upgrade.
|
|
234
|
+
|
|
235
|
+
Flare owns HTTP routing: detector, guest, and new-login requests follow the
|
|
236
|
+
global proxy policy; account requests and relogin requests follow that account's
|
|
237
|
+
policy, including OAuth resumed after restart. Plugins cannot select a proxy.
|
|
238
|
+
Proxy failures never fall back to direct connections, and changing a route may
|
|
239
|
+
cancel its in-flight requests, including uploads.
|
|
240
|
+
|
|
241
|
+
## Login
|
|
242
|
+
|
|
243
|
+
For OAuth, Flare owns `flowId`, state, callback validation, persistence,
|
|
244
|
+
expiry, replay protection, and relogin identity validation. `begin` returns:
|
|
245
|
+
|
|
246
|
+
```js
|
|
247
|
+
{
|
|
248
|
+
type: "externalBrowser",
|
|
249
|
+
url: authorizationUrl,
|
|
250
|
+
pendingPayload: { /* bounded opaque JSON */ },
|
|
251
|
+
}
|
|
252
|
+
```
|
|
253
|
+
|
|
254
|
+
`resume` receives validated callback parameters and returns:
|
|
255
|
+
|
|
256
|
+
```js
|
|
257
|
+
{
|
|
258
|
+
type: "success",
|
|
259
|
+
value: {
|
|
260
|
+
accountId,
|
|
261
|
+
origin: context.origin,
|
|
262
|
+
credential: { accessToken },
|
|
263
|
+
profile,
|
|
264
|
+
capabilities: { "flare.datasource.timeline/v1": ["page"] },
|
|
265
|
+
composeConfig,
|
|
266
|
+
},
|
|
267
|
+
}
|
|
268
|
+
```
|
|
269
|
+
|
|
270
|
+
At least one displayable capability must be negotiated. `accountId` must equal
|
|
271
|
+
`profile.key.id`, and `profile.key.host` must equal the selected origin's host.
|
|
272
|
+
The Host retains this login profile as the current account's identity for account
|
|
273
|
+
menus, compose, notifications, discovery/search, and direct-message selection when
|
|
274
|
+
a plugin does not provide profile lookup. This fallback never enables arbitrary
|
|
275
|
+
profile lookup or profile timelines. Cached login media follows the current grant. Login cannot replace an existing account owned
|
|
276
|
+
by another platform with the same account ID and host.
|
|
277
|
+
|
|
278
|
+
## Errors
|
|
279
|
+
|
|
280
|
+
Only errors created with `flare.error` are recoverable plugin errors:
|
|
281
|
+
|
|
282
|
+
```js
|
|
283
|
+
throw flare.error({
|
|
284
|
+
code: "RateLimited",
|
|
285
|
+
message: { key: "error.rateLimited", fallback: "Try again later" },
|
|
286
|
+
retryAfterSeconds: 30,
|
|
287
|
+
});
|
|
288
|
+
```
|
|
289
|
+
|
|
290
|
+
Codes are `AuthenticationRequired`, `NotFound`, `Validation`, `RateLimited`,
|
|
291
|
+
`Network`, `Remote`, `Unsupported`, `InvalidResponse`, and `Cancelled`.
|
|
292
|
+
Unmarked exceptions are fatal and retire the Runtime generation.
|
|
293
|
+
|
|
294
|
+
## Manifest text, icon, and Deep Links
|
|
295
|
+
|
|
296
|
+
Plugin-authored manifest text may be either a final string or:
|
|
297
|
+
|
|
298
|
+
```json
|
|
299
|
+
{ "key": "timeline.home", "fallback": "Home" }
|
|
300
|
+
```
|
|
301
|
+
|
|
302
|
+
Localized keys must exist in the default locale catalog. Resolution uses exact
|
|
303
|
+
BCP-47 tag, language-script, language, default locale, then fallback. The only
|
|
304
|
+
formatting feature in v1 is named `{argument}` substitution.
|
|
305
|
+
|
|
306
|
+
The packaged image is the platform icon on every target and the icon for default
|
|
307
|
+
timeline tabs. The first automatically added default tab uses `platform.name`;
|
|
308
|
+
other defaults and the manual-add list retain timeline titles. Other manifest
|
|
309
|
+
icons use Host semantic enum names. See the
|
|
310
|
+
[tab presentation rules](references/manifest.md#default-and-manually-added-tabs).
|
|
311
|
+
Deep Links, when needed, are manifest-only structured rules; JavaScript cannot
|
|
312
|
+
resolve them.
|
|
313
|
+
|
|
314
|
+
For full field defaults and validation, read the [manifest reference](references/manifest.md).
|
|
315
|
+
All five authentication interactions are covered in [authentication](references/authentication.md).
|
|
316
|
+
|
|
317
|
+
## Lifecycle and trust
|
|
318
|
+
|
|
319
|
+
Install, update, and uninstall take effect immediately. Installed plugins are always enabled. Local packages are always unverified. Repository trust is
|
|
320
|
+
Host-owned; a manifest cannot claim official status or broader runtime access.
|
|
321
|
+
|
|
322
|
+
Uninstall removes the plugin's accounts, credentials, account-scoped caches,
|
|
323
|
+
selections/tabs, and draft targets from this device, together with local source
|
|
324
|
+
and package files. Shared drafts and attachments remain while another account
|
|
325
|
+
uses them. Updates preserve accounts. Loading failures or restoring accounts
|
|
326
|
+
without their plugin leave accounts unavailable; they do not delete them.
|
|
327
|
+
Login, publishing, and uploads can delay or block replacement/removal. Closed
|
|
328
|
+
sessions cannot recreate accounts through a late callback. Account ownership and
|
|
329
|
+
the persisted removal intent are checked before any account data is changed.
|
|
330
|
+
Once removal starts, an account-cleanup or final-index-write failure keeps the
|
|
331
|
+
plugin stopped, including after restart, and its management entry remains
|
|
332
|
+
available to retry deletion. Updates and installation cannot reactivate a plugin
|
|
333
|
+
with incomplete removal. Unused package-file cleanup is repeatable through
|
|
334
|
+
plugin management's cleanup action after deletion completes.
|