@datalayer/core 1.2.10 → 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 +2 -2
- package/lib/api/iam/authentication.js +6 -4
- package/lib/api/iam/healthz.js +2 -2
- package/lib/api/iam/oauth2.js +18 -12
- package/lib/api/iam/secrets.js +1 -2
- package/lib/api/mcp/observability.d.ts +9 -2
- package/lib/api/mcp/observability.js +40 -15
- package/lib/client/auth/strategies.js +1 -1
- package/lib/client/mixins/IAMMixin.js +2 -2
- package/lib/components/checkout/StripeCheckout.d.ts +1 -1
- package/lib/components/checkout/StripeCheckout.js +1 -1
- package/lib/components/display/VisuallyHidden.d.ts +1 -2
- package/lib/components/sharing/sandboxSharing.js +7 -1
- 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/useBackdrop.d.ts +4 -5
- package/lib/hooks/useCache.d.ts +29 -19
- package/lib/hooks/useCache.js +164 -189
- package/lib/hooks/useMcp.js +1 -1
- package/lib/hooks/useNavigate.js +10 -0
- package/lib/hooks/useWindowSize.js +1 -1
- package/lib/models/IAMProvidersSpecs.d.ts +10 -5
- package/lib/models/IAMProvidersSpecs.js +0 -23
- package/lib/navigation/adapters/react-router.d.ts +1 -1
- package/lib/navigation/adapters/react-router.js +3 -0
- package/lib/state/sessionEnd.js +1 -1
- package/lib/state/substates/CoreState.js +3 -16
- package/lib/state/substates/IAMState.d.ts +3 -3
- package/lib/state/substates/NavigationState.d.ts +82 -0
- package/lib/state/substates/NavigationState.js +255 -0
- package/lib/state/substates/index.d.ts +1 -0
- package/lib/state/substates/index.js +1 -0
- package/lib/utils/Screencapture.d.ts +15 -0
- package/lib/utils/Screencapture.js +26 -23
- package/lib/views/mcp/McpHome.js +1 -1
- package/package.json +6 -4
- package/scripts/generate-mcp-types.py +15 -9
package/lib/hooks/useCache.js
CHANGED
|
@@ -727,6 +727,10 @@ export const useCache = ({ loginRoute = '/login' } = {}) => {
|
|
|
727
727
|
*/
|
|
728
728
|
if (raw.publicUrl)
|
|
729
729
|
meta.publicUrl = raw.publicUrl;
|
|
730
|
+
if (raw.shareCardUrl)
|
|
731
|
+
meta.shareCardUrl = raw.shareCardUrl;
|
|
732
|
+
if (raw.shareCardVersion)
|
|
733
|
+
meta.shareCardVersion = raw.shareCardVersion;
|
|
730
734
|
return meta;
|
|
731
735
|
};
|
|
732
736
|
/**
|
|
@@ -6853,6 +6857,104 @@ export const useCache = ({ loginRoute = '/login' } = {}) => {
|
|
|
6853
6857
|
onSuccess: invalidateArtifactVisibility,
|
|
6854
6858
|
});
|
|
6855
6859
|
};
|
|
6860
|
+
/** Publish a public artifact natively to LinkedIn through Library's saga. */
|
|
6861
|
+
const usePublishLinkedInShare = () => {
|
|
6862
|
+
return useMutation({
|
|
6863
|
+
mutationFn: async ({ itemId, commentary, idempotencyKey, imageDataUrl, imageAltText, }) => {
|
|
6864
|
+
const resp = await requestDatalayer({
|
|
6865
|
+
url: `${configuration.libraryUrl}/api/library/v1/items/${encodeURIComponent(itemId)}/shares/linkedin`,
|
|
6866
|
+
method: 'POST',
|
|
6867
|
+
headers: { 'Idempotency-Key': idempotencyKey },
|
|
6868
|
+
body: { commentary, imageDataUrl, imageAltText },
|
|
6869
|
+
});
|
|
6870
|
+
if (!resp.success) {
|
|
6871
|
+
throw new Error(resp.message || 'Failed to publish to LinkedIn');
|
|
6872
|
+
}
|
|
6873
|
+
return resp.share;
|
|
6874
|
+
},
|
|
6875
|
+
});
|
|
6876
|
+
};
|
|
6877
|
+
const useUnpublishLinkedInShare = () => {
|
|
6878
|
+
return useMutation({
|
|
6879
|
+
mutationFn: async (idempotencyKey) => {
|
|
6880
|
+
const resp = await requestDatalayer({
|
|
6881
|
+
url: `${configuration.libraryUrl}/api/library/v1/shares/linkedin/${encodeURIComponent(idempotencyKey)}`,
|
|
6882
|
+
method: 'DELETE',
|
|
6883
|
+
});
|
|
6884
|
+
if (!resp.success) {
|
|
6885
|
+
throw new Error(resp.message || 'Failed to unpublish from LinkedIn');
|
|
6886
|
+
}
|
|
6887
|
+
return resp.share;
|
|
6888
|
+
},
|
|
6889
|
+
});
|
|
6890
|
+
};
|
|
6891
|
+
const useLinkedInShares = (itemId, enabled = true) => {
|
|
6892
|
+
return useQuery({
|
|
6893
|
+
queryKey: ['library', 'social-shares', 'linkedin', itemId],
|
|
6894
|
+
queryFn: async () => {
|
|
6895
|
+
const resp = await requestDatalayer({
|
|
6896
|
+
url: `${configuration.libraryUrl}/api/library/v1/items/${encodeURIComponent(itemId)}/shares/linkedin`,
|
|
6897
|
+
method: 'GET',
|
|
6898
|
+
notifyOnError: false,
|
|
6899
|
+
});
|
|
6900
|
+
if (!resp.success) {
|
|
6901
|
+
throw new Error(resp.message || 'Failed to load LinkedIn publications');
|
|
6902
|
+
}
|
|
6903
|
+
return Array.isArray(resp.shares) ? resp.shares : [];
|
|
6904
|
+
},
|
|
6905
|
+
...DEFAULT_QUERY_OPTIONS,
|
|
6906
|
+
enabled: Boolean(configuration.libraryUrl) && Boolean(itemId) && enabled,
|
|
6907
|
+
});
|
|
6908
|
+
};
|
|
6909
|
+
/** Publish one selected public result through the durable Bluesky saga. */
|
|
6910
|
+
const usePublishBlueskyShare = () => {
|
|
6911
|
+
return useMutation({
|
|
6912
|
+
mutationFn: async ({ itemId, finding, cellId, outputIndex, idempotencyKey, imageDataUrl, imageAltText, }) => {
|
|
6913
|
+
const resp = await requestDatalayer({
|
|
6914
|
+
url: `${configuration.libraryUrl}/api/library/v1/items/${encodeURIComponent(itemId)}/shares/bluesky`,
|
|
6915
|
+
method: 'POST',
|
|
6916
|
+
headers: { 'Idempotency-Key': idempotencyKey },
|
|
6917
|
+
body: { finding, cellId, outputIndex, imageDataUrl, imageAltText },
|
|
6918
|
+
});
|
|
6919
|
+
if (!resp.success) {
|
|
6920
|
+
throw new Error(resp.message || 'Failed to publish to Bluesky');
|
|
6921
|
+
}
|
|
6922
|
+
return resp.share;
|
|
6923
|
+
},
|
|
6924
|
+
});
|
|
6925
|
+
};
|
|
6926
|
+
const useUnpublishBlueskyShare = () => {
|
|
6927
|
+
return useMutation({
|
|
6928
|
+
mutationFn: async (idempotencyKey) => {
|
|
6929
|
+
const resp = await requestDatalayer({
|
|
6930
|
+
url: `${configuration.libraryUrl}/api/library/v1/shares/bluesky/${encodeURIComponent(idempotencyKey)}`,
|
|
6931
|
+
method: 'DELETE',
|
|
6932
|
+
});
|
|
6933
|
+
if (!resp.success) {
|
|
6934
|
+
throw new Error(resp.message || 'Failed to unpublish from Bluesky');
|
|
6935
|
+
}
|
|
6936
|
+
return resp.share;
|
|
6937
|
+
},
|
|
6938
|
+
});
|
|
6939
|
+
};
|
|
6940
|
+
const useBlueskyShares = (itemId, enabled = true) => {
|
|
6941
|
+
return useQuery({
|
|
6942
|
+
queryKey: ['library', 'social-shares', 'bluesky', itemId],
|
|
6943
|
+
queryFn: async () => {
|
|
6944
|
+
const resp = await requestDatalayer({
|
|
6945
|
+
url: `${configuration.libraryUrl}/api/library/v1/items/${encodeURIComponent(itemId)}/shares/bluesky`,
|
|
6946
|
+
method: 'GET',
|
|
6947
|
+
notifyOnError: false,
|
|
6948
|
+
});
|
|
6949
|
+
if (!resp.success) {
|
|
6950
|
+
throw new Error(resp.message || 'Failed to load Bluesky publications');
|
|
6951
|
+
}
|
|
6952
|
+
return Array.isArray(resp.shares) ? resp.shares : [];
|
|
6953
|
+
},
|
|
6954
|
+
...DEFAULT_QUERY_OPTIONS,
|
|
6955
|
+
enabled: Boolean(configuration.libraryUrl) && Boolean(itemId) && enabled,
|
|
6956
|
+
});
|
|
6957
|
+
};
|
|
6856
6958
|
/**
|
|
6857
6959
|
* Tell the library that an artifact was reused: cloned into a space, or
|
|
6858
6960
|
* instantiated as a runtime. The reuse itself belongs to the service that
|
|
@@ -6860,11 +6962,14 @@ export const useCache = ({ loginRoute = '/login' } = {}) => {
|
|
|
6860
6962
|
*/
|
|
6861
6963
|
const useCountItemReuse = () => {
|
|
6862
6964
|
return useMutation({
|
|
6863
|
-
mutationFn: async ({ itemId, kind, }) => {
|
|
6965
|
+
mutationFn: async ({ itemId, kind, signupSource, shareRef, }) => {
|
|
6864
6966
|
const resp = await requestDatalayer({
|
|
6865
6967
|
url: `${configuration.libraryUrl}/api/library/v1/items/${encodeURIComponent(itemId)}/reused`,
|
|
6866
6968
|
method: 'POST',
|
|
6867
|
-
body: {
|
|
6969
|
+
body: {
|
|
6970
|
+
kind,
|
|
6971
|
+
...(signupSource && shareRef ? { signupSource, shareRef } : {}),
|
|
6972
|
+
},
|
|
6868
6973
|
});
|
|
6869
6974
|
if (!resp.success) {
|
|
6870
6975
|
throw new Error(resp.message || 'Failed to count the reuse');
|
|
@@ -7062,215 +7167,80 @@ export const useCache = ({ loginRoute = '/login' } = {}) => {
|
|
|
7062
7167
|
},
|
|
7063
7168
|
});
|
|
7064
7169
|
};
|
|
7065
|
-
/**
|
|
7066
|
-
* Get LinkedIn profile via proxy
|
|
7067
|
-
*/
|
|
7170
|
+
/** Get the server-connected LinkedIn profile. */
|
|
7068
7171
|
const useGetLinkedinProfile = () => {
|
|
7069
7172
|
return useMutation({
|
|
7070
|
-
mutationFn: async (
|
|
7173
|
+
mutationFn: async () => {
|
|
7071
7174
|
return requestDatalayer({
|
|
7072
|
-
url: `${configuration.iamUrl}/api/iam/v1/
|
|
7073
|
-
method: '
|
|
7074
|
-
body: {
|
|
7075
|
-
request_method: 'GET',
|
|
7076
|
-
request_url: 'https://api.linkedin.com/v2/userinfo',
|
|
7077
|
-
request_token: accessToken,
|
|
7078
|
-
},
|
|
7175
|
+
url: `${configuration.iamUrl}/api/iam/v1/social/linkedin/profile`,
|
|
7176
|
+
method: 'GET',
|
|
7079
7177
|
});
|
|
7080
7178
|
},
|
|
7081
7179
|
});
|
|
7082
7180
|
};
|
|
7083
|
-
/**
|
|
7084
|
-
* Post LinkedIn share
|
|
7085
|
-
*/
|
|
7181
|
+
/** Publish a LinkedIn text post through the server-held connection. */
|
|
7086
7182
|
const usePostLinkedinShare = () => {
|
|
7087
7183
|
return useMutation({
|
|
7088
|
-
mutationFn: async ({
|
|
7089
|
-
const postShareRequest = {
|
|
7090
|
-
author: linkedinUserUrn,
|
|
7091
|
-
lifecycleState: 'PUBLISHED',
|
|
7092
|
-
specificContent: {
|
|
7093
|
-
'com.linkedin.ugc.ShareContent': {
|
|
7094
|
-
shareCommentary: { text: postText },
|
|
7095
|
-
shareMediaCategory: 'NONE',
|
|
7096
|
-
},
|
|
7097
|
-
},
|
|
7098
|
-
visibility: {
|
|
7099
|
-
'com.linkedin.ugc.MemberNetworkVisibility': 'PUBLIC',
|
|
7100
|
-
},
|
|
7101
|
-
};
|
|
7184
|
+
mutationFn: async ({ postText }) => {
|
|
7102
7185
|
return requestDatalayer({
|
|
7103
|
-
url: `${configuration.iamUrl}/api/iam/v1/
|
|
7186
|
+
url: `${configuration.iamUrl}/api/iam/v1/social/linkedin/posts`,
|
|
7104
7187
|
method: 'POST',
|
|
7105
|
-
body: {
|
|
7106
|
-
request_method: 'POST',
|
|
7107
|
-
request_url: 'https://api.linkedin.com/v2/ugcPosts',
|
|
7108
|
-
request_token: accessToken,
|
|
7109
|
-
request_body: postShareRequest,
|
|
7110
|
-
},
|
|
7188
|
+
body: { commentary: postText },
|
|
7111
7189
|
});
|
|
7112
7190
|
},
|
|
7113
7191
|
});
|
|
7114
7192
|
};
|
|
7115
|
-
/**
|
|
7116
|
-
* Post LinkedIn share with image upload
|
|
7117
|
-
*/
|
|
7193
|
+
/** Publish a LinkedIn post, optionally with one uploaded image. */
|
|
7118
7194
|
const usePostLinkedinShareWithUpload = () => {
|
|
7119
7195
|
return useMutation({
|
|
7120
|
-
mutationFn: async ({
|
|
7121
|
-
let shareRequest;
|
|
7122
|
-
if (uploadObject) {
|
|
7123
|
-
// Step 1: Register upload
|
|
7124
|
-
const registerUploadRequest = {
|
|
7125
|
-
registerUploadRequest: {
|
|
7126
|
-
recipes: ['urn:li:digitalmediaRecipe:feedshare-image'],
|
|
7127
|
-
owner: linkedinUserUrn,
|
|
7128
|
-
serviceRelationships: [
|
|
7129
|
-
{
|
|
7130
|
-
relationshipType: 'OWNER',
|
|
7131
|
-
identifier: 'urn:li:userGeneratedContent',
|
|
7132
|
-
},
|
|
7133
|
-
],
|
|
7134
|
-
},
|
|
7135
|
-
};
|
|
7136
|
-
const registerResp = await requestDatalayer({
|
|
7137
|
-
url: `${configuration.iamUrl}/api/iam/v1/proxy/request`,
|
|
7138
|
-
method: 'POST',
|
|
7139
|
-
body: {
|
|
7140
|
-
request_method: 'POST',
|
|
7141
|
-
request_url: 'https://api.linkedin.com/v2/assets?action=registerUpload',
|
|
7142
|
-
request_token: accessToken,
|
|
7143
|
-
request_body: registerUploadRequest,
|
|
7144
|
-
},
|
|
7145
|
-
});
|
|
7146
|
-
const asset = registerResp.response.value.asset;
|
|
7147
|
-
const uploadUrl = registerResp.response.value.uploadMechanism['com.linkedin.digitalmedia.uploading.MediaUploadHttpRequest'].uploadUrl;
|
|
7148
|
-
// Step 2: Upload image
|
|
7149
|
-
await requestDatalayer({
|
|
7150
|
-
url: `${configuration.iamUrl}/api/iam/v1/proxy/request`,
|
|
7151
|
-
method: 'POST',
|
|
7152
|
-
body: {
|
|
7153
|
-
request_method: 'PUT',
|
|
7154
|
-
request_url: uploadUrl,
|
|
7155
|
-
request_token: accessToken,
|
|
7156
|
-
request_body: {
|
|
7157
|
-
uploadURL: uploadUrl,
|
|
7158
|
-
content: uploadObject,
|
|
7159
|
-
userURN: linkedinUserUrn,
|
|
7160
|
-
},
|
|
7161
|
-
},
|
|
7162
|
-
});
|
|
7163
|
-
// Step 3: Create share with media
|
|
7164
|
-
shareRequest = {
|
|
7165
|
-
author: linkedinUserUrn,
|
|
7166
|
-
lifecycleState: 'PUBLISHED',
|
|
7167
|
-
specificContent: {
|
|
7168
|
-
'com.linkedin.ugc.ShareContent': {
|
|
7169
|
-
shareCommentary: { text: postText },
|
|
7170
|
-
shareMediaCategory: 'IMAGE',
|
|
7171
|
-
media: [
|
|
7172
|
-
{
|
|
7173
|
-
status: 'READY',
|
|
7174
|
-
description: { text: 'Datalayer Notebook' },
|
|
7175
|
-
media: asset,
|
|
7176
|
-
title: { text: 'Datalayer Notebook' },
|
|
7177
|
-
},
|
|
7178
|
-
],
|
|
7179
|
-
},
|
|
7180
|
-
},
|
|
7181
|
-
visibility: {
|
|
7182
|
-
'com.linkedin.ugc.MemberNetworkVisibility': 'PUBLIC',
|
|
7183
|
-
},
|
|
7184
|
-
};
|
|
7185
|
-
}
|
|
7186
|
-
else {
|
|
7187
|
-
// Text-only share (no image upload)
|
|
7188
|
-
shareRequest = {
|
|
7189
|
-
author: linkedinUserUrn,
|
|
7190
|
-
lifecycleState: 'PUBLISHED',
|
|
7191
|
-
specificContent: {
|
|
7192
|
-
'com.linkedin.ugc.ShareContent': {
|
|
7193
|
-
shareCommentary: { text: postText },
|
|
7194
|
-
shareMediaCategory: 'NONE',
|
|
7195
|
-
},
|
|
7196
|
-
},
|
|
7197
|
-
visibility: {
|
|
7198
|
-
'com.linkedin.ugc.MemberNetworkVisibility': 'PUBLIC',
|
|
7199
|
-
},
|
|
7200
|
-
};
|
|
7201
|
-
}
|
|
7196
|
+
mutationFn: async ({ postText, uploadObject, }) => {
|
|
7202
7197
|
return requestDatalayer({
|
|
7203
|
-
url: `${configuration.iamUrl}/api/iam/v1/
|
|
7198
|
+
url: `${configuration.iamUrl}/api/iam/v1/social/linkedin/posts`,
|
|
7204
7199
|
method: 'POST',
|
|
7205
7200
|
body: {
|
|
7206
|
-
|
|
7207
|
-
|
|
7208
|
-
request_token: accessToken,
|
|
7209
|
-
request_body: shareRequest,
|
|
7210
|
-
},
|
|
7211
|
-
});
|
|
7212
|
-
},
|
|
7213
|
-
});
|
|
7214
|
-
};
|
|
7215
|
-
// ============================================================================
|
|
7216
|
-
// Proxy Operations
|
|
7217
|
-
// ============================================================================
|
|
7218
|
-
/**
|
|
7219
|
-
* Proxy GET request
|
|
7220
|
-
*/
|
|
7221
|
-
const useProxyGET = () => {
|
|
7222
|
-
return useMutation({
|
|
7223
|
-
mutationFn: async ({ url, token }) => {
|
|
7224
|
-
return requestDatalayer({
|
|
7225
|
-
url: `${configuration.iamUrl}/api/iam/v1/proxy/request`,
|
|
7226
|
-
method: 'POST',
|
|
7227
|
-
body: {
|
|
7228
|
-
request_method: 'GET',
|
|
7229
|
-
request_url: url,
|
|
7230
|
-
request_token: token,
|
|
7231
|
-
},
|
|
7232
|
-
});
|
|
7233
|
-
},
|
|
7234
|
-
});
|
|
7235
|
-
};
|
|
7236
|
-
/**
|
|
7237
|
-
* Proxy POST request
|
|
7238
|
-
*/
|
|
7239
|
-
const useProxyPOST = () => {
|
|
7240
|
-
return useMutation({
|
|
7241
|
-
mutationFn: async ({ url, body, token, }) => {
|
|
7242
|
-
return requestDatalayer({
|
|
7243
|
-
url: `${configuration.iamUrl}/api/iam/v1/proxy/request`,
|
|
7244
|
-
method: 'POST',
|
|
7245
|
-
body: {
|
|
7246
|
-
request_method: 'POST',
|
|
7247
|
-
request_url: url,
|
|
7248
|
-
request_token: token,
|
|
7249
|
-
request_body: body,
|
|
7201
|
+
commentary: postText,
|
|
7202
|
+
image_data_url: uploadObject,
|
|
7250
7203
|
},
|
|
7251
7204
|
});
|
|
7252
7205
|
},
|
|
7253
7206
|
});
|
|
7254
7207
|
};
|
|
7208
|
+
/** Connect-only AT Protocol account operations. */
|
|
7209
|
+
const useGetBlueskyConnection = () => useMutation({
|
|
7210
|
+
mutationFn: async () => requestDatalayer({
|
|
7211
|
+
url: `${configuration.iamUrl}/api/iam/v1/social/bluesky/profile`,
|
|
7212
|
+
method: 'GET',
|
|
7213
|
+
notifyOnError: false,
|
|
7214
|
+
}),
|
|
7215
|
+
});
|
|
7255
7216
|
/**
|
|
7256
|
-
*
|
|
7257
|
-
|
|
7258
|
-
|
|
7259
|
-
|
|
7260
|
-
|
|
7261
|
-
|
|
7262
|
-
|
|
7263
|
-
|
|
7264
|
-
|
|
7265
|
-
|
|
7266
|
-
|
|
7267
|
-
|
|
7268
|
-
|
|
7269
|
-
|
|
7270
|
-
|
|
7271
|
-
|
|
7272
|
-
|
|
7273
|
-
|
|
7217
|
+
* Begin a Bluesky connection.
|
|
7218
|
+
*
|
|
7219
|
+
* `returnOrigin` is where the reader should come back to — their own origin,
|
|
7220
|
+
* so a connection begun on a developer's machine does not end on
|
|
7221
|
+
* production. IAM takes the origin only and builds the address itself, so
|
|
7222
|
+
* this cannot ask to be sent anywhere.
|
|
7223
|
+
*/
|
|
7224
|
+
const useConnectBluesky = () => useMutation({
|
|
7225
|
+
mutationFn: async (asked) => {
|
|
7226
|
+
const { identifier, returnOrigin } = typeof asked === 'string'
|
|
7227
|
+
? { identifier: asked, returnOrigin: undefined }
|
|
7228
|
+
: asked;
|
|
7229
|
+
return requestDatalayer({
|
|
7230
|
+
url: `${configuration.iamUrl}/api/iam/v1/social/bluesky/connect`,
|
|
7231
|
+
method: 'POST',
|
|
7232
|
+
body: returnOrigin
|
|
7233
|
+
? { identifier, return_origin: returnOrigin }
|
|
7234
|
+
: { identifier },
|
|
7235
|
+
});
|
|
7236
|
+
},
|
|
7237
|
+
});
|
|
7238
|
+
const useDisconnectBluesky = () => useMutation({
|
|
7239
|
+
mutationFn: async () => requestDatalayer({
|
|
7240
|
+
url: `${configuration.iamUrl}/api/iam/v1/social/bluesky/connection`,
|
|
7241
|
+
method: 'DELETE',
|
|
7242
|
+
}),
|
|
7243
|
+
});
|
|
7274
7244
|
// ============================================================================
|
|
7275
7245
|
// Waiting List & Growth
|
|
7276
7246
|
// ============================================================================
|
|
@@ -8319,11 +8289,16 @@ export const useCache = ({ loginRoute = '/login' } = {}) => {
|
|
|
8319
8289
|
useGetLinkedinProfile,
|
|
8320
8290
|
usePostLinkedinShare,
|
|
8321
8291
|
usePostLinkedinShareWithUpload,
|
|
8292
|
+
useGetBlueskyConnection,
|
|
8293
|
+
useConnectBluesky,
|
|
8294
|
+
useDisconnectBluesky,
|
|
8295
|
+
usePublishLinkedInShare,
|
|
8296
|
+
useUnpublishLinkedInShare,
|
|
8297
|
+
useLinkedInShares,
|
|
8298
|
+
usePublishBlueskyShare,
|
|
8299
|
+
useUnpublishBlueskyShare,
|
|
8300
|
+
useBlueskyShares,
|
|
8322
8301
|
useRegisterToWaitingList,
|
|
8323
|
-
// Proxy
|
|
8324
|
-
useProxyGET,
|
|
8325
|
-
useProxyPOST,
|
|
8326
|
-
useProxyPUT,
|
|
8327
8302
|
// Users
|
|
8328
8303
|
useUser,
|
|
8329
8304
|
useUserByHandle,
|
package/lib/hooks/useMcp.js
CHANGED
|
@@ -34,7 +34,7 @@ import { deleteMcpPolicy, getAdmittedClients, getMcpPolicy, setMcpPolicy, } from
|
|
|
34
34
|
import { createServiceAgent, listServiceAgents, revokeServiceAgent, rotateServiceAgentKey, } from '../api/iam/serviceAgents.js';
|
|
35
35
|
import { useCoreStore, useIAMStore } from '../state/index.js';
|
|
36
36
|
import { queryKeys } from './useCache.js';
|
|
37
|
-
const useMcpServerUrl = () => useCoreStore(state => state.configuration.
|
|
37
|
+
const useMcpServerUrl = () => useCoreStore(state => state.configuration.datalayerMcpServerUrl);
|
|
38
38
|
const useIamUrl = () => useCoreStore(state => state.configuration.iamUrl);
|
|
39
39
|
const useOtelUrl = () => useCoreStore(state => state.configuration.otelUrl);
|
|
40
40
|
// -- Tasks -----------------------------------------------------------------
|
package/lib/hooks/useNavigate.js
CHANGED
|
@@ -14,10 +14,17 @@
|
|
|
14
14
|
* `window.open` otherwise, so a button gets it too. `newTab` in the options
|
|
15
15
|
* opens a new tab outright.
|
|
16
16
|
*
|
|
17
|
+
* Every navigation that stays in this tab is also **recorded** against the
|
|
18
|
+
* shell the reader is in ({@link state/substates/NavigationState}). That is
|
|
19
|
+
* what lets a reader switch from Agentify back to Home and find the page they
|
|
20
|
+
* left rather than a landing page, and it is done here — the one place every
|
|
21
|
+
* navigation goes through — rather than in an effect per layout.
|
|
22
|
+
*
|
|
17
23
|
* @module hooks/useNavigate
|
|
18
24
|
*/
|
|
19
25
|
import { useCallback, useMemo } from 'react';
|
|
20
26
|
import { useLayoutStore } from '../state/index.js';
|
|
27
|
+
import { navigationStore } from '../state/substates/NavigationState.js';
|
|
21
28
|
import { createNativeNavigate } from '../navigation/adapters/native.js';
|
|
22
29
|
// Import React Router hooks from our wrapper
|
|
23
30
|
import { useNavigateRR } from '../navigation/adapters/react-router.js';
|
|
@@ -125,6 +132,9 @@ export const useNavigate = () => {
|
|
|
125
132
|
window.scrollTo(0, 0);
|
|
126
133
|
document.body.scrollTop = 0;
|
|
127
134
|
}
|
|
135
|
+
// Where the reader is now, for the shell they are in. A new tab and a
|
|
136
|
+
// step back through history are both already past by here.
|
|
137
|
+
navigationStore.getState().rememberRoute(to);
|
|
128
138
|
if (rrNavigate) {
|
|
129
139
|
rrNavigate(to, { replace: options.replace, state: options.state });
|
|
130
140
|
return;
|
|
@@ -1,9 +1,15 @@
|
|
|
1
1
|
import { IUser } from './User';
|
|
2
2
|
export type IIAMProviderName = 'bluesky' | 'discord' | 'github' | 'google' | 'linkedin' | 'okta' | 'x';
|
|
3
|
+
/** Providers whose access token is intentionally available to browser code. */
|
|
4
|
+
export type IBrowserTokenProviderName = Exclude<IIAMProviderName, 'bluesky' | 'linkedin'>;
|
|
3
5
|
export type IIAMProviderSpec = {
|
|
4
6
|
name: IIAMProviderName;
|
|
5
7
|
oauth2CallbackServerRoute: string;
|
|
6
8
|
oauth2CallbackUIRoute: string;
|
|
9
|
+
};
|
|
10
|
+
/** Provider metadata used only when its access token may be read by the UI. */
|
|
11
|
+
export type IBrowserTokenProviderSpec = IIAMProviderSpec & {
|
|
12
|
+
name: IBrowserTokenProviderName;
|
|
7
13
|
accessTokenCookieName: (user: IUser) => string;
|
|
8
14
|
refreshTokenCookieName: string;
|
|
9
15
|
userInfoURL: string;
|
|
@@ -13,11 +19,10 @@ export type IIAMProviderSpec = {
|
|
|
13
19
|
};
|
|
14
20
|
export declare class IAMProvidersSpecs {
|
|
15
21
|
private constructor();
|
|
16
|
-
static getProvider(providerIAMProvidersType:
|
|
17
|
-
static readonly
|
|
18
|
-
static readonly
|
|
19
|
-
static readonly Google: IIAMProviderSpec;
|
|
22
|
+
static getProvider(providerIAMProvidersType: IBrowserTokenProviderName): IBrowserTokenProviderSpec;
|
|
23
|
+
static readonly GitHub: IBrowserTokenProviderSpec;
|
|
24
|
+
static readonly Google: IBrowserTokenProviderSpec;
|
|
20
25
|
static readonly LinkedIn: IIAMProviderSpec;
|
|
21
|
-
static readonly Okta:
|
|
26
|
+
static readonly Okta: IBrowserTokenProviderSpec;
|
|
22
27
|
}
|
|
23
28
|
export default IAMProvidersSpecs;
|
|
@@ -6,18 +6,12 @@ export class IAMProvidersSpecs {
|
|
|
6
6
|
constructor() { }
|
|
7
7
|
static getProvider(providerIAMProvidersType) {
|
|
8
8
|
switch (providerIAMProvidersType) {
|
|
9
|
-
case 'bluesky': {
|
|
10
|
-
return this.Bluesky;
|
|
11
|
-
}
|
|
12
9
|
case 'github': {
|
|
13
10
|
return this.GitHub;
|
|
14
11
|
}
|
|
15
12
|
case 'google': {
|
|
16
13
|
return this.Google;
|
|
17
14
|
}
|
|
18
|
-
case 'linkedin': {
|
|
19
|
-
return this.LinkedIn;
|
|
20
|
-
}
|
|
21
15
|
case 'okta': {
|
|
22
16
|
return this.Okta;
|
|
23
17
|
}
|
|
@@ -27,17 +21,6 @@ export class IAMProvidersSpecs {
|
|
|
27
21
|
}
|
|
28
22
|
}
|
|
29
23
|
}
|
|
30
|
-
static Bluesky = {
|
|
31
|
-
name: 'bluesky',
|
|
32
|
-
oauth2CallbackServerRoute: 'jupyter_iam/oauth2/callback',
|
|
33
|
-
oauth2CallbackUIRoute: '/iam/oauth2/bluesky/callback',
|
|
34
|
-
accessTokenCookieName: (user) => `__datalayer__bluesky_access_token_${user.id}`,
|
|
35
|
-
refreshTokenCookieName: '__datalayer__bluesky_refresh_token',
|
|
36
|
-
userInfoURL: '',
|
|
37
|
-
tokenRefreshURL: '',
|
|
38
|
-
postShareURL: '',
|
|
39
|
-
registerUploadURL: '',
|
|
40
|
-
};
|
|
41
24
|
static GitHub = {
|
|
42
25
|
name: 'github',
|
|
43
26
|
oauth2CallbackServerRoute: 'jupyter_iam/oauth2/callback',
|
|
@@ -64,12 +47,6 @@ export class IAMProvidersSpecs {
|
|
|
64
47
|
name: 'linkedin',
|
|
65
48
|
oauth2CallbackServerRoute: 'jupyter_iam/oauth2/callback',
|
|
66
49
|
oauth2CallbackUIRoute: '/iam/oauth2/linkedin/callback',
|
|
67
|
-
accessTokenCookieName: (user) => `__datalayer__linkedin_access_token_${user.id}`,
|
|
68
|
-
refreshTokenCookieName: '__datalayer__linkedin_refresh_token',
|
|
69
|
-
userInfoURL: 'https://api.linkedin.com/v2/userinfo',
|
|
70
|
-
tokenRefreshURL: '',
|
|
71
|
-
postShareURL: 'https://api.linkedin.com/v2/ugcPosts',
|
|
72
|
-
registerUploadURL: 'https://api.linkedin.com/v2/assets?action=registerUpload',
|
|
73
50
|
};
|
|
74
51
|
static Okta = {
|
|
75
52
|
name: 'okta',
|
|
@@ -1,4 +1,4 @@
|
|
|
1
1
|
import * as ReactRouterDom from 'react-router-dom';
|
|
2
2
|
export declare const useParamsRR: typeof ReactRouterDom.useParams;
|
|
3
3
|
export declare const useLocationRR: typeof ReactRouterDom.useLocation;
|
|
4
|
-
export declare const useNavigateRR:
|
|
4
|
+
export declare const useNavigateRR: () => ReactRouterDom.NavigateFunction;
|
|
@@ -9,4 +9,7 @@ import * as ReactRouterDom from 'react-router-dom';
|
|
|
9
9
|
// Export hooks for use in our navigation hooks
|
|
10
10
|
export const useParamsRR = ReactRouterDom.useParams;
|
|
11
11
|
export const useLocationRR = ReactRouterDom.useLocation;
|
|
12
|
+
// Typed here rather than inferred: the inferred type carries React Router's
|
|
13
|
+
// own doc comment, whose links (`redirect`, `To`, `<ScrollRestoration>`) point
|
|
14
|
+
// at symbols these docs do not include, and typedoc fails the build on them.
|
|
12
15
|
export const useNavigateRR = ReactRouterDom.useNavigate;
|
package/lib/state/sessionEnd.js
CHANGED
|
@@ -4,6 +4,7 @@
|
|
|
4
4
|
*/
|
|
5
5
|
import { createStore } from 'zustand/vanilla';
|
|
6
6
|
import { useStore } from 'zustand';
|
|
7
|
+
import { DEFAULT_PLANE_URLS } from '../../config/planes.js';
|
|
7
8
|
import { configLogger } from '../../utils/Logger.js';
|
|
8
9
|
let loadConfigurationFromServer = true;
|
|
9
10
|
let initialConfiguration = {
|
|
@@ -15,22 +16,8 @@ let initialConfiguration = {
|
|
|
15
16
|
whiteLabel: true,
|
|
16
17
|
loadConfigurationFromServer: true,
|
|
17
18
|
jupyterServerless: false,
|
|
18
|
-
|
|
19
|
-
|
|
20
|
-
managerUrl: 'https://prod1.datalayer.run',
|
|
21
|
-
runtimesUrl: 'https://r1.datalayer.run',
|
|
22
|
-
schedulerUrl: 'https://r1.datalayer.run',
|
|
23
|
-
libraryUrl: 'https://prod1.datalayer.run',
|
|
24
|
-
spacerUrl: 'https://prod1.datalayer.run',
|
|
25
|
-
aiAgentsUrl: 'https://r1.datalayer.run',
|
|
26
|
-
aiInferenceUrl: 'https://r1.datalayer.run',
|
|
27
|
-
jupyterMcpServerUrl: 'https://mcp.datalayer.run/mcp',
|
|
28
|
-
otelUrl: 'https://prod1.datalayer.run',
|
|
29
|
-
// Defaults to prod so telemetry is consumed from the production OTEL service
|
|
30
|
-
growthUrl: 'https://prod1.datalayer.run',
|
|
31
|
-
inboundsUrl: 'https://prod1.datalayer.run',
|
|
32
|
-
successUrl: 'https://prod1.datalayer.run',
|
|
33
|
-
supportUrl: 'https://prod1.datalayer.run',
|
|
19
|
+
// Which plane each service is on is said once, in `config/planes`.
|
|
20
|
+
...DEFAULT_PLANE_URLS,
|
|
34
21
|
launcher: {
|
|
35
22
|
category: 'Datalayer',
|
|
36
23
|
name: 'Datalayer',
|
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import { IUser, IIAMProviderName } from '../../models';
|
|
1
|
+
import { IUser, IIAMProviderName, IBrowserTokenProviderName } from '../../models';
|
|
2
2
|
import type { ICredits, ICreditsReservation } from '../../models';
|
|
3
3
|
/**
|
|
4
4
|
* Limit to warn about low credits in milliseconds.
|
|
@@ -55,8 +55,8 @@ export type IAMState = IIAMState & {
|
|
|
55
55
|
*/
|
|
56
56
|
refreshCredits: () => Promise<void>;
|
|
57
57
|
checkIAMToken: (token: string) => Promise<void>;
|
|
58
|
-
setIAMProviderAccessToken: (provider:
|
|
59
|
-
getIAMProviderAccessToken: (user: IUser, provider:
|
|
58
|
+
setIAMProviderAccessToken: (provider: IBrowserTokenProviderName, accessToken?: string | null) => void;
|
|
59
|
+
getIAMProviderAccessToken: (user: IUser, provider: IBrowserTokenProviderName) => string | undefined;
|
|
60
60
|
refreshUser: () => Promise<void>;
|
|
61
61
|
refreshUserByTokenStored: () => Promise<void>;
|
|
62
62
|
refreshUserByToken: (token: string) => Promise<void>;
|