initiative-plugin-sdk 2.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.
Files changed (64) hide show
  1. package/LICENSE +21 -0
  2. package/README.md +656 -0
  3. package/dist/build.d.ts +52 -0
  4. package/dist/build.js +229 -0
  5. package/dist/build.js.map +1 -0
  6. package/dist/cli.d.ts +24 -0
  7. package/dist/cli.js +160 -0
  8. package/dist/cli.js.map +1 -0
  9. package/dist/client.d.ts +288 -0
  10. package/dist/client.js +539 -0
  11. package/dist/client.js.map +1 -0
  12. package/dist/contract.d.ts +1247 -0
  13. package/dist/contract.js +167 -0
  14. package/dist/contract.js.map +1 -0
  15. package/dist/define.d.ts +336 -0
  16. package/dist/define.js +120 -0
  17. package/dist/define.js.map +1 -0
  18. package/dist/dev.d.ts +28 -0
  19. package/dist/dev.js +147 -0
  20. package/dist/dev.js.map +1 -0
  21. package/dist/expression.d.ts +28 -0
  22. package/dist/expression.js +67 -0
  23. package/dist/expression.js.map +1 -0
  24. package/dist/init.d.ts +14 -0
  25. package/dist/init.js +52 -0
  26. package/dist/init.js.map +1 -0
  27. package/dist/keys.d.ts +85 -0
  28. package/dist/keys.js +109 -0
  29. package/dist/keys.js.map +1 -0
  30. package/dist/manifest.d.ts +8 -0
  31. package/dist/manifest.js +8 -0
  32. package/dist/manifest.js.map +1 -0
  33. package/dist/pack.d.ts +35 -0
  34. package/dist/pack.js +84 -0
  35. package/dist/pack.js.map +1 -0
  36. package/dist/plugin-api.generated.d.ts +4263 -0
  37. package/dist/plugin-api.generated.js +1019 -0
  38. package/dist/plugin-api.generated.js.map +1 -0
  39. package/dist/server.d.ts +75 -0
  40. package/dist/server.js +408 -0
  41. package/dist/server.js.map +1 -0
  42. package/dist/testing.d.ts +116 -0
  43. package/dist/testing.js +386 -0
  44. package/dist/testing.js.map +1 -0
  45. package/dist/tokens.d.ts +161 -0
  46. package/dist/tokens.js +215 -0
  47. package/dist/tokens.js.map +1 -0
  48. package/dist/validate.d.ts +86 -0
  49. package/dist/validate.js +997 -0
  50. package/dist/validate.js.map +1 -0
  51. package/dist/widget.d.ts +235 -0
  52. package/dist/widget.js +26 -0
  53. package/dist/widget.js.map +1 -0
  54. package/examples/minimal/README.md +48 -0
  55. package/examples/minimal/assets/avatar.png +0 -0
  56. package/examples/minimal/package.json +22 -0
  57. package/examples/minimal/src/plugin.ts +77 -0
  58. package/examples/minimal/src/widgets/open-issues.ts +11 -0
  59. package/examples/minimal/test/fixtures/issues-statistics.json +9 -0
  60. package/examples/minimal/test/issue-counts.test.ts +48 -0
  61. package/examples/minimal/tsconfig.json +14 -0
  62. package/manifest.contract.json +1886 -0
  63. package/package.json +92 -0
  64. package/schemas/plugin-manifest.json +1747 -0
@@ -0,0 +1,1247 @@
1
+ /**
2
+ * The plug-in contract, as TypeScript.
3
+ *
4
+ * GENERATED from `manifest.contract.json` by `scripts/generate.mjs`. Do not
5
+ * edit it: change the contract and run `npm run generate`.
6
+ *
7
+ * These are the enums, caps and character sets the bundled JSON Schema is built
8
+ * from, and the shape of every object it defines, so this package's types
9
+ * cannot describe a manifest the schema refuses, nor miss a term it allows.
10
+ */
11
+ export type Feature = "dashboards" | "embeds" | "endpoints" | "widgets";
12
+ export declare const FEATURES: readonly Feature[];
13
+ export type Protocol = 1;
14
+ export declare const PROTOCOLS: readonly Protocol[];
15
+ export type ConnectionScope = "interactive" | "static";
16
+ export declare const CONNECTION_SCOPES: readonly ConnectionScope[];
17
+ export type FlowType = "oauth2";
18
+ export declare const FLOW_TYPES: readonly FlowType[];
19
+ export type TokenType = "jwt_bearer";
20
+ export declare const TOKEN_TYPES: readonly TokenType[];
21
+ export type RevokeMethod = "github_grant" | "hook" | "rfc7009";
22
+ export declare const REVOKE_METHODS: readonly RevokeMethod[];
23
+ export type JwtAlgorithm = "ES256" | "RS256";
24
+ export declare const JWT_ALGORITHMS: readonly JwtAlgorithm[];
25
+ export type FieldType = "bool" | "int" | "secret" | "select" | "string" | "url";
26
+ export declare const FIELD_TYPES: readonly FieldType[];
27
+ export type VendorFieldType = "secret" | "string" | "url";
28
+ export declare const VENDOR_FIELD_TYPES: readonly VendorFieldType[];
29
+ export type GithubPermissionLevel = "read" | "write";
30
+ export declare const GITHUB_PERMISSION_LEVELS: readonly GithubPermissionLevel[];
31
+ export type GithubAppValue = "client_id" | "client_secret" | "id" | "pem" | "slug" | "webhook_secret";
32
+ export declare const GITHUB_APP_VALUES: readonly GithubAppValue[];
33
+ export type WebhookScheme = "hmac_sha1" | "hmac_sha256";
34
+ export declare const WEBHOOK_SCHEMES: readonly WebhookScheme[];
35
+ export type WebhookEncoding = "base64" | "hex";
36
+ export declare const WEBHOOK_ENCODINGS: readonly WebhookEncoding[];
37
+ export type ParamType = "bool" | "datetime" | "int" | "select" | "string" | "url";
38
+ export declare const PARAM_TYPES: readonly ParamType[];
39
+ export type ReturnValueType = "bool" | "datetime" | "int" | "string" | "url";
40
+ export declare const RETURN_VALUE_TYPES: readonly ReturnValueType[];
41
+ export type Direction = "emit" | "read" | "write";
42
+ export declare const DIRECTIONS: readonly Direction[];
43
+ export type ActorKind = "installation" | "member";
44
+ export declare const ACTOR_KINDS: readonly ActorKind[];
45
+ export type Scope = "projects:read" | "projects:write" | "documents:read" | "documents: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" | "sharing:read" | "sharing:write" | "members:read" | "initiatives:read" | "initiatives:moderate" | "community:admin";
46
+ export declare const SCOPES: readonly Scope[];
47
+ export type SurfaceScope = "community" | "initiative";
48
+ export declare const SURFACE_SCOPES: readonly SurfaceScope[];
49
+ export type EmbedCapability = "camera" | "clipboard-read" | "clipboard-write" | "display-capture" | "fullscreen" | "geolocation" | "microphone";
50
+ export declare const EMBED_CAPABILITIES: readonly EmbedCapability[];
51
+ export type ListingKind = "plugin" | "dashboard";
52
+ export declare const LISTING_KINDS: readonly ListingKind[];
53
+ export type HttpMethod = "DELETE" | "GET" | "PATCH" | "POST" | "PUT";
54
+ export declare const HTTP_METHODS: readonly HttpMethod[];
55
+ export type PageLimit = "refuse" | "truncate";
56
+ export declare const PAGE_LIMITS: readonly PageLimit[];
57
+ export type StatusRange = "2xx" | "3xx" | "4xx" | "5xx";
58
+ export declare const STATUS_RANGES: readonly StatusRange[];
59
+ export type ConnectionState = "ok" | "removed" | "suspended" | "unavailable";
60
+ export declare const CONNECTION_STATES: readonly ConnectionState[];
61
+ export type PlatformCode = "invalid" | "mapping-failed" | "not-authorized" | "not-found" | "range-too-large";
62
+ export declare const PLATFORM_CODES: readonly PlatformCode[];
63
+ /** Every cap the platform enforces, by the name the contract gives it. */
64
+ export declare const CAPS: {
65
+ readonly connections: 20;
66
+ readonly fieldsPerConnection: 12;
67
+ readonly vendorFields: 12;
68
+ readonly githubAppPermissions: 100;
69
+ readonly githubAppEvents: 100;
70
+ readonly flowScopes: 24;
71
+ readonly authorizeParams: 12;
72
+ readonly tokenLifetimeSeconds: 600;
73
+ readonly selectOptions: 24;
74
+ readonly accessHintScopes: 24;
75
+ readonly requiresTerms: 10;
76
+ readonly widgets: 12;
77
+ readonly widgetEndpoints: 8;
78
+ readonly endpoints: 64;
79
+ readonly paramsPerEndpoint: 12;
80
+ readonly returnsPerEndpoint: 24;
81
+ readonly embeds: 12;
82
+ readonly embedCapabilities: 8;
83
+ readonly bundledDashboards: 8;
84
+ readonly dashboardWidgets: 50;
85
+ readonly dashboardGridColumns: 12;
86
+ readonly dashboardBindingParams: 12;
87
+ readonly identifierLength: 64;
88
+ readonly publicIdLength: 120;
89
+ readonly pathLength: 200;
90
+ readonly endpointIdLength: 200;
91
+ readonly nameLength: 255;
92
+ readonly labelLength: 120;
93
+ readonly hintLength: 120;
94
+ readonly descriptionLength: 500;
95
+ readonly paramValueLength: 2000;
96
+ readonly uidLength: 14;
97
+ readonly textLength: 120;
98
+ readonly locales: 40;
99
+ readonly cacheTtlSeconds: 86400;
100
+ readonly moduleSourceBytes: 65536;
101
+ readonly sampleDataBytes: 32768;
102
+ readonly serviceDefinitionBytes: 524288;
103
+ readonly versionLength: 32;
104
+ readonly publisherNameLength: 120;
105
+ readonly urlLength: 300;
106
+ readonly localeTagLength: 12;
107
+ readonly widgetDescriptionLength: 400;
108
+ readonly widgetOptions: 12;
109
+ readonly valuesPerOption: 24;
110
+ readonly identityKeyParts: 4;
111
+ readonly pluginScopes: 24;
112
+ readonly schedules: 8;
113
+ readonly scheduleMinMinutes: 5;
114
+ readonly scheduleMaxMinutes: 1440;
115
+ readonly scheduleEveryLength: 5;
116
+ readonly hosts: 8;
117
+ readonly hostLength: 253;
118
+ readonly steps: 3;
119
+ readonly pages: 10;
120
+ readonly perPage: 100;
121
+ readonly requestQuery: 24;
122
+ readonly requestHeaders: 12;
123
+ readonly errorRules: 12;
124
+ readonly unavailableCodes: 12;
125
+ readonly webhookEvents: 32;
126
+ readonly webhookStatuses: 12;
127
+ readonly healthStates: 12;
128
+ readonly statusCode: 599;
129
+ readonly expressionLength: 16384;
130
+ readonly graphqlLength: 16384;
131
+ readonly expressionTimeMs: 1000;
132
+ readonly expressionDepth: 500;
133
+ readonly expressionOutputBytes: 1048576;
134
+ };
135
+ /** The character sets ids and paths are drawn from. */
136
+ export declare const CHARSETS: {
137
+ readonly identifier: "-0123456789_abcdefghijklmnopqrstuvwxyz";
138
+ readonly namespacedId: "-.0123456789_abcdefghijklmnopqrstuvwxyz";
139
+ readonly publicId: "-.0123456789_abcdefghijklmnopqrstuvwxyz";
140
+ readonly uid: "0123456789ABCDEFGHJKMNPQRSTVWXYZ";
141
+ readonly path: "-./0123456789ABCDEFGHIJKLMNOPQRSTUVWXYZ_abcdefghijklmnopqrstuvwxyz";
142
+ readonly headerName: "-0123456789ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz";
143
+ readonly fieldPath: "-.0123456789ABCDEFGHIJKLMNOPQRSTUVWXYZ_abcdefghijklmnopqrstuvwxyz";
144
+ readonly localeTag: "-ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz";
145
+ readonly version: "0123456789.-+abcdefghijklmnopqrstuvwxyz";
146
+ readonly artwork: "abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789/._-";
147
+ readonly queryName: "-.0123456789ABCDEFGHIJKLMNOPQRSTUVWXYZ[]_abcdefghijklmnopqrstuvwxyz~";
148
+ };
149
+ /**
150
+ * Every field the contract declares, by the object that owns it.
151
+ *
152
+ * The inventory the platform holds its normalizer to, exported so a consumer
153
+ * can enumerate what a manifest may carry without parsing the schema.
154
+ */
155
+ export declare const FIELDS: {
156
+ readonly requires: readonly ["all_of", "any_of"];
157
+ readonly accessHint: readonly ["api", "scopes"];
158
+ readonly connectionField: readonly ["key", "type", "required", "label", "options", "managed"];
159
+ readonly vendor: readonly ["label", "fields", "setup"];
160
+ readonly vendorField: readonly ["key", "type", "required", "label"];
161
+ readonly githubAppManifestSetup: readonly ["kind", "app", "values"];
162
+ readonly githubAppManifest: readonly ["name", "url", "public", "default_permissions", "default_events"];
163
+ readonly endpointParam: readonly ["key", "type", "required", "label", "options", "options_from", "list"];
164
+ readonly endpointReturn: readonly ["key", "type", "label", "list"];
165
+ readonly connection: readonly ["id", "scope", "label", "fields", "flow", "token", "access_hint", "health"];
166
+ readonly connectionFlow: readonly ["type", "authorize_url", "token_url", "client_id", "client_secret", "scopes", "pkce", "authorize_params", "install_url", "after_connect", "revoke", "revoke_url"];
167
+ readonly connectionToken: readonly ["type", "exchange_url", "iss", "key", "alg", "lifetime"];
168
+ readonly webhooks: readonly ["verify", "dedup", "route", "events", "status"];
169
+ readonly webhookVerify: readonly ["scheme", "header", "prefix", "encoding", "secret"];
170
+ readonly webhookRoute: readonly ["path", "header", "connection", "field"];
171
+ readonly schedule: readonly ["id", "every"];
172
+ 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"];
173
+ readonly widget: readonly ["id", "meta", "module_source", "endpoints", "sample_data", "requires"];
174
+ readonly embed: readonly ["id", "path", "name", "scopes", "admin_only", "capabilities", "requires"];
175
+ readonly bundledDashboard: readonly ["uid", "public_id", "name", "description", "layout", "widgets"];
176
+ readonly bundledDashboardWidget: readonly ["id", "type", "title", "grid", "binding"];
177
+ readonly endpointIdentity: readonly ["kind", "key"];
178
+ readonly vendorAuth: readonly ["header", "prefix"];
179
+ readonly vendorRequest: readonly ["method", "url", "query", "headers", "body", "graphql", "connection", "paging"];
180
+ readonly graphqlRequest: readonly ["query", "variables"];
181
+ readonly requestStep: readonly ["name", "request"];
182
+ readonly pageNumberPaging: readonly ["kind", "page_param", "per_page_param", "per_page", "items", "max_pages", "on_limit"];
183
+ readonly linkHeaderPaging: readonly ["kind", "items", "max_pages", "on_limit"];
184
+ readonly cursorPaging: readonly ["kind", "next", "more", "param", "variable", "items", "max_pages", "on_limit"];
185
+ readonly errorRule: readonly ["status", "when", "code"];
186
+ readonly afterConnect: readonly ["request", "steps", "map", "refuse_when", "code"];
187
+ readonly connectionHealth: readonly ["request", "every", "states"];
188
+ readonly healthState: readonly ["status", "when", "state"];
189
+ readonly webhookEvent: readonly ["when", "emit", "map"];
190
+ readonly webhookStatus: readonly ["when", "connection", "state"];
191
+ readonly manifest: readonly ["plugin_kind", "service", "features", "default_name", "hosts", "auth", "vendor", "connections", "webhooks", "schedules", "endpoints", "community_summary", "widgets", "embeds", "dashboards"];
192
+ };
193
+ export type Identifier = string;
194
+ /**
195
+ * A route on the plug-in's own service, never an address. The deployment joins
196
+ * it to the base URL its registration supplies.
197
+ */
198
+ export type Path = string;
199
+ /**
200
+ * Localized text, keyed by language tag. At least one usable entry; the
201
+ * platform falls back to the reader's language, then to any entry. Values
202
+ * should be strings: text longer than 120 characters is truncated, and an entry
203
+ * that is not a string, is not a language tag, or falls past the first 40 is
204
+ * ignored rather than refused.
205
+ */
206
+ export type LocalizedText = Record<string, string>;
207
+ /**
208
+ * Connection ids that must hold a value before this is offered. Exactly one of
209
+ * 'all_of' or 'any_of'; each id must name a connection this manifest declares.
210
+ * Absent means always available.
211
+ */
212
+ export interface Requires {
213
+ all_of?: Identifier[];
214
+ any_of?: Identifier[];
215
+ }
216
+ /**
217
+ * What the credential will be used for. Display-only: it is shown beside the
218
+ * form so an admin can mint a minimal credential, and no other system's
219
+ * permissions are enforced from it.
220
+ */
221
+ export interface AccessHint {
222
+ api?: string;
223
+ scopes?: string[];
224
+ }
225
+ export interface ConnectionField {
226
+ key: Identifier;
227
+ type: FieldType;
228
+ required?: boolean;
229
+ label: LocalizedText;
230
+ /**
231
+ * Required when type is 'select'.
232
+ */
233
+ options?: string[];
234
+ /**
235
+ * Returned by the plug-in's after_connect hook when a flow finishes; it is
236
+ * not typed into the settings form.
237
+ */
238
+ managed?: boolean;
239
+ }
240
+ /**
241
+ * What an operator supplies once per deployment for the vendor's own client:
242
+ * its id, its secret, its signing key. Declared here and never valued here: the
243
+ * values are entered on the deployment, or written there by the vendor's own
244
+ * setup flow, and referenced from a connection's flow or token as
245
+ * '{vendor.<key>}'.
246
+ */
247
+ export interface Vendor {
248
+ /**
249
+ * What the vendor client is called, for the operator's form.
250
+ */
251
+ label?: LocalizedText;
252
+ fields: VendorField[];
253
+ /**
254
+ * How the vendor's client can be made for a deployment by the vendor itself,
255
+ * rather than registered by hand. Absent: the operator enters every value.
256
+ */
257
+ setup?: VendorSetup;
258
+ }
259
+ export interface VendorField {
260
+ key: Identifier;
261
+ /**
262
+ * A 'secret' is written once and never shown again.
263
+ */
264
+ type: VendorFieldType;
265
+ /**
266
+ * The plug-in is not live on a deployment until every required value is set.
267
+ */
268
+ required?: boolean;
269
+ label: LocalizedText;
270
+ }
271
+ /**
272
+ * A flow at the vendor that creates the vendor's client and answers with its
273
+ * values. Initiative runs it from the operator's browser and writes what the
274
+ * vendor answers into the deployment's vendor values, so none is typed or
275
+ * copied. One member per flow, told apart by 'kind'.
276
+ */
277
+ export type VendorSetup = GithubAppManifestSetup;
278
+ /**
279
+ * A GitHub App created from a manifest (GitHub's app manifest flow). The
280
+ * operator confirms it on GitHub, and Initiative exchanges the code GitHub
281
+ * returns for the new app's values. Initiative fills in every address itself
282
+ * (the callback, setup, webhook and redirect URLs), so the manifest names none.
283
+ */
284
+ export interface GithubAppManifestSetup {
285
+ kind: "github_app_manifest";
286
+ app: GithubAppManifest;
287
+ /**
288
+ * Which vendor value each of GitHub's answers is written to: one of this
289
+ * plug-in's vendor field keys to one field of GitHub's manifest-conversion
290
+ * response. Every key must be a field of the vendor block, each response
291
+ * field is written at most once, and 'client_secret', 'pem' and
292
+ * 'webhook_secret' are written only to a 'secret' field.
293
+ */
294
+ values: Record<string, GithubAppValue>;
295
+ }
296
+ /**
297
+ * What GitHub is asked to create: the parts of a GitHub App manifest a plug-in
298
+ * decides.
299
+ */
300
+ export interface GithubAppManifest {
301
+ /**
302
+ * The name GitHub offers for the new app. The operator may change it on
303
+ * GitHub, where an app's name is unique.
304
+ */
305
+ name: string;
306
+ /**
307
+ * The app's homepage, https.
308
+ */
309
+ url: string;
310
+ /**
311
+ * Any GitHub account may install the new app. Absent: only the account that
312
+ * owns it.
313
+ */
314
+ public?: boolean;
315
+ /**
316
+ * The permissions the app is created with, by GitHub's name for each, such as
317
+ * 'issues'. At most 100.
318
+ */
319
+ default_permissions?: Record<string, GithubPermissionLevel>;
320
+ /**
321
+ * The webhook events the app subscribes to, by GitHub's name for each, such
322
+ * as 'issues'. GitHub accepts an event only beside a permission that covers
323
+ * it. At most 100.
324
+ */
325
+ default_events?: Identifier[];
326
+ }
327
+ export interface EndpointParam {
328
+ key: Identifier;
329
+ type: ParamType;
330
+ required?: boolean;
331
+ label: LocalizedText;
332
+ /**
333
+ * Required when type is 'select'. The values themselves — a consumer that
334
+ * shows a menu writes its own words for them.
335
+ */
336
+ options?: string[];
337
+ /**
338
+ * Where this parameter's values come from when only the plug-in can know
339
+ * them. Names a read endpoint in THIS manifest and which of its returns holds
340
+ * the values; a consumer building a form asks the deployment to resolve it
341
+ * rather than showing a text box. For everything a manifest cannot list
342
+ * because the answer differs per install and changes after it — a repository,
343
+ * a channel, a board, a project. `options` is the other case: a set that is
344
+ * the same on every deployment forever. Declaring values, not a control: what
345
+ * to draw is still the consumer's. Resolution is server-side, inherits the
346
+ * source endpoint's `requires` and `cache_ttl_seconds`, and a source that
347
+ * cannot be resolved leaves the parameter enterable rather than unusable.
348
+ */
349
+ options_from?: {
350
+ /**
351
+ * A read endpoint this same manifest declares. Not another plug-in's:
352
+ * reading across plug-ins has no consent story, and an id from elsewhere is
353
+ * refused on publish.
354
+ */
355
+ endpoint: NamespacedId;
356
+ /**
357
+ * Which of that endpoint's returns holds the values. Must be one it
358
+ * declares, and a list: a menu comes from a column of values, not from one.
359
+ */
360
+ key: Identifier;
361
+ /**
362
+ * Optional. A second return, parallel to `key`, holding what a person reads
363
+ * — a board's title beside its opaque id. Absent means the value is its own
364
+ * label.
365
+ */
366
+ label_key?: Identifier;
367
+ /**
368
+ * Optional. What to send that endpoint, written as one of ITS parameter
369
+ * names to one of THIS endpoint's. A repository's labels, a board's fields,
370
+ * a field's values — past the first source in a form, most of them answer
371
+ * differently depending on what has been chosen already, and a source that
372
+ * could not be told a sibling's answer could only ever offer the whole
373
+ * account's worth. Every named sibling must be a parameter this endpoint
374
+ * declares, and none of them this one. Until all of them have a value the
375
+ * source is not called and the parameter stays enterable, exactly as for a
376
+ * source that will not resolve.
377
+ */
378
+ needs?: Record<string, Identifier>;
379
+ };
380
+ /**
381
+ * Several values rather than one. Cardinality is a fact about the value, so
382
+ * it is yours; what to draw for it is the consumer's. Without it, a plug-in
383
+ * wanting several of something declares a string and documents a comma —
384
+ * which nothing downstream can validate or complete.
385
+ */
386
+ list?: boolean;
387
+ }
388
+ export interface EndpointReturn {
389
+ key: Identifier;
390
+ /**
391
+ * The parameter vocabulary minus 'select', because a select is a control and
392
+ * the value behind one is a string.
393
+ */
394
+ type: ReturnValueType;
395
+ label?: LocalizedText;
396
+ /**
397
+ * Several values rather than one. It matters to a consumer with somewhere to
398
+ * put exactly one — a form field, a tile's number — which is why it is a flag
399
+ * rather than a second set of types.
400
+ */
401
+ list?: boolean;
402
+ }
403
+ export interface Connection {
404
+ id: Identifier;
405
+ /**
406
+ * Who the credential belongs to. 'static' is one credential the whole
407
+ * community uses; 'interactive' is each member's own account at a vendor that
408
+ * authorizes people. It does not say how the credential is obtained: a static
409
+ * connection with a 'flow' is still one credential for the whole community,
410
+ * run by an admin through the vendor's own pages rather than typed into a
411
+ * form. An interactive connection always declares a 'flow'.
412
+ */
413
+ scope: ConnectionScope;
414
+ label: LocalizedText;
415
+ /**
416
+ * Without a 'flow', what an admin types. With one, only the values the
417
+ * plug-in's after_connect hook returns, and every field is 'managed'. The
418
+ * tokens a flow obtains are held apart from these, under reserved keys the
419
+ * plug-in never declares.
420
+ */
421
+ fields: ConnectionField[];
422
+ /**
423
+ * How the connection is established. Initiative runs it: the redirect, the
424
+ * code exchange, refreshing and revoking. The plug-in never holds the vendor
425
+ * client's secret or a refresh token.
426
+ */
427
+ flow?: ConnectionFlow;
428
+ /**
429
+ * How a usable access token is got for this connection. Absent: the tokens
430
+ * the flow stored, refreshed as needed. Static connections only.
431
+ */
432
+ token?: ConnectionToken;
433
+ access_hint?: AccessHint;
434
+ health?: ConnectionHealth;
435
+ }
436
+ /**
437
+ * An OAuth 2.0 authorization code flow (RFC 6749 §4.1) that Initiative runs for
438
+ * a connection, with the redirect addresses the deployment publishes.
439
+ */
440
+ export interface ConnectionFlow {
441
+ type: FlowType;
442
+ /**
443
+ * The vendor's authorization endpoint, https. May name a vendor value as
444
+ * '{vendor.<key>}' and one of this connection's own fields as '{<key>}'.
445
+ */
446
+ authorize_url: string;
447
+ /**
448
+ * The vendor's token endpoint, https. May name a vendor value as
449
+ * '{vendor.<key>}' and one of this connection's own fields as '{<key>}'.
450
+ */
451
+ token_url: string;
452
+ /**
453
+ * The vendor client's id, normally '{vendor.client_id}'. May name a vendor
454
+ * value as '{vendor.<key>}' and one of this connection's own fields as
455
+ * '{<key>}'.
456
+ */
457
+ client_id: string;
458
+ /**
459
+ * The vendor client's secret, normally '{vendor.client_secret}'. Absent for a
460
+ * public client. May name a vendor value as '{vendor.<key>}' and one of this
461
+ * connection's own fields as '{<key>}'.
462
+ */
463
+ client_secret?: string;
464
+ /**
465
+ * The vendor scopes asked for, sent space-separated.
466
+ */
467
+ scopes?: string[];
468
+ /**
469
+ * Send an S256 code challenge (RFC 7636).
470
+ */
471
+ pkce?: boolean;
472
+ /**
473
+ * Extra query parameters for the authorization request. May name a vendor
474
+ * value as '{vendor.<key>}' and one of this connection's own fields as
475
+ * '{<key>}'.
476
+ */
477
+ authorize_params?: Record<string, string>;
478
+ /**
479
+ * Static connections only. The vendor's install page, for a connection an
480
+ * organization installs: the person installs first, the vendor returns to the
481
+ * setup address with the installation's id, and one authorization trip
482
+ * follows so the plug-in can check who installed it. Requires
483
+ * 'after_connect'. May name a vendor value as '{vendor.<key>}' and one of
484
+ * this connection's own fields as '{<key>}'.
485
+ */
486
+ install_url?: string;
487
+ /**
488
+ * What runs once the code is exchanged, with the fresh access token, to learn
489
+ * the connection's managed values and an account label, or to refuse it. A
490
+ * container plug-in sets true, and Initiative calls its after_connect hook; a
491
+ * declarative plug-in gives the call and its mapping.
492
+ */
493
+ after_connect?: boolean | AfterConnect;
494
+ /**
495
+ * How a grant is ended at the vendor when the connection ends: 'rfc7009'
496
+ * posts to 'revoke_url' with the client's credentials; 'github_grant' sends
497
+ * DELETE to 'revoke_url' (GitHub's 'Delete an app authorization') with the
498
+ * client's credentials as HTTP Basic auth and the access token in the JSON
499
+ * body as 'access_token'; 'hook' calls the plug-in's revoke hook with the
500
+ * tokens, so a container plug-in's only. Absent: the tokens are deleted and
501
+ * nothing is sent.
502
+ */
503
+ revoke?: RevokeMethod;
504
+ /**
505
+ * The vendor's revocation endpoint: RFC 7009's for 'rfc7009', or GitHub's
506
+ * grant address
507
+ * (https://api.github.com/applications/{vendor.client_id}/grant) for
508
+ * 'github_grant'. Required when 'revoke' is either. May name a vendor value
509
+ * as '{vendor.<key>}' and one of this connection's own fields as '{<key>}'.
510
+ */
511
+ revoke_url?: string;
512
+ }
513
+ /**
514
+ * An access token minted on demand rather than stored: Initiative signs a JWT
515
+ * with the vendor key and exchanges it, and caches the answer until shortly
516
+ * before it expires.
517
+ */
518
+ export interface ConnectionToken {
519
+ type: TokenType;
520
+ /**
521
+ * Where the signed JWT is posted, https. The answer's 'token' (or
522
+ * 'access_token') and 'expires_at' (or 'expires_in') are read. May name a
523
+ * vendor value as '{vendor.<key>}' and one of this connection's own fields as
524
+ * '{<key>}'.
525
+ */
526
+ exchange_url: string;
527
+ /**
528
+ * The JWT's issuer, normally '{vendor.app_id}'. May name a vendor value as
529
+ * '{vendor.<key>}' and one of this connection's own fields as '{<key>}'.
530
+ */
531
+ iss: string;
532
+ /**
533
+ * The signing key, as a vendor value: '{vendor.private_key}'. A PEM private
534
+ * key.
535
+ */
536
+ key: string;
537
+ alg?: JwtAlgorithm;
538
+ /**
539
+ * How long the signed JWT lives, in seconds.
540
+ */
541
+ lifetime?: number;
542
+ }
543
+ /**
544
+ * The vendor's webhooks, received by Initiative at one address per plug-in on
545
+ * the deployment, '/api/v1/plugin-hooks/<public_id>'. Initiative checks each
546
+ * delivery's signature, drops one it has already delivered, finds the
547
+ * communities it belongs to by a value in its body, and forwards it to the
548
+ * plug-in's webhook hook once for each. A container plug-in's hook receives
549
+ * each delivery; a declarative plug-in maps it with 'events' and 'status'
550
+ * instead.
551
+ */
552
+ export interface Webhooks {
553
+ verify: WebhookVerify;
554
+ /**
555
+ * The header carrying the vendor's id for one delivery, such as
556
+ * 'X-GitHub-Delivery'. A delivery with an id already forwarded to a community
557
+ * is not forwarded to it again.
558
+ */
559
+ dedup: string;
560
+ route: WebhookRoute;
561
+ /**
562
+ * Declarative plug-ins: how a delivery becomes one of this plug-in's events.
563
+ * The first row whose 'when' holds emits; a delivery no row matches is
564
+ * dropped.
565
+ */
566
+ events?: WebhookEvent[];
567
+ /**
568
+ * Declarative plug-ins: deliveries that say what state a connection is in at
569
+ * the vendor. The first row whose 'when' holds sets it.
570
+ */
571
+ status?: WebhookStatus[];
572
+ }
573
+ /**
574
+ * How a delivery's signature is checked: an HMAC over the raw body under a
575
+ * vendor value.
576
+ */
577
+ export interface WebhookVerify {
578
+ scheme: WebhookScheme;
579
+ /**
580
+ * The header carrying the signature, such as 'X-Hub-Signature-256'.
581
+ */
582
+ header: string;
583
+ /**
584
+ * What precedes the signature in the header, such as 'sha256='. Absent:
585
+ * nothing does.
586
+ */
587
+ prefix?: string;
588
+ /**
589
+ * How the signature is written.
590
+ */
591
+ encoding: WebhookEncoding;
592
+ /**
593
+ * The signing secret, as one vendor value: '{vendor.<key>}'.
594
+ */
595
+ secret: string;
596
+ }
597
+ /**
598
+ * Which communities a delivery belongs to: a value in its body or in one of its
599
+ * headers, matched against one field of a static connection as each community's
600
+ * connect stored it. Exactly one of 'path' and 'header'.
601
+ */
602
+ export interface WebhookRoute {
603
+ /**
604
+ * Where the value is in the JSON body, as keys joined by '.', such as
605
+ * 'installation.id'.
606
+ */
607
+ path?: string;
608
+ /**
609
+ * The header carrying the value, such as 'X-Shopify-Shop-Domain'.
610
+ */
611
+ header?: string;
612
+ /**
613
+ * A static connection this plug-in declares.
614
+ */
615
+ connection: Identifier;
616
+ /**
617
+ * A field that connection declares, whose stored value the body's value is
618
+ * matched against.
619
+ */
620
+ field: Identifier;
621
+ }
622
+ /**
623
+ * An interval at which Initiative calls the plug-in's schedule hook, once for
624
+ * each community that installed it, with when the call last succeeded there.
625
+ */
626
+ export interface Schedule {
627
+ /**
628
+ * Unique within the manifest. The hook is told which schedule is due by it.
629
+ */
630
+ id: Identifier;
631
+ /**
632
+ * How often: a whole number of minutes ('15m') or hours ('6h'), at least 5
633
+ * minutes and at most 1440 minutes.
634
+ */
635
+ every: string;
636
+ }
637
+ /**
638
+ * Namespaced under the plug-in's own service id — 'plugin.<public_id>.<name>'.
639
+ * The prefix is checked against the declaring registration at ingress.
640
+ */
641
+ export type NamespacedId = string;
642
+ /**
643
+ * 'plugins:<public_id>': permission to call another plug-in's public endpoints
644
+ * through the deployment, as this community or as one of its members. Not one
645
+ * of the fixed scopes: the family is open, one per plug-in, and the public id
646
+ * after the prefix is the plug-in being called. The deployment never lets a
647
+ * plug-in address another directly; the call goes through it, and the plug-in
648
+ * called is handed its own references for whoever the call is for.
649
+ */
650
+ export type PluginScope = `plugins:${string}`;
651
+ export interface Endpoint {
652
+ id: NamespacedId;
653
+ /**
654
+ * What this endpoint IS, in words somebody picks it out of a list by. Every
655
+ * direction, and an emission most of all: it is the one thing here chosen
656
+ * without ever being called.
657
+ */
658
+ label?: LocalizedText;
659
+ /**
660
+ * A second line, where the label needs one.
661
+ */
662
+ description?: LocalizedText;
663
+ /**
664
+ * What this hands back, by name and type — the response for a read or a
665
+ * write, the payload for an emission. Declared rather than discovered,
666
+ * because a consumer binds one of these before the endpoint has ever run and
667
+ * a bad binding has to be refusable when somebody arranges it.
668
+ */
669
+ returns?: EndpointReturn[];
670
+ /**
671
+ * Where a consumer that groups a plug-in's endpoints should file this one.
672
+ * Opaque here: the grouping is the consumer's, and an endpoint that says
673
+ * nothing sits in the flat list.
674
+ */
675
+ group?: Identifier;
676
+ /**
677
+ * What a caller must already have in hand for this to mean anything. Opaque
678
+ * here — the vocabulary belongs to whoever consumes it; the automation
679
+ * service names the subjects a run can be about.
680
+ */
681
+ needs_subject?: Identifier;
682
+ /**
683
+ * 'read' and 'write' are called through the deployment and answer in place;
684
+ * 'emit' travels the other way — the plug-in posts it to a subscriber that
685
+ * registered a URL, so it carries no parameters and nothing to gate.
686
+ */
687
+ direction: Direction;
688
+ /**
689
+ * What a caller may send. Read and write only.
690
+ */
691
+ params?: EndpointParam[];
692
+ /**
693
+ * Whose credential the call runs on, best first. Read and write only. An
694
+ * endpoint offering only 'member' refuses when that member has connected
695
+ * nothing, rather than quietly acting as the plug-in instead.
696
+ */
697
+ actors?: ActorKind[];
698
+ /**
699
+ * Only the community's admins read or call this endpoint — a figure for the
700
+ * community's settings page, say. Anyone who can see where it is used may
701
+ * otherwise.
702
+ */
703
+ admin_only?: boolean;
704
+ /**
705
+ * Read and write only. Other plug-ins may call this endpoint through the
706
+ * deployment, when the community has let them use this plug-in
707
+ * ('plugins:<your public id>'). A caller acts as the community or as one of
708
+ * its members, and `actors` says which of the two this endpoint takes: one
709
+ * that names neither is not callable this way. A write endpoint is reachable
710
+ * only like this; a widget binds reads alone. Absent means only the
711
+ * deployment's own surfaces reach it.
712
+ */
713
+ public?: boolean;
714
+ requires?: Requires;
715
+ /**
716
+ * Read only. How long a response may be reused. Clamped into 0..86400 rather
717
+ * than refused, so a value outside that range is accepted and takes effect at
718
+ * the bound — which is why no range is asserted here.
719
+ */
720
+ cache_ttl_seconds?: number;
721
+ /**
722
+ * 'write' and 'emit': what this touched, or what it is about. Read endpoints
723
+ * have none — they touched nothing, so there is no echo to suppress.
724
+ */
725
+ identity?: EndpointIdentity;
726
+ /**
727
+ * Read and write only. The codes this endpoint may answer 'unavailable' with
728
+ * beyond Initiative's own (invalid, mapping-failed, not-authorized,
729
+ * not-found, range-too-large), so a consumer can put each into words.
730
+ */
731
+ unavailable?: Identifier[];
732
+ /**
733
+ * Declarative plug-ins: the one call that answers this endpoint. Not beside
734
+ * 'steps'.
735
+ */
736
+ request?: VendorRequest;
737
+ /**
738
+ * Declarative plug-ins: up to 3 calls made in order, each able to read the
739
+ * answers of the ones before it. Not beside 'request'.
740
+ */
741
+ steps?: RequestStep[];
742
+ /**
743
+ * Declarative plug-ins: the endpoint's answer, from 'response' (the last
744
+ * call's answer) and 'steps': an object of its declared returns, or
745
+ * {"unavailable": "<code>"} naming one of its codes.
746
+ */
747
+ map?: Expression;
748
+ /**
749
+ * Declarative plug-ins: vendor answers this endpoint gives its own meaning,
750
+ * tried on every answer before the defaults. The defaults: 401 and 403 are
751
+ * not-authorized, 404 not-found, 400, 422 and any other 4xx invalid, and 429,
752
+ * 3xx and 5xx transient.
753
+ */
754
+ errors?: ErrorRule[];
755
+ }
756
+ export interface Widget {
757
+ id: Identifier;
758
+ /**
759
+ * The widget's own name and description, as the picker shows them. Must name
760
+ * the widget in at least one language.
761
+ */
762
+ meta: Record<string, unknown>;
763
+ /**
764
+ * The widget's browser-side module. Stored as an opaque string and executed
765
+ * only inside the sandbox; the platform never parses it. Capped in UTF-8
766
+ * bytes, which this schema cannot express.
767
+ */
768
+ module_source: string;
769
+ /**
770
+ * Read endpoint ids this manifest also declares. Only a read answers with
771
+ * something to draw.
772
+ */
773
+ endpoints?: NamespacedId[];
774
+ /**
775
+ * What each endpoint would answer with, keyed by declared read endpoint id,
776
+ * so a preview renders with no network call. Written in the endpoint's own
777
+ * returns and read through them exactly as a live answer is. Keys naming an
778
+ * undeclared endpoint are dropped.
779
+ */
780
+ sample_data?: Record<string, unknown>;
781
+ requires?: Requires;
782
+ }
783
+ export interface Embed {
784
+ id: Identifier;
785
+ path: Path;
786
+ name: LocalizedText;
787
+ /**
788
+ * Where the surface renders. Declaring both gives it a community-wide entry
789
+ * and an entry inside each initiative.
790
+ */
791
+ scopes?: SurfaceScope[];
792
+ /**
793
+ * Only the community's admins open this surface, whatever roles a placement
794
+ * allows — a settings page, say. Who else may open a surface is chosen in the
795
+ * community, per initiative and per role, not declared here.
796
+ */
797
+ admin_only?: boolean;
798
+ /**
799
+ * Browser features the frame is granted. A surface that names nothing is
800
+ * framed with all of them denied.
801
+ */
802
+ capabilities?: EmbedCapability[];
803
+ requires?: Requires;
804
+ }
805
+ export interface BundledDashboard {
806
+ /**
807
+ * This dashboard's own catalog id — publisher-assigned, immutable, never
808
+ * reused. It becomes a listing of its own, so this is a real catalog identity
809
+ * and not the plug-in's.
810
+ */
811
+ uid: string;
812
+ /**
813
+ * '<publisher>.<slug>', and not the plug-in's own — a bundled dashboard is a
814
+ * separate listing.
815
+ */
816
+ public_id: string;
817
+ name: string;
818
+ description?: string;
819
+ layout?: {
820
+ columns?: number;
821
+ };
822
+ widgets: BundledDashboardWidget[];
823
+ }
824
+ export interface BundledDashboardWidget {
825
+ id?: Identifier;
826
+ /**
827
+ * One of this manifest's own widget ids — bare, with no uid. The platform
828
+ * stamps the plug-in's uid on when it publishes, so the two can never
829
+ * disagree.
830
+ */
831
+ type: Identifier;
832
+ title?: string;
833
+ grid?: {
834
+ x?: number;
835
+ y?: number;
836
+ w?: number;
837
+ h?: number;
838
+ };
839
+ binding: {
840
+ /**
841
+ * One of this manifest's own read endpoint ids. Only a read answers with
842
+ * something to draw.
843
+ */
844
+ endpoint_id: NamespacedId;
845
+ params?: Record<string, string | number | boolean>;
846
+ };
847
+ }
848
+ /**
849
+ * Which of this endpoint's returns identify the thing it touched. A consumer
850
+ * keeps a change an automation made from firing that automation again, and for
851
+ * a plug-in there was no key — so guessing would silently drop a fire somebody
852
+ * was waiting on, and a rate cap was the only guard. Declare the SAME kind and
853
+ * key on the write and on the emission about it, and the two produce the same
854
+ * address.
855
+ */
856
+ export interface EndpointIdentity {
857
+ /**
858
+ * Your own word for what sort of thing this is ('issue'). Namespaced by your
859
+ * public id downstream, because two plug-ins declaring the same kind mean two
860
+ * different things.
861
+ */
862
+ kind: Identifier;
863
+ /**
864
+ * Returns of this endpoint, in order, joined to form the address. Every one
865
+ * must be a single value rather than a list — half an address matches
866
+ * nothing, and one built from the parts that happened to be there matches the
867
+ * wrong thing.
868
+ */
869
+ key: Identifier[];
870
+ }
871
+ /**
872
+ * A JSONata expression (https://jsonata.org): standard JSONata, with no
873
+ * functions added. It reads one document. On the way out that holds 'params',
874
+ * the call's parameters as the caller sent them; 'connection', the non-secret
875
+ * fields of the connection the request names; 'connections', on an endpoint's
876
+ * requests and map, each connection its 'requires' names that the call has, by
877
+ * its id, holding the same fields; 'now', the time of the call in ISO 8601,
878
+ * which $now() and $millis() also answer; and 'steps', each earlier step's
879
+ * answer by its name. On the way back it also holds 'response', the answer
880
+ * being read: {status, headers, body}, with header names in lowercase. Each
881
+ * evaluation is bounded: at most 1000 milliseconds, 500 levels of nesting and
882
+ * an answer of 1048576 bytes as JSON. An expression that fails or passes a
883
+ * bound answers 'unavailable: mapping-failed'.
884
+ */
885
+ export type Expression = string;
886
+ /**
887
+ * A host a declarative plug-in calls, in lowercase: exact ('api.github.com'),
888
+ * or with one leading '*.' that stands for exactly one label
889
+ * ('*.myshopify.com'). No scheme, port or path: every call is https on port
890
+ * 443, and goes only to a public address.
891
+ */
892
+ export type Host = string;
893
+ export type HeaderName = string;
894
+ export type QueryName = string;
895
+ /**
896
+ * How Initiative puts a connection's credential on a declarative plug-in's
897
+ * requests: one header, holding the prefix and the token joined by a space.
898
+ * Absent: 'Authorization: Bearer <token>'.
899
+ */
900
+ export interface VendorAuth {
901
+ header?: HeaderName;
902
+ /**
903
+ * Written before the token. Empty: the token alone.
904
+ */
905
+ prefix?: string;
906
+ }
907
+ /**
908
+ * One call Initiative makes to the vendor for a declarative plug-in, rendered
909
+ * from expressions. Initiative adds the credential itself, as 'auth' says, and
910
+ * follows no redirect.
911
+ */
912
+ export interface VendorRequest {
913
+ method: HttpMethod;
914
+ /**
915
+ * The address, as an expression answering a string: https, on one of the
916
+ * plug-in's hosts. Query parameters may be written into it or given in
917
+ * 'query'.
918
+ */
919
+ url: Expression;
920
+ /**
921
+ * Query parameters by name, each an expression. One answering null or nothing
922
+ * is left out, and a list repeats the parameter once per value.
923
+ */
924
+ query?: Record<string, Expression>;
925
+ /**
926
+ * Headers by name, each an expression answering a string; one answering null
927
+ * or nothing is left out. Never the credential's header, which Initiative
928
+ * sets.
929
+ */
930
+ headers?: Record<string, Expression>;
931
+ /**
932
+ * The JSON body, as an expression. Not beside 'graphql'.
933
+ */
934
+ body?: Expression;
935
+ graphql?: GraphqlRequest;
936
+ /**
937
+ * Which connection's credential the request carries: a static connection's is
938
+ * the community's, an interactive one's the acting member's. A call made as a
939
+ * member carries a static connection's credential only when the endpoint's
940
+ * 'requires' names that connection, and is refused otherwise. Required on an
941
+ * endpoint's requests. Absent on 'after_connect' and 'health', which carry
942
+ * the credential of the connection they belong to.
943
+ */
944
+ connection?: Identifier;
945
+ paging?: Paging;
946
+ }
947
+ /**
948
+ * A GraphQL request, sent by POST as the JSON body {query, variables}.
949
+ */
950
+ export interface GraphqlRequest {
951
+ /**
952
+ * The GraphQL document, as text. What varies goes in 'variables'.
953
+ */
954
+ query: string;
955
+ /**
956
+ * The variables, as an expression answering an object.
957
+ */
958
+ variables?: Expression;
959
+ }
960
+ export interface RequestStep {
961
+ /**
962
+ * Unique among its steps. Later steps, the map and the predicates beside it
963
+ * read this step's answer as 'steps.<name>'.
964
+ */
965
+ name: Identifier;
966
+ request: VendorRequest;
967
+ }
968
+ /**
969
+ * How a request reads more than one page, one member per method, told apart by
970
+ * 'kind'. Every page is read before the answer is mapped: 'response.body' is
971
+ * then every page's items appended in order, and the status and headers are the
972
+ * last page's. 'max_pages' is how many pages may be read; finding more after
973
+ * that many truncates or refuses, as 'on_limit' says, and a refusal answers
974
+ * 'unavailable: range-too-large'.
975
+ */
976
+ export type Paging = PageNumberPaging | LinkHeaderPaging | CursorPaging;
977
+ /**
978
+ * Numbered pages from 1, read until one holds fewer than 'per_page' items. Both
979
+ * parameters are added to the request's query.
980
+ */
981
+ export interface PageNumberPaging {
982
+ kind: "page_number";
983
+ /**
984
+ * The parameter carrying the page number.
985
+ */
986
+ page_param: QueryName;
987
+ /**
988
+ * The parameter carrying 'per_page'. Absent: the vendor's page size is fixed,
989
+ * and 'per_page' says what it is.
990
+ */
991
+ per_page_param?: QueryName;
992
+ per_page: number;
993
+ items?: PageItems;
994
+ max_pages: MaxPages;
995
+ on_limit: PageLimit;
996
+ }
997
+ /**
998
+ * The address in the Link header's rel="next", followed until there is none. It
999
+ * must be https on one of the plug-in's hosts.
1000
+ */
1001
+ export interface LinkHeaderPaging {
1002
+ kind: "link_header";
1003
+ items?: PageItems;
1004
+ max_pages: MaxPages;
1005
+ on_limit: PageLimit;
1006
+ }
1007
+ /**
1008
+ * A cursor read from each page and sent with the next, while 'more' holds.
1009
+ * Exactly one of 'param' and 'variable' says where it is sent.
1010
+ */
1011
+ export interface CursorPaging {
1012
+ kind: "cursor";
1013
+ /**
1014
+ * The next page's cursor, from this page's 'response'.
1015
+ */
1016
+ next: Expression;
1017
+ /**
1018
+ * Whether there is a next page, from this page's 'response'.
1019
+ */
1020
+ more: Expression;
1021
+ /**
1022
+ * The query parameter the cursor is sent in.
1023
+ */
1024
+ param?: QueryName;
1025
+ /**
1026
+ * The GraphQL variable the cursor is sent in.
1027
+ */
1028
+ variable?: string;
1029
+ items?: PageItems;
1030
+ max_pages: MaxPages;
1031
+ on_limit: PageLimit;
1032
+ }
1033
+ /**
1034
+ * A page's items, from that page's 'response'. Absent: its body.
1035
+ */
1036
+ export type PageItems = Expression;
1037
+ export type MaxPages = number;
1038
+ /**
1039
+ * An HTTP status: one code, or a range of a hundred ('4xx').
1040
+ */
1041
+ export type StatusMatch = number | StatusRange;
1042
+ /**
1043
+ * A vendor answer an endpoint gives its own meaning. Rules are tried in order
1044
+ * on every answer, a 2xx included, and the first that matches decides.
1045
+ */
1046
+ export interface ErrorRule {
1047
+ status: StatusMatch;
1048
+ /**
1049
+ * Also required to hold, over the answer as 'response'. Absent: the status
1050
+ * alone matches.
1051
+ */
1052
+ when?: Expression;
1053
+ /**
1054
+ * What the call answers: one of the endpoint's 'unavailable' codes, one of
1055
+ * Initiative's own (invalid, mapping-failed, not-authorized, not-found,
1056
+ * range-too-large), or 'transient' for a passing failure such as a throttle,
1057
+ * which is answered as one to retry.
1058
+ */
1059
+ code: Identifier;
1060
+ }
1061
+ /**
1062
+ * A declarative plug-in's after_connect: a request, or up to 3 steps, made with
1063
+ * the access token just obtained, and the answers mapped to what the hook would
1064
+ * answer. 'params' holds the flow's own parameters, such as the installation_id
1065
+ * an install page returned.
1066
+ */
1067
+ export interface AfterConnect {
1068
+ /**
1069
+ * The one call. Not beside 'steps'.
1070
+ */
1071
+ request?: VendorRequest;
1072
+ /**
1073
+ * Up to 3 calls made in order, each able to read the answers of the ones
1074
+ * before it. Not beside 'request'.
1075
+ */
1076
+ steps?: RequestStep[];
1077
+ /**
1078
+ * The connection's managed values and its account label, from 'response' (the
1079
+ * last call's answer) and 'steps': {"values": {…}, "account_label": "…"}.
1080
+ */
1081
+ map: Expression;
1082
+ /**
1083
+ * Refuses the connection when it holds. It reads the map's answer as
1084
+ * 'result', beside 'response' and 'steps'.
1085
+ */
1086
+ refuse_when?: Expression;
1087
+ /**
1088
+ * What a refusal answers. Given exactly when 'refuse_when' is.
1089
+ */
1090
+ code?: Identifier;
1091
+ }
1092
+ /**
1093
+ * Declarative plug-ins: a request Initiative makes on an interval, with this
1094
+ * connection's credential, to learn whether the connection still works. A state
1095
+ * other than 'ok' is reported once two answers in a row give it.
1096
+ */
1097
+ export interface ConnectionHealth {
1098
+ request: VendorRequest;
1099
+ /**
1100
+ * How often: a whole number of minutes ('15m') or hours ('6h'), at least 5
1101
+ * minutes and at most 1440 minutes.
1102
+ */
1103
+ every: string;
1104
+ /**
1105
+ * Tried in order; the first that matches gives the state. An answer none
1106
+ * matches is 'ok' when it is 2xx and 'unavailable' otherwise.
1107
+ */
1108
+ states: HealthState[];
1109
+ }
1110
+ /**
1111
+ * The answers one row matches, and the state they mean. A row naming neither
1112
+ * 'status' nor 'when' matches any answer.
1113
+ */
1114
+ export interface HealthState {
1115
+ status?: StatusMatch;
1116
+ /**
1117
+ * Also required to hold, over the answer as 'response'.
1118
+ */
1119
+ when?: Expression;
1120
+ state: ConnectionState;
1121
+ }
1122
+ /**
1123
+ * One way a delivery becomes an event. Its expressions read 'headers' (names in
1124
+ * lowercase), 'payload' (the parsed body), 'connection' (the routed
1125
+ * connection's non-secret fields) and 'now'.
1126
+ */
1127
+ export interface WebhookEvent {
1128
+ /**
1129
+ * Whether this row applies.
1130
+ */
1131
+ when: Expression;
1132
+ /**
1133
+ * An emit endpoint this manifest declares.
1134
+ */
1135
+ emit: NamespacedId;
1136
+ /**
1137
+ * The event's payload: an object of that endpoint's declared returns.
1138
+ */
1139
+ map: Expression;
1140
+ }
1141
+ /**
1142
+ * A delivery that says what state a connection is in, read as an event's
1143
+ * expressions are.
1144
+ */
1145
+ export interface WebhookStatus {
1146
+ /**
1147
+ * Whether this row applies.
1148
+ */
1149
+ when: Expression;
1150
+ /**
1151
+ * A connection this plug-in declares.
1152
+ */
1153
+ connection: Identifier;
1154
+ /**
1155
+ * 'ok', 'suspended' or 'removed'.
1156
+ */
1157
+ state: ConnectionState;
1158
+ }
1159
+ /**
1160
+ * What a plug-in declares it can do. A plug-in is a container, which names its
1161
+ * `service` and answers Initiative's calls, or declarative, which names its
1162
+ * `hosts` and no service, and whose endpoints, connection checks and webhook
1163
+ * events Initiative runs itself from the requests and JSONata expressions
1164
+ * written here; one plug-in is never both. This is the 'definition' field of
1165
+ * the document served at /.well-known/initiative-plugin.json, NOT that whole
1166
+ * document: a registrar also requires protocol_version, public_id and kind
1167
+ * alongside it, and refuses a definition served bare. Generated from the
1168
+ * platform's own validator vocabulary. A manifest that satisfies this schema is
1169
+ * well-formed, not necessarily acceptable. Cross-references (the endpoint a
1170
+ * widget binds, a requires term's connection, an endpoint's service prefix),
1171
+ * the direction-specific rules on an endpoint, the features/blocks cross-check
1172
+ * in both directions, UTF-8 byte-size caps, the rules tying a connection's flow
1173
+ * and token to its scope and fields, what a webhooks block names, what a vendor
1174
+ * setup writes to, whether every expression parses, what a declarative request
1175
+ * and its steps name, and the bounds and unique ids of schedules are enforced
1176
+ * by the platform on publish and are not expressible here.
1177
+ */
1178
+ export interface Manifest {
1179
+ /**
1180
+ * The kind every plug-in manifest has, container or declarative: a
1181
+ * declarative plug-in is one with no 'service' block.
1182
+ */
1183
+ plugin_kind: "service";
1184
+ /**
1185
+ * A container plug-in's service, which Initiative calls. Absent for a
1186
+ * declarative plug-in, whose public id is its listing's.
1187
+ */
1188
+ service?: {
1189
+ /**
1190
+ * '<publisher>.<slug>'. The name the deployment's registration is matched
1191
+ * by, and the namespace this plug-in's events are emitted under.
1192
+ */
1193
+ public_id: string;
1194
+ protocol?: Protocol;
1195
+ /**
1196
+ * The scopes this plug-in asks a community to grant: what its installation
1197
+ * and member tokens act with. The fixed scopes, and 'plugins:<public_id>'
1198
+ * for each plug-in this one calls (at most 24 of those). The community
1199
+ * grants some or all of them when it installs the plug-in, and a token
1200
+ * never carries more than was granted. Writing implies reading. Absent
1201
+ * means none.
1202
+ */
1203
+ scopes?: Array<Scope | PluginScope>;
1204
+ };
1205
+ /**
1206
+ * What this plug-in contributes. Cross-checked against the blocks present in
1207
+ * both directions: a feature with no block, or a block with no feature, is
1208
+ * refused.
1209
+ */
1210
+ features: Feature[];
1211
+ default_name?: string;
1212
+ /**
1213
+ * Declarative plug-ins, which must name at least one: every host their
1214
+ * requests, paging and links may reach. A container plug-in names none.
1215
+ */
1216
+ hosts?: Host[];
1217
+ /**
1218
+ * Declarative plug-ins only.
1219
+ */
1220
+ auth?: VendorAuth;
1221
+ vendor?: Vendor;
1222
+ connections?: Connection[];
1223
+ webhooks?: Webhooks;
1224
+ /**
1225
+ * What Initiative calls the plug-in's schedule hook for, and how often. At
1226
+ * most 8.
1227
+ */
1228
+ schedules?: Schedule[];
1229
+ endpoints?: Endpoint[];
1230
+ /**
1231
+ * A read endpoint whose declared returns describe this community's standing
1232
+ * with your service — what it has used, what it is allowed. A deployment may
1233
+ * render them on the community's own settings page, beside its own figures.
1234
+ * Whether it does is the deployment's decision and not this manifest's: a
1235
+ * plug-in the operator did not ship is declaring where it would like to
1236
+ * appear, which is not the same as appearing.
1237
+ */
1238
+ community_summary?: NamespacedId;
1239
+ widgets?: Widget[];
1240
+ embeds?: Embed[];
1241
+ /**
1242
+ * Ready-made arrangements of this plug-in's own widgets. Publishing the
1243
+ * plug-in publishes one ordinary dashboard listing per entry, offered to
1244
+ * communities that install the plug-in.
1245
+ */
1246
+ dashboards?: BundledDashboard[];
1247
+ }