@selvajs/server 1.1.0 → 1.3.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/dist/access/guards.d.ts +213 -0
- package/dist/access/guards.d.ts.map +1 -0
- package/dist/access/guards.js +417 -0
- package/dist/access/guards.js.map +1 -0
- package/dist/access/index.d.ts +2 -0
- package/dist/access/index.d.ts.map +1 -1
- package/dist/access/index.js +6 -0
- package/dist/access/index.js.map +1 -1
- package/dist/access/permissions-scope.d.ts +15 -0
- package/dist/access/permissions-scope.d.ts.map +1 -0
- package/dist/access/permissions-scope.js +23 -0
- package/dist/access/permissions-scope.js.map +1 -0
- package/dist/api/bodies.d.ts +104 -0
- package/dist/api/bodies.d.ts.map +1 -0
- package/dist/api/bodies.js +87 -0
- package/dist/api/bodies.js.map +1 -0
- package/dist/api/deps.d.ts +135 -0
- package/dist/api/deps.d.ts.map +1 -0
- package/dist/api/deps.js +55 -0
- package/dist/api/deps.js.map +1 -0
- package/dist/api/errors.d.ts +35 -0
- package/dist/api/errors.d.ts.map +1 -0
- package/dist/api/errors.js +63 -0
- package/dist/api/errors.js.map +1 -0
- package/dist/api/index.d.ts +12 -0
- package/dist/api/index.d.ts.map +1 -0
- package/dist/api/index.js +15 -0
- package/dist/api/index.js.map +1 -0
- package/dist/api/map-core-error.d.ts +19 -0
- package/dist/api/map-core-error.d.ts.map +1 -0
- package/dist/api/map-core-error.js +49 -0
- package/dist/api/map-core-error.js.map +1 -0
- package/dist/api/pagination.d.ts +19 -0
- package/dist/api/pagination.d.ts.map +1 -0
- package/dist/api/pagination.js +40 -0
- package/dist/api/pagination.js.map +1 -0
- package/dist/api/request.d.ts +93 -0
- package/dist/api/request.d.ts.map +1 -0
- package/dist/api/request.js +150 -0
- package/dist/api/request.js.map +1 -0
- package/dist/api/respond.d.ts +29 -0
- package/dist/api/respond.d.ts.map +1 -0
- package/dist/api/respond.js +59 -0
- package/dist/api/respond.js.map +1 -0
- package/dist/api/responses-schema.d.ts +158 -0
- package/dist/api/responses-schema.d.ts.map +1 -0
- package/dist/api/responses-schema.js +104 -0
- package/dist/api/responses-schema.js.map +1 -0
- package/dist/api/responses.d.ts +19 -0
- package/dist/api/responses.d.ts.map +1 -0
- package/dist/api/responses.js +21 -0
- package/dist/api/responses.js.map +1 -0
- package/dist/api/shaped.d.ts +23 -0
- package/dist/api/shaped.d.ts.map +1 -0
- package/dist/api/shaped.js +29 -0
- package/dist/api/shaped.js.map +1 -0
- package/dist/api/types.d.ts +41 -0
- package/dist/api/types.d.ts.map +1 -0
- package/dist/api/types.js +12 -0
- package/dist/api/types.js.map +1 -0
- package/dist/compute/errors.d.ts +18 -0
- package/dist/compute/errors.d.ts.map +1 -0
- package/dist/compute/errors.js +21 -0
- package/dist/compute/errors.js.map +1 -0
- package/dist/compute/evict-changed-servers.d.ts +22 -0
- package/dist/compute/evict-changed-servers.d.ts.map +1 -0
- package/dist/compute/evict-changed-servers.js +31 -0
- package/dist/compute/evict-changed-servers.js.map +1 -0
- package/dist/compute/idempotency-http.d.ts +47 -0
- package/dist/compute/idempotency-http.d.ts.map +1 -0
- package/dist/compute/idempotency-http.js +51 -0
- package/dist/compute/idempotency-http.js.map +1 -0
- package/dist/compute/index.d.ts +5 -0
- package/dist/compute/index.d.ts.map +1 -1
- package/dist/compute/index.js +5 -0
- package/dist/compute/index.js.map +1 -1
- package/dist/compute/resolve-server.d.ts +25 -0
- package/dist/compute/resolve-server.d.ts.map +1 -0
- package/dist/compute/resolve-server.js +35 -0
- package/dist/compute/resolve-server.js.map +1 -0
- package/dist/compute/server-config-write.d.ts +52 -0
- package/dist/compute/server-config-write.d.ts.map +1 -0
- package/dist/compute/server-config-write.js +100 -0
- package/dist/compute/server-config-write.js.map +1 -0
- package/dist/definitions/index.d.ts +1 -0
- package/dist/definitions/index.d.ts.map +1 -1
- package/dist/definitions/index.js +1 -0
- package/dist/definitions/index.js.map +1 -1
- package/dist/definitions/visibility.d.ts +74 -0
- package/dist/definitions/visibility.d.ts.map +1 -0
- package/dist/definitions/visibility.js +117 -0
- package/dist/definitions/visibility.js.map +1 -0
- package/dist/handlers/definitionVersions.d.ts +30 -0
- package/dist/handlers/definitionVersions.d.ts.map +1 -0
- package/dist/handlers/definitionVersions.js +93 -0
- package/dist/handlers/definitionVersions.js.map +1 -0
- package/dist/handlers/definitions.d.ts +35 -0
- package/dist/handlers/definitions.d.ts.map +1 -0
- package/dist/handlers/definitions.js +207 -0
- package/dist/handlers/definitions.js.map +1 -0
- package/dist/handlers/index.d.ts +27 -0
- package/dist/handlers/index.d.ts.map +1 -0
- package/dist/handlers/index.js +29 -0
- package/dist/handlers/index.js.map +1 -0
- package/dist/handlers/invite-lookup.d.ts +11 -0
- package/dist/handlers/invite-lookup.d.ts.map +1 -0
- package/dist/handlers/invite-lookup.js +20 -0
- package/dist/handlers/invite-lookup.js.map +1 -0
- package/dist/handlers/invites.d.ts +31 -0
- package/dist/handlers/invites.d.ts.map +1 -0
- package/dist/handlers/invites.js +148 -0
- package/dist/handlers/invites.js.map +1 -0
- package/dist/handlers/me.d.ts +8 -0
- package/dist/handlers/me.d.ts.map +1 -0
- package/dist/handlers/me.js +21 -0
- package/dist/handlers/me.js.map +1 -0
- package/dist/handlers/me.starred.d.ts +11 -0
- package/dist/handlers/me.starred.d.ts.map +1 -0
- package/dist/handlers/me.starred.js +21 -0
- package/dist/handlers/me.starred.js.map +1 -0
- package/dist/handlers/orgAssets.d.ts +13 -0
- package/dist/handlers/orgAssets.d.ts.map +1 -0
- package/dist/handlers/orgAssets.js +54 -0
- package/dist/handlers/orgAssets.js.map +1 -0
- package/dist/handlers/orgCompute.d.ts +16 -0
- package/dist/handlers/orgCompute.d.ts.map +1 -0
- package/dist/handlers/orgCompute.js +96 -0
- package/dist/handlers/orgCompute.js.map +1 -0
- package/dist/handlers/orgMembers.d.ts +29 -0
- package/dist/handlers/orgMembers.d.ts.map +1 -0
- package/dist/handlers/orgMembers.js +200 -0
- package/dist/handlers/orgMembers.js.map +1 -0
- package/dist/handlers/orgs.d.ts +16 -0
- package/dist/handlers/orgs.d.ts.map +1 -0
- package/dist/handlers/orgs.js +26 -0
- package/dist/handlers/orgs.js.map +1 -0
- package/dist/handlers/projectMembers.d.ts +15 -0
- package/dist/handlers/projectMembers.d.ts.map +1 -0
- package/dist/handlers/projectMembers.js +95 -0
- package/dist/handlers/projectMembers.js.map +1 -0
- package/dist/handlers/projects.d.ts +21 -0
- package/dist/handlers/projects.d.ts.map +1 -0
- package/dist/handlers/projects.js +164 -0
- package/dist/handlers/projects.js.map +1 -0
- package/dist/handlers/reclaim.d.ts +10 -0
- package/dist/handlers/reclaim.d.ts.map +1 -0
- package/dist/handlers/reclaim.js +38 -0
- package/dist/handlers/reclaim.js.map +1 -0
- package/dist/handlers/services.d.ts +22 -0
- package/dist/handlers/services.d.ts.map +1 -0
- package/dist/handlers/services.js +37 -0
- package/dist/handlers/services.js.map +1 -0
- package/dist/handlers/shareLinks.d.ts +23 -0
- package/dist/handlers/shareLinks.d.ts.map +1 -0
- package/dist/handlers/shareLinks.js +85 -0
- package/dist/handlers/shareLinks.js.map +1 -0
- package/dist/http/index.d.ts +1 -0
- package/dist/http/index.d.ts.map +1 -1
- package/dist/http/index.js +1 -0
- package/dist/http/index.js.map +1 -1
- package/dist/http/login-rate-limit.d.ts +72 -0
- package/dist/http/login-rate-limit.d.ts.map +1 -0
- package/dist/http/login-rate-limit.js +84 -0
- package/dist/http/login-rate-limit.js.map +1 -0
- package/dist/notifications/deliver-invite.d.ts +27 -0
- package/dist/notifications/deliver-invite.d.ts.map +1 -0
- package/dist/notifications/deliver-invite.js +32 -0
- package/dist/notifications/deliver-invite.js.map +1 -0
- package/dist/notifications/index.d.ts +4 -0
- package/dist/notifications/index.d.ts.map +1 -0
- package/dist/notifications/index.js +4 -0
- package/dist/notifications/index.js.map +1 -0
- package/dist/notifications/smtp-config.d.ts +37 -0
- package/dist/notifications/smtp-config.d.ts.map +1 -0
- package/dist/notifications/smtp-config.js +41 -0
- package/dist/notifications/smtp-config.js.map +1 -0
- package/dist/notifications/smtp-provider.d.ts +18 -0
- package/dist/notifications/smtp-provider.d.ts.map +1 -0
- package/dist/notifications/smtp-provider.js +71 -0
- package/dist/notifications/smtp-provider.js.map +1 -0
- package/dist/ops/deploymentConfig.d.ts +73 -0
- package/dist/ops/deploymentConfig.d.ts.map +1 -0
- package/dist/ops/deploymentConfig.js +154 -0
- package/dist/ops/deploymentConfig.js.map +1 -0
- package/dist/ops/index.d.ts +1 -0
- package/dist/ops/index.d.ts.map +1 -1
- package/dist/ops/index.js +3 -2
- package/dist/ops/index.js.map +1 -1
- package/dist/organizations/index.d.ts +3 -0
- package/dist/organizations/index.d.ts.map +1 -0
- package/dist/organizations/index.js +5 -0
- package/dist/organizations/index.js.map +1 -0
- package/dist/organizations/list-all-members.d.ts +10 -0
- package/dist/organizations/list-all-members.d.ts.map +1 -0
- package/dist/organizations/list-all-members.js +36 -0
- package/dist/organizations/list-all-members.js.map +1 -0
- package/dist/organizations/org-asset-service.d.ts +39 -0
- package/dist/organizations/org-asset-service.d.ts.map +1 -0
- package/dist/organizations/org-asset-service.js +71 -0
- package/dist/organizations/org-asset-service.js.map +1 -0
- package/dist/projects/create-project.d.ts +30 -0
- package/dist/projects/create-project.d.ts.map +1 -0
- package/dist/projects/create-project.js +56 -0
- package/dist/projects/create-project.js.map +1 -0
- package/dist/projects/index.d.ts +2 -0
- package/dist/projects/index.d.ts.map +1 -0
- package/dist/projects/index.js +3 -0
- package/dist/projects/index.js.map +1 -0
- package/dist/providers/auth-lookup.d.ts +14 -0
- package/dist/providers/auth-lookup.d.ts.map +1 -0
- package/dist/providers/auth-lookup.js +34 -0
- package/dist/providers/auth-lookup.js.map +1 -0
- package/dist/providers/index.d.ts +1 -0
- package/dist/providers/index.d.ts.map +1 -1
- package/dist/providers/index.js +1 -0
- package/dist/providers/index.js.map +1 -1
- package/dist/testing/harness.d.ts +168 -0
- package/dist/testing/harness.d.ts.map +1 -0
- package/dist/testing/harness.js +314 -0
- package/dist/testing/harness.js.map +1 -0
- package/dist/testing/index.d.ts +18 -0
- package/dist/testing/index.d.ts.map +1 -0
- package/dist/testing/index.js +15 -0
- package/dist/testing/index.js.map +1 -0
- package/dist/testing/scenarios.d.ts +67 -0
- package/dist/testing/scenarios.d.ts.map +1 -0
- package/dist/testing/scenarios.js +104 -0
- package/dist/testing/scenarios.js.map +1 -0
- package/dist/testing/seed-adapter.d.ts +31 -0
- package/dist/testing/seed-adapter.d.ts.map +1 -0
- package/dist/testing/seed-adapter.js +19 -0
- package/dist/testing/seed-adapter.js.map +1 -0
- package/package.json +42 -3
|
@@ -0,0 +1,51 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* The HTTP layer over {@link createIdempotencyStore}: how a replayed response
|
|
3
|
+
* is keyed, snapshotted, and identified on the wire.
|
|
4
|
+
*
|
|
5
|
+
* The store itself is generic over `T` and knows nothing about requests. This
|
|
6
|
+
* is the part two hosts must agree on to implement the same `Idempotency-Key`
|
|
7
|
+
* contract, and the part each would otherwise reinvent:
|
|
8
|
+
*
|
|
9
|
+
* - **The key namespaces by caller.** `Idempotency-Key` is client-chosen, so
|
|
10
|
+
* two tenants can pick the same string. Without the caller in the key one
|
|
11
|
+
* would replay the other's result — that is the whole security property
|
|
12
|
+
* here, and a host that got it wrong would leak across tenants with
|
|
13
|
+
* nothing failing at build time.
|
|
14
|
+
* - **The response round-trips through a snapshot.** A `Response` body reads
|
|
15
|
+
* exactly once, so storing the object itself replays an empty body.
|
|
16
|
+
* - **A replay says so**, via `Idempotency-Replayed`. A client that cannot
|
|
17
|
+
* tell a replay from a fresh run cannot tell a successful retry from a
|
|
18
|
+
* second execution.
|
|
19
|
+
*
|
|
20
|
+
* How long a response stays replayable is *not* here: that trades a client's
|
|
21
|
+
* retry window against serving a stale result after the underlying resource
|
|
22
|
+
* moves, and only the host knows its own deadlines.
|
|
23
|
+
*/
|
|
24
|
+
/** Header stamped on a replayed response, so a client can distinguish one. */
|
|
25
|
+
export const IDEMPOTENCY_REPLAYED_HEADER = 'Idempotency-Replayed';
|
|
26
|
+
/**
|
|
27
|
+
* Namespace a client-chosen key by its caller.
|
|
28
|
+
*
|
|
29
|
+
* `callerId` should be the narrowest identity available — a token id rather
|
|
30
|
+
* than a user id where the host issues per-token credentials, so two tokens
|
|
31
|
+
* held by one user do not share replays.
|
|
32
|
+
*/
|
|
33
|
+
export function idempotencyKey(callerId, clientKey) {
|
|
34
|
+
return `${callerId} ${clientKey}`;
|
|
35
|
+
}
|
|
36
|
+
/** Flatten a response so it can be replayed. Consumes the body. */
|
|
37
|
+
export async function toStoredResponse(res) {
|
|
38
|
+
return {
|
|
39
|
+
status: res.status,
|
|
40
|
+
headers: [...res.headers.entries()],
|
|
41
|
+
body: await res.arrayBuffer()
|
|
42
|
+
};
|
|
43
|
+
}
|
|
44
|
+
/** Rebuild a live `Response` from a snapshot, marking it when it is a replay. */
|
|
45
|
+
export function fromStoredResponse(stored, replayed) {
|
|
46
|
+
const headers = new Headers(stored.headers);
|
|
47
|
+
if (replayed)
|
|
48
|
+
headers.set(IDEMPOTENCY_REPLAYED_HEADER, 'true');
|
|
49
|
+
return new Response(stored.body, { status: stored.status, headers });
|
|
50
|
+
}
|
|
51
|
+
//# sourceMappingURL=idempotency-http.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"idempotency-http.js","sourceRoot":"","sources":["../../src/compute/idempotency-http.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;;;;;;;;GAsBG;AAEH,8EAA8E;AAC9E,MAAM,CAAC,MAAM,2BAA2B,GAAG,sBAAsB,CAAC;AAYlE;;;;;;GAMG;AACH,MAAM,UAAU,cAAc,CAAC,QAAgB,EAAE,SAAiB;IACjE,OAAO,GAAG,QAAQ,IAAI,SAAS,EAAE,CAAC;AACnC,CAAC;AAED,mEAAmE;AACnE,MAAM,CAAC,KAAK,UAAU,gBAAgB,CAAC,GAAa;IACnD,OAAO;QACN,MAAM,EAAE,GAAG,CAAC,MAAM;QAClB,OAAO,EAAE,CAAC,GAAG,GAAG,CAAC,OAAO,CAAC,OAAO,EAAE,CAAC;QACnC,IAAI,EAAE,MAAM,GAAG,CAAC,WAAW,EAAE;KAC7B,CAAC;AACH,CAAC;AAED,iFAAiF;AACjF,MAAM,UAAU,kBAAkB,CAAC,MAAsB,EAAE,QAAiB;IAC3E,MAAM,OAAO,GAAG,IAAI,OAAO,CAAC,MAAM,CAAC,OAAO,CAAC,CAAC;IAC5C,IAAI,QAAQ;QAAE,OAAO,CAAC,GAAG,CAAC,2BAA2B,EAAE,MAAM,CAAC,CAAC;IAC/D,OAAO,IAAI,QAAQ,CAAC,MAAM,CAAC,IAAI,EAAE,EAAE,MAAM,EAAE,MAAM,CAAC,MAAM,EAAE,OAAO,EAAE,CAAC,CAAC;AACtE,CAAC"}
|
package/dist/compute/index.d.ts
CHANGED
|
@@ -3,4 +3,9 @@ export { createComputeRateLimiter, DEFAULT_MAX_KEYS, type ComputeRateLimiter, ty
|
|
|
3
3
|
export { createIdempotencyStore, DEFAULT_IDEMPOTENCY_MAX_KEYS, type IdempotencyStore, type IdempotencyStoreConfig, type IdempotencyOutcome } from './idempotency.js';
|
|
4
4
|
export { isSafeRemoteDefinitionUrl, assertSafeRemoteDefinitionUrl, isLinkLocalUrl } from './safe-url.js';
|
|
5
5
|
export { createRemoteDefinitionFetcher, readBodyWithCap, type RemoteDefinitionFetcher, type RemoteDefinitionConfig } from './remote-definition.js';
|
|
6
|
+
export { resolveServerForOrg } from './resolve-server.js';
|
|
7
|
+
export { ComputeServerUnconfiguredError } from './errors.js';
|
|
8
|
+
export { evictChangedServers, type ServerConnection } from './evict-changed-servers.js';
|
|
9
|
+
export { validateIncomingServers, resolveApiKey, storedKeysById, type IncomingServerBase } from './server-config-write.js';
|
|
10
|
+
export { idempotencyKey, toStoredResponse, fromStoredResponse, IDEMPOTENCY_REPLAYED_HEADER, type StoredResponse } from './idempotency-http.js';
|
|
6
11
|
//# sourceMappingURL=index.d.ts.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../src/compute/index.ts"],"names":[],"mappings":"AAWA,OAAO,EACN,oBAAoB,EACpB,eAAe,EACf,kBAAkB,EAClB,QAAQ,EACR,KAAK,aAAa,EAClB,KAAK,SAAS,EACd,MAAM,aAAa,CAAC;AAErB,OAAO,EACN,wBAAwB,EACxB,gBAAgB,EAChB,KAAK,kBAAkB,EACvB,KAAK,wBAAwB,EAC7B,KAAK,eAAe,EACpB,MAAM,iBAAiB,CAAC;AAEzB,OAAO,EACN,sBAAsB,EACtB,4BAA4B,EAC5B,KAAK,gBAAgB,EACrB,KAAK,sBAAsB,EAC3B,KAAK,kBAAkB,EACvB,MAAM,kBAAkB,CAAC;AAE1B,OAAO,EACN,yBAAyB,EACzB,6BAA6B,EAC7B,cAAc,EACd,MAAM,eAAe,CAAC;AAEvB,OAAO,EACN,6BAA6B,EAC7B,eAAe,EACf,KAAK,uBAAuB,EAC5B,KAAK,sBAAsB,EAC3B,MAAM,wBAAwB,CAAC"}
|
|
1
|
+
{"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../src/compute/index.ts"],"names":[],"mappings":"AAWA,OAAO,EACN,oBAAoB,EACpB,eAAe,EACf,kBAAkB,EAClB,QAAQ,EACR,KAAK,aAAa,EAClB,KAAK,SAAS,EACd,MAAM,aAAa,CAAC;AAErB,OAAO,EACN,wBAAwB,EACxB,gBAAgB,EAChB,KAAK,kBAAkB,EACvB,KAAK,wBAAwB,EAC7B,KAAK,eAAe,EACpB,MAAM,iBAAiB,CAAC;AAEzB,OAAO,EACN,sBAAsB,EACtB,4BAA4B,EAC5B,KAAK,gBAAgB,EACrB,KAAK,sBAAsB,EAC3B,KAAK,kBAAkB,EACvB,MAAM,kBAAkB,CAAC;AAE1B,OAAO,EACN,yBAAyB,EACzB,6BAA6B,EAC7B,cAAc,EACd,MAAM,eAAe,CAAC;AAEvB,OAAO,EACN,6BAA6B,EAC7B,eAAe,EACf,KAAK,uBAAuB,EAC5B,KAAK,sBAAsB,EAC3B,MAAM,wBAAwB,CAAC;AAEhC,OAAO,EAAE,mBAAmB,EAAE,MAAM,qBAAqB,CAAC;AAC1D,OAAO,EAAE,8BAA8B,EAAE,MAAM,aAAa,CAAC;AAC7D,OAAO,EAAE,mBAAmB,EAAE,KAAK,gBAAgB,EAAE,MAAM,4BAA4B,CAAC;AACxF,OAAO,EACN,uBAAuB,EACvB,aAAa,EACb,cAAc,EACd,KAAK,kBAAkB,EACvB,MAAM,0BAA0B,CAAC;AAClC,OAAO,EACN,cAAc,EACd,gBAAgB,EAChB,kBAAkB,EAClB,2BAA2B,EAC3B,KAAK,cAAc,EACnB,MAAM,uBAAuB,CAAC"}
|
package/dist/compute/index.js
CHANGED
|
@@ -13,4 +13,9 @@ export { createComputeRateLimiter, DEFAULT_MAX_KEYS } from './rate-limit.js';
|
|
|
13
13
|
export { createIdempotencyStore, DEFAULT_IDEMPOTENCY_MAX_KEYS } from './idempotency.js';
|
|
14
14
|
export { isSafeRemoteDefinitionUrl, assertSafeRemoteDefinitionUrl, isLinkLocalUrl } from './safe-url.js';
|
|
15
15
|
export { createRemoteDefinitionFetcher, readBodyWithCap } from './remote-definition.js';
|
|
16
|
+
export { resolveServerForOrg } from './resolve-server.js';
|
|
17
|
+
export { ComputeServerUnconfiguredError } from './errors.js';
|
|
18
|
+
export { evictChangedServers } from './evict-changed-servers.js';
|
|
19
|
+
export { validateIncomingServers, resolveApiKey, storedKeysById } from './server-config-write.js';
|
|
20
|
+
export { idempotencyKey, toStoredResponse, fromStoredResponse, IDEMPOTENCY_REPLAYED_HEADER } from './idempotency-http.js';
|
|
16
21
|
//# sourceMappingURL=index.js.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"index.js","sourceRoot":"","sources":["../../src/compute/index.ts"],"names":[],"mappings":"AAAA,+EAA+E;AAC/E,EAAE;AACF,kGAAkG;AAClG,mGAAmG;AACnG,oBAAoB;AACpB,EAAE;AACF,6FAA6F;AAC7F,6FAA6F;AAC7F,8FAA8F;AAC9F,qCAAqC;AAErC,OAAO,EACN,oBAAoB,EACpB,eAAe,EACf,kBAAkB,EAClB,QAAQ,EAGR,MAAM,aAAa,CAAC;AAErB,OAAO,EACN,wBAAwB,EACxB,gBAAgB,EAIhB,MAAM,iBAAiB,CAAC;AAEzB,OAAO,EACN,sBAAsB,EACtB,4BAA4B,EAI5B,MAAM,kBAAkB,CAAC;AAE1B,OAAO,EACN,yBAAyB,EACzB,6BAA6B,EAC7B,cAAc,EACd,MAAM,eAAe,CAAC;AAEvB,OAAO,EACN,6BAA6B,EAC7B,eAAe,EAGf,MAAM,wBAAwB,CAAC"}
|
|
1
|
+
{"version":3,"file":"index.js","sourceRoot":"","sources":["../../src/compute/index.ts"],"names":[],"mappings":"AAAA,+EAA+E;AAC/E,EAAE;AACF,kGAAkG;AAClG,mGAAmG;AACnG,oBAAoB;AACpB,EAAE;AACF,6FAA6F;AAC7F,6FAA6F;AAC7F,8FAA8F;AAC9F,qCAAqC;AAErC,OAAO,EACN,oBAAoB,EACpB,eAAe,EACf,kBAAkB,EAClB,QAAQ,EAGR,MAAM,aAAa,CAAC;AAErB,OAAO,EACN,wBAAwB,EACxB,gBAAgB,EAIhB,MAAM,iBAAiB,CAAC;AAEzB,OAAO,EACN,sBAAsB,EACtB,4BAA4B,EAI5B,MAAM,kBAAkB,CAAC;AAE1B,OAAO,EACN,yBAAyB,EACzB,6BAA6B,EAC7B,cAAc,EACd,MAAM,eAAe,CAAC;AAEvB,OAAO,EACN,6BAA6B,EAC7B,eAAe,EAGf,MAAM,wBAAwB,CAAC;AAEhC,OAAO,EAAE,mBAAmB,EAAE,MAAM,qBAAqB,CAAC;AAC1D,OAAO,EAAE,8BAA8B,EAAE,MAAM,aAAa,CAAC;AAC7D,OAAO,EAAE,mBAAmB,EAAyB,MAAM,4BAA4B,CAAC;AACxF,OAAO,EACN,uBAAuB,EACvB,aAAa,EACb,cAAc,EAEd,MAAM,0BAA0B,CAAC;AAClC,OAAO,EACN,cAAc,EACd,gBAAgB,EAChB,kBAAkB,EAClB,2BAA2B,EAE3B,MAAM,uBAAuB,CAAC"}
|
|
@@ -0,0 +1,25 @@
|
|
|
1
|
+
import { type ComputeServerConfig, type IDataProvider, type RequestContext } from '@selvajs/platform';
|
|
2
|
+
import { ComputeServerUnconfiguredError } from './errors.js';
|
|
3
|
+
export { ComputeServerUnconfiguredError };
|
|
4
|
+
/** The one store this module reads — `SelvaDeps['computeServer']`. */
|
|
5
|
+
type ComputeServerStore = IDataProvider['computeServer'];
|
|
6
|
+
/**
|
|
7
|
+
* Pick the right Rhino.Compute server for an (org, definition) pair.
|
|
8
|
+
*
|
|
9
|
+
* Resolution order, narrowest wins:
|
|
10
|
+
* 1. `definitionPin` if it points at a server visible to `orgId`.
|
|
11
|
+
* 2. `orgDefaults[orgId]` if set and visible.
|
|
12
|
+
* 3. Global `defaultServerId`.
|
|
13
|
+
*
|
|
14
|
+
* The store returns the full config; the visibility predicate runs in the pure
|
|
15
|
+
* helper so callers don't reimplement it. Re-throws the pure helper's "nothing
|
|
16
|
+
* visible" failure as a typed `ComputeServerUnconfiguredError`.
|
|
17
|
+
*
|
|
18
|
+
* Reads a key-free config and fetches the `apiKey` only for the server that
|
|
19
|
+
* actually wins, instead of decrypting every configured server's key to use
|
|
20
|
+
* exactly one of them.
|
|
21
|
+
*/
|
|
22
|
+
export declare function resolveServerForOrg(ctx: RequestContext, orgId: string | null | undefined, store: ComputeServerStore, opts?: {
|
|
23
|
+
definitionPin?: string | null;
|
|
24
|
+
}): Promise<ComputeServerConfig>;
|
|
25
|
+
//# sourceMappingURL=resolve-server.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"resolve-server.d.ts","sourceRoot":"","sources":["../../src/compute/resolve-server.ts"],"names":[],"mappings":"AAAA,OAAO,EAEN,KAAK,mBAAmB,EACxB,KAAK,aAAa,EAClB,KAAK,cAAc,EACnB,MAAM,mBAAmB,CAAC;AAC3B,OAAO,EAAE,8BAA8B,EAAE,MAAM,aAAa,CAAC;AAI7D,OAAO,EAAE,8BAA8B,EAAE,CAAC;AAE1C,sEAAsE;AACtE,KAAK,kBAAkB,GAAG,aAAa,CAAC,eAAe,CAAC,CAAC;AAEzD;;;;;;;;;;;;;;;GAeG;AACH,wBAAsB,mBAAmB,CACxC,GAAG,EAAE,cAAc,EACnB,KAAK,EAAE,MAAM,GAAG,IAAI,GAAG,SAAS,EAChC,KAAK,EAAE,kBAAkB,EACzB,IAAI,GAAE;IAAE,aAAa,CAAC,EAAE,MAAM,GAAG,IAAI,CAAA;CAAO,GAC1C,OAAO,CAAC,mBAAmB,CAAC,CAU9B"}
|
|
@@ -0,0 +1,35 @@
|
|
|
1
|
+
import { resolveServerForOrg as resolvePure } from '@selvajs/platform';
|
|
2
|
+
import { ComputeServerUnconfiguredError } from './errors.js';
|
|
3
|
+
// Re-exported so the throw site and the class still read as one unit. Error
|
|
4
|
+
// mappers should import from `./errors.js` directly.
|
|
5
|
+
export { ComputeServerUnconfiguredError };
|
|
6
|
+
/**
|
|
7
|
+
* Pick the right Rhino.Compute server for an (org, definition) pair.
|
|
8
|
+
*
|
|
9
|
+
* Resolution order, narrowest wins:
|
|
10
|
+
* 1. `definitionPin` if it points at a server visible to `orgId`.
|
|
11
|
+
* 2. `orgDefaults[orgId]` if set and visible.
|
|
12
|
+
* 3. Global `defaultServerId`.
|
|
13
|
+
*
|
|
14
|
+
* The store returns the full config; the visibility predicate runs in the pure
|
|
15
|
+
* helper so callers don't reimplement it. Re-throws the pure helper's "nothing
|
|
16
|
+
* visible" failure as a typed `ComputeServerUnconfiguredError`.
|
|
17
|
+
*
|
|
18
|
+
* Reads a key-free config and fetches the `apiKey` only for the server that
|
|
19
|
+
* actually wins, instead of decrypting every configured server's key to use
|
|
20
|
+
* exactly one of them.
|
|
21
|
+
*/
|
|
22
|
+
export async function resolveServerForOrg(ctx, orgId, store, opts = {}) {
|
|
23
|
+
const config = await store.getConfig(ctx);
|
|
24
|
+
let server;
|
|
25
|
+
try {
|
|
26
|
+
server = resolvePure(config, orgId, { definitionPin: opts.definitionPin });
|
|
27
|
+
}
|
|
28
|
+
catch (err) {
|
|
29
|
+
throw new ComputeServerUnconfiguredError(err instanceof Error ? err.message : undefined);
|
|
30
|
+
}
|
|
31
|
+
if (!server.hasApiKey)
|
|
32
|
+
return server;
|
|
33
|
+
return { ...server, apiKey: await store.getServerApiKey(ctx, server.id) };
|
|
34
|
+
}
|
|
35
|
+
//# sourceMappingURL=resolve-server.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"resolve-server.js","sourceRoot":"","sources":["../../src/compute/resolve-server.ts"],"names":[],"mappings":"AAAA,OAAO,EACN,mBAAmB,IAAI,WAAW,EAIlC,MAAM,mBAAmB,CAAC;AAC3B,OAAO,EAAE,8BAA8B,EAAE,MAAM,aAAa,CAAC;AAE7D,4EAA4E;AAC5E,qDAAqD;AACrD,OAAO,EAAE,8BAA8B,EAAE,CAAC;AAK1C;;;;;;;;;;;;;;;GAeG;AACH,MAAM,CAAC,KAAK,UAAU,mBAAmB,CACxC,GAAmB,EACnB,KAAgC,EAChC,KAAyB,EACzB,OAA0C,EAAE;IAE5C,MAAM,MAAM,GAAG,MAAM,KAAK,CAAC,SAAS,CAAC,GAAG,CAAC,CAAC;IAC1C,IAAI,MAA2B,CAAC;IAChC,IAAI,CAAC;QACJ,MAAM,GAAG,WAAW,CAAC,MAAM,EAAE,KAAK,EAAE,EAAE,aAAa,EAAE,IAAI,CAAC,aAAa,EAAE,CAAC,CAAC;IAC5E,CAAC;IAAC,OAAO,GAAG,EAAE,CAAC;QACd,MAAM,IAAI,8BAA8B,CAAC,GAAG,YAAY,KAAK,CAAC,CAAC,CAAC,GAAG,CAAC,OAAO,CAAC,CAAC,CAAC,SAAS,CAAC,CAAC;IAC1F,CAAC;IACD,IAAI,CAAC,MAAM,CAAC,SAAS;QAAE,OAAO,MAAM,CAAC;IACrC,OAAO,EAAE,GAAG,MAAM,EAAE,MAAM,EAAE,MAAM,KAAK,CAAC,eAAe,CAAC,GAAG,EAAE,MAAM,CAAC,EAAE,CAAC,EAAE,CAAC;AAC3E,CAAC"}
|
|
@@ -0,0 +1,52 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Shared write-path rules for compute server config.
|
|
3
|
+
*
|
|
4
|
+
* Two routes accept a server set: `/api/admin/compute` (platform scope,
|
|
5
|
+
* `manage_compute`) and `/api/v1/orgs/{orgId}/compute` (org scope,
|
|
6
|
+
* `manage_org_compute`). They differ in who may call them, what extra fields
|
|
7
|
+
* they carry (`sharedWith` vs `ownerOrgId`), and how they validate the default
|
|
8
|
+
* selection — but the field validation and the apiKey merge below must behave
|
|
9
|
+
* identically in both, so they live here rather than in either handler.
|
|
10
|
+
*
|
|
11
|
+
* The apiKey merge is why this file exists: if the two copies disagree, a
|
|
12
|
+
* stored credential silently gets cleared or leaked, and nothing fails at
|
|
13
|
+
* build time.
|
|
14
|
+
*/
|
|
15
|
+
/** The fields every incoming server carries, whatever its scope. */
|
|
16
|
+
export interface IncomingServerBase {
|
|
17
|
+
id: string;
|
|
18
|
+
label: string;
|
|
19
|
+
serverUrl: string;
|
|
20
|
+
/**
|
|
21
|
+
* `undefined` → preserve the stored key; `null` → clear it;
|
|
22
|
+
* non-empty string → replace it. See {@link resolveApiKey}.
|
|
23
|
+
*/
|
|
24
|
+
apiKey?: string | null;
|
|
25
|
+
timeoutMs?: number;
|
|
26
|
+
retryCount?: number;
|
|
27
|
+
}
|
|
28
|
+
/**
|
|
29
|
+
* Validates the scope-independent fields of every submitted server. Throws the
|
|
30
|
+
* first failure as a 400; scope-specific fields (`sharedWith`, `ownerOrgId`)
|
|
31
|
+
* are the caller's business.
|
|
32
|
+
*/
|
|
33
|
+
export declare function validateIncomingServers(servers: readonly IncomingServerBase[]): void;
|
|
34
|
+
/**
|
|
35
|
+
* The UI never receives stored keys — it sends back `hasApiKey` and omits the
|
|
36
|
+
* field for servers the operator didn't touch. So "omitted" cannot mean "clear":
|
|
37
|
+
* it has to preserve, or every save through the settings form would wipe the
|
|
38
|
+
* keys of every server the operator left alone. Clearing is explicit (`null`);
|
|
39
|
+
* an empty string is treated as "not provided" since that's what an untouched
|
|
40
|
+
* password input submits.
|
|
41
|
+
*/
|
|
42
|
+
export declare function resolveApiKey(submitted: string | null | undefined, storedKey: string | undefined): string | undefined;
|
|
43
|
+
/**
|
|
44
|
+
* Builds the id → stored-key lookup the merge reads. The caller passes only the
|
|
45
|
+
* servers in its own scope, so one scope's write can never resolve a key from
|
|
46
|
+
* another's rows.
|
|
47
|
+
*/
|
|
48
|
+
export declare function storedKeysById(scopedServers: readonly {
|
|
49
|
+
id: string;
|
|
50
|
+
apiKey?: string;
|
|
51
|
+
}[]): Map<string, string | undefined>;
|
|
52
|
+
//# sourceMappingURL=server-config-write.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"server-config-write.d.ts","sourceRoot":"","sources":["../../src/compute/server-config-write.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;GAaG;AAqDH,oEAAoE;AACpE,MAAM,WAAW,kBAAkB;IAClC,EAAE,EAAE,MAAM,CAAC;IACX,KAAK,EAAE,MAAM,CAAC;IACd,SAAS,EAAE,MAAM,CAAC;IAClB;;;OAGG;IACH,MAAM,CAAC,EAAE,MAAM,GAAG,IAAI,CAAC;IACvB,SAAS,CAAC,EAAE,MAAM,CAAC;IACnB,UAAU,CAAC,EAAE,MAAM,CAAC;CACpB;AAED;;;;GAIG;AACH,wBAAgB,uBAAuB,CAAC,OAAO,EAAE,SAAS,kBAAkB,EAAE,GAAG,IAAI,CAYpF;AAED;;;;;;;GAOG;AACH,wBAAgB,aAAa,CAC5B,SAAS,EAAE,MAAM,GAAG,IAAI,GAAG,SAAS,EACpC,SAAS,EAAE,MAAM,GAAG,SAAS,GAC3B,MAAM,GAAG,SAAS,CAGpB;AAED;;;;GAIG;AACH,wBAAgB,cAAc,CAC7B,aAAa,EAAE,SAAS;IAAE,EAAE,EAAE,MAAM,CAAC;IAAC,MAAM,CAAC,EAAE,MAAM,CAAA;CAAE,EAAE,GACvD,GAAG,CAAC,MAAM,EAAE,MAAM,GAAG,SAAS,CAAC,CAEjC"}
|
|
@@ -0,0 +1,100 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Shared write-path rules for compute server config.
|
|
3
|
+
*
|
|
4
|
+
* Two routes accept a server set: `/api/admin/compute` (platform scope,
|
|
5
|
+
* `manage_compute`) and `/api/v1/orgs/{orgId}/compute` (org scope,
|
|
6
|
+
* `manage_org_compute`). They differ in who may call them, what extra fields
|
|
7
|
+
* they carry (`sharedWith` vs `ownerOrgId`), and how they validate the default
|
|
8
|
+
* selection — but the field validation and the apiKey merge below must behave
|
|
9
|
+
* identically in both, so they live here rather than in either handler.
|
|
10
|
+
*
|
|
11
|
+
* The apiKey merge is why this file exists: if the two copies disagree, a
|
|
12
|
+
* stored credential silently gets cleared or leaked, and nothing fails at
|
|
13
|
+
* build time.
|
|
14
|
+
*/
|
|
15
|
+
import { isLinkLocalUrl } from './safe-url.js';
|
|
16
|
+
import { apiError, ApiErrorCode } from '../api/errors.js';
|
|
17
|
+
/**
|
|
18
|
+
* A stored `serverUrl` is fetched server-side on every status probe, every
|
|
19
|
+
* purge/shutdown action, and every solve, so an unfiltered one is an SSRF
|
|
20
|
+
* primitive handed to whoever holds `manage_compute`. Two rules:
|
|
21
|
+
*
|
|
22
|
+
* - Scheme allowlist: `http`/`https`. `file:`, `gopher:` and friends are never
|
|
23
|
+
* a Rhino.Compute endpoint.
|
|
24
|
+
* - Link-local (`169.254.0.0/16`) is refused. That range carries the cloud
|
|
25
|
+
* metadata service at `169.254.169.254`, which hands out the host's own IAM
|
|
26
|
+
* credentials to anything running on the box.
|
|
27
|
+
*
|
|
28
|
+
* **Loopback and RFC1918 are deliberately allowed.** Running compute on
|
|
29
|
+
* `localhost:6500` or a LAN box is the ordinary self-hosted layout, not an
|
|
30
|
+
* attack — most deployments reach their compute server over exactly those
|
|
31
|
+
* addresses. Blocking them by default would break those instances on upgrade
|
|
32
|
+
* and push every operator toward an opt-out flag, and a guard that everyone
|
|
33
|
+
* disables protects nobody. So the check is narrowed to the range where no
|
|
34
|
+
* legitimate compute server ever lives.
|
|
35
|
+
*
|
|
36
|
+
* What this does not stop: a privileged admin pointing the app at an internal
|
|
37
|
+
* host to probe it. That is a real but much weaker concern than credential
|
|
38
|
+
* theft, it needs `manage_compute` already, and it is inseparable from the
|
|
39
|
+
* legitimate case. Revisit if `manage_org_compute` is ever delegated widely on
|
|
40
|
+
* a multi-tenant instance.
|
|
41
|
+
*
|
|
42
|
+
* `isLinkLocalUrl` is reused rather than hand-rolled because a string compare
|
|
43
|
+
* against `169.254.169.254` misses the encodings that reach the same address:
|
|
44
|
+
* `http://2852039166/`, `http://0xa9fea9fe/`, `http://0251.0376.0251.0376/`.
|
|
45
|
+
*/
|
|
46
|
+
function assertUsableServerUrl(serverUrl) {
|
|
47
|
+
let parsed;
|
|
48
|
+
try {
|
|
49
|
+
parsed = new URL(serverUrl);
|
|
50
|
+
}
|
|
51
|
+
catch {
|
|
52
|
+
apiError(400, ApiErrorCode.VALIDATION_FAILED, `Invalid serverUrl: ${serverUrl}`);
|
|
53
|
+
}
|
|
54
|
+
if (parsed.protocol !== 'http:' && parsed.protocol !== 'https:') {
|
|
55
|
+
apiError(400, ApiErrorCode.VALIDATION_FAILED, `serverUrl must use http or https: ${serverUrl}`);
|
|
56
|
+
}
|
|
57
|
+
if (isLinkLocalUrl(serverUrl)) {
|
|
58
|
+
apiError(400, ApiErrorCode.VALIDATION_FAILED, `serverUrl points at the link-local range, which carries the cloud metadata service: ${serverUrl}`);
|
|
59
|
+
}
|
|
60
|
+
}
|
|
61
|
+
/**
|
|
62
|
+
* Validates the scope-independent fields of every submitted server. Throws the
|
|
63
|
+
* first failure as a 400; scope-specific fields (`sharedWith`, `ownerOrgId`)
|
|
64
|
+
* are the caller's business.
|
|
65
|
+
*/
|
|
66
|
+
export function validateIncomingServers(servers) {
|
|
67
|
+
for (const s of servers) {
|
|
68
|
+
if (!s.id || typeof s.id !== 'string')
|
|
69
|
+
apiError(400, ApiErrorCode.VALIDATION_FAILED, 'Each server needs an id');
|
|
70
|
+
if (!s.label || typeof s.label !== 'string')
|
|
71
|
+
apiError(400, ApiErrorCode.VALIDATION_FAILED, 'Each server needs a label');
|
|
72
|
+
if (!s.serverUrl || typeof s.serverUrl !== 'string')
|
|
73
|
+
apiError(400, ApiErrorCode.VALIDATION_FAILED, 'Each server needs a serverUrl');
|
|
74
|
+
assertUsableServerUrl(s.serverUrl);
|
|
75
|
+
if (s.apiKey !== undefined && s.apiKey !== null && typeof s.apiKey !== 'string')
|
|
76
|
+
apiError(400, ApiErrorCode.VALIDATION_FAILED, 'apiKey must be a string, null, or omitted');
|
|
77
|
+
}
|
|
78
|
+
}
|
|
79
|
+
/**
|
|
80
|
+
* The UI never receives stored keys — it sends back `hasApiKey` and omits the
|
|
81
|
+
* field for servers the operator didn't touch. So "omitted" cannot mean "clear":
|
|
82
|
+
* it has to preserve, or every save through the settings form would wipe the
|
|
83
|
+
* keys of every server the operator left alone. Clearing is explicit (`null`);
|
|
84
|
+
* an empty string is treated as "not provided" since that's what an untouched
|
|
85
|
+
* password input submits.
|
|
86
|
+
*/
|
|
87
|
+
export function resolveApiKey(submitted, storedKey) {
|
|
88
|
+
if (submitted === null)
|
|
89
|
+
return undefined;
|
|
90
|
+
return submitted ? submitted : storedKey;
|
|
91
|
+
}
|
|
92
|
+
/**
|
|
93
|
+
* Builds the id → stored-key lookup the merge reads. The caller passes only the
|
|
94
|
+
* servers in its own scope, so one scope's write can never resolve a key from
|
|
95
|
+
* another's rows.
|
|
96
|
+
*/
|
|
97
|
+
export function storedKeysById(scopedServers) {
|
|
98
|
+
return new Map(scopedServers.map((s) => [s.id, s.apiKey]));
|
|
99
|
+
}
|
|
100
|
+
//# sourceMappingURL=server-config-write.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"server-config-write.js","sourceRoot":"","sources":["../../src/compute/server-config-write.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;GAaG;AAEH,OAAO,EAAE,cAAc,EAAE,MAAM,eAAe,CAAC;AAC/C,OAAO,EAAE,QAAQ,EAAE,YAAY,EAAE,MAAM,kBAAkB,CAAC;AAE1D;;;;;;;;;;;;;;;;;;;;;;;;;;;;GA4BG;AACH,SAAS,qBAAqB,CAAC,SAAiB;IAC/C,IAAI,MAAW,CAAC;IAChB,IAAI,CAAC;QACJ,MAAM,GAAG,IAAI,GAAG,CAAC,SAAS,CAAC,CAAC;IAC7B,CAAC;IAAC,MAAM,CAAC;QACR,QAAQ,CAAC,GAAG,EAAE,YAAY,CAAC,iBAAiB,EAAE,sBAAsB,SAAS,EAAE,CAAC,CAAC;IAClF,CAAC;IACD,IAAI,MAAM,CAAC,QAAQ,KAAK,OAAO,IAAI,MAAM,CAAC,QAAQ,KAAK,QAAQ,EAAE,CAAC;QACjE,QAAQ,CAAC,GAAG,EAAE,YAAY,CAAC,iBAAiB,EAAE,qCAAqC,SAAS,EAAE,CAAC,CAAC;IACjG,CAAC;IACD,IAAI,cAAc,CAAC,SAAS,CAAC,EAAE,CAAC;QAC/B,QAAQ,CACP,GAAG,EACH,YAAY,CAAC,iBAAiB,EAC9B,uFAAuF,SAAS,EAAE,CAClG,CAAC;IACH,CAAC;AACF,CAAC;AAgBD;;;;GAIG;AACH,MAAM,UAAU,uBAAuB,CAAC,OAAsC;IAC7E,KAAK,MAAM,CAAC,IAAI,OAAO,EAAE,CAAC;QACzB,IAAI,CAAC,CAAC,CAAC,EAAE,IAAI,OAAO,CAAC,CAAC,EAAE,KAAK,QAAQ;YACpC,QAAQ,CAAC,GAAG,EAAE,YAAY,CAAC,iBAAiB,EAAE,yBAAyB,CAAC,CAAC;QAC1E,IAAI,CAAC,CAAC,CAAC,KAAK,IAAI,OAAO,CAAC,CAAC,KAAK,KAAK,QAAQ;YAC1C,QAAQ,CAAC,GAAG,EAAE,YAAY,CAAC,iBAAiB,EAAE,2BAA2B,CAAC,CAAC;QAC5E,IAAI,CAAC,CAAC,CAAC,SAAS,IAAI,OAAO,CAAC,CAAC,SAAS,KAAK,QAAQ;YAClD,QAAQ,CAAC,GAAG,EAAE,YAAY,CAAC,iBAAiB,EAAE,+BAA+B,CAAC,CAAC;QAChF,qBAAqB,CAAC,CAAC,CAAC,SAAS,CAAC,CAAC;QACnC,IAAI,CAAC,CAAC,MAAM,KAAK,SAAS,IAAI,CAAC,CAAC,MAAM,KAAK,IAAI,IAAI,OAAO,CAAC,CAAC,MAAM,KAAK,QAAQ;YAC9E,QAAQ,CAAC,GAAG,EAAE,YAAY,CAAC,iBAAiB,EAAE,2CAA2C,CAAC,CAAC;IAC7F,CAAC;AACF,CAAC;AAED;;;;;;;GAOG;AACH,MAAM,UAAU,aAAa,CAC5B,SAAoC,EACpC,SAA6B;IAE7B,IAAI,SAAS,KAAK,IAAI;QAAE,OAAO,SAAS,CAAC;IACzC,OAAO,SAAS,CAAC,CAAC,CAAC,SAAS,CAAC,CAAC,CAAC,SAAS,CAAC;AAC1C,CAAC;AAED;;;;GAIG;AACH,MAAM,UAAU,cAAc,CAC7B,aAAyD;IAEzD,OAAO,IAAI,GAAG,CAAC,aAAa,CAAC,GAAG,CAAC,CAAC,CAAC,EAAE,EAAE,CAAC,CAAC,CAAC,CAAC,EAAE,EAAE,CAAC,CAAC,MAAM,CAAC,CAAC,CAAC,CAAC;AAC5D,CAAC"}
|
|
@@ -2,4 +2,5 @@ export { DefinitionService, type CreateDefinitionRecord } from './definition-ser
|
|
|
2
2
|
export { fetchSchemaFromCompute, postSchemaFormData, assertSupportedSchemaVersion, assertCamelCaseSchema, readSchemaResults, SchemaExtractionError } from './schema-extraction.js';
|
|
3
3
|
export type { SchemaExtractionResult } from './schema-extraction.js';
|
|
4
4
|
export { createDefinitionLoader, DefinitionLoadError, type DefinitionChannel, type DefinitionLoader, type DefinitionLoaderDeps, type DefinitionLoadErrorKind, type DefinitionLoadOptions, type LoadedDefinition } from './load-for-render.js';
|
|
5
|
+
export { resolveAccessibleProjects, listVisibleDefinitions, getVisibleDefinition, loadVisibleVersion, type VisibilityDeps, type AccessibleProjectSet, type ListVisibleDefinitionsResult } from './visibility.js';
|
|
5
6
|
//# sourceMappingURL=index.d.ts.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../src/definitions/index.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,iBAAiB,EAAE,KAAK,sBAAsB,EAAE,MAAM,yBAAyB,CAAC;AAEzF,OAAO,EACN,sBAAsB,EACtB,kBAAkB,EAClB,4BAA4B,EAC5B,qBAAqB,EACrB,iBAAiB,EACjB,qBAAqB,EACrB,MAAM,wBAAwB,CAAC;AAChC,YAAY,EAAE,sBAAsB,EAAE,MAAM,wBAAwB,CAAC;AAErE,OAAO,EACN,sBAAsB,EACtB,mBAAmB,EACnB,KAAK,iBAAiB,EACtB,KAAK,gBAAgB,EACrB,KAAK,oBAAoB,EACzB,KAAK,uBAAuB,EAC5B,KAAK,qBAAqB,EAC1B,KAAK,gBAAgB,EACrB,MAAM,sBAAsB,CAAC"}
|
|
1
|
+
{"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../src/definitions/index.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,iBAAiB,EAAE,KAAK,sBAAsB,EAAE,MAAM,yBAAyB,CAAC;AAEzF,OAAO,EACN,sBAAsB,EACtB,kBAAkB,EAClB,4BAA4B,EAC5B,qBAAqB,EACrB,iBAAiB,EACjB,qBAAqB,EACrB,MAAM,wBAAwB,CAAC;AAChC,YAAY,EAAE,sBAAsB,EAAE,MAAM,wBAAwB,CAAC;AAErE,OAAO,EACN,sBAAsB,EACtB,mBAAmB,EACnB,KAAK,iBAAiB,EACtB,KAAK,gBAAgB,EACrB,KAAK,oBAAoB,EACzB,KAAK,uBAAuB,EAC5B,KAAK,qBAAqB,EAC1B,KAAK,gBAAgB,EACrB,MAAM,sBAAsB,CAAC;AAE9B,OAAO,EACN,yBAAyB,EACzB,sBAAsB,EACtB,oBAAoB,EACpB,kBAAkB,EAClB,KAAK,cAAc,EACnB,KAAK,oBAAoB,EACzB,KAAK,4BAA4B,EACjC,MAAM,iBAAiB,CAAC"}
|
|
@@ -1,4 +1,5 @@
|
|
|
1
1
|
export { DefinitionService } from './definition-service.js';
|
|
2
2
|
export { fetchSchemaFromCompute, postSchemaFormData, assertSupportedSchemaVersion, assertCamelCaseSchema, readSchemaResults, SchemaExtractionError } from './schema-extraction.js';
|
|
3
3
|
export { createDefinitionLoader, DefinitionLoadError } from './load-for-render.js';
|
|
4
|
+
export { resolveAccessibleProjects, listVisibleDefinitions, getVisibleDefinition, loadVisibleVersion } from './visibility.js';
|
|
4
5
|
//# sourceMappingURL=index.js.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"index.js","sourceRoot":"","sources":["../../src/definitions/index.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,iBAAiB,EAA+B,MAAM,yBAAyB,CAAC;AAEzF,OAAO,EACN,sBAAsB,EACtB,kBAAkB,EAClB,4BAA4B,EAC5B,qBAAqB,EACrB,iBAAiB,EACjB,qBAAqB,EACrB,MAAM,wBAAwB,CAAC;AAGhC,OAAO,EACN,sBAAsB,EACtB,mBAAmB,EAOnB,MAAM,sBAAsB,CAAC"}
|
|
1
|
+
{"version":3,"file":"index.js","sourceRoot":"","sources":["../../src/definitions/index.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,iBAAiB,EAA+B,MAAM,yBAAyB,CAAC;AAEzF,OAAO,EACN,sBAAsB,EACtB,kBAAkB,EAClB,4BAA4B,EAC5B,qBAAqB,EACrB,iBAAiB,EACjB,qBAAqB,EACrB,MAAM,wBAAwB,CAAC;AAGhC,OAAO,EACN,sBAAsB,EACtB,mBAAmB,EAOnB,MAAM,sBAAsB,CAAC;AAE9B,OAAO,EACN,yBAAyB,EACzB,sBAAsB,EACtB,oBAAoB,EACpB,kBAAkB,EAIlB,MAAM,iBAAiB,CAAC"}
|
|
@@ -0,0 +1,74 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Visibility-filtered definition reads, shared by the library page load and
|
|
3
|
+
* `GET /api/v1/definitions`.
|
|
4
|
+
*
|
|
5
|
+
* **This is a tenancy boundary.** The project scan runs as `SYSTEM_CONTEXT` so
|
|
6
|
+
* cross-org `public` projects are reachable when `ALLOW_CROSS_ORG_PUBLIC` is on;
|
|
7
|
+
* `canView` over the fetched membership rows is the only thing keeping another
|
|
8
|
+
* org's projects out of the result. The definition list itself is then filtered
|
|
9
|
+
* *in the query* via `projectIds`, so the cursor is applied after visibility
|
|
10
|
+
* rather than over a page that gets thinned afterwards.
|
|
11
|
+
*
|
|
12
|
+
* Cost is constant in the number of orgs and projects: three bulk membership
|
|
13
|
+
* reads regardless of N. Anything added here must keep that property — a
|
|
14
|
+
* per-project `await` inside a loop reintroduces the N+1 this replaced.
|
|
15
|
+
*/
|
|
16
|
+
import type { DefinitionListOptions, DefinitionRecord, DefinitionVersion, OrgMember, Page, Project, ProjectMember, RequestContext } from '@selvajs/platform';
|
|
17
|
+
import type { SelvaDeps } from '../api/deps.js';
|
|
18
|
+
/**
|
|
19
|
+
* The stores this module reads. Required at every call site.
|
|
20
|
+
*
|
|
21
|
+
* These used to fall back to a host's composition root, which welded this
|
|
22
|
+
* tenancy boundary to one app's boot — anything importing it started the whole
|
|
23
|
+
* application. Handlers pass `req.deps`; page loads pass their own equivalent.
|
|
24
|
+
* That is what lets a second host on a different provider set reuse this
|
|
25
|
+
* boundary instead of rebuilding it.
|
|
26
|
+
*/
|
|
27
|
+
export type VisibilityDeps = Pick<SelvaDeps, 'orgs' | 'projects' | 'platformProjectGrants' | 'definitionMeta' | 'flag'>;
|
|
28
|
+
/**
|
|
29
|
+
* The caller's accessible project set plus the membership rows it was derived
|
|
30
|
+
* from, so a caller needing a second rule (`canEdit` on the projects page)
|
|
31
|
+
* can evaluate it with no further I/O.
|
|
32
|
+
*/
|
|
33
|
+
export interface AccessibleProjectSet {
|
|
34
|
+
projects: Project[];
|
|
35
|
+
/** Every project the scan saw, keyed by id — for name lookups on rows. */
|
|
36
|
+
allById: Map<string, Project>;
|
|
37
|
+
/** The caller's project-membership row per scanned project (`null` = not a member). */
|
|
38
|
+
memberByProjectId: Map<string, ProjectMember | null>;
|
|
39
|
+
/** The caller's org-membership row per scanned org (`null` = not a member). */
|
|
40
|
+
orgMemberByOrgId: Map<string, OrgMember | null>;
|
|
41
|
+
}
|
|
42
|
+
/**
|
|
43
|
+
* Resolve the caller's accessible project set in a constant number of queries.
|
|
44
|
+
* Platform grants are fetched only for `platform`-visibility projects —
|
|
45
|
+
* `canView` short-circuits before reading them for every other visibility.
|
|
46
|
+
*/
|
|
47
|
+
export declare function resolveAccessibleProjects(ctx: RequestContext, deps: VisibilityDeps): Promise<AccessibleProjectSet>;
|
|
48
|
+
export interface ListVisibleDefinitionsResult extends Page<DefinitionRecord> {
|
|
49
|
+
/** For resolving a definition's `projectId` to a name. */
|
|
50
|
+
projects: Project[];
|
|
51
|
+
}
|
|
52
|
+
/**
|
|
53
|
+
* `opts.projectId` narrows to one project; a caller who cannot view it gets an
|
|
54
|
+
* empty page rather than a 403, so this never reveals that a project exists.
|
|
55
|
+
*/
|
|
56
|
+
export declare function listVisibleDefinitions(ctx: RequestContext, opts: (DefinitionListOptions & {
|
|
57
|
+
projectId?: string;
|
|
58
|
+
}) | undefined, deps: VisibilityDeps): Promise<ListVisibleDefinitionsResult>;
|
|
59
|
+
/**
|
|
60
|
+
* One definition, or `null` when the caller cannot view its project.
|
|
61
|
+
*
|
|
62
|
+
* Returns `null` rather than throwing 403 so callers surface a 404: a public
|
|
63
|
+
* API that answers "forbidden" for a guid the caller cannot see turns
|
|
64
|
+
* `/definitions/{guid}` into a cross-tenant existence oracle.
|
|
65
|
+
*/
|
|
66
|
+
export declare function getVisibleDefinition(ctx: RequestContext, guid: string, deps: VisibilityDeps): Promise<DefinitionRecord | null>;
|
|
67
|
+
/**
|
|
68
|
+
* One version of a definition the caller can view, including its cached
|
|
69
|
+
* `schema`. `null` when the definition is invisible, the version is missing, or
|
|
70
|
+
* the version belongs to a different definition — a caller must not be able to
|
|
71
|
+
* read an arbitrary version by pairing it with a guid they can see.
|
|
72
|
+
*/
|
|
73
|
+
export declare function loadVisibleVersion(ctx: RequestContext, guid: string, versionId: string, deps: VisibilityDeps): Promise<DefinitionVersion | null>;
|
|
74
|
+
//# sourceMappingURL=visibility.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"visibility.d.ts","sourceRoot":"","sources":["../../src/definitions/visibility.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;GAcG;AAGH,OAAO,KAAK,EACX,qBAAqB,EACrB,gBAAgB,EAChB,iBAAiB,EACjB,SAAS,EACT,IAAI,EAEJ,OAAO,EACP,aAAa,EACb,cAAc,EACd,MAAM,mBAAmB,CAAC;AAE3B,OAAO,KAAK,EAAE,SAAS,EAAE,MAAM,gBAAgB,CAAC;AAKhD;;;;;;;;GAQG;AACH,MAAM,MAAM,cAAc,GAAG,IAAI,CAChC,SAAS,EACT,MAAM,GAAG,UAAU,GAAG,uBAAuB,GAAG,gBAAgB,GAAG,MAAM,CACzE,CAAC;AAEF;;;;GAIG;AACH,MAAM,WAAW,oBAAoB;IACpC,QAAQ,EAAE,OAAO,EAAE,CAAC;IACpB,0EAA0E;IAC1E,OAAO,EAAE,GAAG,CAAC,MAAM,EAAE,OAAO,CAAC,CAAC;IAC9B,uFAAuF;IACvF,iBAAiB,EAAE,GAAG,CAAC,MAAM,EAAE,aAAa,GAAG,IAAI,CAAC,CAAC;IACrD,+EAA+E;IAC/E,gBAAgB,EAAE,GAAG,CAAC,MAAM,EAAE,SAAS,GAAG,IAAI,CAAC,CAAC;CAChD;AAED;;;;GAIG;AACH,wBAAsB,yBAAyB,CAC9C,GAAG,EAAE,cAAc,EACnB,IAAI,EAAE,cAAc,GAClB,OAAO,CAAC,oBAAoB,CAAC,CAyC/B;AAED,MAAM,WAAW,4BAA6B,SAAQ,IAAI,CAAC,gBAAgB,CAAC;IAC3E,0DAA0D;IAC1D,QAAQ,EAAE,OAAO,EAAE,CAAC;CACpB;AAED;;;GAGG;AACH,wBAAsB,sBAAsB,CAC3C,GAAG,EAAE,cAAc,EACnB,IAAI,GAAE,qBAAqB,GAAG;IAAE,SAAS,CAAC,EAAE,MAAM,CAAA;CAAE,aAAK,EACzD,IAAI,EAAE,cAAc,GAClB,OAAO,CAAC,4BAA4B,CAAC,CAavC;AAED;;;;;;GAMG;AACH,wBAAsB,oBAAoB,CACzC,GAAG,EAAE,cAAc,EACnB,IAAI,EAAE,MAAM,EACZ,IAAI,EAAE,cAAc,GAClB,OAAO,CAAC,gBAAgB,GAAG,IAAI,CAAC,CA0BlC;AAED;;;;;GAKG;AACH,wBAAsB,kBAAkB,CACvC,GAAG,EAAE,cAAc,EACnB,IAAI,EAAE,MAAM,EACZ,SAAS,EAAE,MAAM,EACjB,IAAI,EAAE,cAAc,GAClB,OAAO,CAAC,iBAAiB,GAAG,IAAI,CAAC,CAOnC"}
|
|
@@ -0,0 +1,117 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Visibility-filtered definition reads, shared by the library page load and
|
|
3
|
+
* `GET /api/v1/definitions`.
|
|
4
|
+
*
|
|
5
|
+
* **This is a tenancy boundary.** The project scan runs as `SYSTEM_CONTEXT` so
|
|
6
|
+
* cross-org `public` projects are reachable when `ALLOW_CROSS_ORG_PUBLIC` is on;
|
|
7
|
+
* `canView` over the fetched membership rows is the only thing keeping another
|
|
8
|
+
* org's projects out of the result. The definition list itself is then filtered
|
|
9
|
+
* *in the query* via `projectIds`, so the cursor is applied after visibility
|
|
10
|
+
* rather than over a page that gets thinned afterwards.
|
|
11
|
+
*
|
|
12
|
+
* Cost is constant in the number of orgs and projects: three bulk membership
|
|
13
|
+
* reads regardless of N. Anything added here must keep that property — a
|
|
14
|
+
* per-project `await` inside a loop reintroduces the N+1 this replaced.
|
|
15
|
+
*/
|
|
16
|
+
import { SYSTEM_CONTEXT, canView } from '@selvajs/platform';
|
|
17
|
+
import { projectAccessInputFromRowsWith } from '../access/index.js';
|
|
18
|
+
/** Upper bound on the org/project scan. Visibility needs the whole set. */
|
|
19
|
+
const SCAN_LIMIT = 200;
|
|
20
|
+
/**
|
|
21
|
+
* Resolve the caller's accessible project set in a constant number of queries.
|
|
22
|
+
* Platform grants are fetched only for `platform`-visibility projects —
|
|
23
|
+
* `canView` short-circuits before reading them for every other visibility.
|
|
24
|
+
*/
|
|
25
|
+
export async function resolveAccessibleProjects(ctx, deps) {
|
|
26
|
+
const orgs = deps.orgs;
|
|
27
|
+
const projectStore = deps.projects;
|
|
28
|
+
const grantStore = deps.platformProjectGrants;
|
|
29
|
+
const orgsPage = await orgs.listOrgs(SYSTEM_CONTEXT, { limit: SCAN_LIMIT });
|
|
30
|
+
const orgIds = orgsPage.items.map((o) => o.id);
|
|
31
|
+
const projectPages = await Promise.all(orgIds.map((orgId) => projectStore.listProjects(SYSTEM_CONTEXT, orgId, { limit: SCAN_LIMIT })));
|
|
32
|
+
const allProjects = projectPages.flatMap((p) => p.items);
|
|
33
|
+
const projectIds = allProjects.map((p) => p.id);
|
|
34
|
+
const platformProjectIds = allProjects
|
|
35
|
+
.filter((p) => p.visibility === 'platform')
|
|
36
|
+
.map((p) => p.id);
|
|
37
|
+
const [orgMemberByOrgId, memberByProjectId, grantsByProjectId] = await Promise.all([
|
|
38
|
+
orgs.getOrgMembersFor(SYSTEM_CONTEXT, orgIds, ctx.userId),
|
|
39
|
+
projectStore.getProjectMembersFor(SYSTEM_CONTEXT, projectIds, ctx.userId),
|
|
40
|
+
platformProjectIds.length
|
|
41
|
+
? grantStore.listByProjects(SYSTEM_CONTEXT, platformProjectIds)
|
|
42
|
+
: Promise.resolve(new Map())
|
|
43
|
+
]);
|
|
44
|
+
const projects = allProjects.filter((project) => canView(projectAccessInputFromRowsWith({ deps }, ctx, project, {
|
|
45
|
+
member: memberByProjectId.get(project.id) ?? null,
|
|
46
|
+
orgMember: orgMemberByOrgId.get(project.orgId) ?? null,
|
|
47
|
+
platformGrants: grantsByProjectId.get(project.id) ?? []
|
|
48
|
+
})));
|
|
49
|
+
return {
|
|
50
|
+
projects,
|
|
51
|
+
allById: new Map(allProjects.map((p) => [p.id, p])),
|
|
52
|
+
memberByProjectId,
|
|
53
|
+
orgMemberByOrgId
|
|
54
|
+
};
|
|
55
|
+
}
|
|
56
|
+
/**
|
|
57
|
+
* `opts.projectId` narrows to one project; a caller who cannot view it gets an
|
|
58
|
+
* empty page rather than a 403, so this never reveals that a project exists.
|
|
59
|
+
*/
|
|
60
|
+
export async function listVisibleDefinitions(ctx, opts = {}, deps) {
|
|
61
|
+
const { projectId, ...listOpts } = opts;
|
|
62
|
+
const { projects } = await resolveAccessibleProjects(ctx, deps);
|
|
63
|
+
const scoped = projectId ? projects.filter((p) => p.id === projectId) : projects;
|
|
64
|
+
// An empty id set matches nothing, which is what a caller with no visible
|
|
65
|
+
// projects should get — not an unfiltered listing.
|
|
66
|
+
const page = await deps.definitionMeta.list(ctx, {
|
|
67
|
+
...listOpts,
|
|
68
|
+
projectIds: scoped.map((p) => p.id)
|
|
69
|
+
});
|
|
70
|
+
return { items: page.items, nextCursor: page.nextCursor, projects: scoped };
|
|
71
|
+
}
|
|
72
|
+
/**
|
|
73
|
+
* One definition, or `null` when the caller cannot view its project.
|
|
74
|
+
*
|
|
75
|
+
* Returns `null` rather than throwing 403 so callers surface a 404: a public
|
|
76
|
+
* API that answers "forbidden" for a guid the caller cannot see turns
|
|
77
|
+
* `/definitions/{guid}` into a cross-tenant existence oracle.
|
|
78
|
+
*/
|
|
79
|
+
export async function getVisibleDefinition(ctx, guid, deps) {
|
|
80
|
+
const meta = deps.definitionMeta;
|
|
81
|
+
const projectStore = deps.projects;
|
|
82
|
+
const record = await meta.get(ctx, guid);
|
|
83
|
+
if (!record)
|
|
84
|
+
return null;
|
|
85
|
+
const project = await projectStore.getProject(SYSTEM_CONTEXT, record.projectId);
|
|
86
|
+
if (!project)
|
|
87
|
+
return null;
|
|
88
|
+
const [orgMembers, projectMembers, grants] = await Promise.all([
|
|
89
|
+
deps.orgs.getOrgMembersFor(SYSTEM_CONTEXT, [project.orgId], ctx.userId),
|
|
90
|
+
projectStore.getProjectMembersFor(SYSTEM_CONTEXT, [project.id], ctx.userId),
|
|
91
|
+
project.visibility === 'platform'
|
|
92
|
+
? deps.platformProjectGrants.listByProject(SYSTEM_CONTEXT, project.id)
|
|
93
|
+
: Promise.resolve([])
|
|
94
|
+
]);
|
|
95
|
+
const allowed = canView(projectAccessInputFromRowsWith({ deps }, ctx, project, {
|
|
96
|
+
member: projectMembers.get(project.id) ?? null,
|
|
97
|
+
orgMember: orgMembers.get(project.orgId) ?? null,
|
|
98
|
+
platformGrants: grants
|
|
99
|
+
}));
|
|
100
|
+
return allowed ? record : null;
|
|
101
|
+
}
|
|
102
|
+
/**
|
|
103
|
+
* One version of a definition the caller can view, including its cached
|
|
104
|
+
* `schema`. `null` when the definition is invisible, the version is missing, or
|
|
105
|
+
* the version belongs to a different definition — a caller must not be able to
|
|
106
|
+
* read an arbitrary version by pairing it with a guid they can see.
|
|
107
|
+
*/
|
|
108
|
+
export async function loadVisibleVersion(ctx, guid, versionId, deps) {
|
|
109
|
+
const record = await getVisibleDefinition(ctx, guid, deps);
|
|
110
|
+
if (!record)
|
|
111
|
+
return null;
|
|
112
|
+
const version = await deps.definitionMeta.getVersion(ctx, versionId);
|
|
113
|
+
if (!version || version.definitionId !== record.guid)
|
|
114
|
+
return null;
|
|
115
|
+
return version;
|
|
116
|
+
}
|
|
117
|
+
//# sourceMappingURL=visibility.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"visibility.js","sourceRoot":"","sources":["../../src/definitions/visibility.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1,30 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Version handlers: list, upload, read, delete, and a version's cached schema.
|
|
3
|
+
*
|
|
4
|
+
* Reads resolve through `getVisibleDefinition` / `loadVisibleVersion`, which
|
|
5
|
+
* return `null` rather than throwing, so an invisible definition answers 404.
|
|
6
|
+
* A 403 anywhere here would confirm a guid exists across a tenant boundary.
|
|
7
|
+
*/
|
|
8
|
+
import type { ApiHandler } from '../api/index.js';
|
|
9
|
+
export declare const listVersions: ApiHandler;
|
|
10
|
+
/** Upload a new version. Advances `draft`; `live` is unchanged until publish. */
|
|
11
|
+
export declare const uploadVersion: ApiHandler;
|
|
12
|
+
/**
|
|
13
|
+
* Version metadata. `schema` is excluded and served by the `/schema`
|
|
14
|
+
* sub-resource, so a version read never carries a several-hundred-KB blob.
|
|
15
|
+
*/
|
|
16
|
+
export declare const getVersion: ApiHandler;
|
|
17
|
+
/**
|
|
18
|
+
* Delete an old version. The store throws 409 if the version is currently
|
|
19
|
+
* referenced by `liveVersionId` or `draftVersionId` — repoint first.
|
|
20
|
+
*/
|
|
21
|
+
export declare const deleteVersion: ApiHandler;
|
|
22
|
+
/**
|
|
23
|
+
* The UI schema cached on this version at upload. Reads what is stored — no
|
|
24
|
+
* Rhino.Compute round-trip, unlike the pre-upload `POST /api/v1/compute/schema`.
|
|
25
|
+
*
|
|
26
|
+
* Schemas belong to a version, so this is the canonical location;
|
|
27
|
+
* `/definitions/{guid}/schema` is an alias for the live one.
|
|
28
|
+
*/
|
|
29
|
+
export declare const getVersionSchema: ApiHandler;
|
|
30
|
+
//# sourceMappingURL=definitionVersions.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"definitionVersions.d.ts","sourceRoot":"","sources":["../../src/handlers/definitionVersions.ts"],"names":[],"mappings":"AAAA;;;;;;GAMG;AAcH,OAAO,KAAK,EAAE,UAAU,EAAE,MAAM,iBAAiB,CAAC;AAYlD,eAAO,MAAM,YAAY,EAAE,UAa1B,CAAC;AAEF,iFAAiF;AACjF,eAAO,MAAM,aAAa,EAAE,UAgC3B,CAAC;AAEF;;;GAGG;AACH,eAAO,MAAM,UAAU,EAAE,UASxB,CAAC;AAEF;;;GAGG;AACH,eAAO,MAAM,aAAa,EAAE,UAO3B,CAAC;AAEF;;;;;;GAMG;AACH,eAAO,MAAM,gBAAgB,EAAE,UAW9B,CAAC"}
|