initiative-plugin-sdk 7.1.0 → 8.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.
@@ -3,7 +3,7 @@
3
3
  "schema": {
4
4
  "$id": "https://initiativetasks.com/schemas/plugin-manifest-v1.json",
5
5
  "title": "Initiative plug-in manifest (the 'definition' body)",
6
- "description": "What a plug-in declares it can do. A plug-in is a container, which names its `service` and answers Initiative's calls, or declarative, which names its `hosts` and no service, and whose endpoints, connection checks and webhook events Initiative runs itself from the requests and JSONata expressions written here; one plug-in is never both. This is the 'definition' field of the document served at /.well-known/initiative-plugin.json, NOT that whole document: a registrar also requires protocol_version, public_id and kind alongside it, and refuses a definition served bare. Generated from the platform's own validator vocabulary. A manifest that satisfies this schema is well-formed, not necessarily acceptable. Cross-references (the endpoint a widget binds, a requires term's connection, an endpoint's service prefix), the direction-specific rules on an endpoint, the features/blocks cross-check in both directions, UTF-8 byte-size caps, the rules tying a connection's flow and token to its scope and fields, what a webhooks block names, what a vendor setup writes to, whether every expression parses, what a declarative request and its steps name, the bounds and unique ids of schedules, the unique keys and ids of fields, parts and actions, what a part's nodes and an action name, and a part's size and depth are enforced by the platform on publish and are not expressible here."
6
+ "description": "What a plug-in declares it can do. A plug-in is a container, which names its `service` and answers Initiative's calls, or declarative, which names its `hosts` and no service, and whose endpoints, connection checks, webhook events, schedules and actions Initiative runs itself from the requests and JSONata expressions written here, keeping the values they write on items; one plug-in is never both. This is the 'definition' field of the document served at /.well-known/initiative-plugin.json, NOT that whole document: a registrar also requires protocol_version, public_id and kind alongside it, and refuses a definition served bare. Generated from the platform's own validator vocabulary. A manifest that satisfies this schema is well-formed, not necessarily acceptable. Cross-references (the endpoint a widget binds, a requires term's connection, an endpoint's service prefix), the direction-specific rules on an endpoint, the features/blocks cross-check in both directions, UTF-8 byte-size caps, the rules tying a connection's flow and token to its scope and fields, what a webhooks block names, what a vendor setup writes to, whether every expression parses, what a declarative request and its steps name, the bounds, ids and endpoints of schedules, which terms each kind's schedules, actions, fields and webhook events take, the unique keys and ids of fields, parts, actions and settings, what a part's nodes, a field's element actions and an action's endpoint and params name, the placeholders in a part's text, and a part's size and depth are enforced by the platform on publish and are not expressible here."
7
7
  },
8
8
  "charsets": {
9
9
  "identifier": "-0123456789_abcdefghijklmnopqrstuvwxyz",
@@ -17,7 +17,8 @@
17
17
  "version": "0123456789.-+abcdefghijklmnopqrstuvwxyz",
18
18
  "artwork": "abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789/._-",
19
19
  "queryName": "-.0123456789ABCDEFGHIJKLMNOPQRSTUVWXYZ[]_abcdefghijklmnopqrstuvwxyz~",
20
- "metadataKey": "._0123456789abcdefghijklmnopqrstuvwxyz"
20
+ "metadataKey": "._0123456789abcdefghijklmnopqrstuvwxyz",
21
+ "uniqueSettingValue": "0123456789abcdefghijklmnopqrstuvwxyz"
21
22
  },
22
23
  "enums": {
23
24
  "feature": [
@@ -181,6 +182,12 @@
181
182
  "neutral",
182
183
  "muted"
183
184
  ],
185
+ "settingType": [
186
+ "string"
187
+ ],
188
+ "settingAssignment": [
189
+ "community_name"
190
+ ],
184
191
  "listingKind": [
185
192
  "plugin",
186
193
  "dashboard"
@@ -241,6 +248,8 @@
241
248
  "actions": 16,
242
249
  "partNodes": 50,
243
250
  "partDepth": 4,
251
+ "facetsPerField": 4,
252
+ "valuesPerFacet": 12,
244
253
  "metadataKeyLength": 64,
245
254
  "metadataValueBytes": 8192,
246
255
  "metadataLookupLength": 255,
@@ -248,7 +257,11 @@
248
257
  "metadataBytesPerObject": 65536,
249
258
  "installMetadataKeys": 256,
250
259
  "installMetadataBytes": 1048576,
260
+ "writeTargets": 100,
251
261
  "partsPlacedPerItem": 3,
262
+ "settings": 16,
263
+ "uniqueSettingValueLength": 16,
264
+ "helpLength": 2000,
252
265
  "bundledDashboards": 8,
253
266
  "dashboardWidgets": 50,
254
267
  "dashboardGridColumns": 12,
@@ -834,6 +847,17 @@
834
847
  "maxLength": "urlLength",
835
848
  "description": "Where the signed JWT is posted, https. The answer's 'token' (or 'access_token') and 'expires_at' (or 'expires_in') are read. May name a vendor value as '{vendor.<key>}' and one of this connection's own fields as '{<key>}'."
836
849
  },
850
+ "exchange_body": {
851
+ "anyOf": [
852
+ {
853
+ "type": "object"
854
+ },
855
+ {
856
+ "ref": "expression"
857
+ }
858
+ ],
859
+ "description": "A JSON body posted with the signed JWT, such as the narrower permissions a token is asked for. Absent: none. A string anywhere in it may name a vendor value as '{vendor.<key>}' and one of this connection's own fields as '{<key>}'. Or an expression answering the body, which reads only 'connection': this connection's own non-secret fields by key, its managed values included, as 'after_connect' stored them. A body that names a vendor value is written as an object. An answer that is not an object fails the token request, so the connection cannot be used until the expression answers one."
860
+ },
837
861
  "iss": {
838
862
  "type": "string",
839
863
  "minLength": 1,
@@ -889,7 +913,7 @@
889
913
  "items": {
890
914
  "ref": "webhookEvent"
891
915
  },
892
- "description": "Declarative plug-ins: how a delivery becomes one of this plug-in's events. The first row whose 'when' holds emits; a delivery no row matches is dropped."
916
+ "description": "Declarative plug-ins: what a delivery does: emit one of this plug-in's events, change the plug-in's values, or both. The first row whose 'when' holds applies, its 'emit' and its 'write' both; a delivery no row matches is dropped."
893
917
  },
894
918
  "status": {
895
919
  "type": "array",
@@ -976,7 +1000,7 @@
976
1000
  },
977
1001
  "schedule": {
978
1002
  "type": "object",
979
- "description": "An interval at which Initiative calls the plug-in's schedule hook, once for each community that installed it, with when the call last succeeded there.",
1003
+ "description": "Something Initiative runs on an interval, once for each community that installed the plug-in, with when it last succeeded there as 'since'. A container plug-in's schedule calls its schedule hook, and names nothing more. A declarative plug-in's makes one of its read endpoints' calls as the installation and changes the plug-in's values from the answer: it names the 'endpoint' and the 'write', and 'params' when the endpoint takes any.",
980
1004
  "required": [
981
1005
  "id",
982
1006
  "every"
@@ -984,13 +1008,25 @@
984
1008
  "properties": {
985
1009
  "id": {
986
1010
  "ref": "identifier",
987
- "description": "Unique within the manifest. The hook is told which schedule is due by it."
1011
+ "description": "Unique within the manifest. A container's hook is told which schedule is due by it. A declarative plug-in's differs from every connection's id: Initiative keys connection health checks by connection id."
988
1012
  },
989
1013
  "every": {
990
1014
  "type": "string",
991
1015
  "maxLength": "scheduleEveryLength",
992
1016
  "pattern": "^[0-9]+[mh]$",
993
1017
  "description": "How often: a whole number of minutes ('15m') or hours ('6h'), at least {scheduleMinMinutes} minutes and at most {scheduleMaxMinutes} minutes."
1018
+ },
1019
+ "endpoint": {
1020
+ "ref": "namespacedId",
1021
+ "description": "Declarative plug-ins: a read endpoint this manifest declares, whose 'actors' include 'installation': no person is present when a schedule runs."
1022
+ },
1023
+ "params": {
1024
+ "ref": "expression",
1025
+ "description": "Declarative plug-ins: the endpoint's params, as one expression answering an object. It reads 'since', when the schedule last succeeded in the community (ISO 8601), or null the first time; 'now'; 'connection', the non-secret fields of the connection the endpoint's first request names; 'settings' and 'aliases'. Absent: none."
1026
+ },
1027
+ "write": {
1028
+ "ref": "expression",
1029
+ "description": "Declarative plug-ins: the changes Initiative makes to the plug-in's values from the endpoint's answer, as the install: a list of at most {writeTargets} targeted changes ('targetedChange'). It reads 'result', the endpoint's mapped answer, 'since', 'now', 'settings' and 'aliases'. Answering nothing changes nothing."
994
1030
  }
995
1031
  }
996
1032
  },
@@ -1006,7 +1042,7 @@
1006
1042
  "patternFrom": "publicId",
1007
1043
  "patternForm": "dotted",
1008
1044
  "patternPrefix": "plugins:",
1009
- "description": "'plugins:<public_id>': permission to call another plug-in's public endpoints through the deployment, as this community or as one of its members. Not one of the fixed scopes: the family is open, one per plug-in, and the public id after the prefix is the plug-in being called. The deployment never lets a plug-in address another directly; the call goes through it, and the plug-in called is handed its own references for whoever the call is for."
1045
+ "description": "'plugins:<public_id>': permission to call another plug-in's public endpoints through the deployment, as this community or as one of its members, and to read the values that plug-in shows on items this one can read. Not one of the fixed scopes: the family is open, one per plug-in, and the public id after the prefix is the plug-in being called. The deployment never lets a plug-in address another directly; the call goes through it, and the plug-in called is handed its own references for whoever the call is for."
1010
1046
  },
1011
1047
  "endpoint": {
1012
1048
  "type": "object",
@@ -1219,7 +1255,7 @@
1219
1255
  },
1220
1256
  "field": {
1221
1257
  "type": "object",
1222
- "description": "How one of the plug-in's metadata keys is shown on Initiative's items. The plug-in keeps the value in Initiative, through its installation token; Initiative draws it with its own component for `kind` and computes its plain text itself, so a field filters, sorts and exports with no call to the plug-in. Which views show it is chosen by the community's managers, never by the plug-in. Initiative holds what is kept, and these caps are enforced there rather than here: a value of at most {metadataValueBytes} bytes as JSON, with a string of at most {metadataLookupLength} characters to be found by; at most {metadataKeysPerObject} keys and {metadataBytesPerObject} bytes on one item, and {installMetadataKeys} keys and {installMetadataBytes} bytes on the install.",
1258
+ "description": "How one of the plug-in's metadata keys is shown on Initiative's items. The value is kept in Initiative: a container plug-in writes it with its installation token, and for a declarative plug-in Initiative writes it from the plug-in's expressions. Initiative draws it with its own component for `kind` and computes its plain text itself, so a field filters, sorts and exports with no call to the plug-in. Which views show it is chosen by the community's managers, never by the plug-in. Initiative holds what is kept, and these caps are enforced there rather than here: a value of at most {metadataValueBytes} bytes as JSON, with a string of at most {metadataLookupLength} characters to be found by, and each element of a list a value of its own, found by its 'ref'; at most {metadataKeysPerObject} keys and {metadataBytesPerObject} bytes on one item, and {installMetadataKeys} keys and {installMetadataBytes} bytes on the install.",
1223
1259
  "required": [
1224
1260
  "key",
1225
1261
  "name",
@@ -1239,6 +1275,11 @@
1239
1275
  "enum": "fieldKind",
1240
1276
  "description": "What the value is, and so how it is drawn: 'text' a string; 'number' a number; 'date' a 'YYYY-MM-DD' string; 'datetime' an ISO 8601 string with its offset; 'link' {url, text?}; 'badge' {text, tone?}; 'progress' {value, max}; 'checkbox' a boolean."
1241
1277
  },
1278
+ "list": {
1279
+ "type": "boolean",
1280
+ "default": false,
1281
+ "description": "Several values rather than one: the value is a list of elements, each one value of 'kind' with a 'ref' that tells it from the others ('listElement'). A change gives the whole list in 'set', or adds, replaces and removes elements by 'ref' with 'upsert' and 'remove'. Absent: one value, which a change sets."
1282
+ },
1242
1283
  "on": {
1243
1284
  "type": "array",
1244
1285
  "minItems": 1,
@@ -1259,11 +1300,76 @@
1259
1300
  "enum": "tone",
1260
1301
  "description": "A badge's tone when its value names none."
1261
1302
  },
1303
+ "states": {
1304
+ "type": "object",
1305
+ "minProperties": 1,
1306
+ "maxProperties": "facetsPerField",
1307
+ "propertyNames": {
1308
+ "ref": "identifier"
1309
+ },
1310
+ "additionalProperties": {
1311
+ "ref": "stateFacet"
1312
+ },
1313
+ "description": "What state the value is in, as facets by id, at most {facetsPerField}, each with keys of its own. The value names a key of each facet it is in as 'state', {\"<facet>\": \"<key>\"}, and Initiative draws each as a badge, labelled in the reader's language. A list element, and a link, badge or progress value, carries 'state' beside its other properties; a text, number, date, datetime or checkbox value that carries one is written as an element is, without the 'ref': {\"value\": \u2026, \"state\": \u2026}."
1314
+ },
1315
+ "actions": {
1316
+ "type": "array",
1317
+ "minItems": 1,
1318
+ "maxItems": "actions",
1319
+ "uniqueItems": true,
1320
+ "items": {
1321
+ "ref": "identifier"
1322
+ },
1323
+ "description": "Declarative plug-ins, on a list field: actions offered on each of its elements, by id, each one offered on every item kind this field is. An action run from an element reads that element's 'ref' as 'element'."
1324
+ },
1262
1325
  "requires": {
1263
1326
  "ref": "requires"
1264
1327
  }
1265
1328
  }
1266
1329
  },
1330
+ "stateFacet": {
1331
+ "type": "object",
1332
+ "description": "One facet of a field's state, such as whether a piece of work is open or what review it has: its name, and the keys a value may name.",
1333
+ "required": [
1334
+ "name",
1335
+ "values"
1336
+ ],
1337
+ "properties": {
1338
+ "name": {
1339
+ "ref": "localizedText",
1340
+ "description": "What the facet is called."
1341
+ },
1342
+ "values": {
1343
+ "type": "object",
1344
+ "minProperties": 1,
1345
+ "maxProperties": "valuesPerFacet",
1346
+ "propertyNames": {
1347
+ "ref": "identifier"
1348
+ },
1349
+ "additionalProperties": {
1350
+ "ref": "stateValue"
1351
+ },
1352
+ "description": "The keys a value may name, at most {valuesPerFacet}, each with its badge's words and tone."
1353
+ }
1354
+ },
1355
+ "additionalProperties": false
1356
+ },
1357
+ "stateValue": {
1358
+ "type": "object",
1359
+ "description": "One key of a state facet, as its badge shows it.",
1360
+ "required": [
1361
+ "label"
1362
+ ],
1363
+ "properties": {
1364
+ "label": {
1365
+ "ref": "localizedText"
1366
+ },
1367
+ "tone": {
1368
+ "enum": "tone"
1369
+ }
1370
+ },
1371
+ "additionalProperties": false
1372
+ },
1267
1373
  "partNode": {
1268
1374
  "description": "One node of a part: one of Initiative's own components, told apart by 'type', with its props and, for a section or a stack, the nodes inside it.",
1269
1375
  "oneOf": [
@@ -1442,7 +1548,8 @@
1442
1548
  ],
1443
1549
  "properties": {
1444
1550
  "text": {
1445
- "ref": "localizedText"
1551
+ "ref": "localizedText",
1552
+ "description": "May name '{item.id}', the item's id, and '{settings.<key>}', one of this plug-in's settings, which Initiative fills in when it draws the part. Any other '{\u2026}' is refused."
1446
1553
  },
1447
1554
  "tone": {
1448
1555
  "enum": "tone"
@@ -1532,11 +1639,10 @@
1532
1639
  },
1533
1640
  "action": {
1534
1641
  "type": "object",
1535
- "description": "Something a reader runs on one item, from a part's button or the item's own menu. Initiative only connects: it calls the write endpoint as the installation, with the reader as 'viewer' and the item as 'subject' in the call's token, and the endpoint does the work, usually writing the plug-in's metadata. Initiative then answers the reader with the item's metadata as it stands.",
1642
+ "description": "Something a reader runs on one item, from a part's button, the item's own menu, or an element of a list field that offers it. Initiative first asks the reader for the 'params' the action names, when it names any. For a container plug-in, Initiative only connects: it calls the write endpoint as the installation, with those parameters, the reader as 'viewer' and the item as 'subject' in the call's token, and the endpoint does the work, usually writing the plug-in's metadata. For a declarative plug-in, Initiative does the work: it makes the endpoint's call, when the action names one, with those parameters, on the credential its 'actors' say, its expressions reading the item as 'item' and the element it was run from, if any, as 'element'; then it makes the change 'write' answers, when the action has one, to the plug-in's values on the item, as the install. Either way Initiative then answers the reader with the item's metadata as it stands.",
1536
1643
  "required": [
1537
1644
  "id",
1538
1645
  "name",
1539
- "endpoint",
1540
1646
  "on"
1541
1647
  ],
1542
1648
  "properties": {
@@ -1550,7 +1656,21 @@
1550
1656
  },
1551
1657
  "endpoint": {
1552
1658
  "ref": "namespacedId",
1553
- "description": "A write endpoint this manifest declares."
1659
+ "description": "An endpoint this manifest declares. A container plug-in's action names a write, which its handler answers. A declarative plug-in's names a read or a write, a 'write' expression, or both: a read fetches what the 'write' keeps, a write changes something at the vendor."
1660
+ },
1661
+ "params": {
1662
+ "type": "array",
1663
+ "minItems": 1,
1664
+ "maxItems": "paramsPerEndpoint",
1665
+ "uniqueItems": true,
1666
+ "items": {
1667
+ "ref": "identifier"
1668
+ },
1669
+ "description": "Parameters of the action's endpoint, by key, that Initiative asks the reader for before it runs the action, in a form drawn from the endpoint's own declarations of them: each one's type and label, and its 'options' or 'options_from'. The endpoint is sent these and nothing else, so every parameter it requires is among them."
1670
+ },
1671
+ "write": {
1672
+ "ref": "expression",
1673
+ "description": "Declarative plug-ins: the change Initiative makes to the plug-in's values on the action's item, as the install: one change ('change'). It reads 'item', the item ({kind, id, title}); 'held', this install's values on it, by key; 'result', the endpoint's mapped answer, absent when the action names no endpoint; 'params', what the reader answered; 'element', the 'ref' of the list element it was run from, absent when it was not; 'settings', 'aliases' and 'now'. Answering nothing changes nothing."
1554
1674
  },
1555
1675
  "on": {
1556
1676
  "type": "array",
@@ -1573,11 +1693,308 @@
1573
1693
  "default": false,
1574
1694
  "description": "Also offered in the item's own menu."
1575
1695
  },
1696
+ "admin_only": {
1697
+ "type": "boolean",
1698
+ "default": false,
1699
+ "description": "Only the community's admins run this action, whatever roles a placement allows. Who else may run it is chosen in the community, per initiative and per role, not declared here."
1700
+ },
1576
1701
  "requires": {
1577
1702
  "ref": "requires"
1578
1703
  }
1579
1704
  }
1580
1705
  },
1706
+ "change": {
1707
+ "type": "object",
1708
+ "description": "A change to the plug-in's values on one item or on its install, as a declarative plug-in's 'write' answers it. 'set' writes values by key, as a container's client.metadata.set does; 'upsert' and 'remove' change a list field's elements by their 'ref'. A change gives at least one of the three, and changes each key with only one. Initiative makes it as the install, and holds what is kept to the caps a field's description gives.",
1709
+ "properties": {
1710
+ "set": {
1711
+ "type": "object",
1712
+ "propertyNames": {
1713
+ "ref": "metadataKey"
1714
+ },
1715
+ "description": "Values by metadata key, each any JSON value of at most {metadataValueBytes} bytes; a null removes its key. A list field's value is its whole list of elements, each held to that cap."
1716
+ },
1717
+ "upsert": {
1718
+ "type": "object",
1719
+ "propertyNames": {
1720
+ "ref": "metadataKey"
1721
+ },
1722
+ "additionalProperties": {
1723
+ "type": "array",
1724
+ "items": {
1725
+ "ref": "listElement"
1726
+ }
1727
+ },
1728
+ "description": "Elements by metadata key ('listElement'): each is added to that key's list, or merged into the element there with its 'ref': the properties it gives replace that element's, the ones it leaves out stay, and its 'state' merges the same way by facet. So a write that knows one fact about an element changes that fact alone."
1729
+ },
1730
+ "remove": {
1731
+ "type": "object",
1732
+ "propertyNames": {
1733
+ "ref": "metadataKey"
1734
+ },
1735
+ "additionalProperties": {
1736
+ "type": "array",
1737
+ "items": {
1738
+ "ref": "elementRef"
1739
+ }
1740
+ },
1741
+ "description": "Refs by metadata key: the element with each is taken from that key's list. A ref the list does not hold changes nothing."
1742
+ }
1743
+ },
1744
+ "anyOf": [
1745
+ {
1746
+ "required": [
1747
+ "set"
1748
+ ]
1749
+ },
1750
+ {
1751
+ "required": [
1752
+ "upsert"
1753
+ ]
1754
+ },
1755
+ {
1756
+ "required": [
1757
+ "remove"
1758
+ ]
1759
+ }
1760
+ ],
1761
+ "additionalProperties": false
1762
+ },
1763
+ "targetedChange": {
1764
+ "type": "object",
1765
+ "description": "A change and where Initiative makes it. A webhook event's or a schedule's 'write' answers a list of at most {writeTargets}, and cannot read what their targets hold.",
1766
+ "required": [
1767
+ "target"
1768
+ ],
1769
+ "properties": {
1770
+ "target": {
1771
+ "ref": "changeTarget"
1772
+ },
1773
+ "set": {
1774
+ "type": "object",
1775
+ "propertyNames": {
1776
+ "ref": "metadataKey"
1777
+ },
1778
+ "description": "As a change's: values by metadata key, a null removing its key."
1779
+ },
1780
+ "upsert": {
1781
+ "type": "object",
1782
+ "propertyNames": {
1783
+ "ref": "metadataKey"
1784
+ },
1785
+ "additionalProperties": {
1786
+ "type": "array",
1787
+ "items": {
1788
+ "ref": "listElement"
1789
+ }
1790
+ },
1791
+ "description": "As a change's: elements by metadata key, each added to its list or merged into the one with its 'ref', property by property and its 'state' facet by facet."
1792
+ },
1793
+ "remove": {
1794
+ "type": "object",
1795
+ "propertyNames": {
1796
+ "ref": "metadataKey"
1797
+ },
1798
+ "additionalProperties": {
1799
+ "type": "array",
1800
+ "items": {
1801
+ "ref": "elementRef"
1802
+ }
1803
+ },
1804
+ "description": "As a change's: refs by metadata key, each element with one taken from its list."
1805
+ }
1806
+ },
1807
+ "anyOf": [
1808
+ {
1809
+ "required": [
1810
+ "set"
1811
+ ]
1812
+ },
1813
+ {
1814
+ "required": [
1815
+ "upsert"
1816
+ ]
1817
+ },
1818
+ {
1819
+ "required": [
1820
+ "remove"
1821
+ ]
1822
+ }
1823
+ ],
1824
+ "additionalProperties": false
1825
+ },
1826
+ "changeTarget": {
1827
+ "description": "Where a change is made: {kind, id}, one item; {install: true}, the install itself; or {holding: {key, value}}, every item on which this install holds 'value' under 'key', as a container's client.metadata.find finds them. Initiative keeps each element of a list as a value of its own, so 'holding' reaches an element by its 'ref'. A target the install cannot read is skipped.",
1828
+ "oneOf": [
1829
+ {
1830
+ "type": "object",
1831
+ "required": [
1832
+ "kind",
1833
+ "id"
1834
+ ],
1835
+ "properties": {
1836
+ "kind": {
1837
+ "enum": "itemKind"
1838
+ },
1839
+ "id": {
1840
+ "type": "integer",
1841
+ "minimum": 1
1842
+ }
1843
+ },
1844
+ "additionalProperties": false
1845
+ },
1846
+ {
1847
+ "type": "object",
1848
+ "required": [
1849
+ "install"
1850
+ ],
1851
+ "properties": {
1852
+ "install": {
1853
+ "const": true
1854
+ }
1855
+ },
1856
+ "additionalProperties": false
1857
+ },
1858
+ {
1859
+ "type": "object",
1860
+ "required": [
1861
+ "holding"
1862
+ ],
1863
+ "properties": {
1864
+ "holding": {
1865
+ "type": "object",
1866
+ "required": [
1867
+ "key",
1868
+ "value"
1869
+ ],
1870
+ "properties": {
1871
+ "key": {
1872
+ "ref": "metadataKey"
1873
+ },
1874
+ "value": {
1875
+ "type": "string",
1876
+ "maxLength": "metadataLookupLength",
1877
+ "description": "A value is found by its text: a string as it is, a number or a boolean as JSON writes it; a list element by its 'ref'."
1878
+ }
1879
+ },
1880
+ "additionalProperties": false
1881
+ }
1882
+ },
1883
+ "additionalProperties": false
1884
+ }
1885
+ ]
1886
+ },
1887
+ "listElement": {
1888
+ "type": "object",
1889
+ "description": "One element of a list field's value: one value of the field's 'kind', with a 'ref' that tells it from the list's others. A text, number, date, datetime or checkbox element holds its value in 'value'; a link element is {ref, url, text?}, a badge element {ref, text, tone?} and a progress element {ref, value, max}. Initiative keeps each element as a value of its own, of at most {metadataValueBytes} bytes as JSON. An 'upsert' may give only some of an element's properties: they are merged into the element with its 'ref'.",
1890
+ "required": [
1891
+ "ref"
1892
+ ],
1893
+ "properties": {
1894
+ "ref": {
1895
+ "ref": "elementRef"
1896
+ },
1897
+ "value": {
1898
+ "type": [
1899
+ "string",
1900
+ "number",
1901
+ "boolean"
1902
+ ],
1903
+ "description": "A text, number, date, datetime or checkbox element's value, or a progress element's figure."
1904
+ },
1905
+ "url": {
1906
+ "type": "string",
1907
+ "description": "A link element's address."
1908
+ },
1909
+ "text": {
1910
+ "type": "string",
1911
+ "description": "A link element's words, or a badge element's."
1912
+ },
1913
+ "tone": {
1914
+ "enum": "tone",
1915
+ "description": "A badge element's tone."
1916
+ },
1917
+ "max": {
1918
+ "type": "number",
1919
+ "description": "A progress element's whole."
1920
+ },
1921
+ "state": {
1922
+ "type": "object",
1923
+ "propertyNames": {
1924
+ "ref": "identifier"
1925
+ },
1926
+ "additionalProperties": {
1927
+ "ref": "identifier"
1928
+ },
1929
+ "description": "A key of each of the field's state facets this element is in, by facet id."
1930
+ }
1931
+ },
1932
+ "additionalProperties": false
1933
+ },
1934
+ "elementRef": {
1935
+ "type": "string",
1936
+ "minLength": 1,
1937
+ "maxLength": "metadataLookupLength",
1938
+ "description": "What tells a list's element from the others, such as the vendor's own id for what it shows: unique in its list, and how a change replaces or removes the element and a 'holding' target finds it."
1939
+ },
1940
+ "setting": {
1941
+ "type": "object",
1942
+ "description": "A value the community's admins see and may change on the install, which the plug-in's expressions read as 'settings.<key>' and its parts' text names as '{settings.<key>}'.",
1943
+ "required": [
1944
+ "key",
1945
+ "type",
1946
+ "label"
1947
+ ],
1948
+ "properties": {
1949
+ "key": {
1950
+ "ref": "identifier",
1951
+ "description": "Unique among this manifest's settings."
1952
+ },
1953
+ "type": {
1954
+ "enum": "settingType",
1955
+ "description": "What the value is: 'string', a line of text."
1956
+ },
1957
+ "label": {
1958
+ "ref": "localizedText"
1959
+ },
1960
+ "description": {
1961
+ "ref": "localizedText",
1962
+ "description": "A line under the label."
1963
+ },
1964
+ "unique": {
1965
+ "type": "boolean",
1966
+ "default": false,
1967
+ "description": "No two communities on a deployment hold the same value for this plug-in, and the value is a 'uniqueSettingValue'. An admin who renames it keeps the earlier values, which no other community may take and the plug-in's expressions read as 'aliases.<key>'."
1968
+ },
1969
+ "assigned": {
1970
+ "enum": "settingAssignment",
1971
+ "description": "A unique setting's only: Initiative gives it a value when the community installs the plug-in, which an admin may rename. 'community_name': the letters and digits of the community's name, in lowercase, with a short random suffix when another community holds that value."
1972
+ }
1973
+ },
1974
+ "if": {
1975
+ "required": [
1976
+ "assigned"
1977
+ ]
1978
+ },
1979
+ "then": {
1980
+ "required": [
1981
+ "unique"
1982
+ ],
1983
+ "properties": {
1984
+ "unique": {
1985
+ "const": true
1986
+ }
1987
+ }
1988
+ }
1989
+ },
1990
+ "uniqueSettingValue": {
1991
+ "type": "string",
1992
+ "minLength": 2,
1993
+ "maxLength": "uniqueSettingValueLength",
1994
+ "patternFrom": "uniqueSettingValue",
1995
+ "patternForm": "letterFirst",
1996
+ "description": "A unique setting's value: a lowercase letter, then lowercase letters and digits, two to {uniqueSettingValueLength} characters in all. It holds no '-', so a reference such as '<value>-<number>' reads one way."
1997
+ },
1581
1998
  "bundledDashboard": {
1582
1999
  "type": "object",
1583
2000
  "required": [
@@ -1727,7 +2144,7 @@
1727
2144
  "type": "string",
1728
2145
  "minLength": 1,
1729
2146
  "maxLength": "expressionLength",
1730
- "description": "A JSONata expression (https://jsonata.org): standard JSONata, with no functions added. It reads one document. On the way out that holds 'params', the call's parameters as the caller sent them; 'connection', the non-secret fields of the connection the request names; 'connections', on an endpoint's requests and map, each connection its 'requires' names that the call has, by its id, holding the same fields; 'now', the time of the call in ISO 8601, which $now() and $millis() also answer; and 'steps', each earlier step's answer by its name. On the way back it also holds 'response', the answer being read: {status, headers, body}, with header names in lowercase. Each evaluation is bounded: at most {expressionTimeMs} milliseconds, {expressionDepth} levels of nesting and an answer of {expressionOutputBytes} bytes as JSON. An expression that fails or passes a bound answers 'unavailable: mapping-failed'."
2147
+ "description": "A JSONata expression (https://jsonata.org): standard JSONata, with no functions added. It reads one document. On the way out that holds 'params', the call's parameters as the caller sent them; 'connection', the non-secret fields of the connection the request names; 'connections', on an endpoint's requests and map, each connection its 'requires' names that the call has, by its id, holding the same fields; 'now', the time of the call in ISO 8601, which $now() and $millis() also answer; 'steps', each earlier step's answer by its name; and, on the call an action makes, 'item', the item it runs on: {kind, id, title}, and 'element', the 'ref' of the list element it was run from, if it was. On the way back it also holds 'response', the answer being read: {status, headers, body}, with header names in lowercase. Every expression of a declarative plug-in also reads 'settings', the install's settings by key, and 'aliases', each unique setting's earlier values by key, as a list, except a token's 'exchange_body', which reads only its connection. Each evaluation is bounded: at most {expressionTimeMs} milliseconds, {expressionDepth} levels of nesting and an answer of {expressionOutputBytes} bytes as JSON. An expression that fails or passes a bound answers 'unavailable: mapping-failed'."
1731
2148
  },
1732
2149
  "host": {
1733
2150
  "type": "string",
@@ -1812,8 +2229,15 @@
1812
2229
  "ref": "graphqlRequest"
1813
2230
  },
1814
2231
  "connection": {
1815
- "ref": "identifier",
1816
- "description": "Which connection's credential the request carries: a static connection's is the community's, an interactive one's the acting member's. A call made as a member carries a static connection's credential only when the endpoint's 'requires' names that connection, and is refused otherwise. Required on an endpoint's requests. Absent on 'after_connect' and 'health', which carry the credential of the connection they belong to."
2232
+ "anyOf": [
2233
+ {
2234
+ "ref": "identifier"
2235
+ },
2236
+ {
2237
+ "ref": "actorConnections"
2238
+ }
2239
+ ],
2240
+ "description": "Which connection's credential the request carries: one connection for every call, or, on a write endpoint's requests, one per actor ('actorConnections'), so a call made as the member carries the member's own credential and one made as the installation the community's. A static connection's credential is the community's, an interactive one's the acting member's, which a call made as the installation does not have. A call made as a member carries a static connection's credential only when the endpoint's 'requires' names that connection, and is refused otherwise. Required on an endpoint's requests. Absent on 'after_connect' and 'health', which carry the credential of the connection they belong to."
1817
2241
  },
1818
2242
  "paging": {
1819
2243
  "ref": "paging"
@@ -1841,6 +2265,22 @@
1841
2265
  },
1842
2266
  "additionalProperties": false
1843
2267
  },
2268
+ "actorConnections": {
2269
+ "type": "object",
2270
+ "description": "One connection per actor, on a write endpoint's requests: a call carries the credential of the connection named for the actor it is made as. Names exactly the actors the endpoint's 'actors' declare. The member's connection need not be named in 'requires': a call made as the member requires the connection its requests name for the member.",
2271
+ "minProperties": 1,
2272
+ "properties": {
2273
+ "member": {
2274
+ "ref": "identifier",
2275
+ "description": "An interactive connection, which a call made as the member carries: the member's own account."
2276
+ },
2277
+ "installation": {
2278
+ "ref": "identifier",
2279
+ "description": "A static connection, which a call made as the installation carries: the community's own."
2280
+ }
2281
+ },
2282
+ "additionalProperties": false
2283
+ },
1844
2284
  "requestStep": {
1845
2285
  "type": "object",
1846
2286
  "required": [
@@ -2123,11 +2563,9 @@
2123
2563
  },
2124
2564
  "webhookEvent": {
2125
2565
  "type": "object",
2126
- "description": "One way a delivery becomes an event. Its expressions read 'headers' (names in lowercase), 'payload' (the parsed body), 'connection' (the routed connection's non-secret fields) and 'now'.",
2566
+ "description": "What one kind of delivery does: emit an event, change the plug-in's values, or both. It gives 'emit', 'write' or both, and 'map' exactly when it gives 'emit'. Its expressions read 'headers' (names in lowercase), 'payload' (the parsed body), 'connection' (the routed connection's non-secret fields), 'now', 'settings' and 'aliases'.",
2127
2567
  "required": [
2128
- "when",
2129
- "emit",
2130
- "map"
2568
+ "when"
2131
2569
  ],
2132
2570
  "properties": {
2133
2571
  "when": {
@@ -2141,6 +2579,10 @@
2141
2579
  "map": {
2142
2580
  "ref": "expression",
2143
2581
  "description": "The event's payload: an object of that endpoint's declared returns."
2582
+ },
2583
+ "write": {
2584
+ "ref": "expression",
2585
+ "description": "The changes Initiative makes to the plug-in's values, as the install: a list of at most {writeTargets} targeted changes ('targetedChange'). Answering nothing changes nothing."
2144
2586
  }
2145
2587
  },
2146
2588
  "additionalProperties": false
@@ -2214,7 +2656,12 @@
2214
2656
  }
2215
2657
  ]
2216
2658
  },
2217
- "description": "The scopes this plug-in asks a community to grant: what its installation and member tokens act with. The fixed scopes, and 'plugins:<public_id>' for each plug-in this one calls (at most {pluginScopes} of those). The community grants some or all of them when it installs the plug-in, and a token never carries more than was granted. Writing implies reading. Absent means none."
2659
+ "description": "The scopes this plug-in asks a community to grant: what its installation and member tokens act with. The fixed scopes, and 'plugins:<public_id>' for each plug-in this one uses, to call its public endpoints and read the values it shows on items (at most {pluginScopes} of those). The community grants some or all of them when it installs the plug-in, and a token never carries more than was granted. Writing implies reading. Absent means none."
2660
+ },
2661
+ "calls_plugins": {
2662
+ "type": "boolean",
2663
+ "default": false,
2664
+ "description": "This plug-in may act through any plug-in the community lets it use, not only those its scopes name as 'plugins:<public_id>'. When a community installs another plug-in, it is asked there whether this one may use it, which grants 'plugins:<public_id>' for it. Absent: only the plug-ins its scopes name."
2218
2665
  }
2219
2666
  },
2220
2667
  "description": "A container plug-in's service, which Initiative calls. Absent for a declarative plug-in, whose public id is its listing's."
@@ -2267,6 +2714,25 @@
2267
2714
  "ref": "vendorAuth",
2268
2715
  "description": "Declarative plug-ins only."
2269
2716
  },
2717
+ "scopes": {
2718
+ "type": "array",
2719
+ "maxItems": {
2720
+ "wholeOf": "scope",
2721
+ "plus": "pluginScopes"
2722
+ },
2723
+ "uniqueItems": true,
2724
+ "items": {
2725
+ "anyOf": [
2726
+ {
2727
+ "enum": "scope"
2728
+ },
2729
+ {
2730
+ "ref": "pluginScope"
2731
+ }
2732
+ ]
2733
+ },
2734
+ "description": "Declarative plug-ins: the scopes this plug-in asks a community to grant, all of them read scopes ('<resource>:read'). A declarative plug-in keeps its own values on items it can read and does not call Initiative, and Initiative keeps them only on items these scopes read. A container plug-in declares its scopes in its service block."
2735
+ },
2270
2736
  "vendor": {
2271
2737
  "ref": "vendor"
2272
2738
  },
@@ -2286,7 +2752,7 @@
2286
2752
  "items": {
2287
2753
  "ref": "schedule"
2288
2754
  },
2289
- "description": "What Initiative calls the plug-in's schedule hook for, and how often. At most {schedules}."
2755
+ "description": "What Initiative runs on an interval for each community: a container plug-in's schedule hook, or a declarative plug-in's read and the values it writes from the answer. At most {schedules}."
2290
2756
  },
2291
2757
  "endpoints": {
2292
2758
  "type": "array",
@@ -2327,7 +2793,7 @@
2327
2793
  "items": {
2328
2794
  "ref": "field"
2329
2795
  },
2330
- "description": "How the plug-in's metadata is shown on items. A container plug-in's only: a declarative plug-in holds no installation token, so it keeps no metadata to show."
2796
+ "description": "How the plug-in's values on items are shown there. Any plug-in may keep values on items: a container writes them with its installation token, and for a declarative plug-in Initiative writes them from the plug-in's expressions."
2331
2797
  },
2332
2798
  "parts": {
2333
2799
  "type": "array",
@@ -2335,7 +2801,7 @@
2335
2801
  "items": {
2336
2802
  "ref": "part"
2337
2803
  },
2338
- "description": "Pieces of items' pages and views, built from Initiative's components and bound to the plug-in's fields and actions. A container plug-in's only, as fields are."
2804
+ "description": "Pieces of items' pages and views, built from Initiative's components and bound to the plug-in's fields and actions."
2339
2805
  },
2340
2806
  "actions": {
2341
2807
  "type": "array",
@@ -2343,7 +2809,32 @@
2343
2809
  "items": {
2344
2810
  "ref": "action"
2345
2811
  },
2346
- "description": "What a reader may run on an item, each one of the plug-in's write endpoints. A container plug-in's only: a declarative plug-in has no handler to do an action's work."
2812
+ "description": "What a reader may run on an item: a container plug-in's write endpoints, which its handlers answer, or a declarative plug-in's calls and changes to its values, which Initiative makes."
2813
+ },
2814
+ "settings": {
2815
+ "type": "array",
2816
+ "maxItems": "settings",
2817
+ "items": {
2818
+ "ref": "setting"
2819
+ },
2820
+ "description": "Values the community's admins set on the install, which the plug-in's expressions and its parts' text read. At most {settings}."
2821
+ },
2822
+ "help": {
2823
+ "type": "object",
2824
+ "minProperties": 1,
2825
+ "maxProperties": "locales",
2826
+ "propertyNames": {
2827
+ "type": "string",
2828
+ "maxLength": "localeTagLength",
2829
+ "patternFrom": "localeTag",
2830
+ "patternForm": "plus"
2831
+ },
2832
+ "additionalProperties": {
2833
+ "type": "string",
2834
+ "minLength": 1,
2835
+ "maxLength": "helpLength"
2836
+ },
2837
+ "description": "Help with the plug-in, keyed by language tag: markdown of at most {helpLength} characters in each language. Initiative shows it behind a '?' on the headers of the plug-in's parts and on its settings, in the reader's language, or failing that in any."
2347
2838
  }
2348
2839
  }
2349
2840
  }