@datalayer/core 1.1.66 → 1.2.12
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/README.md +43 -20
- package/lib/api/constants.d.ts +1 -1
- package/lib/api/constants.js +1 -1
- package/lib/api/contents/attachments.js +3 -7
- package/lib/api/contents/datasets.d.ts +48 -0
- package/lib/api/contents/datasets.js +44 -7
- package/lib/api/contents/runtimeMounts.js +1 -1
- package/lib/api/contents/sandboxUid.d.ts +13 -45
- package/lib/api/contents/sandboxUid.js +14 -65
- package/lib/api/evals/client.d.ts +402 -0
- package/lib/api/evals/client.js +359 -0
- package/lib/api/evals/index.d.ts +10 -0
- package/lib/api/evals/index.js +18 -0
- package/lib/api/evals/request.d.ts +43 -0
- package/lib/api/evals/request.js +67 -0
- package/lib/api/evals/status.d.ts +27 -0
- package/lib/api/evals/status.js +122 -0
- package/lib/api/evals/types.d.ts +1335 -0
- package/lib/api/evals/types.js +5 -0
- package/lib/api/iam/authentication.js +6 -4
- package/lib/api/iam/connectedAgents.d.ts +29 -0
- package/lib/api/iam/connectedAgents.js +35 -0
- package/lib/api/iam/healthz.js +2 -2
- package/lib/api/iam/identityProviders.d.ts +76 -0
- package/lib/api/iam/identityProviders.js +187 -0
- package/lib/api/iam/index.d.ts +1 -0
- package/lib/api/iam/index.js +1 -0
- package/lib/api/iam/mcpPolicy.d.ts +102 -1
- package/lib/api/iam/mcpPolicy.js +38 -2
- package/lib/api/iam/oauth2.js +18 -12
- package/lib/api/iam/profile.d.ts +17 -1
- package/lib/api/iam/profile.js +27 -0
- package/lib/api/iam/scimTokens.d.ts +79 -0
- package/lib/api/iam/scimTokens.js +141 -0
- package/lib/api/iam/secrets.js +10 -23
- package/lib/api/iam/trials.d.ts +38 -0
- package/lib/api/iam/trials.js +66 -0
- package/lib/api/index.d.ts +4 -0
- package/lib/api/index.js +4 -0
- package/lib/api/mcp/observability.d.ts +34 -11
- package/lib/api/mcp/observability.js +97 -59
- package/lib/api/orchestration/client.d.ts +53 -0
- package/lib/api/orchestration/client.js +105 -0
- package/lib/api/orchestration/events.d.ts +88 -0
- package/lib/api/orchestration/events.js +245 -0
- package/lib/api/orchestration/generated.d.ts +693 -0
- package/lib/api/orchestration/generated.js +687 -0
- package/lib/api/orchestration/index.d.ts +30 -0
- package/lib/api/orchestration/index.js +34 -0
- package/lib/api/orchestration/lifecycle.d.ts +39 -0
- package/lib/api/orchestration/lifecycle.js +57 -0
- package/lib/api/orchestration/measures.d.ts +55 -0
- package/lib/api/orchestration/measures.js +99 -0
- package/lib/api/otel/dashboards.d.ts +56 -0
- package/lib/api/otel/dashboards.js +50 -0
- package/lib/api/otel/index.d.ts +1 -0
- package/lib/api/otel/index.js +1 -0
- package/lib/api/otel/metrics.d.ts +16 -0
- package/lib/api/otel/metrics.js +15 -0
- package/lib/api/scheduler/client.d.ts +32 -0
- package/lib/api/scheduler/client.js +42 -0
- package/lib/api/scheduler/index.d.ts +8 -0
- package/lib/api/scheduler/index.js +16 -0
- package/lib/api/scheduler/request.d.ts +28 -0
- package/lib/api/scheduler/request.js +50 -0
- package/lib/api/scheduler/types.d.ts +88 -0
- package/lib/api/scheduler/types.js +5 -0
- package/lib/api/spacer/comments.d.ts +97 -0
- package/lib/api/spacer/comments.js +45 -0
- package/lib/api/spacer/index.d.ts +9 -0
- package/lib/api/spacer/index.js +17 -0
- package/lib/api/spacer/notebooks.d.ts +33 -0
- package/lib/api/spacer/notebooks.js +39 -0
- package/lib/api/spacer/request.d.ts +25 -0
- package/lib/api/spacer/request.js +46 -0
- package/lib/api/spacer/spaces.d.ts +68 -0
- package/lib/api/spacer/spaces.js +45 -0
- package/lib/api/utils/validation.d.ts +4 -4
- package/lib/api/utils/validation.js +10 -7
- package/lib/client/auth/strategies.js +1 -1
- package/lib/client/constants.d.ts +1 -0
- package/lib/client/constants.js +1 -0
- package/lib/client/mixins/IAMMixin.js +2 -2
- package/lib/components/animation/AnimatedText.d.ts +1 -44
- package/lib/components/animation/AnimatedText.js +6 -122
- package/lib/components/anonymous/AnonymousKeyExpired.d.ts +56 -0
- package/lib/components/anonymous/AnonymousKeyExpired.js +96 -0
- package/lib/components/anonymous/AnonymousKeyTimer.d.ts +63 -0
- package/lib/components/anonymous/AnonymousKeyTimer.js +140 -0
- package/lib/components/anonymous/index.d.ts +7 -0
- package/lib/components/anonymous/index.js +15 -0
- package/lib/components/avatars/UserAvatar.d.ts +7 -1
- package/lib/components/avatars/UserAvatar.js +15 -1
- package/lib/components/billing/BillingEntitySelect.d.ts +6 -0
- package/lib/components/billing/BillingEntitySelect.js +49 -10
- package/lib/components/billing/eligibility.d.ts +22 -0
- package/lib/components/billing/eligibility.js +27 -0
- package/lib/components/billing/index.d.ts +1 -0
- package/lib/components/billing/index.js +1 -0
- package/lib/components/checkout/StripeCheckout.d.ts +1 -1
- package/lib/components/checkout/StripeCheckout.js +1 -1
- package/lib/components/collaboration/LiveEditorCollaborators.d.ts +5 -0
- package/lib/components/collaboration/LiveEditorCollaborators.js +3 -1
- package/lib/components/display/DatalayerBox.d.ts +2 -3
- package/lib/components/display/DatalayerBox.js +1 -1
- package/lib/components/display/NavLink.js +3 -2
- package/lib/components/display/VisuallyHidden.d.ts +1 -2
- package/lib/components/labels/StatusLabels.d.ts +2 -10
- package/lib/components/labels/StatusLabels.js +2 -26
- package/lib/components/principal/PrincipalAppearance.d.ts +21 -42
- package/lib/components/principal/PrincipalAppearance.js +232 -174
- package/lib/components/principal/PrincipalAvatar.d.ts +8 -1
- package/lib/components/principal/PrincipalAvatar.js +2 -2
- package/lib/components/principal/PrincipalDetailsOverlay.d.ts +8 -1
- package/lib/components/principal/PrincipalDetailsOverlay.js +2 -2
- package/lib/components/screencapture/Screencapture.js +46 -3
- package/lib/components/sharing/ShareAccessComponent.d.ts +45 -4
- package/lib/components/sharing/ShareAccessComponent.js +110 -78
- package/lib/components/sharing/SharingEditor.d.ts +5 -1
- package/lib/components/sharing/SharingEditor.js +9 -4
- package/lib/components/sharing/index.d.ts +1 -0
- package/lib/components/sharing/index.js +1 -0
- package/lib/components/sharing/sandboxSharing.d.ts +26 -0
- package/lib/components/sharing/sandboxSharing.js +47 -0
- package/lib/components/spaces/SpaceDetailsOverlay.d.ts +39 -0
- package/lib/components/spaces/SpaceDetailsOverlay.js +80 -0
- package/lib/components/spaces/SpaceDisplay.d.ts +38 -0
- package/lib/components/spaces/SpaceDisplay.js +92 -0
- package/lib/components/spaces/index.d.ts +4 -0
- package/lib/components/spaces/index.js +7 -0
- package/lib/components/spaces/spaceDisplayModel.d.ts +93 -0
- package/lib/components/spaces/spaceDisplayModel.js +170 -0
- package/lib/config/Configuration.d.ts +4 -4
- package/lib/config/Configuration.js +7 -7
- package/lib/config/index.d.ts +1 -0
- package/lib/config/index.js +1 -0
- package/lib/config/planes.d.ts +45 -0
- package/lib/config/planes.js +53 -0
- package/lib/hooks/cacheConverters.d.ts +0 -7
- package/lib/hooks/cacheConverters.js +0 -25
- package/lib/hooks/index.d.ts +1 -0
- package/lib/hooks/index.js +1 -0
- package/lib/hooks/useBackdrop.d.ts +4 -5
- package/lib/hooks/useBillingEntityStore.js +3 -0
- package/lib/hooks/useCache.d.ts +197 -44
- package/lib/hooks/useCache.js +1586 -494
- package/lib/hooks/useContents.d.ts +22 -1
- package/lib/hooks/useContents.js +90 -21
- package/lib/hooks/useMcp.d.ts +87 -1
- package/lib/hooks/useMcp.js +248 -13
- package/lib/hooks/useNavigate.d.ts +41 -3
- package/lib/hooks/useNavigate.js +116 -52
- package/lib/hooks/usePrincipalCacheStore.js +3 -0
- package/lib/hooks/usePrincipalStore.js +3 -0
- package/lib/hooks/useSpaceCacheStore.d.ts +50 -0
- package/lib/hooks/useSpaceCacheStore.js +85 -0
- package/lib/hooks/useWindowSize.js +1 -1
- package/lib/models/CreditsDTO.d.ts +6 -5
- package/lib/models/CreditsDTO.js +7 -5
- package/lib/models/IAMProvidersSpecs.d.ts +10 -5
- package/lib/models/IAMProvidersSpecs.js +0 -23
- package/lib/models/McpBinding.d.ts +6 -0
- package/lib/models/Organization.d.ts +69 -0
- package/lib/models/Organization.js +96 -0
- package/lib/models/Secret.d.ts +1 -2
- package/lib/models/Secret.js +2 -18
- package/lib/models/StartedBy.d.ts +34 -0
- package/lib/models/StartedBy.js +36 -0
- package/lib/models/Team.d.ts +2 -0
- package/lib/models/Team.js +2 -0
- package/lib/models/User.d.ts +4 -0
- package/lib/models/User.js +3 -0
- package/lib/models/UserSettings.d.ts +13 -0
- package/lib/models/UserSettings.js +9 -0
- package/lib/models/contents/__fixtures__/v1-contracts.json +158 -30
- package/lib/navigation/adapters/react-router.d.ts +1 -1
- package/lib/navigation/adapters/react-router.js +3 -0
- package/lib/navigation/components.js +2 -3
- package/lib/routes/publicPaths.js +4 -0
- package/lib/state/index.d.ts +1 -0
- package/lib/state/index.js +1 -0
- package/lib/state/sessionEnd.d.ts +55 -0
- package/lib/state/sessionEnd.js +162 -0
- package/lib/state/substates/CoreState.js +3 -16
- package/lib/state/substates/IAMState.d.ts +3 -3
- package/lib/state/substates/IAMState.js +7 -0
- package/lib/state/substates/LayoutState.js +12 -0
- package/lib/state/substates/NavigationState.d.ts +82 -0
- package/lib/state/substates/NavigationState.js +255 -0
- package/lib/state/substates/ProfileState.d.ts +1 -0
- package/lib/state/substates/ProfileState.js +1 -0
- package/lib/state/substates/index.d.ts +1 -0
- package/lib/state/substates/index.js +1 -0
- package/lib/utils/Lazy.d.ts +20 -0
- package/lib/utils/Lazy.js +32 -6
- package/lib/utils/Screencapture.d.ts +15 -0
- package/lib/utils/Screencapture.js +26 -20
- package/lib/utils/WithSuspense.d.ts +11 -1
- package/lib/utils/WithSuspense.js +11 -1
- package/lib/views/mcp/AdmittedClients.d.ts +44 -0
- package/lib/views/mcp/AdmittedClients.js +59 -0
- package/lib/views/mcp/ApprovalQueue.d.ts +66 -0
- package/lib/views/mcp/ApprovalQueue.js +95 -0
- package/lib/views/mcp/ConnectedAgents.js +38 -3
- package/lib/views/mcp/EnterpriseConsole.d.ts +1 -1
- package/lib/views/mcp/EnterpriseConsole.js +23 -1
- package/lib/views/mcp/IdentityProviders.d.ts +33 -0
- package/lib/views/mcp/IdentityProviders.js +299 -0
- package/lib/views/mcp/McpDashboard.js +90 -7
- package/lib/views/mcp/McpHome.js +1 -1
- package/lib/views/mcp/McpObservability.d.ts +30 -1
- package/lib/views/mcp/McpObservability.js +105 -19
- package/lib/views/mcp/NotebookRuns.d.ts +39 -0
- package/lib/views/mcp/NotebookRuns.js +44 -0
- package/lib/views/mcp/OrganizationPolicy.js +2 -1
- package/lib/views/mcp/PersonalPolicy.js +2 -1
- package/lib/views/mcp/PolicyForm.d.ts +17 -1
- package/lib/views/mcp/PolicyForm.js +25 -3
- package/lib/views/mcp/PolicyHistory.d.ts +13 -0
- package/lib/views/mcp/PolicyHistory.js +14 -1
- package/lib/views/mcp/RunDetail.d.ts +87 -0
- package/lib/views/mcp/RunDetail.js +186 -0
- package/lib/views/mcp/ScimProvisioning.d.ts +54 -0
- package/lib/views/mcp/ScimProvisioning.js +173 -0
- package/lib/views/mcp/TeamPolicies.js +66 -5
- package/lib/views/mcp/ToolAccess.d.ts +60 -0
- package/lib/views/mcp/ToolAccess.js +101 -0
- package/lib/views/mcp/TraceTimeline.d.ts +81 -0
- package/lib/views/mcp/TraceTimeline.js +132 -0
- package/lib/views/mcp/index.d.ts +5 -0
- package/lib/views/mcp/index.js +5 -0
- package/lib/views/otel/simpleAuthStore.js +3 -0
- package/lib/views/secrets/SecretEdit.js +3 -2
- package/lib/views/secrets/SecretNew.js +5 -1
- package/package.json +271 -264
- package/scripts/generate-mcp-types.py +16 -10
- package/scripts/generate-orchestration-types.py +920 -0
package/lib/api/iam/profile.d.ts
CHANGED
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import { MembershipsResponse, ShareablePrincipalsResponse, UserMeResponse, WhoAmIResponse } from '../../models/IAM';
|
|
1
|
+
import { MembershipsResponse, PrincipalSearchResponse, PrincipalSearchUser, ShareablePrincipalsResponse, UserMeResponse, WhoAmIResponse } from '../../models/IAM';
|
|
2
2
|
/**
|
|
3
3
|
* Get current authenticated user profile
|
|
4
4
|
* @param token - Authentication token (required)
|
|
@@ -28,3 +28,19 @@ export declare const memberships: (token: string, baseUrl?: string) => Promise<M
|
|
|
28
28
|
* @param baseUrl - Base URL for the API (defaults to production IAM URL)
|
|
29
29
|
*/
|
|
30
30
|
export declare const principalsShareable: (token: string, baseUrl?: string) => Promise<ShareablePrincipalsResponse>;
|
|
31
|
+
/**
|
|
32
|
+
* Search the people, teams and organizations the caller may name: what the
|
|
33
|
+
* sharing dialogs search, and whom a comment mentions or assigns (B4-02).
|
|
34
|
+
*
|
|
35
|
+
* @param token - Authentication token (required)
|
|
36
|
+
* @param query - What is typed: part of a handle or of a name
|
|
37
|
+
* @param principalTypes - What to search; people only by default
|
|
38
|
+
* @param baseUrl - Base URL for the API (defaults to production IAM URL)
|
|
39
|
+
*/
|
|
40
|
+
export declare const searchPrincipals: (token: string, query: string, principalTypes?: Array<"user" | "team" | "organization">, baseUrl?: string) => Promise<PrincipalSearchResponse>;
|
|
41
|
+
/** A person `searchPrincipals` found, as a comment or a report names them. */
|
|
42
|
+
export declare const personOfPrincipalUser: (user: PrincipalSearchUser) => {
|
|
43
|
+
uid: string;
|
|
44
|
+
handle: string;
|
|
45
|
+
name: string | null;
|
|
46
|
+
};
|
package/lib/api/iam/profile.js
CHANGED
|
@@ -69,3 +69,30 @@ export const principalsShareable = async (token, baseUrl = DEFAULT_SERVICE_URLS.
|
|
|
69
69
|
token,
|
|
70
70
|
});
|
|
71
71
|
};
|
|
72
|
+
/**
|
|
73
|
+
* Search the people, teams and organizations the caller may name: what the
|
|
74
|
+
* sharing dialogs search, and whom a comment mentions or assigns (B4-02).
|
|
75
|
+
*
|
|
76
|
+
* @param token - Authentication token (required)
|
|
77
|
+
* @param query - What is typed: part of a handle or of a name
|
|
78
|
+
* @param principalTypes - What to search; people only by default
|
|
79
|
+
* @param baseUrl - Base URL for the API (defaults to production IAM URL)
|
|
80
|
+
*/
|
|
81
|
+
export const searchPrincipals = async (token, query, principalTypes = ['user'], baseUrl = DEFAULT_SERVICE_URLS.IAM) => {
|
|
82
|
+
validateToken(token);
|
|
83
|
+
return requestDatalayerAPI({
|
|
84
|
+
url: `${baseUrl}${API_BASE_PATHS.IAM}/principals/search`,
|
|
85
|
+
method: 'POST',
|
|
86
|
+
body: { query, principalTypes },
|
|
87
|
+
token,
|
|
88
|
+
});
|
|
89
|
+
};
|
|
90
|
+
/** A person `searchPrincipals` found, as a comment or a report names them. */
|
|
91
|
+
export const personOfPrincipalUser = (user) => ({
|
|
92
|
+
uid: user.uid,
|
|
93
|
+
handle: user.handle_s,
|
|
94
|
+
name: `${user.first_name_t ?? ''} ${user.last_name_t ?? ''}`.trim() ||
|
|
95
|
+
user.display_name_t ||
|
|
96
|
+
user.display_name ||
|
|
97
|
+
null,
|
|
98
|
+
});
|
|
@@ -0,0 +1,79 @@
|
|
|
1
|
+
/** A SCIM credential as the console may see it — never the secret or its hash. */
|
|
2
|
+
export interface ScimToken {
|
|
3
|
+
uid: string;
|
|
4
|
+
orgUid: string;
|
|
5
|
+
/** What an administrator called it, to tell two directories apart. */
|
|
6
|
+
name: string;
|
|
7
|
+
/**
|
|
8
|
+
* Revoked rather than deleted, so the rows a provisioning run wrote can
|
|
9
|
+
* still name the token that wrote them.
|
|
10
|
+
*/
|
|
11
|
+
revoked: boolean;
|
|
12
|
+
/**
|
|
13
|
+
* When the secret was last replaced. A token that has never been rotated
|
|
14
|
+
* carries its creation moment here.
|
|
15
|
+
*/
|
|
16
|
+
rotatedAt?: string;
|
|
17
|
+
/**
|
|
18
|
+
* When it last authenticated a SCIM call, or empty for never. Written best
|
|
19
|
+
* effort — a provisioning call is never failed for the bookkeeping.
|
|
20
|
+
*/
|
|
21
|
+
lastUsedAt?: string;
|
|
22
|
+
createdBy?: string;
|
|
23
|
+
createdAt?: string;
|
|
24
|
+
updatedAt?: string;
|
|
25
|
+
}
|
|
26
|
+
/**
|
|
27
|
+
* A freshly minted credential: the record, and the secret **this once**.
|
|
28
|
+
*
|
|
29
|
+
* The two are separate fields rather than one merged object on purpose. The
|
|
30
|
+
* secret does not belong in anything the console stores, renders twice, or
|
|
31
|
+
* puts in a list, and a shape that carried it alongside every other field
|
|
32
|
+
* invites exactly that.
|
|
33
|
+
*/
|
|
34
|
+
export interface MintedScimToken {
|
|
35
|
+
token: ScimToken;
|
|
36
|
+
/** Shown once. Not retrievable, by construction — only a hash is stored. */
|
|
37
|
+
secret: string;
|
|
38
|
+
}
|
|
39
|
+
export declare const listScimTokens: (token: string, orgUid: string, baseUrl?: string) => Promise<ScimToken[]>;
|
|
40
|
+
/**
|
|
41
|
+
* Mint one. The secret is in this answer and nowhere else, ever again.
|
|
42
|
+
*
|
|
43
|
+
* The caller must put it in front of somebody before the next render. There
|
|
44
|
+
* is no second chance and no call that would provide one.
|
|
45
|
+
*/
|
|
46
|
+
export declare const createScimToken: (token: string, orgUid: string, name: string, baseUrl?: string) => Promise<MintedScimToken>;
|
|
47
|
+
/**
|
|
48
|
+
* A new secret for the same record; the old one stops at once.
|
|
49
|
+
*
|
|
50
|
+
* Rotation rather than delete-and-recreate because the record's uid is what
|
|
51
|
+
* the provisioning rows name. Replacing it would leave them pointing at
|
|
52
|
+
* nothing.
|
|
53
|
+
*/
|
|
54
|
+
export declare const rotateScimToken: (token: string, orgUid: string, uid: string, baseUrl?: string) => Promise<MintedScimToken>;
|
|
55
|
+
/** Stop a token, keeping the rows that name it readable. */
|
|
56
|
+
export declare const revokeScimToken: (token: string, orgUid: string, uid: string, baseUrl?: string) => Promise<ScimToken>;
|
|
57
|
+
/**
|
|
58
|
+
* The base URL a directory is configured with.
|
|
59
|
+
*
|
|
60
|
+
* Built here rather than typed into the page, because it is half of what an
|
|
61
|
+
* administrator copies into Okta or Entra and a typo in it looks like an
|
|
62
|
+
* outage on the directory's side. The directory appends `/Users` itself;
|
|
63
|
+
* RFC 7644 fixes everything after this.
|
|
64
|
+
*/
|
|
65
|
+
export declare const scimBaseUrl: (baseUrl?: string) => string;
|
|
66
|
+
/**
|
|
67
|
+
* Whether this organization can actually be provisioned into right now.
|
|
68
|
+
*
|
|
69
|
+
* A list with tokens in it is not the same as a working integration, and the
|
|
70
|
+
* distinction is the one an administrator most needs: every token revoked
|
|
71
|
+
* reads, in a table, almost exactly like a healthy setup. `neverUsed` is the
|
|
72
|
+
* other quiet state — configured, live, and never once called, which is what
|
|
73
|
+
* a directory that was set up and never switched on looks like.
|
|
74
|
+
*/
|
|
75
|
+
export declare const scimStatus: (tokens: ScimToken[]) => {
|
|
76
|
+
state: "none" | "revoked" | "never-used" | "active";
|
|
77
|
+
live: ScimToken[];
|
|
78
|
+
lastUsedAt?: string;
|
|
79
|
+
};
|
|
@@ -0,0 +1,141 @@
|
|
|
1
|
+
/*
|
|
2
|
+
* Copyright (c) 2023-2025 Datalayer, Inc.
|
|
3
|
+
* Distributed under the terms of the Modified BSD License.
|
|
4
|
+
*/
|
|
5
|
+
/*
|
|
6
|
+
* Copyright (c) 2023-2026 Datalayer, Inc.
|
|
7
|
+
* Distributed under the terms of the Modified BSD License.
|
|
8
|
+
*/
|
|
9
|
+
/**
|
|
10
|
+
* The credentials an organization's directory provisions with, over SCIM.
|
|
11
|
+
*
|
|
12
|
+
* The identity provider registry beside this one made a directory able to
|
|
13
|
+
* *sign somebody in*. SCIM is the half that does not wait for them to turn
|
|
14
|
+
* up: the directory says who exists when they join and, far more
|
|
15
|
+
* importantly, who has left.
|
|
16
|
+
*
|
|
17
|
+
* **The token is the tenant.** Every SCIM call resolves its organization
|
|
18
|
+
* from the bearer credential before it looks at anything else, so these
|
|
19
|
+
* records are not a convenience — each one *is* an organization's provisioning
|
|
20
|
+
* authority, and there is nothing else identifying the caller.
|
|
21
|
+
*
|
|
22
|
+
* **The secret is answered once and never again.** `createScimToken` and
|
|
23
|
+
* `rotateScimToken` return it; nothing reads it back, because only a SHA-256
|
|
24
|
+
* of it is stored. A console that offered to show it later would be
|
|
25
|
+
* promising something the server cannot do — so this client has no call that
|
|
26
|
+
* could, and the UI has to say "copy it now" and mean it.
|
|
27
|
+
*
|
|
28
|
+
* `lastUsedAt` is the column worth reading. A directory configured once and
|
|
29
|
+
* forgotten looks exactly like a live one in every other field, and the
|
|
30
|
+
* difference matters most for deprovisioning: the integration that has not
|
|
31
|
+
* called in a month is not removing anybody.
|
|
32
|
+
*
|
|
33
|
+
* @module api/iam/scimTokens
|
|
34
|
+
*/
|
|
35
|
+
import { requestDatalayerAPI } from '../DatalayerApi.js';
|
|
36
|
+
import { API_BASE_PATHS, DEFAULT_SERVICE_URLS } from '../constants.js';
|
|
37
|
+
const fromWire = (wire) => ({
|
|
38
|
+
uid: wire.uid ?? '',
|
|
39
|
+
orgUid: wire.org_uid ?? '',
|
|
40
|
+
name: wire.name ?? '',
|
|
41
|
+
// A record with no `revoked` field is a live one: absence is not
|
|
42
|
+
// revocation, and reading it as one would show every token as stopped.
|
|
43
|
+
revoked: wire.revoked === true,
|
|
44
|
+
rotatedAt: wire.rotated_at || undefined,
|
|
45
|
+
lastUsedAt: wire.last_used_at || undefined,
|
|
46
|
+
createdBy: wire.created_by || undefined,
|
|
47
|
+
createdAt: wire.created_at || undefined,
|
|
48
|
+
updatedAt: wire.updated_at || undefined,
|
|
49
|
+
});
|
|
50
|
+
const tokensUrl = (baseUrl, orgUid, suffix = '') => `${baseUrl}${API_BASE_PATHS.IAM}/organizations/${encodeURIComponent(orgUid)}` +
|
|
51
|
+
`/scim-tokens${suffix}`;
|
|
52
|
+
export const listScimTokens = async (token, orgUid, baseUrl = DEFAULT_SERVICE_URLS.IAM) => {
|
|
53
|
+
const response = await requestDatalayerAPI({
|
|
54
|
+
url: tokensUrl(baseUrl, orgUid),
|
|
55
|
+
method: 'GET',
|
|
56
|
+
token,
|
|
57
|
+
});
|
|
58
|
+
return (response.tokens ?? []).map(fromWire);
|
|
59
|
+
};
|
|
60
|
+
/**
|
|
61
|
+
* Mint one. The secret is in this answer and nowhere else, ever again.
|
|
62
|
+
*
|
|
63
|
+
* The caller must put it in front of somebody before the next render. There
|
|
64
|
+
* is no second chance and no call that would provide one.
|
|
65
|
+
*/
|
|
66
|
+
export const createScimToken = async (token, orgUid, name, baseUrl = DEFAULT_SERVICE_URLS.IAM) => {
|
|
67
|
+
const response = await requestDatalayerAPI({
|
|
68
|
+
url: tokensUrl(baseUrl, orgUid),
|
|
69
|
+
method: 'POST',
|
|
70
|
+
token,
|
|
71
|
+
body: { name },
|
|
72
|
+
});
|
|
73
|
+
return {
|
|
74
|
+
token: fromWire(response.token ?? {}),
|
|
75
|
+
secret: response.token?.token ?? '',
|
|
76
|
+
};
|
|
77
|
+
};
|
|
78
|
+
/**
|
|
79
|
+
* A new secret for the same record; the old one stops at once.
|
|
80
|
+
*
|
|
81
|
+
* Rotation rather than delete-and-recreate because the record's uid is what
|
|
82
|
+
* the provisioning rows name. Replacing it would leave them pointing at
|
|
83
|
+
* nothing.
|
|
84
|
+
*/
|
|
85
|
+
export const rotateScimToken = async (token, orgUid, uid, baseUrl = DEFAULT_SERVICE_URLS.IAM) => {
|
|
86
|
+
const response = await requestDatalayerAPI({
|
|
87
|
+
url: tokensUrl(baseUrl, orgUid, `/${encodeURIComponent(uid)}/rotate`),
|
|
88
|
+
method: 'POST',
|
|
89
|
+
token,
|
|
90
|
+
});
|
|
91
|
+
return {
|
|
92
|
+
token: fromWire(response.token ?? {}),
|
|
93
|
+
secret: response.token?.token ?? '',
|
|
94
|
+
};
|
|
95
|
+
};
|
|
96
|
+
/** Stop a token, keeping the rows that name it readable. */
|
|
97
|
+
export const revokeScimToken = async (token, orgUid, uid, baseUrl = DEFAULT_SERVICE_URLS.IAM) => {
|
|
98
|
+
const response = await requestDatalayerAPI({
|
|
99
|
+
url: tokensUrl(baseUrl, orgUid, `/${encodeURIComponent(uid)}`),
|
|
100
|
+
method: 'DELETE',
|
|
101
|
+
token,
|
|
102
|
+
});
|
|
103
|
+
return fromWire(response.token ?? {});
|
|
104
|
+
};
|
|
105
|
+
/**
|
|
106
|
+
* The base URL a directory is configured with.
|
|
107
|
+
*
|
|
108
|
+
* Built here rather than typed into the page, because it is half of what an
|
|
109
|
+
* administrator copies into Okta or Entra and a typo in it looks like an
|
|
110
|
+
* outage on the directory's side. The directory appends `/Users` itself;
|
|
111
|
+
* RFC 7644 fixes everything after this.
|
|
112
|
+
*/
|
|
113
|
+
export const scimBaseUrl = (baseUrl = DEFAULT_SERVICE_URLS.IAM) => `${baseUrl}/api/iam/scim/v2`;
|
|
114
|
+
/**
|
|
115
|
+
* Whether this organization can actually be provisioned into right now.
|
|
116
|
+
*
|
|
117
|
+
* A list with tokens in it is not the same as a working integration, and the
|
|
118
|
+
* distinction is the one an administrator most needs: every token revoked
|
|
119
|
+
* reads, in a table, almost exactly like a healthy setup. `neverUsed` is the
|
|
120
|
+
* other quiet state — configured, live, and never once called, which is what
|
|
121
|
+
* a directory that was set up and never switched on looks like.
|
|
122
|
+
*/
|
|
123
|
+
export const scimStatus = (tokens) => {
|
|
124
|
+
const live = tokens.filter(entry => !entry.revoked);
|
|
125
|
+
if (tokens.length === 0) {
|
|
126
|
+
return { state: 'none', live };
|
|
127
|
+
}
|
|
128
|
+
if (live.length === 0) {
|
|
129
|
+
return { state: 'revoked', live };
|
|
130
|
+
}
|
|
131
|
+
const used = live
|
|
132
|
+
.map(entry => entry.lastUsedAt)
|
|
133
|
+
.filter((value) => Boolean(value))
|
|
134
|
+
.sort();
|
|
135
|
+
const lastUsedAt = used.length > 0 ? used[used.length - 1] : undefined;
|
|
136
|
+
return {
|
|
137
|
+
state: lastUsedAt ? 'active' : 'never-used',
|
|
138
|
+
live,
|
|
139
|
+
lastUsedAt,
|
|
140
|
+
};
|
|
141
|
+
};
|
package/lib/api/iam/secrets.js
CHANGED
|
@@ -9,21 +9,6 @@
|
|
|
9
9
|
import { requestDatalayerAPI } from '../DatalayerApi.js';
|
|
10
10
|
import { API_BASE_PATHS, DEFAULT_SERVICE_URLS } from '../constants.js';
|
|
11
11
|
import { validateToken, validateRequiredString } from '../utils/validation.js';
|
|
12
|
-
/**
|
|
13
|
-
* Helper function to Base64 encode a value (cross-platform).
|
|
14
|
-
* @param value - Plain text value to encode
|
|
15
|
-
* @returns Base64 encoded string
|
|
16
|
-
*/
|
|
17
|
-
function encodeValue(value) {
|
|
18
|
-
if (typeof Buffer !== 'undefined') {
|
|
19
|
-
// Node.js environment
|
|
20
|
-
return Buffer.from(value).toString('base64');
|
|
21
|
-
}
|
|
22
|
-
else {
|
|
23
|
-
// Browser environment
|
|
24
|
-
return btoa(value);
|
|
25
|
-
}
|
|
26
|
-
}
|
|
27
12
|
/**
|
|
28
13
|
* Create a new secret.
|
|
29
14
|
* Creates a new encrypted secret for the authenticated user.
|
|
@@ -47,12 +32,14 @@ export const createSecret = async (token, data, baseUrl = DEFAULT_SERVICE_URLS.I
|
|
|
47
32
|
validateToken(token);
|
|
48
33
|
validateRequiredString(data.name, 'Secret name');
|
|
49
34
|
validateRequiredString(data.value, 'Secret value');
|
|
50
|
-
// Base64 encode the value before sending to API
|
|
51
35
|
const requestBody = {
|
|
52
36
|
variant: data.variant || 'generic',
|
|
53
37
|
name: data.name,
|
|
54
38
|
description: data.description || '',
|
|
55
|
-
|
|
39
|
+
// As it is. A secret has one representation end to end (PLAN_ENVS.md
|
|
40
|
+
// E3-05): this used to base64-encode, and nothing on the read side undid
|
|
41
|
+
// it, so a build secret arrived at its build encoded and opened nothing.
|
|
42
|
+
value: data.value,
|
|
56
43
|
};
|
|
57
44
|
try {
|
|
58
45
|
return await requestDatalayerAPI({
|
|
@@ -64,7 +51,7 @@ export const createSecret = async (token, data, baseUrl = DEFAULT_SERVICE_URLS.I
|
|
|
64
51
|
}
|
|
65
52
|
catch (error) {
|
|
66
53
|
if (error.response?.status === 409) {
|
|
67
|
-
throw new Error(`Secret with name '${data.name}' already exists. Please use a different name
|
|
54
|
+
throw new Error(`Secret with name '${data.name}' already exists. Please use a different name.`, { cause: error });
|
|
68
55
|
}
|
|
69
56
|
throw error;
|
|
70
57
|
}
|
|
@@ -118,7 +105,7 @@ export const getSecret = async (token, secretId, baseUrl = DEFAULT_SERVICE_URLS.
|
|
|
118
105
|
}
|
|
119
106
|
catch (error) {
|
|
120
107
|
if (error.response?.status === 404) {
|
|
121
|
-
throw new Error(`Secret '${secretId}' not found
|
|
108
|
+
throw new Error(`Secret '${secretId}' not found.`, { cause: error });
|
|
122
109
|
}
|
|
123
110
|
throw error;
|
|
124
111
|
}
|
|
@@ -144,10 +131,10 @@ export const getSecret = async (token, secretId, baseUrl = DEFAULT_SERVICE_URLS.
|
|
|
144
131
|
export const updateSecret = async (token, secretId, data, baseUrl = DEFAULT_SERVICE_URLS.IAM) => {
|
|
145
132
|
validateToken(token);
|
|
146
133
|
validateRequiredString(secretId, 'Secret ID');
|
|
147
|
-
//
|
|
134
|
+
// Secret values are opaque. Send exactly what the owner supplied.
|
|
148
135
|
const requestBody = { ...data };
|
|
149
136
|
if (data.value) {
|
|
150
|
-
requestBody.value =
|
|
137
|
+
requestBody.value = data.value;
|
|
151
138
|
}
|
|
152
139
|
try {
|
|
153
140
|
return await requestDatalayerAPI({
|
|
@@ -159,7 +146,7 @@ export const updateSecret = async (token, secretId, data, baseUrl = DEFAULT_SERV
|
|
|
159
146
|
}
|
|
160
147
|
catch (error) {
|
|
161
148
|
if (error.response?.status === 404) {
|
|
162
|
-
throw new Error(`Secret '${secretId}' not found
|
|
149
|
+
throw new Error(`Secret '${secretId}' not found.`, { cause: error });
|
|
163
150
|
}
|
|
164
151
|
throw error;
|
|
165
152
|
}
|
|
@@ -189,7 +176,7 @@ export const deleteSecret = async (token, secretId, baseUrl = DEFAULT_SERVICE_UR
|
|
|
189
176
|
}
|
|
190
177
|
catch (error) {
|
|
191
178
|
if (error.response?.status === 404) {
|
|
192
|
-
throw new Error(`Secret '${secretId}' not found
|
|
179
|
+
throw new Error(`Secret '${secretId}' not found.`, { cause: error });
|
|
193
180
|
}
|
|
194
181
|
throw error;
|
|
195
182
|
}
|
|
@@ -0,0 +1,38 @@
|
|
|
1
|
+
/** Where a claim carries the trial's own key. */
|
|
2
|
+
export declare const TRIAL_TOKEN_HEADER = "X-Datalayer-Trial-Token";
|
|
3
|
+
/** What a visitor may try here, if anything. */
|
|
4
|
+
export interface TrialOffer {
|
|
5
|
+
offered: boolean;
|
|
6
|
+
/** The one benchmark a trial may run. */
|
|
7
|
+
evalsetId: string;
|
|
8
|
+
/** The credits it may spend. */
|
|
9
|
+
credits: number;
|
|
10
|
+
/** How long it lives, in seconds. */
|
|
11
|
+
ttlSeconds: number;
|
|
12
|
+
}
|
|
13
|
+
export interface Trial {
|
|
14
|
+
id: string;
|
|
15
|
+
/** The uid the trial's work is owned by, which is the trial's own. */
|
|
16
|
+
ownerUid: string;
|
|
17
|
+
state: 'open' | 'claimed' | 'expired';
|
|
18
|
+
evalsetId: string;
|
|
19
|
+
creditsLimit: number | null;
|
|
20
|
+
creditsSpent: number;
|
|
21
|
+
expiresAt: string | null;
|
|
22
|
+
claimedByUid: string;
|
|
23
|
+
claimedAt: string | null;
|
|
24
|
+
}
|
|
25
|
+
/** A trial and the key that acts as it. The key is answered once. */
|
|
26
|
+
export interface IssuedTrial {
|
|
27
|
+
trial: Trial;
|
|
28
|
+
token: string;
|
|
29
|
+
}
|
|
30
|
+
/**
|
|
31
|
+
* Whether this deployment lets a visitor try a benchmark, and which one.
|
|
32
|
+
* Unauthenticated: it is what a public page asks before it offers the run.
|
|
33
|
+
*/
|
|
34
|
+
export declare const getTrialOffer: (baseUrl?: string) => Promise<TrialOffer>;
|
|
35
|
+
/** Take a trial. Unauthenticated, rate limited, and refused where none are offered. */
|
|
36
|
+
export declare const createTrial: (baseUrl?: string) => Promise<IssuedTrial>;
|
|
37
|
+
/** The trial a key acts as: what it has left, and how long it has. */
|
|
38
|
+
export declare const getCurrentTrial: (trialToken: string, baseUrl?: string) => Promise<Trial>;
|
|
@@ -0,0 +1,66 @@
|
|
|
1
|
+
/*
|
|
2
|
+
* Copyright (c) 2023-2025 Datalayer, Inc.
|
|
3
|
+
* Distributed under the terms of the Modified BSD License.
|
|
4
|
+
*/
|
|
5
|
+
/*
|
|
6
|
+
* Copyright (c) 2023-2026 Datalayer, Inc.
|
|
7
|
+
* Distributed under the terms of the Modified BSD License.
|
|
8
|
+
*/
|
|
9
|
+
/**
|
|
10
|
+
* The anonymous trial: running the public benchmark before signing up
|
|
11
|
+
* (BENCHMARK.md, B2-14).
|
|
12
|
+
*
|
|
13
|
+
* A visitor with no account asks for a trial and gets a principal of its
|
|
14
|
+
* own with one benchmark it may run, a few credits and a short expiry. The
|
|
15
|
+
* work they make is owned by that principal, so when they sign up it is
|
|
16
|
+
* given to them rather than lost — `claimTrial` in the evals client moves
|
|
17
|
+
* it, and the trial's own key has to be presented alongside their new one.
|
|
18
|
+
*
|
|
19
|
+
* A deployment that has not named a public benchmark offers no trials, and
|
|
20
|
+
* `getTrialOffer` says so: a page asks before it shows the button.
|
|
21
|
+
*
|
|
22
|
+
* @module api/iam/trials
|
|
23
|
+
*/
|
|
24
|
+
import { requestDatalayerAPI } from '../DatalayerApi.js';
|
|
25
|
+
import { API_BASE_PATHS, DEFAULT_SERVICE_URLS } from '../constants.js';
|
|
26
|
+
/** Where a claim carries the trial's own key. */
|
|
27
|
+
export const TRIAL_TOKEN_HEADER = 'X-Datalayer-Trial-Token';
|
|
28
|
+
const trialsUrl = (baseUrl, suffix = '') => `${baseUrl}${API_BASE_PATHS.IAM}/trials${suffix}`;
|
|
29
|
+
const asTrial = (wire) => ({
|
|
30
|
+
id: wire.id,
|
|
31
|
+
ownerUid: wire.owner_uid ?? wire.id,
|
|
32
|
+
state: wire.state ?? 'open',
|
|
33
|
+
evalsetId: wire.evalset_id ?? '',
|
|
34
|
+
creditsLimit: wire.credits_limit ?? null,
|
|
35
|
+
creditsSpent: wire.credits_spent ?? 0,
|
|
36
|
+
expiresAt: wire.expires_at ?? null,
|
|
37
|
+
claimedByUid: wire.claimed_by_uid ?? '',
|
|
38
|
+
claimedAt: wire.claimed_at ?? null,
|
|
39
|
+
});
|
|
40
|
+
/**
|
|
41
|
+
* Whether this deployment lets a visitor try a benchmark, and which one.
|
|
42
|
+
* Unauthenticated: it is what a public page asks before it offers the run.
|
|
43
|
+
*/
|
|
44
|
+
export const getTrialOffer = async (baseUrl = DEFAULT_SERVICE_URLS.IAM) => {
|
|
45
|
+
const response = await requestDatalayerAPI({ url: trialsUrl(baseUrl, '/offer'), method: 'GET' });
|
|
46
|
+
return {
|
|
47
|
+
offered: !!response.offered,
|
|
48
|
+
evalsetId: response.evalset_id ?? '',
|
|
49
|
+
credits: response.credits ?? 0,
|
|
50
|
+
ttlSeconds: response.ttl_seconds ?? 0,
|
|
51
|
+
};
|
|
52
|
+
};
|
|
53
|
+
/** Take a trial. Unauthenticated, rate limited, and refused where none are offered. */
|
|
54
|
+
export const createTrial = async (baseUrl = DEFAULT_SERVICE_URLS.IAM) => {
|
|
55
|
+
const response = await requestDatalayerAPI({ url: trialsUrl(baseUrl), method: 'POST' });
|
|
56
|
+
return { trial: asTrial(response.trial), token: response.token };
|
|
57
|
+
};
|
|
58
|
+
/** The trial a key acts as: what it has left, and how long it has. */
|
|
59
|
+
export const getCurrentTrial = async (trialToken, baseUrl = DEFAULT_SERVICE_URLS.IAM) => {
|
|
60
|
+
const response = await requestDatalayerAPI({
|
|
61
|
+
url: trialsUrl(baseUrl, '/me'),
|
|
62
|
+
method: 'GET',
|
|
63
|
+
token: trialToken,
|
|
64
|
+
});
|
|
65
|
+
return asTrial(response.trial);
|
|
66
|
+
};
|
package/lib/api/index.d.ts
CHANGED
|
@@ -11,6 +11,10 @@ export type { IRequestDatalayerAPIOptions } from './DatalayerApi';
|
|
|
11
11
|
export type { IDatalayerAPIResponse } from './DatalayerApi';
|
|
12
12
|
export * as iam from './iam';
|
|
13
13
|
export * as contents from './contents';
|
|
14
|
+
export * as evals from './evals';
|
|
14
15
|
export * as mcp from './mcp';
|
|
16
|
+
export * as orchestration from './orchestration';
|
|
15
17
|
export * as otel from './otel';
|
|
18
|
+
export * as scheduler from './scheduler';
|
|
19
|
+
export * as spacer from './spacer';
|
|
16
20
|
export * from '../api/DatalayerApi';
|
package/lib/api/index.js
CHANGED
|
@@ -15,6 +15,10 @@ export { requestDatalayerAPI, requestDatalayerAPIWithResponse, RunResponseError,
|
|
|
15
15
|
// Domain-organized API exports
|
|
16
16
|
export * as iam from './iam/index.js';
|
|
17
17
|
export * as contents from './contents/index.js';
|
|
18
|
+
export * as evals from './evals/index.js';
|
|
18
19
|
export * as mcp from './mcp/index.js';
|
|
20
|
+
export * as orchestration from './orchestration/index.js';
|
|
19
21
|
export * as otel from './otel/index.js';
|
|
22
|
+
export * as scheduler from './scheduler/index.js';
|
|
23
|
+
export * as spacer from './spacer/index.js';
|
|
20
24
|
export * from '../api/DatalayerApi.js';
|
|
@@ -1,4 +1,5 @@
|
|
|
1
|
-
import
|
|
1
|
+
import { type DashboardData } from '../otel/dashboards';
|
|
2
|
+
import type { OtelLog, OtelSpan } from '../otel/types';
|
|
2
3
|
import type { McpTask } from '../../models/McpTask';
|
|
3
4
|
/**
|
|
4
5
|
* The `service.name` the gateway exports under, and the one its workers use.
|
|
@@ -9,8 +10,15 @@ import type { McpTask } from '../../models/McpTask';
|
|
|
9
10
|
* queryable after the process is gone.
|
|
10
11
|
*/
|
|
11
12
|
export declare const MCP_GATEWAY_SERVICE_NAME = "jupyter-mcp-server";
|
|
12
|
-
/**
|
|
13
|
-
|
|
13
|
+
/**
|
|
14
|
+
* The `service.name` a worker's relayed output is filed under.
|
|
15
|
+
*
|
|
16
|
+
* `mcp-worker` since the service was renamed to `datalayer-mcp-server`: the
|
|
17
|
+
* gateway names its workers, and a name carrying `jupyter` said the wrong
|
|
18
|
+
* thing about a process that serves Datalayer sandboxes as readily as a
|
|
19
|
+
* Jupyter server.
|
|
20
|
+
*/
|
|
21
|
+
export declare const MCP_WORKER_SERVICE_NAME = "mcp-worker";
|
|
14
22
|
/**
|
|
15
23
|
* The `service.name` the durable execution service exports under.
|
|
16
24
|
*
|
|
@@ -40,11 +48,25 @@ export declare const MCP_SLI_METRICS: {
|
|
|
40
48
|
readonly taskSuccess: "mcp.tasks";
|
|
41
49
|
readonly sandboxLaunch: "sandbox.launch_seconds";
|
|
42
50
|
};
|
|
51
|
+
/** The OTEL service's built-in dashboard the four SLIs are read from. */
|
|
52
|
+
export declare const MCP_SERVICE_LEVELS_DASHBOARD = "mcp-service-levels";
|
|
53
|
+
/**
|
|
54
|
+
* Its panels, by the ids the OTEL service gives them. A contract test there
|
|
55
|
+
* holds them, so a panel renamed on the service fails a test rather than
|
|
56
|
+
* reading here as nothing measured.
|
|
57
|
+
*/
|
|
58
|
+
export declare const MCP_SERVICE_LEVEL_PANELS: {
|
|
59
|
+
readonly callsByOutcome: "mcp-calls-by-outcome";
|
|
60
|
+
readonly callDurationP95: "mcp-call-duration-p95";
|
|
61
|
+
readonly tasksByStatus: "mcp-tasks-by-status";
|
|
62
|
+
readonly sandboxLaunchP95: "sandbox-launch_seconds-by-provider-p95";
|
|
63
|
+
readonly sandboxLaunches: "sandbox-launch_seconds-by-provider-count";
|
|
64
|
+
};
|
|
43
65
|
export interface McpMetricsFilters {
|
|
44
66
|
/** The `client_id` of one agent: read from spans, not from metrics. */
|
|
45
67
|
agent?: string;
|
|
46
68
|
org?: string;
|
|
47
|
-
/** ISO 8601;
|
|
69
|
+
/** ISO 8601; the reading starts there. */
|
|
48
70
|
since?: string;
|
|
49
71
|
limit?: number;
|
|
50
72
|
}
|
|
@@ -66,8 +88,8 @@ export interface McpSliSummary {
|
|
|
66
88
|
}
|
|
67
89
|
export interface McpMetricsSnapshot {
|
|
68
90
|
filters: McpMetricsFilters;
|
|
69
|
-
/** The catalog points
|
|
70
|
-
|
|
91
|
+
/** The catalog metrics the OTEL service holds points of, in catalog order. */
|
|
92
|
+
reporting: McpMetricName[];
|
|
71
93
|
/** The `mcp.request` spans a per-agent or per-organization reading rests on. */
|
|
72
94
|
spans: OtelSpan[];
|
|
73
95
|
slis: McpSliSummary;
|
|
@@ -76,13 +98,14 @@ export interface McpMetricsSnapshot {
|
|
|
76
98
|
/** The nearest-rank percentile of a sample; `null` for an empty one. */
|
|
77
99
|
export declare const percentile: (values: number[], fraction: number) => number | null;
|
|
78
100
|
/**
|
|
79
|
-
* The SLIs
|
|
101
|
+
* The SLIs from the service levels dashboard — the platform-wide reading.
|
|
80
102
|
*
|
|
81
|
-
*
|
|
82
|
-
*
|
|
83
|
-
*
|
|
103
|
+
* Its panels arrive summarised: calls and tasks as how much each counter grew
|
|
104
|
+
* over the window, the two p95s from their histograms' buckets. The call
|
|
105
|
+
* duration is recorded in seconds and shown in milliseconds. A panel with
|
|
106
|
+
* nothing in it reads as not measured, never as a zero.
|
|
84
107
|
*/
|
|
85
|
-
export declare const
|
|
108
|
+
export declare const summarizeServiceLevels: (data: DashboardData) => McpSliSummary;
|
|
86
109
|
/**
|
|
87
110
|
* The SLIs over `mcp.request` spans — the per-agent or per-organization
|
|
88
111
|
* reading, since metrics carry neither label.
|