@vormio/plugin-sdk 0.0.6 → 0.0.7-rc.1
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/README.md +33 -5
- package/dist/bridge.d.ts +5 -0
- package/dist/manifest.d.ts +2 -2
- package/dist/manifest.js +1 -1
- package/dist/report.js +4 -0
- package/package.json +1 -1
package/README.md
CHANGED
|
@@ -1,8 +1,8 @@
|
|
|
1
1
|
# @vormio/plugin-sdk
|
|
2
2
|
|
|
3
|
-
The manifest schema, runtime helpers and packaging command for writing Vormio plugins, plus the commands that publish a signed plugin catalog. The package is versioned with Vormio-Core (currently 0.0.
|
|
3
|
+
The manifest schema, runtime helpers and packaging command for writing Vormio plugins, plus the commands that publish a signed plugin catalog. The package is versioned with Vormio-Core (currently 0.0.7) and published to npm under the MIT license: `npm install @vormio/plugin-sdk@0.0.7`.
|
|
4
4
|
|
|
5
|
-
Plugin contract version: `apiVersion:
|
|
5
|
+
Plugin contract version: `apiVersion: 3`. During development (0.0.x) there is no cross-version compatibility promise: the host loads only plugins with the same `apiVersion` as its own.
|
|
6
6
|
|
|
7
7
|
## What a plugin can do
|
|
8
8
|
|
|
@@ -28,7 +28,7 @@ A plugin is a folder: a `manifest.json` at the root plus the built static files.
|
|
|
28
28
|
|
|
29
29
|
```json
|
|
30
30
|
{
|
|
31
|
-
"apiVersion":
|
|
31
|
+
"apiVersion": 3,
|
|
32
32
|
"id": "acme.model-viewer",
|
|
33
33
|
"version": "0.1.0",
|
|
34
34
|
"name": "Model Viewer",
|
|
@@ -164,6 +164,7 @@ interface CompositionReport {
|
|
|
164
164
|
key?: string // Points to a subresource in this file; give exactly one of uri and key
|
|
165
165
|
role: string // Display role, e.g. "Base color texture"
|
|
166
166
|
evidence?: string // Location in the file, e.g. "/images/2/uri"
|
|
167
|
+
inferred?: string // Not written in the file: how you inferred it, e.g. "Same name as the skeleton"
|
|
167
168
|
}[]
|
|
168
169
|
/** Problems found during analysis, at most 500. */
|
|
169
170
|
diagnostics: { severity: 'error' | 'warning' | 'info'; message: string; key?: string }[]
|
|
@@ -172,12 +173,37 @@ interface CompositionReport {
|
|
|
172
173
|
}
|
|
173
174
|
```
|
|
174
175
|
|
|
175
|
-
- The host validates reports with `compositionReportSchema` (`parseReport` also checks the size); plugins can check themselves against the same schema before returning. The report serialized as JSON is at most 4 MiB (counted in UTF-8 bytes). Names and keys are at most 200 characters, kinds and roles 80, evidence 300, diagnostics 500 and addresses 2,048. Names, kinds, roles and evidence must not contain control characters.
|
|
176
|
-
- The report is invalid if it has duplicate keys, a `parent`, `from` or `key` that points to a missing subresource, a cyclic hierarchy,
|
|
176
|
+
- The host validates reports with `compositionReportSchema` (`parseReport` also checks the size); plugins can check themselves against the same schema before returning. The report serialized as JSON is at most 4 MiB (counted in UTF-8 bytes). Names and keys are at most 200 characters, kinds and roles 80, bases of inference 120, evidence 300, diagnostics 500 and addresses 2,048. Names, kinds, roles, bases of inference and evidence must not contain control characters.
|
|
177
|
+
- The report is invalid if it has duplicate keys, a `parent`, `from` or `key` that points to a missing subresource, a cyclic hierarchy, a reference with both or neither of `uri` and `key`, or an `inferred` reference with a `key`.
|
|
177
178
|
- Write `uri` exactly as it appears in the file; do not resolve it yourself. The host decodes percent-encoding once, ignores everything after `?` and `#`, treats `\` as `/`, resolves it relative to the analyzed file and classifies it: a file in the linked folder, out of bounds (`..` leaving the linked folder), embedded (`data:`), external (absolute paths, drive letters, other schemes) or invalid (undecodable, containing control characters, or pointing to a folder). Whether the target exists is decided by the host at query time.
|
|
178
179
|
- For embedded data (`data:`), report only the header up to the comma, e.g. `data:image/png;base64`. The host classifies it as embedded by prefix and does not store the content; a full `data:` address often exceeds 2,048 characters and would invalidate the whole report.
|
|
179
180
|
- Reporting a reference does not require reading the target file, so you do not need `companionFormats` just to report references. Declare them only when the analysis actually reads companion files.
|
|
180
181
|
|
|
182
|
+
### Inferred references
|
|
183
|
+
|
|
184
|
+
Some formats pair files by convention rather than by an address in the file. A Spine skeleton does not name its atlas; the runtime pairs `hero.json` with `hero.atlas` because they share a name. Report such a relation as an inferred reference, with the basis of the inference in `inferred`:
|
|
185
|
+
|
|
186
|
+
```ts
|
|
187
|
+
analyzer(async (input) => {
|
|
188
|
+
const skeleton = parseSkeleton(await readInput(input))
|
|
189
|
+
const atlas = `${input.name.replace(/\.[^.]*$/, '')}.atlas`
|
|
190
|
+
return {
|
|
191
|
+
...skeleton.report,
|
|
192
|
+
references: [
|
|
193
|
+
...skeleton.report.references,
|
|
194
|
+
{ uri: atlas, role: 'Atlas', inferred: 'Same name as the skeleton' },
|
|
195
|
+
],
|
|
196
|
+
}
|
|
197
|
+
})
|
|
198
|
+
```
|
|
199
|
+
|
|
200
|
+
- Mark a reference as inferred only when the file does not write the address. References read from the file stay as they are.
|
|
201
|
+
- The basis is shown to the user as is. Say why you think the relation exists, not where it is.
|
|
202
|
+
- Write the address relative to the analyzed file and do not check that the target exists: the host decides at query time, so a target that appears or disappears needs no new analysis.
|
|
203
|
+
- The host shows inferred references apart from written ones. A missing target is shown as "not found": it does not count as a missing reference, does not appear in the missing references filter and gets no note about where a moved file went, because the convention may simply not apply.
|
|
204
|
+
- The inference may depend on the file's name. When an analyzed file with inferred references is renamed or moved, the host analyzes it again.
|
|
205
|
+
- Do not report the same target both as written and as inferred.
|
|
206
|
+
|
|
181
207
|
## Packaging and development
|
|
182
208
|
|
|
183
209
|
The package declares `"sideEffects": false`: when a plugin page uses only the runtime helpers, bundlers (esbuild, Vite, Rollup, webpack) drop the manifest schema and its zod dependency, leaving about 1 KB of runtime code for a minimal page. Node-side packaging and validation are imported from `@vormio/plugin-sdk/node`.
|
|
@@ -190,6 +216,8 @@ The command validates the manifest and every file, then writes a zip-format `.vo
|
|
|
190
216
|
|
|
191
217
|
During development, open the **插件** (Plugins) page in Vormio, choose **添加开发目录…** (Add development folder…) and point it at the build output folder. The host watches the folder: every change is validated again, and a valid build reloads the plugin. If validation fails, the last valid version stays loaded and the error is shown on the plugin card. Vormio never runs build commands.
|
|
192
218
|
|
|
219
|
+
When the host lacks something your plugin needs, or behaves wrongly, open an issue at [Vormio/Vormio-Core](https://github.com/Vormio/Vormio-Core/issues) with the plugin request template: the scenario, the plugin capability it blocks, what you expect, and how to tell it works. Host capabilities are added in a generic form, never for one format. A contract change may first ship as a prerelease under the npm tag `next` (`npm install @vormio/plugin-sdk@next`) so you can try it; `latest` follows Vormio releases.
|
|
220
|
+
|
|
193
221
|
## Plugin catalogs
|
|
194
222
|
|
|
195
223
|
A plugin catalog is a signed `catalog.json` plus the plugin packages it lists, on static hosting. Vormio installs and updates plugins from it. Publishers produce one with two commands:
|
package/dist/bridge.d.ts
CHANGED
|
@@ -39,6 +39,11 @@ export interface ReportReference {
|
|
|
39
39
|
role: string;
|
|
40
40
|
/** Where in the file the reference is, such as "/images/2/uri". */
|
|
41
41
|
evidence?: string;
|
|
42
|
+
/**
|
|
43
|
+
* The reference is not written in the file: how the analyzer inferred it, shown to the user, such
|
|
44
|
+
* as "Same name as the skeleton". Only with `uri`. A missing target is "not found", not missing.
|
|
45
|
+
*/
|
|
46
|
+
inferred?: string;
|
|
42
47
|
}
|
|
43
48
|
export interface ReportDiagnostic {
|
|
44
49
|
severity: 'error' | 'warning' | 'info';
|
package/dist/manifest.d.ts
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
import { z } from 'zod';
|
|
2
2
|
/** The plugin contract version this SDK describes. Hosts load only plugins with this version. */
|
|
3
|
-
export declare const pluginApiVersion =
|
|
3
|
+
export declare const pluginApiVersion = 3;
|
|
4
4
|
declare const contributionSchema: z.ZodObject<{
|
|
5
5
|
id: z.ZodString;
|
|
6
6
|
entry: z.ZodString;
|
|
@@ -13,7 +13,7 @@ export declare const pluginIdSchema: z.ZodString;
|
|
|
13
13
|
/** A semantic version without build metadata. */
|
|
14
14
|
export declare const versionSchema: z.ZodString;
|
|
15
15
|
export declare const manifestSchema: z.ZodObject<{
|
|
16
|
-
apiVersion: z.ZodLiteral<
|
|
16
|
+
apiVersion: z.ZodLiteral<3>;
|
|
17
17
|
id: z.ZodString;
|
|
18
18
|
version: z.ZodString;
|
|
19
19
|
name: z.ZodString;
|
package/dist/manifest.js
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
import { z } from 'zod';
|
|
2
2
|
import { checkPackagePath } from "./package-rules.js";
|
|
3
3
|
/** The plugin contract version this SDK describes. Hosts load only plugins with this version. */
|
|
4
|
-
export const pluginApiVersion =
|
|
4
|
+
export const pluginApiVersion = 3;
|
|
5
5
|
const unique = (values) => new Set(values).size === values.length;
|
|
6
6
|
const extension = z.string().regex(/^[a-z0-9]{1,16}$/, 'Use a lower-case extension without a dot');
|
|
7
7
|
const extensions = (min) => z.array(extension).min(min).max(64).refine(unique, 'Extensions must not repeat');
|
package/dist/report.js
CHANGED
|
@@ -27,9 +27,13 @@ const referenceSchema = z
|
|
|
27
27
|
key: key.optional(),
|
|
28
28
|
role: plain(80).min(1),
|
|
29
29
|
evidence: plain(300).optional(),
|
|
30
|
+
inferred: plain(120).min(1).optional(),
|
|
30
31
|
})
|
|
31
32
|
.refine((reference) => (reference.uri === undefined) !== (reference.key === undefined), {
|
|
32
33
|
message: 'Give exactly one of uri and key',
|
|
34
|
+
})
|
|
35
|
+
.refine((reference) => reference.inferred === undefined || reference.uri !== undefined, {
|
|
36
|
+
message: 'Only a reference with a uri can be inferred',
|
|
33
37
|
});
|
|
34
38
|
const diagnosticSchema = z.strictObject({
|
|
35
39
|
severity: z.enum(['error', 'warning', 'info']),
|