rasler 0.1.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/LICENSE +180 -0
- package/README.md +140 -0
- package/openapi.json +859 -0
- package/package.json +68 -0
- package/src/config.js +81 -0
- package/src/crypto/cid.js +49 -0
- package/src/index.js +45 -0
- package/src/masl/document.js +148 -0
- package/src/middleware/auth.js +11 -0
- package/src/middleware/cors.js +31 -0
- package/src/routes/mountPoints.js +86 -0
- package/src/routes/operator.js +944 -0
- package/src/routes/rasl.js +139 -0
- package/src/server.js +83 -0
- package/src/static.js +168 -0
- package/src/storage/db.js +133 -0
- package/src/storage/files.js +47 -0
- package/src/storage/store.js +171 -0
- package/src/util/env.js +32 -0
- package/src/util/loadRaslerConfig.js +14 -0
- package/src/util/mime.js +29 -0
- package/src/util/normalizeMountPath.js +12 -0
- package/src/util/parseJsonConfig.js +57 -0
- package/src/util/parseSize.js +16 -0
- package/src/watcher.js +42 -0
package/openapi.json
ADDED
|
@@ -0,0 +1,859 @@
|
|
|
1
|
+
{
|
|
2
|
+
"openapi": "3.0.3",
|
|
3
|
+
"info": {
|
|
4
|
+
"title": "RASL Node Operator API",
|
|
5
|
+
"version": "0.1.0",
|
|
6
|
+
"description": "HTTP API for managing a RASL node: uploading and pinning content, inspecting storage, and monitoring node status. All endpoints require the `x-rasl-operator-secret` header."
|
|
7
|
+
},
|
|
8
|
+
"servers": [
|
|
9
|
+
{
|
|
10
|
+
"url": "http://localhost:3000",
|
|
11
|
+
"description": "Local node"
|
|
12
|
+
}
|
|
13
|
+
],
|
|
14
|
+
"components": {
|
|
15
|
+
"securitySchemes": {
|
|
16
|
+
"operatorSecret": {
|
|
17
|
+
"type": "apiKey",
|
|
18
|
+
"in": "header",
|
|
19
|
+
"name": "x-rasl-operator-secret",
|
|
20
|
+
"description": "Pre-shared operator secret (API_SECRET env var)"
|
|
21
|
+
}
|
|
22
|
+
},
|
|
23
|
+
"schemas": {
|
|
24
|
+
"ContentItem": {
|
|
25
|
+
"type": "object",
|
|
26
|
+
"properties": {
|
|
27
|
+
"cid": {
|
|
28
|
+
"type": "string",
|
|
29
|
+
"example": "bafkreid7qoywk7hv5udpjlmxqmr4of3d5jx4k5r2kvfm4vs3l4dz3t7ku"
|
|
30
|
+
},
|
|
31
|
+
"maslCid": {
|
|
32
|
+
"type": "string",
|
|
33
|
+
"nullable": true,
|
|
34
|
+
"example": "bafyreid7qoywk7hv5udpjlmxqmr4of3d5jx4k5r2kvfm4vs3l4dz3t7ku"
|
|
35
|
+
},
|
|
36
|
+
"size": {
|
|
37
|
+
"type": "integer",
|
|
38
|
+
"example": 4096
|
|
39
|
+
},
|
|
40
|
+
"pinned": {
|
|
41
|
+
"type": "boolean"
|
|
42
|
+
},
|
|
43
|
+
"lastRequested": {
|
|
44
|
+
"type": "integer",
|
|
45
|
+
"nullable": true,
|
|
46
|
+
"description": "Unix timestamp in milliseconds"
|
|
47
|
+
}
|
|
48
|
+
}
|
|
49
|
+
},
|
|
50
|
+
"UploadResult": {
|
|
51
|
+
"type": "object",
|
|
52
|
+
"properties": {
|
|
53
|
+
"filename": {
|
|
54
|
+
"type": "string"
|
|
55
|
+
},
|
|
56
|
+
"maslCid": {
|
|
57
|
+
"type": "string"
|
|
58
|
+
}
|
|
59
|
+
}
|
|
60
|
+
},
|
|
61
|
+
"Error": {
|
|
62
|
+
"type": "object",
|
|
63
|
+
"properties": {
|
|
64
|
+
"error": {
|
|
65
|
+
"type": "string"
|
|
66
|
+
}
|
|
67
|
+
}
|
|
68
|
+
}
|
|
69
|
+
}
|
|
70
|
+
},
|
|
71
|
+
"security": [
|
|
72
|
+
{
|
|
73
|
+
"operatorSecret": []
|
|
74
|
+
}
|
|
75
|
+
],
|
|
76
|
+
"tags": [
|
|
77
|
+
{
|
|
78
|
+
"name": "Content",
|
|
79
|
+
"description": "Upload, pin, and manage locally held content"
|
|
80
|
+
},
|
|
81
|
+
{
|
|
82
|
+
"name": "Node",
|
|
83
|
+
"description": "Node status"
|
|
84
|
+
}
|
|
85
|
+
],
|
|
86
|
+
"paths": {
|
|
87
|
+
"/upload": {
|
|
88
|
+
"post": {
|
|
89
|
+
"tags": [
|
|
90
|
+
"Content"
|
|
91
|
+
],
|
|
92
|
+
"summary": "Upload one or more files",
|
|
93
|
+
"description": "Each file is stored unpinned. Files are either a raw data file (any content type) or a CARv1 bundle (detected by content-type `application/vnd.ipld.car` or a `.car` extension). A raw file gets a single-mode MASL wrapper generated automatically.\n",
|
|
94
|
+
"requestBody": {
|
|
95
|
+
"required": true,
|
|
96
|
+
"content": {
|
|
97
|
+
"multipart/form-data": {
|
|
98
|
+
"schema": {
|
|
99
|
+
"type": "object",
|
|
100
|
+
"required": [
|
|
101
|
+
"files"
|
|
102
|
+
],
|
|
103
|
+
"properties": {
|
|
104
|
+
"files": {
|
|
105
|
+
"type": "array",
|
|
106
|
+
"items": {
|
|
107
|
+
"type": "string",
|
|
108
|
+
"format": "binary"
|
|
109
|
+
}
|
|
110
|
+
}
|
|
111
|
+
}
|
|
112
|
+
}
|
|
113
|
+
}
|
|
114
|
+
}
|
|
115
|
+
},
|
|
116
|
+
"responses": {
|
|
117
|
+
"200": {
|
|
118
|
+
"description": "All files stored successfully",
|
|
119
|
+
"content": {
|
|
120
|
+
"application/json": {
|
|
121
|
+
"schema": {
|
|
122
|
+
"type": "object",
|
|
123
|
+
"properties": {
|
|
124
|
+
"uploads": {
|
|
125
|
+
"type": "array",
|
|
126
|
+
"items": {
|
|
127
|
+
"$ref": "#/components/schemas/UploadResult"
|
|
128
|
+
}
|
|
129
|
+
}
|
|
130
|
+
}
|
|
131
|
+
}
|
|
132
|
+
}
|
|
133
|
+
}
|
|
134
|
+
},
|
|
135
|
+
"400": {
|
|
136
|
+
"description": "Invalid input (bad CAR, CID mismatch, no files)",
|
|
137
|
+
"content": {
|
|
138
|
+
"application/json": {
|
|
139
|
+
"schema": {
|
|
140
|
+
"$ref": "#/components/schemas/Error"
|
|
141
|
+
}
|
|
142
|
+
}
|
|
143
|
+
}
|
|
144
|
+
},
|
|
145
|
+
"401": {
|
|
146
|
+
"description": "Missing or invalid operator secret"
|
|
147
|
+
},
|
|
148
|
+
"507": {
|
|
149
|
+
"description": "Insufficient storage",
|
|
150
|
+
"content": {
|
|
151
|
+
"application/json": {
|
|
152
|
+
"schema": {
|
|
153
|
+
"$ref": "#/components/schemas/Error"
|
|
154
|
+
}
|
|
155
|
+
}
|
|
156
|
+
}
|
|
157
|
+
}
|
|
158
|
+
}
|
|
159
|
+
}
|
|
160
|
+
},
|
|
161
|
+
"/pin": {
|
|
162
|
+
"post": {
|
|
163
|
+
"tags": [
|
|
164
|
+
"Content"
|
|
165
|
+
],
|
|
166
|
+
"summary": "Pin stored CIDs",
|
|
167
|
+
"description": "Marks CIDs as operator-pinned so they are never evicted. Pinning a MASL CID also pins all its linked data CIDs; pinning a data CID also pins its MASL wrapper.\n",
|
|
168
|
+
"requestBody": {
|
|
169
|
+
"required": true,
|
|
170
|
+
"content": {
|
|
171
|
+
"application/json": {
|
|
172
|
+
"schema": {
|
|
173
|
+
"type": "object",
|
|
174
|
+
"required": [
|
|
175
|
+
"cids"
|
|
176
|
+
],
|
|
177
|
+
"properties": {
|
|
178
|
+
"cids": {
|
|
179
|
+
"type": "array",
|
|
180
|
+
"items": {
|
|
181
|
+
"type": "string"
|
|
182
|
+
},
|
|
183
|
+
"example": [
|
|
184
|
+
"bafyreid7qoywk7hv5udpjlmxqmr4of3d5jx4k5r2kvfm4vs3l4dz3t7ku"
|
|
185
|
+
]
|
|
186
|
+
}
|
|
187
|
+
}
|
|
188
|
+
}
|
|
189
|
+
}
|
|
190
|
+
}
|
|
191
|
+
},
|
|
192
|
+
"responses": {
|
|
193
|
+
"200": {
|
|
194
|
+
"description": "CIDs pinned (includes cascade pins)",
|
|
195
|
+
"content": {
|
|
196
|
+
"application/json": {
|
|
197
|
+
"schema": {
|
|
198
|
+
"type": "object",
|
|
199
|
+
"properties": {
|
|
200
|
+
"pinned": {
|
|
201
|
+
"type": "array",
|
|
202
|
+
"items": {
|
|
203
|
+
"type": "string"
|
|
204
|
+
}
|
|
205
|
+
}
|
|
206
|
+
}
|
|
207
|
+
}
|
|
208
|
+
}
|
|
209
|
+
}
|
|
210
|
+
},
|
|
211
|
+
"400": {
|
|
212
|
+
"description": "cids missing or empty",
|
|
213
|
+
"content": {
|
|
214
|
+
"application/json": {
|
|
215
|
+
"schema": {
|
|
216
|
+
"$ref": "#/components/schemas/Error"
|
|
217
|
+
}
|
|
218
|
+
}
|
|
219
|
+
}
|
|
220
|
+
},
|
|
221
|
+
"401": {
|
|
222
|
+
"description": "Missing or invalid operator secret"
|
|
223
|
+
},
|
|
224
|
+
"404": {
|
|
225
|
+
"description": "One or more CIDs not held locally",
|
|
226
|
+
"content": {
|
|
227
|
+
"application/json": {
|
|
228
|
+
"schema": {
|
|
229
|
+
"$ref": "#/components/schemas/Error"
|
|
230
|
+
}
|
|
231
|
+
}
|
|
232
|
+
}
|
|
233
|
+
}
|
|
234
|
+
}
|
|
235
|
+
}
|
|
236
|
+
},
|
|
237
|
+
"/pin/{cid}": {
|
|
238
|
+
"delete": {
|
|
239
|
+
"tags": [
|
|
240
|
+
"Content"
|
|
241
|
+
],
|
|
242
|
+
"summary": "Unpin a CID",
|
|
243
|
+
"description": "Removes the operator pin from a CID, making it eligible for eviction. Unpinning a MASL CID also unpins its linked data CIDs; unpinning a data CID also unpins its MASL wrapper. Returns 200 even if the CID is not held.\n",
|
|
244
|
+
"parameters": [
|
|
245
|
+
{
|
|
246
|
+
"in": "path",
|
|
247
|
+
"name": "cid",
|
|
248
|
+
"required": true,
|
|
249
|
+
"schema": {
|
|
250
|
+
"type": "string"
|
|
251
|
+
}
|
|
252
|
+
}
|
|
253
|
+
],
|
|
254
|
+
"responses": {
|
|
255
|
+
"200": {
|
|
256
|
+
"description": "Unpinned (or not found)",
|
|
257
|
+
"content": {
|
|
258
|
+
"application/json": {
|
|
259
|
+
"schema": {
|
|
260
|
+
"type": "object",
|
|
261
|
+
"properties": {
|
|
262
|
+
"status": {
|
|
263
|
+
"type": "string",
|
|
264
|
+
"enum": [
|
|
265
|
+
"ok",
|
|
266
|
+
"not found"
|
|
267
|
+
]
|
|
268
|
+
}
|
|
269
|
+
}
|
|
270
|
+
}
|
|
271
|
+
}
|
|
272
|
+
}
|
|
273
|
+
},
|
|
274
|
+
"401": {
|
|
275
|
+
"description": "Missing or invalid operator secret"
|
|
276
|
+
}
|
|
277
|
+
}
|
|
278
|
+
}
|
|
279
|
+
},
|
|
280
|
+
"/content": {
|
|
281
|
+
"get": {
|
|
282
|
+
"tags": [
|
|
283
|
+
"Content"
|
|
284
|
+
],
|
|
285
|
+
"summary": "List locally held CIDs",
|
|
286
|
+
"description": "Cursor-based pagination over all CIDs held by this node, ordered by CID.",
|
|
287
|
+
"parameters": [
|
|
288
|
+
{
|
|
289
|
+
"in": "query",
|
|
290
|
+
"name": "limit",
|
|
291
|
+
"schema": {
|
|
292
|
+
"type": "integer",
|
|
293
|
+
"default": 50,
|
|
294
|
+
"minimum": 1,
|
|
295
|
+
"maximum": 200
|
|
296
|
+
},
|
|
297
|
+
"description": "Number of items per page"
|
|
298
|
+
},
|
|
299
|
+
{
|
|
300
|
+
"in": "query",
|
|
301
|
+
"name": "cursor",
|
|
302
|
+
"schema": {
|
|
303
|
+
"type": "string"
|
|
304
|
+
},
|
|
305
|
+
"description": "Exclusive lower-bound CID from the previous page's `nextCursor`"
|
|
306
|
+
}
|
|
307
|
+
],
|
|
308
|
+
"responses": {
|
|
309
|
+
"200": {
|
|
310
|
+
"description": "Page of content items",
|
|
311
|
+
"content": {
|
|
312
|
+
"application/json": {
|
|
313
|
+
"schema": {
|
|
314
|
+
"type": "object",
|
|
315
|
+
"properties": {
|
|
316
|
+
"total": {
|
|
317
|
+
"type": "integer",
|
|
318
|
+
"description": "Total number of CIDs held (across all pages)"
|
|
319
|
+
},
|
|
320
|
+
"items": {
|
|
321
|
+
"type": "array",
|
|
322
|
+
"items": {
|
|
323
|
+
"$ref": "#/components/schemas/ContentItem"
|
|
324
|
+
}
|
|
325
|
+
},
|
|
326
|
+
"nextCursor": {
|
|
327
|
+
"type": "string",
|
|
328
|
+
"nullable": true,
|
|
329
|
+
"description": "Pass as `cursor` to fetch the next page; null on the last page"
|
|
330
|
+
}
|
|
331
|
+
}
|
|
332
|
+
}
|
|
333
|
+
}
|
|
334
|
+
}
|
|
335
|
+
},
|
|
336
|
+
"401": {
|
|
337
|
+
"description": "Missing or invalid operator secret"
|
|
338
|
+
}
|
|
339
|
+
}
|
|
340
|
+
}
|
|
341
|
+
},
|
|
342
|
+
"/content/{cid}": {
|
|
343
|
+
"get": {
|
|
344
|
+
"tags": [
|
|
345
|
+
"Content"
|
|
346
|
+
],
|
|
347
|
+
"summary": "Get metadata for a single CID",
|
|
348
|
+
"parameters": [
|
|
349
|
+
{
|
|
350
|
+
"in": "path",
|
|
351
|
+
"name": "cid",
|
|
352
|
+
"required": true,
|
|
353
|
+
"schema": {
|
|
354
|
+
"type": "string"
|
|
355
|
+
}
|
|
356
|
+
}
|
|
357
|
+
],
|
|
358
|
+
"responses": {
|
|
359
|
+
"200": {
|
|
360
|
+
"description": "CID metadata",
|
|
361
|
+
"content": {
|
|
362
|
+
"application/json": {
|
|
363
|
+
"schema": {
|
|
364
|
+
"$ref": "#/components/schemas/ContentItem"
|
|
365
|
+
}
|
|
366
|
+
}
|
|
367
|
+
}
|
|
368
|
+
},
|
|
369
|
+
"401": {
|
|
370
|
+
"description": "Missing or invalid operator secret"
|
|
371
|
+
},
|
|
372
|
+
"404": {
|
|
373
|
+
"description": "CID not held locally",
|
|
374
|
+
"content": {
|
|
375
|
+
"application/json": {
|
|
376
|
+
"schema": {
|
|
377
|
+
"$ref": "#/components/schemas/Error"
|
|
378
|
+
}
|
|
379
|
+
}
|
|
380
|
+
}
|
|
381
|
+
}
|
|
382
|
+
}
|
|
383
|
+
},
|
|
384
|
+
"delete": {
|
|
385
|
+
"tags": [
|
|
386
|
+
"Content"
|
|
387
|
+
],
|
|
388
|
+
"summary": "Force-remove a CID",
|
|
389
|
+
"description": "Permanently deletes a CID regardless of pin status. If the CID is a MASL document, all linked data CIDs that are held locally are also deleted. Returns the list of all CIDs actually removed.\n",
|
|
390
|
+
"parameters": [
|
|
391
|
+
{
|
|
392
|
+
"in": "path",
|
|
393
|
+
"name": "cid",
|
|
394
|
+
"required": true,
|
|
395
|
+
"schema": {
|
|
396
|
+
"type": "string"
|
|
397
|
+
}
|
|
398
|
+
}
|
|
399
|
+
],
|
|
400
|
+
"responses": {
|
|
401
|
+
"200": {
|
|
402
|
+
"description": "CID(s) deleted",
|
|
403
|
+
"content": {
|
|
404
|
+
"application/json": {
|
|
405
|
+
"schema": {
|
|
406
|
+
"type": "object",
|
|
407
|
+
"properties": {
|
|
408
|
+
"deleted": {
|
|
409
|
+
"type": "array",
|
|
410
|
+
"items": {
|
|
411
|
+
"type": "string"
|
|
412
|
+
}
|
|
413
|
+
}
|
|
414
|
+
}
|
|
415
|
+
}
|
|
416
|
+
}
|
|
417
|
+
}
|
|
418
|
+
},
|
|
419
|
+
"401": {
|
|
420
|
+
"description": "Missing or invalid operator secret"
|
|
421
|
+
},
|
|
422
|
+
"404": {
|
|
423
|
+
"description": "CID not held locally",
|
|
424
|
+
"content": {
|
|
425
|
+
"application/json": {
|
|
426
|
+
"schema": {
|
|
427
|
+
"$ref": "#/components/schemas/Error"
|
|
428
|
+
}
|
|
429
|
+
}
|
|
430
|
+
}
|
|
431
|
+
}
|
|
432
|
+
}
|
|
433
|
+
}
|
|
434
|
+
},
|
|
435
|
+
"/static-roots": {
|
|
436
|
+
"get": {
|
|
437
|
+
"tags": [
|
|
438
|
+
"Content"
|
|
439
|
+
],
|
|
440
|
+
"summary": "List configured static roots and their current MASL CIDs",
|
|
441
|
+
"description": "Returns one entry per directory configured in STATIC_ROOTS. `maslCid` is null if background indexing has not yet completed for that root.\n",
|
|
442
|
+
"responses": {
|
|
443
|
+
"200": {
|
|
444
|
+
"description": "Static root list",
|
|
445
|
+
"content": {
|
|
446
|
+
"application/json": {
|
|
447
|
+
"schema": {
|
|
448
|
+
"type": "array",
|
|
449
|
+
"items": {
|
|
450
|
+
"type": "object",
|
|
451
|
+
"properties": {
|
|
452
|
+
"path": {
|
|
453
|
+
"type": "string",
|
|
454
|
+
"description": "Configured directory path"
|
|
455
|
+
},
|
|
456
|
+
"maslCid": {
|
|
457
|
+
"type": "string",
|
|
458
|
+
"nullable": true,
|
|
459
|
+
"description": "Current bundle MASL CID, or null if not yet indexed"
|
|
460
|
+
}
|
|
461
|
+
}
|
|
462
|
+
}
|
|
463
|
+
}
|
|
464
|
+
}
|
|
465
|
+
}
|
|
466
|
+
},
|
|
467
|
+
"401": {
|
|
468
|
+
"description": "Missing or invalid operator secret"
|
|
469
|
+
}
|
|
470
|
+
}
|
|
471
|
+
}
|
|
472
|
+
},
|
|
473
|
+
"/mount-points": {
|
|
474
|
+
"get": {
|
|
475
|
+
"tags": [
|
|
476
|
+
"Content"
|
|
477
|
+
],
|
|
478
|
+
"summary": "List all virtual hosts and their current MASL CIDs",
|
|
479
|
+
"description": "Returns all mount points: those set via the operator API (`source: runtime`) and those configured in MOUNT_POINTS (`source: static`). Runtime entries take priority in serving. `hostname` is null for wildcard entries that match any `Host:` header. `maslCid` is null only for static entries whose background indexing has not yet completed.\n",
|
|
480
|
+
"responses": {
|
|
481
|
+
"200": {
|
|
482
|
+
"description": "Mount point list",
|
|
483
|
+
"content": {
|
|
484
|
+
"application/json": {
|
|
485
|
+
"schema": {
|
|
486
|
+
"type": "array",
|
|
487
|
+
"items": {
|
|
488
|
+
"type": "object",
|
|
489
|
+
"properties": {
|
|
490
|
+
"hostname": {
|
|
491
|
+
"type": "string",
|
|
492
|
+
"nullable": true,
|
|
493
|
+
"description": "Hostname matched by this mount point, or null for a wildcard entry that matches any Host: header.\n"
|
|
494
|
+
},
|
|
495
|
+
"mountPath": {
|
|
496
|
+
"type": "string",
|
|
497
|
+
"description": "URL path prefix for this mount point (e.g. / or /docs)"
|
|
498
|
+
},
|
|
499
|
+
"path": {
|
|
500
|
+
"type": "string",
|
|
501
|
+
"nullable": true,
|
|
502
|
+
"description": "Directory path (static entries only)"
|
|
503
|
+
},
|
|
504
|
+
"maslCid": {
|
|
505
|
+
"type": "string",
|
|
506
|
+
"nullable": true
|
|
507
|
+
},
|
|
508
|
+
"source": {
|
|
509
|
+
"type": "string",
|
|
510
|
+
"enum": [
|
|
511
|
+
"runtime",
|
|
512
|
+
"static"
|
|
513
|
+
]
|
|
514
|
+
}
|
|
515
|
+
}
|
|
516
|
+
}
|
|
517
|
+
}
|
|
518
|
+
}
|
|
519
|
+
}
|
|
520
|
+
},
|
|
521
|
+
"401": {
|
|
522
|
+
"description": "Missing or invalid operator secret"
|
|
523
|
+
}
|
|
524
|
+
}
|
|
525
|
+
}
|
|
526
|
+
},
|
|
527
|
+
"/mount-points/{hostname}": {
|
|
528
|
+
"put": {
|
|
529
|
+
"tags": [
|
|
530
|
+
"Content"
|
|
531
|
+
],
|
|
532
|
+
"summary": "Map a hostname to a bundle MASL CID (root mount)",
|
|
533
|
+
"description": "Registers a runtime mount point at the hostname root. To mount at a path prefix instead, append it to the URL: `PUT /mount-points/{hostname}/{prefix}`. Use `-` as the hostname to create a wildcard mount point that matches any `Host:` header value (e.g. `PUT /mount-points/-` or `PUT /mount-points/-/docs`). The MASL CID must already be held locally and must be a bundle MASL. The MASL is pinned automatically to prevent eviction. This mapping takes priority over any static-root mapping for the same (hostname, mountPath) and persists across restarts.\n",
|
|
534
|
+
"parameters": [
|
|
535
|
+
{
|
|
536
|
+
"in": "path",
|
|
537
|
+
"name": "hostname",
|
|
538
|
+
"required": true,
|
|
539
|
+
"schema": {
|
|
540
|
+
"type": "string"
|
|
541
|
+
},
|
|
542
|
+
"description": "Hostname to match against the `Host:` header. Use `-` to match any hostname (wildcard).\n"
|
|
543
|
+
}
|
|
544
|
+
],
|
|
545
|
+
"requestBody": {
|
|
546
|
+
"required": true,
|
|
547
|
+
"content": {
|
|
548
|
+
"application/json": {
|
|
549
|
+
"schema": {
|
|
550
|
+
"type": "object",
|
|
551
|
+
"required": [
|
|
552
|
+
"maslCid"
|
|
553
|
+
],
|
|
554
|
+
"properties": {
|
|
555
|
+
"maslCid": {
|
|
556
|
+
"type": "string"
|
|
557
|
+
}
|
|
558
|
+
}
|
|
559
|
+
}
|
|
560
|
+
}
|
|
561
|
+
}
|
|
562
|
+
},
|
|
563
|
+
"responses": {
|
|
564
|
+
"200": {
|
|
565
|
+
"description": "Mapping set",
|
|
566
|
+
"content": {
|
|
567
|
+
"application/json": {
|
|
568
|
+
"schema": {
|
|
569
|
+
"type": "object",
|
|
570
|
+
"properties": {
|
|
571
|
+
"hostname": {
|
|
572
|
+
"type": "string",
|
|
573
|
+
"nullable": true,
|
|
574
|
+
"description": "Matched hostname, or null for a wildcard mount"
|
|
575
|
+
},
|
|
576
|
+
"mountPath": {
|
|
577
|
+
"type": "string"
|
|
578
|
+
},
|
|
579
|
+
"maslCid": {
|
|
580
|
+
"type": "string"
|
|
581
|
+
}
|
|
582
|
+
}
|
|
583
|
+
}
|
|
584
|
+
}
|
|
585
|
+
}
|
|
586
|
+
},
|
|
587
|
+
"400": {
|
|
588
|
+
"description": "Invalid or non-bundle MASL CID",
|
|
589
|
+
"content": {
|
|
590
|
+
"application/json": {
|
|
591
|
+
"schema": {
|
|
592
|
+
"$ref": "#/components/schemas/Error"
|
|
593
|
+
}
|
|
594
|
+
}
|
|
595
|
+
}
|
|
596
|
+
},
|
|
597
|
+
"401": {
|
|
598
|
+
"description": "Missing or invalid operator secret"
|
|
599
|
+
},
|
|
600
|
+
"404": {
|
|
601
|
+
"description": "CID not held locally",
|
|
602
|
+
"content": {
|
|
603
|
+
"application/json": {
|
|
604
|
+
"schema": {
|
|
605
|
+
"$ref": "#/components/schemas/Error"
|
|
606
|
+
}
|
|
607
|
+
}
|
|
608
|
+
}
|
|
609
|
+
}
|
|
610
|
+
}
|
|
611
|
+
},
|
|
612
|
+
"delete": {
|
|
613
|
+
"tags": [
|
|
614
|
+
"Content"
|
|
615
|
+
],
|
|
616
|
+
"summary": "Remove a runtime mount point mapping (root)",
|
|
617
|
+
"description": "Removes the root mapping for this hostname. To remove a prefixed mapping, use `DELETE /mount-points/{hostname}/{prefix}`. Use `-` as the hostname to target a wildcard mount point.\n",
|
|
618
|
+
"parameters": [
|
|
619
|
+
{
|
|
620
|
+
"in": "path",
|
|
621
|
+
"name": "hostname",
|
|
622
|
+
"required": true,
|
|
623
|
+
"schema": {
|
|
624
|
+
"type": "string"
|
|
625
|
+
},
|
|
626
|
+
"description": "Hostname of the mapping to remove. Use `-` for a wildcard mount.\n"
|
|
627
|
+
}
|
|
628
|
+
],
|
|
629
|
+
"responses": {
|
|
630
|
+
"200": {
|
|
631
|
+
"description": "Mapping removed",
|
|
632
|
+
"content": {
|
|
633
|
+
"application/json": {
|
|
634
|
+
"schema": {
|
|
635
|
+
"type": "object",
|
|
636
|
+
"properties": {
|
|
637
|
+
"status": {
|
|
638
|
+
"type": "string",
|
|
639
|
+
"enum": [
|
|
640
|
+
"ok"
|
|
641
|
+
]
|
|
642
|
+
}
|
|
643
|
+
}
|
|
644
|
+
}
|
|
645
|
+
}
|
|
646
|
+
}
|
|
647
|
+
},
|
|
648
|
+
"401": {
|
|
649
|
+
"description": "Missing or invalid operator secret"
|
|
650
|
+
},
|
|
651
|
+
"404": {
|
|
652
|
+
"description": "Runtime mapping not found",
|
|
653
|
+
"content": {
|
|
654
|
+
"application/json": {
|
|
655
|
+
"schema": {
|
|
656
|
+
"$ref": "#/components/schemas/Error"
|
|
657
|
+
}
|
|
658
|
+
}
|
|
659
|
+
}
|
|
660
|
+
}
|
|
661
|
+
}
|
|
662
|
+
}
|
|
663
|
+
},
|
|
664
|
+
"/mount-points/{hostname}/{prefix}": {
|
|
665
|
+
"put": {
|
|
666
|
+
"tags": [
|
|
667
|
+
"Content"
|
|
668
|
+
],
|
|
669
|
+
"summary": "Map a hostname + path prefix to a bundle MASL CID",
|
|
670
|
+
"description": "Same as `PUT /mount-points/{hostname}` but mounts at a path prefix (e.g. `/docs`). The prefix is stripped before MASL resource lookup. Use `-` as the hostname for a wildcard mount at the given prefix.\n",
|
|
671
|
+
"parameters": [
|
|
672
|
+
{
|
|
673
|
+
"in": "path",
|
|
674
|
+
"name": "hostname",
|
|
675
|
+
"required": true,
|
|
676
|
+
"schema": {
|
|
677
|
+
"type": "string"
|
|
678
|
+
},
|
|
679
|
+
"description": "Hostname to match, or `-` for any hostname.\n"
|
|
680
|
+
},
|
|
681
|
+
{
|
|
682
|
+
"in": "path",
|
|
683
|
+
"name": "prefix",
|
|
684
|
+
"required": true,
|
|
685
|
+
"schema": {
|
|
686
|
+
"type": "string"
|
|
687
|
+
}
|
|
688
|
+
}
|
|
689
|
+
],
|
|
690
|
+
"requestBody": {
|
|
691
|
+
"required": true,
|
|
692
|
+
"content": {
|
|
693
|
+
"application/json": {
|
|
694
|
+
"schema": {
|
|
695
|
+
"type": "object",
|
|
696
|
+
"required": [
|
|
697
|
+
"maslCid"
|
|
698
|
+
],
|
|
699
|
+
"properties": {
|
|
700
|
+
"maslCid": {
|
|
701
|
+
"type": "string"
|
|
702
|
+
}
|
|
703
|
+
}
|
|
704
|
+
}
|
|
705
|
+
}
|
|
706
|
+
}
|
|
707
|
+
},
|
|
708
|
+
"responses": {
|
|
709
|
+
"200": {
|
|
710
|
+
"description": "Mapping set",
|
|
711
|
+
"content": {
|
|
712
|
+
"application/json": {
|
|
713
|
+
"schema": {
|
|
714
|
+
"type": "object",
|
|
715
|
+
"properties": {
|
|
716
|
+
"hostname": {
|
|
717
|
+
"type": "string",
|
|
718
|
+
"nullable": true,
|
|
719
|
+
"description": "Matched hostname, or null for a wildcard mount"
|
|
720
|
+
},
|
|
721
|
+
"mountPath": {
|
|
722
|
+
"type": "string"
|
|
723
|
+
},
|
|
724
|
+
"maslCid": {
|
|
725
|
+
"type": "string"
|
|
726
|
+
}
|
|
727
|
+
}
|
|
728
|
+
}
|
|
729
|
+
}
|
|
730
|
+
}
|
|
731
|
+
},
|
|
732
|
+
"400": {
|
|
733
|
+
"$ref": "#/components/responses/400"
|
|
734
|
+
},
|
|
735
|
+
"401": {
|
|
736
|
+
"description": "Missing or invalid operator secret"
|
|
737
|
+
},
|
|
738
|
+
"404": {
|
|
739
|
+
"$ref": "#/components/responses/404"
|
|
740
|
+
}
|
|
741
|
+
}
|
|
742
|
+
},
|
|
743
|
+
"delete": {
|
|
744
|
+
"tags": [
|
|
745
|
+
"Content"
|
|
746
|
+
],
|
|
747
|
+
"summary": "Remove a runtime mount point mapping (prefixed)",
|
|
748
|
+
"parameters": [
|
|
749
|
+
{
|
|
750
|
+
"in": "path",
|
|
751
|
+
"name": "hostname",
|
|
752
|
+
"required": true,
|
|
753
|
+
"schema": {
|
|
754
|
+
"type": "string"
|
|
755
|
+
},
|
|
756
|
+
"description": "Hostname of the mapping to remove. Use `-` for a wildcard mount.\n"
|
|
757
|
+
},
|
|
758
|
+
{
|
|
759
|
+
"in": "path",
|
|
760
|
+
"name": "prefix",
|
|
761
|
+
"required": true,
|
|
762
|
+
"schema": {
|
|
763
|
+
"type": "string"
|
|
764
|
+
}
|
|
765
|
+
}
|
|
766
|
+
],
|
|
767
|
+
"responses": {
|
|
768
|
+
"200": {
|
|
769
|
+
"description": "Mapping removed",
|
|
770
|
+
"content": {
|
|
771
|
+
"application/json": {
|
|
772
|
+
"schema": {
|
|
773
|
+
"type": "object",
|
|
774
|
+
"properties": {
|
|
775
|
+
"status": {
|
|
776
|
+
"type": "string",
|
|
777
|
+
"enum": [
|
|
778
|
+
"ok"
|
|
779
|
+
]
|
|
780
|
+
}
|
|
781
|
+
}
|
|
782
|
+
}
|
|
783
|
+
}
|
|
784
|
+
}
|
|
785
|
+
},
|
|
786
|
+
"401": {
|
|
787
|
+
"description": "Missing or invalid operator secret"
|
|
788
|
+
},
|
|
789
|
+
"404": {
|
|
790
|
+
"description": "Runtime mapping not found",
|
|
791
|
+
"content": {
|
|
792
|
+
"application/json": {
|
|
793
|
+
"schema": {
|
|
794
|
+
"$ref": "#/components/schemas/Error"
|
|
795
|
+
}
|
|
796
|
+
}
|
|
797
|
+
}
|
|
798
|
+
}
|
|
799
|
+
}
|
|
800
|
+
}
|
|
801
|
+
},
|
|
802
|
+
"/status": {
|
|
803
|
+
"get": {
|
|
804
|
+
"tags": [
|
|
805
|
+
"Node status"
|
|
806
|
+
],
|
|
807
|
+
"summary": "Get node status",
|
|
808
|
+
"description": "Returns the node's public origin and current storage metrics. Overlay routers may add additional fields to the response before the terminator sends it.\n",
|
|
809
|
+
"responses": {
|
|
810
|
+
"200": {
|
|
811
|
+
"description": "Node status",
|
|
812
|
+
"content": {
|
|
813
|
+
"application/json": {
|
|
814
|
+
"schema": {
|
|
815
|
+
"type": "object",
|
|
816
|
+
"properties": {
|
|
817
|
+
"origin": {
|
|
818
|
+
"type": "string",
|
|
819
|
+
"description": "Public origin of this node (protocol + host)",
|
|
820
|
+
"example": "https://node1.example.com"
|
|
821
|
+
},
|
|
822
|
+
"storage": {
|
|
823
|
+
"type": "object",
|
|
824
|
+
"properties": {
|
|
825
|
+
"totalCapacity": {
|
|
826
|
+
"type": "integer",
|
|
827
|
+
"description": "Total storage budget in bytes"
|
|
828
|
+
},
|
|
829
|
+
"poolUsed": {
|
|
830
|
+
"type": "integer",
|
|
831
|
+
"description": "Bytes used by unpinned (evictable) content"
|
|
832
|
+
},
|
|
833
|
+
"poolAvailable": {
|
|
834
|
+
"type": "integer",
|
|
835
|
+
"description": "Bytes remaining before eviction is triggered"
|
|
836
|
+
},
|
|
837
|
+
"pinnedUsed": {
|
|
838
|
+
"type": "integer",
|
|
839
|
+
"description": "Bytes used by pinned content (not evictable)"
|
|
840
|
+
},
|
|
841
|
+
"pinnedCount": {
|
|
842
|
+
"type": "integer",
|
|
843
|
+
"description": "Number of pinned CIDs"
|
|
844
|
+
}
|
|
845
|
+
}
|
|
846
|
+
}
|
|
847
|
+
}
|
|
848
|
+
}
|
|
849
|
+
}
|
|
850
|
+
}
|
|
851
|
+
},
|
|
852
|
+
"401": {
|
|
853
|
+
"description": "Missing or invalid operator secret"
|
|
854
|
+
}
|
|
855
|
+
}
|
|
856
|
+
}
|
|
857
|
+
}
|
|
858
|
+
}
|
|
859
|
+
}
|