was-teaching-server 0.9.1
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 +1432 -0
- package/LICENSE +661 -0
- package/README.md +305 -0
- package/common/css/materialize.1.0.0.min.css +13 -0
- package/dist/auth-header-hooks.d.ts +84 -0
- package/dist/auth-header-hooks.d.ts.map +1 -0
- package/dist/auth-header-hooks.js +136 -0
- package/dist/auth-header-hooks.js.map +1 -0
- package/dist/authorize.d.ts +45 -0
- package/dist/authorize.d.ts.map +1 -0
- package/dist/authorize.js +76 -0
- package/dist/authorize.js.map +1 -0
- package/dist/backends/filesystem.d.ts +1179 -0
- package/dist/backends/filesystem.d.ts.map +1 -0
- package/dist/backends/filesystem.js +2727 -0
- package/dist/backends/filesystem.js.map +1 -0
- package/dist/backends/postgres.d.ts +833 -0
- package/dist/backends/postgres.d.ts.map +1 -0
- package/dist/backends/postgres.js +2164 -0
- package/dist/backends/postgres.js.map +1 -0
- package/dist/backends/postgresSchema.d.ts +36 -0
- package/dist/backends/postgresSchema.d.ts.map +1 -0
- package/dist/backends/postgresSchema.js +203 -0
- package/dist/backends/postgresSchema.js.map +1 -0
- package/dist/config.default.d.ts +360 -0
- package/dist/config.default.d.ts.map +1 -0
- package/dist/config.default.js +493 -0
- package/dist/config.default.js.map +1 -0
- package/dist/corsProxy.d.ts +45 -0
- package/dist/corsProxy.d.ts.map +1 -0
- package/dist/corsProxy.js +278 -0
- package/dist/corsProxy.js.map +1 -0
- package/dist/digest.d.ts +45 -0
- package/dist/digest.d.ts.map +1 -0
- package/dist/digest.js +174 -0
- package/dist/digest.js.map +1 -0
- package/dist/errors.d.ts +654 -0
- package/dist/errors.d.ts.map +1 -0
- package/dist/errors.js +960 -0
- package/dist/errors.js.map +1 -0
- package/dist/index.d.ts +22 -0
- package/dist/index.d.ts.map +1 -0
- package/dist/index.js +21 -0
- package/dist/index.js.map +1 -0
- package/dist/lib/atomicFile.d.ts +61 -0
- package/dist/lib/atomicFile.d.ts.map +1 -0
- package/dist/lib/atomicFile.js +150 -0
- package/dist/lib/atomicFile.js.map +1 -0
- package/dist/lib/backendRegistry.d.ts +59 -0
- package/dist/lib/backendRegistry.d.ts.map +1 -0
- package/dist/lib/backendRegistry.js +92 -0
- package/dist/lib/backendRegistry.js.map +1 -0
- package/dist/lib/backendUsage.d.ts +28 -0
- package/dist/lib/backendUsage.d.ts.map +1 -0
- package/dist/lib/backendUsage.js +55 -0
- package/dist/lib/backendUsage.js.map +1 -0
- package/dist/lib/backends.d.ts +142 -0
- package/dist/lib/backends.d.ts.map +1 -0
- package/dist/lib/backends.js +272 -0
- package/dist/lib/backends.js.map +1 -0
- package/dist/lib/blindedIndex.d.ts +156 -0
- package/dist/lib/blindedIndex.d.ts.map +1 -0
- package/dist/lib/blindedIndex.js +338 -0
- package/dist/lib/blindedIndex.js.map +1 -0
- package/dist/lib/collectionDescription.d.ts +33 -0
- package/dist/lib/collectionDescription.d.ts.map +1 -0
- package/dist/lib/collectionDescription.js +21 -0
- package/dist/lib/collectionDescription.js.map +1 -0
- package/dist/lib/cursor.d.ts +18 -0
- package/dist/lib/cursor.d.ts.map +1 -0
- package/dist/lib/cursor.js +50 -0
- package/dist/lib/cursor.js.map +1 -0
- package/dist/lib/edvEnvelope.d.ts +50 -0
- package/dist/lib/edvEnvelope.d.ts.map +1 -0
- package/dist/lib/edvEnvelope.js +106 -0
- package/dist/lib/edvEnvelope.js.map +1 -0
- package/dist/lib/encryption.d.ts +192 -0
- package/dist/lib/encryption.d.ts.map +1 -0
- package/dist/lib/encryption.js +383 -0
- package/dist/lib/encryption.js.map +1 -0
- package/dist/lib/etag.d.ts +33 -0
- package/dist/lib/etag.d.ts.map +1 -0
- package/dist/lib/etag.js +36 -0
- package/dist/lib/etag.js.map +1 -0
- package/dist/lib/exportManifest.d.ts +29 -0
- package/dist/lib/exportManifest.d.ts.map +1 -0
- package/dist/lib/exportManifest.js +77 -0
- package/dist/lib/exportManifest.js.map +1 -0
- package/dist/lib/importTar.d.ts +81 -0
- package/dist/lib/importTar.d.ts.map +1 -0
- package/dist/lib/importTar.js +301 -0
- package/dist/lib/importTar.js.map +1 -0
- package/dist/lib/isJson.d.ts +16 -0
- package/dist/lib/isJson.d.ts.map +1 -0
- package/dist/lib/isJson.js +17 -0
- package/dist/lib/isJson.js.map +1 -0
- package/dist/lib/keyEpoch.d.ts +38 -0
- package/dist/lib/keyEpoch.d.ts.map +1 -0
- package/dist/lib/keyEpoch.js +75 -0
- package/dist/lib/keyEpoch.js.map +1 -0
- package/dist/lib/keyedMutex.d.ts +28 -0
- package/dist/lib/keyedMutex.d.ts.map +1 -0
- package/dist/lib/keyedMutex.js +45 -0
- package/dist/lib/keyedMutex.js.map +1 -0
- package/dist/lib/kmsModule.d.ts +62 -0
- package/dist/lib/kmsModule.d.ts.map +1 -0
- package/dist/lib/kmsModule.js +327 -0
- package/dist/lib/kmsModule.js.map +1 -0
- package/dist/lib/kmsRecordCipher.d.ts +82 -0
- package/dist/lib/kmsRecordCipher.d.ts.map +1 -0
- package/dist/lib/kmsRecordCipher.js +226 -0
- package/dist/lib/kmsRecordCipher.js.map +1 -0
- package/dist/lib/pagination.d.ts +19 -0
- package/dist/lib/pagination.d.ts.map +1 -0
- package/dist/lib/pagination.js +21 -0
- package/dist/lib/pagination.js.map +1 -0
- package/dist/lib/paths.d.ts +273 -0
- package/dist/lib/paths.d.ts.map +1 -0
- package/dist/lib/paths.js +270 -0
- package/dist/lib/paths.js.map +1 -0
- package/dist/lib/preconditions.d.ts +65 -0
- package/dist/lib/preconditions.d.ts.map +1 -0
- package/dist/lib/preconditions.js +112 -0
- package/dist/lib/preconditions.js.map +1 -0
- package/dist/lib/resourceFileName.d.ts +41 -0
- package/dist/lib/resourceFileName.d.ts.map +1 -0
- package/dist/lib/resourceFileName.js +58 -0
- package/dist/lib/resourceFileName.js.map +1 -0
- package/dist/lib/revocations.d.ts +49 -0
- package/dist/lib/revocations.d.ts.map +1 -0
- package/dist/lib/revocations.js +86 -0
- package/dist/lib/revocations.js.map +1 -0
- package/dist/lib/validateDid.d.ts +19 -0
- package/dist/lib/validateDid.d.ts.map +1 -0
- package/dist/lib/validateDid.js +35 -0
- package/dist/lib/validateDid.js.map +1 -0
- package/dist/lib/validateId.d.ts +66 -0
- package/dist/lib/validateId.d.ts.map +1 -0
- package/dist/lib/validateId.js +126 -0
- package/dist/lib/validateId.js.map +1 -0
- package/dist/plugin.d.ts +115 -0
- package/dist/plugin.d.ts.map +1 -0
- package/dist/plugin.js +134 -0
- package/dist/plugin.js.map +1 -0
- package/dist/policy.d.ts +78 -0
- package/dist/policy.d.ts.map +1 -0
- package/dist/policy.js +115 -0
- package/dist/policy.js.map +1 -0
- package/dist/provisioning.d.ts +38 -0
- package/dist/provisioning.d.ts.map +1 -0
- package/dist/provisioning.js +72 -0
- package/dist/provisioning.js.map +1 -0
- package/dist/requests/BackendRequest.d.ts +61 -0
- package/dist/requests/BackendRequest.d.ts.map +1 -0
- package/dist/requests/BackendRequest.js +152 -0
- package/dist/requests/BackendRequest.js.map +1 -0
- package/dist/requests/CollectionRequest.d.ts +234 -0
- package/dist/requests/CollectionRequest.d.ts.map +1 -0
- package/dist/requests/CollectionRequest.js +705 -0
- package/dist/requests/CollectionRequest.js.map +1 -0
- package/dist/requests/KeyRequest.d.ts +115 -0
- package/dist/requests/KeyRequest.d.ts.map +1 -0
- package/dist/requests/KeyRequest.js +468 -0
- package/dist/requests/KeyRequest.js.map +1 -0
- package/dist/requests/KeystoreRequest.d.ts +99 -0
- package/dist/requests/KeystoreRequest.d.ts.map +1 -0
- package/dist/requests/KeystoreRequest.js +247 -0
- package/dist/requests/KeystoreRequest.js.map +1 -0
- package/dist/requests/PolicyRequest.d.ts +53 -0
- package/dist/requests/PolicyRequest.d.ts.map +1 -0
- package/dist/requests/PolicyRequest.js +124 -0
- package/dist/requests/PolicyRequest.js.map +1 -0
- package/dist/requests/ResourceRequest.d.ts +134 -0
- package/dist/requests/ResourceRequest.d.ts.map +1 -0
- package/dist/requests/ResourceRequest.js +548 -0
- package/dist/requests/ResourceRequest.js.map +1 -0
- package/dist/requests/RevocationRequest.d.ts +67 -0
- package/dist/requests/RevocationRequest.d.ts.map +1 -0
- package/dist/requests/RevocationRequest.js +187 -0
- package/dist/requests/RevocationRequest.js.map +1 -0
- package/dist/requests/SpaceRequest.d.ts +204 -0
- package/dist/requests/SpaceRequest.d.ts.map +1 -0
- package/dist/requests/SpaceRequest.js +520 -0
- package/dist/requests/SpaceRequest.js.map +1 -0
- package/dist/requests/SpacesRepositoryRequest.d.ts +50 -0
- package/dist/requests/SpacesRepositoryRequest.d.ts.map +1 -0
- package/dist/requests/SpacesRepositoryRequest.js +159 -0
- package/dist/requests/SpacesRepositoryRequest.js.map +1 -0
- package/dist/requests/collectionContext.d.ts +21 -0
- package/dist/requests/collectionContext.d.ts.map +1 -0
- package/dist/requests/collectionContext.js +30 -0
- package/dist/requests/collectionContext.js.map +1 -0
- package/dist/requests/controllerConsent.d.ts +58 -0
- package/dist/requests/controllerConsent.d.ts.map +1 -0
- package/dist/requests/controllerConsent.js +73 -0
- package/dist/requests/controllerConsent.js.map +1 -0
- package/dist/requests/keystoreContext.d.ts +68 -0
- package/dist/requests/keystoreContext.d.ts.map +1 -0
- package/dist/requests/keystoreContext.js +87 -0
- package/dist/requests/keystoreContext.js.map +1 -0
- package/dist/requests/resourceInput.d.ts +19 -0
- package/dist/requests/resourceInput.d.ts.map +1 -0
- package/dist/requests/resourceInput.js +102 -0
- package/dist/requests/resourceInput.js.map +1 -0
- package/dist/requests/spaceContext.d.ts +127 -0
- package/dist/requests/spaceContext.d.ts.map +1 -0
- package/dist/requests/spaceContext.js +201 -0
- package/dist/requests/spaceContext.js.map +1 -0
- package/dist/routes.d.ts +55 -0
- package/dist/routes.d.ts.map +1 -0
- package/dist/routes.js +306 -0
- package/dist/routes.js.map +1 -0
- package/dist/server.d.ts +20 -0
- package/dist/server.d.ts.map +1 -0
- package/dist/server.js +60 -0
- package/dist/server.js.map +1 -0
- package/dist/start.d.ts +7 -0
- package/dist/start.d.ts.map +1 -0
- package/dist/start.js +61 -0
- package/dist/start.js.map +1 -0
- package/dist/storage.d.ts +29 -0
- package/dist/storage.d.ts.map +1 -0
- package/dist/storage.js +47 -0
- package/dist/storage.js.map +1 -0
- package/dist/types.d.ts +915 -0
- package/dist/types.d.ts.map +1 -0
- package/dist/types.js +2 -0
- package/dist/types.js.map +1 -0
- package/dist/views/home.hbs +9 -0
- package/dist/views/templates/main.hbs +12 -0
- package/dist/zcap.d.ts +267 -0
- package/dist/zcap.d.ts.map +1 -0
- package/dist/zcap.js +478 -0
- package/dist/zcap.js.map +1 -0
- package/package.json +109 -0
- package/src/auth-header-hooks.ts +163 -0
- package/src/authorize.ts +117 -0
- package/src/backends/filesystem.ts +3626 -0
- package/src/backends/postgres.ts +3073 -0
- package/src/backends/postgresSchema.ts +231 -0
- package/src/config.default.ts +657 -0
- package/src/corsProxy.ts +326 -0
- package/src/declarations.d.ts +28 -0
- package/src/digest.ts +223 -0
- package/src/errors.ts +1122 -0
- package/src/index.ts +21 -0
- package/src/lib/atomicFile.ts +176 -0
- package/src/lib/backendRegistry.ts +139 -0
- package/src/lib/backendUsage.ts +79 -0
- package/src/lib/backends.ts +351 -0
- package/src/lib/blindedIndex.ts +466 -0
- package/src/lib/collectionDescription.ts +43 -0
- package/src/lib/cursor.ts +52 -0
- package/src/lib/edvEnvelope.ts +120 -0
- package/src/lib/encryption.ts +472 -0
- package/src/lib/etag.ts +40 -0
- package/src/lib/exportManifest.ts +115 -0
- package/src/lib/importTar.ts +381 -0
- package/src/lib/isJson.ts +18 -0
- package/src/lib/keyEpoch.ts +89 -0
- package/src/lib/keyedMutex.ts +45 -0
- package/src/lib/kmsModule.ts +451 -0
- package/src/lib/kmsRecordCipher.ts +292 -0
- package/src/lib/pagination.ts +22 -0
- package/src/lib/paths.ts +382 -0
- package/src/lib/preconditions.ts +145 -0
- package/src/lib/resourceFileName.ts +69 -0
- package/src/lib/revocations.ts +116 -0
- package/src/lib/validateDid.ts +41 -0
- package/src/lib/validateId.ts +148 -0
- package/src/plugin.ts +288 -0
- package/src/policy.ts +176 -0
- package/src/provisioning.ts +98 -0
- package/src/requests/BackendRequest.ts +219 -0
- package/src/requests/CollectionRequest.ts +899 -0
- package/src/requests/KeyRequest.ts +617 -0
- package/src/requests/KeystoreRequest.ts +325 -0
- package/src/requests/PolicyRequest.ts +169 -0
- package/src/requests/ResourceRequest.ts +649 -0
- package/src/requests/RevocationRequest.ts +267 -0
- package/src/requests/SpaceRequest.ts +686 -0
- package/src/requests/SpacesRepositoryRequest.ts +194 -0
- package/src/requests/collectionContext.ts +41 -0
- package/src/requests/controllerConsent.ts +108 -0
- package/src/requests/keystoreContext.ts +124 -0
- package/src/requests/resourceInput.ts +118 -0
- package/src/requests/spaceContext.ts +311 -0
- package/src/routes.ts +420 -0
- package/src/server.ts +69 -0
- package/src/start.ts +71 -0
- package/src/storage.ts +60 -0
- package/src/types.ts +1016 -0
- package/src/views/home.hbs +9 -0
- package/src/views/templates/main.hbs +12 -0
- package/src/zcap.ts +657 -0
|
@@ -0,0 +1,219 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Request handlers for registering an `external` backend against a Space (spec
|
|
3
|
+
* "Backends"): register (`POST`), replace (`PUT`), and deregister (`DELETE`) a
|
|
4
|
+
* backend record. Authorization is the Space controller's key (capability-only,
|
|
5
|
+
* no policy fallback), exactly like Create Collection / Delete Space.
|
|
6
|
+
*
|
|
7
|
+
* The write body is secret-bearing (`BackendConnectionInput`), but every
|
|
8
|
+
* response returns the **sanitized** `BackendDescriptor` (via
|
|
9
|
+
* `sanitizeBackendRecord`), so a client response can never carry the secret. A
|
|
10
|
+
* registered backend is inert this increment: it is listed but not yet
|
|
11
|
+
* selectable as a Collection's `backend` (the live provider adapter is future
|
|
12
|
+
* work).
|
|
13
|
+
*/
|
|
14
|
+
import type { FastifyReply, FastifyRequest } from 'fastify'
|
|
15
|
+
import { fetchSpaceAndVerify } from './spaceContext.js'
|
|
16
|
+
import { assertValidIds } from '../lib/validateId.js'
|
|
17
|
+
import {
|
|
18
|
+
DEFAULT_BACKEND_ID,
|
|
19
|
+
assertProviderAllowed,
|
|
20
|
+
assertValidBackendId,
|
|
21
|
+
buildBackendRecord,
|
|
22
|
+
parseBackendRegistration,
|
|
23
|
+
sanitizeBackendRecord
|
|
24
|
+
} from '../lib/backends.js'
|
|
25
|
+
import { invalidateResolvedBackend } from '../lib/backendRegistry.js'
|
|
26
|
+
import { backendsPath, registeredBackendPath } from '../lib/paths.js'
|
|
27
|
+
import { InvalidRequestBodyError, IdConflictError } from '../errors.js'
|
|
28
|
+
|
|
29
|
+
export class BackendRequest {
|
|
30
|
+
/**
|
|
31
|
+
* POST /space/:spaceId/backends
|
|
32
|
+
* Registers a new `external` backend. Rejects the reserved `default` id and a
|
|
33
|
+
* duplicate id (checked after capability verification so an unauthorized
|
|
34
|
+
* caller cannot probe ids). Responds 201 with the sanitized descriptor.
|
|
35
|
+
* @param request {import('fastify').FastifyRequest}
|
|
36
|
+
* @param reply {import('fastify').FastifyReply}
|
|
37
|
+
* @returns {Promise<FastifyReply>}
|
|
38
|
+
*/
|
|
39
|
+
static async post(
|
|
40
|
+
request: FastifyRequest<{
|
|
41
|
+
Params: { spaceId: string }
|
|
42
|
+
Body: unknown
|
|
43
|
+
}>,
|
|
44
|
+
reply: FastifyReply
|
|
45
|
+
): Promise<FastifyReply> {
|
|
46
|
+
const {
|
|
47
|
+
params: { spaceId },
|
|
48
|
+
body
|
|
49
|
+
} = request
|
|
50
|
+
const { serverUrl, storage } = request.server
|
|
51
|
+
const requestName = 'Register Backend'
|
|
52
|
+
|
|
53
|
+
// Reject path-traversal / non-URL-safe ids before any storage access.
|
|
54
|
+
assertValidIds({ spaceId }, { requestName })
|
|
55
|
+
const registration = parseBackendRegistration(body, { requestName })
|
|
56
|
+
// Fail fast if the server's registration allowlist excludes this provider
|
|
57
|
+
// (permissive when no allowlist is configured).
|
|
58
|
+
assertProviderAllowed({
|
|
59
|
+
provider: registration.provider,
|
|
60
|
+
enabledProviders: request.server.enabledBackendProviders
|
|
61
|
+
})
|
|
62
|
+
assertValidBackendId(registration.id, { requestName })
|
|
63
|
+
|
|
64
|
+
// Verify (capability-only): registering a backend requires a valid
|
|
65
|
+
// capability invocation by the Space controller; no policy fallback.
|
|
66
|
+
await fetchSpaceAndVerify({
|
|
67
|
+
request,
|
|
68
|
+
spaceId,
|
|
69
|
+
targetPath: backendsPath({ spaceId }),
|
|
70
|
+
requestName
|
|
71
|
+
})
|
|
72
|
+
|
|
73
|
+
// After verification (so an unauthorized caller cannot probe ids): the
|
|
74
|
+
// `default` id is reserved for the server backend, and POST must not replace
|
|
75
|
+
// an existing record (create-or-replace by id is PUT's job).
|
|
76
|
+
if (registration.id === DEFAULT_BACKEND_ID) {
|
|
77
|
+
throw new InvalidRequestBodyError({
|
|
78
|
+
requestName,
|
|
79
|
+
detail: `"${DEFAULT_BACKEND_ID}" is the reserved server backend id and cannot be registered.`,
|
|
80
|
+
pointer: '#/id'
|
|
81
|
+
})
|
|
82
|
+
}
|
|
83
|
+
if (await storage.getBackend({ spaceId, backendId: registration.id })) {
|
|
84
|
+
throw new IdConflictError({ kind: 'Backend' })
|
|
85
|
+
}
|
|
86
|
+
|
|
87
|
+
const record = buildBackendRecord(registration)
|
|
88
|
+
await storage.writeBackend({ spaceId, backendId: record.id, record })
|
|
89
|
+
|
|
90
|
+
const createdUrl = new URL(
|
|
91
|
+
registeredBackendPath({ spaceId, backendId: record.id }),
|
|
92
|
+
serverUrl
|
|
93
|
+
).toString()
|
|
94
|
+
reply.header('Location', createdUrl)
|
|
95
|
+
return reply.status(201).send(sanitizeBackendRecord(record))
|
|
96
|
+
}
|
|
97
|
+
|
|
98
|
+
/**
|
|
99
|
+
* PUT /space/:spaceId/backends/:backendId
|
|
100
|
+
* Upsert (the re-consent path): create-or-replace a backend record at a chosen
|
|
101
|
+
* id. The body `id` (when present) must match the path id, and `default` is
|
|
102
|
+
* rejected. Responds 201 + Location + sanitized body on create, 204 on update.
|
|
103
|
+
* @param request {import('fastify').FastifyRequest}
|
|
104
|
+
* @param reply {import('fastify').FastifyReply}
|
|
105
|
+
* @returns {Promise<FastifyReply>}
|
|
106
|
+
*/
|
|
107
|
+
static async put(
|
|
108
|
+
request: FastifyRequest<{
|
|
109
|
+
Params: { spaceId: string; backendId: string }
|
|
110
|
+
Body: unknown
|
|
111
|
+
}>,
|
|
112
|
+
reply: FastifyReply
|
|
113
|
+
): Promise<FastifyReply> {
|
|
114
|
+
const {
|
|
115
|
+
params: { spaceId, backendId },
|
|
116
|
+
body
|
|
117
|
+
} = request
|
|
118
|
+
const { serverUrl, storage } = request.server
|
|
119
|
+
const requestName = 'Register Backend'
|
|
120
|
+
|
|
121
|
+
// Reject path-traversal / non-URL-safe ids before any storage access.
|
|
122
|
+
assertValidIds({ spaceId }, { requestName })
|
|
123
|
+
assertValidBackendId(backendId, { requestName })
|
|
124
|
+
const registration = parseBackendRegistration(body, { requestName })
|
|
125
|
+
// Fail fast if the server's registration allowlist excludes this provider
|
|
126
|
+
// (permissive when no allowlist is configured).
|
|
127
|
+
assertProviderAllowed({
|
|
128
|
+
provider: registration.provider,
|
|
129
|
+
enabledProviders: request.server.enabledBackendProviders
|
|
130
|
+
})
|
|
131
|
+
|
|
132
|
+
// The backend `id` is immutable: a body `id`, when present, must match the
|
|
133
|
+
// URL id; and `default` is the reserved server backend id.
|
|
134
|
+
if (registration.id !== backendId) {
|
|
135
|
+
throw new InvalidRequestBodyError({
|
|
136
|
+
requestName,
|
|
137
|
+
detail: `Backend "id" (${registration.id}) does not match the URL backend id (${backendId}).`,
|
|
138
|
+
pointer: '#/id'
|
|
139
|
+
})
|
|
140
|
+
}
|
|
141
|
+
if (backendId === DEFAULT_BACKEND_ID) {
|
|
142
|
+
throw new InvalidRequestBodyError({
|
|
143
|
+
requestName,
|
|
144
|
+
detail: `"${DEFAULT_BACKEND_ID}" is the reserved server backend id and cannot be registered.`,
|
|
145
|
+
pointer: '#/id'
|
|
146
|
+
})
|
|
147
|
+
}
|
|
148
|
+
|
|
149
|
+
// Verify (capability-only): no policy fallback for a write.
|
|
150
|
+
await fetchSpaceAndVerify({
|
|
151
|
+
request,
|
|
152
|
+
spaceId,
|
|
153
|
+
targetPath: registeredBackendPath({ spaceId, backendId }),
|
|
154
|
+
requestName
|
|
155
|
+
})
|
|
156
|
+
|
|
157
|
+
const existing = await storage.getBackend({ spaceId, backendId })
|
|
158
|
+
const record = buildBackendRecord(registration)
|
|
159
|
+
await storage.writeBackend({ spaceId, backendId, record })
|
|
160
|
+
// Bust any memoized adapter so the next resolve rebuilds it from the new
|
|
161
|
+
// connection material.
|
|
162
|
+
invalidateResolvedBackend({
|
|
163
|
+
providers: request.server.backendProviders,
|
|
164
|
+
spaceId,
|
|
165
|
+
backendId
|
|
166
|
+
})
|
|
167
|
+
|
|
168
|
+
if (existing) {
|
|
169
|
+
return reply.status(204).send()
|
|
170
|
+
}
|
|
171
|
+
const createdUrl = new URL(
|
|
172
|
+
registeredBackendPath({ spaceId, backendId }),
|
|
173
|
+
serverUrl
|
|
174
|
+
).toString()
|
|
175
|
+
reply.header('Location', createdUrl)
|
|
176
|
+
return reply.status(201).send(sanitizeBackendRecord(record))
|
|
177
|
+
}
|
|
178
|
+
|
|
179
|
+
/**
|
|
180
|
+
* DELETE /space/:spaceId/backends/:backendId
|
|
181
|
+
* Deregisters a backend. Idempotent (204 even if the record was absent).
|
|
182
|
+
* @param request {import('fastify').FastifyRequest}
|
|
183
|
+
* @param reply {import('fastify').FastifyReply}
|
|
184
|
+
* @returns {Promise<FastifyReply>}
|
|
185
|
+
*/
|
|
186
|
+
static async delete(
|
|
187
|
+
request: FastifyRequest<{
|
|
188
|
+
Params: { spaceId: string; backendId: string }
|
|
189
|
+
}>,
|
|
190
|
+
reply: FastifyReply
|
|
191
|
+
): Promise<FastifyReply> {
|
|
192
|
+
const {
|
|
193
|
+
params: { spaceId, backendId }
|
|
194
|
+
} = request
|
|
195
|
+
const { storage } = request.server
|
|
196
|
+
const requestName = 'Deregister Backend'
|
|
197
|
+
|
|
198
|
+
// Reject path-traversal / non-URL-safe ids before any storage access.
|
|
199
|
+
assertValidIds({ spaceId }, { requestName })
|
|
200
|
+
assertValidBackendId(backendId, { requestName })
|
|
201
|
+
|
|
202
|
+
// Verify (capability-only): no policy fallback for a write.
|
|
203
|
+
await fetchSpaceAndVerify({
|
|
204
|
+
request,
|
|
205
|
+
spaceId,
|
|
206
|
+
targetPath: registeredBackendPath({ spaceId, backendId }),
|
|
207
|
+
requestName
|
|
208
|
+
})
|
|
209
|
+
|
|
210
|
+
await storage.deleteBackend({ spaceId, backendId })
|
|
211
|
+
// Bust any memoized adapter for the now-removed record.
|
|
212
|
+
invalidateResolvedBackend({
|
|
213
|
+
providers: request.server.backendProviders,
|
|
214
|
+
spaceId,
|
|
215
|
+
backendId
|
|
216
|
+
})
|
|
217
|
+
return reply.status(204).send()
|
|
218
|
+
}
|
|
219
|
+
}
|