@ekka-ai/shelves 0.2.2
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/CHANGELOG.md +44 -0
- package/LICENSE +8 -0
- package/README.md +70 -0
- package/dist/check.d.ts +26 -0
- package/dist/check.js +151 -0
- package/dist/cli.d.ts +2 -0
- package/dist/cli.js +124 -0
- package/dist/contracts/PINNED.json +8 -0
- package/dist/contracts/gate/attested/shelf.v1.json +77 -0
- package/dist/contracts/shelves/protocol-v1.schema.json +595 -0
- package/dist/contracts/shelves/registry.json +129 -0
- package/dist/generate.d.ts +6 -0
- package/dist/generate.js +44 -0
- package/dist/index.d.ts +12 -0
- package/dist/index.js +22 -0
- package/dist/plugin.d.ts +43 -0
- package/dist/plugin.js +125 -0
- package/dist/protocol.d.ts +131 -0
- package/dist/protocol.js +166 -0
- package/dist/registry.d.ts +46 -0
- package/dist/registry.js +131 -0
- package/dist/scaffold.d.ts +20 -0
- package/dist/scaffold.js +200 -0
- package/dist/shelf.d.ts +85 -0
- package/dist/shelf.js +71 -0
- package/package.json +56 -0
|
@@ -0,0 +1,595 @@
|
|
|
1
|
+
{
|
|
2
|
+
"$schema": "http://json-schema.org/draft-07/schema#",
|
|
3
|
+
"$id": "https://schemas.ekka.ai/shelves/protocol-v1.schema.json",
|
|
4
|
+
"title": "ShelfProtocolV1",
|
|
5
|
+
"description": "The shelf protocol v1 between an EKKA Enclave and a Business API (E1 v3.2, section 2; ekka-ai/.github#674). Three routes, mounted by the provider's `@ekka/shelves` plugin and nothing else: `GET /ekka/shelves/v1/ping` (public, answers `ping` below), `GET /ekka/shelves/v1/manifest` (bearer-authenticated, answers `manifest`), `POST /ekka/shelves/v1/invoke` (bearer-authenticated, takes `request`, answers `response`). The Enclave never learns another route, and a plan never supplies a URL, method or header. The bearer is the per-shelf principal key the provider issued; it is the provider's transport auth, not EKKA's authority. This file declares shapes; which definition a route uses is stated in each definition.",
|
|
6
|
+
"definitions": {
|
|
7
|
+
"shelf_id": {
|
|
8
|
+
"type": "string",
|
|
9
|
+
"pattern": "^[a-z][a-z0-9_]{0,31}(\\.[a-z][a-z0-9_]{0,31})+$",
|
|
10
|
+
"maxLength": 200,
|
|
11
|
+
"description": "A shelf id: lowercase dotted segments. A predefined id (shelves/registry.json) has exactly two segments; a company's private shelf may be deeper and may never equal a predefined id (checked at import)."
|
|
12
|
+
},
|
|
13
|
+
"verb": {
|
|
14
|
+
"type": "string",
|
|
15
|
+
"enum": [
|
|
16
|
+
"read",
|
|
17
|
+
"list"
|
|
18
|
+
],
|
|
19
|
+
"description": "v1 verbs. `write`, `update`, `delete` and `send` are reserved and refused."
|
|
20
|
+
},
|
|
21
|
+
"scalar": {
|
|
22
|
+
"type": [
|
|
23
|
+
"string",
|
|
24
|
+
"integer",
|
|
25
|
+
"boolean"
|
|
26
|
+
],
|
|
27
|
+
"description": "No floats: a lookup value is a string, an integer or a boolean."
|
|
28
|
+
},
|
|
29
|
+
"by": {
|
|
30
|
+
"type": "object",
|
|
31
|
+
"maxProperties": 16,
|
|
32
|
+
"propertyNames": {
|
|
33
|
+
"pattern": "^[a-z][a-z0-9_]{0,31}$"
|
|
34
|
+
},
|
|
35
|
+
"additionalProperties": {
|
|
36
|
+
"$ref": "#/definitions/scalar"
|
|
37
|
+
},
|
|
38
|
+
"description": "Equality-only lookup. For `read` it names EXACTLY the shelf's unique key set; for `list` a subset of its declared keys. The provider refuses an undeclared key with `unknown_key`."
|
|
39
|
+
},
|
|
40
|
+
"page": {
|
|
41
|
+
"type": "object",
|
|
42
|
+
"properties": {
|
|
43
|
+
"limit": {
|
|
44
|
+
"type": "integer",
|
|
45
|
+
"minimum": 1,
|
|
46
|
+
"maximum": 1000
|
|
47
|
+
},
|
|
48
|
+
"cursor": {
|
|
49
|
+
"type": [
|
|
50
|
+
"string",
|
|
51
|
+
"null"
|
|
52
|
+
],
|
|
53
|
+
"maxLength": 1024
|
|
54
|
+
}
|
|
55
|
+
},
|
|
56
|
+
"required": [
|
|
57
|
+
"limit"
|
|
58
|
+
],
|
|
59
|
+
"additionalProperties": false,
|
|
60
|
+
"description": "`list` only. The provider returns at most min(limit, the shelf's page_cap) records."
|
|
61
|
+
},
|
|
62
|
+
"record": {
|
|
63
|
+
"type": "object",
|
|
64
|
+
"maxProperties": 64,
|
|
65
|
+
"description": "One record in the shelf's field set. Its exact shape is checked by the Enclave against the interface pinned for the run (SHELF_RECORD_INVALID), not by this schema."
|
|
66
|
+
},
|
|
67
|
+
"invocation_payload": {
|
|
68
|
+
"type": "object",
|
|
69
|
+
"properties": {
|
|
70
|
+
"tenant": {
|
|
71
|
+
"type": "string",
|
|
72
|
+
"minLength": 1,
|
|
73
|
+
"maxLength": 64
|
|
74
|
+
},
|
|
75
|
+
"agent": {
|
|
76
|
+
"type": "string",
|
|
77
|
+
"minLength": 1,
|
|
78
|
+
"maxLength": 128
|
|
79
|
+
},
|
|
80
|
+
"run": {
|
|
81
|
+
"type": "string",
|
|
82
|
+
"minLength": 1,
|
|
83
|
+
"maxLength": 64
|
|
84
|
+
},
|
|
85
|
+
"step": {
|
|
86
|
+
"type": "string",
|
|
87
|
+
"minLength": 1,
|
|
88
|
+
"maxLength": 128
|
|
89
|
+
},
|
|
90
|
+
"shelf": {
|
|
91
|
+
"$ref": "#/definitions/shelf_id"
|
|
92
|
+
},
|
|
93
|
+
"verb": {
|
|
94
|
+
"$ref": "#/definitions/verb"
|
|
95
|
+
},
|
|
96
|
+
"iat": {
|
|
97
|
+
"type": "integer",
|
|
98
|
+
"minimum": 0,
|
|
99
|
+
"description": "Issued at, whole seconds since the Unix epoch."
|
|
100
|
+
},
|
|
101
|
+
"exp": {
|
|
102
|
+
"type": "integer",
|
|
103
|
+
"minimum": 0,
|
|
104
|
+
"description": "Expiry, whole seconds; exactly iat + 60."
|
|
105
|
+
}
|
|
106
|
+
},
|
|
107
|
+
"required": [
|
|
108
|
+
"tenant",
|
|
109
|
+
"agent",
|
|
110
|
+
"run",
|
|
111
|
+
"step",
|
|
112
|
+
"shelf",
|
|
113
|
+
"verb",
|
|
114
|
+
"iat",
|
|
115
|
+
"exp"
|
|
116
|
+
],
|
|
117
|
+
"additionalProperties": false,
|
|
118
|
+
"description": "What the Enclave asserts about one invocation. No person identity in v1: an automated run has none."
|
|
119
|
+
},
|
|
120
|
+
"invocation_assertion": {
|
|
121
|
+
"type": "object",
|
|
122
|
+
"properties": {
|
|
123
|
+
"alg": {
|
|
124
|
+
"type": "string",
|
|
125
|
+
"const": "ed25519"
|
|
126
|
+
},
|
|
127
|
+
"key_id": {
|
|
128
|
+
"type": "string",
|
|
129
|
+
"minLength": 1,
|
|
130
|
+
"maxLength": 128,
|
|
131
|
+
"description": "The Enclave node key's id, the same key that signs its receipts; its public key is published by govern and fetched once at import."
|
|
132
|
+
},
|
|
133
|
+
"payload_b64": {
|
|
134
|
+
"type": "string",
|
|
135
|
+
"minLength": 1,
|
|
136
|
+
"maxLength": 4096,
|
|
137
|
+
"pattern": "^[A-Za-z0-9+/]+={0,2}$",
|
|
138
|
+
"description": "Standard base64 of the canonical JSON of `invocation_payload`."
|
|
139
|
+
},
|
|
140
|
+
"sig_b64": {
|
|
141
|
+
"type": "string",
|
|
142
|
+
"minLength": 1,
|
|
143
|
+
"maxLength": 256,
|
|
144
|
+
"pattern": "^[A-Za-z0-9+/]+={0,2}$",
|
|
145
|
+
"description": "Standard base64 of the ed25519 signature over the SIGNED BYTES defined in this definition's description."
|
|
146
|
+
}
|
|
147
|
+
},
|
|
148
|
+
"required": [
|
|
149
|
+
"alg",
|
|
150
|
+
"key_id",
|
|
151
|
+
"payload_b64",
|
|
152
|
+
"sig_b64"
|
|
153
|
+
],
|
|
154
|
+
"additionalProperties": false,
|
|
155
|
+
"description": "The signed invocation, carried as `request.auth`. DOMAIN-SEPARATED SIGNING, so these bytes can never be replayed as any other EKKA signature: SIGNED BYTES = the ASCII prefix `ekka.shelf.invocation.v1` followed by one newline (0x0A), followed by the canonical JSON of the payload. CANONICAL JSON is SECURITY.CANONICALIZE.V1: UTF-8, object keys sorted by code point at every level, no insignificant whitespace, integers only (the payload has no floats), strings escaped per RFC 8785. `payload_b64` carries exactly those canonical bytes (without the prefix), so a verifier: (1) base64-decodes `payload_b64`; (2) prepends `ekka.shelf.invocation.v1\\n`; (3) verifies `sig_b64` over the result with the public key for `key_id`; (4) parses the payload and checks `shelf` and `verb` equal the request's, `exp == iat + 60`, and now is within [iat - 5, exp]; it NEVER re-canonicalizes. v1 providers MAY skip verification; the field is always present so v2 row policy needs no protocol change."
|
|
156
|
+
},
|
|
157
|
+
"request": {
|
|
158
|
+
"type": "object",
|
|
159
|
+
"properties": {
|
|
160
|
+
"protocol": {
|
|
161
|
+
"const": 1
|
|
162
|
+
},
|
|
163
|
+
"request_id": {
|
|
164
|
+
"type": "string",
|
|
165
|
+
"minLength": 1,
|
|
166
|
+
"maxLength": 128
|
|
167
|
+
},
|
|
168
|
+
"shelf": {
|
|
169
|
+
"$ref": "#/definitions/shelf_id"
|
|
170
|
+
},
|
|
171
|
+
"interface_major": {
|
|
172
|
+
"type": "integer",
|
|
173
|
+
"minimum": 1
|
|
174
|
+
},
|
|
175
|
+
"verb": {
|
|
176
|
+
"$ref": "#/definitions/verb"
|
|
177
|
+
},
|
|
178
|
+
"by": {
|
|
179
|
+
"$ref": "#/definitions/by"
|
|
180
|
+
},
|
|
181
|
+
"page": {
|
|
182
|
+
"$ref": "#/definitions/page"
|
|
183
|
+
},
|
|
184
|
+
"auth": {
|
|
185
|
+
"$ref": "#/definitions/invocation_assertion"
|
|
186
|
+
}
|
|
187
|
+
},
|
|
188
|
+
"required": [
|
|
189
|
+
"protocol",
|
|
190
|
+
"request_id",
|
|
191
|
+
"shelf",
|
|
192
|
+
"interface_major",
|
|
193
|
+
"verb",
|
|
194
|
+
"by",
|
|
195
|
+
"auth"
|
|
196
|
+
],
|
|
197
|
+
"additionalProperties": false,
|
|
198
|
+
"description": "Body of `POST /ekka/shelves/v1/invoke`. `page` is for `list` only; a `read` carrying one is refused as `shape`."
|
|
199
|
+
},
|
|
200
|
+
"refusal": {
|
|
201
|
+
"type": "object",
|
|
202
|
+
"properties": {
|
|
203
|
+
"code": {
|
|
204
|
+
"type": "string",
|
|
205
|
+
"enum": [
|
|
206
|
+
"unknown_key",
|
|
207
|
+
"forbidden",
|
|
208
|
+
"not_implemented",
|
|
209
|
+
"shape",
|
|
210
|
+
"provider_error"
|
|
211
|
+
]
|
|
212
|
+
},
|
|
213
|
+
"message": {
|
|
214
|
+
"type": "string",
|
|
215
|
+
"maxLength": 500,
|
|
216
|
+
"description": "For the operator. Never a record value."
|
|
217
|
+
}
|
|
218
|
+
},
|
|
219
|
+
"required": [
|
|
220
|
+
"code",
|
|
221
|
+
"message"
|
|
222
|
+
],
|
|
223
|
+
"additionalProperties": false,
|
|
224
|
+
"description": "A typed refusal. `unknown_key`: `by` names a key the shelf does not declare. `forbidden`: the presenting principal may not use this shelf or verb. `not_implemented`: the verb is not served. `shape`: the request is malformed. `provider_error`: the provider failed."
|
|
225
|
+
},
|
|
226
|
+
"read_result": {
|
|
227
|
+
"oneOf": [
|
|
228
|
+
{
|
|
229
|
+
"type": "object",
|
|
230
|
+
"properties": {
|
|
231
|
+
"record": {
|
|
232
|
+
"$ref": "#/definitions/record"
|
|
233
|
+
}
|
|
234
|
+
},
|
|
235
|
+
"required": [
|
|
236
|
+
"record"
|
|
237
|
+
],
|
|
238
|
+
"additionalProperties": false
|
|
239
|
+
},
|
|
240
|
+
{
|
|
241
|
+
"type": "object",
|
|
242
|
+
"properties": {
|
|
243
|
+
"not_found": {
|
|
244
|
+
"const": true
|
|
245
|
+
}
|
|
246
|
+
},
|
|
247
|
+
"required": [
|
|
248
|
+
"not_found"
|
|
249
|
+
],
|
|
250
|
+
"additionalProperties": false
|
|
251
|
+
}
|
|
252
|
+
]
|
|
253
|
+
},
|
|
254
|
+
"list_result": {
|
|
255
|
+
"type": "object",
|
|
256
|
+
"properties": {
|
|
257
|
+
"records": {
|
|
258
|
+
"type": "array",
|
|
259
|
+
"maxItems": 1000,
|
|
260
|
+
"items": {
|
|
261
|
+
"$ref": "#/definitions/record"
|
|
262
|
+
}
|
|
263
|
+
},
|
|
264
|
+
"next_cursor": {
|
|
265
|
+
"type": [
|
|
266
|
+
"string",
|
|
267
|
+
"null"
|
|
268
|
+
],
|
|
269
|
+
"maxLength": 1024
|
|
270
|
+
}
|
|
271
|
+
},
|
|
272
|
+
"required": [
|
|
273
|
+
"records",
|
|
274
|
+
"next_cursor"
|
|
275
|
+
],
|
|
276
|
+
"additionalProperties": false
|
|
277
|
+
},
|
|
278
|
+
"response": {
|
|
279
|
+
"type": "object",
|
|
280
|
+
"properties": {
|
|
281
|
+
"protocol": {
|
|
282
|
+
"const": 1
|
|
283
|
+
},
|
|
284
|
+
"request_id": {
|
|
285
|
+
"type": "string",
|
|
286
|
+
"minLength": 1,
|
|
287
|
+
"maxLength": 128
|
|
288
|
+
},
|
|
289
|
+
"offer_version": {
|
|
290
|
+
"type": "string",
|
|
291
|
+
"minLength": 1,
|
|
292
|
+
"maxLength": 64
|
|
293
|
+
},
|
|
294
|
+
"shelf": {
|
|
295
|
+
"$ref": "#/definitions/shelf_id"
|
|
296
|
+
},
|
|
297
|
+
"verb": {
|
|
298
|
+
"$ref": "#/definitions/verb"
|
|
299
|
+
},
|
|
300
|
+
"result": {
|
|
301
|
+
"oneOf": [
|
|
302
|
+
{
|
|
303
|
+
"$ref": "#/definitions/read_result"
|
|
304
|
+
},
|
|
305
|
+
{
|
|
306
|
+
"$ref": "#/definitions/list_result"
|
|
307
|
+
}
|
|
308
|
+
]
|
|
309
|
+
},
|
|
310
|
+
"refusal": {
|
|
311
|
+
"$ref": "#/definitions/refusal"
|
|
312
|
+
}
|
|
313
|
+
},
|
|
314
|
+
"required": [
|
|
315
|
+
"protocol",
|
|
316
|
+
"request_id",
|
|
317
|
+
"offer_version",
|
|
318
|
+
"shelf",
|
|
319
|
+
"verb"
|
|
320
|
+
],
|
|
321
|
+
"oneOf": [
|
|
322
|
+
{
|
|
323
|
+
"required": [
|
|
324
|
+
"result"
|
|
325
|
+
]
|
|
326
|
+
},
|
|
327
|
+
{
|
|
328
|
+
"required": [
|
|
329
|
+
"refusal"
|
|
330
|
+
]
|
|
331
|
+
}
|
|
332
|
+
],
|
|
333
|
+
"additionalProperties": false,
|
|
334
|
+
"description": "Answer of `invoke`: exactly one of `result` or `refusal`. The Enclave also checks `request_id`, `shelf` and `verb` echo the request and `offer_version` equals the version pinned for the run."
|
|
335
|
+
},
|
|
336
|
+
"private_shape": {
|
|
337
|
+
"type": "object",
|
|
338
|
+
"properties": {
|
|
339
|
+
"keys": {
|
|
340
|
+
"type": "array",
|
|
341
|
+
"minItems": 1,
|
|
342
|
+
"maxItems": 16,
|
|
343
|
+
"items": {
|
|
344
|
+
"type": "object",
|
|
345
|
+
"properties": {
|
|
346
|
+
"name": {
|
|
347
|
+
"type": "string",
|
|
348
|
+
"pattern": "^[a-z][a-z0-9_]{0,31}$"
|
|
349
|
+
},
|
|
350
|
+
"type": {
|
|
351
|
+
"type": "string",
|
|
352
|
+
"enum": [
|
|
353
|
+
"string",
|
|
354
|
+
"integer",
|
|
355
|
+
"boolean",
|
|
356
|
+
"month",
|
|
357
|
+
"date",
|
|
358
|
+
"currency_code",
|
|
359
|
+
"money_minor"
|
|
360
|
+
]
|
|
361
|
+
},
|
|
362
|
+
"unique": {
|
|
363
|
+
"type": "boolean"
|
|
364
|
+
}
|
|
365
|
+
},
|
|
366
|
+
"required": [
|
|
367
|
+
"name",
|
|
368
|
+
"type",
|
|
369
|
+
"unique"
|
|
370
|
+
],
|
|
371
|
+
"additionalProperties": false
|
|
372
|
+
}
|
|
373
|
+
},
|
|
374
|
+
"fields": {
|
|
375
|
+
"type": "array",
|
|
376
|
+
"minItems": 1,
|
|
377
|
+
"maxItems": 64,
|
|
378
|
+
"items": {
|
|
379
|
+
"type": "object",
|
|
380
|
+
"properties": {
|
|
381
|
+
"name": {
|
|
382
|
+
"type": "string",
|
|
383
|
+
"pattern": "^[a-z][a-z0-9_]{0,31}$"
|
|
384
|
+
},
|
|
385
|
+
"type": {
|
|
386
|
+
"type": "string",
|
|
387
|
+
"enum": [
|
|
388
|
+
"string",
|
|
389
|
+
"integer",
|
|
390
|
+
"boolean",
|
|
391
|
+
"month",
|
|
392
|
+
"date",
|
|
393
|
+
"currency_code",
|
|
394
|
+
"money_minor"
|
|
395
|
+
]
|
|
396
|
+
},
|
|
397
|
+
"required": {
|
|
398
|
+
"type": "boolean"
|
|
399
|
+
}
|
|
400
|
+
},
|
|
401
|
+
"required": [
|
|
402
|
+
"name",
|
|
403
|
+
"type",
|
|
404
|
+
"required"
|
|
405
|
+
],
|
|
406
|
+
"additionalProperties": false
|
|
407
|
+
}
|
|
408
|
+
},
|
|
409
|
+
"page_cap": {
|
|
410
|
+
"type": "integer",
|
|
411
|
+
"minimum": 1,
|
|
412
|
+
"maximum": 1000
|
|
413
|
+
}
|
|
414
|
+
},
|
|
415
|
+
"required": [
|
|
416
|
+
"keys",
|
|
417
|
+
"fields",
|
|
418
|
+
"page_cap"
|
|
419
|
+
],
|
|
420
|
+
"additionalProperties": false,
|
|
421
|
+
"description": "A private shelf's declared shape: the same parts a predefined shelf has in shelves/registry.json."
|
|
422
|
+
},
|
|
423
|
+
"manifest_shelf": {
|
|
424
|
+
"type": "object",
|
|
425
|
+
"properties": {
|
|
426
|
+
"id": {
|
|
427
|
+
"$ref": "#/definitions/shelf_id"
|
|
428
|
+
},
|
|
429
|
+
"origin": {
|
|
430
|
+
"type": "string",
|
|
431
|
+
"enum": [
|
|
432
|
+
"predefined",
|
|
433
|
+
"private"
|
|
434
|
+
]
|
|
435
|
+
},
|
|
436
|
+
"interface_major": {
|
|
437
|
+
"type": "integer",
|
|
438
|
+
"minimum": 1,
|
|
439
|
+
"description": "Predefined shelves: the registry major served."
|
|
440
|
+
},
|
|
441
|
+
"shape": {
|
|
442
|
+
"$ref": "#/definitions/private_shape"
|
|
443
|
+
},
|
|
444
|
+
"verbs": {
|
|
445
|
+
"type": "array",
|
|
446
|
+
"minItems": 1,
|
|
447
|
+
"uniqueItems": true,
|
|
448
|
+
"items": {
|
|
449
|
+
"$ref": "#/definitions/verb"
|
|
450
|
+
}
|
|
451
|
+
},
|
|
452
|
+
"required_role": {
|
|
453
|
+
"type": "object",
|
|
454
|
+
"propertyNames": {
|
|
455
|
+
"enum": [
|
|
456
|
+
"read",
|
|
457
|
+
"list"
|
|
458
|
+
]
|
|
459
|
+
},
|
|
460
|
+
"additionalProperties": {
|
|
461
|
+
"type": "string",
|
|
462
|
+
"pattern": "^[a-z][a-z0-9_]{0,31}$"
|
|
463
|
+
},
|
|
464
|
+
"description": "The provider role required per verb, imported as named; the org maps it to its own roles."
|
|
465
|
+
},
|
|
466
|
+
"probe_fixture": {
|
|
467
|
+
"type": "object",
|
|
468
|
+
"properties": {
|
|
469
|
+
"synthetic": {
|
|
470
|
+
"const": true
|
|
471
|
+
},
|
|
472
|
+
"read": {
|
|
473
|
+
"$ref": "#/definitions/by"
|
|
474
|
+
},
|
|
475
|
+
"list": {
|
|
476
|
+
"$ref": "#/definitions/by"
|
|
477
|
+
}
|
|
478
|
+
},
|
|
479
|
+
"required": [
|
|
480
|
+
"synthetic"
|
|
481
|
+
],
|
|
482
|
+
"additionalProperties": false,
|
|
483
|
+
"description": "Synthetic lookups the import probe invokes, marked so no real person's data is ever a fixture."
|
|
484
|
+
}
|
|
485
|
+
},
|
|
486
|
+
"required": [
|
|
487
|
+
"id",
|
|
488
|
+
"origin",
|
|
489
|
+
"verbs",
|
|
490
|
+
"required_role",
|
|
491
|
+
"probe_fixture"
|
|
492
|
+
],
|
|
493
|
+
"additionalProperties": false,
|
|
494
|
+
"allOf": [
|
|
495
|
+
{
|
|
496
|
+
"if": {
|
|
497
|
+
"properties": {
|
|
498
|
+
"origin": {
|
|
499
|
+
"const": "predefined"
|
|
500
|
+
}
|
|
501
|
+
}
|
|
502
|
+
},
|
|
503
|
+
"then": {
|
|
504
|
+
"required": [
|
|
505
|
+
"interface_major"
|
|
506
|
+
],
|
|
507
|
+
"not": {
|
|
508
|
+
"required": [
|
|
509
|
+
"shape"
|
|
510
|
+
]
|
|
511
|
+
}
|
|
512
|
+
}
|
|
513
|
+
},
|
|
514
|
+
{
|
|
515
|
+
"if": {
|
|
516
|
+
"properties": {
|
|
517
|
+
"origin": {
|
|
518
|
+
"const": "private"
|
|
519
|
+
}
|
|
520
|
+
}
|
|
521
|
+
},
|
|
522
|
+
"then": {
|
|
523
|
+
"required": [
|
|
524
|
+
"shape"
|
|
525
|
+
],
|
|
526
|
+
"not": {
|
|
527
|
+
"required": [
|
|
528
|
+
"interface_major"
|
|
529
|
+
]
|
|
530
|
+
}
|
|
531
|
+
}
|
|
532
|
+
}
|
|
533
|
+
]
|
|
534
|
+
},
|
|
535
|
+
"manifest": {
|
|
536
|
+
"type": "object",
|
|
537
|
+
"properties": {
|
|
538
|
+
"protocol": {
|
|
539
|
+
"const": 1
|
|
540
|
+
},
|
|
541
|
+
"provider_id": {
|
|
542
|
+
"type": "string",
|
|
543
|
+
"pattern": "^[a-z][a-z0-9-]{0,62}$"
|
|
544
|
+
},
|
|
545
|
+
"offer_version": {
|
|
546
|
+
"type": "string",
|
|
547
|
+
"minLength": 1,
|
|
548
|
+
"maxLength": 64
|
|
549
|
+
},
|
|
550
|
+
"digest": {
|
|
551
|
+
"type": "string",
|
|
552
|
+
"pattern": "^sha256:[a-f0-9]{64}$",
|
|
553
|
+
"description": "Over the offer: a changed digest under the same version is refused at re-import."
|
|
554
|
+
},
|
|
555
|
+
"principal": {
|
|
556
|
+
"type": "string",
|
|
557
|
+
"minLength": 1,
|
|
558
|
+
"maxLength": 128,
|
|
559
|
+
"description": "The principal the presenting bearer belongs to. PER-PRINCIPAL LISTING: `shelves` names only the shelves this principal serves, never the provider's full list, because the shelf names themselves can be a client list."
|
|
560
|
+
},
|
|
561
|
+
"shelves": {
|
|
562
|
+
"type": "array",
|
|
563
|
+
"minItems": 1,
|
|
564
|
+
"maxItems": 64,
|
|
565
|
+
"items": {
|
|
566
|
+
"$ref": "#/definitions/manifest_shelf"
|
|
567
|
+
}
|
|
568
|
+
}
|
|
569
|
+
},
|
|
570
|
+
"required": [
|
|
571
|
+
"protocol",
|
|
572
|
+
"provider_id",
|
|
573
|
+
"offer_version",
|
|
574
|
+
"digest",
|
|
575
|
+
"principal",
|
|
576
|
+
"shelves"
|
|
577
|
+
],
|
|
578
|
+
"additionalProperties": false,
|
|
579
|
+
"description": "Answer of `GET /ekka/shelves/v1/manifest`, bearer-authenticated."
|
|
580
|
+
},
|
|
581
|
+
"ping": {
|
|
582
|
+
"type": "object",
|
|
583
|
+
"properties": {
|
|
584
|
+
"protocol": {
|
|
585
|
+
"const": 1
|
|
586
|
+
}
|
|
587
|
+
},
|
|
588
|
+
"required": [
|
|
589
|
+
"protocol"
|
|
590
|
+
],
|
|
591
|
+
"additionalProperties": false,
|
|
592
|
+
"description": "Answer of the one public route, `GET /ekka/shelves/v1/ping`: the protocol version and nothing else, no names."
|
|
593
|
+
}
|
|
594
|
+
}
|
|
595
|
+
}
|