initiative-plugin-sdk 4.1.1 → 5.0.0
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 +71 -17
- package/dist/contract.d.ts +27 -17
- package/dist/contract.js +7 -7
- package/dist/contract.js.map +1 -1
- package/dist/define.d.ts +18 -10
- package/dist/define.js +5 -4
- package/dist/define.js.map +1 -1
- package/dist/manifest.d.ts +4 -2
- package/dist/manifest.js +3 -1
- package/dist/manifest.js.map +1 -1
- package/dist/plugin-api.d.ts +20 -0
- package/dist/plugin-api.generated.d.ts +2 -2
- package/dist/plugin-api.generated.js +2 -2
- package/dist/plugin-api.js +35 -0
- package/dist/plugin-api.js.map +1 -0
- package/dist/server.d.ts +2 -2
- package/dist/server.js +6 -6
- package/dist/server.js.map +1 -1
- package/dist/tokens.d.ts +3 -3
- package/dist/tokens.js +3 -3
- package/dist/tokens.js.map +1 -1
- package/dist/validate.js +4 -4
- package/dist/validate.js.map +1 -1
- package/manifest.contract.json +20 -15
- package/package.json +3 -2
- package/schemas/plugin-api.json +20925 -0
- package/schemas/plugin-manifest.json +12 -7
package/README.md
CHANGED
|
@@ -10,11 +10,12 @@ holds its tokens, and builds its manifest.
|
|
|
10
10
|
|
|
11
11
|
| Import | Holds |
|
|
12
12
|
|---|---|
|
|
13
|
-
| `initiative-plugin-sdk/manifest` | `definePlugin`, `defineEndpoint`, the contract's types, `validateManifest` |
|
|
13
|
+
| `initiative-plugin-sdk/manifest` | `definePlugin`, `defineEndpoint`, the contract's types, `validateManifest`, `pluginApiCompatible` |
|
|
14
14
|
| `initiative-plugin-sdk/server` | `createPlugin`, `serve`, `EndpointError` |
|
|
15
15
|
| `initiative-plugin-sdk/client` | `Initiative` and the `Client` it gives, acting as the community or a member; plug-in keys |
|
|
16
16
|
| `initiative-plugin-sdk/widget` | What a widget is handed, and the scenes it returns |
|
|
17
17
|
| `initiative-plugin-sdk/testing` | A declarative plug-in's requests and maps, run against recorded vendor answers |
|
|
18
|
+
| `initiative-plugin-sdk/plugin-api.json` | The plug-in API contract: the OpenAPI document of every route a plug-in may call |
|
|
18
19
|
| bin `initiative-plugin` | `init`, `build`, `pack`, `dev`, `validate`, `keygen`, `uid`, `schema` |
|
|
19
20
|
|
|
20
21
|
Node 20 or later. Two runtime dependencies, `ajv` and `jsonata`; everything
|
|
@@ -77,7 +78,7 @@ export default definePlugin({
|
|
|
77
78
|
uses the key.
|
|
78
79
|
- **Everything else is the contract's own shape**, from
|
|
79
80
|
[`manifest.contract.json`](manifest.contract.json): `vendor`, `connections`
|
|
80
|
-
(keyed by id), `webhooks`, `
|
|
81
|
+
(keyed by id), `webhooks`, `pages` (keyed by id),
|
|
81
82
|
`dashboards`. The types are generated from the contract, so every term the
|
|
82
83
|
contract declares has a type here.
|
|
83
84
|
- **Features follow from what is filled in.** A plug-in with widgets declares
|
|
@@ -172,12 +173,12 @@ vendor: {
|
|
|
172
173
|
key must be a vendor field, each answer is written at most once, and
|
|
173
174
|
`client_secret`, `pem` and `webhook_secret` go to `secret` fields.
|
|
174
175
|
|
|
175
|
-
###
|
|
176
|
+
### Pages
|
|
176
177
|
|
|
177
|
-
A
|
|
178
|
+
A page is one of your plug-in's screens, framed by Initiative:
|
|
178
179
|
|
|
179
180
|
```ts
|
|
180
|
-
|
|
181
|
+
pages: {
|
|
181
182
|
board: {
|
|
182
183
|
path: "/board",
|
|
183
184
|
name: { en: "Board" },
|
|
@@ -191,8 +192,8 @@ surfaces: {
|
|
|
191
192
|
```
|
|
192
193
|
|
|
193
194
|
Initiative hands the frame a one-use handoff token. Send it from the page to
|
|
194
|
-
any path under the
|
|
195
|
-
(type, signature, audience,
|
|
195
|
+
any path under the page's as `Authorization: Bearer …`: the SDK verifies it
|
|
196
|
+
(type, signature, audience, page, and that it was not used before) and hands the
|
|
196
197
|
handler `viewer`, `admin`, `initiative` and a `client` acting as the
|
|
197
198
|
installation, narrowed to that initiative.
|
|
198
199
|
|
|
@@ -275,7 +276,7 @@ speaks `Request` and `Response`. `serve` runs it on `node:http`, on `PORT`
|
|
|
275
276
|
| `GET /.well-known/initiative-plugin.json` | The manifest document: the manifest with the plug-in's id, uid and name. |
|
|
276
277
|
| `GET, POST /v1/endpoints` | What the plug-in declares; Initiative's endpoint calls, on a context token. |
|
|
277
278
|
| `POST /v1/hooks/{name}` | Initiative's hook calls, on a lifecycle token for that hook. |
|
|
278
|
-
| a
|
|
279
|
+
| a page's path | The page's handler. |
|
|
279
280
|
|
|
280
281
|
Every call's token is verified against the deployment's JWKS, which is cached
|
|
281
282
|
and refetched once for a key it does not know. Each kind carries its own `typ`
|
|
@@ -368,10 +369,10 @@ for (const { installation, active } of await initiative.installations()) {
|
|
|
368
369
|
`files:write`), or, where Initiative checks each item, at least one of
|
|
369
370
|
them. `MissingScopeError` names the scope instead. Writing implies reading.
|
|
370
371
|
|
|
371
|
-
`client.api`
|
|
372
|
-
|
|
373
|
-
|
|
374
|
-
|
|
372
|
+
`client.api` is generated from the plug-in API contract this SDK publishes
|
|
373
|
+
([The plug-in API contract](#the-plug-in-api-contract)), so it changes as
|
|
374
|
+
the contract does: a minor release adds routes and fields, and only a major
|
|
375
|
+
release removes or changes one.
|
|
375
376
|
`PluginApiSchemas["TaskRead"]` names a schema's type.
|
|
376
377
|
- `client.request(method, path, { scope, body })` calls a community route (the
|
|
377
378
|
path after `/c/{community}`) by hand, with the same scope check.
|
|
@@ -426,6 +427,19 @@ the build, so a misspelt placeholder cannot ship. `baseUrl` is where the
|
|
|
426
427
|
service answers on the Compose network, an http or https URL of at most 512
|
|
427
428
|
characters; Initiative pre-fills the deployment's base URL with it.
|
|
428
429
|
|
|
430
|
+
`minAppVersion` is the oldest Initiative release a version runs on. Beside it,
|
|
431
|
+
the definition's `minPluginApi` (the manifest's `min_plugin_api`) is the
|
|
432
|
+
oldest [plug-in API contract](#the-plug-in-api-contract) the plug-in calls, as
|
|
433
|
+
`"MAJOR.MINOR"`: the SDK version its `client.api` was written against.
|
|
434
|
+
|
|
435
|
+
```ts
|
|
436
|
+
definePlugin({ publicId: "acme.tracker", /* … */ minPluginApi: "4.1" });
|
|
437
|
+
```
|
|
438
|
+
|
|
439
|
+
A deployment serving contract `4.3.2` runs it; one serving `4.0.5` or `5.0.0`
|
|
440
|
+
does not. Leave it out and the plug-in makes no claim: it is offered on any
|
|
441
|
+
contract, as listings written before the field were.
|
|
442
|
+
|
|
429
443
|
```sh
|
|
430
444
|
npx initiative-plugin build --registry ../registry/sources
|
|
431
445
|
```
|
|
@@ -564,7 +578,7 @@ it("lists a repository's open issues", async () => {
|
|
|
564
578
|
connection's state; a delivery may be routed by a `header` instead of a
|
|
565
579
|
body `path`.
|
|
566
580
|
- **One plug-in is one kind.** A declarative plug-in has no handlers, hooks,
|
|
567
|
-
schedules or
|
|
581
|
+
schedules or pages, and asks for no scopes; a container plug-in uses none of
|
|
568
582
|
these terms. `validateManifest` and `build` refuse a mix.
|
|
569
583
|
|
|
570
584
|
`runEndpoint`, `runAfterConnect`, `runHealth` and `runWebhook` render each
|
|
@@ -642,10 +656,45 @@ may say. `schemas/plugin-manifest.json` and `src/contract.ts` (its types) are
|
|
|
642
656
|
generated from it with `npm run generate`; `npm run check:generated` fails when
|
|
643
657
|
either is stale. Initiative vendors the contract from this repository's tags.
|
|
644
658
|
|
|
645
|
-
|
|
646
|
-
|
|
647
|
-
|
|
648
|
-
|
|
659
|
+
## The plug-in API contract
|
|
660
|
+
|
|
661
|
+
A plug-in and Initiative release on their own schedules. What they share is
|
|
662
|
+
one file this package publishes, `schemas/plugin-api.json`, exported as
|
|
663
|
+
`initiative-plugin-sdk/plugin-api.json`: the OpenAPI document of every route a
|
|
664
|
+
plug-in may call, as Initiative describes it. A plug-in depends on an SDK
|
|
665
|
+
version and nothing else.
|
|
666
|
+
|
|
667
|
+
- **The contract version is this package's version.** The file's
|
|
668
|
+
`info.version` is the SDK's version, and `info["x-initiative-source"]` names
|
|
669
|
+
the Initiative release and commit the document was taken from. A minor
|
|
670
|
+
release adds operations, fields or optional parameters; removing or changing
|
|
671
|
+
anything is a major release.
|
|
672
|
+
- **Every client comes from the file.** `src/plugin-api.generated.ts`, behind
|
|
673
|
+
`client.api`, is generated from `schemas/plugin-api.json`, never from
|
|
674
|
+
Initiative directly. A plug-in in another language generates its own client
|
|
675
|
+
from the same file, at the SDK version it targets.
|
|
676
|
+
- **A deployment serves the contract it vendors.** Initiative carries a copy of
|
|
677
|
+
this file from an SDK release, serves that SDK version as its plug-in API
|
|
678
|
+
version, and checks in its own CI that what it serves still holds every
|
|
679
|
+
route, parameter and response field the copy has. It may serve more.
|
|
680
|
+
- **A plug-in names the oldest contract it needs**, as `min_plugin_api`
|
|
681
|
+
(`"MAJOR.MINOR"`) in its manifest. A deployment serving contract `S` runs a
|
|
682
|
+
plug-in needing `N` when they share a major version and `S`'s minor is at
|
|
683
|
+
least `N`'s. A manifest without the field runs on any contract.
|
|
684
|
+
Initiative, the registry and the SDK decide with the same rule, exported as
|
|
685
|
+
`pluginApiCompatible`:
|
|
686
|
+
|
|
687
|
+
```ts
|
|
688
|
+
import { pluginApiCompatible } from "initiative-plugin-sdk/manifest";
|
|
689
|
+
|
|
690
|
+
pluginApiCompatible("4.3.2", "4.1"); // true
|
|
691
|
+
pluginApiCompatible("5.0.0", "4.1"); // false: another major
|
|
692
|
+
pluginApiCompatible("4.3.2", undefined); // true: no claim
|
|
693
|
+
```
|
|
694
|
+
|
|
695
|
+
The file is never edited by hand. Take it again when Initiative's plug-in API
|
|
696
|
+
grows, from a checkout, a release or a running deployment; this rewrites the
|
|
697
|
+
file at the package's version and then the client from it:
|
|
649
698
|
|
|
650
699
|
```sh
|
|
651
700
|
npm run generate:plugin-api -- --checkout ../initiative # runs its export with uv
|
|
@@ -653,6 +702,11 @@ npm run generate:plugin-api -- --release v0.75.0
|
|
|
653
702
|
npm run generate:plugin-api -- --url https://initiative.example.com
|
|
654
703
|
```
|
|
655
704
|
|
|
705
|
+
With no source, `npm run generate:plugin-api` regenerates the client from the
|
|
706
|
+
file and restamps its `info.version` with the package's; the Promote workflow
|
|
707
|
+
does this when it bumps the version. `npm run check:generated` fails when
|
|
708
|
+
either the file's version or the client is stale.
|
|
709
|
+
|
|
656
710
|
## Scopes
|
|
657
711
|
|
|
658
712
|
| Scope | Grants |
|
package/dist/contract.d.ts
CHANGED
|
@@ -8,7 +8,7 @@
|
|
|
8
8
|
* from, and the shape of every object it defines, so this package's types
|
|
9
9
|
* cannot describe a manifest the schema refuses, nor miss a term it allows.
|
|
10
10
|
*/
|
|
11
|
-
export type Feature = "dashboards" | "
|
|
11
|
+
export type Feature = "dashboards" | "endpoints" | "pages" | "widgets";
|
|
12
12
|
export declare const FEATURES: readonly Feature[];
|
|
13
13
|
export type Protocol = 1;
|
|
14
14
|
export declare const PROTOCOLS: readonly Protocol[];
|
|
@@ -46,8 +46,8 @@ export type Scope = "projects:read" | "projects:write" | "files:read" | "files:w
|
|
|
46
46
|
export declare const SCOPES: readonly Scope[];
|
|
47
47
|
export type SurfaceScope = "community" | "initiative";
|
|
48
48
|
export declare const SURFACE_SCOPES: readonly SurfaceScope[];
|
|
49
|
-
export type
|
|
50
|
-
export declare const
|
|
49
|
+
export type PageCapability = "camera" | "clipboard-read" | "clipboard-write" | "display-capture" | "fullscreen" | "geolocation" | "microphone";
|
|
50
|
+
export declare const PAGE_CAPABILITIES: readonly PageCapability[];
|
|
51
51
|
export type ListingKind = "plugin" | "dashboard";
|
|
52
52
|
export declare const LISTING_KINDS: readonly ListingKind[];
|
|
53
53
|
export type HttpMethod = "DELETE" | "GET" | "PATCH" | "POST" | "PUT";
|
|
@@ -78,8 +78,8 @@ export declare const CAPS: {
|
|
|
78
78
|
readonly endpoints: 64;
|
|
79
79
|
readonly paramsPerEndpoint: 12;
|
|
80
80
|
readonly returnsPerEndpoint: 24;
|
|
81
|
-
readonly
|
|
82
|
-
readonly
|
|
81
|
+
readonly pages: 12;
|
|
82
|
+
readonly pageCapabilities: 8;
|
|
83
83
|
readonly bundledDashboards: 8;
|
|
84
84
|
readonly dashboardWidgets: 50;
|
|
85
85
|
readonly dashboardGridColumns: 12;
|
|
@@ -116,7 +116,7 @@ export declare const CAPS: {
|
|
|
116
116
|
readonly hosts: 8;
|
|
117
117
|
readonly hostLength: 253;
|
|
118
118
|
readonly steps: 3;
|
|
119
|
-
readonly
|
|
119
|
+
readonly maxPages: 10;
|
|
120
120
|
readonly perPage: 100;
|
|
121
121
|
readonly requestQuery: 24;
|
|
122
122
|
readonly requestHeaders: 12;
|
|
@@ -173,7 +173,7 @@ export declare const FIELDS: {
|
|
|
173
173
|
readonly schedule: readonly ["id", "every"];
|
|
174
174
|
readonly endpoint: readonly ["id", "label", "description", "returns", "group", "needs_subject", "direction", "params", "actors", "admin_only", "public", "requires", "cache_ttl_seconds", "identity", "unavailable", "request", "steps", "map", "errors"];
|
|
175
175
|
readonly widget: readonly ["id", "meta", "module_source", "endpoints", "sample_data", "requires"];
|
|
176
|
-
readonly
|
|
176
|
+
readonly page: readonly ["id", "path", "name", "scopes", "admin_only", "capabilities", "requires"];
|
|
177
177
|
readonly bundledDashboard: readonly ["uid", "public_id", "name", "description", "layout", "widgets"];
|
|
178
178
|
readonly bundledDashboardWidget: readonly ["id", "type", "title", "grid", "binding"];
|
|
179
179
|
readonly endpointIdentity: readonly ["kind", "key"];
|
|
@@ -190,7 +190,7 @@ export declare const FIELDS: {
|
|
|
190
190
|
readonly healthState: readonly ["status", "when", "state"];
|
|
191
191
|
readonly webhookEvent: readonly ["when", "emit", "map"];
|
|
192
192
|
readonly webhookStatus: readonly ["when", "connection", "state"];
|
|
193
|
-
readonly manifest: readonly ["plugin_kind", "service", "features", "default_name", "minimum_age", "hosts", "auth", "vendor", "connections", "webhooks", "schedules", "endpoints", "community_summary", "widgets", "
|
|
193
|
+
readonly manifest: readonly ["plugin_kind", "service", "features", "default_name", "minimum_age", "min_plugin_api", "hosts", "auth", "vendor", "connections", "webhooks", "schedules", "endpoints", "community_summary", "widgets", "pages", "dashboards"];
|
|
194
194
|
};
|
|
195
195
|
export type Identifier = string;
|
|
196
196
|
/**
|
|
@@ -791,26 +791,26 @@ export interface Widget {
|
|
|
791
791
|
sample_data?: Record<string, unknown>;
|
|
792
792
|
requires?: Requires;
|
|
793
793
|
}
|
|
794
|
-
export interface
|
|
794
|
+
export interface Page {
|
|
795
795
|
id: Identifier;
|
|
796
796
|
path: Path;
|
|
797
797
|
name: LocalizedText;
|
|
798
798
|
/**
|
|
799
|
-
* Where the
|
|
800
|
-
*
|
|
799
|
+
* Where the page renders. Declaring both gives it a community-wide entry and
|
|
800
|
+
* an entry inside each initiative.
|
|
801
801
|
*/
|
|
802
802
|
scopes?: SurfaceScope[];
|
|
803
803
|
/**
|
|
804
|
-
* Only the community's admins open this
|
|
805
|
-
* allows — a settings page, say. Who else may open a
|
|
804
|
+
* Only the community's admins open this page, whatever roles a placement
|
|
805
|
+
* allows — a settings page, say. Who else may open a page is chosen in the
|
|
806
806
|
* community, per initiative and per role, not declared here.
|
|
807
807
|
*/
|
|
808
808
|
admin_only?: boolean;
|
|
809
809
|
/**
|
|
810
|
-
* Browser features the frame is granted. A
|
|
811
|
-
*
|
|
810
|
+
* Browser features the frame is granted. A page that names nothing is framed
|
|
811
|
+
* with all of them denied.
|
|
812
812
|
*/
|
|
813
|
-
capabilities?:
|
|
813
|
+
capabilities?: PageCapability[];
|
|
814
814
|
requires?: Requires;
|
|
815
815
|
}
|
|
816
816
|
export interface BundledDashboard {
|
|
@@ -1232,6 +1232,16 @@ export interface Manifest {
|
|
|
1232
1232
|
* each from 13 to 21.
|
|
1233
1233
|
*/
|
|
1234
1234
|
minimum_age?: Record<string, number>;
|
|
1235
|
+
/**
|
|
1236
|
+
* The oldest plug-in API contract this plug-in needs, as 'MAJOR.MINOR':
|
|
1237
|
+
* '4.1'. The contract is the plug-in API published with
|
|
1238
|
+
* initiative-plugin-sdk, versioned as that package is. A deployment serving
|
|
1239
|
+
* contract S can run it when S has the same major version and a minor version
|
|
1240
|
+
* at least this one's. Absent: any contract; the plug-in makes no claim.
|
|
1241
|
+
* Beside a listing's min_app_version, the oldest Initiative release it runs
|
|
1242
|
+
* on, this says what the plug-in calls rather than which release serves it.
|
|
1243
|
+
*/
|
|
1244
|
+
min_plugin_api?: string;
|
|
1235
1245
|
/**
|
|
1236
1246
|
* Declarative plug-ins, which must name at least one: every host their
|
|
1237
1247
|
* requests, paging and links may reach. A container plug-in names none.
|
|
@@ -1260,7 +1270,7 @@ export interface Manifest {
|
|
|
1260
1270
|
*/
|
|
1261
1271
|
community_summary?: NamespacedId;
|
|
1262
1272
|
widgets?: Widget[];
|
|
1263
|
-
|
|
1273
|
+
pages?: Page[];
|
|
1264
1274
|
/**
|
|
1265
1275
|
* Ready-made arrangements of this plug-in's own widgets. Publishing the
|
|
1266
1276
|
* plug-in publishes one ordinary dashboard listing per entry, offered to
|
package/dist/contract.js
CHANGED
|
@@ -8,7 +8,7 @@
|
|
|
8
8
|
* from, and the shape of every object it defines, so this package's types
|
|
9
9
|
* cannot describe a manifest the schema refuses, nor miss a term it allows.
|
|
10
10
|
*/
|
|
11
|
-
export const FEATURES = ["dashboards", "
|
|
11
|
+
export const FEATURES = ["dashboards", "endpoints", "pages", "widgets"];
|
|
12
12
|
export const PROTOCOLS = [1];
|
|
13
13
|
export const CONNECTION_SCOPES = ["interactive", "static"];
|
|
14
14
|
export const FLOW_TYPES = ["oauth2"];
|
|
@@ -27,7 +27,7 @@ export const DIRECTIONS = ["emit", "read", "write"];
|
|
|
27
27
|
export const ACTOR_KINDS = ["installation", "member"];
|
|
28
28
|
export const SCOPES = ["projects:read", "projects:write", "files:read", "files:write", "queues:read", "queues:write", "counter_groups:read", "counter_groups:write", "calendars:read", "calendars:write", "dashboards:read", "dashboards:write", "posts:read", "posts:write", "galleries:read", "galleries:write", "wikis:read", "wikis:write", "comments:read", "comments:write", "relationships:read", "relationships:write", "tags:read", "tags:write", "properties:read", "properties:write", "sharing:read", "sharing:write", "members:read", "initiatives:read", "initiatives:moderate", "community:admin"];
|
|
29
29
|
export const SURFACE_SCOPES = ["community", "initiative"];
|
|
30
|
-
export const
|
|
30
|
+
export const PAGE_CAPABILITIES = ["camera", "clipboard-read", "clipboard-write", "display-capture", "fullscreen", "geolocation", "microphone"];
|
|
31
31
|
export const LISTING_KINDS = ["plugin", "dashboard"];
|
|
32
32
|
export const HTTP_METHODS = ["DELETE", "GET", "PATCH", "POST", "PUT"];
|
|
33
33
|
export const PAGE_LIMITS = ["refuse", "truncate"];
|
|
@@ -52,8 +52,8 @@ export const CAPS = {
|
|
|
52
52
|
endpoints: 64,
|
|
53
53
|
paramsPerEndpoint: 12,
|
|
54
54
|
returnsPerEndpoint: 24,
|
|
55
|
-
|
|
56
|
-
|
|
55
|
+
pages: 12,
|
|
56
|
+
pageCapabilities: 8,
|
|
57
57
|
bundledDashboards: 8,
|
|
58
58
|
dashboardWidgets: 50,
|
|
59
59
|
dashboardGridColumns: 12,
|
|
@@ -90,7 +90,7 @@ export const CAPS = {
|
|
|
90
90
|
hosts: 8,
|
|
91
91
|
hostLength: 253,
|
|
92
92
|
steps: 3,
|
|
93
|
-
|
|
93
|
+
maxPages: 10,
|
|
94
94
|
perPage: 100,
|
|
95
95
|
requestQuery: 24,
|
|
96
96
|
requestHeaders: 12,
|
|
@@ -147,7 +147,7 @@ export const FIELDS = {
|
|
|
147
147
|
schedule: ["id", "every"],
|
|
148
148
|
endpoint: ["id", "label", "description", "returns", "group", "needs_subject", "direction", "params", "actors", "admin_only", "public", "requires", "cache_ttl_seconds", "identity", "unavailable", "request", "steps", "map", "errors"],
|
|
149
149
|
widget: ["id", "meta", "module_source", "endpoints", "sample_data", "requires"],
|
|
150
|
-
|
|
150
|
+
page: ["id", "path", "name", "scopes", "admin_only", "capabilities", "requires"],
|
|
151
151
|
bundledDashboard: ["uid", "public_id", "name", "description", "layout", "widgets"],
|
|
152
152
|
bundledDashboardWidget: ["id", "type", "title", "grid", "binding"],
|
|
153
153
|
endpointIdentity: ["kind", "key"],
|
|
@@ -164,6 +164,6 @@ export const FIELDS = {
|
|
|
164
164
|
healthState: ["status", "when", "state"],
|
|
165
165
|
webhookEvent: ["when", "emit", "map"],
|
|
166
166
|
webhookStatus: ["when", "connection", "state"],
|
|
167
|
-
manifest: ["plugin_kind", "service", "features", "default_name", "minimum_age", "hosts", "auth", "vendor", "connections", "webhooks", "schedules", "endpoints", "community_summary", "widgets", "
|
|
167
|
+
manifest: ["plugin_kind", "service", "features", "default_name", "minimum_age", "min_plugin_api", "hosts", "auth", "vendor", "connections", "webhooks", "schedules", "endpoints", "community_summary", "widgets", "pages", "dashboards"],
|
|
168
168
|
};
|
|
169
169
|
//# sourceMappingURL=contract.js.map
|
package/dist/contract.js.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"contract.js","sourceRoot":"","sources":["../src/contract.ts"],"names":[],"mappings":"AAAA;;;;;;;;;GASG;AAGH,MAAM,CAAC,MAAM,QAAQ,GAAuB,CAAC,YAAY,EAAE,
|
|
1
|
+
{"version":3,"file":"contract.js","sourceRoot":"","sources":["../src/contract.ts"],"names":[],"mappings":"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"}
|
package/dist/define.d.ts
CHANGED
|
@@ -2,7 +2,7 @@
|
|
|
2
2
|
* One typed definition of a plug-in.
|
|
3
3
|
*
|
|
4
4
|
* {@link definePlugin} takes everything a plug-in declares and does: its endpoints
|
|
5
|
-
* with their handlers, its hooks and schedules, its widgets and
|
|
5
|
+
* with their handlers, its hooks and schedules, its widgets and pages, and
|
|
6
6
|
* its listing. The same object routes Initiative's calls (`createPlugin`) and
|
|
7
7
|
* becomes the manifest (`initiative-plugin build`), so nothing is stated twice.
|
|
8
8
|
*
|
|
@@ -20,7 +20,7 @@
|
|
|
20
20
|
* parameter's `options_from`, a bundled dashboard, `communitySummary`) it uses the
|
|
21
21
|
* key.
|
|
22
22
|
*/
|
|
23
|
-
import type { ActorKind, PluginScope, BundledDashboard, BundledDashboardWidget, Connection,
|
|
23
|
+
import type { ActorKind, PluginScope, BundledDashboard, BundledDashboardWidget, Connection, Page, Endpoint, EndpointParam, EndpointReturn, ErrorRule, Expression, Manifest, RequestStep, ReturnValueType, Scope, Vendor, VendorAuth, VendorRequest, WebhookEvent, Webhooks, Widget } from "./contract.js";
|
|
24
24
|
import type { Client } from "./client.js";
|
|
25
25
|
/**
|
|
26
26
|
* What every handler is handed as `context`: the value given to `createPlugin`.
|
|
@@ -184,17 +184,17 @@ export interface ScheduleDeclaration {
|
|
|
184
184
|
every: `${number}${"m" | "h"}`;
|
|
185
185
|
run: (call: ScheduleCall) => Promise<void>;
|
|
186
186
|
}
|
|
187
|
-
/** A member opening one of the plug-in's
|
|
187
|
+
/** A member opening one of the plug-in's pages, as the handoff token names them. */
|
|
188
188
|
export interface Handoff extends Call {
|
|
189
|
-
|
|
189
|
+
page: string;
|
|
190
190
|
/** The member, by this installation's reference for them. */
|
|
191
191
|
viewer: string;
|
|
192
192
|
/** Whether the viewer administers the community. For shaping screens; not a grant. */
|
|
193
193
|
admin: boolean;
|
|
194
|
-
/** The initiative the
|
|
194
|
+
/** The initiative the page was opened in, or null for the whole community. */
|
|
195
195
|
initiative: number | null;
|
|
196
196
|
}
|
|
197
|
-
export interface
|
|
197
|
+
export interface PageCall {
|
|
198
198
|
request: Request;
|
|
199
199
|
/** Null for a request that carries no handoff token, such as the page's own files. */
|
|
200
200
|
handoff: Handoff | null;
|
|
@@ -204,8 +204,8 @@ export interface SurfaceCall {
|
|
|
204
204
|
* request under its path that carries a handoff token reaches the handler with
|
|
205
205
|
* the handoff verified.
|
|
206
206
|
*/
|
|
207
|
-
export interface
|
|
208
|
-
handler?: (call:
|
|
207
|
+
export interface PageDeclaration extends Omit<Page, "id"> {
|
|
208
|
+
handler?: (call: PageCall) => Promise<Response>;
|
|
209
209
|
}
|
|
210
210
|
type ReadName<E> = {
|
|
211
211
|
[K in keyof E]: E[K] extends {
|
|
@@ -296,6 +296,14 @@ export interface PluginDefinition<E, W> {
|
|
|
296
296
|
name: string;
|
|
297
297
|
/** How old somebody must be to use it, by ISO 3166-1 alpha-2 country, with `default` for the rest: `{ default: 16, US: 13 }`. */
|
|
298
298
|
minimumAge?: Record<string, number>;
|
|
299
|
+
/**
|
|
300
|
+
* The oldest plug-in API contract the plug-in needs, as `"MAJOR.MINOR"`: the
|
|
301
|
+
* SDK version whose `client.api` it was written against, such as `"4.1"`. A
|
|
302
|
+
* deployment serving a contract of the same major version and at least this
|
|
303
|
+
* minor runs it (`pluginApiCompatible`). Absent: no claim. Beside
|
|
304
|
+
* `listing.minAppVersion`, the oldest Initiative release it runs on.
|
|
305
|
+
*/
|
|
306
|
+
minPluginApi?: string;
|
|
299
307
|
scopes?: Array<Scope | PluginScope>;
|
|
300
308
|
/** A declarative plug-in's hosts: every host its requests may reach. Naming them makes the plug-in declarative. */
|
|
301
309
|
hosts?: string[];
|
|
@@ -312,8 +320,8 @@ export interface PluginDefinition<E, W> {
|
|
|
312
320
|
communitySummary?: ReadName<E>;
|
|
313
321
|
hooks?: Hooks;
|
|
314
322
|
widgets?: W;
|
|
315
|
-
/** Pages and panels, keyed by
|
|
316
|
-
|
|
323
|
+
/** Pages and panels, keyed by page id. */
|
|
324
|
+
pages?: Record<string, PageDeclaration>;
|
|
317
325
|
dashboards?: DashboardDeclaration<E, W>[];
|
|
318
326
|
listing?: ListingDeclaration;
|
|
319
327
|
}
|
package/dist/define.js
CHANGED
|
@@ -2,7 +2,7 @@
|
|
|
2
2
|
* One typed definition of a plug-in.
|
|
3
3
|
*
|
|
4
4
|
* {@link definePlugin} takes everything a plug-in declares and does: its endpoints
|
|
5
|
-
* with their handlers, its hooks and schedules, its widgets and
|
|
5
|
+
* with their handlers, its hooks and schedules, its widgets and pages, and
|
|
6
6
|
* its listing. The same object routes Initiative's calls (`createPlugin`) and
|
|
7
7
|
* becomes the manifest (`initiative-plugin build`), so nothing is stated twice.
|
|
8
8
|
*
|
|
@@ -51,9 +51,9 @@ export function manifestOf(plugin, modules = {}) {
|
|
|
51
51
|
endpoints: listOf(plugin.endpoints, (key, endpoint) => endpointOf(id(key), endpoint, id)),
|
|
52
52
|
community_summary: plugin.communitySummary === undefined ? undefined : id(plugin.communitySummary),
|
|
53
53
|
widgets: listOf(plugin.widgets, (key, widget) => widgetOf(key, widget, modules[key] ?? "", id)),
|
|
54
|
-
|
|
55
|
-
const { handler: _handler, ...
|
|
56
|
-
return { id: key, ...
|
|
54
|
+
pages: listOf(plugin.pages, (key, page) => {
|
|
55
|
+
const { handler: _handler, ...declared } = page;
|
|
56
|
+
return { id: key, ...declared };
|
|
57
57
|
}),
|
|
58
58
|
dashboards: plugin.dashboards?.map((dashboard) => ({
|
|
59
59
|
...dashboard,
|
|
@@ -72,6 +72,7 @@ export function manifestOf(plugin, modules = {}) {
|
|
|
72
72
|
features: FEATURES.filter((feature) => present[feature] !== undefined),
|
|
73
73
|
default_name: plugin.name,
|
|
74
74
|
...(plugin.minimumAge ? { minimum_age: { ...plugin.minimumAge } } : {}),
|
|
75
|
+
...(plugin.minPluginApi !== undefined ? { min_plugin_api: plugin.minPluginApi } : {}),
|
|
75
76
|
...(plugin.hosts ? { hosts: [...plugin.hosts] } : {}),
|
|
76
77
|
...(plugin.auth ? { auth: plugin.auth } : {}),
|
|
77
78
|
...present,
|
package/dist/define.js.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"define.js","sourceRoot":"","sources":["../src/define.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;;;;;;;GAqBG;AAyBH,OAAO,EAAE,QAAQ,EAAE,MAAM,eAAe,CAAC;AAgIzC,MAAM,UAAU,cAAc,CAAC,QAA6B;IAC1D,OAAO,QAAQ,CAAC;AAClB,CAAC;
|
|
1
|
+
{"version":3,"file":"define.js","sourceRoot":"","sources":["../src/define.ts"],"names":[],"mappings":"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"}
|
package/dist/manifest.d.ts
CHANGED
|
@@ -1,8 +1,10 @@
|
|
|
1
1
|
/**
|
|
2
2
|
* `initiative-plugin-sdk/manifest`: the contract as types, the plug-in's one
|
|
3
|
-
* definition,
|
|
3
|
+
* definition, checking a manifest before a deployment does, and the rule for
|
|
4
|
+
* which plug-in API contract a manifest's `min_plugin_api` runs on.
|
|
4
5
|
*/
|
|
5
6
|
export * from "./contract.js";
|
|
6
|
-
export { definePlugin, defineEndpoint, type Actor, type AfterConnectAnswer, type AfterConnectCall, type PluginContext, type PluginDefinition, type Call, type CallableEndpoint, type DashboardDeclaration, type EmittedEndpoint, type EndpointCall, type EndpointDeclaration, type Handoff, type Hooks, type ListingDeclaration, type Outcome, type Params, type ParamSpec, type ParamValue, type Result, type ReturnSpec, type RevokeCall, type ScheduleCall, type ScheduleDeclaration, type
|
|
7
|
+
export { definePlugin, defineEndpoint, type Actor, type AfterConnectAnswer, type AfterConnectCall, type PluginContext, type PluginDefinition, type Call, type CallableEndpoint, type DashboardDeclaration, type EmittedEndpoint, type EndpointCall, type EndpointDeclaration, type Handoff, type Hooks, type ListingDeclaration, type Outcome, type PageCall, type PageDeclaration, type Params, type ParamSpec, type ParamValue, type Result, type ReturnSpec, type RevokeCall, type ScheduleCall, type ScheduleDeclaration, type WebhookCall, type WidgetDeclaration, } from "./define.js";
|
|
7
8
|
export { MANIFEST_PATH, manifestSchema, validateDocument, validateManifest, type PluginDocument, type ValidationProblem, } from "./validate.js";
|
|
9
|
+
export { pluginApiCompatible } from "./plugin-api.js";
|
|
8
10
|
export type { Jwks, PublicJwk } from "./keys.js";
|
package/dist/manifest.js
CHANGED
|
@@ -1,8 +1,10 @@
|
|
|
1
1
|
/**
|
|
2
2
|
* `initiative-plugin-sdk/manifest`: the contract as types, the plug-in's one
|
|
3
|
-
* definition,
|
|
3
|
+
* definition, checking a manifest before a deployment does, and the rule for
|
|
4
|
+
* which plug-in API contract a manifest's `min_plugin_api` runs on.
|
|
4
5
|
*/
|
|
5
6
|
export * from "./contract.js";
|
|
6
7
|
export { definePlugin, defineEndpoint, } from "./define.js";
|
|
7
8
|
export { MANIFEST_PATH, manifestSchema, validateDocument, validateManifest, } from "./validate.js";
|
|
9
|
+
export { pluginApiCompatible } from "./plugin-api.js";
|
|
8
10
|
//# sourceMappingURL=manifest.js.map
|
package/dist/manifest.js.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"manifest.js","sourceRoot":"","sources":["../src/manifest.ts"],"names":[],"mappings":"AAAA
|
|
1
|
+
{"version":3,"file":"manifest.js","sourceRoot":"","sources":["../src/manifest.ts"],"names":[],"mappings":"AAAA;;;;GAIG;AAEH,cAAc,eAAe,CAAC;AAE9B,OAAO,EACL,YAAY,EACZ,cAAc,GA4Bf,MAAM,aAAa,CAAC;AAErB,OAAO,EACL,aAAa,EACb,cAAc,EACd,gBAAgB,EAChB,gBAAgB,GAGjB,MAAM,eAAe,CAAC;AAEvB,OAAO,EAAE,mBAAmB,EAAE,MAAM,iBAAiB,CAAC"}
|
|
@@ -0,0 +1,20 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* The plug-in API contract's one compatibility rule.
|
|
3
|
+
*
|
|
4
|
+
* The contract is `schemas/plugin-api.json`, published at this package's
|
|
5
|
+
* version: a minor release adds to it, a major one removes or changes
|
|
6
|
+
* something. A deployment serves one contract version, `MAJOR.MINOR.PATCH`; a
|
|
7
|
+
* plug-in's manifest may name the oldest it needs, `min_plugin_api`, as
|
|
8
|
+
* `MAJOR.MINOR`. Initiative, the registry and the SDK all decide with this
|
|
9
|
+
* rule, so it is stated once here.
|
|
10
|
+
*/
|
|
11
|
+
/**
|
|
12
|
+
* Whether a deployment serving contract `served` (`"4.1.1"`) can run a plug-in
|
|
13
|
+
* whose manifest needs `required` (`"4.1"`): the same major version, and a
|
|
14
|
+
* minor version at least the one needed. A plug-in that names no
|
|
15
|
+
* `min_plugin_api` (`undefined` or `null`) runs on any contract.
|
|
16
|
+
*
|
|
17
|
+
* Throws a `RangeError` on a version that is not in its form, rather than
|
|
18
|
+
* guessing: a manifest that passed validation cannot carry one.
|
|
19
|
+
*/
|
|
20
|
+
export declare function pluginApiCompatible(served: string, required: string | null | undefined): boolean;
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
/**
|
|
2
|
-
* Generated by scripts/generate-plugin-api.mjs from
|
|
3
|
-
*
|
|
2
|
+
* Generated by scripts/generate-plugin-api.mjs from schemas/plugin-api.json, the plug-in API
|
|
3
|
+
* taken from Initiative 0.74.0 (commit 0492f28bb). Do not edit: regenerate.
|
|
4
4
|
*/
|
|
5
5
|
import type { Scope } from "./contract.js";
|
|
6
6
|
/**
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
/**
|
|
2
|
-
* Generated by scripts/generate-plugin-api.mjs from
|
|
3
|
-
*
|
|
2
|
+
* Generated by scripts/generate-plugin-api.mjs from schemas/plugin-api.json, the plug-in API
|
|
3
|
+
* taken from Initiative 0.74.0 (commit 0492f28bb). Do not edit: regenerate.
|
|
4
4
|
*/
|
|
5
5
|
/**
|
|
6
6
|
* Each operation a plug-in may call: its method, its path after `/api/v1/c/0`, the
|
|
@@ -0,0 +1,35 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* The plug-in API contract's one compatibility rule.
|
|
3
|
+
*
|
|
4
|
+
* The contract is `schemas/plugin-api.json`, published at this package's
|
|
5
|
+
* version: a minor release adds to it, a major one removes or changes
|
|
6
|
+
* something. A deployment serves one contract version, `MAJOR.MINOR.PATCH`; a
|
|
7
|
+
* plug-in's manifest may name the oldest it needs, `min_plugin_api`, as
|
|
8
|
+
* `MAJOR.MINOR`. Initiative, the registry and the SDK all decide with this
|
|
9
|
+
* rule, so it is stated once here.
|
|
10
|
+
*/
|
|
11
|
+
const SERVED = /^([0-9]+)\.([0-9]+)\.([0-9]+)$/;
|
|
12
|
+
const REQUIRED = /^([0-9]+)\.([0-9]+)$/;
|
|
13
|
+
/**
|
|
14
|
+
* Whether a deployment serving contract `served` (`"4.1.1"`) can run a plug-in
|
|
15
|
+
* whose manifest needs `required` (`"4.1"`): the same major version, and a
|
|
16
|
+
* minor version at least the one needed. A plug-in that names no
|
|
17
|
+
* `min_plugin_api` (`undefined` or `null`) runs on any contract.
|
|
18
|
+
*
|
|
19
|
+
* Throws a `RangeError` on a version that is not in its form, rather than
|
|
20
|
+
* guessing: a manifest that passed validation cannot carry one.
|
|
21
|
+
*/
|
|
22
|
+
export function pluginApiCompatible(served, required) {
|
|
23
|
+
const serving = SERVED.exec(served);
|
|
24
|
+
if (!serving)
|
|
25
|
+
throw new RangeError(`the served plug-in API version '${served}' is not MAJOR.MINOR.PATCH`);
|
|
26
|
+
if (required === undefined || required === null)
|
|
27
|
+
return true;
|
|
28
|
+
const needing = REQUIRED.exec(required);
|
|
29
|
+
if (!needing)
|
|
30
|
+
throw new RangeError(`min_plugin_api '${required}' is not MAJOR.MINOR`);
|
|
31
|
+
const [servedMajor, servedMinor] = [Number(serving[1]), Number(serving[2])];
|
|
32
|
+
const [neededMajor, neededMinor] = [Number(needing[1]), Number(needing[2])];
|
|
33
|
+
return servedMajor === neededMajor && servedMinor >= neededMinor;
|
|
34
|
+
}
|
|
35
|
+
//# sourceMappingURL=plugin-api.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"plugin-api.js","sourceRoot":"","sources":["../src/plugin-api.ts"],"names":[],"mappings":"AAAA;;;;;;;;;GASG;AAEH,MAAM,MAAM,GAAG,gCAAgC,CAAC;AAChD,MAAM,QAAQ,GAAG,sBAAsB,CAAC;AAExC;;;;;;;;GAQG;AACH,MAAM,UAAU,mBAAmB,CAAC,MAAc,EAAE,QAAmC;IACrF,MAAM,OAAO,GAAG,MAAM,CAAC,IAAI,CAAC,MAAM,CAAC,CAAC;IACpC,IAAI,CAAC,OAAO;QAAE,MAAM,IAAI,UAAU,CAAC,mCAAmC,MAAM,4BAA4B,CAAC,CAAC;IAC1G,IAAI,QAAQ,KAAK,SAAS,IAAI,QAAQ,KAAK,IAAI;QAAE,OAAO,IAAI,CAAC;IAC7D,MAAM,OAAO,GAAG,QAAQ,CAAC,IAAI,CAAC,QAAQ,CAAC,CAAC;IACxC,IAAI,CAAC,OAAO;QAAE,MAAM,IAAI,UAAU,CAAC,mBAAmB,QAAQ,sBAAsB,CAAC,CAAC;IACtF,MAAM,CAAC,WAAW,EAAE,WAAW,CAAC,GAAG,CAAC,MAAM,CAAC,OAAO,CAAC,CAAC,CAAC,CAAC,EAAE,MAAM,CAAC,OAAO,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC;IAC5E,MAAM,CAAC,WAAW,EAAE,WAAW,CAAC,GAAG,CAAC,MAAM,CAAC,OAAO,CAAC,CAAC,CAAC,CAAC,EAAE,MAAM,CAAC,OAAO,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC;IAC5E,OAAO,WAAW,KAAK,WAAW,IAAI,WAAW,IAAI,WAAW,CAAC;AACnE,CAAC"}
|